/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
/**
* An implementation of Set that manages a map of soft references to the set
* values. The map is keyed by the value hashCode and so this is only useful for
* value whose hashCode is a valid identity representation (String, primative
* wrappers, etc).
*
* @author Scott.Stark@jboss.org
* @version $Revision: 2787 $
*/
@SuppressWarnings("unchecked")
public class SoftSet implements Set {
private HashMap map = new HashMap();
/** The queue of garbage collected soft references */
private ReferenceQueue gcqueue = new ReferenceQueue();
static class ComparableSoftReference extends SoftReference {
private Integer key;
ComparableSoftReference(Integer key, Object o, ReferenceQueue q) {
super(o, q);
this.key = key;
}
Integer getKey() {
return key;
}
}
static class ComparableSoftReferenceIterator implements Iterator {
Iterator theIter;
ComparableSoftReferenceIterator(Iterator theIter) {
this.theIter = theIter;
}
public boolean hasNext() {
return theIter.hasNext();
}
public Object next() {
ComparableSoftReference csr = (ComparableSoftReference) theIter.next();
return csr.get();
}
public void remove() {
theIter.remove();
}
}
/**
*
*/
public SoftSet() {
}
public int size() {
processQueue();
return map.size();
}
public boolean isEmpty() {
processQueue();
return map.isEmpty();
}
public boolean contains(Object o) {
processQueue();
Integer key = new Integer(o.hashCode());
boolean contains = map.containsKey(key);
return contains;
}
public Iterator iterator() {
processQueue();
Iterator theIter = map.values().iterator();
return new ComparableSoftReferenceIterator(theIter);
}
public Object[] toArray() {
processQueue();
return toArray(new Object[0]);
}
public Object[] toArray(Object[] a) {
processQueue();
int size = map.size();
Object[] array = {};
if (a.length >= size)
array = a;
Iterator iter = map.values().iterator();
int index = 0;
while (iter.hasNext()) {
ComparableSoftReference csr = (ComparableSoftReference) iter.next();
Object value = csr.get();
// Create the correct array type
if (array.length == 0) {
if (value == null) {
index++;
continue;
}
Array.newInstance(value.getClass(), size);
}
array[index] = value;
index++;
}
return array;
}
public boolean add(Object o) {
processQueue();
Integer key = new Integer(o.hashCode());
ComparableSoftReference sr = new ComparableSoftReference(key, o, gcqueue);
return map.put(key, sr) == null;
}
public boolean remove(Object o) {
processQueue();
Integer key = new Integer(o.hashCode());
return map.remove(key) != null;
}
public boolean containsAll(Collection c) {
processQueue();
Iterator iter = c.iterator();
boolean contains = true;
while (iter.hasNext()) {
Object value = iter.next();
Integer key = new Integer(value.hashCode());
contains &= map.containsKey(key);
}
return contains;
}
public boolean addAll(Collection c) {
processQueue();
Iterator iter = c.iterator();
boolean added = false;
while (iter.hasNext()) {
Object value = iter.next();
Integer key = new Integer(value.hashCode());
ComparableSoftReference sr = new ComparableSoftReference(key, value, gcqueue);
added |= map.put(key, sr) == null;
}
return added;
}
public boolean retainAll(Collection c) {
Iterator iter = iterator();
boolean removed = false;
while (iter.hasNext()) {
Object value = iter.next();
if (c.contains(value) == false) {
iter.remove();
removed = true;
}
}
return removed;
}
public boolean removeAll(Collection c) {
processQueue();
Iterator iter = c.iterator();
boolean removed = false;
while (iter.hasNext()) {
Object value = iter.next();
removed |= remove(value);
}
return removed;
}
public void clear() {
while (gcqueue.poll() != null)
;
map.clear();
}
public boolean equals(Object o) {
return map.equals(o);
}
public int hashCode() {
return map.hashCode();
}
/**
* Iterate through the gcqueue for for any cleared reference, remove the
* associated value from the underlying set.
*/
private void processQueue() {
ComparableSoftReference cr;
while ((cr = (ComparableSoftReference) gcqueue.poll()) != null) {
map.remove(cr.getKey());
}
}
}