Added ImmutableOpenHashMap that is not editable (is linked by default

for fast iteration)
This commit is contained in:
Speiger 2021-06-25 17:44:48 +02:00
parent 84bc785cdc
commit 9d17dc17fd
5 changed files with 982 additions and 3 deletions

View File

@ -9,6 +9,7 @@
- Added: OpenHashSets now implement foreach and have less overhead.
- Added: ImmutableOpenHashSet that is not editable (is linked by default for fast iteration)
- Added: CustomOpenHashSets now implement foreach and have less overhead.
- Added: ImmutableOpenHashMap that is not editable (is linked by default for fast iteration)
### Version 0.3.1
- Fixed: containsKey & containsValue in HashMaps were deprecated for Object Variants.

View File

@ -141,6 +141,7 @@ public class GlobalVariables
addAbstractMapper("IMMUTABLE_HASH_SET", "Immutable%sOpenHashSet");
addClassMapper("CUSTOM_HASH_SET", "OpenCustomHashSet");
addClassMapper("HASH_SET", "OpenHashSet");
addAbstractBiMapper("IMMUTABLE_HASH_MAP", "Immutable%sOpenHashMap", "2");
addBiClassMapper("LINKED_CUSTOM_HASH_MAP", "LinkedOpenCustomHashMap", "2");
addBiClassMapper("LINKED_HASH_MAP", "LinkedOpenHashMap", "2");
addBiClassMapper("CUSTOM_HASH_MAP", "OpenCustomHashMap", "2");

View File

@ -70,7 +70,7 @@ public class PrimitiveCollectionsBuilder extends TemplateProcessor
enumRequired.add("LinkedEnumMap");
biRequired.put("BiConsumer", "");
biRequired.put("UnaryOperator", "");
addBiClass("Function", "Maps", "Map", "SortedMap", "NavigableMap", "AbstractMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap");
addBiClass("Function", "Maps", "Map", "SortedMap", "NavigableMap", "AbstractMap", "ImmutableOpenHashMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap");
nameRemapper.put("BiConsumer", "%sConsumer");
nameRemapper.put("IArray", "I%sArray");
nameRemapper.put("AbstractMap", "Abstract%sMap");
@ -81,10 +81,11 @@ public class PrimitiveCollectionsBuilder extends TemplateProcessor
nameRemapper.put("LinkedEnumMap", "LinkedEnum2%sMap");
nameRemapper.put("ImmutableList", "Immutable%sList");
nameRemapper.put("ImmutableOpenHashSet", "Immutable%sOpenHashSet");
nameRemapper.put("ImmutableOpenHashMap", "Immutable%sOpenHashMap");
addBlockage(ClassType.OBJECT, "Consumer", "Comparator", "Stack");
addBlockage(ClassType.BOOLEAN, "ArraySet", "AVLTreeSet", "RBTreeSet", "SortedSet", "NavigableSet", "OpenHashSet", "OpenCustomHashSet", "LinkedOpenHashSet", "LinkedOpenCustomHashSet");
addBlockage(ClassType.BOOLEAN, "ImmutableOpenHashSet", "SortedMap", "NavigableMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap");
addBlockage(ClassType.BOOLEAN, "ImmutableOpenHashMap", "ImmutableOpenHashSet", "SortedMap", "NavigableMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap");
}
protected void create(ClassType mainType, ClassType subType)

View File

