123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later,
- * or the Apache License Version 2.0.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
- package javassist.scopedpool;
-
- import java.lang.ref.ReferenceQueue;
- import java.lang.ref.SoftReference;
- import java.util.AbstractMap.SimpleImmutableEntry;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashSet;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.concurrent.ConcurrentHashMap;
-
- /**
- * This Map will remove entries when the value in the map has been cleaned from
- * garbage collection
- *
- * @version <code>$Revision: 1.4 $</code>
- * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
- */
- public class SoftValueHashMap<K,V> implements Map<K,V> {
- private static class SoftValueRef<K,V> extends SoftReference<V> {
- public K key;
-
- private SoftValueRef(K key, V val, ReferenceQueue<V> q) {
- super(val, q);
- this.key = key;
- }
-
- private static <K,V> SoftValueRef<K,V> create(
- K key, V val, ReferenceQueue<V> q) {
- if (val == null)
- return null;
- else
- return new SoftValueRef<K,V>(key, val, q);
- }
-
- }
-
- /**
- * Returns a set of the mappings contained in this hash table.
- */
- @Override
- public Set<Map.Entry<K, V>> entrySet() {
- processQueue();
- Set<Entry<K,V>> ret = new HashSet<Entry<K,V>>();
- for (Entry<K,SoftValueRef<K,V>> e:hash.entrySet())
- ret.add(new SimpleImmutableEntry<K,V> (
- e.getKey(), e.getValue().get()));
- return ret;
- }
-
- /* Hash table mapping WeakKeys to values */
- private Map<K,SoftValueRef<K,V>> hash;
-
- /* Reference queue for cleared WeakKeys */
- private ReferenceQueue<V> queue = new ReferenceQueue<V>();
-
- /*
- * Remove all invalidated entries from the map, that is, remove all entries
- * whose values have been discarded.
- */
- private void processQueue() {
- Object ref;
- if (!hash.isEmpty())
- while ((ref = queue.poll()) != null)
- if (ref instanceof SoftValueRef) {
- @SuppressWarnings("rawtypes")
- SoftValueRef que =(SoftValueRef) ref;
- if (ref == hash.get(que.key))
- // only remove if it is the *exact* same SoftValueRef
- hash.remove(que.key);
- }
- }
-
- /* -- Constructors -- */
-
- /**
- * Constructs a new, empty <code>WeakHashMap</code> with the given initial
- * capacity and the given load factor.
- *
- * @param initialCapacity
- * The initial capacity of the <code>WeakHashMap</code>
- *
- * @param loadFactor
- * The load factor of the <code>WeakHashMap</code>
- *
- * @throws IllegalArgumentException
- * If the initial capacity is less than zero, or if the load
- * factor is nonpositive
- */
- public SoftValueHashMap(int initialCapacity, float loadFactor) {
- hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>(initialCapacity, loadFactor);
- }
-
- /**
- * Constructs a new, empty <code>WeakHashMap</code> with the given initial
- * capacity and the default load factor, which is <code>0.75</code>.
- *
- * @param initialCapacity
- * The initial capacity of the <code>WeakHashMap</code>
- *
- * @throws IllegalArgumentException
- * If the initial capacity is less than zero
- */
- public SoftValueHashMap(int initialCapacity) {
- hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>(initialCapacity);
- }
-
- /**
- * Constructs a new, empty <code>WeakHashMap</code> with the default
- * initial capacity and the default load factor, which is <code>0.75</code>.
- */
- public SoftValueHashMap() {
- hash = new ConcurrentHashMap<K,SoftValueRef<K,V>>();
- }
-
- /**
- * Constructs a new <code>WeakHashMap</code> with the same mappings as the
- * specified <code>Map</code>. The <code>WeakHashMap</code> is created with
- * an initial capacity of twice the number of mappings in the specified map
- * or 11 (whichever is greater), and a default load factor, which is
- * <code>0.75</code>.
- *
- * @param t the map whose mappings are to be placed in this map.
- */
- public SoftValueHashMap(Map<K,V> t) {
- this(Math.max(2 * t.size(), 11), 0.75f);
- putAll(t);
- }
-
- /* -- Simple queries -- */
-
- /**
- * Returns the number of key-value mappings in this map. <strong>Note:</strong>
- * <em>In contrast with most implementations of the
- * <code>Map</code> interface, the time required by this operation is
- * linear in the size of the map.</em>
- */
- @Override
- public int size() {
- processQueue();
- return hash.size();
- }
-
- /**
- * Returns <code>true</code> if this map contains no key-value mappings.
- */
- @Override
- public boolean isEmpty() {
- processQueue();
- return hash.isEmpty();
- }
-
- /**
- * Returns <code>true</code> if this map contains a mapping for the
- * specified key.
- *
- * @param key
- * The key whose presence in this map is to be tested.
- */
- @Override
- public boolean containsKey(Object key) {
- processQueue();
- return hash.containsKey(key);
- }
-
- /* -- Lookup and modification operations -- */
-
- /**
- * Returns the value to which this map maps the specified <code>key</code>.
- * If this map does not contain a value for this key, then return
- * <code>null</code>.
- *
- * @param key
- * The key whose associated value, if any, is to be returned.
- */
- @Override
- public V get(Object key) {
- processQueue();
- return valueOrNull(hash.get(key));
- }
-
- /**
- * Updates this map so that the given <code>key</code> maps to the given
- * <code>value</code>. If the map previously contained a mapping for
- * <code>key</code> then that mapping is replaced and the previous value
- * is returned.
- *
- * @param key
- * The key that is to be mapped to the given <code>value</code>
- * @param value
- * The value to which the given <code>key</code> is to be
- * mapped
- *
- * @return The previous value to which this key was mapped, or
- * <code>null</code> if if there was no mapping for the key
- */
- @Override
- public V put(K key, V value) {
- processQueue();
- return valueOrNull(hash.put(key, SoftValueRef.create(key, value, queue)));
- }
-
- /**
- * Removes the mapping for the given <code>key</code> from this map, if
- * present.
- *
- * @param key
- * The key whose mapping is to be removed.
- *
- * @return The value to which this key was mapped, or <code>null</code> if
- * there was no mapping for the key.
- */
- @Override
- public V remove(Object key) {
- processQueue();
- return valueOrNull(hash.remove(key));
- }
-
- /**
- * Removes all mappings from this map.
- */
- @Override
- public void clear() {
- processQueue();
- hash.clear();
- }
-
- /*
- * Check whether the supplied value exists.
- * @param Object the value to compare.
- * @return true if it was found or null.
- */
- @Override
- public boolean containsValue(Object arg0) {
- processQueue();
- if (null == arg0)
- return false;
-
- for (SoftValueRef<K,V> e:hash.values())
- if (null != e && arg0.equals(e.get()))
- return true;
- return false;
- }
-
- /* {@inheritDoc} */
- @Override
- public Set<K> keySet() {
- processQueue();
- return hash.keySet();
- }
-
- /* {@inheritDoc} */
- @Override
- public void putAll(Map<? extends K,? extends V> arg0) {
- processQueue();
- for (K key:arg0.keySet())
- put(key, arg0.get(key));
- }
-
- /* {@inheritDoc} */
- @Override
- public Collection<V> values() {
- processQueue();
- List<V> ret = new ArrayList<V>();
- for (SoftValueRef<K,V> e:hash.values())
- ret.add(e.get());
- return ret;
- }
-
- private V valueOrNull(SoftValueRef<K,V> rtn) {
- if (null == rtn)
- return null;
- return rtn.get();
- }
- }
|