From 9d17dc17fdb6a018ce96427d8e039af33ec244ac Mon Sep 17 00:00:00 2001 From: Speiger Date: Fri, 25 Jun 2021 17:44:48 +0200 Subject: [PATCH] Added ImmutableOpenHashMap that is not editable (is linked by default for fast iteration) --- Changelog.md | 1 + .../speiger/src/builder/GlobalVariables.java | 1 + .../builder/PrimitiveCollectionsBuilder.java | 5 +- .../maps/impl/hash/LinkedOpenHashMap.template | 2 +- .../immutable/ImmutableOpenHashMap.template | 976 ++++++++++++++++++ 5 files changed, 982 insertions(+), 3 deletions(-) create mode 100644 src/builder/resources/speiger/assets/collections/templates/maps/impl/immutable/ImmutableOpenHashMap.template diff --git a/Changelog.md b/Changelog.md index 56d9fd6f..319d665f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -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. diff --git a/src/builder/java/speiger/src/builder/GlobalVariables.java b/src/builder/java/speiger/src/builder/GlobalVariables.java index 4293e25e..4624bfe4 100644 --- a/src/builder/java/speiger/src/builder/GlobalVariables.java +++ b/src/builder/java/speiger/src/builder/GlobalVariables.java @@ -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"); diff --git a/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java b/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java index ce60acef..2ebc2276 100644 --- a/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java +++ b/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java @@ -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) diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template index baa92f37..43eee81b 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template @@ -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 */ diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/immutable/ImmutableOpenHashMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/immutable/ImmutableOpenHashMap.template new file mode 100644 index 00000000..eb3c9738 --- /dev/null +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/immutable/ImmutableOpenHashMap.template @@ -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 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 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 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= 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 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 { + 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 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 iterator() { + return new EntryIterator(); + } + + @Override + public ObjectBidirectionalIterator iterator(MAP.Entry KEY_VALUE_GENERIC_TYPE fromElement) { + return new EntryIterator(fromElement.ENTRY_KEY()); + } + + @Override + public ObjectBidirectionalIterator fastIterator() { + return new FastEntryIterator(); + } + + @Override + public ObjectBidirectionalIterator fastIterator(KEY_TYPE fromElement) { + return new FastEntryIterator(fromElement); + } + + @Override + public void forEach(Consumer 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 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 comparator() { + return null; + } + @Override + public ObjectSortedSet subSet(MAP.Entry KEY_VALUE_GENERIC_TYPE fromElement, MAP.Entry KEY_VALUE_GENERIC_TYPE toElement) { throw new UnsupportedOperationException(); } + @Override + public ObjectSortedSet headSet(MAP.Entry KEY_VALUE_GENERIC_TYPE toElement) { throw new UnsupportedOperationException(); } + @Override + public ObjectSortedSet 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 { + 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 { + + 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++); + } + } + } + } +} \ No newline at end of file