From cbbd1f281d98e100e1379462805236a0efa96b9c Mon Sep 17 00:00:00 2001 From: Ray Greenwell Date: Thu, 16 Apr 2009 22:55:40 +0000 Subject: [PATCH] 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 --- .../com/threerings/util/WeakValueHashMap.as | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/as/com/threerings/util/WeakValueHashMap.as diff --git a/src/as/com/threerings/util/WeakValueHashMap.as b/src/as/com/threerings/util/WeakValueHashMap.as new file mode 100644 index 000000000..47bc05c7b --- /dev/null +++ b/src/as/com/threerings/util/WeakValueHashMap.as @@ -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; + } +} +}