diff --git a/src/java/com/samskivert/util/MapEntry.java b/src/java/com/samskivert/util/MapEntry.java new file mode 100644 index 00000000..836bab14 --- /dev/null +++ b/src/java/com/samskivert/util/MapEntry.java @@ -0,0 +1,90 @@ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2001-2006 Michael Bayne +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.util; + +import java.util.Map; + +/** + * A useful building block for implementing one's own {@link Map} classes. Sun + * has this same damned code in AbstractMap and have idiotically declared it + * package protected, with a genius comment saying "This should be made public + * as soon as possible. It greatly simplifies the task of implementing Map." No + * doubt that comment was added half a decade ago. Thanks guys! + */ +public class MapEntry implements Map.Entry +{ + public MapEntry (K key, V value) + { + _key = key; + _value = value; + } + + public MapEntry (Map.Entry e) + { + _key = e.getKey(); + _value = e.getValue(); + } + + // from interface Map.Entry + public K getKey () + { + return _key; + } + + // from interface Map.Entry + public V getValue () + { + return _value; + } + + // from interface Map.Entry + public V setValue (V value) + { + V oldValue = _value; + _value = value; + return oldValue; + } + + @Override // from Object + public boolean equals (Object o) + { + if (!(o instanceof Map.Entry)) { + return false; + } + Map.Entry e = (Map.Entry)o; + return ObjectUtil.equals(_key, e.getKey()) && + ObjectUtil.equals(_value, e.getValue()); + } + + @Override // from Object + public int hashCode () + { + return ((_key == null) ? 0 : _key.hashCode()) ^ + ((_value == null) ? 0 : _value.hashCode()); + } + + @Override // from Object + public String toString () + { + return _key + "=" + _value; + } + + protected K _key; + protected V _value; +} diff --git a/src/java/com/samskivert/util/SoftCacheMap.java b/src/java/com/samskivert/util/SoftCacheMap.java new file mode 100644 index 00000000..743f3c53 --- /dev/null +++ b/src/java/com/samskivert/util/SoftCacheMap.java @@ -0,0 +1,169 @@ +// +// samskivert library - useful routines for java programs +// Copyright (C) 2001-2006 Michael Bayne +// +// This library is free software; you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation; either version 2.1 of the License, or +// (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +package com.samskivert.util; + +import java.lang.ref.SoftReference; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * Implements a {@link SoftReference} cache wherein the values in the hashmap + * are not prevented from being garbage collected. + * + *

Beware! if you iterate over the contents of this map, some + * values may be null. Also note that if you try to store null values in this + * map, those entries will be pruned because the map cannot distinguish between + * an expired soft reference and a null value. Why would you cache null anyway? + */ +public class SoftCacheMap extends AbstractMap +{ + public SoftCacheMap (int initialCapacity, float loadFactor) + { + _map = new HashMap>(initialCapacity, loadFactor); + } + + public SoftCacheMap (int initialCapacity) + { + _map = new HashMap>(initialCapacity); + } + + public SoftCacheMap () + { + _map = new HashMap>(); + } + + // from interface Map + public int size () + { + return _map.size(); + } + + // from interface Map + public boolean containsKey (Object key) + { + return (get(key) != null); + } + + // from interface Map + public V get (Object key) + { + V value = null; + SoftReference ref = _map.get(key); + if (ref != null) { + value = ref.get(); + if (value == null) { + _map.remove(key); + } + } + return value; + } + + // from interface Map + public V put (K key, V value) + { + SoftReference old = _map.put(key, new SoftReference(value)); + return (old == null) ? null : old.get(); + } + + // from interface Map + public V remove (Object key) + { + SoftReference ref = _map.remove(key); + return (ref == null) ? null : ref.get(); + } + + // from interface Map + public void clear () + { + _map.clear(); + } + + // from interface Map + public Set keySet () + { + return _map.keySet(); + } + + // from interface Map + public Set> entrySet () + { + return new EntrySet(); + } + + /** + * Used by {@link EntrySet}. + */ + protected Entry getEntry (Object key) + { + SoftReference value = _map.get(key); + @SuppressWarnings("unchecked") K ckey = (K)key; + return (value == null) ? null : new MapEntry(ckey, value.get()); + } + + protected class EntrySet extends AbstractSet> { + public Iterator> iterator () { + final Iterator>> iter = + _map.entrySet().iterator(); + return new Iterator>() { + public boolean hasNext () { + return iter.hasNext(); + } + public Entry next () { + Entry> ent = iter.next(); + return (ent == null) ? null : + new MapEntry(ent.getKey(), ent.getValue().get()); + } + public void remove () { + iter.remove(); + } + }; + } + + public boolean contains (Object o) { + if (!(o instanceof Entry)) { + return false; + } + @SuppressWarnings("unchecked") Entry entry = (Entry)o; + return containsKey(entry.getKey()); + } + + public boolean remove (Object o) { + if (!(o instanceof Entry)) { + return false; + } + @SuppressWarnings("unchecked") Entry entry = (Entry)o; + return remove(entry.getKey()); + } + + public int size () { + return _map.size(); + } + + public void clear () { + _map.clear(); + } + } + + protected HashMap> _map; +}