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