Implemented a map that maintains soft references to its values so that they may
be garbage collected. If you iterate over the keys, values or entries, you have to cope with interleaved null values, doing the "right" thing there is a bit PITA and iterating over the cache is wacky anyway because size() will most likely never be right (unless we validated every entry in the cache at the time you called size() which is also wacky). git-svn-id: https://samskivert.googlecode.com/svn/trunk@1885 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -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<K,V> implements Map.Entry<K,V>
|
||||
{
|
||||
public MapEntry (K key, V value)
|
||||
{
|
||||
_key = key;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public MapEntry (Map.Entry<K,V> 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;
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
* <p><em>Beware!</em> 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<K,V> extends AbstractMap<K,V>
|
||||
{
|
||||
public SoftCacheMap (int initialCapacity, float loadFactor)
|
||||
{
|
||||
_map = new HashMap<K,SoftReference<V>>(initialCapacity, loadFactor);
|
||||
}
|
||||
|
||||
public SoftCacheMap (int initialCapacity)
|
||||
{
|
||||
_map = new HashMap<K,SoftReference<V>>(initialCapacity);
|
||||
}
|
||||
|
||||
public SoftCacheMap ()
|
||||
{
|
||||
_map = new HashMap<K,SoftReference<V>>();
|
||||
}
|
||||
|
||||
// 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<V> 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<V> old = _map.put(key, new SoftReference<V>(value));
|
||||
return (old == null) ? null : old.get();
|
||||
}
|
||||
|
||||
// from interface Map
|
||||
public V remove (Object key)
|
||||
{
|
||||
SoftReference<V> ref = _map.remove(key);
|
||||
return (ref == null) ? null : ref.get();
|
||||
}
|
||||
|
||||
// from interface Map
|
||||
public void clear ()
|
||||
{
|
||||
_map.clear();
|
||||
}
|
||||
|
||||
// from interface Map
|
||||
public Set<K> keySet ()
|
||||
{
|
||||
return _map.keySet();
|
||||
}
|
||||
|
||||
// from interface Map
|
||||
public Set<Entry<K,V>> entrySet ()
|
||||
{
|
||||
return new EntrySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by {@link EntrySet}.
|
||||
*/
|
||||
protected Entry<K,V> getEntry (Object key)
|
||||
{
|
||||
SoftReference<V> value = _map.get(key);
|
||||
@SuppressWarnings("unchecked") K ckey = (K)key;
|
||||
return (value == null) ? null : new MapEntry<K,V>(ckey, value.get());
|
||||
}
|
||||
|
||||
protected class EntrySet extends AbstractSet<Entry<K,V>> {
|
||||
public Iterator<Entry<K,V>> iterator () {
|
||||
final Iterator<Entry<K,SoftReference<V>>> iter =
|
||||
_map.entrySet().iterator();
|
||||
return new Iterator<Entry<K,V>>() {
|
||||
public boolean hasNext () {
|
||||
return iter.hasNext();
|
||||
}
|
||||
public Entry<K,V> next () {
|
||||
Entry<K,SoftReference<V>> ent = iter.next();
|
||||
return (ent == null) ? null :
|
||||
new MapEntry<K,V>(ent.getKey(), ent.getValue().get());
|
||||
}
|
||||
public void remove () {
|
||||
iter.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public boolean contains (Object o) {
|
||||
if (!(o instanceof Entry)) {
|
||||
return false;
|
||||
}
|
||||
@SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)o;
|
||||
return containsKey(entry.getKey());
|
||||
}
|
||||
|
||||
public boolean remove (Object o) {
|
||||
if (!(o instanceof Entry)) {
|
||||
return false;
|
||||
}
|
||||
@SuppressWarnings("unchecked") Entry<K,V> entry = (Entry<K,V>)o;
|
||||
return remove(entry.getKey());
|
||||
}
|
||||
|
||||
public int size () {
|
||||
return _map.size();
|
||||
}
|
||||
|
||||
public void clear () {
|
||||
_map.clear();
|
||||
}
|
||||
}
|
||||
|
||||
protected HashMap<K,SoftReference<V>> _map;
|
||||
}
|
||||
Reference in New Issue
Block a user