forked from I2P_Developers/i2p.i2p
ArraySet implementation
This commit is contained in:
281
router/java/src/net/i2p/router/util/ArraySet.java
Normal file
281
router/java/src/net/i2p/router/util/ArraySet.java
Normal file
@@ -0,0 +1,281 @@
|
||||
package net.i2p.router.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A small, fast Set with a maximum size, backed by a fixed-size array.
|
||||
* Unsynchronized, not thread-safe.
|
||||
* Null elements are not permitted.
|
||||
* Not appropriate for large Sets.
|
||||
*
|
||||
* @since 0.9.25
|
||||
*/
|
||||
public class ArraySet<E> extends AbstractSet<E> implements Set<E> {
|
||||
public static final int MAX_CAPACITY = 32;
|
||||
private final Object[] _entries;
|
||||
private final boolean _throwOnFull;
|
||||
private int _size;
|
||||
private int _overflowIndex;
|
||||
private transient int modCount;
|
||||
|
||||
/**
|
||||
* A fixed capacity of MAX_CAPACITY.
|
||||
* Adds over capacity will throw a SetFullException.
|
||||
*/
|
||||
public ArraySet() {
|
||||
this(MAX_CAPACITY);
|
||||
}
|
||||
|
||||
/**
|
||||
* A fixed capacity of MAX_CAPACITY.
|
||||
* Adds over capacity will throw a SetFullException.
|
||||
* @throws SetFullException if more than MAX_CAPACITY unique elements in c.
|
||||
*/
|
||||
public ArraySet(Collection<? extends E> c) {
|
||||
this();
|
||||
addAll(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds over capacity will throw a SetFullException.
|
||||
*
|
||||
* @param capacity the maximum size
|
||||
* @throws IllegalArgumentException if capacity less than 1 or more than MAX_CAPACITY.
|
||||
*/
|
||||
public ArraySet(int capacity) {
|
||||
this(capacity, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* If throwOnFull is false,
|
||||
* adds over capacity will overwrite starting at slot zero.
|
||||
* This breaks the AbstractCollection invariant that
|
||||
* "a Collection will always contain the specified element after add() returns",
|
||||
* but it prevents unexpected exceptions.
|
||||
* If throwOnFull is true, adds over capacity will throw a SetFullException.
|
||||
*
|
||||
* @param capacity the maximum size
|
||||
* @throws IllegalArgumentException if capacity less than 1 or more than MAX_CAPACITY.
|
||||
*/
|
||||
public ArraySet(int capacity, boolean throwOnFull) {
|
||||
if (capacity <= 0 || capacity > MAX_CAPACITY)
|
||||
throw new IllegalArgumentException("bad capacity");
|
||||
_entries = new Object[capacity];
|
||||
_throwOnFull = throwOnFull;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return -1 if not found or if o is null
|
||||
*/
|
||||
private int indexOf(Object o) {
|
||||
if (o != null) {
|
||||
for (int i = 0; i < _size; i++) {
|
||||
if (o.equals(_entries[i]))
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws SetFullException if throwOnFull was true in constructor
|
||||
* @throws NullPointerException if o is null
|
||||
*/
|
||||
@Override
|
||||
public boolean add(E o) {
|
||||
if (o == null)
|
||||
throw new NullPointerException();
|
||||
int i = indexOf(o);
|
||||
if (i >= 0) {
|
||||
_entries[i] = o;
|
||||
return false;
|
||||
}
|
||||
if (_size >= _entries.length) {
|
||||
if (_throwOnFull)
|
||||
throw new SetFullException();
|
||||
i = _overflowIndex++;
|
||||
if (i >= _entries.length) {
|
||||
i = 0;
|
||||
_overflowIndex = 0;
|
||||
}
|
||||
} else {
|
||||
modCount++;
|
||||
i = _size++;
|
||||
}
|
||||
_entries[i] = o;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (_size != 0) {
|
||||
modCount++;
|
||||
for (int i = 0; i < _size; i++) {
|
||||
_entries[i] = null;
|
||||
}
|
||||
_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return indexOf(o) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return _size <= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
int i = indexOf(o);
|
||||
if (i < 0)
|
||||
return false;
|
||||
modCount++;
|
||||
_size--;
|
||||
for (int j = i; j < _size; j++) {
|
||||
_entries[j] = _entries[j + 1];
|
||||
}
|
||||
_entries[_size] = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return _size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supports remove.
|
||||
* Supports comodification checks.
|
||||
*/
|
||||
public Iterator<E> iterator() {
|
||||
return new ASIterator();
|
||||
}
|
||||
|
||||
public static class SetFullException extends IllegalStateException {
|
||||
private static final long serialVersionUID = 9087390587254111L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modified from CachedIteratorArrayList
|
||||
*/
|
||||
private class ASIterator implements Iterator<E>, Serializable {
|
||||
/**
|
||||
* Index of element to be returned by subsequent call to next.
|
||||
*/
|
||||
int cursor = 0;
|
||||
|
||||
/**
|
||||
* Index of element returned by most recent call to next or
|
||||
* previous. Reset to -1 if this element is deleted by a call
|
||||
* to remove.
|
||||
*/
|
||||
int lastRet = -1;
|
||||
|
||||
/**
|
||||
* The modCount value that the iterator believes that the backing
|
||||
* List should have. If this expectation is violated, the iterator
|
||||
* has detected concurrent modification.
|
||||
*/
|
||||
int expectedModCount = modCount;
|
||||
|
||||
public boolean hasNext() {
|
||||
return cursor != _size;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public E next() {
|
||||
checkForComodification();
|
||||
try {
|
||||
int i = cursor;
|
||||
E next = (E) _entries[i];
|
||||
lastRet = i;
|
||||
cursor = i + 1;
|
||||
return next;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
checkForComodification();
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (lastRet < 0)
|
||||
throw new IllegalStateException();
|
||||
checkForComodification();
|
||||
|
||||
try {
|
||||
ArraySet.this.remove(lastRet);
|
||||
if (lastRet < cursor)
|
||||
cursor--;
|
||||
lastRet = -1;
|
||||
expectedModCount = modCount;
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
|
||||
final void checkForComodification() {
|
||||
if (modCount != expectedModCount)
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* About 3x faster than HashSet.
|
||||
*/
|
||||
/****
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public static void main(String[] args) {
|
||||
if (args.length > 0) {
|
||||
System.out.println("Test with overwrite");
|
||||
Set s = new ArraySet(4, false);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
System.out.println("Added " + args[i] + "? " + s.add(args[i]));
|
||||
System.out.println("Size is now " + s.size());
|
||||
}
|
||||
// toString tests the iterator
|
||||
System.out.println("Set now contains" + s);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
System.out.println("Removed " + args[i] + "? " + s.remove(args[i]));
|
||||
System.out.println("Size is now " + s.size());
|
||||
}
|
||||
System.out.println("\nTest with throw on full");
|
||||
s = new ArraySet(4);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
System.out.println("Added " + args[i] + "? " + s.add(args[i]));
|
||||
System.out.println("Size is now " + s.size());
|
||||
}
|
||||
// toString tests the iterator
|
||||
System.out.println("Set now contains" + s);
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
System.out.println("Removed " + args[i] + "? " + s.remove(args[i]));
|
||||
System.out.println("Size is now " + s.size());
|
||||
}
|
||||
}
|
||||
|
||||
//java.util.List c = java.util.Arrays.asList(new String[] {"foo", "bar", "baz", "splat", "barf", "baz", "moose", "bear", "cat", "dog"} );
|
||||
java.util.List c = java.util.Arrays.asList(new String[] {"foo", "bar"} );
|
||||
long start = System.currentTimeMillis();
|
||||
Set s = new java.util.HashSet(c);
|
||||
int runs = 10000000;
|
||||
for (int i = 0; i < runs; i++) {
|
||||
s = new java.util.HashSet(s);
|
||||
}
|
||||
System.out.println("HashSet took " + (System.currentTimeMillis() - start));
|
||||
|
||||
start = System.currentTimeMillis();
|
||||
s = new ArraySet(c);
|
||||
for (int i = 0; i < runs; i++) {
|
||||
s = new ArraySet(s);
|
||||
}
|
||||
System.out.println("ArraySet took " + (System.currentTimeMillis() - start));
|
||||
}
|
||||
****/
|
||||
}
|
||||
Reference in New Issue
Block a user