Home | History | Annotate | Download | only in scopedpool
      1 /*
      2  * Javassist, a Java-bytecode translator toolkit.
      3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License.  Alternatively, the contents of this file may be used under
      8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  */
     15 
     16 package javassist.scopedpool;
     17 
     18 import java.lang.ref.ReferenceQueue;
     19 import java.lang.ref.SoftReference;
     20 import java.util.AbstractMap;
     21 import java.util.HashMap;
     22 import java.util.Map;
     23 import java.util.Set;
     24 
     25 /**
     26  * This Map will remove entries when the value in the map has been cleaned from
     27  * garbage collection
     28  *
     29  * @version <tt>$Revision: 1.4 $</tt>
     30  * @author <a href="mailto:bill (at) jboss.org">Bill Burke</a>
     31  */
     32 public class SoftValueHashMap extends AbstractMap implements Map {
     33     private static class SoftValueRef extends SoftReference {
     34         public Object key;
     35 
     36         private SoftValueRef(Object key, Object val, ReferenceQueue q) {
     37             super(val, q);
     38             this.key = key;
     39         }
     40 
     41         private static SoftValueRef create(Object key, Object val,
     42                 ReferenceQueue q) {
     43             if (val == null)
     44                 return null;
     45             else
     46                 return new SoftValueRef(key, val, q);
     47         }
     48 
     49     }
     50 
     51     /**
     52      * Returns a set of the mappings contained in this hash table.
     53      */
     54     public Set entrySet() {
     55         processQueue();
     56         return hash.entrySet();
     57     }
     58 
     59     /* Hash table mapping WeakKeys to values */
     60     private Map hash;
     61 
     62     /* Reference queue for cleared WeakKeys */
     63     private ReferenceQueue queue = new ReferenceQueue();
     64 
     65     /*
     66      * Remove all invalidated entries from the map, that is, remove all entries
     67      * whose values have been discarded.
     68      */
     69     private void processQueue() {
     70         SoftValueRef ref;
     71         while ((ref = (SoftValueRef)queue.poll()) != null) {
     72             if (ref == (SoftValueRef)hash.get(ref.key)) {
     73                 // only remove if it is the *exact* same WeakValueRef
     74                 //
     75                 hash.remove(ref.key);
     76             }
     77         }
     78     }
     79 
     80     /* -- Constructors -- */
     81 
     82     /**
     83      * Constructs a new, empty <code>WeakHashMap</code> with the given initial
     84      * capacity and the given load factor.
     85      *
     86      * @param initialCapacity
     87      *            The initial capacity of the <code>WeakHashMap</code>
     88      *
     89      * @param loadFactor
     90      *            The load factor of the <code>WeakHashMap</code>
     91      *
     92      * @throws IllegalArgumentException
     93      *             If the initial capacity is less than zero, or if the load
     94      *             factor is nonpositive
     95      */
     96     public SoftValueHashMap(int initialCapacity, float loadFactor) {
     97         hash = new HashMap(initialCapacity, loadFactor);
     98     }
     99 
    100     /**
    101      * Constructs a new, empty <code>WeakHashMap</code> with the given initial
    102      * capacity and the default load factor, which is <code>0.75</code>.
    103      *
    104      * @param initialCapacity
    105      *            The initial capacity of the <code>WeakHashMap</code>
    106      *
    107      * @throws IllegalArgumentException
    108      *             If the initial capacity is less than zero
    109      */
    110     public SoftValueHashMap(int initialCapacity) {
    111         hash = new HashMap(initialCapacity);
    112     }
    113 
    114     /**
    115      * Constructs a new, empty <code>WeakHashMap</code> with the default
    116      * initial capacity and the default load factor, which is <code>0.75</code>.
    117      */
    118     public SoftValueHashMap() {
    119         hash = new HashMap();
    120     }
    121 
    122     /**
    123      * Constructs a new <code>WeakHashMap</code> with the same mappings as the
    124      * specified <tt>Map</tt>. The <code>WeakHashMap</code> is created with
    125      * an initial capacity of twice the number of mappings in the specified map
    126      * or 11 (whichever is greater), and a default load factor, which is
    127      * <tt>0.75</tt>.
    128      *
    129      * @param t     the map whose mappings are to be placed in this map.
    130      */
    131     public SoftValueHashMap(Map t) {
    132         this(Math.max(2 * t.size(), 11), 0.75f);
    133         putAll(t);
    134     }
    135 
    136     /* -- Simple queries -- */
    137 
    138     /**
    139      * Returns the number of key-value mappings in this map. <strong>Note:</strong>
    140      * <em>In contrast with most implementations of the
    141      * <code>Map</code> interface, the time required by this operation is
    142      * linear in the size of the map.</em>
    143      */
    144     public int size() {
    145         processQueue();
    146         return hash.size();
    147     }
    148 
    149     /**
    150      * Returns <code>true</code> if this map contains no key-value mappings.
    151      */
    152     public boolean isEmpty() {
    153         processQueue();
    154         return hash.isEmpty();
    155     }
    156 
    157     /**
    158      * Returns <code>true</code> if this map contains a mapping for the
    159      * specified key.
    160      *
    161      * @param key
    162      *            The key whose presence in this map is to be tested.
    163      */
    164     public boolean containsKey(Object key) {
    165         processQueue();
    166         return hash.containsKey(key);
    167     }
    168 
    169     /* -- Lookup and modification operations -- */
    170 
    171     /**
    172      * Returns the value to which this map maps the specified <code>key</code>.
    173      * If this map does not contain a value for this key, then return
    174      * <code>null</code>.
    175      *
    176      * @param key
    177      *            The key whose associated value, if any, is to be returned.
    178      */
    179     public Object get(Object key) {
    180         processQueue();
    181         SoftReference ref = (SoftReference)hash.get(key);
    182         if (ref != null)
    183             return ref.get();
    184         return null;
    185     }
    186 
    187     /**
    188      * Updates this map so that the given <code>key</code> maps to the given
    189      * <code>value</code>. If the map previously contained a mapping for
    190      * <code>key</code> then that mapping is replaced and the previous value
    191      * is returned.
    192      *
    193      * @param key
    194      *            The key that is to be mapped to the given <code>value</code>
    195      * @param value
    196      *            The value to which the given <code>key</code> is to be
    197      *            mapped
    198      *
    199      * @return The previous value to which this key was mapped, or
    200      *         <code>null</code> if if there was no mapping for the key
    201      */
    202     public Object put(Object key, Object value) {
    203         processQueue();
    204         Object rtn = hash.put(key, SoftValueRef.create(key, value, queue));
    205         if (rtn != null)
    206             rtn = ((SoftReference)rtn).get();
    207         return rtn;
    208     }
    209 
    210     /**
    211      * Removes the mapping for the given <code>key</code> from this map, if
    212      * present.
    213      *
    214      * @param key
    215      *            The key whose mapping is to be removed.
    216      *
    217      * @return The value to which this key was mapped, or <code>null</code> if
    218      *         there was no mapping for the key.
    219      */
    220     public Object remove(Object key) {
    221         processQueue();
    222         return hash.remove(key);
    223     }
    224 
    225     /**
    226      * Removes all mappings from this map.
    227      */
    228     public void clear() {
    229         processQueue();
    230         hash.clear();
    231     }
    232 }
    233