Mercurial Hosting > luan
view src/goodjava/util/CacheMap.java @ 1625:57c8baadb357
handle UnsupportedClassVersionError
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sun, 05 Sep 2021 12:32:27 -0600 |
parents | fa066aaa068c |
children |
line wrap: on
line source
package goodjava.util; import java.lang.ref.ReferenceQueue; import java.util.Map; import java.util.AbstractMap; import java.util.HashMap; import java.util.Set; import java.util.AbstractSet; import java.util.Iterator; public abstract class CacheMap<K,V> extends AbstractMap<K,V> { protected static interface MyReference<K,V> { public K key(); public V get(); public void clear(); } protected abstract MyReference<K,V> newReference(K key,V value,ReferenceQueue<V> q); private final Map<K,MyReference<K,V>> cache = new HashMap<K,MyReference<K,V>>(); private final ReferenceQueue<V> queue = new ReferenceQueue<V>(); private void sweep() { while(true) { @SuppressWarnings("unchecked") MyReference<K,V> ref = (MyReference<K,V>)queue.poll(); if( ref == null ) return; MyReference<K,V> mappedRef = cache.remove(ref.key()); if( mappedRef != ref && mappedRef != null ) cache.put( mappedRef.key(), mappedRef ); // put it back } } @Override public int size() { return cache.size(); } @Override public boolean isEmpty() { return cache.isEmpty(); } @Override public boolean containsKey(Object key) { return cache.containsKey(key); } @Override public V get(Object key) { MyReference<K,V> ref = cache.get(key); return ref==null ? null : ref.get(); } @Override public V put(K key,V value) { sweep(); MyReference<K,V> ref = cache.put( key, newReference(key,value,queue) ); return ref==null ? null : ref.get(); } @Override public V remove(Object key) { sweep(); MyReference<K,V> ref = cache.remove(key); return ref==null ? null : ref.get(); } @Override public void clear() { sweep(); cache.clear(); } /* public Object clone() { GCCacheMap map = new GCCacheMap(); map.cache = (HashMap)cache.clone(); return map; } */ @Override public Set<K> keySet() { return cache.keySet(); } @Override public Set<Map.Entry<K,V>> entrySet() { return new MySet(); } private class MySet extends AbstractSet<Map.Entry<K,V>> { @Override public int size() { return CacheMap.this.size(); } @Override public Iterator<Map.Entry<K,V>> iterator() { return new MyIterator(); } } private class MyIterator implements Iterator<Map.Entry<K,V>> { final Iterator<Map.Entry<K,MyReference<K,V>>> iter = cache.entrySet().iterator(); @Override public boolean hasNext() { return iter.hasNext(); } @Override public void remove() { iter.remove(); } @Override public Map.Entry<K,V> next() { return new MyEntry( iter.next() ); } } private class MyEntry implements Map.Entry<K,V> { Map.Entry<K,MyReference<K,V>> entry; MyEntry(Map.Entry<K,MyReference<K,V>> entry) { this.entry = entry; } @Override public K getKey() { return entry.getKey(); } @Override public V getValue() { MyReference<K,V> ref = entry.getValue(); return ref.get(); } @Override public V setValue(V value) { MyReference<K,V> ref = entry.setValue( newReference(getKey(),value,queue) ); return ref.get(); } @Override public boolean equals(Object o) { if( o==null || !(o instanceof CacheMap.MyEntry) ) return false; @SuppressWarnings("unchecked") MyEntry m = (MyEntry)o; return entry.equals(m.entry); } @Override public int hashCode() { K key = getKey(); V value = getValue(); return (key==null ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode()); } } }