Mega Code Archive

 
Categories / Java / Collections Data Structure
 

Weak ValueMap

/*  * Copyright 2002-2006 (C) TJDO.  * All rights reserved.  *  * This software is distributed under the terms of the TJDO License version 1.0.  * See the terms of the TJDO License in the documentation provided with this software.  *  * $Id: WeakValueMap.java,v 1.5 2006/09/08 16:11:28 jackknifebarber Exp $  */ import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; 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; /**  * A <code>java.util.Map</code> implementation with weak values.  * <p>  * The values are stored in the map as weak references.  * If the garbage collector clears the reference, the corresponding key is  * automatically removed from the map.  *  * @author <a href="mailto:mmartin5@austin.rr.com">Mike Martin</a>  * @version $Revision: 1.5 $  *  * @see WeakReference  */ public class WeakValueMap extends ReferenceValueMap {     public WeakValueMap()     {         super(new HashMap());     }     public WeakValueMap(int initialCapacity)     {         super(new HashMap(initialCapacity));     }     public WeakValueMap(int initialCapacity, float loadFactor)     {         super(new HashMap(initialCapacity, loadFactor));     }     public WeakValueMap(Map m)     {         super(new HashMap(m));     }     protected Reference newReference(Object value)     {         return new WeakReference(value, refQueue);     } } /**  * A <code>java.util.Map</code> implementation using reference values.  * <p>  * The values are stored in the map as references.  * If the garbage collector clears the reference, the corresponding key is  * automatically removed from the map.  *  * @author  <a href="mailto:jackknifebarber@users.sourceforge.net">Mike Martin</a>  * @version $Revision: 1.8 $  */ abstract class ReferenceValueMap extends AbstractMap {     protected final ReferenceQueue refQueue = new ReferenceQueue();     /** Backing map. */     private final Map backing;     ReferenceValueMap(Map backing)     {         this.backing = backing;     }     /**      * Returns a new <code>Reference</code> object to be inserted into the map.      * Subclasses must implement this method to construct <code>Reference</code>      * objects of the desired type (e.g. <code>SoftReference</code>, etc.).      *      * @param value      *      The associated value to be referenced.      *      * @return      *      A new <code>Reference</code> object to be inserted into the map.      */     protected abstract Reference newReference(Object value);     private void reap()     {         Reference ref;         while ((ref = refQueue.poll()) != null)             backing.values().remove(ref);     }     public Object put(Object key, Object value)     {         reap();         return backing.put(key, newReference(value));     }     public Object get(Object key)     {         reap();         Object v = backing.get(key);         return (v instanceof Reference) ? ((Reference)v).get() : v;     }     public int size()     {         reap();         return backing.size();     }     public boolean isEmpty()     {         reap();         return backing.isEmpty();     }     public boolean containsKey(Object key)     {         reap();         return backing.containsKey(key);     }     public boolean containsValue(Object value)     {         reap();         return super.containsValue(value);     }     public Set keySet()     {         reap();         return backing.keySet();     }     public Collection values()     {         reap();         return super.values();     }     public Set entrySet()     {         reap();         return new EntrySet();     }     public Object remove(Object key)     {         reap();         return backing.remove(key);     }     public int hashCode()     {         reap();         return super.hashCode();     }     public boolean equals(Object o)     {         reap();         return super.equals(o);     }     public String toString()     {         reap();         return super.toString();     }     static boolean eq(Object o1, Object o2)     {         return o1 == null ? o2 == null : o1.equals(o2);     }     private class EntrySet extends AbstractSet     {         /** Backing set. */         private final Set set = backing.entrySet();         public Iterator iterator()         {             return new Iterator()             {                 private Iterator i = set.iterator();                 public boolean hasNext()                 {                     return i.hasNext();                 }                 public void remove()                 {                     i.remove();                 }                 public Object next()                 {                     final Map.Entry ent = (Map.Entry)i.next();                     return new Map.Entry()                     {                         public Object getKey()                         {                             return ent.getKey();                         }                         public Object getValue()                         {                             Object v = ent.getValue();                             return (v instanceof Reference) ? ((Reference)v).get() : v;                         }                         public Object setValue(Object v)                         {                             Object oldVal = getValue();                             ent.setValue(newReference(v));                             return oldVal;                         }                         public boolean equals(Object o)                         {                             if (o == this)                                 return true;                             if (!(o instanceof Map.Entry))                                 return false;                             Map.Entry e = (Map.Entry)o;                             return eq(ent.getKey(), e.getKey())                                 && eq(ent.getValue(), e.getValue());                         }                         public int hashCode()                         {                             Object key = ent.getKey();                             Object val = ent.getValue();                             return (key == null ? 0 : key.hashCode())                                  ^ (val == null ? 0 : val.hashCode());                         }                         public String toString()                         {                             return ent.getKey() + "=" + ent.getValue();                         }                     };                 }             };         }         public int size()         {             reap();             return set.size();         }         public boolean isEmpty()         {             reap();             return set.isEmpty();         }         public boolean contains(Object o)         {             reap();             return super.contains(o);         }         public Object[] toArray()         {             reap();             return super.toArray();         }         public Object[] toArray(Object[] a)         {             reap();             return super.toArray(a);         }         public boolean remove(Object o)         {             reap();             return super.remove(o);         }         public boolean containsAll(Collection c)         {             reap();             return super.containsAll(c);         }         public boolean removeAll(Collection c)         {             reap();             return super.removeAll(c);         }         public boolean retainAll(Collection c)         {             reap();             return super.retainAll(c);         }         public void clear()         {             set.clear();         }         public String toString()         {             reap();             return super.toString();         }     } }