package speiger.src.collections.PACKAGE.maps.impl.hash; 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 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 { protected long[] links; protected int firstIndex = -1; protected int lastIndex = -1; public LINKED_HASH_MAP() { this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR); } public LINKED_HASH_MAP(int minCapacity) { this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR); } public LINKED_HASH_MAP(int minCapacity, float loadFactor) { super(minCapacity, loadFactor); links = new long[nullIndex + 1]; } #if !TYPE_OBJECT || !VALUE_OBJECT public LINKED_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values) { this(keys, values, HashUtil.DEFAULT_LOAD_FACTOR); } public LINKED_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values, float loadFactor) { this(keys.length, loadFactor); if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size"); for(int i = 0,m=keys.length;i map) { this(map, HashUtil.DEFAULT_LOAD_FACTOR); } public LINKED_HASH_MAP(Map map, float loadFactor) { this(map.size(), loadFactor); putAll(map); } public LINKED_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map) { this(map, HashUtil.DEFAULT_LOAD_FACTOR); } public LINKED_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map, float loadFactor) { this(map.size(), loadFactor); putAll(map); } @Override public VALUE_TYPE putAndMoveToFirst(KEY_TYPE key, VALUE_TYPE value) { if(KEY_EQUALS_NULL(key)) { if(containsNull) { VALUE_TYPE lastValue = values[nullIndex]; values[nullIndex] = value; moveToFirstIndex(nullIndex); return lastValue; } values[nullIndex] = value; containsNull = true; onNodeAdded(nullIndex); moveToFirstIndex(nullIndex); } else { int pos = HashUtil.mix(KEY_TO_HASH(key)) & mask; while(KEY_EQUALS_NOT_NULL(keys[pos])) { if(KEY_EQUALS(keys[pos], key)) { VALUE_TYPE lastValue = values[pos]; values[pos] = value; moveToFirstIndex(pos); return lastValue; } pos = ++pos & mask; } keys[pos] = key; values[pos] = value; onNodeAdded(pos); moveToFirstIndex(pos); } if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); return getDefaultReturnValue(); } @Override public VALUE_TYPE putAndMoveToLast(KEY_TYPE key, VALUE_TYPE value) { if(KEY_EQUALS_NULL(key)) { if(containsNull) { VALUE_TYPE lastValue = values[nullIndex]; values[nullIndex] = value; moveToLastIndex(nullIndex); return lastValue; } values[nullIndex] = value; containsNull = true; onNodeAdded(nullIndex); moveToLastIndex(nullIndex); } else { int pos = HashUtil.mix(KEY_TO_HASH(key)) & mask; while(KEY_EQUALS_NOT_NULL(keys[pos])) { if(KEY_EQUALS(keys[pos], key)) { VALUE_TYPE lastValue = values[pos]; values[pos] = value; moveToLastIndex(pos); return lastValue; } pos = ++pos & mask; } keys[pos] = key; values[pos] = value; onNodeAdded(pos); moveToLastIndex(pos); } if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); return getDefaultReturnValue(); } @Override public boolean moveToFirst(KEY_TYPE key) { if(KEY_EQUALS(FIRST_ENTRY_KEY(), key)) return false; if(KEY_EQUALS_NULL(key)) { if(containsNull) { moveToFirstIndex(nullIndex); return true; } } else { int pos = HashUtil.mix(KEY_TO_HASH(key)) & mask; while(KEY_EQUALS_NOT_NULL(keys[pos])) { if(KEY_EQUALS(keys[pos], key)) { moveToFirstIndex(pos); return true; } pos = ++pos & mask; } } return false; } @Override public boolean moveToLast(KEY_TYPE key) { if(KEY_EQUALS(LAST_ENTRY_KEY(), key)) return false; if(KEY_EQUALS_NULL(key)) { if(containsNull) { moveToLastIndex(nullIndex); return true; } } else { int pos = HashUtil.mix(KEY_TO_HASH(key)) & mask; while(KEY_EQUALS_NOT_NULL(keys[pos])) { if(KEY_EQUALS(keys[pos], key)) { moveToLastIndex(pos); return true; } pos = ++pos & mask; } } return false; } @Override public VALUE_TYPE getAndMoveToFirst(KEY_TYPE key) { int index = findIndex(key); if(index < 0) return getDefaultReturnValue(); moveToFirstIndex(index); return values[index]; } @Override public VALUE_TYPE getAndMoveToLast(KEY_TYPE key) { int index = findIndex(key); 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(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 KEY_TYPE FIRST_ENTRY_KEY() { if(size == 0) throw new NoSuchElementException(); return keys[firstIndex]; } @Override public KEY_TYPE POLL_FIRST_ENTRY_KEY() { if(size == 0) throw new NoSuchElementException(); int pos = firstIndex; firstIndex = (int)links[pos]; if(0 <= firstIndex) links[firstIndex] |= 0xFFFFFFFF00000000L; KEY_TYPE result = keys[pos]; size--; if(KEY_EQUALS_NULL(result)) { containsNull = false; keys[nullIndex] = EMPTY_KEY_VALUE; values[nullIndex] = EMPTY_VALUE; } else shiftKeys(pos); if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); return result; } @Override public KEY_TYPE LAST_ENTRY_KEY() { if(size == 0) throw new NoSuchElementException(); return keys[lastIndex]; } @Override public KEY_TYPE POLL_LAST_ENTRY_KEY() { if(size == 0) throw new NoSuchElementException(); int pos = lastIndex; lastIndex = (int)(links[pos] >>> 32); if(0 <= lastIndex) links[lastIndex] |= 0xFFFFFFFFL; KEY_TYPE result = keys[pos]; size--; if(KEY_EQUALS_NULL(result)) { containsNull = false; keys[nullIndex] = EMPTY_KEY_VALUE; values[nullIndex] = EMPTY_VALUE; } else shiftKeys(pos); if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); 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); } } @Override protected void onNodeMoved(int from, int to) { if(size == 1) { firstIndex = lastIndex = to; links[to] = -1L; } else if(firstIndex == from) { firstIndex = to; links[(int)links[from]] ^= ((links[(int)links[from]] ^ ((to & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L); links[to] = links[from]; } else if(lastIndex == from) { lastIndex = to; links[(int)(links[from] >>> 32)] ^= ((links[(int)(links[from] >>> 32)] ^ (to & 0xFFFFFFFFL)) & 0xFFFFFFFFL); links[to] = links[from]; } else { long link = links[from]; int prev = (int)(link >>> 32); int next = (int)link; links[prev] ^= ((links[prev] ^ (to & 0xFFFFFFFFL)) & 0xFFFFFFFFL); links[next] ^= ((links[next] ^ ((to & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L); links[to] = link; } } @Override protected void rehash(int newSize) { 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 i = firstIndex, prev = -1, newPrev = -1, pos; firstIndex = -1; for(int j = size; j-- != 0;) { if(KEY_EQUALS_NULL(keys[i])) pos = newSize; else { pos = HashUtil.mix(KEY_TO_HASH(keys[i])) & newMask; while(KEY_EQUALS_NOT_NULL(newKeys[pos])) pos = ++pos & newMask; } newKeys[pos] = keys[i]; newValues[pos] = values[i]; if(prev != -1) { newLinks[newPrev] ^= ((newLinks[newPrev] ^ (pos & 0xFFFFFFFFL)) & 0xFFFFFFFFL); newLinks[pos] ^= ((newLinks[pos] ^ ((newPrev & 0xFFFFFFFFL) << 32)) & 0xFFFFFFFF00000000L); newPrev = pos; } else { newPrev = firstIndex = pos; newLinks[pos] = -1L; } i = (int)links[prev = i]; } links = newLinks; lastIndex = newPrev; if(newPrev != -1) newLinks[newPrev] |= 0xFFFFFFFFL; nullIndex = newSize; mask = newMask; maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); keys = newKeys; values = newValues; } 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_HASH_MAP.this.moveToFirst(o.ENTRY_KEY()); } @Override public boolean moveToLast(MAP.Entry KEY_VALUE_GENERIC_TYPE o) { return LINKED_HASH_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(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 LINKED_HASH_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); return LINKED_HASH_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_HASH_MAP.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); } Map.Entry entry = (Map.Entry)o; return LINKED_HASH_MAP.this.remove(entry.getKey(), entry.getValue()); } return false; } @Override public int size() { return LINKED_HASH_MAP.this.size(); } @Override public void clear() { LINKED_HASH_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(KEY_TYPE e) { return containsKey(e); } @Override public boolean remove(KEY_TYPE o) { int oldSize = size; remove(o); return size != oldSize; } #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) { return LINKED_HASH_MAP.this.moveToFirst(o); } @Override public boolean moveToLast(KEY_TYPE o) { return LINKED_HASH_MAP.this.moveToLast(o); } @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 LINKED_HASH_MAP.this.size(); } @Override public void clear() { LINKED_HASH_MAP.this.clear(); } @Override public KEY_TYPE FIRST_KEY() { return FIRST_ENTRY_KEY(); } @Override public KEY_TYPE POLL_FIRST_KEY() { return POLL_FIRST_ENTRY_KEY(); } @Override public KEY_TYPE LAST_KEY() { return LAST_ENTRY_KEY(); } @Override public KEY_TYPE 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(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 LINKED_HASH_MAP.this.size(); } @Override public void clear() { LINKED_HASH_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(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 { MapEntry entry; public EntryIterator() {} public EntryIterator(KEY_TYPE 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(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() { 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); if(current == nullIndex) { current = -1; containsNull = false; keys[nullIndex] = EMPTY_KEY_VALUE; values[nullIndex] = EMPTY_VALUE; } else { int slot, last, startPos = current; current = -1; KEY_TYPE current; while(true) { startPos = ((last = startPos) + 1) & mask; while(true){ if(KEY_EQUALS_NULL((current = keys[startPos]))) { keys[last] = EMPTY_KEY_VALUE; values[last] = EMPTY_VALUE; return; } slot = HashUtil.mix(KEY_TO_HASH(current)) & mask; if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; startPos = ++startPos & mask; } keys[last] = current; values[last] = values[startPos]; if(next == startPos) next = last; if(previous == startPos) previous = last; onNodeMoved(startPos, last); } } } 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++); } } } } }