@ -46,7 +46,7 @@ import speiger.src.collections.utils.HashUtil;
public class LINKED_HASH_MAP KEY_VALUE_GENERIC_TYPE extends HASH_MAP KEY_VALUE_GENERIC_TYPE implements SORTED_MAP KEY_VALUE_GENERIC_TYPE
{
/** The Backing array for links between nodes. Left 32 Bits => Previous Entry, Right 32 Bits => Next Entry */
protected long[] links;
protected transient long[] links;
/** The First Index in the Map */
protected int firstIndex = -1;
/** The Last Index in the Map */

View File

@ -0,0 +1,976 @@
package speiger.src.collections.PACKAGE.maps.impl.immutable;
import java.util.Map;
import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.Consumer;
#if !TYPE_OBJECT
import speiger.src.collections.PACKAGE.collections.BI_ITERATOR;
import speiger.src.collections.PACKAGE.functions.CONSUMER;
import speiger.src.collections.PACKAGE.functions.COMPARATOR;
#endif
import speiger.src.collections.PACKAGE.functions.consumer.BI_CONSUMER;
import speiger.src.collections.PACKAGE.functions.function.FUNCTION;
import speiger.src.collections.PACKAGE.functions.function.UNARY_OPERATOR;
import speiger.src.collections.PACKAGE.lists.LIST_ITERATOR;
import speiger.src.collections.PACKAGE.maps.interfaces.SORTED_MAP;
import speiger.src.collections.PACKAGE.maps.abstracts.ABSTRACT_MAP;
import speiger.src.collections.PACKAGE.maps.interfaces.MAP;
import speiger.src.collections.PACKAGE.sets.SORTED_SET;
import speiger.src.collections.PACKAGE.utils.maps.MAPS;
#if !TYPE_OBJECT
import speiger.src.collections.PACKAGE.utils.ARRAYS;
#endif
#if !TYPE_OBJECT
import speiger.src.collections.PACKAGE.sets.ABSTRACT_SET;
import speiger.src.collections.PACKAGE.sets.SET;
#endif
import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_ABSTRACT_COLLECTION;
import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_COLLECTION;
import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_ITERATOR;
#if !SAME_TYPE
import speiger.src.collections.VALUE_PACKAGE.functions.function.VALUE_UNARY_OPERATOR;
#if !VALUE_OBJECT
import speiger.src.collections.VALUE_PACKAGE.functions.VALUE_CONSUMER;
import speiger.src.collections.VALUE_PACKAGE.lists.VALUE_LIST_ITERATOR;
import speiger.src.collections.VALUE_PACKAGE.utils.VALUE_ARRAYS;
#endif
#endif
import speiger.src.collections.objects.collections.ObjectBidirectionalIterator;
#if !TYPE_OBJECT
import speiger.src.collections.objects.lists.ObjectListIterator;
import speiger.src.collections.objects.sets.ObjectSortedSet;
#endif
import speiger.src.collections.objects.sets.AbstractObjectSet;
import speiger.src.collections.objects.sets.ObjectSet;
import speiger.src.collections.utils.HashUtil;
import speiger.src.collections.utils.SanityChecks;
/**
* A Type Specific Custom implementation of the HashMap
* Instead of using Wrapper Object Arrays for storing keys and values there is dedicated arrays for storing keys and values.
* Extra to that there is a couple quality of life functions provided
* @Type(T)
* @ValueType(V)
*/
public class IMMUTABLE_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE implements SORTED_MAP KEY_VALUE_GENERIC_TYPE
{
/** The Backing keys array */
protected transient KEY_TYPE[] keys;
/** The Backing values array */
protected transient VALUE_TYPE[] values;
/** The Backing array for links between nodes. Left 32 Bits => Previous Entry, Right 32 Bits => Next Entry */
protected transient long[] links;
/** If a null value is present */
protected transient boolean containsNull;
/** Index of the Null Value */
protected transient int nullIndex;
/** Max Index that is allowed to be searched through nullIndex - 1 */
protected transient int mask;
/** The First Index in the Map */
protected int firstIndex = -1;
/** The Last Index in the Map */
protected int lastIndex = -1;
/** EntrySet cache */
protected transient FastEntrySet KEY_VALUE_GENERIC_TYPE entrySet;
/** KeySet cache */
protected transient SET KEY_GENERIC_TYPE keySet;
/** Values cache */
protected transient VALUE_COLLECTION VALUE_GENERIC_TYPE valuesC;
/** Amount of Elements stored in the HashMap */
protected int size;
#if !TYPE_OBJECT || !VALUE_OBJECT
/**
* Helper constructor that allow to create a map from boxed values (it will unbox them)
* @param keys the keys that should be put into the map
* @param values the values that should be put into the map.
* @throws IllegalStateException if the keys and values do not match in lenght
*/
public IMMUTABLE_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values) {
this(keys, values, HashUtil.DEFAULT_LOAD_FACTOR);
}
/**
* Helper constructor that allow to create a map from boxed values (it will unbox them)
* @param keys the keys that should be put into the map
* @param values the values that should be put into the map.
* @param loadFactor the percentage of how full the backing array can be before they resize
* @throws IllegalStateException if the keys and values do not match in lenght
* @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
*/
public IMMUTABLE_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values, float loadFactor) {
if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size");
#if TYPE_OBJECT && VALUE_OBJECT
init(keys, values, 0, keys.length, loadFactor);
#else if TYPE_OBJECT
init(keys, VALUE_ARRAYS.unwrap(values), 0, keys.length, loadFactor);
#else if VALUE_OBJECT
init(ARRAYS.unwrap(keys), values, 0, keys.length, loadFactor);
#else
init(ARRAYS.unwrap(keys), VALUE_ARRAYS.unwrap(values), 0, keys.length, loadFactor);
#endif
}
#endif
/**
* Helper constructor that allow to create a map from unboxed values
* @param keys the keys that should be put into the map
* @param values the values that should be put into the map.
* @throws IllegalStateException if the keys and values do not match in lenght
*/
public IMMUTABLE_HASH_MAP(KEY_TYPE[] keys, VALUE_TYPE[] values) {
this(keys, values, HashUtil.DEFAULT_LOAD_FACTOR);
}
/**
* Helper constructor that allow to create a map from unboxed values
* @param keys the keys that should be put into the map
* @param values the values that should be put into the map.
* @param loadFactor the percentage of how full the backing array can be before they resize
* @throws IllegalStateException if the keys and values do not match in lenght
* @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
*/
public IMMUTABLE_HASH_MAP(KEY_TYPE[] keys, VALUE_TYPE[] values, float loadFactor) {
if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size");
init(keys, values, 0, keys.length, loadFactor);
}
/**
* A Helper constructor that allows to create a Map with exactly the same values as the provided map.
* @param map the values that should be present in the map
*/
public IMMUTABLE_HASH_MAP(Map<? extends CLASS_TYPE, ? extends CLASS_VALUE_TYPE> map) {
this(map, HashUtil.DEFAULT_LOAD_FACTOR);
}
/**
* A Helper constructor that allows to create a Map with exactly the same values as the provided map.
* @param map the values that should be present in the map
* @param loadFactor the percentage of how full the backing array can be before they resize
* @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
*/
public IMMUTABLE_HASH_MAP(Map<? extends CLASS_TYPE, ? extends CLASS_VALUE_TYPE> map, float loadFactor) {
KEY_TYPE[] keys = NEW_KEY_ARRAY(map.size());
VALUE_TYPE[] values = NEW_VALUE_ARRAY(keys.length);
int index = 0;
for(Map.Entry<? extends CLASS_TYPE, ? extends CLASS_VALUE_TYPE> entry : map.entrySet()) {
keys[index] = OBJ_TO_KEY(entry.getKey());
values[index] = OBJ_TO_VALUE(entry.getValue());
index++;
}
init(keys, values, 0, index, loadFactor);
}
/**
* A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map.
* @param map the values that should be present in the map
*/
public IMMUTABLE_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map) {
this(map, HashUtil.DEFAULT_LOAD_FACTOR);
}
/**
* A Type Specific Helper function that allows to create a new Map with exactly the same values as the provided map.
* @param map the values that should be present in the map
* @param loadFactor the percentage of how full the backing array can be before they resize
* @throws IllegalStateException if the loadfactor is either below/equal to 0 or above/equal to 1
*/
public IMMUTABLE_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map, float loadFactor) {
KEY_TYPE[] keys = NEW_KEY_ARRAY(map.size());
VALUE_TYPE[] values = NEW_VALUE_ARRAY(keys.length);
int index = 0;
for(MAP.Entry KEY_VALUE_GENERIC_TYPE entry : MAPS.fastIterable(map)) {
keys[index] = entry.ENTRY_KEY();
values[index] = entry.ENTRY_VALUE();
index++;
}
init(keys, values, 0, index, loadFactor);
}
protected void init(KEY_TYPE[] a, VALUE_TYPE[] b, int offset, int length, float loadFactor) {
SanityChecks.checkArrayCapacity(a.length, offset, length);
int newSize = HashUtil.arraySize(length+1, loadFactor);
int newMask = newSize - 1;
KEY_TYPE[] newKeys = NEW_KEY_ARRAY(newSize + 1);
VALUE_TYPE[] newValues = NEW_VALUE_ARRAY(newSize + 1);
long[] newLinks = new long[newSize + 1];
int prev = -1;
for(int i = offset,m=offset+length;i<m;i++)
{
KEY_TYPE o = a[i];
if(KEY_EQUALS_NULL(o)) {
if(!containsNull) size++;
containsNull = true;
continue;
}
boolean found = true;
int pos = HashUtil.mix(KEY_TO_HASH(o)) & newMask;
KEY_TYPE current = newKeys[pos];
if(KEY_EQUALS_NOT_NULL(current)) {
if(KEY_EQUALS(current, o)) {
found = false;
break;
}
while(KEY_EQUALS_NOT_NULL((current = newKeys[pos = (++pos & mask)]))) {
if(KEY_EQUALS(current, o)) {
found = false;
break;
}
}
}
if(found) {
size++;
newKeys[pos] = o;
values[pos] = b[i];
if(prev != -1) {
newLinks[prev] ^= ((newLinks[prev] ^ (pos & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
newLinks[pos] ^= ((newLinks[pos] ^ ((prev & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L);
prev = pos;
}
else {
prev = firstIndex = pos;
newLinks[pos] = -1L;
}
}
}
nullIndex = size;
mask = newMask;
keys = newKeys;
values = newValues;
links = newLinks;
lastIndex = prev;
if(prev != -1) newLinks[prev] |= 0xFFFFFFFFL;
}
@Override
public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { throw new UnsupportedOperationException(); }
#if VALUE_PRIMITIVES
@Override
public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { throw new UnsupportedOperationException(); }
#endif
@Override
public VALUE_TYPE putAndMoveToFirst(KEY_TYPE key, VALUE_TYPE value) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE putAndMoveToLast(KEY_TYPE key, VALUE_TYPE value) { throw new UnsupportedOperationException(); }
@Override
public boolean moveToFirst(KEY_TYPE key) { throw new UnsupportedOperationException(); }
@Override
public boolean moveToLast(KEY_TYPE key) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE getAndMoveToFirst(KEY_TYPE key) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE getAndMoveToLast(KEY_TYPE key) { throw new UnsupportedOperationException(); }
#if !TYPE_OBJECT
@Override
public boolean containsKey(KEY_TYPE key) {
return findIndex(key) >= 0;
}
#endif
@Override
@Primitive
public boolean containsKey(Object key) {
return findIndex(key) >= 0;
}
#if !VALUE_OBJECT
@Override
public boolean containsValue(VALUE_TYPE value) {
if(VALUE_EQUALS(value, values[nullIndex])) return true;
for(int i = nullIndex-1;i >= 0;i--)
if(KEY_EQUALS_NOT_NULL(keys[i]) && VALUE_EQUALS(values[i], value)) return true;
return false;
}
#endif
@Override
@ValuePrimitive
public boolean containsValue(Object value) {
if((value == null && VALUE_EQUALS(values[nullIndex], getDefaultReturnValue())) || EQUALS_VALUE_TYPE(values[nullIndex], value)) return true;
for(int i = nullIndex-1;i >= 0;i--)
if(KEY_EQUALS_NOT_NULL(keys[i]) && ((value == null && values[i] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[i], value))) return true;
return false;
}
@Override
public VALUE_TYPE REMOVE_VALUE(KEY_TYPE key) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE REMOVE_VALUEOrDefault(KEY_TYPE key, VALUE_TYPE defaultValue) { throw new UnsupportedOperationException(); }
@Override
@Deprecated
public CLASS_VALUE_TYPE remove(Object key) { throw new UnsupportedOperationException(); }
#if !TYPE_OBJECT || !VALUE_OBJECT
@Override
public boolean remove(KEY_TYPE key, VALUE_TYPE value) { throw new UnsupportedOperationException(); }
#endif
@Override
public boolean remove(Object key, Object value) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE GET_VALUE(KEY_TYPE key) {
int slot = findIndex(key);
return slot < 0 ? getDefaultReturnValue() : values[slot];
}
@Override
public CLASS_VALUE_TYPE get(Object key) {
int slot = findIndex(key);
return VALUE_TO_OBJ(slot < 0 ? getDefaultReturnValue() : values[slot]);
}
#if TYPE_OBJECT && VALUE_OBJECT
@Override
public VALUE_TYPE getOrDefault(Object key, VALUE_TYPE defaultValue) {
int slot = findIndex(key);
return slot < 0 ? defaultValue : values[slot];
}
#else
@Override
public VALUE_TYPE getOrDefault(KEY_TYPE key, VALUE_TYPE defaultValue) {
int slot = findIndex(key);
return slot < 0 ? defaultValue : values[slot];
}
#endif
@Override
public KEY_TYPE FIRST_ENTRY_KEY() {
if(size == 0) throw new NoSuchElementException();
return keys[firstIndex];
}
@Override
public KEY_TYPE POLL_FIRST_ENTRY_KEY() { throw new UnsupportedOperationException(); }
@Override
public KEY_TYPE LAST_ENTRY_KEY() {
if(size == 0) throw new NoSuchElementException();
return keys[lastIndex];
}
@Override
public KEY_TYPE POLL_LAST_ENTRY_KEY() { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE FIRST_ENTRY_VALUE() {
if(size == 0) throw new NoSuchElementException();
return values[firstIndex];
}
@Override
public VALUE_TYPE LAST_ENTRY_VALUE() {
if(size == 0) throw new NoSuchElementException();
return values[lastIndex];
}
@Override
public ObjectSet<MAP.Entry KEY_VALUE_GENERIC_TYPE> ENTRY_SET() {
if(entrySet == null) entrySet = new MapEntrySet();
return entrySet;
}
@Override
public SET KEY_GENERIC_TYPE keySet() {
if(keySet == null) keySet = new KeySet();
return keySet;
}
@Override
public VALUE_COLLECTION VALUE_GENERIC_TYPE values() {
if(valuesC == null) valuesC = new Values();
return valuesC;
}
@Override
public COMPARATOR KEY_GENERIC_TYPE comparator() { return null; }
@Override
public SORTED_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, KEY_TYPE toKey) { throw new UnsupportedOperationException(); }
@Override
public SORTED_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey) { throw new UnsupportedOperationException(); }
@Override
public SORTED_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey) { throw new UnsupportedOperationException(); }
@Override
public void forEach(BI_CONSUMER KEY_VALUE_GENERIC_TYPE action) {
int index = firstIndex;
while(index != -1){
action.accept(keys[index], values[index]);
index = (int)links[index];
}
}
@Override
public boolean replace(KEY_TYPE key, VALUE_TYPE oldValue, VALUE_TYPE newValue) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE replace(KEY_TYPE key, VALUE_TYPE value) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE COMPUTE(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE COMPUTE_IF_ABSENT(KEY_TYPE key, FUNCTION KEY_VALUE_GENERIC_TYPE mappingFunction) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE COMPUTE_IF_PRESENT(KEY_TYPE key, UNARY_OPERATOR KEY_VALUE_GENERIC_TYPE mappingFunction) { throw new UnsupportedOperationException(); }
@Override
public VALUE_TYPE MERGE(KEY_TYPE key, VALUE_TYPE value, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) { throw new UnsupportedOperationException(); }
@Override
public void BULK_MERGE(MAP KEY_VALUE_GENERIC_TYPE m, VALUE_UNARY_OPERATOR VALUE_VALUE_GENERIC_TYPE mappingFunction) { throw new UnsupportedOperationException(); }
@Override
public int size() { return size; }
@Override
public void clear() { throw new UnsupportedOperationException(); }
#if !TYPE_OBJECT
protected int findIndex(KEY_TYPE key) {
if(KEY_EQUALS_NULL(key)) return containsNull ? nullIndex : -(nullIndex + 1);
int pos = HashUtil.mix(KEY_TO_HASH(key)) & mask;
KEY_TYPE current = keys[pos];
if(KEY_EQUALS_NOT_NULL(current)) {
if(KEY_EQUALS(current, key)) return pos;
while(KEY_EQUALS_NOT_NULL((current = keys[pos = (++pos & mask)])))
if(KEY_EQUALS(current, key)) return pos;
}
return -(pos + 1);
}
#endif
protected int findIndex(Object key) {
if(key == null) return containsNull ? nullIndex : -(nullIndex + 1);
int pos = HashUtil.mix(key.hashCode()) & mask;
KEY_TYPE current = keys[pos];
if(KEY_EQUALS_NOT_NULL(current)) {
if(EQUALS_KEY_TYPE(current, key)) return pos;
while(KEY_EQUALS_NOT_NULL((current = keys[pos = (++pos & mask)])))
if(EQUALS_KEY_TYPE(current, key)) return pos;
}
return -(pos + 1);
}
protected class MapEntry implements MAP.Entry KEY_VALUE_GENERIC_TYPE, Map.Entry<CLASS_TYPE, CLASS_VALUE_TYPE> {
public int index = -1;
public MapEntry() {}
public MapEntry(int index) {
this.index = index;
}
@Override
public KEY_TYPE ENTRY_KEY() {
return keys[index];
}
@Override
public VALUE_TYPE ENTRY_VALUE() {
return values[index];
}
@Override
public VALUE_TYPE setValue(VALUE_TYPE value) { throw new UnsupportedOperationException(); }
@Override
public boolean equals(Object obj) {
if(obj instanceof Map.Entry) {
if(obj instanceof MAP.Entry) {
MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)obj;
return KEY_EQUALS(keys[index], entry.ENTRY_KEY()) && VALUE_EQUALS(values[index], entry.ENTRY_VALUE());
}
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)obj;
Object key = entry.getKey();
Object value = entry.getValue();
#if TYPE_OBJECT && VALUE_OBJECT
return KEY_EQUALS(keys[index], key) && VALUE_EQUALS(values[index], value);
#else if TYPE_OBJECT
return value instanceof CLASS_VALUE_TYPE && KEY_EQUALS(keys[index], key) && VALUE_EQUALS(values[index], CLASS_TO_VALUE(value));
#else if VALUE_OBJECT
return key instanceof CLASS_TYPE && KEY_EQUALS(keys[index], CLASS_TO_KEY(key)) && VALUE_EQUALS(values[index], value);
#else
return key instanceof CLASS_TYPE && value instanceof CLASS_VALUE_TYPE && KEY_EQUALS(keys[index], CLASS_TO_KEY(key)) && VALUE_EQUALS(values[index], CLASS_TO_VALUE(value));
#endif
}
return false;
}
@Override
public int hashCode() {
return KEY_TO_HASH(keys[index]) ^ VALUE_TO_HASH(values[index]);
}
@Override
public String toString() {
return KEY_TO_STRING(keys[index]) + "->" + VALUE_TO_STRING(values[index]);
}
}
private class MapEntrySet extends AbstractObjectSet<MAP.Entry KEY_VALUE_GENERIC_TYPE> implements SORTED_MAP.FastSortedSet KEY_VALUE_GENERIC_TYPE {
@Override
public boolean addAndMoveToFirst(MAP.Entry KEY_VALUE_GENERIC_TYPE o) { throw new UnsupportedOperationException(); }
@Override
public boolean addAndMoveToLast(MAP.Entry KEY_VALUE_GENERIC_TYPE o) { throw new UnsupportedOperationException(); }
@Override
public boolean moveToFirst(MAP.Entry KEY_VALUE_GENERIC_TYPE o) { throw new UnsupportedOperationException(); }
@Override
public boolean moveToLast(MAP.Entry KEY_VALUE_GENERIC_TYPE o) { throw new UnsupportedOperationException(); }
@Override
public MAP.Entry KEY_VALUE_GENERIC_TYPE first() {
return new BasicEntryKV_BRACES(FIRST_ENTRY_KEY(), FIRST_ENTRY_VALUE());
}
@Override
public MAP.Entry KEY_VALUE_GENERIC_TYPE last() {
return new BasicEntryKV_BRACES(LAST_ENTRY_KEY(), LAST_ENTRY_VALUE());
}
@Override
public MAP.Entry KEY_VALUE_GENERIC_TYPE pollFirst() { throw new UnsupportedOperationException(); }
@Override
public MAP.Entry KEY_VALUE_GENERIC_TYPE pollLast() { throw new UnsupportedOperationException(); }
@Override
public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC_TYPE> iterator() {
return new EntryIterator();
}
@Override
public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC_TYPE> iterator(MAP.Entry KEY_VALUE_GENERIC_TYPE fromElement) {
return new EntryIterator(fromElement.ENTRY_KEY());
}
@Override
public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC_TYPE> fastIterator() {
return new FastEntryIterator();
}
@Override
public ObjectBidirectionalIterator<MAP.Entry KEY_VALUE_GENERIC_TYPE> fastIterator(KEY_TYPE fromElement) {
return new FastEntryIterator(fromElement);
}
@Override
public void forEach(Consumer<? super MAP.Entry KEY_VALUE_GENERIC_TYPE> action) {
int index = firstIndex;
while(index != -1){
action.accept(new BasicEntryKV_BRACES(keys[index], values[index]));
index = (int)links[index];
}
}
@Override
public void fastForEach(Consumer<? super MAP.Entry KEY_VALUE_GENERIC_TYPE> action) {
BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES();
int index = firstIndex;
while(index != -1){
entry.set(keys[index], values[index]);
action.accept(entry);
index = (int)links[index];
}
}
@Override
@Deprecated
public boolean contains(Object o) {
if(o instanceof Map.Entry) {
if(o instanceof MAP.Entry) return IMMUTABLE_HASH_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY());
return IMMUTABLE_HASH_MAP.this.containsKey(((Map.Entry<?, ?>)o).getKey());
}
return false;
}
@Override
@Deprecated
public boolean remove(Object o) { throw new UnsupportedOperationException(); }
@Override
public int size() {
return IMMUTABLE_HASH_MAP.this.size();
}
@Override
public void clear() { throw new UnsupportedOperationException(); }
@Override
public Comparator<MAP.Entry KEY_VALUE_GENERIC_TYPE> comparator() {
return null;
}
@Override
public ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC_TYPE> subSet(MAP.Entry KEY_VALUE_GENERIC_TYPE fromElement, MAP.Entry KEY_VALUE_GENERIC_TYPE toElement) { throw new UnsupportedOperationException(); }
@Override
public ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC_TYPE> headSet(MAP.Entry KEY_VALUE_GENERIC_TYPE toElement) { throw new UnsupportedOperationException(); }
@Override
public ObjectSortedSet<MAP.Entry KEY_VALUE_GENERIC_TYPE> tailSet(MAP.Entry KEY_VALUE_GENERIC_TYPE fromElement) { throw new UnsupportedOperationException(); }
}
private final class KeySet extends ABSTRACT_SET KEY_GENERIC_TYPE implements SORTED_SET KEY_GENERIC_TYPE {
#if TYPE_OBJECT
@Override
@Deprecated
public boolean contains(Object e) {
return containsKey(e);
}
@Override
public boolean remove(Object o) { throw new UnsupportedOperationException(); }
#else
@Override
public boolean contains(KEY_TYPE e) {
return containsKey(e);
}
@Override
public boolean remove(KEY_TYPE o) { throw new UnsupportedOperationException(); }
#endif
@Override
public boolean add(KEY_TYPE o) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAndMoveToFirst(KEY_TYPE o) { throw new UnsupportedOperationException(); }
@Override
public boolean addAndMoveToLast(KEY_TYPE o) { throw new UnsupportedOperationException(); }
@Override
public boolean moveToFirst(KEY_TYPE o) { throw new UnsupportedOperationException(); }
@Override
public boolean moveToLast(KEY_TYPE o) { throw new UnsupportedOperationException(); }
@Override
public LIST_ITERATOR KEY_GENERIC_TYPE iterator() {
return new KeyIterator();
}
@Override
public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) {
return new KeyIterator(fromElement);
}
@Override
public int size() {
return IMMUTABLE_HASH_MAP.this.size();
}
@Override
public void clear() { throw new UnsupportedOperationException(); }
@Override
public KEY_TYPE FIRST_KEY() {
return FIRST_ENTRY_KEY();
}
@Override
public KEY_TYPE POLL_FIRST_KEY() { throw new UnsupportedOperationException(); }
@Override
public KEY_TYPE LAST_KEY() {
return LAST_ENTRY_KEY();
}
@Override
public KEY_TYPE POLL_LAST_KEY() { throw new UnsupportedOperationException(); }
#if TYPE_OBJECT
@Override
public void forEach(Consumer KEY_SUPER_GENERIC_TYPE action) {
int index = firstIndex;
while(index != -1){
action.accept(keys[index]);
index = (int)links[index];
}
}
#else
@Override
public void forEach(CONSUMER KEY_SUPER_GENERIC_TYPE action) {
int index = firstIndex;
while(index != -1){
action.accept(keys[index]);
index = (int)links[index];
}
}
#endif
@Override
public COMPARATOR KEY_GENERIC_TYPE comparator() { return null; }
@Override
public SORTED_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, KEY_TYPE toElement) { throw new UnsupportedOperationException(); }
@Override
public SORTED_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement) { throw new UnsupportedOperationException(); }
@Override
public SORTED_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement) { throw new UnsupportedOperationException(); }
}
private class Values extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC_TYPE {
#if VALUE_OBJECT
@Override
@Deprecated
public boolean contains(Object e) {
return containsValue(e);
}
#else
@Override
public boolean contains(VALUE_TYPE e) {
return containsValue(e);
}
#endif
@Override
public boolean add(VALUE_TYPE o) {
throw new UnsupportedOperationException();
}
@Override
public VALUE_ITERATOR VALUE_GENERIC_TYPE iterator() {
return new ValueIterator();
}
@Override
public int size() {
return IMMUTABLE_HASH_MAP.this.size();
}
@Override
public void clear() { throw new UnsupportedOperationException(); }
#if VALUE_OBJECT
@Override
public void forEach(Consumer VALUE_SUPER_GENERIC_TYPE action) {
int index = firstIndex;
while(index != -1){
action.accept(values[index]);
index = (int)links[index];
}
}
#else
@Override
public void forEach(VALUE_CONSUMER VALUE_SUPER_GENERIC_TYPE action) {
int index = firstIndex;
while(index != -1){
action.accept(values[index]);
index = (int)links[index];
}
}
#endif
}
private class FastEntryIterator extends MapIterator implements ObjectListIterator<MAP.Entry KEY_VALUE_GENERIC_TYPE> {
MapEntry entry = new MapEntry();
public FastEntryIterator() {}
public FastEntryIterator(KEY_TYPE from) {
super(from);
}
@Override
public MAP.Entry KEY_VALUE_GENERIC_TYPE next() {
entry.index = nextEntry();
return entry;
}
@Override
public MAP.Entry KEY_VALUE_GENERIC_TYPE previous() {
entry.index = previousEntry();
return entry;
}
@Override
public void set(MAP.Entry KEY_VALUE_GENERIC_TYPE entry) { throw new UnsupportedOperationException(); }
@Override
public void add(MAP.Entry KEY_VALUE_GENERIC_TYPE entry) { throw new UnsupportedOperationException(); }
}
private class EntryIterator extends MapIterator implements ObjectListIterator<MAP.Entry KEY_VALUE_GENERIC_TYPE> {
public EntryIterator() {}
public EntryIterator(KEY_TYPE from) {
super(from);
}
@Override
public MAP.Entry KEY_VALUE_GENERIC_TYPE next() {
return new MapEntry(nextEntry());
}
@Override
public MAP.Entry KEY_VALUE_GENERIC_TYPE previous() {
return new MapEntry(previousEntry());
}
@Override
public void remove() { throw new UnsupportedOperationException(); }
@Override
public void set(MAP.Entry KEY_VALUE_GENERIC_TYPE entry) { throw new UnsupportedOperationException(); }
@Override
public void add(MAP.Entry KEY_VALUE_GENERIC_TYPE entry) { throw new UnsupportedOperationException(); }
}
private class KeyIterator extends MapIterator implements LIST_ITERATOR KEY_GENERIC_TYPE {
public KeyIterator() {}
public KeyIterator(KEY_TYPE from) {
super(from);
}
@Override
public KEY_TYPE PREVIOUS() {
return keys[previousEntry()];
}
@Override
public KEY_TYPE NEXT() {
return keys[nextEntry()];
}
@Override
public void set(KEY_TYPE e) { throw new UnsupportedOperationException(); }
@Override
public void add(KEY_TYPE e) { throw new UnsupportedOperationException(); }
}
private class ValueIterator extends MapIterator implements VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE {
public ValueIterator() {}
@Override
public VALUE_TYPE VALUE_PREVIOUS() {
return values[previousEntry()];
}
@Override
public VALUE_TYPE VALUE_NEXT() {
return values[nextEntry()];
}
@Override
public void set(VALUE_TYPE e) { throw new UnsupportedOperationException(); }
@Override
public void add(VALUE_TYPE e) { throw new UnsupportedOperationException(); }
}
private class MapIterator {
int previous = -1;
int next = -1;
int current = -1;
int index = 0;
MapIterator() {
next = firstIndex;
}
MapIterator(KEY_TYPE from) {
if(KEY_EQUALS_NULL(from)) {
if(containsNull) {
next = (int) links[nullIndex];
previous = nullIndex;
}
else throw new NoSuchElementException("The null element is not in the set");
}
else if(keys[lastIndex] == from) {
previous = lastIndex;
index = size;
}
else {
int pos = HashUtil.mix(KEY_TO_HASH(from)) & mask;
while(KEY_EQUALS_NOT_NULL(keys[pos])) {
if(KEY_EQUALS(keys[pos], from)) {
next = (int)links[pos];
previous = pos;
break;
}
pos = ++pos & mask;
}
if(previous == -1 && next == -1)
throw new NoSuchElementException("The element was not found");
}
}
public boolean hasNext() {
return next != -1;
}
public boolean hasPrevious() {
return previous != -1;
}
public int nextIndex() {
ensureIndexKnown();
return index;
}
public int previousIndex() {
ensureIndexKnown();
return index - 1;
}
public void remove() { throw new UnsupportedOperationException(); }
public int previousEntry() {
if(!hasPrevious()) throw new NoSuchElementException();
current = previous;
previous = (int)(links[current] >> 32);
next = current;
if(index >= 0) index--;
return current;
}
public int nextEntry() {
if(!hasNext()) throw new NoSuchElementException();
current = next;
next = (int)(links[current]);
previous = current;
if(index >= 0) index++;
return current;
}
private void ensureIndexKnown() {
if(index == -1) {
if(previous == -1) {
index = 0;
}
else if(next == -1) {
index = size;
}
else {
index = 1;
for(int pos = firstIndex;pos != previous;pos = (int)links[pos], index++);
}
}
}
}
}