package the8472.utils;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class SortedCoWSet<T> {
final Comparator<? super T> comparator;
final Class<T> clazz;
final Object copyOnWriteLock = new Object();
volatile T[] storage;
public SortedCoWSet(Class<T> clazz, Comparator<T> comp) {
this.comparator = comp;
this.clazz = clazz;
storage = (T[]) Array.newInstance(clazz, 0);
}
/**
* @return the current backing array. consumers must not modify it
*/
public T[] getSnapshot() {
return storage;
}
public boolean contains(T toCheck) {
return java.util.Arrays.binarySearch(storage, toCheck, comparator) >= 0;
}
public int size() {
return storage.length;
}
public boolean add(T toAdd) {
synchronized (copyOnWriteLock) {
int insertIndex = java.util.Arrays.binarySearch(storage, toAdd, comparator);
if(insertIndex >= 0) {
// already present
return false;
}
insertIndex = -(insertIndex + 1);
T[] newStorage = java.util.Arrays.copyOf(storage, storage.length+1);
if(newStorage.length > 1)
System.arraycopy(newStorage, insertIndex, newStorage, insertIndex +1, newStorage.length - insertIndex - 1);
newStorage[insertIndex] = toAdd;
storage = newStorage;
}
return true;
}
public void removeIf(Predicate<T> matcher) {
synchronized (copyOnWriteLock) {
ArrayList<T> newSet = new ArrayList<>();
Arrays.asList(storage).stream().filter(e -> !matcher.test(e)).collect(Collectors.toCollection(() -> newSet));
if(newSet.size() != storage.length) {
Collections.sort(newSet, comparator);
storage = newSet.toArray((T[]) Array.newInstance(clazz, newSet.size()));
}
}
}
}