Mercurial Hosting > luan
annotate src/goodjava/util/CacheMap.java @ 1889:0d11447423a2
use NimbusLookAndFeel
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Thu, 10 Apr 2025 18:48:50 -0600 (4 weeks ago) |
parents | fa066aaa068c |
children |
rev | line source |
---|---|
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 } |