WeakValueHashMap. Apply directly to the ...
I hate your checkin comments, but I love your product! The real reason I cleaned up HashMap: I override forEach(), and now I don't need to do anything to make values() and keys() work properly for weak values. Less code is better code. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@5726 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -0,0 +1,89 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
|
||||||
|
package com.threerings.util {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A HashMap that stores values weakly: if not referenced anywhere else, they may
|
||||||
|
* be garbage collected. Note that the size might change unexpectedly as things are removed.
|
||||||
|
*/
|
||||||
|
public class WeakValueHashMap extends HashMap
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function WeakValueHashMap (
|
||||||
|
loadFactor :Number = 1.75,
|
||||||
|
equalsFn :Function = null,
|
||||||
|
hashFn :Function = null)
|
||||||
|
{
|
||||||
|
super(loadFactor, equalsFn, hashFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
override public function get (key :Object) :*
|
||||||
|
{
|
||||||
|
var result :* = super.get(key);
|
||||||
|
if (result is WeakReference) { // could also just be undefined
|
||||||
|
result = WeakReference(result).get();
|
||||||
|
if (result === undefined) {
|
||||||
|
remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
override public function put (key :Object, value :Object) :*
|
||||||
|
{
|
||||||
|
return unwrap(super.put(key, (value == null) ? null : new WeakReference(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
override public function remove (key :Object) :*
|
||||||
|
{
|
||||||
|
return unwrap(super.remove(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
override public function size () :int
|
||||||
|
{
|
||||||
|
prune();
|
||||||
|
return super.size(); // alternately, we could prune and increment a count for all present..
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
override public function forEach (fn :Function) :void
|
||||||
|
{
|
||||||
|
prune(fn); // just prune & run the forEach at the same time
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prune garbage collected values from the map, optionally calling a function for each
|
||||||
|
* found key/value pair.
|
||||||
|
*/
|
||||||
|
protected function prune (fn :Function = null) :void
|
||||||
|
{
|
||||||
|
var removeKeys :Array = [];
|
||||||
|
super.forEach(function (key :*, value :WeakReference) :void {
|
||||||
|
var rawVal :* = (value == null) ? null : value.get();
|
||||||
|
if (rawVal === undefined) {
|
||||||
|
removeKeys.push(key);
|
||||||
|
} else if (fn != null) {
|
||||||
|
fn(key, rawVal);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for each (var key :Object in removeKeys) {
|
||||||
|
super.remove(key); // slightly more efficient, since we don't need to unwrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unwrap a possible WeakReference for returning to the user.
|
||||||
|
*/
|
||||||
|
protected function unwrap (val :*) :*
|
||||||
|
{
|
||||||
|
return (val is WeakReference) ? WeakReference(val).get() : val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user