net.sf.extcos.internal.RandomPollingArraySet Maven / Gradle / Ivy
package net.sf.extcos.internal;
import java.util.Collection;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Random;
import net.sf.extcos.collection.RandomPollingSet;
import net.sf.extcos.exception.UnsuccessfulOperationException;
/**
* Resizable-array implementation of the RandomPollingSet interface.
* Implements all optional Collection operations, and permits all elements,
* excluding null.
*
* In addition to implementing the RandomPollingSet interface,
* this class provides methods to manipulate the size of the array of the
* ArrayList that is used internally to store the set.
*
* The size, isEmpty, get, set,
* and iterator operations run in constant time. The add
* operation runs in amortized constant time, that is, adding n elements
* requires O(n) time. All of the other operations run in linear time (roughly
* speaking).
*
* The ArrayList instance of each RandomPollingArraySet
* instance has a capacity. The capacity is the size of the array
* used to store the elements of the set. It is always at least as large as
* the set size. As elements are added to a RandomPollingArraySet,
* its capacity grows automatically. The details of the growth policy are
* not specified beyond the fact that adding an element has constant
* amortized time cost.
*
* An application can increase the capacity of a RandomPollingArraySet
* instance before adding a large number of elements using the
* ensureCapacity operation. This may reduce the amount of
* incremental reallocation.
*
*
Note that this implementation is not synchronized.
* If multiple threads access a RandomPollingArraySet instance
* concurrently, and at least one of the threads modifies the set
* structurally, it must be synchronized externally. (A structural
* modification is any operation that adds or deletes one or more elements,
* or explicitly resizes the array of the backing ArrayList; merely
* setting the value of an element is not a structural modification.) This
* is typically accomplished by synchronizing on some object that naturally
* encapsulates the set.
*
* If no such object exists, the set should be "wrapped" using the
* {@link Collections#synchronizedSet Collections.synchronizedSet}
* method. This is best done at creation time, to prevent accidental
* unsynchronized access to the set:
* Set set = Collections.synchronizedSet(new ArraySet(...));
*
* The iterator returned by this class's iterator method is
* not fail-fast: changes of any kind to the set will not result
* in a {@link ConcurrentModificationException} being thrown. Therefore
* the iterator does risk arbitrary, non-deterministic behavior at an
* undetermined time in the future. This is acceptable because any iteration
* over this set is non-deterministic anyhow.
*
* @author Matthias Rothe
* @see Collection
* @see RandomPollingSet
* @see ArraySet
*/
public class RandomPollingArraySet extends ArraySet implements
RandomPollingSet {
private static final long serialVersionUID = -5304262039454673339L;
private class Itr implements Iterator {
private RandomPollingArraySet workingCopy;
@Override
public boolean hasNext() {
return workingCopy.size() > 0;
}
@Override
public E next() {
if (hasNext()) {
return workingCopy.pollRandom();
}
throw new NoSuchElementException();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
* Constructs an empty set with an initial capacity of ten.
*/
public RandomPollingArraySet(){
}
/**
* Constructs an empty set with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the set
* @throws IllegalArgumentException if the specified initial capacity is negative
*/
public RandomPollingArraySet(final int initialCapacity){
super(initialCapacity);
}
/**
* Constructs a set containing the unique elements of the specified
* collection, in the order they are returned by the collection's iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public RandomPollingArraySet(final Collection c){
super(c);
}
/*
* (non-Javadoc)
* @see java.util.AbstractCollection#iterator()
*/
@Override
public Iterator iterator(){
RandomPollingArraySet workingCopy = new RandomPollingArraySet();
for (int i = 0; i < size(); i++) {
workingCopy.add(get(i));
}
Itr itr = new Itr();
itr.workingCopy = workingCopy;
return itr;
}
/*
* (non-Javadoc)
* @see org.jcs.collection.RandomPollingSet#pollRandom()
*/
@Override
public E pollRandom() {
int size = size();
if (size == 0) {
throw new UnsuccessfulOperationException();
} else if(size == 1) {
return remove(0);
} else {
Random prng = new Random();
double d = prng.nextDouble() * size;
return remove((int)d == size ? size - 1 : (int)Math.floor(d));
}
}
}