| 
1498
 | 
     1 package goodjava.util;
 | 
| 
 | 
     2 
 | 
| 
 | 
     3 import java.lang.ref.ReferenceQueue;
 | 
| 
 | 
     4 import java.util.Map;
 | 
| 
 | 
     5 import java.util.AbstractMap;
 | 
| 
 | 
     6 import java.util.HashMap;
 | 
| 
 | 
     7 import java.util.Set;
 | 
| 
 | 
     8 import java.util.AbstractSet;
 | 
| 
 | 
     9 import java.util.Iterator;
 | 
| 
 | 
    10 
 | 
| 
 | 
    11 
 | 
| 
 | 
    12 public abstract class CacheMap<K,V> extends AbstractMap<K,V> {
 | 
| 
 | 
    13 
 | 
| 
 | 
    14 	protected static interface MyReference<K,V> {
 | 
| 
 | 
    15 		public K key();
 | 
| 
 | 
    16 		public V get();
 | 
| 
 | 
    17 		public void clear();
 | 
| 
 | 
    18 	}
 | 
| 
 | 
    19 
 | 
| 
 | 
    20 	protected abstract MyReference<K,V> newReference(K key,V value,ReferenceQueue<V> q);
 | 
| 
 | 
    21  
 | 
| 
 | 
    22 	private final Map<K,MyReference<K,V>> cache = new HashMap<K,MyReference<K,V>>();
 | 
| 
 | 
    23 	private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
 | 
| 
 | 
    24 
 | 
| 
 | 
    25 	private void sweep() {
 | 
| 
 | 
    26 		while(true) {
 | 
| 
 | 
    27 			@SuppressWarnings("unchecked")
 | 
| 
 | 
    28 			MyReference<K,V> ref = (MyReference<K,V>)queue.poll();
 | 
| 
 | 
    29 			if( ref == null )
 | 
| 
 | 
    30 				return;
 | 
| 
 | 
    31 			MyReference<K,V> mappedRef = cache.remove(ref.key());
 | 
| 
 | 
    32 			if( mappedRef != ref && mappedRef != null )
 | 
| 
 | 
    33 				cache.put( mappedRef.key(), mappedRef );  // put it back
 | 
| 
 | 
    34 		}
 | 
| 
 | 
    35 	}
 | 
| 
 | 
    36 
 | 
| 
1607
 | 
    37 	@Override public int size() {
 | 
| 
1498
 | 
    38 		return cache.size();
 | 
| 
 | 
    39 	}
 | 
| 
 | 
    40 
 | 
| 
1607
 | 
    41 	@Override public boolean isEmpty() {
 | 
| 
1498
 | 
    42 		return cache.isEmpty();
 | 
| 
 | 
    43 	}
 | 
| 
 | 
    44 
 | 
| 
1607
 | 
    45 	@Override public boolean containsKey(Object key) {
 | 
| 
1498
 | 
    46 		return cache.containsKey(key);
 | 
| 
 | 
    47 	}
 | 
| 
 | 
    48 
 | 
| 
1607
 | 
    49 	@Override public V get(Object key) {
 | 
| 
1498
 | 
    50 		MyReference<K,V> ref = cache.get(key);
 | 
| 
 | 
    51 		return ref==null ? null : ref.get();
 | 
| 
 | 
    52 	}
 | 
| 
 | 
    53 
 | 
| 
1607
 | 
    54 	@Override public V put(K key,V value) {
 | 
| 
1498
 | 
    55 		sweep();
 | 
| 
 | 
    56 		MyReference<K,V> ref = cache.put( key, newReference(key,value,queue) );
 | 
| 
 | 
    57 		return ref==null ? null : ref.get();
 | 
| 
 | 
    58 	}
 | 
| 
 | 
    59 
 | 
| 
1607
 | 
    60 	@Override public V remove(Object key) {
 | 
| 
1498
 | 
    61 		sweep();
 | 
| 
 | 
    62 		MyReference<K,V> ref = cache.remove(key);
 | 
| 
 | 
    63 		return ref==null ? null : ref.get();
 | 
| 
 | 
    64 	}
 | 
| 
 | 
    65 
 | 
| 
1607
 | 
    66 	@Override public void clear() {
 | 
| 
1498
 | 
    67 		sweep();
 | 
| 
 | 
    68 		cache.clear();
 | 
| 
 | 
    69 	}
 | 
| 
 | 
    70 
 | 
| 
 | 
    71 /*
 | 
| 
 | 
    72 	public Object clone() {
 | 
| 
 | 
    73 		GCCacheMap map = new GCCacheMap();
 | 
| 
 | 
    74 		map.cache = (HashMap)cache.clone();
 | 
| 
 | 
    75 		return map;
 | 
| 
 | 
    76 	}
 | 
| 
 | 
    77 */
 | 
| 
1607
 | 
    78 	@Override public Set<K> keySet() {
 | 
| 
1498
 | 
    79 		return cache.keySet();
 | 
| 
 | 
    80 	}
 | 
| 
 | 
    81 
 | 
| 
1607
 | 
    82 	@Override public Set<Map.Entry<K,V>> entrySet() {
 | 
| 
1498
 | 
    83 		return new MySet();
 | 
| 
 | 
    84 	}
 | 
| 
 | 
    85 
 | 
| 
 | 
    86 
 | 
| 
 | 
    87 	private class MySet extends AbstractSet<Map.Entry<K,V>> {
 | 
| 
 | 
    88 
 | 
| 
1607
 | 
    89 		@Override public int size() {
 | 
| 
1498
 | 
    90 			return CacheMap.this.size();
 | 
| 
 | 
    91 		}
 | 
| 
 | 
    92 
 | 
| 
1607
 | 
    93 		@Override public Iterator<Map.Entry<K,V>> iterator() {
 | 
| 
 | 
    94 			return new MyIterator();
 | 
| 
1498
 | 
    95 		}
 | 
| 
 | 
    96 
 | 
| 
 | 
    97 	}
 | 
| 
 | 
    98 
 | 
| 
 | 
    99 	private class MyIterator implements Iterator<Map.Entry<K,V>> {
 | 
| 
1607
 | 
   100 		final Iterator<Map.Entry<K,MyReference<K,V>>> iter = cache.entrySet().iterator();
 | 
| 
1498
 | 
   101 
 | 
| 
1607
 | 
   102 		@Override public boolean hasNext() {
 | 
| 
1498
 | 
   103 			return iter.hasNext();
 | 
| 
 | 
   104 		}
 | 
| 
 | 
   105 
 | 
| 
1607
 | 
   106 		@Override public void remove() {
 | 
| 
1498
 | 
   107 			iter.remove();
 | 
| 
 | 
   108 		}
 | 
| 
 | 
   109 
 | 
| 
1607
 | 
   110 		@Override public Map.Entry<K,V> next() {
 | 
| 
1498
 | 
   111 			return new MyEntry( iter.next() );
 | 
| 
 | 
   112 		}
 | 
| 
 | 
   113 	}
 | 
| 
 | 
   114 
 | 
| 
 | 
   115 	private class MyEntry implements Map.Entry<K,V> {
 | 
| 
 | 
   116 		Map.Entry<K,MyReference<K,V>> entry;
 | 
| 
 | 
   117 
 | 
| 
 | 
   118 		MyEntry(Map.Entry<K,MyReference<K,V>> entry) {
 | 
| 
 | 
   119 			this.entry = entry;
 | 
| 
 | 
   120 		}
 | 
| 
 | 
   121 
 | 
| 
1607
 | 
   122 		@Override public K getKey() {
 | 
| 
1498
 | 
   123 			return entry.getKey();
 | 
| 
 | 
   124 		}
 | 
| 
 | 
   125 
 | 
| 
1607
 | 
   126 		@Override public V getValue() {
 | 
| 
1498
 | 
   127 			MyReference<K,V> ref = entry.getValue();
 | 
| 
 | 
   128 			return ref.get();
 | 
| 
 | 
   129 		}
 | 
| 
 | 
   130 
 | 
| 
1607
 | 
   131 		@Override public V setValue(V value) {
 | 
| 
1498
 | 
   132 			MyReference<K,V> ref = entry.setValue( newReference(getKey(),value,queue) );
 | 
| 
 | 
   133 			return ref.get();
 | 
| 
 | 
   134 		}
 | 
| 
 | 
   135 
 | 
| 
1607
 | 
   136 		@Override public boolean equals(Object o) {
 | 
| 
1498
 | 
   137 			if( o==null || !(o instanceof CacheMap.MyEntry) )
 | 
| 
 | 
   138 				return false;
 | 
| 
 | 
   139 			@SuppressWarnings("unchecked")
 | 
| 
 | 
   140 			MyEntry m = (MyEntry)o;
 | 
| 
 | 
   141 			return entry.equals(m.entry);
 | 
| 
 | 
   142 		}
 | 
| 
 | 
   143 
 | 
| 
1607
 | 
   144 		@Override public int hashCode() {
 | 
| 
1498
 | 
   145 			K key = getKey();
 | 
| 
 | 
   146 			V value = getValue();
 | 
| 
 | 
   147 			return (key==null ? 0 : key.hashCode()) ^
 | 
| 
 | 
   148 					(value==null ? 0 : value.hashCode());
 | 
| 
 | 
   149 		}
 | 
| 
 | 
   150 	}
 | 
| 
 | 
   151 
 | 
| 
 | 
   152 }
 |