@mezzy/collections
Version:
A luxurious user experience framework, developed by your friends at Mezzanine.
200 lines (167 loc) • 6.39 kB
text/typescript
import CollectionTools from './collectionTools';
import IMapPair from './interfaces/iMapPair';
import IMap from './interfaces/iMap';
export class MapList<K, V> implements IMap<K, V> {
/**
* Creates an empty map.
* @class <p>Dictionaries map keys to values; each key can map to at most one value.
* This implementation accepts any kind of objects as keys.</p>
*
* <p>If the keys are custom objects a function which converts keys to unique
* strings must be provided. Example:</p>
* <pre>
* function petToString(pet) {
* return pet.key;
* }
* </pre>
* @constructor
* @param {function(Object):string=} _toStringFunction optional function used
* to convert keys to strings. If the keys aren't strings or if _toStringing()
* is not appropriate, a custom function which receives a key and returns a
* unique string must be provided.
*/
constructor(_toStringFunction?:(key:K) => string) {
this.table = {};
this.p_length = 0;
this._toString = _toStringFunction || CollectionTools.defaultToString;
}
/**
* Object holding the key-value pairs.
* [key: K] will not work since indices can only be strings in javascript and typescript enforces this.
*/
private table:{ [key:string]:IMapPair<K, V> };
/**
* Number of elements in the list.
*/
/**
* Returns the number of keys in this map.
* @return {number} the number of key-value mappings in this map.
*/
get size():number { return this.p_length; }
protected p_length:number;
/**
* Function used to convert keys to strings.
*/
private _toString:(key:K) => string;
/**
* Returns the value to which this map maps the specified key.
* Returns undefined if this map has no mapping for this key.
* @param {Object} key key whose associated value is to be returned.
* @return {*} the value to which this map maps the specified key or undefined if the map has no mapping for this key.
*/
get(key:K):V {
let pair:IMapPair<K, V> = this.table[this._toString(key)];
if (CollectionTools.isUndefined(pair)) return undefined;
return pair.value;
}
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for this key, the old
* value is replaced by the specified value.
* @param {Object} key key with which the specified value is to be associated.
* @param {Object} value value to be associated with the specified key.
* @return {*} previous value associated with the specified key, or undefined if there was no mapping for the key or if the key/value are undefined.
*/
set(key:K, value:V):V {
if (CollectionTools.isUndefined(key) || CollectionTools.isUndefined(value)) return undefined;
let ret:V;
let k = this._toString(key);
let previousElement:IMapPair<K, V> = this.table[k];
if (CollectionTools.isUndefined(previousElement)) {
this.p_length++;
ret = undefined;
} else ret = previousElement.value;
this.table[k] = {
key: key,
value: value
};
return ret;
}
/**
* Removes the mapping for this key from this map if it is present.
* @param {Object} key key whose mapping is to be deleted from the map.
* @return {*} value associated with specified key, or undefined if there was no mapping for key.
*/
delete(key:K):V {
let k = this._toString(key);
let previousElement:IMapPair<K, V> = this.table[k];
if (!CollectionTools.isUndefined(previousElement)) {
delete this.table[k];
this.p_length--;
return previousElement.value;
}
return undefined;
}
/**
* Returns an array containing all of the keys in this map.
* @return {Array} an array containing all of the keys in this map.
*/
get keys():K[] {
let array:K[] = [];
for (let name in this.table) {
if ((<any>this.table).hasOwnProperty(name)) {
let pair:IMapPair<K, V> = this.table[name];
array.push(pair.key);
}
}
return array;
}
/**
* Returns an array containing all of the values in this map.
* @return {Array} an array containing all of the values in this map.
*/
get values():V[] {
let array:V[] = [];
for (let name in this.table) {
if ((<any>this.table).hasOwnProperty(name)) {
let pair:IMapPair<K, V> = this.table[name];
array.push(pair.value);
}
}
return array;
}
/**
* Executes the provided function once for each key-value pair
* present in this map.
* @param {function(Object, Object):*} callback function to execute, it is
* invoked with two arguments: value and key. To break the iteration you can
* optionally return false.
*/
forEach(callback:(value:V, key:K) => boolean):void {
for (let name in this.table) {
if ((<any>this.table).hasOwnProperty(name)) {
let pair:IMapPair<K, V> = this.table[name];
let ret = callback(pair.value, pair.key);
if (ret === false) return;
}
}
}
/**
* Returns true if this map has a mapping for the specified key.
* @param {Object} key key whose presence in this map is to be tested.
* @return {boolean} true if this map has a mapping for the specified key.
*/
has(key:K):boolean { return !CollectionTools.isUndefined(this.get(key)); }
/**
* Removes all mappings from this map.
* @this {CollectionTools.Map}
*/
clear() {
this.table = {};
this.p_length = 0;
}
/**
* Returns true if this map has no mappings.
* @return {boolean} true if this map has no mappings.
*/
get isEmpty():boolean { return this.p_length <= 0; }
toString():string {
let toret = "{";
this.forEach((k, v):boolean => {
toret = toret + "\n\t" + k.toString() + " : " + v.toString();
return true;
});
return toret + "\n}";
}
} // End class
export default MapList;