275 lines
6.1 KiB
Java
275 lines
6.1 KiB
Java
package me.brianlong.git;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Comparator;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.NoSuchElementException;
|
|
import java.util.Queue;
|
|
import java.util.Set;
|
|
import java.util.TreeSet;
|
|
|
|
public class UniquePriorityFifoQueue<T> implements Queue<T> {
|
|
|
|
private final Counter counter = new SimpleCounter();
|
|
private final Counter fakeCounter = new FakeCounter();
|
|
private final TreeSet<PriorityFifoElement<T>> elements;
|
|
// TreeSet does not check for uniqueness using hashCode, but using the comparator instead
|
|
private final Set<PriorityFifoElement<T>> uelements;
|
|
|
|
public UniquePriorityFifoQueue() {
|
|
this.elements = new TreeSet<PriorityFifoElement<T>>();
|
|
this.uelements = new HashSet<PriorityFifoElement<T>>();
|
|
}
|
|
|
|
public UniquePriorityFifoQueue(Collection<? extends T> c) {
|
|
this();
|
|
this.addAll(c);
|
|
}
|
|
|
|
public UniquePriorityFifoQueue(final Comparator<? super T> comparator) {
|
|
this.elements = new TreeSet<PriorityFifoElement<T>>(new Comparator<PriorityFifoElement<T>>() {
|
|
@Override
|
|
public int compare(PriorityFifoElement<T> o1, PriorityFifoElement<T> o2) {
|
|
int compare = comparator.compare(o1.element, o2.element);
|
|
if (compare != 0) return compare;
|
|
return o1.compareTo(o2);
|
|
}
|
|
});
|
|
this.uelements = new HashSet<PriorityFifoElement<T>>();
|
|
}
|
|
|
|
@Override
|
|
public boolean add(T e) {
|
|
PriorityFifoElement<T> element = new PriorityFifoElement<T>(e, this.counter);
|
|
return this.uelements.add(element) && this.elements.add(element);
|
|
|
|
}
|
|
|
|
@Override
|
|
public boolean addAll(Collection<? extends T> c) {
|
|
boolean anyAdded = false;
|
|
if (c != null) for (T e : c) {
|
|
PriorityFifoElement<T> element = new PriorityFifoElement<T>(e, this.counter);
|
|
if (this.uelements.add(element) && this.elements.add(element))
|
|
anyAdded = true;
|
|
}
|
|
return anyAdded;
|
|
}
|
|
|
|
@Override
|
|
public void clear() {
|
|
this.elements.clear();
|
|
this.uelements.clear();
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
@Override
|
|
public boolean contains(Object o) {
|
|
return this.uelements.contains(new PriorityFifoElement<T>((T)o, this.fakeCounter));
|
|
}
|
|
|
|
@Override
|
|
public boolean containsAll(Collection<?> c) {
|
|
if (c != null) for (Object o : c)
|
|
if (!this.contains(o))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public T element() {
|
|
return this.elements.iterator().next().element;
|
|
}
|
|
|
|
@Override
|
|
public boolean isEmpty() {
|
|
return this.elements.isEmpty();
|
|
}
|
|
|
|
@Override
|
|
public Iterator<T> iterator() {
|
|
final Iterator<PriorityFifoElement<T>> i = this.elements.iterator();
|
|
return new Iterator<T>() {
|
|
private T lastElement;
|
|
|
|
@Override
|
|
public boolean hasNext() {
|
|
return i.hasNext();
|
|
}
|
|
|
|
@Override
|
|
public T next() {
|
|
this.lastElement = i.next().element;
|
|
return this.lastElement;
|
|
}
|
|
|
|
@Override
|
|
public void remove() {
|
|
i.remove();
|
|
uelements.remove(this.lastElement);
|
|
}
|
|
};
|
|
}
|
|
|
|
@Override
|
|
public boolean offer(T e) {
|
|
return this.add(e);
|
|
}
|
|
|
|
@Override
|
|
public T peek() {
|
|
Iterator<PriorityFifoElement<T>> i = this.elements.iterator();
|
|
return i.hasNext() ? i.next().element : null;
|
|
}
|
|
|
|
@Override
|
|
public T poll() {
|
|
PriorityFifoElement<T> element = this.elements.pollFirst();
|
|
if (element == null)
|
|
return null;
|
|
this.uelements.remove(element);
|
|
return element.element;
|
|
}
|
|
|
|
@Override
|
|
public T remove() {
|
|
PriorityFifoElement<T> element = this.elements.pollFirst();
|
|
if (element == null)
|
|
throw new NoSuchElementException();
|
|
this.uelements.remove(element);
|
|
return element.element;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
@Override
|
|
public boolean remove(Object o) {
|
|
PriorityFifoElement<T> element = new PriorityFifoElement<T>((T)o, this.fakeCounter);
|
|
this.uelements.remove(element);
|
|
|
|
element = this.find(element.element);
|
|
return this.elements.remove(element);
|
|
}
|
|
|
|
@Override
|
|
public boolean removeAll(Collection<?> c) {
|
|
if (c != null) for (Object o : c)
|
|
this.remove(o);
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean retainAll(Collection<?> c) {
|
|
Iterator<PriorityFifoElement<T>> i = this.elements.iterator();
|
|
while (i.hasNext()) {
|
|
PriorityFifoElement<T> e = i.next();
|
|
T element = e.element;
|
|
if (!c.contains(element)) {
|
|
i.remove();
|
|
this.uelements.remove(e);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public int size() {
|
|
return this.elements.size();
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
@Override
|
|
public Object[] toArray() {
|
|
Object[] objs = this.elements.toArray();
|
|
Object[] ts = new Object[objs.length];
|
|
for (int i = 0; i < objs.length; i++)
|
|
ts[i] = ((PriorityFifoElement<T>)objs[i]).element;
|
|
return ts;
|
|
}
|
|
|
|
@SuppressWarnings("unchecked")
|
|
public <U extends Object> U[] toArray(U[] a) {
|
|
if (a.length < this.elements.size())
|
|
a = Arrays.copyOf(a, this.elements.size());
|
|
|
|
int i = 0;
|
|
for (PriorityFifoElement<T> element : this.elements)
|
|
a[i] = (U)element.element;
|
|
return a;
|
|
}
|
|
|
|
private PriorityFifoElement<T> find(T e) {
|
|
for (PriorityFifoElement<T> element : this.elements) {
|
|
if (element.element.equals(e))
|
|
return element;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
|
|
|
|
private class PriorityFifoElement<E> implements Comparable<PriorityFifoElement<E>> {
|
|
|
|
private final E element;
|
|
private final int fifoId;
|
|
|
|
public PriorityFifoElement(E element, Counter counter) {
|
|
this.element = element;
|
|
this.fifoId = counter.next();
|
|
}
|
|
|
|
@Override
|
|
public int compareTo(PriorityFifoElement<E> o) {
|
|
if (this.fifoId < 0) return 0;
|
|
else if (o == null) return 1;
|
|
else if (o.fifoId < 0) return 0;
|
|
else return this.fifoId - o.fifoId;
|
|
}
|
|
|
|
@Override
|
|
public int hashCode() {
|
|
return this.element.hashCode();
|
|
}
|
|
|
|
@SuppressWarnings("rawtypes")
|
|
@Override
|
|
public boolean equals(Object obj) {
|
|
if (obj instanceof PriorityFifoElement) {
|
|
return this.element.equals(((PriorityFifoElement)obj).element);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
private interface Counter {
|
|
|
|
int next();
|
|
|
|
}
|
|
|
|
public class FakeCounter implements Counter {
|
|
|
|
public int next() {
|
|
return -1;
|
|
}
|
|
|
|
}
|
|
|
|
public class SimpleCounter implements Counter {
|
|
|
|
private int count = 0;
|
|
|
|
public synchronized int next() {
|
|
this.count++;
|
|
return this.count;
|
|
}
|
|
|
|
}
|
|
|
|
}
|