Mercurial Hosting > luan
comparison src/goodjava/util/CacheMap.java @ 1498:1b809d2fdf03
add CacheMap
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Fri, 08 May 2020 18:07:14 -0600 |
parents | |
children | fa066aaa068c |
comparison
equal
deleted
inserted
replaced
1497:f04bfbb08721 | 1498:1b809d2fdf03 |
---|---|
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 | |
37 public int size() { | |
38 return cache.size(); | |
39 } | |
40 | |
41 public boolean isEmpty() { | |
42 return cache.isEmpty(); | |
43 } | |
44 | |
45 public boolean containsKey(Object key) { | |
46 return cache.containsKey(key); | |
47 } | |
48 | |
49 public V get(Object key) { | |
50 MyReference<K,V> ref = cache.get(key); | |
51 return ref==null ? null : ref.get(); | |
52 } | |
53 | |
54 public V put(K key,V value) { | |
55 sweep(); | |
56 MyReference<K,V> ref = cache.put( key, newReference(key,value,queue) ); | |
57 return ref==null ? null : ref.get(); | |
58 } | |
59 | |
60 public V remove(Object key) { | |
61 sweep(); | |
62 MyReference<K,V> ref = cache.remove(key); | |
63 return ref==null ? null : ref.get(); | |
64 } | |
65 | |
66 public void clear() { | |
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 */ | |
78 public Set<K> keySet() { | |
79 return cache.keySet(); | |
80 } | |
81 | |
82 public Set<Map.Entry<K,V>> entrySet() { | |
83 return new MySet(); | |
84 } | |
85 | |
86 | |
87 private class MySet extends AbstractSet<Map.Entry<K,V>> { | |
88 | |
89 public int size() { | |
90 return CacheMap.this.size(); | |
91 } | |
92 | |
93 public Iterator<Map.Entry<K,V>> iterator() { | |
94 return new MyIterator(cache.entrySet().iterator()); | |
95 } | |
96 | |
97 } | |
98 | |
99 private class MyIterator implements Iterator<Map.Entry<K,V>> { | |
100 Iterator<Map.Entry<K,MyReference<K,V>>> iter; | |
101 | |
102 MyIterator(Iterator<Map.Entry<K,MyReference<K,V>>> iter) { | |
103 this.iter = iter; | |
104 } | |
105 | |
106 public boolean hasNext() { | |
107 return iter.hasNext(); | |
108 } | |
109 | |
110 public void remove() { | |
111 iter.remove(); | |
112 } | |
113 | |
114 public Map.Entry<K,V> next() { | |
115 return new MyEntry( iter.next() ); | |
116 } | |
117 } | |
118 | |
119 private class MyEntry implements Map.Entry<K,V> { | |
120 Map.Entry<K,MyReference<K,V>> entry; | |
121 | |
122 MyEntry(Map.Entry<K,MyReference<K,V>> entry) { | |
123 this.entry = entry; | |
124 } | |
125 | |
126 public K getKey() { | |
127 return entry.getKey(); | |
128 } | |
129 | |
130 public V getValue() { | |
131 MyReference<K,V> ref = entry.getValue(); | |
132 return ref.get(); | |
133 } | |
134 | |
135 public V setValue(V value) { | |
136 MyReference<K,V> ref = entry.setValue( newReference(getKey(),value,queue) ); | |
137 return ref.get(); | |
138 } | |
139 | |
140 public boolean equals(Object o) { | |
141 if( o==null || !(o instanceof CacheMap.MyEntry) ) | |
142 return false; | |
143 @SuppressWarnings("unchecked") | |
144 MyEntry m = (MyEntry)o; | |
145 return entry.equals(m.entry); | |
146 } | |
147 | |
148 public int hashCode() { | |
149 K key = getKey(); | |
150 V value = getValue(); | |
151 return (key==null ? 0 : key.hashCode()) ^ | |
152 (value==null ? 0 : value.hashCode()); | |
153 } | |
154 } | |
155 | |
156 } |