All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jhotdraw8.icollection.MutableChampVectorSet Maven / Gradle / Ivy

The newest version!
/*
 * @(#)MutableChampVectorSet.java
 * Copyright © 2023 The authors and contributors of JHotDraw. MIT License.
 */

package org.jhotdraw8.icollection;

import org.jhotdraw8.icollection.facade.ReadOnlySequencedSetFacade;
import org.jhotdraw8.icollection.impl.champ.AbstractMutableChampSet;
import org.jhotdraw8.icollection.impl.champ.BitmapIndexedNode;
import org.jhotdraw8.icollection.impl.champ.ChangeEvent;
import org.jhotdraw8.icollection.impl.champ.Node;
import org.jhotdraw8.icollection.impl.champ.ReverseTombSkippingVectorSpliterator;
import org.jhotdraw8.icollection.impl.champ.SequencedData;
import org.jhotdraw8.icollection.impl.champ.SequencedElement;
import org.jhotdraw8.icollection.impl.champ.TombSkippingVectorSpliterator;
import org.jhotdraw8.icollection.impl.iteration.FailFastIterator;
import org.jhotdraw8.icollection.impl.iteration.FailFastSpliterator;
import org.jhotdraw8.icollection.readonly.ReadOnlySequencedSet;
import org.jhotdraw8.icollection.sequenced.ReversedSequencedSetView;
import org.jhotdraw8.icollection.serialization.SetSerializationProxy;
import org.jspecify.annotations.Nullable;

import java.io.Serial;
import java.util.Iterator;
import java.util.Objects;
import java.util.SequencedSet;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;

import static org.jhotdraw8.icollection.impl.champ.SequencedData.vecRemove;

