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 implements Queue { private final Counter counter = new SimpleCounter(); private final Counter fakeCounter = new FakeCounter(); private final TreeSet> elements; // TreeSet does not check for uniqueness using hashCode, but using the comparator instead private final Set> uelements; public UniquePriorityFifoQueue() { this.elements = new TreeSet>(); this.uelements = new HashSet>(); } public UniquePriorityFifoQueue(Collection c) { this(); this.addAll(c); } public UniquePriorityFifoQueue(final Comparator comparator) { this.elements = new TreeSet>(new Comparator>() { @Override public int compare(PriorityFifoElement o1, PriorityFifoElement o2) { int compare = comparator.compare(o1.element, o2.element); if (compare != 0) return compare; return o1.compareTo(o2); } }); this.uelements = new HashSet>(); } @Override public boolean add(T e) { PriorityFifoElement element = new PriorityFifoElement(e, this.counter); return this.uelements.add(element) && this.elements.add(element); } @Override public boolean addAll(Collection c) { boolean anyAdded = false; if (c != null) for (T e : c) { PriorityFifoElement element = new PriorityFifoElement(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)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 iterator() { final Iterator> i = this.elements.iterator(); return new Iterator() { 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> i = this.elements.iterator(); return i.hasNext() ? i.next().element : null; } @Override public T poll() { PriorityFifoElement element = this.elements.pollFirst(); if (element == null) return null; this.uelements.remove(element); return element.element; } @Override public T remove() { PriorityFifoElement 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 element = new PriorityFifoElement((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> i = this.elements.iterator(); while (i.hasNext()) { PriorityFifoElement 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)objs[i]).element; return ts; } @SuppressWarnings("unchecked") public U[] toArray(U[] a) { if (a.length < this.elements.size()) a = Arrays.copyOf(a, this.elements.size()); int i = 0; for (PriorityFifoElement element : this.elements) a[i] = (U)element.element; return a; } private PriorityFifoElement find(T e) { for (PriorityFifoElement element : this.elements) { if (element.element.equals(e)) return element; } return null; } private class PriorityFifoElement implements Comparable> { 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 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; } } }