
de.tsl2.nano.collection.ReferenceMap Maven / Gradle / Ivy
/*
* File: $HeadURL$
* Id : $Id$
*
* created by: Tom
* created on: 26.12.2013
*
* Copyright: (c) Thomas Schneider 2013, all rights reserved
*/
package de.tsl2.nano.collection;
/**
* Simple HashMap holding it's values as Soft- or Weak References. To have weak references on keys, use java's WeakHashMap.
* @author Tom
* @version $Revision$
*/
import java.io.Serializable;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
public class ReferenceMap extends AbstractMap
implements Serializable {
/** serialVersionUID */
private static final long serialVersionUID = 1L;
/** internal HashMap holding the Reference. */
private final Map> hash =
new HashMap>();
private final Map, K> reverseLookup =
new HashMap, K>();
/** Reference queue for cleared Reference objects. */
transient private final ReferenceQueue queue = new ReferenceQueue();
private boolean weak = true;
/**
* hashmap as weak map
*/
public ReferenceMap() {
this(true);
}
/**
* constructor
* @param weak if false, {@link SoftReference}s will be used on it's values.
*/
public ReferenceMap(boolean weak) {
super();
this.weak = weak;
}
/**
* creates a reference using {@link #weak} to instantiate {@link WeakReference} or {@link SoftReference}.
*
* @param value value
* @param queue queue
* @return new {@link Reference} instance
*/
protected Reference createReference(V value, ReferenceQueue queue) {
return weak ? new WeakReference(value, queue) : new SoftReference(value, queue);
}
@Override
public V get(Object key) {
expungeStaleEntries();
V result = null;
// We get the Reference represented by that key
Reference soft_ref = hash.get(key);
if (soft_ref != null) {
// From the Reference we get the value, which can be
// null if it has been garbage collected
result = soft_ref.get();
if (result == null) {
// If the value has been garbage collected, remove the
// entry from the HashMap.
hash.remove(key);
reverseLookup.remove(soft_ref);
}
}
return result;
}
private void expungeStaleEntries() {
Reference extends V> sv;
while ((sv = queue.poll()) != null) {
hash.remove(reverseLookup.remove(sv));
}
}
@Override
public V put(K key, V value) {
expungeStaleEntries();
Reference soft_ref = createReference(value, queue);
reverseLookup.put(soft_ref, key);
Reference result = hash.put(key, soft_ref);
if (result == null) {
return null;
}
reverseLookup.remove(result);
return result.get();
}
@Override
public V remove(Object key) {
expungeStaleEntries();
Reference result = hash.remove(key);
if (result == null) {
return null;
}
return result.get();
}
@Override
public void clear() {
hash.clear();
reverseLookup.clear();
}
@Override
public int size() {
expungeStaleEntries();
return hash.size();
}
/**
* Returns a copy of the key/values in the map at the point of calling. However, setValue still sets the value in
* the actual HashMap.
*/
@Override
public Set> entrySet() {
expungeStaleEntries();
Set> result = new LinkedHashSet>();
for (final Entry> entry : hash.entrySet()) {
final V value = entry.getValue().get();
if (value != null) {
result.add(new Entry() {
@Override
public K getKey() {
return entry.getKey();
}
@Override
public V getValue() {
return value;
}
@Override
public V setValue(V v) {
entry.setValue(createReference(v, queue));
return value;
}
});
}
}
return result;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy