/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/.ɪᴏ
* ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
*/
package io.vavr.collection;
import io.vavr.Tuple;
import io.vavr.Tuple2;
import io.vavr.control.Option;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.*;
import java.util.stream.Collector;
/**
* An immutable {@code HashMap} implementation based on a
* <a href="https://en.wikipedia.org/wiki/Hash_array_mapped_trie">Hash array mapped trie (HAMT)</a>.
*
* @author Ruslan Sennov, Patryk Najda, Daniel Dietrich
*/
public final class HashMap<K, V> implements Map<K, V>, Serializable {
private static final long serialVersionUID = 1L;
private static final HashMap<?, ?> EMPTY = new HashMap<>(HashArrayMappedTrie.empty());
private final HashArrayMappedTrie<K, V> trie;
private HashMap(HashArrayMappedTrie<K, V> trie) {
this.trie = trie;
}
/**
* Returns a {@link java.util.stream.Collector} which may be used in conjunction with
* {@link java.util.stream.Stream#collect(java.util.stream.Collector)} to obtain a {@link HashMap}.
*
* @param <K> The key type
* @param <V> The value type
* @return A {@link HashMap} Collector.
*/
public static <K, V> Collector<Tuple2<K, V>, ArrayList<Tuple2<K, V>>, HashMap<K, V>> collector() {
final Supplier<ArrayList<Tuple2<K, V>>> supplier = ArrayList::new;
final BiConsumer<ArrayList<Tuple2<K, V>>, Tuple2<K, V>> accumulator = ArrayList::add;
final BinaryOperator<ArrayList<Tuple2<K, V>>> combiner = (left, right) -> {
left.addAll(right);
return left;
};
final Function<ArrayList<Tuple2<K, V>>, HashMap<K, V>> finisher = HashMap::ofEntries;
return Collector.of(supplier, accumulator, combiner, finisher);
}
@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> empty() {
return (HashMap<K, V>) EMPTY;
}
/**
* Narrows a widened {@code HashMap<? extends K, ? extends V>} to {@code HashMap<K, V>}
* by performing a type-safe cast. This is eligible because immutable/read-only
* collections are covariant.
*
* @param hashMap A {@code HashMap}.
* @param <K> Key type
* @param <V> Value type
* @return the given {@code hashMap} instance as narrowed type {@code HashMap<K, V>}.
*/
@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> narrow(HashMap<? extends K, ? extends V> hashMap) {
return (HashMap<K, V>) hashMap;
}
/**
* Returns a singleton {@code HashMap}, i.e. a {@code HashMap} of one element.
*
* @param entry A map entry.
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entry
*/
public static <K, V> HashMap<K, V> of(Tuple2<? extends K, ? extends V> entry) {
return new HashMap<>(HashArrayMappedTrie.<K, V> empty().put(entry._1, entry._2));
}
/**
* Returns a {@code HashMap}, from a source java.util.Map.
*
* @param map A map
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given map
*/
public static <K, V> HashMap<K, V> ofAll(java.util.Map<? extends K, ? extends V> map) {
Objects.requireNonNull(map, "map is null");
HashArrayMappedTrie<K, V> tree = HashArrayMappedTrie.empty();
for (java.util.Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
tree = tree.put(entry.getKey(), entry.getValue());
}
return wrap(tree);
}
/**
* Returns a {@code HashMap}, from entries mapped from stream.
*
* @param stream the source stream
* @param keyMapper the key mapper
* @param valueMapper the value mapper
* @param <T> The stream element type
* @param <K> The key type
* @param <V> The value type
* @return A new Map
*/
public static <T, K, V> HashMap<K, V> ofAll(java.util.stream.Stream<? extends T> stream,
Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends V> valueMapper) {
return Maps.ofStream(empty(), stream, keyMapper, valueMapper);
}
/**
* Returns a {@code HashMap}, from entries mapped from stream.
*
* @param stream the source stream
* @param entryMapper the entry mapper
* @param <T> The stream element type
* @param <K> The key type
* @param <V> The value type
* @return A new Map
*/
public static <T, K, V> HashMap<K, V> ofAll(java.util.stream.Stream<? extends T> stream,
Function<? super T, Tuple2<? extends K, ? extends V>> entryMapper) {
return Maps.ofStream(empty(), stream, entryMapper);
}
/**
* Returns a singleton {@code HashMap}, i.e. a {@code HashMap} of one element.
*
* @param key A singleton map key.
* @param value A singleton map value.
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entry
*/
public static <K, V> HashMap<K, V> of(K key, V value) {
return new HashMap<>(HashArrayMappedTrie.<K, V> empty().put(key, value));
}
/**
* Creates a HashMap of the given list of key-value pairs.
*
* @param k1 a key for the map
* @param v1 the value for k1
* @param k2 a key for the map
* @param v2 the value for k2
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
public static <K, V> HashMap<K, V> of(K k1, V v1, K k2, V v2) {
return of(k1, v1).put(k2, v2);
}
/**
* Creates a HashMap of the given list of key-value pairs.
*
* @param k1 a key for the map
* @param v1 the value for k1
* @param k2 a key for the map
* @param v2 the value for k2
* @param k3 a key for the map
* @param v3 the value for k3
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
public static <K, V> HashMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
return of(k1, v1, k2, v2).put(k3, v3);
}
/**
* Creates a HashMap of the given list of key-value pairs.
*
* @param <K> The key type
* @param <V> The value type
* @param k1 a key for the map
* @param v1 the value for k1
* @param k2 a key for the map
* @param v2 the value for k2
* @param k3 a key for the map
* @param v3 the value for k3
* @param k4 a key for the map
* @param v4 the value for k4
* @return A new Map containing the given entries
*/
public static <K, V> HashMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
return of(k1, v1, k2, v2, k3, v3).put(k4, v4);
}
/**
* Creates a HashMap of the given list of key-value pairs.
*
* @param k1 a key for the map
* @param v1 the value for k1
* @param k2 a key for the map
* @param v2 the value for k2
* @param k3 a key for the map
* @param v3 the value for k3
* @param k4 a key for the map
* @param v4 the value for k4
* @param k5 a key for the map
* @param v5 the value for k5
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
public static <K, V> HashMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
return of(k1, v1, k2, v2, k3, v3, k4, v4).put(k5, v5);
}
/**
* Creates a HashMap of the given list of key-value pairs.
*
* @param k1 a key for the map
* @param v1 the value for k1
* @param k2 a key for the map
* @param v2 the value for k2
* @param k3 a key for the map
* @param v3 the value for k3
* @param k4 a key for the map
* @param v4 the value for k4
* @param k5 a key for the map
* @param v5 the value for k5
* @param k6 a key for the map
* @param v6 the value for k6
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
public static <K, V> HashMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) {
return of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5).put(k6, v6);
}
/**
* Creates a HashMap of the given list of key-value pairs.
*
* @param k1 a key for the map
* @param v1 the value for k1
* @param k2 a key for the map
* @param v2 the value for k2
* @param k3 a key for the map
* @param v3 the value for k3
* @param k4 a key for the map
* @param v4 the value for k4
* @param k5 a key for the map
* @param v5 the value for k5
* @param k6 a key for the map
* @param v6 the value for k6
* @param k7 a key for the map
* @param v7 the value for k7
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
public static <K, V> HashMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) {
return of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6).put(k7, v7);
}
/**
* Creates a HashMap of the given list of key-value pairs.
*
* @param k1 a key for the map
* @param v1 the value for k1
* @param k2 a key for the map
* @param v2 the value for k2
* @param k3 a key for the map
* @param v3 the value for k3
* @param k4 a key for the map
* @param v4 the value for k4
* @param k5 a key for the map
* @param v5 the value for k5
* @param k6 a key for the map
* @param v6 the value for k6
* @param k7 a key for the map
* @param v7 the value for k7
* @param k8 a key for the map
* @param v8 the value for k8
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
public static <K, V> HashMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) {
return of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7).put(k8, v8);
}
/**
* Creates a HashMap of the given list of key-value pairs.
*
* @param k1 a key for the map
* @param v1 the value for k1
* @param k2 a key for the map
* @param v2 the value for k2
* @param k3 a key for the map
* @param v3 the value for k3
* @param k4 a key for the map
* @param v4 the value for k4
* @param k5 a key for the map
* @param v5 the value for k5
* @param k6 a key for the map
* @param v6 the value for k6
* @param k7 a key for the map
* @param v7 the value for k7
* @param k8 a key for the map
* @param v8 the value for k8
* @param k9 a key for the map
* @param v9 the value for k9
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
public static <K, V> HashMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
return of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8).put(k9, v9);
}
/**
* Creates a HashMap of the given list of key-value pairs.
*
* @param k1 a key for the map
* @param v1 the value for k1
* @param k2 a key for the map
* @param v2 the value for k2
* @param k3 a key for the map
* @param v3 the value for k3
* @param k4 a key for the map
* @param v4 the value for k4
* @param k5 a key for the map
* @param v5 the value for k5
* @param k6 a key for the map
* @param v6 the value for k6
* @param k7 a key for the map
* @param v7 the value for k7
* @param k8 a key for the map
* @param v8 the value for k8
* @param k9 a key for the map
* @param v9 the value for k9
* @param k10 a key for the map
* @param v10 the value for k10
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
public static <K, V> HashMap<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
return of(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9).put(k10, v10);
}
/**
* Returns an HashMap containing {@code n} values of a given Function {@code f}
* over a range of integer values from 0 to {@code n - 1}.
*
* @param <K> The key type
* @param <V> The value type
* @param n The number of elements in the HashMap
* @param f The Function computing element values
* @return An HashMap consisting of elements {@code f(0),f(1), ..., f(n - 1)}
* @throws NullPointerException if {@code f} is null
*/
@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> tabulate(int n, Function<? super Integer, ? extends Tuple2<? extends K, ? extends V>> f) {
Objects.requireNonNull(f, "f is null");
return ofEntries(Collections.tabulate(n, (Function<? super Integer, ? extends Tuple2<K, V>>) f));
}
/**
* Returns an HashMap containing {@code n} values supplied by a given Supplier {@code s}.
*
* @param <K> The key type
* @param <V> The value type
* @param n The number of elements in the HashMap
* @param s The Supplier computing element values
* @return An HashMap of size {@code n}, where each element contains the result supplied by {@code s}.
* @throws NullPointerException if {@code s} is null
*/
@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> fill(int n, Supplier<? extends Tuple2<? extends K, ? extends V>> s) {
Objects.requireNonNull(s, "s is null");
return ofEntries(Collections.fill(n, (Supplier<? extends Tuple2<K, V>>) s));
}
/**
* Creates a HashMap of the given entries.
*
* @param entries Map entries
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
@SafeVarargs
public static <K, V> HashMap<K, V> ofEntries(java.util.Map.Entry<? extends K, ? extends V>... entries) {
Objects.requireNonNull(entries, "entries is null");
HashArrayMappedTrie<K, V> trie = HashArrayMappedTrie.empty();
for (java.util.Map.Entry<? extends K, ? extends V> entry : entries) {
trie = trie.put(entry.getKey(), entry.getValue());
}
return wrap(trie);
}
/**
* Creates a HashMap of the given entries.
*
* @param entries Map entries
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
@SafeVarargs
public static <K, V> HashMap<K, V> ofEntries(Tuple2<? extends K, ? extends V>... entries) {
Objects.requireNonNull(entries, "entries is null");
HashArrayMappedTrie<K, V> trie = HashArrayMappedTrie.empty();
for (Tuple2<? extends K, ? extends V> entry : entries) {
trie = trie.put(entry._1, entry._2);
}
return wrap(trie);
}
/**
* Creates a HashMap of the given entries.
*
* @param entries Map entries
* @param <K> The key type
* @param <V> The value type
* @return A new Map containing the given entries
*/
@SuppressWarnings("unchecked")
public static <K, V> HashMap<K, V> ofEntries(Iterable<? extends Tuple2<? extends K, ? extends V>> entries) {
Objects.requireNonNull(entries, "entries is null");
if (entries instanceof HashMap) {
return (HashMap<K, V>) entries;
} else {
HashArrayMappedTrie<K, V> trie = HashArrayMappedTrie.empty();
for (Tuple2<? extends K, ? extends V> entry : entries) {
trie = trie.put(entry._1, entry._2);
}
return trie.isEmpty() ? empty() : wrap(trie);
}
}
@Override
public <K2, V2> HashMap<K2, V2> bimap(Function<? super K, ? extends K2> keyMapper, Function<? super V, ? extends V2> valueMapper) {
Objects.requireNonNull(keyMapper, "keyMapper is null");
Objects.requireNonNull(valueMapper, "valueMapper is null");
final Iterator<Tuple2<K2, V2>> entries = iterator().map(entry -> Tuple.of(keyMapper.apply(entry._1), valueMapper.apply(entry._2)));
return HashMap.ofEntries(entries);
}
@Override
public Tuple2<V, HashMap<K, V>> computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
return Maps.computeIfAbsent(this, key, mappingFunction);
}
@Override
public Tuple2<Option<V>, HashMap<K, V>> computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
return Maps.computeIfPresent(this, key, remappingFunction);
}
@Override
public boolean containsKey(K key) {
return trie.containsKey(key);
}
@Override
public HashMap<K, V> distinct() {
return Maps.distinct(this);
}
@Override
public HashMap<K, V> distinctBy(Comparator<? super Tuple2<K, V>> comparator) {
return Maps.distinctBy(this, this::createFromEntries, comparator);
}
@Override
public <U> HashMap<K, V> distinctBy(Function<? super Tuple2<K, V>, ? extends U> keyExtractor) {
return Maps.distinctBy(this, this::createFromEntries, keyExtractor);
}
@Override
public HashMap<K, V> drop(int n) {
return Maps.drop(this, this::createFromEntries, HashMap::empty, n);
}
@Override
public HashMap<K, V> dropRight(int n) {
return Maps.dropRight(this, this::createFromEntries, HashMap::empty, n);
}
@Override
public HashMap<K, V> dropUntil(Predicate<? super Tuple2<K, V>> predicate) {
return Maps.dropUntil(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> dropWhile(Predicate<? super Tuple2<K, V>> predicate) {
return Maps.dropWhile(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> filter(BiPredicate<? super K, ? super V> predicate) {
return Maps.filter(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> filter(Predicate<? super Tuple2<K, V>> predicate) {
return Maps.filter(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> filterKeys(Predicate<? super K> predicate) {
return Maps.filterKeys(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> filterValues(Predicate<? super V> predicate) {
return Maps.filterValues(this, this::createFromEntries, predicate);
}
@Override
public <K2, V2> HashMap<K2, V2> flatMap(BiFunction<? super K, ? super V, ? extends Iterable<Tuple2<K2, V2>>> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
return foldLeft(HashMap.<K2, V2> empty(), (acc, entry) -> {
for (Tuple2<? extends K2, ? extends V2> mappedEntry : mapper.apply(entry._1, entry._2)) {
acc = acc.put(mappedEntry);
}
return acc;
});
}
@Override
public Option<V> get(K key) {
return trie.get(key);
}
@Override
public V getOrElse(K key, V defaultValue) {
return trie.getOrElse(key, defaultValue);
}
@Override
public <C> Map<C, HashMap<K, V>> groupBy(Function<? super Tuple2<K, V>, ? extends C> classifier) {
return Maps.groupBy(this, this::createFromEntries, classifier);
}
@Override
public Iterator<HashMap<K, V>> grouped(int size) {
return Maps.grouped(this, this::createFromEntries, size);
}
@Override
public Tuple2<K, V> head() {
if (isEmpty()) {
throw new NoSuchElementException("head of empty HashMap");
} else {
return iterator().next();
}
}
@Override
public HashMap<K, V> init() {
if (trie.isEmpty()) {
throw new UnsupportedOperationException("init of empty HashMap");
} else {
return remove(last()._1);
}
}
@Override
public Option<HashMap<K, V>> initOption() {
return Maps.initOption(this);
}
/**
* A {@code HashMap} is computed synchronously.
*
* @return false
*/
@Override
public boolean isAsync() {
return false;
}
@Override
public boolean isEmpty() {
return trie.isEmpty();
}
/**
* A {@code HashMap} is computed eagerly.
*
* @return false
*/
@Override
public boolean isLazy() {
return false;
}
@Override
public Iterator<Tuple2<K, V>> iterator() {
return trie.iterator();
}
@Override
public Set<K> keySet() {
return HashSet.ofAll(iterator().map(Tuple2::_1));
}
@Override
public <K2, V2> HashMap<K2, V2> map(BiFunction<? super K, ? super V, Tuple2<K2, V2>> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
return foldLeft(HashMap.empty(), (acc, entry) -> acc.put(entry.map(mapper)));
}
@Override
public <K2> HashMap<K2, V> mapKeys(Function<? super K, ? extends K2> keyMapper) {
Objects.requireNonNull(keyMapper, "keyMapper is null");
return map((k, v) -> Tuple.of(keyMapper.apply(k), v));
}
@Override
public <K2> HashMap<K2, V> mapKeys(Function<? super K, ? extends K2> keyMapper, BiFunction<? super V, ? super V, ? extends V> valueMerge) {
return Collections.mapKeys(this, HashMap.empty(), keyMapper, valueMerge);
}
@Override
public <V2> HashMap<K, V2> mapValues(Function<? super V, ? extends V2> valueMapper) {
Objects.requireNonNull(valueMapper, "valueMapper is null");
return map((k, v) -> Tuple.of(k, valueMapper.apply(v)));
}
@Override
public HashMap<K, V> merge(Map<? extends K, ? extends V> that) {
return Maps.merge(this, this::createFromEntries, that);
}
@Override
public <U extends V> HashMap<K, V> merge(Map<? extends K, U> that,
BiFunction<? super V, ? super U, ? extends V> collisionResolution) {
return Maps.merge(this, this::createFromEntries, that, collisionResolution);
}
@Override
public HashMap<K, V> orElse(Iterable<? extends Tuple2<K, V>> other) {
return isEmpty() ? ofEntries(other) : this;
}
@Override
public HashMap<K, V> orElse(Supplier<? extends Iterable<? extends Tuple2<K, V>>> supplier) {
return isEmpty() ? ofEntries(supplier.get()) : this;
}
@Override
public Tuple2<HashMap<K, V>, HashMap<K, V>> partition(Predicate<? super Tuple2<K, V>> predicate) {
return Maps.partition(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> peek(Consumer<? super Tuple2<K, V>> action) {
return Maps.peek(this, action);
}
@Override
public <U extends V> HashMap<K, V> put(K key, U value, BiFunction<? super V, ? super U, ? extends V> merge) {
return Maps.put(this, key, value, merge);
}
@Override
public HashMap<K, V> put(K key, V value) {
return new HashMap<>(trie.put(key, value));
}
@Override
public HashMap<K, V> put(Tuple2<? extends K, ? extends V> entry) {
return Maps.put(this, entry);
}
@Override
public <U extends V> HashMap<K, V> put(Tuple2<? extends K, U> entry,
BiFunction<? super V, ? super U, ? extends V> merge) {
return Maps.put(this, entry, merge);
}
@Override
public HashMap<K, V> remove(K key) {
final HashArrayMappedTrie<K, V> result = trie.remove(key);
return result.size() == trie.size() ? this : wrap(result);
}
@Override
public HashMap<K, V> removeAll(BiPredicate<? super K, ? super V> predicate) {
return Maps.removeAll(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> removeAll(Iterable<? extends K> keys) {
Objects.requireNonNull(keys, "keys is null");
HashArrayMappedTrie<K, V> result = trie;
for (K key : keys) {
result = result.remove(key);
}
if (result.isEmpty()) {
return empty();
} else if (result.size() == trie.size()) {
return this;
} else {
return wrap(result);
}
}
@Override
public HashMap<K, V> removeKeys(Predicate<? super K> predicate) {
return Maps.removeKeys(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> removeValues(Predicate<? super V> predicate) {
return Maps.removeValues(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> replace(Tuple2<K, V> currentElement, Tuple2<K, V> newElement) {
return Maps.replace(this, currentElement, newElement);
}
@Override
public HashMap<K, V> replaceAll(Tuple2<K, V> currentElement, Tuple2<K, V> newElement) {
return Maps.replaceAll(this, currentElement, newElement);
}
@Override
public HashMap<K, V> replaceValue(K key, V value) {
return Maps.replaceValue(this, key, value);
}
@Override
public HashMap<K, V> replace(K key, V oldValue, V newValue) {
return Maps.replace(this, key, oldValue, newValue);
}
@Override
public HashMap<K, V> replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
return Maps.replaceAll(this, function);
}
@Override
public HashMap<K, V> retainAll(Iterable<? extends Tuple2<K, V>> elements) {
Objects.requireNonNull(elements, "elements is null");
HashArrayMappedTrie<K, V> tree = HashArrayMappedTrie.empty();
for (Tuple2<K, V> entry : elements) {
if (contains(entry)) {
tree = tree.put(entry._1, entry._2);
}
}
return wrap(tree);
}
@Override
public HashMap<K, V> scan(
Tuple2<K, V> zero,
BiFunction<? super Tuple2<K, V>, ? super Tuple2<K, V>, ? extends Tuple2<K, V>> operation) {
return Maps.scan(this, zero, operation, this::createFromEntries);
}
@Override
public int size() {
return trie.size();
}
@Override
public Iterator<HashMap<K, V>> slideBy(Function<? super Tuple2<K, V>, ?> classifier) {
return Maps.slideBy(this, this::createFromEntries, classifier);
}
@Override
public Iterator<HashMap<K, V>> sliding(int size) {
return Maps.sliding(this, this::createFromEntries, size);
}
@Override
public Iterator<HashMap<K, V>> sliding(int size, int step) {
return Maps.sliding(this, this::createFromEntries, size, step);
}
@Override
public Tuple2<HashMap<K, V>, HashMap<K, V>> span(Predicate<? super Tuple2<K, V>> predicate) {
return Maps.span(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> tail() {
if (trie.isEmpty()) {
throw new UnsupportedOperationException("tail of empty HashMap");
} else {
return remove(head()._1);
}
}
@Override
public Option<HashMap<K, V>> tailOption() {
return Maps.tailOption(this);
}
@Override
public HashMap<K, V> take(int n) {
return Maps.take(this, this::createFromEntries, n);
}
@Override
public HashMap<K, V> takeRight(int n) {
return Maps.takeRight(this, this::createFromEntries, n);
}
@Override
public HashMap<K, V> takeUntil(Predicate<? super Tuple2<K, V>> predicate) {
return Maps.takeUntil(this, this::createFromEntries, predicate);
}
@Override
public HashMap<K, V> takeWhile(Predicate<? super Tuple2<K, V>> predicate) {
return Maps.takeWhile(this, this::createFromEntries, predicate);
}
@Override
public java.util.HashMap<K, V> toJavaMap() {
return toJavaMap(java.util.HashMap::new, t -> t);
}
@Override
public Seq<V> values() {
return map(Tuple2::_2);
}
@Override
public boolean equals(Object o) {
return Collections.equals(this, o);
}
@Override
public int hashCode() {
return Collections.hashUnordered(this);
}
private Object readResolve() {
return isEmpty() ? EMPTY : this;
}
@Override
public String stringPrefix() {
return "HashMap";
}
@Override
public String toString() {
return mkString(stringPrefix() + "(", ", ", ")");
}
private static <K, V> HashMap<K, V> wrap(HashArrayMappedTrie<K, V> trie) {
return trie.isEmpty() ? empty() : new HashMap<>(trie);
}
// We need this method to narrow the argument of `ofEntries`.
// If this method is static with type args <K, V>, the jdk fails to infer types at the call site.
private HashMap<K, V> createFromEntries(Iterable<Tuple2<K, V>> tuples) {
return HashMap.ofEntries(tuples);
}
}