// -has fast nextElement() and prevElement()
// -design allows for more functions like reordering the list
// -Saves up to 34% in space over LinkedHashSet
// (e.g. 22% for a set of 1,000 Ints)
sclass CompactLinkedHashSet extends AbstractSet {
new UnsynchronizedCompactHashSet> entries;
Entry head, tail;
sclass Entry {
A value;
Entry prev, next;
public int hashCode() {
ret _hashCode(value);
}
// "magic" equals function for CompactHashSet lookup without temp object
public bool equals(O o) {
ret o == this || eq(value, o);
}
}
public bool add(A a) {
if (entries.contains(a)) false;
new Entry n;
n.value = a;
n.prev = tail;
if (tail != null) tail.next = n;
tail = n;
if (head == null) head = n;
entries.add(n);
true;
}
public bool remove(O a) {
ret remove(entries.find(a));
}
public bool remove(Entry node) {
if (node == null) false;
if (node.next != null) node.next.prev = node.prev; else tail = node.prev;
if (node.prev != null) node.prev.next = node.next; else head = node.next;
entries.remove(node);
true;
}
public int size() { ret entries.size(); }
public ItIt iterator() {
ret new ItIt {
Entry entry = head, prev = null;
public bool hasNext() { ret entry != null; }
public A next() {
A a = entry.value;
prev = entry;
entry = entry.next;
ret a;
}
// untested
public void remove() {
if (prev == null) throw new IllegalStateException;
CompactLinkedHashSet.this.remove(prev);
prev = null;
}
};
}
public void clear() {
entries.clear();
head = tail = null;
}
public bool contains(O a) {
ret entries.contains(a);
}
public A find(O o) {
Entry e = entries.find(o);
ret e?.value;
}
public A prevElement(A a) {
Entry e = entries.find(a);
if (e == null || e.prev == null) null;
ret e.prev.value;
}
public A nextElement(A a) {
Entry e = entries.find(a);
if (e == null || e.next == null) null;
ret e.next.value;
}
public A first() { ret head?.value; }
public A last() { ret tail?.value; }
bool removeIfSame(O o) {
A value = find(o);
if (value == o) {
remove(value);
true;
}
false;
}
}