UNPKG

buckets-js

Version:

Buckets is a complete, fully tested and documented data structure library written in pure JavaScript.

211 lines (196 loc) 7 kB
/** * Creates an empty dictionary. * @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 that converts keys to unique * strings must be provided at construction time.</p> * <p>Example:</p> * <pre> * function petToString(pet) { * return pet.name; * } * </pre> * @constructor * @param {function(Object):string=} toStrFunction Optional function used * to convert keys to unique strings. If the keys aren't strings or if toString() * is not appropriate, a custom function which receives a key and returns a * unique string must be provided. */ buckets.Dictionary = function (toStrFunction) { /** * @exports dictionary as buckets.Dictionary * @private */ var dictionary = {}, // Object holding the key-value pairs. table = {}, // Number of keys in the dictionary. nElements = 0, // Function to convert keys unique to strings. toStr = toStrFunction || buckets.defaultToString, // Special string to prefix keys and avoid name collisions with existing properties. keyPrefix = '/$ '; /** * Returns the value associated with the specified key in the dictionary. * @param {Object} key The key. * @return {*} The mapped value or * undefined if the dictionary contains no mapping for the provided key. */ dictionary.get = function (key) { var pair = table[keyPrefix + toStr(key)]; if (buckets.isUndefined(pair)) { return undefined; } return pair.value; }; /** * Associates the specified value with the specified key in the dictionary. * If the dictionary previously contained a mapping for the key, the old * value is replaced by the specified value. * @param {Object} key The key. * @param {Object} value Value to be mapped with the specified key. * @return {*} Previous value associated with the provided key, or undefined if * there was no mapping for the key or the key/value is undefined. */ dictionary.set = function (key, value) { var ret, k, previousElement; if (buckets.isUndefined(key) || buckets.isUndefined(value)) { return undefined; } k = keyPrefix + toStr(key); previousElement = table[k]; if (buckets.isUndefined(previousElement)) { nElements += 1; ret = undefined; } else { ret = previousElement.value; } table[k] = { key: key, value: value }; return ret; }; /** * Removes the value associated with the specified key from the dictionary if it exists. * @param {Object} key The key. * @return {*} Removed value associated with the specified key, or undefined if * there was no mapping for the key. */ dictionary.remove = function (key) { var k = keyPrefix + toStr(key), previousElement = table[k]; if (!buckets.isUndefined(previousElement)) { delete table[k]; nElements -= 1; return previousElement.value; } return undefined; }; /** * Returns an array containing all the keys in the dictionary. * @return {Array} An array containing all the keys in the dictionary. */ dictionary.keys = function () { var array = [], name; for (name in table) { if (Object.prototype.hasOwnProperty.call(table, name)) { array.push(table[name].key); } } return array; }; /** * Returns an array containing all the values in the dictionary. * @return {Array} An array containing all the values in the dictionary. */ dictionary.values = function () { var array = [], name; for (name in table) { if (Object.prototype.hasOwnProperty.call(table, name)) { array.push(table[name].value); } } return array; }; /** * Executes the provided function once per key-value pair * present in the dictionary. * @param {function(Object,Object):*} callback Function to execute. Receives * 2 arguments: key and value. To break the iteration you can * optionally return false inside the callback. */ dictionary.forEach = function (callback) { var name, pair, ret; for (name in table) { if (Object.prototype.hasOwnProperty.call(table, name)) { pair = table[name]; ret = callback(pair.key, pair.value); if (ret === false) { return; } } } }; /** * Returns true if the dictionary contains a mapping for the specified key. * @param {Object} key The key. * @return {boolean} True if the dictionary contains a mapping for the * specified key. */ dictionary.containsKey = function (key) { return !buckets.isUndefined(dictionary.get(key)); }; /** * Removes all keys and values from the dictionary. * @this {buckets.Dictionary} */ dictionary.clear = function () { table = {}; nElements = 0; }; /** * Returns the number of key-value pais in the dictionary. * @return {number} The number of key-value mappings in the dictionary. */ dictionary.size = function () { return nElements; }; /** * Returns true if the dictionary contains no keys. * @return {boolean} True if this dictionary contains no mappings. */ dictionary.isEmpty = function () { return nElements <= 0; }; /** * Returns true if the dictionary is equal to another dictionary. * Two dictionaries are equal if they have the same key-value pairs. * @param {buckets.Dictionary} other The other dictionary. * @param {function(Object,Object):boolean=} equalsFunction Optional * function to check if two values are equal. If the values in the dictionaries * are custom objects you should provide a custom equals function, otherwise * the === operator is used to check equality between values. * @return {boolean} True if the dictionary is equal to the given dictionary. */ dictionary.equals = function (other, equalsFunction) { var eqf, isEqual; if (buckets.isUndefined(other) || typeof other.keys !== 'function') { return false; } if (dictionary.size() !== other.size()) { return false; } eqf = equalsFunction || buckets.defaultEquals; isEqual = true; other.forEach(function (k, v) { isEqual = eqf(dictionary.get(k), v); return isEqual; }); return isEqual; }; return dictionary; };