Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jhotdraw8.icollection.MutableChampVectorSet Maven / Gradle / Ivy
/*
* @(#)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 extends E> c) {
if (c instanceof MutableChampVectorSet>) {
c = ((MutableChampVectorSet extends E>) 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);
}
}
}