diff options
Diffstat (limited to 'src/main/javassist/scopedpool/SoftValueHashMap.java')
-rw-r--r-- | src/main/javassist/scopedpool/SoftValueHashMap.java | 132 |
1 files changed, 96 insertions, 36 deletions
diff --git a/src/main/javassist/scopedpool/SoftValueHashMap.java b/src/main/javassist/scopedpool/SoftValueHashMap.java index df6ae599..1154e62e 100644 --- a/src/main/javassist/scopedpool/SoftValueHashMap.java +++ b/src/main/javassist/scopedpool/SoftValueHashMap.java @@ -18,10 +18,14 @@ package javassist.scopedpool; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; -import java.util.AbstractMap; -import java.util.HashMap; +import java.util.AbstractMap.SimpleImmutableEntry; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * This Map will remove entries when the value in the map has been cleaned from @@ -30,21 +34,21 @@ import java.util.Set; * @version <tt>$Revision: 1.4 $</tt> * @author <a href="mailto:bill@jboss.org">Bill Burke</a> */ -public class SoftValueHashMap extends AbstractMap implements Map { - private static class SoftValueRef extends SoftReference { - public Object key; +public class SoftValueHashMap<K,V> implements Map<K,V> { + private static class SoftValueRef<K,V> extends SoftReference<V> { + public K key; - private SoftValueRef(Object key, Object val, ReferenceQueue q) { + private SoftValueRef(K key, V val, ReferenceQueue<V> q) { super(val, q); this.key = key; } - private static SoftValueRef create(Object key, Object val, - ReferenceQueue q) { + private static <K,V> SoftValueRef<K,V> create( + K key, V val, ReferenceQueue<V> q) { if (val == null) return null; else - return new SoftValueRef(key, val, q); + return new SoftValueRef<K,V>(key, val, q); } } @@ -52,30 +56,37 @@ public class SoftValueHashMap extends AbstractMap implements Map { /** * Returns a set of the mappings contained in this hash table. */ - public Set entrySet() { + @Override + public Set<Map.Entry<K, V>> entrySet() { processQueue(); - return hash.entrySet(); + Set<Entry<K,V>> ret = new HashSet<Entry<K,V>>(); + for (Entry<K,SoftValueRef<K,V>> e:hash.entrySet()) + ret.add(new SimpleImmutableEntry<K,V> ( + e.getKey(), e.getValue().get())); + return ret; } /* Hash table mapping WeakKeys to values */ - private Map hash; + private Map<K,SoftValueRef<K,V>> hash; /* Reference queue for cleared WeakKeys */ - private ReferenceQueue queue = new ReferenceQueue(); + private ReferenceQueue<V> queue = new ReferenceQueue<V>(); /* * Remove all invalidated entries from the map, that is, remove all entries * whose values have been discarded. */ private void processQueue() { - SoftValueRef ref; - while ((ref = (SoftValueRef)queue.poll()) != null) { - if (ref == (SoftValueRef)hash.get(ref.key)) { - // only remove if it is the *exact* same WeakValueRef - // - hash.remove(ref.key); + Object ref; + if (!hash.isEmpty()) + while ((ref = queue.poll()) != null) + if (ref instanceof SoftValueRef) { + @SuppressWarnings("rawtypes") + SoftValueRef que =(SoftValueRef) ref; + if (ref == hash.get(que.key)) + // only remove if it is the *exact* same SoftValueRef + hash.remove(que.key); } - } } /* -- Constructors -- */ @@ -95,7 +106,7 @@ public class SoftValueHashMap extends AbstractMap implements Map { * factor is nonpositive */ public SoftValueHashMap(int initialCapacity, float loadFactor) { - hash = new HashMap(initialCapacity, loadFactor); + hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>(initialCapacity, loadFactor); } /** @@ -109,7 +120,7 @@ public class SoftValueHashMap extends AbstractMap implements Map { * If the initial capacity is less than zero */ public SoftValueHashMap(int initialCapacity) { - hash = new HashMap(initialCapacity); + hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>(initialCapacity); } /** @@ -117,7 +128,7 @@ public class SoftValueHashMap extends AbstractMap implements Map { * initial capacity and the default load factor, which is <code>0.75</code>. */ public SoftValueHashMap() { - hash = new HashMap(); + hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>(); } /** @@ -129,7 +140,7 @@ public class SoftValueHashMap extends AbstractMap implements Map { * * @param t the map whose mappings are to be placed in this map. */ - public SoftValueHashMap(Map t) { + public SoftValueHashMap(Map<K,V> t) { this(Math.max(2 * t.size(), 11), 0.75f); putAll(t); } @@ -142,6 +153,7 @@ public class SoftValueHashMap extends AbstractMap implements Map { * <code>Map</code> interface, the time required by this operation is * linear in the size of the map.</em> */ + @Override public int size() { processQueue(); return hash.size(); @@ -150,6 +162,7 @@ public class SoftValueHashMap extends AbstractMap implements Map { /** * Returns <code>true</code> if this map contains no key-value mappings. */ + @Override public boolean isEmpty() { processQueue(); return hash.isEmpty(); @@ -162,6 +175,7 @@ public class SoftValueHashMap extends AbstractMap implements Map { * @param key * The key whose presence in this map is to be tested. */ + @Override public boolean containsKey(Object key) { processQueue(); return hash.containsKey(key); @@ -177,12 +191,10 @@ public class SoftValueHashMap extends AbstractMap implements Map { * @param key * The key whose associated value, if any, is to be returned. */ - public Object get(Object key) { + @Override + public V get(Object key) { processQueue(); - SoftReference ref = (SoftReference)hash.get(key); - if (ref != null) - return ref.get(); - return null; + return valueOrNull(hash.get(key)); } /** @@ -200,12 +212,10 @@ public class SoftValueHashMap extends AbstractMap implements Map { * @return The previous value to which this key was mapped, or * <code>null</code> if if there was no mapping for the key */ - public Object put(Object key, Object value) { + @Override + public V put(K key, V value) { processQueue(); - Object rtn = hash.put(key, SoftValueRef.create(key, value, queue)); - if (rtn != null) - rtn = ((SoftReference)rtn).get(); - return rtn; + return valueOrNull(hash.put(key, SoftValueRef.create(key, value, queue))); } /** @@ -218,16 +228,66 @@ public class SoftValueHashMap extends AbstractMap implements Map { * @return The value to which this key was mapped, or <code>null</code> if * there was no mapping for the key. */ - public Object remove(Object key) { + @Override + public V remove(Object key) { processQueue(); - return hash.remove(key); + return valueOrNull(hash.remove(key)); } /** * Removes all mappings from this map. */ + @Override public void clear() { processQueue(); hash.clear(); } + + /* + * Check whether the supplied value exists. + * @param Object the value to compare. + * @return true if it was found or null. + */ + @Override + public boolean containsValue(Object arg0) { + processQueue(); + if (null == arg0) + return false; + + for (SoftValueRef<K,V> e:hash.values()) + if (null != e && arg0.equals(e.get())) + return true; + return false; + } + + /* {@inheritDoc} */ + @Override + public Set<K> keySet() { + processQueue(); + return hash.keySet(); + } + + /* {@inheritDoc} */ + @Override + public void putAll(Map<? extends K,? extends V> arg0) { + processQueue(); + for (K key:arg0.keySet()) + put(key, arg0.get(key)); + } + + /* {@inheritDoc} */ + @Override + public Collection<V> values() { + processQueue(); + List<V> ret = new ArrayList<V>(); + for (SoftValueRef<K,V> e:hash.values()) + ret.add(e.get()); + return ret; + } + + private V valueOrNull(SoftValueRef<K,V> rtn) { + if (null == rtn) + return null; + return rtn.get(); + } } |