/**
 * Implements the {@link SequencedSet} interface using a Compressed
 * Hash-Array Mapped Prefix-tree (CHAMP) and a bit-mapped trie (Vector).
 * 

* Features: *

    *
  • supports up to 230 elements
  • *
  • allows null elements
  • *
  • is mutable
  • *
  • is not thread-safe
  • *
  • iterates in the order, in which elements were inserted
  • *
*

* Performance characteristics: *

    *
  • add: O(1) amortized
  • *
  • remove: O(1)
  • *
  • contains: O(1)
  • *
  • toImmutable: O(1) + O(log N) distributed across subsequent updates in * this set
  • *
  • clone: O(1) + O(log N) distributed across subsequent updates in this * set and in the clone
  • *
  • iterator creation: O(1)
  • *
  • iterator.next: O(1)
  • *
  • getFirst, getLast: O(1)
  • *
*

* Implementation details: *

* See description at {@link ChampVectorSet}. *

* References: *

*
Michael J. Steindorfer (2017). * Efficient Immutable Collections.
*
michael.steindorfer.name * *
The Capsule Hash Trie Collections Library. *
Copyright (c) Michael Steindorfer. BSD-2-Clause License
*
github.com *
* * @param the element type */ @SuppressWarnings("exports") public class MutableChampVectorSet extends AbstractMutableChampSet> implements ReadOnlySequencedSet, SequencedSet { @Serial private static final long serialVersionUID = 0L; /** * Offset of sequence numbers to vector indices. * *
vector index = sequence number + offset
*/ private int offset = 0; /** * In this vector we store the elements in the order in which they were inserted. */ private VectorList vector; /** * Constructs a new empty set. */ public MutableChampVectorSet() { root = BitmapIndexedNode.emptyNode(); vector = VectorList.of(); } /** * Constructs a set containing the elements in the specified * {@link Iterable}. * * @param c an iterable */ @SuppressWarnings({"unchecked", "this-escape"}) public MutableChampVectorSet(Iterable c) { if (c instanceof MutableChampVectorSet) { c = ((MutableChampVectorSet) c).toImmutable(); } if (c instanceof ChampVectorSet) { ChampVectorSet that = (ChampVectorSet) c; this.root = that.root; this.size = that.size; this.offset = that.offset; this.vector = that.vector; } else { this.root = BitmapIndexedNode.emptyNode(); this.vector = VectorList.of(); addAll(c); } } @Override public boolean add(@Nullable E e) { return addLast(e, false); } @Override public void addFirst(@Nullable E e) { addFirst(e, true); } private boolean addFirst(@Nullable E e, boolean moveToFirst) { var details = new ChangeEvent>(); var newElem = new SequencedElement<>(e, -offset - 1); root = root.put(makeOwner(), newElem, SequencedElement.keyHash(e), 0, details, moveToFirst ? SequencedElement::putAndMoveToFirst : SequencedElement::put, Objects::equals, SequencedElement::elementKeyHash); boolean modified = details.isModified(); if (modified) { if (details.isReplaced()) { if (moveToFirst) { var result = vecRemove(vector, details.getOldDataNonNull(), offset); vector = result.first(); } } else { size++; } offset++; modCount++; vector = vector.addFirst(newElem); renumber(); } return modified; } @Override public void addLast(@Nullable E e) { addLast(e, true); } private boolean addLast(@Nullable E e, boolean moveToLast) { var details = new ChangeEvent>(); var newElem = new SequencedElement<>(e, offset + vector.size()); root = root.put(makeOwner(), newElem, SequencedElement.keyHash(e), 0, details, moveToLast ? SequencedElement::putAndMoveToLast : SequencedElement::put, Objects::equals, SequencedElement::elementKeyHash); boolean modified = details.isModified(); if (modified) { var oldElem = details.getOldData(); if (details.isReplaced()) { var result = vecRemove(vector, oldElem, offset); vector = result.first(); offset = result.second(); } else { modCount++; size++; } vector = vector.add(newElem); renumber(); } return modified; } /** * Removes all elements from this set. */ @Override public void clear() { root = BitmapIndexedNode.emptyNode(); vector = VectorList.of(); size = 0; modCount++; offset = -1; } /** * Returns a shallow copy of this set. */ @Override public MutableChampVectorSet clone() { return (MutableChampVectorSet) super.clone(); } @Override @SuppressWarnings("unchecked") public boolean contains(@Nullable final Object o) { return Node.NO_DATA != root.find(new SequencedElement<>((E) o), SequencedElement.keyHash(o), 0, Objects::equals); } @SuppressWarnings("unchecked") @Override public E getFirst() { return ((SequencedElement) vector.getFirst()).getElement(); } @SuppressWarnings("unchecked") @Override public E getLast() { return ((SequencedElement) vector.getLast()).getElement(); } @Override @SuppressWarnings("unchecked") public Iterator iterator() { return new FailFastIterator<>(Spliterators.iterator(new TombSkippingVectorSpliterator<>(vector.trie, (Object o) -> ((SequencedElement) o).getElement(), 0, size, vector.size(), Spliterator.SIZED | Spliterator.DISTINCT | Spliterator.ORDERED)), this::iteratorRemove, () -> modCount); } /* public boolean removeAll(Iterable c) { if (isEmpty() || (c instanceof Collection cc && cc.isEmpty()) || (c instanceof ReadOnlyCollection rc) && rc.isEmpty()) { return false; } if (c == this) { clear(); return true; } Predicate predicate; if (c instanceof Collection that) { predicate = that::contains; } else if (c instanceof ReadOnlyCollection that) { predicate = that::contains; } else { HashSet that = new HashSet<>(); c.forEach(that::add); predicate = that::contains; } return filterAll(predicate.negate()); } /* public boolean retainAll(Iterable c) { if(c==this||isEmpty()) { return false; } if ((c instanceof Collection cc && cc.isEmpty()) || (c instanceof ReadOnlyCollection rc) && rc.isEmpty()) { clear(); return true; } Predicate predicate; if (c instanceof Collection that) { predicate = that::contains; } else if (c instanceof ReadOnlyCollection that) { predicate = that::contains; } else { HashSet that = new HashSet<>(); c.forEach(that::add); predicate = that::contains; } return filterAll(predicate); } boolean filterAll(Predicate predicate) { class VectorPredicate implements Predicate> { SimpleImmutableList newVector = vector; int newOffset = offset; @Override public boolean test(SequencedElement e) { if (!predicate.test(e.getElement())) { OrderedPair, Integer> result = vecRemove(newVector, e, newOffset); newVector = result.first(); newOffset = result.second(); return false; } return true; } } VectorPredicate vp = new VectorPredicate(); BulkChangeEvent bulkChange = new BulkChangeEvent(); BitmapIndexedNode> newRootNode = root.filterAll(makeOwner(), vp, 0, bulkChange); if (bulkChange.removed == 0) { return false; } root = newRootNode; vector = vp.newVector; offset = vp.newOffset; size -= bulkChange.removed; modCount++; return true; } */ @SuppressWarnings("unchecked") private Iterator reverseIterator() { return new FailFastIterator<>(Spliterators.iterator(new ReverseTombSkippingVectorSpliterator<>(vector, (Object o) -> ((SequencedElement) o).getElement(), size(), Spliterator.SIZED | Spliterator.DISTINCT | Spliterator.ORDERED)), this::iteratorRemove, () -> modCount); } @SuppressWarnings("unchecked") private Spliterator reverseSpliterator() { return new FailFastSpliterator<>(new ReverseTombSkippingVectorSpliterator<>(vector, (Object o) -> ((SequencedElement) o).getElement(), size(), Spliterator.SIZED | Spliterator.DISTINCT | Spliterator.ORDERED), () -> modCount, null); } @SuppressWarnings("unchecked") @Override public Spliterator spliterator() { return new FailFastSpliterator<>(new TombSkippingVectorSpliterator<>(vector.trie, (Object o) -> ((SequencedElement) o).getElement(), 0, size(), vector.size(), Spliterator.SIZED | Spliterator.DISTINCT | Spliterator.ORDERED), () -> modCount, null); } private void iteratorRemove(E element) { owner = null; remove(element); } @Override public ReadOnlySequencedSet readOnlyReversed() { return new ReadOnlySequencedSetFacade<>(this.reversed()); } @SuppressWarnings("unchecked") @Override public boolean remove(Object o) { var details = new ChangeEvent>(); root = root.remove(makeOwner(), new SequencedElement<>((E) o), SequencedElement.keyHash(o), 0, details, Objects::equals); boolean modified = details.isModified(); if (modified) { var result = vecRemove(vector, details.getOldDataNonNull(), offset); size--; modCount++; vector = result.first(); offset = result.second(); renumber(); } return modified; } @Override public E removeFirst() { var e = this.getFirst(); remove(e); return e; } @Override public E removeLast() { var e = this.getLast(); remove(e); return e; } /** * Renumbers the sequence numbers if they have overflown. */ private void renumber() { if (SequencedData.vecMustRenumber(size, offset, vector.size())) { var result = SequencedData.vecRenumber(makeOwner(), size, vector.size(), root, vector.trie, SequencedElement::elementKeyHash, Objects::equals, (e, seq) -> new SequencedElement<>(e.getElement(), seq)); root = result.first(); vector = result.second(); offset = 0; } } @Override public SequencedSet reversed() { return new ReversedSequencedSetView<>(this, this::reverseIterator, this::reverseSpliterator); } /** * Returns an immutable copy of this set. * * @return an immutable copy */ public ChampVectorSet toImmutable() { owner = null; return size == 0 ? ChampVectorSet.of() : new ChampVectorSet<>(root, vector, size, offset); } @Serial private Object writeReplace() { return new SerializationProxy<>(this); } private static class SerializationProxy extends SetSerializationProxy { @Serial private static final long serialVersionUID = 0L; protected SerializationProxy(Set target) { super(target); } @Serial @Override protected Object readResolve() { return new MutableChampVectorSet<>(deserializedElements); } } }