• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
SoftValueRef(Object key, Object val, ReferenceQueue q)36         private SoftValueRef(Object key, Object val, ReferenceQueue q) {
37             super(val, q);
38             this.key = key;
39         }
40 
create(Object key, Object val, ReferenceQueue q)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      */
entrySet()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      */
processQueue()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      */
SoftValueHashMap(int initialCapacity, float loadFactor)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      */
SoftValueHashMap(int initialCapacity)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      */
SoftValueHashMap()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      */
SoftValueHashMap(Map t)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      */
size()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      */
isEmpty()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      */
containsKey(Object key)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      */
get(Object key)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      */
put(Object key, Object value)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      */
remove(Object key)220     public Object remove(Object key) {
221         processQueue();
222         return hash.remove(key);
223     }
224 
225     /**
226      * Removes all mappings from this map.
227      */
clear()228     public void clear() {
229         processQueue();
230         hash.clear();
231     }
232 }
233