diff --git a/src/builder/java/speiger/src/builder/GlobalVariables.java b/src/builder/java/speiger/src/builder/GlobalVariables.java index 02565533..fa126bcd 100644 --- a/src/builder/java/speiger/src/builder/GlobalVariables.java +++ b/src/builder/java/speiger/src/builder/GlobalVariables.java @@ -142,6 +142,7 @@ public class GlobalVariables addBiClassMapper("CUSTOM_HASH_MAP", "OpenCustomHashMap", "2"); addBiClassMapper("AVL_TREE_MAP", "AVLTreeMap", "2"); addBiClassMapper("RB_TREE_MAP", "RBTreeMap", "2"); + addFunctionValueMappers("LINKED_ENUM_MAP", valueType.isObject() ? "LinkedEnum2ObjectMap" : "LinkedEnum2%sMap"); addFunctionValueMappers("ENUM_MAP", valueType.isObject() ? "Enum2ObjectMap" : "Enum2%sMap"); addBiClassMapper("HASH_MAP", "OpenHashMap", "2"); addBiClassMapper("ARRAY_MAP", "ArrayMap", "2"); diff --git a/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java b/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java index 5847ef4f..ba15f334 100644 --- a/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java +++ b/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java @@ -67,6 +67,7 @@ public class PrimitiveCollectionsBuilder extends TemplateProcessor } } enumRequired.add("EnumMap"); + enumRequired.add("LinkedEnumMap"); biRequired.put("BiConsumer", ""); biRequired.put("UnaryOperator", ""); addBiClass("Function", "Maps", "Map", "SortedMap", "NavigableMap", "AbstractMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap"); @@ -77,6 +78,7 @@ public class PrimitiveCollectionsBuilder extends TemplateProcessor nameRemapper.put("AbstractSet", "Abstract%sSet"); nameRemapper.put("AbstractList", "Abstract%sList"); nameRemapper.put("EnumMap", "Enum2%sMap"); + nameRemapper.put("LinkedEnumMap", "LinkedEnum2%sMap"); addBlockage(ClassType.OBJECT, "Consumer", "Comparator", "Stack"); addBlockage(ClassType.BOOLEAN, "ArraySet", "AVLTreeSet", "RBTreeSet", "SortedSet", "NavigableSet", "OpenHashSet", "OpenCustomHashSet", "LinkedOpenHashSet", "LinkedOpenCustomHashSet"); addBlockage(ClassType.BOOLEAN, "SortedMap", "NavigableMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap"); diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template index f127b6a9..6d402240 100644 --- a/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template @@ -212,7 +212,6 @@ public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE } protected boolean isSet(int index) { return (present[index >> 6] & (1L << index)) != 0; } private static > K[] getKeyUniverse(Class keyType) { -// return keyType.getEnumConstants(); return SharedSecrets.getJavaLangAccess().getEnumConstantsShared(keyType); } diff --git a/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/LinkedEnumMap.template b/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/LinkedEnumMap.template new file mode 100644 index 00000000..9f08bf03 --- /dev/null +++ b/src/builder/resources/speiger/assets/collections/templates/maps/impl/misc/LinkedEnumMap.template @@ -0,0 +1,845 @@ +package speiger.src.collections.PACKAGE.maps.impl.misc; + +import java.util.Comparator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.function.Consumer; +#if TYPE_OBJECT +import java.util.Objects; +#endif + +import speiger.src.collections.PACKAGE.collections.BI_ITERATOR; +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.functions.COMPARATOR; +import speiger.src.collections.PACKAGE.functions.CONSUMER; +#endif +import speiger.src.collections.PACKAGE.functions.consumer.BI_CONSUMER; +import speiger.src.collections.PACKAGE.lists.LIST_ITERATOR; +import speiger.src.collections.PACKAGE.maps.interfaces.MAP; +import speiger.src.collections.PACKAGE.maps.interfaces.SORTED_MAP; +import speiger.src.collections.PACKAGE.sets.ABSTRACT_SET; +import speiger.src.collections.PACKAGE.sets.SORTED_SET; +import speiger.src.collections.PACKAGE.sets.SET; +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 !VALUE_OBJECT && !SAME_TYPE +import speiger.src.collections.VALUE_PACKAGE.functions.VALUE_CONSUMER; +import speiger.src.collections.VALUE_PACKAGE.lists.VALUE_LIST_ITERATOR; +#endif +#if !TYPE_OBJECT +import speiger.src.collections.objects.collections.ObjectBidirectionalIterator; +import speiger.src.collections.objects.lists.ObjectListIterator; +import speiger.src.collections.objects.sets.AbstractObjectSet; +import speiger.src.collections.objects.sets.ObjectSortedSet; +import speiger.src.collections.objects.sets.ObjectSet; +#endif + +/** + * A Type Specific LinkedEnumMap implementation that allows for Primitive Values and faster iteration. + * Unlike javas implementation this one does not jump around between a single long or long array implementation based around the enum size + * This will cause a bit more memory usage but allows for a simpler implementation. + * @Type(T) + * @ValueType(V) + */ +public class LINKED_ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ENUM_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; + /** The First Index in the Map */ + protected int firstIndex = -1; + /** The Last Index in the Map */ + protected int lastIndex = -1; + /** + * Default Constructor + * @param keyType the type of Enum that should be used + */ + public LINKED_ENUM_MAP(Class keyType) { + super(keyType); + links = new long[keys.length]; + } + + @Override + public VALUE_TYPE putAndMoveToFirst(T key, VALUE_TYPE value) { + int index = key.ordinal(); + if(isSet(index)) { + VALUE_TYPE result = values[index]; + values[index] = value; + moveToFirstIndex(index); + return result; + } + set(index); + values[index] = value; + onNodeAdded(index); + moveToFirstIndex(index); + return getDefaultReturnValue(); + } + + @Override + public VALUE_TYPE putAndMoveToLast(T key, VALUE_TYPE value) { + int index = key.ordinal(); + if(isSet(index)) { + VALUE_TYPE result = values[index]; + values[index] = value; + moveToLastIndex(index); + return result; + } + set(index); + values[index] = value; + onNodeAdded(index); + moveToLastIndex(index); + return getDefaultReturnValue(); + } + + @Override + public boolean moveToFirst(T key) { + int index = key.ordinal(); + if(isSet(index)) { + moveToFirstIndex(index); + return true; + } + return false; + } + + @Override + public boolean moveToLast(T key) { + int index = key.ordinal(); + if(isSet(index)) { + moveToLastIndex(index); + return true; + } + return false; + } + + @Override + public VALUE_TYPE getAndMoveToFirst(T key) { + int index = key.ordinal(); + if(index < 0) return getDefaultReturnValue(); + moveToFirstIndex(index); + return values[index]; + } + + @Override + public VALUE_TYPE getAndMoveToLast(T key) { + int index = key.ordinal(); + if(index < 0) return getDefaultReturnValue(); + moveToLastIndex(index); + return values[index]; + } + + @Override + public COMPARATOR KEY_GENERIC_TYPE comparator() { + return null; + } + + @Override + public SORTED_MAP KEY_VALUE_GENERIC_TYPE subMap(T fromKey, T toKey) { throw new UnsupportedOperationException(); } + + @Override + public SORTED_MAP KEY_VALUE_GENERIC_TYPE headMap(T toKey) { throw new UnsupportedOperationException(); } + + @Override + public SORTED_MAP KEY_VALUE_GENERIC_TYPE tailMap(T fromKey) { throw new UnsupportedOperationException(); } + + @Override + public T FIRST_ENTRY_KEY() { + if(size == 0) throw new NoSuchElementException(); + return keys[firstIndex]; + } + + @Override + public T POLL_FIRST_ENTRY_KEY() { + if(size == 0) throw new NoSuchElementException(); + int pos = firstIndex; + firstIndex = (int)links[pos]; + if(0 <= firstIndex) links[firstIndex] |= 0xFFFFFFFF00000000L; + T result = keys[pos]; + size--; + values[result.ordinal()] = EMPTY_VALUE; + return result; + } + + @Override + public T LAST_ENTRY_KEY() { + if(size == 0) throw new NoSuchElementException(); + return keys[lastIndex]; + } + + @Override + public T POLL_LAST_ENTRY_KEY() { + if(size == 0) throw new NoSuchElementException(); + int pos = lastIndex; + lastIndex = (int)(links[pos] >>> 32); + if(0 <= lastIndex) links[lastIndex] |= 0xFFFFFFFFL; + T result = keys[pos]; + size--; + values[result.ordinal()] = EMPTY_VALUE; + return result; + } + + @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 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 void clear() { + super.clear(); + firstIndex = lastIndex = -1; + } + + protected void moveToFirstIndex(int startPos) { + if(size == 1 || firstIndex == startPos) return; + if(lastIndex == startPos) { + lastIndex = (int)(links[startPos] >>> 32); + links[lastIndex] |= 0xFFFFFFFFL; + } + else { + long link = links[startPos]; + int prev = (int)(link >>> 32); + int next = (int)link; + links[prev] ^= ((links[prev] ^ (link & 0xFFFFFFFFL)) & 0xFFFFFFFFL); + links[next] ^= ((links[next] ^ (link & 0xFFFFFFFF00000000L)) & 0xFFFFFFFF00000000L); + } + links[firstIndex] ^= ((links[firstIndex] ^ ((startPos & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L); + links[startPos] = 0xFFFFFFFF00000000L | (firstIndex & 0xFFFFFFFFL); + firstIndex = startPos; + } + + protected void moveToLastIndex(int startPos) { + if(size == 1 || lastIndex == startPos) return; + if(firstIndex == startPos) { + firstIndex = (int)links[startPos]; + links[lastIndex] |= 0xFFFFFFFF00000000L; + } + else { + long link = links[startPos]; + int prev = (int)(link >>> 32); + int next = (int)link; + links[prev] ^= ((links[prev] ^ (link & 0xFFFFFFFFL)) & 0xFFFFFFFFL); + links[next] ^= ((links[next] ^ (link & 0xFFFFFFFF00000000L)) & 0xFFFFFFFF00000000L); + } + links[lastIndex] ^= ((links[lastIndex] ^ (startPos & 0xFFFFFFFFL)) & 0xFFFFFFFFL); + links[startPos] = ((lastIndex & 0xFFFFFFFFL) << 32) | 0xFFFFFFFFL; + lastIndex = startPos; + } + + @Override + protected void onNodeAdded(int pos) { + if(size == 0) { + firstIndex = lastIndex = pos; + links[pos] = -1L; + } + else { + links[lastIndex] ^= ((links[lastIndex] ^ (pos & 0xFFFFFFFFL)) & 0xFFFFFFFFL); + links[pos] = ((lastIndex & 0xFFFFFFFFL) << 32) | 0xFFFFFFFFL; + lastIndex = pos; + } + } + + @Override + protected void onNodeRemoved(int pos) { + if(size == 0) firstIndex = lastIndex = -1; + else if(firstIndex == pos) { + firstIndex = (int)links[pos]; + if(0 <= firstIndex) links[firstIndex] |= 0xFFFFFFFF00000000L; + } + else if(lastIndex == pos) { + lastIndex = (int)(links[pos] >>> 32); + if(0 <= lastIndex) links[pos] |= 0xFFFFFFFFL; + } + else { + long link = links[pos]; + int prev = (int)(link >>> 32); + int next = (int)link; + links[prev] ^= ((links[prev] ^ (link & 0xFFFFFFFFL)) & 0xFFFFFFFFL); + links[next] ^= ((links[next] ^ (link & 0xFFFFFFFF00000000L)) & 0xFFFFFFFF00000000L); + } + } + + 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) { + return LINKED_ENUM_MAP.this.moveToFirst(o.ENTRY_KEY()); + } + + @Override + public boolean moveToLast(MAP.Entry KEY_VALUE_GENERIC_TYPE o) { + return LINKED_ENUM_MAP.this.moveToLast(o.ENTRY_KEY()); + } + + @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() { + BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES(FIRST_ENTRY_KEY(), FIRST_ENTRY_VALUE()); + POLL_FIRST_ENTRY_KEY(); + return entry; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollLast() { + BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES(LAST_ENTRY_KEY(), LAST_ENTRY_VALUE()); + POLL_LAST_ENTRY_KEY(); + return entry; + } + + @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(T 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 LINKED_ENUM_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); + return LINKED_ENUM_MAP.this.containsKey(((Map.Entry)o).getKey()); + } + return false; + } + + @Override + @Deprecated + public boolean remove(Object o) { + if(o instanceof Map.Entry) { + if(o instanceof MAP.Entry) { + MAP.Entry KEY_VALUE_GENERIC_TYPE entry = (MAP.Entry KEY_VALUE_GENERIC_TYPE)o; + return LINKED_ENUM_MAP.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (Map.Entry)o; + return LINKED_ENUM_MAP.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + + @Override + public int size() { + return LINKED_ENUM_MAP.this.size(); + } + + @Override + public void clear() { + LINKED_ENUM_MAP.this.clear(); + } + + @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) { + int oldSize = size; + remove(o); + return size != oldSize; + } + +#else + @Override + public boolean contains(T e) { + return containsKey(e); + } + + @Override + public boolean remove(T o) { + int oldSize = size; + remove(o); + return size != oldSize; + } + +#endif + @Override + public boolean add(T o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAndMoveToFirst(T o) { throw new UnsupportedOperationException(); } + + @Override + public boolean addAndMoveToLast(T o) { throw new UnsupportedOperationException(); } + + @Override + public boolean moveToFirst(T o) { + return LINKED_ENUM_MAP.this.moveToFirst(o); + } + + @Override + public boolean moveToLast(T o) { + return LINKED_ENUM_MAP.this.moveToLast(o); + } + + @Override + public LIST_ITERATOR KEY_GENERIC_TYPE iterator() { + return new KeyIterator(); + } + + @Override + public BI_ITERATOR KEY_GENERIC_TYPE iterator(T fromElement) { + return new KeyIterator(fromElement); + } + + @Override + public int size() { + return LINKED_ENUM_MAP.this.size(); + } + + @Override + public void clear() { + LINKED_ENUM_MAP.this.clear(); + } + + @Override + public T FIRST_KEY() { + return FIRST_ENTRY_KEY(); + } + + @Override + public T POLL_FIRST_KEY() { + return POLL_FIRST_ENTRY_KEY(); + } + + @Override + public T LAST_KEY() { + return LAST_ENTRY_KEY(); + } + + @Override + public T POLL_LAST_KEY() { + return POLL_LAST_ENTRY_KEY(); + } + +#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(T fromElement, T toElement) { throw new UnsupportedOperationException(); } + + @Override + public SORTED_SET KEY_GENERIC_TYPE headSet(T toElement) { throw new UnsupportedOperationException(); } + + @Override + public SORTED_SET KEY_GENERIC_TYPE tailSet(T 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 LINKED_ENUM_MAP.this.size(); + } + + @Override + public void clear() { + LINKED_ENUM_MAP.this.clear(); + } + +#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(T 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 { + MapEntry entry; + + public EntryIterator() {} + public EntryIterator(T from) { + super(from); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { + return entry = new MapEntry(nextEntry()); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE previous() { + return entry = new MapEntry(previousEntry()); + } + + @Override + public void remove() { + super.remove(); + entry.index = -1; + } + + @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(T from) { + super(from); + } + + @Override + public T PREVIOUS() { + return keys[previousEntry()]; + } + + @Override + public T NEXT() { + return keys[nextEntry()]; + } + + @Override + public void set(T e) { throw new UnsupportedOperationException(); } + @Override + public void add(T 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(T from) { + previous = from.ordinal() - 1; + index = from.ordinal(); + next = from.ordinal(); + } + + 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() { + if(current == -1) throw new IllegalStateException(); + ensureIndexKnown(); + if(current == previous) { + index--; + previous = (int)(links[current] >>> 32); + } + else next = (int)links[current]; + size--; + if(previous == -1) firstIndex = next; + else links[previous] ^= ((links[previous] ^ (next & 0xFFFFFFFFL)) & 0xFFFFFFFFL); + + if (next == -1) lastIndex = previous; + else links[next] ^= ((links[next] ^ ((previous & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L); + values[current] = EMPTY_VALUE; + } + + 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++); + } + } + } + } + + 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) { + VALUE_TYPE oldValue = values[index]; + values[index] = value; + return oldValue; + } + + @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]); + } + } +} \ No newline at end of file