You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SoftValueHashMap.java 7.1KB

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