package org.devtcg.five.util; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.HashMap; public class MemCache<K, V> { private final HashMap<K, CacheValue<K, V>> mCache = new HashMap<K, CacheValue<K, V>>(); private final ReferenceQueue<V> mRefQueue = new ReferenceQueue<V>(); public V get(K key) { prune(); CacheValue<K, V> ref = mCache.get(key); if (ref != null) { V value = ref.get(); if (value != null) return value; else mCache.remove(key); } return null; } public void put(K key, V value) { prune(); mCache.put(key, new CacheValue<K, V>(key, value, mRefQueue)); } public V remove(K key) { prune(); CacheValue<K, V> ref = mCache.remove(key); if (ref != null) { V value = ref.get(); if (value != null) return value; } return null; } public int size() { return mCache.size(); } public void clear() { while (mRefQueue.poll() != null) /* Do nothing... */; mCache.clear(); } @SuppressWarnings("unchecked") private void prune() { CacheValue<K, V> ref; while ((ref = (CacheValue<K, V>)mRefQueue.poll()) != null) { K key = ref.key.get(); if (key != null) mCache.remove(key); } } /** * @deprecated Do not use. */ public ReferenceQueue<V> getReferenceQueue() { return mRefQueue; } private static class CacheValue<Key, Value> extends SoftReference<Value> { /** * Reference to the key that installed this value so we can prune * entries when the value expires. * <p> * Must be weakly referenced for the case where the entry is removed * from the cache, but still strongly referenced because of the * reference queue. */ private final WeakReference<Key> key; public CacheValue(Key key, Value value, ReferenceQueue<? super Value> queue) { super(value, queue); this.key = new WeakReference<Key>(key); } } }