169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* 269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit. 369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version 669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with 769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License. Alternatively, the contents of this file may be used under 869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later. 969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis, 1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the 1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License. 1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.scopedpool; 1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.ref.ReferenceQueue; 1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.lang.ref.SoftReference; 2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.AbstractMap; 2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.HashMap; 2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Map; 2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Set; 2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/** 2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * This Map will remove entries when the value in the map has been cleaned from 2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * garbage collection 2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @version <tt>$Revision: 1.4 $</tt> 3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author <a href="mailto:bill@jboss.org">Bill Burke</a> 3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class SoftValueHashMap extends AbstractMap implements Map { 3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static class SoftValueRef extends SoftReference { 3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Object key; 3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private SoftValueRef(Object key, Object val, ReferenceQueue q) { 3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal super(val, q); 3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.key = key; 3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static SoftValueRef create(Object key, Object val, 4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal ReferenceQueue q) { 4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (val == null) 4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return null; 4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal else 4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return new SoftValueRef(key, val, q); 4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns a set of the mappings contained in this hash table. 5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Set entrySet() { 5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal processQueue(); 5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return hash.entrySet(); 5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* Hash table mapping WeakKeys to values */ 6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private Map hash; 6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* Reference queue for cleared WeakKeys */ 6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private ReferenceQueue queue = new ReferenceQueue(); 6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* 6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Remove all invalidated entries from the map, that is, remove all entries 6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * whose values have been discarded. 6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private void processQueue() { 7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal SoftValueRef ref; 7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal while ((ref = (SoftValueRef)queue.poll()) != null) { 7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (ref == (SoftValueRef)hash.get(ref.key)) { 7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // only remove if it is the *exact* same WeakValueRef 7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // 7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal hash.remove(ref.key); 7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* -- Constructors -- */ 8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Constructs a new, empty <code>WeakHashMap</code> with the given initial 8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * capacity and the given load factor. 8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param initialCapacity 8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The initial capacity of the <code>WeakHashMap</code> 8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param loadFactor 9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The load factor of the <code>WeakHashMap</code> 9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @throws IllegalArgumentException 9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If the initial capacity is less than zero, or if the load 9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * factor is nonpositive 9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public SoftValueHashMap(int initialCapacity, float loadFactor) { 9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal hash = new HashMap(initialCapacity, loadFactor); 9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Constructs a new, empty <code>WeakHashMap</code> with the given initial 10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * capacity and the default load factor, which is <code>0.75</code>. 10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param initialCapacity 10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The initial capacity of the <code>WeakHashMap</code> 10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @throws IllegalArgumentException 10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If the initial capacity is less than zero 10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public SoftValueHashMap(int initialCapacity) { 11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal hash = new HashMap(initialCapacity); 11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Constructs a new, empty <code>WeakHashMap</code> with the default 11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * initial capacity and the default load factor, which is <code>0.75</code>. 11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public SoftValueHashMap() { 11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal hash = new HashMap(); 12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Constructs a new <code>WeakHashMap</code> with the same mappings as the 12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * specified <tt>Map</tt>. The <code>WeakHashMap</code> is created with 12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * an initial capacity of twice the number of mappings in the specified map 12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * or 11 (whichever is greater), and a default load factor, which is 12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <tt>0.75</tt>. 12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param t the map whose mappings are to be placed in this map. 13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public SoftValueHashMap(Map t) { 13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this(Math.max(2 * t.size(), 11), 0.75f); 13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal putAll(t); 13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* -- Simple queries -- */ 13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns the number of key-value mappings in this map. <strong>Note:</strong> 14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <em>In contrast with most implementations of the 14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>Map</code> interface, the time required by this operation is 14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * linear in the size of the map.</em> 14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public int size() { 14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal processQueue(); 14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return hash.size(); 14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns <code>true</code> if this map contains no key-value mappings. 15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean isEmpty() { 15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal processQueue(); 15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return hash.isEmpty(); 15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns <code>true</code> if this map contains a mapping for the 15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * specified key. 16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param key 16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The key whose presence in this map is to be tested. 16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public boolean containsKey(Object key) { 16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal processQueue(); 16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return hash.containsKey(key); 16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /* -- Lookup and modification operations -- */ 17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns the value to which this map maps the specified <code>key</code>. 17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If this map does not contain a value for this key, then return 17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>null</code>. 17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param key 17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The key whose associated value, if any, is to be returned. 17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Object get(Object key) { 18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal processQueue(); 18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal SoftReference ref = (SoftReference)hash.get(key); 18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (ref != null) 18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return ref.get(); 18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return null; 18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 18869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Updates this map so that the given <code>key</code> maps to the given 18969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>value</code>. If the map previously contained a mapping for 19069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>key</code> then that mapping is replaced and the previous value 19169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * is returned. 19269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 19369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param key 19469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The key that is to be mapped to the given <code>value</code> 19569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param value 19669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The value to which the given <code>key</code> is to be 19769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * mapped 19869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 19969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return The previous value to which this key was mapped, or 20069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>null</code> if if there was no mapping for the key 20169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 20269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Object put(Object key, Object value) { 20369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal processQueue(); 20469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal Object rtn = hash.put(key, SoftValueRef.create(key, value, queue)); 20569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (rtn != null) 20669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal rtn = ((SoftReference)rtn).get(); 20769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return rtn; 20869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 20969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 21069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 21169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Removes the mapping for the given <code>key</code> from this map, if 21269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * present. 21369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 21469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param key 21569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The key whose mapping is to be removed. 21669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 21769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return The value to which this key was mapped, or <code>null</code> if 21869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * there was no mapping for the key. 21969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 22069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public Object remove(Object key) { 22169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal processQueue(); 22269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return hash.remove(key); 22369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 22469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 22569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 22669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Removes all mappings from this map. 22769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 22869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public void clear() { 22969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal processQueue(); 23069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal hash.clear(); 23169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 23269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal} 233