![JAR search and dependency download from the Maven repository](/logo.png)
org.jhotdraw8.icollection.MutableChampMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.jhotdraw8.icollection Show documentation
Show all versions of org.jhotdraw8.icollection Show documentation
JHotDraw8 Immutable Collections
The newest version!
/*
* @(#)MutableChampMap.java
* Copyright © 2023 The authors and contributors of JHotDraw. MIT License.
*/
package org.jhotdraw8.icollection;
import org.jhotdraw8.icollection.facade.SetFacade;
import org.jhotdraw8.icollection.impl.champmap.AbstractMutableChampMap;
import org.jhotdraw8.icollection.impl.champmap.BitmapIndexedNode;
import org.jhotdraw8.icollection.impl.champmap.ChangeEvent;
import org.jhotdraw8.icollection.impl.champmap.EntryIterator;
import org.jhotdraw8.icollection.impl.champmap.Node;
import org.jhotdraw8.icollection.impl.iteration.FailFastIterator;
import org.jhotdraw8.icollection.impl.iteration.IteratorSpliterator;
import org.jhotdraw8.icollection.serialization.MapSerializationProxy;
import org.jspecify.annotations.Nullable;
import java.io.Serial;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Spliterator;
/**
* Implements the {@link Map} interface using a Compressed Hash-Array Mapped
* Prefix-tree (CHAMP).
*
* Features:
*
* - supports up to 231 - 1 entries
* - allows null keys and null values
* - is mutable
* - is not thread-safe
* - does not guarantee a specific iteration order
*
*
* Performance characteristics:
*
* - put: O(log₃₂ N)
* - remove: O(log₃₂ N)
* - containsKey: O(log₃₂ N)
* - toImmutable: O(1) + O(log₃₂ N) distributed across subsequent updates in
* this map
* - clone: O(1) + O(log₃₂ N) distributed across subsequent updates in this
* map and in the clone
* - iterator.next: O(1)
*
*
* Implementation details:
*
* See description at {@link ChampMap}.
*
* References:
*
* Portions of the code in this class has been derived from 'The Capsule Hash Trie Collections Library'.
*
* - 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 key type
* @param the value type
*/
public class MutableChampMap extends AbstractMutableChampMap {
@Serial
private static final long serialVersionUID = 0L;
/**
* Constructs a new empty map.
*/
public MutableChampMap() {
root = BitmapIndexedNode.emptyNode();
}
/**
* Constructs a map containing the same entries as in the specified
* {@link Map}.
*
* @param m a map
*/
@SuppressWarnings("this-escape")
public MutableChampMap(Map extends K, ? extends V> m) {
if (m instanceof MutableChampMap) {
@SuppressWarnings("unchecked")
MutableChampMap that = (MutableChampMap) m;
this.root = that.root;
this.size = that.size;
this.modCount = 0;
} else {
this.root = BitmapIndexedNode.emptyNode();
this.putAll(m);
}
}
/**
* Constructs a map containing the same entries as in the specified
* {@link Iterable}.
*
* @param m an iterable
*/
@SuppressWarnings("this-escape")
public MutableChampMap(Iterable extends Entry extends K, ? extends V>> m) {
if (m instanceof ChampMap) {
@SuppressWarnings("unchecked")
ChampMap that = (ChampMap) m;
this.root = that.root;
this.size = that.size;
} else {
this.root = BitmapIndexedNode.emptyNode();
for (Entry extends K, ? extends V> e : m) {
this.put(e.getKey(), e.getValue());
}
}
}
/**
* Removes all entries from this map.
*/
@Override
public void clear() {
root = BitmapIndexedNode.emptyNode();
size = 0;
modCount++;
}
/**
* Returns a shallow copy of this map.
*/
@Override
public MutableChampMap clone() {
return (MutableChampMap) super.clone();
}
@Override
@SuppressWarnings("unchecked")
public boolean containsKey(@Nullable Object o) {
return root.findByKey((K) o,
ChampMap.keyHash(o), 0) != Node.NO_DATA;
}
@Override
public Iterator> iterator() {
return new FailFastIterator<>(
new EntryIterator<>(root,
this::iteratorRemoveKey, this::iteratorPutIfPresent), this::getModCount
);
}
@Override
public Spliterator> spliterator() {
return new IteratorSpliterator<>(iterator(), size(), Spliterator.NONNULL | characteristics(), null);
}
/**
* Returns a {@link Set} view of the entries contained in this map.
*
* @return a view of the entries contained in this map
*/
@Override
public Set> entrySet() {
return new SetFacade<>(
this::iterator,
this::spliterator,
this::size,
this::containsEntry,
this::clear,
null,
this::removeEntry
);
}
/**
* Returns the value to which the specified key is mapped,
* or {@code null} if this map contains no entry for the key.
*
* @param o the key whose associated value is to be returned
* @return the associated value or null
*/
@Override
@SuppressWarnings("unchecked")
public @Nullable V get(Object o) {
Object result = root.findByKey((K) o,
ChampMap.keyHash(o), 0);
return result == Node.NO_DATA ? null : (V) result;
}
private void iteratorPutIfPresent(@Nullable K k, @Nullable V v) {
if (containsKey(k)) {
owner = null;
put(k, v);
}
}
@Override
public @Nullable V put(K key, V value) {
return putEntry(key, value).getOldValue();
}
/*
@Override
@SuppressWarnings("unchecked")
public boolean putAll(Iterable extends Entry extends K, ? extends V>> c) {
if (c instanceof MutableChampMap, ?> m) {
c = (Iterable extends Entry extends K, ? extends V>>) m.toImmutable();
}
if (isEmpty() && c instanceof SimpleImmutableMap, ?> that) {
if (that.isEmpty()) {
return false;
}
root = (BitmapIndexedNode) (BitmapIndexedNode>) that.root;
size = that.size;
modCount++;
return true;
}
if (c instanceof SimpleImmutableMap, ?> that) {
var bulkChange = new BulkChangeEvent();
var newRootNode = root.putAll(getOrCreateOwner(), (Node>) (Node>) that.root, 0, bulkChange, SimpleImmutableMap::updateEntry, SimpleImmutableMap::entryKeyEquals,
SimpleImmutableMap::entryKeyHash, new ChangeEvent<>());
if (bulkChange.inBoth == that.size() && !bulkChange.replaced) {
return false;
}
root = newRootNode;
size += that.size - bulkChange.inBoth;
modCount++;
return true;
}
return super.putAll(c);
}*/
ChangeEvent putEntry(@Nullable K key, @Nullable V val) {
int keyHash = ChampMap.keyHash(key);
ChangeEvent details = new ChangeEvent<>();
root = root.put(getOrCreateOwner(), key, val, keyHash, 0, details, ChampMap::keyHash);
if (details.isModified() && !details.isReplaced()) {
size += 1;
modCount++;
}
return details;
}
@Override
public V remove(Object o) {
@SuppressWarnings("unchecked") final K key = (K) o;
return removeKey(key).getOldValue();
}
@Override
public boolean removeAll(Iterable> c) {
return super.removeAll(c);
}
/*
@SuppressWarnings("unchecked")
@Override
public boolean retainAll(Iterable> c) {
if (isEmpty()) {
return false;
}
if ((c instanceof Collection> cc && cc.isEmpty())
|| (c instanceof ReadOnlyCollection> rc) && rc.isEmpty()) {
clear();
return true;
}
BulkChangeEvent bulkChange = new BulkChangeEvent();
BitmapIndexedNode newRootNode;
if (c instanceof Collection> that) {
newRootNode = root.filterAll(getOrCreateOwner(), e -> that.contains(e.getKey()), 0, bulkChange);
} else if (c instanceof ReadOnlyCollection> that) {
newRootNode = root.filterAll(getOrCreateOwner(), e -> that.contains(e.getKey()), 0, bulkChange);
} else {
HashSet
© 2015 - 2025 Weber Informatics LLC | Privacy Policy