// TreeSet variant allowing multiple elements which are considered
// equal by the comparator but not by eq().
// All operations O(log n) with n being the number of _different_ elements.
sclass TreeSetWithDuplicates extends AbstractSet {
NavigableSet> sets;
Comparator comparator;
int size;
*() { this((Comparator) null); }
*(Comparator *comparator) {
sets = new TreeSet>(
comparator == null
? (setA, setB) -> cmp(main first(setA), main first(setB))
: (setA, setB) -> comparator.compare(main first(setA), main first(setB))
);
}
protected *(NavigableSet> *sets) {}
/*swappable*/ CompactLinkedHashSet makeInnerSet() {
ret new CompactLinkedHashSet;
}
public bool add(A a) {
var probe = probe(a);
CompactLinkedHashSet found = navigableSet_find(sets, probe);
if (found != null) {
if (!found.add(a)) false;
} else
sets.add(probe);
++size;
true;
}
public bool remove(O a) {
CompactLinkedHashSet newSet = makeInnerSet();
newSet.add((A) a);
CompactLinkedHashSet found = navigableSet_find(sets, newSet);
if (found == null) false;
if (l(found) == 1)
sets.remove(found);
else
found.remove(a);
--size;
true;
}
A first() {
ret main first(main first(sets));
}
A last() {
var last = sets.last();
ret last?.last();
}
public ItIt iterator() {
ret nestedIterator(sets, methodLambda0 iterator);
}
public int size() { ret size; }
// may return null
Set tiedForFirst() { ret main first(sets); }
CompactLinkedHashSet probe(O a) {
ret addAndReturnCollection(makeInnerSet(), (A) a);
}
public bool contains(O a) {
ret navigableSet_find(sets, probe(a)) != null;
}
}