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 }