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 }
|