javassist.scopedpool.SoftValueHashMap Maven / Gradle / Ivy
The newest version!
/*
* 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 $Revision: 1.4 $
* @author Bill Burke
*/
public class SoftValueHashMap implements Map {
private static class SoftValueRef extends SoftReference {
public K key;
private SoftValueRef(K key, V val, ReferenceQueue q) {
super(val, q);
this.key = key;
}
private static SoftValueRef create(
K key, V val, ReferenceQueue q) {
if (val == null)
return null;
else
return new SoftValueRef(key, val, q);
}
}
/**
* Returns a set of the mappings contained in this hash table.
*/
@Override
public Set> entrySet() {
processQueue();
Set> ret = new HashSet>();
for (Entry> e:hash.entrySet())
ret.add(new SimpleImmutableEntry (
e.getKey(), e.getValue().get()));
return ret;
}
/* Hash table mapping WeakKeys to values */
private Map> hash;
/* Reference queue for cleared WeakKeys */
private ReferenceQueue queue = new ReferenceQueue();
/*
* 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 WeakHashMap
with the given initial
* capacity and the given load factor.
*
* @param initialCapacity
* The initial capacity of the WeakHashMap
*
* @param loadFactor
* The load factor of the WeakHashMap
*
* @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>(initialCapacity, loadFactor);
}
/**
* Constructs a new, empty WeakHashMap
with the given initial
* capacity and the default load factor, which is 0.75
.
*
* @param initialCapacity
* The initial capacity of the WeakHashMap
*
* @throws IllegalArgumentException
* If the initial capacity is less than zero
*/
public SoftValueHashMap(int initialCapacity) {
hash = new ConcurrentHashMap>(initialCapacity);
}
/**
* Constructs a new, empty WeakHashMap
with the default
* initial capacity and the default load factor, which is 0.75
.
*/
public SoftValueHashMap() {
hash = new ConcurrentHashMap>();
}
/**
* Constructs a new WeakHashMap
with the same mappings as the
* specified Map
. The WeakHashMap
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
* 0.75
.
*
* @param t the map whose mappings are to be placed in this map.
*/
public SoftValueHashMap(Map t) {
this(Math.max(2 * t.size(), 11), 0.75f);
putAll(t);
}
/* -- Simple queries -- */
/**
* Returns the number of key-value mappings in this map. Note:
* In contrast with most implementations of the
* Map
interface, the time required by this operation is
* linear in the size of the map.
*/
@Override
public int size() {
processQueue();
return hash.size();
}
/**
* Returns true
if this map contains no key-value mappings.
*/
@Override
public boolean isEmpty() {
processQueue();
return hash.isEmpty();
}
/**
* Returns true
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 key
.
* If this map does not contain a value for this key, then return
* null
.
*
* @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 key
maps to the given
* value
. If the map previously contained a mapping for
* key
then that mapping is replaced and the previous value
* is returned.
*
* @param key
* The key that is to be mapped to the given value
* @param value
* The value to which the given key
is to be
* mapped
*
* @return The previous value to which this key was mapped, or
* null
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 key
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 null
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 e:hash.values())
if (null != e && arg0.equals(e.get()))
return true;
return false;
}
/* {@inheritDoc} */
@Override
public Set 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 values() {
processQueue();
List ret = new ArrayList();
for (SoftValueRef e:hash.values())
ret.add(e.get());
return ret;
}
private V valueOrNull(SoftValueRef rtn) {
if (null == rtn)
return null;
return rtn.get();
}
}