package com.meidusa.amoeba.util; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.util.*; @SuppressWarnings("unchecked") public class SoftCache extends AbstractMap { private class Entry implements java.util.Map.Entry { private java.util.Map.Entry ent; private Object value; Entry(java.util.Map.Entry entry, Object obj) { ent = entry; value = obj; } public Object getKey() { return ent.getKey(); } public Object getValue() { return value; } public Object setValue(Object obj) { return ent.setValue(ValueCell.create(ent.getKey(), obj, queue)); } public boolean equals(Object obj) { if(!(obj instanceof java.util.Map.Entry)) { return false; } else { java.util.Map.Entry entry = (java.util.Map.Entry)obj; return SoftCache.valEquals(ent.getKey(), entry.getKey()) && SoftCache.valEquals(value, entry.getValue()); } } public int hashCode() { Object obj; return ((obj = getKey()) != null ? obj.hashCode() : 0) ^ (value != null ? value.hashCode() : 0); } } private class EntrySet extends AbstractSet { public Iterator iterator() { return new Iterator() { Iterator hashIterator; Entry next; { hashIterator = hashEntries.iterator(); next = null; } public boolean hasNext() { while(hashIterator.hasNext()) { java.util.Map.Entry entry = (java.util.Map.Entry)hashIterator.next(); ValueCell valuecell = (ValueCell)entry.getValue(); Object obj = null; if(valuecell == null || (obj = valuecell.get()) != null) { next = new Entry(entry, obj); return true; } } return false; } public Object next() { if(next == null && !hasNext()) { throw new NoSuchElementException(); } else { Entry entry = next; next = null; return entry; } } public void remove() { hashIterator.remove(); } }; } public boolean isEmpty() { return !iterator().hasNext(); } public int size() { int i = 0; for(Iterator iterator1 = iterator(); iterator1.hasNext(); iterator1.next()) i++; return i; } public boolean remove(Object obj) { processQueue(); if(obj instanceof Entry) return hashEntries.remove(((Entry)obj).ent); else return false; } Set hashEntries; private EntrySet() { hashEntries = hash.entrySet(); } } private static class ValueCell extends SoftReference { private static ValueCell create(Object obj, Object obj1, ReferenceQueue referencequeue) { if(obj1 == null) return null; else return new ValueCell(obj, obj1, referencequeue); } private static Object strip(Object obj, boolean flag) { if(obj == null) return null; ValueCell valuecell = (ValueCell)obj; Object obj1 = valuecell.get(); if(flag) valuecell.drop(); return obj1; } private boolean isValid() { return key != INVALID_KEY; } private void drop() { super.clear(); key = INVALID_KEY; dropped++; } private static Object INVALID_KEY = new Object(); private static int dropped = 0; private Object key; private ValueCell(Object obj, Object obj1, ReferenceQueue referencequeue) { super(obj1, referencequeue); key = obj; } } private void processQueue() { ValueCell valuecell; while((valuecell = (ValueCell)queue.poll()) != null) if(valuecell.isValid()) hash.remove(valuecell.key); else ValueCell.dropped--; } public SoftCache(int i, float f) { queue = new ReferenceQueue(); entrySet = null; hash = new HashMap(i, f); } public SoftCache(int i) { queue = new ReferenceQueue(); entrySet = null; hash = new HashMap(i); } public SoftCache() { queue = new ReferenceQueue(); entrySet = null; hash = new HashMap(); } public int size() { return entrySet().size(); } public boolean isEmpty() { return entrySet().isEmpty(); } public boolean containsKey(Object obj) { return ValueCell.strip(hash.get(obj), false) != null; } protected Object fill(Object obj) { return null; } public Object get(Object obj) { processQueue(); Object obj1 = hash.get(obj); if(obj1 == null) { obj1 = fill(obj); if(obj1 != null) { hash.put(obj, ValueCell.create(obj, obj1, queue)); return obj1; } } return ValueCell.strip(obj1, false); } public Object put(Object obj, Object obj1) { processQueue(); ValueCell valuecell = ValueCell.create(obj, obj1, queue); return ValueCell.strip(hash.put(obj, valuecell), true); } public Object remove(Object obj) { processQueue(); return ValueCell.strip(hash.remove(obj), true); } public void clear() { processQueue(); hash.clear(); } private static boolean valEquals(Object obj, Object obj1) { return obj != null ? obj.equals(obj1) : obj1 == null; } public Set entrySet() { if(entrySet == null) entrySet = new EntrySet(); return entrySet; } private Map hash; private ReferenceQueue queue; private Set entrySet; }