package org.jadira.reflection.cloning.collection;
import java.util.Arrays;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Set;
/**
* A wrapper for IdentityHashMap that resolves object matches quickly for
* small sets using binary search
* @param <E> The type of entries within the set
*/
public class FastIdentityHashSet<E> implements Set<E> {
private int[] entryKeys = new int[0];
private static final int ARRAY_SIZE = 12;
private IdentityHashMap<E, Boolean> hashMap = new IdentityHashMap<E, Boolean>(12);
@Override
public int size() {
if (entryKeys != null) {
return entryKeys.length;
} else {
return hashMap.size();
}
}
@Override
public boolean isEmpty() {
if (entryKeys != null) {
return entryKeys.length == 0;
} else {
return hashMap.isEmpty();
}
}
@Override
public boolean contains(Object key) {
if (entryKeys != null) {
return Arrays.binarySearch(entryKeys, System.identityHashCode(key)) >= 0;
} else {
return hashMap.containsKey(System.identityHashCode(key));
}
}
@Override
public Iterator<E> iterator() {
return hashMap.keySet().iterator();
}
@Override
public Object[] toArray() {
return hashMap.keySet().toArray();
}
@SuppressWarnings("unchecked")
@Override
public <T> T[] toArray(T[] a) {
return (T[]) hashMap.keySet().toArray();
}
@Override
public boolean add(E e) {
boolean res = hashMap.put(e, Boolean.TRUE);
if (res) {
if (entryKeys == null || (entryKeys.length + 1 <= ARRAY_SIZE)) {
Object[] keys = hashMap.keySet().toArray(new Object[]{});
entryKeys = new int[keys.length];
for (int i = 0; i < keys.length; i++) {
entryKeys[i] = System.identityHashCode(keys[i]);
}
Arrays.sort(entryKeys);
} else {
entryKeys = null;
}
}
return res;
}
@Override
public boolean remove(Object o) {
boolean res = hashMap.remove(o);
if (res) {
if (hashMap.size() <= ARRAY_SIZE) {
Object[] keys = hashMap.keySet().toArray(new Object[]{});
entryKeys = new int[keys.length];
for (int i = 0; i < keys.length; i++) {
entryKeys[i] = System.identityHashCode(keys[i]);
}
Arrays.sort(entryKeys);
} else {
entryKeys = null;
}
}
return res;
}
@Override
public boolean containsAll(Collection<?> c) {
for (Object next : c) {
if(!contains(next)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends E> c) {
boolean res = false;
for (E next : c) {
boolean nextRes = add(next);
if (nextRes) { res = nextRes; }
}
return res;
}
@Override
public void clear() {
hashMap.clear();
entryKeys = new int[]{};
}
@Override
public boolean retainAll(Collection<?> c) {
Set<E> keySet = hashMap.keySet();
boolean res = keySet.retainAll(c);
hashMap.clear();
for (E next : keySet) {
hashMap.put(next, Boolean.TRUE);
}
if (res) {
Object[] keys = hashMap.keySet().toArray(new Object[]{});
entryKeys = new int[keys.length];
for (int i = 0; i < keys.length; i++) {
entryKeys[i] = System.identityHashCode(keys[i]);
}
Arrays.sort(entryKeys);
}
return res;
}
@Override
public boolean removeAll(Collection<?> c) {
boolean res = false;
for (Object next : c) {
boolean nextRes = remove(next);
if (nextRes) { res = nextRes; }
}
return res;
}
}