org.jhotdraw8.icollection.MutableRedBlackSet Maven / Gradle / Ivy
package org.jhotdraw8.icollection;
import org.jhotdraw8.icollection.facade.ReadOnlySequencedSetFacade;
import org.jhotdraw8.icollection.impl.iteration.FailFastIterator;
import org.jhotdraw8.icollection.impl.iteration.FailFastSpliterator;
import org.jhotdraw8.icollection.impl.iteration.MappedIterator;
import org.jhotdraw8.icollection.impl.redblack.RedBlackTree;
import org.jhotdraw8.icollection.navigable.DescendingNavigableSetView;
import org.jhotdraw8.icollection.navigable.SubsetNavigableSetView;
import org.jhotdraw8.icollection.readonly.ReadOnlyCollection;
import org.jhotdraw8.icollection.readonly.ReadOnlyNavigableSet;
import org.jhotdraw8.icollection.readonly.ReadOnlySequencedSet;
import org.jhotdraw8.icollection.serialization.SortedSetSerializationProxy;
import org.jspecify.annotations.Nullable;
import java.io.Serial;
import java.io.Serializable;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableSet;
import java.util.SortedSet;
import java.util.Spliterator;
import java.util.stream.Stream;
/**
* Implements the {@link NavigableSet} interface using a Red-Black tree.
*
* References:
*
* For a similar design, see 'TreeSet.java' in vavr. The internal data structure of
* this class is licensed from vavr.
*
* - TreeSet.java. Copyright 2023 (c) vavr. MIT License.
* - github.com
*
*
* @param the element type
*/
public class MutableRedBlackSet extends AbstractSet implements NavigableSet, Serializable, Cloneable, ReadOnlyNavigableSet {
@Serial
private static final long serialVersionUID = 0L;
@SuppressWarnings({"serial", "RedundantSuppression"})// Conditionally serializable
final Comparator comparator;
/**
* The number of times this set has been structurally modified.
*/
protected transient int modCount;
transient RedBlackTree root;
/**
* Constructs a new, empty set, sorted according to the
* specified comparator.
*
* @param comparator a comparator, if {@code null} the natural ordering of the elements is used
*/
public MutableRedBlackSet(@Nullable Comparator comparator) {
this.comparator = comparator == null ? NaturalComparator.instance() : comparator;
this.root = RedBlackTree.empty();
}
/**
* Constructs a new tree set containing the elements in the specified
* collection, sorted according to the specified comparator.
*
* @param comparator a comparator, if {@code null} the natural ordering of the elements is used
* @param c the collection
*/
@SuppressWarnings("this-escape")
public MutableRedBlackSet(@Nullable Comparator comparator, Collection extends E> c) {
this.comparator = comparator == null ? NaturalComparator.instance() : comparator;
this.root = RedBlackTree.empty();
this.addAll(c);
}
/**
* Constructs a new, empty set, sorted according to the
* natural ordering of its elements.
*/
@SuppressWarnings("this-escape")
public MutableRedBlackSet() {
this.comparator = NaturalComparator.instance();
this.root = RedBlackTree.empty();
}
/**
* Constructs a new tree set containing the elements in the specified
* collection, sorted according to the natural ordering of its
* elements.
*
* @param c the collection
*/
@SuppressWarnings("this-escape")
public MutableRedBlackSet(Iterable extends E> c) {
this.comparator = NaturalComparator.instance();
this.root = RedBlackTree.empty();
this.addAll(c);
}
MutableRedBlackSet(@Nullable Comparator comparator, RedBlackTree root) {
this.comparator = comparator == null ? NaturalComparator.instance() : comparator;
this.root = root;
}
@Override
public boolean add(E e) {
RedBlackTree newRoot = root.insert(e, null, comparator);
if (newRoot.size() != root.size()) {
root = newRoot;
modCount++;
return true;
}
return false;
}
public boolean addAll(Iterable extends E> c) {
boolean modified = false;
for (E e : c) {
if (add(e)) {
modified = true;
}
}
return modified;
}
@Nullable
@Override
public E ceiling(E e) {
return root.ceiling(e, comparator).keyOrNull();
}
@Override
public void clear() {
if (!isEmpty()) {
modCount++;
root = RedBlackTree.empty();
}
}
@SuppressWarnings("unchecked")
@Override
public MutableRedBlackSet clone() {
try {
return (MutableRedBlackSet) super.clone();
} catch (CloneNotSupportedException e) {
throw new AssertionError();
}
}
@Nullable
@Override
public Comparator super E> comparator() {
return comparator == NaturalComparator.instance() ? null : comparator;
}
@Override
@SuppressWarnings("unchecked")
public boolean contains(Object o) {
return root.contains((E) o, comparator);
}
@Override
public Iterator descendingIterator() {
return new FailFastIterator<>(
new MappedIterator<>(root.reverseIterator(), Map.Entry::getKey),
this::iteratorRemove, this::getModCount
);
}
@Override
public NavigableSet descendingSet() {
return new DescendingNavigableSetView<>(this, this::getModCount);
}
@Override
public E first() {
return root.min().getKey();
}
@Nullable
@Override
public E floor(E e) {
return root.floor(e, comparator).keyOrNull();
}
@Override
public E getFirst() {
return first();
}
@Override
public E getLast() {
return last();
}
/**
* Returns the current value of the modification counter.
*
* @return value of modification counter
*/
protected int getModCount() {
return modCount;
}
@Override
public NavigableSet headSet(E toElement, boolean inclusive) {
return new SubsetNavigableSetView<>(this, this::getModCount,
true, null, true, false, toElement, inclusive, true);
}
@Override
public SortedSet headSet(E toElement) {
return headSet(toElement, false);
}
@Nullable
@Override
public E higher(E e) {
return root.higher(e, comparator).keyOrNull();
}
@Override
public boolean isEmpty() {
return root.isEmpty();
}
@Override
public Iterator iterator() {
return new FailFastIterator<>(
new MappedIterator<>(root.iterator(), Map.Entry::getKey),
this::iteratorRemove, this::getModCount
);
}
private void iteratorRemove(E e) {
remove(e);
}
@Override
public E last() {
return root.max().getKey();
}
@Nullable
@Override
public E lower(E e) {
return root.lower(e, comparator).keyOrNull();
}
@Nullable
@Override
public E pollFirst() {
E value = root.min().keyOrNull();
root = root.delete(value, comparator);
return value;
}
@Nullable
@Override
public E pollLast() {
E value = root.max().keyOrNull();
root = root.delete(value, comparator);
return value;
}
@Override
public ReadOnlySequencedSet readOnlyReversed() {
return new ReadOnlySequencedSetFacade<>(
this::reverseIterator,
this::iterator,
this::size,
this::contains,
this::getLast,
this::getFirst,
Spliterator.IMMUTABLE);
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(Object o) {
RedBlackTree newRoot = root.delete((E) o, comparator);
if (newRoot.size() != root.size()) {
root = newRoot;
modCount++;
return true;
}
return false;
}
Iterator reverseIterator() {
return new FailFastIterator<>(
new MappedIterator<>(root.reverseIterator(), Map.Entry::getKey),
this::iteratorRemove, this::getModCount
);
}
@Override
public int size() {
return root.size();
}
@Override
public Spliterator spliterator() {
return new FailFastSpliterator<>(
NavigableSet.super.spliterator(),
this::getModCount,
comparator == NaturalComparator.instance() ? null : comparator);
}
@Override
public Stream stream() {
return super.stream();
}
@Override
public NavigableSet subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) {
return new SubsetNavigableSetView<>(this, this::getModCount,
false, fromElement, fromInclusive, false, toElement, toInclusive, true);
}
@Override
public SortedSet subSet(E fromElement, E toElement) {
return subSet(fromElement, true, toElement, false);
}
@Override
public NavigableSet tailSet(E fromElement, boolean inclusive) {
return new SubsetNavigableSetView<>(this, this::getModCount,
false, fromElement, inclusive, true, null, true, true);
}
@Override
public SortedSet tailSet(E fromElement) {
return tailSet(fromElement, true);
}
/**
* Returns an immutable copy of this set.
*
* @return an immutable copy
*/
public RedBlackSet toImmutable() {
return new RedBlackSet<>(comparator, root);
}
@Override
public String toString() {
return ReadOnlyCollection.iterableToString(this);
}
@Serial
private Object writeReplace() {
return new MutableRedBlackSet.SerializationProxy<>(this);
}
private static class SerializationProxy extends SortedSetSerializationProxy {
@Serial
private static final long serialVersionUID = 0L;
protected SerializationProxy(SortedSet target) {
super(target);
}
@Serial
@Override
protected Object readResolve() {
return new MutableRedBlackSet<>(deserializedComparator, deserializedElements);
}
}
}