libraries/bugcore/js/src/data/MultiMap.js
/*
* Copyright (c) 2016 airbug Inc. http://airbug.com
*
* bugcore may be freely distributed under the MIT license.
*/
//-------------------------------------------------------------------------------
// Annotations
//-------------------------------------------------------------------------------
//@Export('MultiMap')
//@Require('Class')
//@Require('Collection')
//@Require('IMap')
//@Require('IMultiMap')
//@Require('Map')
//-------------------------------------------------------------------------------
// Context
//-------------------------------------------------------------------------------
require('bugpack').context("*", function(bugpack) {
//-------------------------------------------------------------------------------
// BugPack
//-------------------------------------------------------------------------------
var Class = bugpack.require('Class');
var Collection = bugpack.require('Collection');
var IMap = bugpack.require('IMap');
var IMultiMap = bugpack.require('IMultiMap');
var Map = bugpack.require('Map');
//-------------------------------------------------------------------------------
// Declare Class
//-------------------------------------------------------------------------------
/**
* Map info
* 1) Supports null values but not undefined values. Undefined values are used to indicate something doesn't exist.
* 2) Any value can be used as a key including null but not undefined.
*
* @class
* @extends {Map.<K, V>}
* @implements {IMultiMap.<K, V>}
* @template K, V
*/
var MultiMap = Class.extend(Map, /** @lends {MultiMap.prototype} */{
_name: "MultiMap",
//-------------------------------------------------------------------------------
// Getters and Setters
//-------------------------------------------------------------------------------
/**
* @return {number}
*/
getKeyCount: function() {
return this.getCount();
},
//-------------------------------------------------------------------------------
// Object Implementation
//-------------------------------------------------------------------------------
/**
* @param {boolean=} deep
* @return {MultiMap.<K, V>}
*/
clone: function(deep) {
var cloneMultiMap = new MultiMap();
cloneMultiMap.putAll(this);
return cloneMultiMap;
},
//-------------------------------------------------------------------------------
// Public methods
//-------------------------------------------------------------------------------
/**
* @param {*} value
* @return {boolean}
*/
containsValue: function(value) {
var iterator = this.iterator();
while (iterator.hasNext()) {
var valueCollection = iterator.nextValue();
if (valueCollection.contains(value)) {
return true;
}
}
return false;
},
/**
* @param {function(ICollection.<V>, K)} func
*/
forEachCollection: function(func) {
this.getHashTable().forEach(func);
},
/**
* @param {function(V, K)} func
*/
forEachValue: function(func) {
this.getHashTable().forEach(function(valueCollection) {
valueCollection.forEach(func);
});
},
/**
* @override
* @param {*} key
* @return {ICollection.<V>}
*/
get: function(key) {
return this.getHashTable().get(key);
},
/**
* @param {K} key
* @param {V} value
* @return {V}
*/
put: function(key, value) {
var valueCollection = this.getHashTable().get(key);
if (!valueCollection) {
valueCollection = new Collection();
this.getHashTable().put(key, valueCollection);
}
valueCollection.add(value);
return value;
},
/**
* @param {IMap.<K, V>} map
*/
putAll: function(map) {
var _this = this;
if (Class.doesImplement(map, IMap)) {
map.toKeyArray().forEach(function(key) {
var value = map.get(key);
_this.put(key, value);
});
} else if (Class.doesImplement(map, IMultiMap)) {
map.toKeyArray().forEach(function(key) {
var valueCollection = map.get(key);
valueCollection.forEach(function(value) {
_this.put(key, value);
});
});
}
},
/**
* Removes all values under the key
* @param {*} key
* @return {ICollection.<V>}
*/
remove: function(key) {
return this.getHashTable().remove(key);
},
/**
* Removes a specific value associated with the key
* @param {*} key
* @param {*} value
* @return {boolean}
*/
removeKeyValuePair: function(key, value) {
var result = false;
var valueCollection = this.getHashTable().get(key);
if (valueCollection) {
result = valueCollection.remove(value);
if (result && valueCollection.isEmpty()) {
this.getHashTable().remove(valueCollection);
}
}
return result;
},
/**
* @return {ICollection.<K>}
*/
toKeyCollection: function() {
var keyCollection = new Collection();
this.forIn(function(key) {
keyCollection.add(key);
});
return keyCollection;
},
/**
* @return {Array.<V>}
*/
toValueArray: function() {
var valueArray = [];
this.forEach(function(valueCollection) {
valueArray = valueArray.concat(valueCollection.toValueArray());
});
return valueArray;
},
/**
* @return {ICollection.<V>}
*/
toValueCollection: function() {
var valueCollection = new Collection();
this.getHashTable().forEach(function(valueSet) {
valueCollection.addAll(valueSet);
});
return valueCollection;
}
});
//-------------------------------------------------------------------------------
// Implement Interfaces
//-------------------------------------------------------------------------------
Class.implement(MultiMap, IMultiMap);
//-------------------------------------------------------------------------------
// Exports
//-------------------------------------------------------------------------------
bugpack.export('MultiMap', MultiMap);
});