UNPKG

ncollections

Version:
144 lines (121 loc) 4.45 kB
'use strict' const UnsupportedOperationException = require(__dirname + '/UnsupportedOperationException.js'); const Util = require(__dirname + '/Util.js'); // Super class of all collections. class Collection { static equals_fn = function(element1, element2) { if ((typeof element1 === 'object') && (element1 != null)&& (typeof element1.equals === 'function')) return element1.equals(element2); if ((typeof element2 === 'object') && (element2 != null)&& (typeof element2.equals === 'function')) return element2.equals(element1); return Util.equals(element1, element2); } static hash_code_fn = function(element) { if ((typeof element === 'object') && (element != null) && (typeof element.hashCode === 'function')) return element.hashCode(); return Util.hashCode(element); } static compare_fn = function(element1, element2) { if ((typeof element1 === 'object') && (element1 != null) && (typeof element1.compare === 'function')) return element1.compare(element2); if ((typeof element2 === 'object') && (element2 != null) && (typeof element2.compare === 'function')) return element2.compare(element1); return Util.compare(element1, element2); } #options; get options() { return this.#options; } constructor(options={}) { this.#options = options; } // Clears the collection, i.e. makes it empty. clear() { throw new UnsupportedOperationException(); } // Returns a shallow clone of the collection. clone() { throw new UnsupportedOperationException(); } clone0(add_method_name='add') { let clone = new this.constructor(this.options); for (let element of this) clone[add_method_name](element); return clone; } // Two collections are equal if they are both Collections and their iterators return "equal" elements in the same order. // Sub-classes will typically overrride this to ensure the Collection class is the same (e.g. Deque or Stack), or shares the same super-class (e.g. List or Set), using the equals0 method. equals(collection) { return this.equals0(collection, Collection); } equals0(collection, instance_of) { if (this == collection) return true; if (!(collection instanceof instance_of)) return false; if (this.size() != collection.size()) return false; let this_iterator = this.next(); let other_iterator = collection.next(); while (true) { let this_next = this_iterator.next(); if (this_next.done) break; let other_next = other_iterator.next(); if (!Collection.equals_fn(this_next.value, other_next.value)) return false; } return true; } // Source: https://stackoverflow.com/questions/1646807/quick-and-simple-hash-code-combinations hashCode() { let hash = 17; for (let element of this) hash = hash * 31 * Collection.hash_code_fn(element); return hash; } // Returns true if the collection size is 0. isEmpty() { return this.size() === 0; } // Implement iterator protocol. // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols next() { throw new UnsupportedOperationException(); } // Implement iterable protocol. // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols [Symbol.iterator]() { return this.next(); } // Returns the number of elements in the collection. size() { throw new UnsupportedOperationException(); } size0() { let size = 0; for (let element of this) size++; return size; } // Returns the collection as an array. toArray() { return Array.from(this); } // Returns a string representation of the collection in iteration order. // Note that two collections (e.g. two sets) that are equal might not necessarily return the same string because their iteration order might be different. toString(options={}) { let start = options.start || '['; let separator = options.separator || ','; let end = options.end || ']'; let element_fn = options.element_fn || function(element) { return Util.toString(element); }; let str = start; let index = 0; let size = this.size(); for (let element of this) { str += element_fn(element); if (index < (size - 1)) str += separator; index++; }; str += end; return str; } } module.exports = Collection;