Skip to content

Instantly share code, notes, and snippets.

@MattiasFestin
Last active September 2, 2015 06:56
Show Gist options
  • Save MattiasFestin/e5e92d5ae5e2b4bf89c3 to your computer and use it in GitHub Desktop.
Save MattiasFestin/e5e92d5ae5e2b4bf89c3 to your computer and use it in GitHub Desktop.
WeakHashMap for ext.js
Ext.define('Ext.util.WeakHashMap', {
mixins: {
observable: 'Ext.util.Observable'
},
generation: 0,
/**
* Creates new HashMap.
* @param {Object} config (optional) Config object.
* @param Array keys Private parameter used in cloneing
* @param Array values Private parameter used in cloneing
*/
constructor: function(config, keys, values) {
config = config || {};
var keyFn = config.keyFn;
this._keys = keys || [];
this._wm = new WeakMap(values || []);
this.initialConfig = config;
this.addEvents(
/**
* @event add
* Fires when a new item is added to the hash.
* @param {Ext.util.HashMap} this
* @param {String} key The key of the added item.
* @param {Object} value The value of the added item.
*/
'add',
/**
* @event clear
* Fires when the hash is cleared.
* @param {Ext.util.HashMap} this
*/
'clear',
/**
* @event remove
* Fires when an item is removed from the hash.
* @param {Ext.util.HashMap} this
* @param {String} key The key of the removed item.
* @param {Object} value The value of the removed item.
*/
'remove',
/**
* @event replace
* Fires when an item is replaced in the hash.
* @param {Ext.util.HashMap} this
* @param {String} key The key of the replaced item.
* @param {Object} value The new value for the item.
* @param {Object} old The old value for the item.
*/
'replace'
);
this.mixins.observable.constructor.call(this, config);
this.clear(true);
if (keyFn) {
this.getKey = keyFn;
}
},
_removeDeadReferenses: function () {
this._keys.forEach(this.get, this);
},
add: function (key, value) {
this.generation++;
var _key = [key];
this._wm.set(_key, value);
this._keys.push(_key);
if (this.hasListeners.add) {
this.fireEvent('add', this, _key, value);
}
return value;
},
clear: function (/* private */ initial) {
var self = this;
this._keys.forEach(function (k) {
self._wm.delete(k);
});
this._keys = [];
this.generation = initial ? 0 : this.generation + 1;
if (initial !== true && this.hasListeners.clear) {
this.fireEvent('clear', this);
}
return this;
},
clone: function () {
this._removeDeadReferenses();
return new Ext.util.WeakHashMap(this.initialConfig, this.getKeys(), this.getValues());
},
contains: function (value) {
this._removeDeadReferenses();
var self = this;
return this._keys.some(function (k) {
return self._wm.get(k) === value;
});
},
containsKey: function (key) {
this._removeDeadReferenses();
return this._keys.some(function (k) {
return k[0] === key;
});
},
each: function (fn, scope) {
this._removeDeadReferenses();
var self = this;
this._keys.forEach(function (k) {
fn.call(scope || self, k[0], self._wm.get(k), this._keys.length);
});
},
indexOf: function (key) {
var index = -1;
this._keys.some(function (k, i) {
if (k[0] === k) {
index = i;
return true;
}
});
},
get: function (key) {
var i = this.indexOf(key);
if (i > -1) {
if (this._wm.has(key)) {
return this._wm.get(key);
} else {
//Garbage collector has taken it from weakmap
//Remove it from _keys array
this._keys.splice(i, 1);
}
}
},
getCount: function () {
this._removeDeadReferenses();
return this._keys.length;
},
getKey: function (value) {
this._removeDeadReferenses();
var self = this;
return this._keys.filter(function (k) {
return self._wm.get(k) === value;
})[0][0];
},
getKeys: function () {
this._removeDeadReferenses();
return this._keys.map(function (k) {
return k[0];
});;
},
getValues: function (value) {
this._removeDeadReferenses();
var self = this;
return this._keys.map(function (k) {
return self._wm.get(k);
});
},
remove: function (value) {
this._removeDeadReferenses();
var key = this.getKey(value),
k = this._keys[this.indexOf(key)],
i = this.indexOf(k),
exsists = k !== undefined && i > -1;
if (exsists) {
this._wm.delete(k);
this._keys.splice(i, 1);
}
if (this.hasListeners.remove) {
this.fireEvent('remove', this, key, value);
}
return exsists;
},
removeAtKey: function (key) {
this._removeDeadReferenses();
var i = this.indexOf(key),
k = this._keys[i],
exsists = key !== undefined && i > -1,
value = this._wm.get(k);
if (exsists) {
this._wm.delete(k);
this._keys.splice(i, 1);
}
if (this.hasListeners.remove) {
this.fireEvent('remove', this, key, value);
}
return exsists;
},
replace: function (key) {
this._removeDeadReferenses();
this.generation++;
var i = this.indexOf(key),
k = this._keys[i],
value = this._wm.get(k);
if (!this.containsKey(key)) {
this.add(key, value);
}
//[FIXME - Mattias 2015-09-02] - Is it dangeourus to give references to old values???
var old = this._wm.get(key);
this._wm.set(key, value);
if (this.hasListeners.replace) {
this.fireEvent('replace', this, key, value, old);
}
return value;
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment