com.github.andrewoma.dexx.collection.DerivedKeyHashMap Maven / Gradle / Ivy
/*
* Copyright (c) 2014 Andrew O'Malley
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.github.andrewoma.dexx.collection;
import com.github.andrewoma.dexx.collection.internal.base.AbstractMap;
import com.github.andrewoma.dexx.collection.internal.builder.AbstractSelfBuilder;
import com.github.andrewoma.dexx.collection.internal.hashmap.CompactHashMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Iterator;
/**
* {@code DerivedKeyHashMap} is a {@code HashMap} variant where the key for the {@code Map} is derived from the value stored.
*
* By deriving the key it is possible to reduce the memory overhead per node in the map (assuming the key is a
* primitive field in the value object). e.g.
*
*
{@code
* static class Value {
* int key;
* int value;
* }
*
* DerivedKeyHashMap map = new DerivedKeyHashMap(
* new KeyFunction() {
* public Integer key(Value value) {
* return value.key;
* }
* });
*
* Value value = new Value();
* value.key = 1;
* value.value = 100;
* map = map.put(value.key, value);
* }
*
* The underlying implementation is a port of Scala's HashMap which is an implementation of a
* hash array mapped trie.
*
* It uses significantly less memory than Scala's implementation as the leaf nodes are the values
* themselves (not objects containing keys, values and hashes).
*
*
As the key is derived from the value, {@code DerivedKeyHashMap} does not support {@code null} values.
*/
public class DerivedKeyHashMap extends AbstractMap {
private final KeyFunction keyFunction;
private CompactHashMap compactHashMap = CompactHashMap.empty();
@NotNull
public static BuilderFactory, DerivedKeyHashMap> factory(final KeyFunction keyFunction) {
return new BuilderFactory, DerivedKeyHashMap>() {
@NotNull
@Override
public Builder, DerivedKeyHashMap> newBuilder() {
return new AbstractSelfBuilder, DerivedKeyHashMap>(new DerivedKeyHashMap(keyFunction)) {
@NotNull
@Override
public Builder, DerivedKeyHashMap> add(Pair element) {
result = result.put(element.component1(), element.component2());
return this;
}
};
}
};
}
public DerivedKeyHashMap(@NotNull KeyFunction keyFunction) {
this.keyFunction = keyFunction;
}
private DerivedKeyHashMap(KeyFunction keyFunction, CompactHashMap compactHashMap) {
this.keyFunction = keyFunction;
this.compactHashMap = compactHashMap;
}
@Override
public boolean containsKey(@NotNull K key) {
return get(key) != null;
}
@NotNull
@Override
public DerivedKeyHashMap put(@NotNull K key, V value) {
return new DerivedKeyHashMap(keyFunction, compactHashMap.put(key, value, keyFunction));
}
@Nullable
@Override
public V get(@NotNull K key) {
return compactHashMap.get(key, keyFunction);
}
@NotNull
@Override
public DerivedKeyHashMap remove(@NotNull K key) {
return new DerivedKeyHashMap(keyFunction, compactHashMap.remove(key, keyFunction));
}
@Override
public int size() {
return compactHashMap.size();
}
@Override
public void forEach(@NotNull final Function, U> f) {
compactHashMap.forEach(new Function, Object>() {
@Override
public Object invoke(Pair parameter) {
f.invoke(parameter);
return null;
}
}, keyFunction);
}
@NotNull
@Override
public Iterator> iterator() {
return compactHashMap.iterator(keyFunction);
}
}