diff --git a/.classpath b/.classpath index 8b3d57e2..a61782f5 100644 --- a/.classpath +++ b/.classpath @@ -26,7 +26,7 @@ - + diff --git a/build.gradle b/build.gradle index 0214f4e8..1a3c8f76 100644 --- a/build.gradle +++ b/build.gradle @@ -6,15 +6,9 @@ tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } +apply plugin: 'java' apply plugin: 'eclipse' -eclipse { - classpath { - downloadJavadoc = true - downloadSources = true - } -} - repositories { jcenter() flatDir { @@ -22,6 +16,28 @@ repositories { } } +sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' + +eclipse { + classpath { + downloadJavadoc = true + downloadSources = true + file { + whenMerged { + //Enforce a custom container and allowing access to the sun.misc package which is nessesary for EnumMaps + entries.find{ it.kind == 'con' && it.path.startsWith('org.eclipse.jdt')}.path = 'org.eclipse.jdt.launching.JRE_CONTAINER'; + } + } + } +} + +task generateSource(type: JavaExec) { + group = 'internal' + description = 'Builds the sourcecode' + classpath = sourceSets.main.runtimeClasspath + main = 'speiger.src.builder.example.TestBuilder' +} + dependencies { compile 'SimpleCodeGenerator:Simple Code Generator:1.0.1' testImplementation 'junit:junit:4.12' diff --git a/libs/Simple Code Generator-1.0.1-sources.jar b/libs/Simple Code Generator-1.0.1-sources.jar index 9b3630f7..60e0673e 100644 Binary files a/libs/Simple Code Generator-1.0.1-sources.jar and b/libs/Simple Code Generator-1.0.1-sources.jar differ diff --git a/libs/Simple Code Generator-1.0.1.jar b/libs/Simple Code Generator-1.0.1.jar index 952d60da..e6cde347 100644 Binary files a/libs/Simple Code Generator-1.0.1.jar and b/libs/Simple Code Generator-1.0.1.jar differ diff --git a/src/main/java/speiger/src/builder/example/GlobalVariables.java b/src/main/java/speiger/src/builder/example/GlobalVariables.java index 44cb6aa7..78ef5e12 100644 --- a/src/main/java/speiger/src/builder/example/GlobalVariables.java +++ b/src/main/java/speiger/src/builder/example/GlobalVariables.java @@ -48,14 +48,16 @@ public class GlobalVariables addSimpleMapper(" NO_GENERIC_TYPE", type.isObject() ? "" : ""); addSimpleMapper(" KEY_COMPAREABLE_TYPE", type.isObject() ? "<"+type.getKeyType()+" extends Comparable>" : ""); addSimpleMapper(" KEY_SUPER_GENERIC_TYPE", type.isObject() ? "" : ""); - addSimpleMapper(" VALUE_SUPER_GENERIC_TYPE", valueType.isObject() ? "" : ""); + addSimpleMapper(" VALUE_SUPER_GENERIC_TYPE", valueType.isObject() ? "" : ""); addSimpleMapper(" KEY_VALUE_SUPER_GENERIC_TYPE", type.isObject() ? (valueType.isObject() ? "" : "") : (valueType.isObject() ? "" : "")); - - + addSimpleMapper(" KEY_ENUM_VALUE_GENERIC_TYPE", type.isObject() ? (valueType.isObject() ? "<"+type.getKeyType()+" extends Enum<"+type.getKeyType()+">, "+valueType.getValueType()+">" : "<"+type.getKeyType()+" extends Enum<"+type.getKeyType()+">>") : (valueType.isObject() ? "<"+valueType.getValueType()+">" : "")); + addSimpleMapper(" KEY_VALUE_ENUM_GENERIC_TYPE", type.isObject() ? (valueType.isObject() ? "<"+type.getKeyType()+", "+valueType.getValueType()+" extends Enum<"+valueType.getValueType()+">>" : "<"+type.getKeyType()+">") : (valueType.isObject() ? "<"+valueType.getValueType()+" extends Enum<"+valueType.getValueType()+">>" : "")); + addSimpleMapper(" GENERIC_KEY_BRACES", type.isObject() ? " <"+type.getKeyType()+">" : ""); addSimpleMapper(" GENERIC_VALUE_BRACES", type.isObject() ? " <"+valueType.getValueType()+">" : ""); addSimpleMapper(" GENERIC_KEY_VALUE_BRACES", type.isObject() ? (valueType.isObject() ? " <"+type.getKeyType()+", "+valueType.getValueType()+">" : " <"+type.getKeyType()+">") : (valueType.isObject() ? " <"+valueType.getValueType()+">" : "")); addSimpleMapper(" COMPAREABLE_KEY_BRACES", type.isObject() ? " <"+type.getKeyType()+" extends Comparable>" : ""); + addSimpleMapper("KV_BRACES", type.isObject() || valueType.isObject() ? "<>" : ""); addSimpleMapper("BRACES", type.isObject() ? "<>" : ""); if(type.needsCustomJDKType()) { @@ -92,7 +94,7 @@ public class GlobalVariables addInjectMapper(fix+"_TO_OBJ", type.isObject() ? "%s" : type.getClassType(value)+".valueOf(%s)").removeBraces(); addInjectMapper("OBJ_TO_"+fix, type.isObject() ? "%s" : "%s."+type.getKeyType(value)+"Value()").removeBraces(); - addInjectMapper("CLASS_TO_"+fix, "(("+type.getClassType(value)+")%s)."+type.getKeyType(value)+"Value()").removeBraces(); + addInjectMapper("CLASS_TO_"+fix, type.isObject() ? "("+type.getKeyType(value)+")%s" : "(("+type.getClassType(value)+")%s)."+type.getKeyType(value)+"Value()").removeBraces(); addInjectMapper(fix+"_TO_HASH", type.isObject() ? "%s.hashCode()" : type.getClassType(value)+".hashCode(%s)").removeBraces(); addInjectMapper(fix+"_TO_STRING", type.isObject() ? "%s.toString()" : type.getClassType(value)+".toString(%s)").removeBraces(); @@ -126,6 +128,14 @@ public class GlobalVariables addClassMapper("LINKED_HASH_SET", "LinkedOpenHashSet"); addClassMapper("CUSTOM_HASH_SET", "OpenCustomHashSet"); addClassMapper("HASH_SET", "OpenHashSet"); + addBiClassMapper("LINKED_CUSTOM_HASH_MAP", "LinkedOpenCustomHashMap", "2"); + addBiClassMapper("LINKED_HASH_MAP", "LinkedOpenHashMap", "2"); + addBiClassMapper("CUSTOM_HASH_MAP", "OpenCustomHashMap", "2"); + addBiClassMapper("AVL_TREE_MAP", "AVLTreeMap", "2"); + addBiClassMapper("RB_TREE_MAP", "RBTreeMap", "2"); + addFunctionValueMappers("ENUM_MAP", valueType.isObject() ? "Enum2ObjectMap" : "Enum2%sMap"); + addBiClassMapper("HASH_MAP", "OpenHashMap", "2"); + addBiClassMapper("ARRAY_MAP", "ArrayMap", "2"); addClassMapper("RB_TREE_SET", "RBTreeSet"); addClassMapper("AVL_TREE_SET", "AVLTreeSet"); addClassMapper("ARRAY_SET", "ArraySet"); @@ -155,6 +165,8 @@ public class GlobalVariables addBiClassMapper("FUNCTION", "Function", "2"); addClassMapper("LIST_ITER", "ListIter"); addClassMapper("LIST", "List"); + addBiClassMapper("NAVIGABLE_MAP", "NavigableMap", "2"); + addBiClassMapper("SORTED_MAP", "SortedMap", "2"); addBiClassMapper("MAP", "Map", "2"); addClassMapper("NAVIGABLE_SET", "NavigableSet"); addClassMapper("PRIORITY_QUEUE", "PriorityQueue"); @@ -166,6 +178,10 @@ public class GlobalVariables addBiClassMapper("UNARY_OPERATOR", "UnaryOperator", ""); if(type.isObject()) { + if(!valueType.isObject()) + { + addSimpleMapper("VALUE_CONSUMER", valueType.getFileType()+"Consumer"); + } addSimpleMapper("CONSUMER", "Consumer"); addSimpleMapper("COMPARATOR", "Comparator"); addSimpleMapper("IARRAY", "IObjectArray"); @@ -191,13 +207,19 @@ public class GlobalVariables addFunctionMapper("ENQUEUE", "enqueue"); addFunctionMapper("DEQUEUE_LAST", "dequeueLast"); addFunctionMapper("DEQUEUE", "dequeue"); - addFunctionMappers("ENTRY_KEY", "get%sKey"); - addFunctionValueMappers("ENTRY_VALUE", "get%sValue"); + addFunctionMappers("POLL_FIRST_ENTRY_KEY", "pollFirst%sKey"); + addFunctionMappers("POLL_LAST_ENTRY_KEY", "pollLast%sKey"); addFunctionMapper("POLL_FIRST_KEY", "pollFirst"); addFunctionMapper("POLL_LAST_KEY", "pollLast"); + addFunctionMappers("FIRST_ENTRY_KEY", "first%sKey"); + addFunctionValueMappers("FIRST_ENTRY_VALUE", "first%sValue"); addFunctionMapper("FIRST_KEY", "first"); + addFunctionMappers("LAST_ENTRY_KEY", "last%sKey"); + addFunctionValueMappers("LAST_ENTRY_VALUE", "last%sValue"); + addFunctionMappers("ENTRY_KEY", "get%sKey"); + addFunctionValueMappers("ENTRY_VALUE", "get%sValue"); addFunctionMapper("GET_KEY", "get"); - addFunctionValueMapper("GET_VALUE", "get"); + addFunctionValueMapper("GET_VALUE", valueType.isObject() ? "getObject" : "get"); addFunctionMapper("LAST_KEY", "last"); addFunctionValueMapper("MERGE", "merge"); addFunctionMapper("NEXT", "next"); @@ -229,18 +251,9 @@ public class GlobalVariables return this; } - public TemplateProcess create(String fileName) + public TemplateProcess create(String fileName, String splitter, boolean valueOnly) { - TemplateProcess process = new TemplateProcess(String.format(fileName+".java", type.getFileType())); - process.setPathBuilder(new PathBuilder(type.getPathType())); - process.addFlags(flags); - process.addMappers(operators); - return process; - } - - public TemplateProcess createBi(String fileName, String splitter) - { - TemplateProcess process = new TemplateProcess(String.format(fileName+".java", type.getFileType()+splitter+valueType.getFileType())); + TemplateProcess process = new TemplateProcess(String.format(fileName+".java", (splitter != null ? type.getFileType()+splitter+valueType.getFileType() : (valueOnly ? valueType : type).getFileType()))); process.setPathBuilder(new PathBuilder(type.getPathType())); process.addFlags(flags); process.addMappers(operators); diff --git a/src/main/java/speiger/src/builder/example/TestBuilder.java b/src/main/java/speiger/src/builder/example/TestBuilder.java index 173364be..401d0af4 100644 --- a/src/main/java/speiger/src/builder/example/TestBuilder.java +++ b/src/main/java/speiger/src/builder/example/TestBuilder.java @@ -6,8 +6,10 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Consumer; import speiger.src.builder.processor.TemplateProcess; @@ -15,12 +17,14 @@ import speiger.src.builder.processor.TemplateProcessor; public class TestBuilder extends TemplateProcessor { - Map> blocked = new HashMap>(); - Map nameRemapper = new HashMap(); - Map biRequired = new HashMap(); + Map> blocked = new HashMap<>(); + Map nameRemapper = new HashMap<>(); + Map biRequired = new HashMap<>(); + Set enumRequired = new HashSet<>(); public static final ClassType[] TYPE = ClassType.values(); - List variables = new ArrayList(); + List variables = new ArrayList<>(); List biVariables = new ArrayList<>(); + List enumVariables = new ArrayList<>(); public TestBuilder() { @@ -61,21 +65,20 @@ public class TestBuilder extends TemplateProcessor create(clzType, subType); } } -// blocked.put("AbstractMap", EnumSet.allOf(ClassType.class)); + enumRequired.add("EnumMap"); biRequired.put("BiConsumer", ""); - biRequired.put("Function", "2"); biRequired.put("UnaryOperator", ""); - biRequired.put("Map", "2"); - biRequired.put("Maps", "2"); - biRequired.put("AbstractMap", "2"); + addBiClass("Function", "Maps", "Map", "SortedMap", "NavigableMap", "AbstractMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap"); nameRemapper.put("BiConsumer", "%sConsumer"); nameRemapper.put("IArray", "I%sArray"); nameRemapper.put("AbstractMap", "Abstract%sMap"); nameRemapper.put("AbstractCollection", "Abstract%sCollection"); nameRemapper.put("AbstractSet", "Abstract%sSet"); nameRemapper.put("AbstractList", "Abstract%sList"); + nameRemapper.put("EnumMap", "Enum2%sMap"); addBlockage(ClassType.OBJECT, "Consumer", "Comparator", "Stack"); addBlockage(ClassType.BOOLEAN, "Sets", "ArraySet", "AVLTreeSet", "RBTreeSet", "SortedSet", "NavigableSet", "OpenHashSet", "OpenCustomHashSet", "LinkedOpenHashSet", "LinkedOpenCustomHashSet"); + addBlockage(ClassType.BOOLEAN, "SortedMap", "NavigableMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap"); } protected void create(ClassType mainType, ClassType subType) @@ -89,12 +92,24 @@ public class TestBuilder extends TemplateProcessor type.createFunctions(); if(mainType == subType) variables.add(type); biVariables.add(type); + if(mainType.isObject()) enumVariables.add(type); } - protected void addBlockage(ClassType type, String...args) { - for(String s : args) { + protected void addBiClass(String...classNames) + { + for(String s : classNames) + { + biRequired.put(s, "2"); + } + } + + protected void addBlockage(ClassType type, String...args) + { + for(String s : args) + { EnumSet set = blocked.get(s); - if(set == null) { + if(set == null) + { set = EnumSet.noneOf(ClassType.class); blocked.put(s, set); } @@ -105,30 +120,26 @@ public class TestBuilder extends TemplateProcessor @Override public void createProcesses(String name, Consumer acceptor) { - EnumSet types = blocked.get(name); String splitter = biRequired.get(name); - if(splitter != null) + boolean valueRequired = enumRequired.contains(name); + List vars = getVariablesByClass(name, splitter != null); + EnumSet types = blocked.get(name); + for(int i = 0,m=vars.size();i getVariablesByClass(String name, boolean bi) { + if(enumRequired.contains(name)) return enumVariables; + if(bi) return biVariables; + return variables; + } + public static void main(String...args) { try diff --git a/src/main/resources/speiger/assets/collections/templates/maps/abstracts/AbstractMap.template b/src/main/resources/speiger/assets/collections/templates/maps/abstracts/AbstractMap.template index 8e4dff3a..0ccc4f7c 100644 --- a/src/main/resources/speiger/assets/collections/templates/maps/abstracts/AbstractMap.template +++ b/src/main/resources/speiger/assets/collections/templates/maps/abstracts/AbstractMap.template @@ -27,7 +27,7 @@ import speiger.src.collections.objects.sets.ObjectSet; public abstract class ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE extends AbstractMap implements MAP KEY_VALUE_GENERIC_TYPE { - VALUE_TYPE defaultReturnValue = EMPTY_VALUE; + protected VALUE_TYPE defaultReturnValue = EMPTY_VALUE; @Override public VALUE_TYPE getDefaultReturnValue() { @@ -174,6 +174,11 @@ public abstract class ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE extends AbstractMap entry = (Map.Entry)obj; Object key = entry.getKey(); diff --git a/src/main/resources/speiger/assets/collections/templates/maps/impl/customHash/LinkedOpenCustomHashMap.template b/src/main/resources/speiger/assets/collections/templates/maps/impl/customHash/LinkedOpenCustomHashMap.template new file mode 100644 index 00000000..8aa9ebce --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/maps/impl/customHash/LinkedOpenCustomHashMap.template @@ -0,0 +1,999 @@ +package speiger.src.collections.PACKAGE.maps.impl.customHash; + +import java.util.Comparator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.function.Consumer; + +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.PACKAGE.utils.STRATEGY; +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_CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE implements SORTED_MAP KEY_VALUE_GENERIC_TYPE +{ + protected transient long[] links; + protected int firstIndex = -1; + protected int lastIndex = -1; + + public LINKED_CUSTOM_HASH_MAP(STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR, strategy); + } + + public LINKED_CUSTOM_HASH_MAP(int minCapacity, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR, strategy); + } + + public LINKED_CUSTOM_HASH_MAP(int minCapacity, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + super(minCapacity, loadFactor, strategy); + links = new long[nullIndex + 1]; + } + +#if !TYPE_OBJECT || !VALUE_OBJECT + public LINKED_CUSTOM_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(keys, values, HashUtil.DEFAULT_LOAD_FACTOR, strategy); + } + + public LINKED_CUSTOM_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(keys.length, loadFactor, strategy); + if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size"); + for(int i = 0,m=keys.length;i map, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(map, HashUtil.DEFAULT_LOAD_FACTOR, strategy); + } + + public LINKED_CUSTOM_HASH_MAP(Map map, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(map.size(), loadFactor, strategy); + putAll(map); + } + + public LINKED_CUSTOM_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(map, HashUtil.DEFAULT_LOAD_FACTOR, strategy); + } + + public LINKED_CUSTOM_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(map.size(), loadFactor, strategy); + putAll(map); + } + + @Override + public VALUE_TYPE putAndMoveToFirst(KEY_TYPE key, VALUE_TYPE value) { + if(strategy.equals(key, EMPTY_KEY_VALUE)) { + if(containsNull) { + VALUE_TYPE lastValue = values[nullIndex]; + values[nullIndex] = value; + moveToFirstIndex(nullIndex); + return lastValue; + } + values[nullIndex] = value; + containsNull = true; + onNodeAdded(nullIndex); + } + else { + int pos = HashUtil.mix(strategy.hashCode(key)) & mask; + while(!strategy.equals(keys[pos], EMPTY_KEY_VALUE)) { + if(strategy.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); + } + if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); + return getDefaultReturnValue(); + } + + @Override + public VALUE_TYPE putAndMoveToLast(KEY_TYPE key, VALUE_TYPE value) { + if(strategy.equals(key, EMPTY_KEY_VALUE)) { + if(containsNull) { + VALUE_TYPE lastValue = values[nullIndex]; + values[nullIndex] = value; + moveToLastIndex(nullIndex); + return lastValue; + } + values[nullIndex] = value; + containsNull = true; + onNodeAdded(nullIndex); + } + else { + int pos = HashUtil.mix(strategy.hashCode(key)) & mask; + while(!strategy.equals(keys[pos], EMPTY_KEY_VALUE)) { + if(strategy.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); + } + if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); + return getDefaultReturnValue(); + } + + @Override + public boolean moveToFirst(KEY_TYPE key) { + if(strategy.equals(FIRST_ENTRY_KEY(), key)) return false; + if(strategy.equals(key, EMPTY_KEY_VALUE)) { + if(containsNull) { + moveToFirstIndex(nullIndex); + return true; + } + } + else { + int pos = HashUtil.mix(strategy.hashCode(key)) & mask; + while(!strategy.equals(keys[pos], EMPTY_KEY_VALUE)) { + if(strategy.equals(keys[pos], key)) { + moveToFirstIndex(pos); + return true; + } + pos = ++pos & mask; + } + } + return false; + } + + @Override + public boolean moveToLast(KEY_TYPE key) { + if(strategy.equals(LAST_ENTRY_KEY(), key)) return false; + if(strategy.equals(key, EMPTY_KEY_VALUE)) { + if(containsNull) { + moveToLastIndex(nullIndex); + return true; + } + } + else { + int pos = HashUtil.mix(strategy.hashCode(key)) & mask; + while(!strategy.equals(keys[pos], EMPTY_KEY_VALUE)) { + if(strategy.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(strategy.equals(result, EMPTY_KEY_VALUE)) { + 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(strategy.equals(result, EMPTY_KEY_VALUE)) { + 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(values == 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 newPrev = -1; + for(int j = size, i = firstIndex, pos = 0, prev = -1;j != 0;) { + if(strategy.equals(keys[i], EMPTY_KEY_VALUE)) pos = newSize; + else { + pos = HashUtil.mix(strategy.hashCode(keys[i])) & newMask; + while(!strategy.equals(newKeys[pos], EMPTY_KEY_VALUE)) 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; + } + + 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_CUSTOM_HASH_MAP.this.moveToFirst(o.ENTRY_KEY()); + } + + @Override + public boolean moveToLast(MAP.Entry KEY_VALUE_GENERIC_TYPE o) { + return LINKED_CUSTOM_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_CUSTOM_HASH_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); + return LINKED_CUSTOM_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_CUSTOM_HASH_MAP.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (Map.Entry)o; + return LINKED_CUSTOM_HASH_MAP.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + + @Override + public int size() { + return LINKED_CUSTOM_HASH_MAP.this.size(); + } + + @Override + public void clear() { + LINKED_CUSTOM_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_CUSTOM_HASH_MAP.this.moveToFirst(o); + } + + @Override + public boolean moveToLast(KEY_TYPE o) { + return LINKED_CUSTOM_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_CUSTOM_HASH_MAP.this.size(); + } + + @Override + public void clear() { + LINKED_CUSTOM_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_CUSTOM_HASH_MAP.this.size(); + } + + @Override + public void clear() { + LINKED_CUSTOM_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(nextEntry()); + + 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(strategy.equals(from, EMPTY_KEY_VALUE)) { + 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(strategy.hashCode(from)) & mask; + while(!strategy.equals(keys[pos], EMPTY_KEY_VALUE)) { + if(strategy.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(strategy.equals((current = keys[startPos]), EMPTY_KEY_VALUE)) { + keys[last] = EMPTY_KEY_VALUE; + values[last] = EMPTY_VALUE; + return; + } + slot = HashUtil.mix(strategy.hashCode(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++); + } + } + } + + } +} \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/maps/impl/customHash/OpenCustomHashMap.template b/src/main/resources/speiger/assets/collections/templates/maps/impl/customHash/OpenCustomHashMap.template new file mode 100644 index 00000000..bbb6cd11 --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/maps/impl/customHash/OpenCustomHashMap.template @@ -0,0 +1,781 @@ +package speiger.src.collections.PACKAGE.maps.impl.customHash; + +import java.util.Arrays; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Consumer; + +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.collections.ITERATOR; +import speiger.src.collections.PACKAGE.functions.CONSUMER; +#endif +import speiger.src.collections.PACKAGE.functions.consumer.BI_CONSUMER; +import speiger.src.collections.PACKAGE.lists.ARRAY_LIST; +import speiger.src.collections.PACKAGE.lists.LIST; +import speiger.src.collections.PACKAGE.maps.abstracts.ABSTRACT_MAP; +import speiger.src.collections.PACKAGE.maps.interfaces.MAP; +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.sets.ABSTRACT_SET; +import speiger.src.collections.PACKAGE.sets.SET; +#endif +import speiger.src.collections.PACKAGE.utils.STRATEGY; +import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_ABSTRACT_COLLECTION; +import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_COLLECTION; +#if !SAME_TYPE && !VALUE_OBJECT +import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_ITERATOR; +import speiger.src.collections.VALUE_PACKAGE.functions.VALUE_CONSUMER; +#endif +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.objects.sets.AbstractObjectSet; +import speiger.src.collections.objects.sets.ObjectSet; +import speiger.src.collections.utils.HashUtil; + +public class CUSTOM_HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE +{ + protected transient KEY_TYPE[] keys; + protected transient VALUE_TYPE[] values; + protected transient boolean containsNull; + protected transient int minCapacity; + protected transient int nullIndex; + protected transient int maxFill; + protected transient int mask; + protected transient FastEntrySet KEY_VALUE_GENERIC_TYPE entrySet; + protected transient SET KEY_GENERIC_TYPE keySet; + protected transient VALUE_COLLECTION VALUE_GENERIC_TYPE valuesC; + + protected int size; + protected final float loadFactor; + protected final STRATEGY KEY_SUPER_GENERIC_TYPE strategy; + + public CUSTOM_HASH_MAP(STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR, strategy); + } + + public CUSTOM_HASH_MAP(int minCapacity, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR, strategy); + } + + public CUSTOM_HASH_MAP(int minCapacity, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); + if(loadFactor <= 0 || loadFactor >= 1F) throw new IllegalStateException("Load Factor is not between 0 and 1"); + this.loadFactor = loadFactor; + this.minCapacity = nullIndex = HashUtil.arraySize(minCapacity, loadFactor); + this.strategy = strategy; + mask = nullIndex - 1; + maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); + keys = NEW_KEY_ARRAY(nullIndex + 1); + values = NEW_VALUE_ARRAY(nullIndex + 1); + } + +#if !TYPE_OBJECT || !VALUE_OBJECT + public CUSTOM_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(keys, values, HashUtil.DEFAULT_LOAD_FACTOR, strategy); + } + + public CUSTOM_HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(keys.length, loadFactor, strategy); + if(keys.length != values.length) throw new IllegalStateException("Input Arrays are not equal size"); + for(int i = 0,m=keys.length;i map, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(map, HashUtil.DEFAULT_LOAD_FACTOR, strategy); + } + + public CUSTOM_HASH_MAP(Map map, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(map.size(), loadFactor, strategy); + putAll(map); + } + + public CUSTOM_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(map, HashUtil.DEFAULT_LOAD_FACTOR, strategy); + } + + public CUSTOM_HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map, float loadFactor, STRATEGY KEY_SUPER_GENERIC_TYPE strategy) { + this(map.size(), loadFactor, strategy); + putAll(map); + } + + @Override + public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { + int slot = findIndex(key); + if(slot < 0) { + insert(-slot-1, key, value); + return getDefaultReturnValue(); + } + VALUE_TYPE oldValue = values[slot]; + values[slot] = value; + return oldValue; + } + + @Override + public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { + int slot = findIndex(key); + if(slot < 0) { + insert(-slot-1, key, value); + return getDefaultReturnValue(); + } + return values[slot]; + } + +#if VALUE_PRIMITIVES + @Override + public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { + int slot = findIndex(key); + if(slot < 0) { + insert(-slot-1, key, value); + return getDefaultReturnValue(); + } + VALUE_TYPE oldValue = values[slot]; + values[slot] += value; + return oldValue; + } + +#endif +#if !TYPE_OBJECT + @Override + public boolean containsKey(KEY_TYPE key) { + return findIndex(key) >= 0; + } + +#endif + @Override + @Deprecated + 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(!strategy.equals(keys[i], EMPTY_KEY_VALUE) && VALUE_EQUALS(values[i], value)) return true; + return false; + } + +#endif + @Override + @Deprecated + 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(!strategy.equals(keys[i], EMPTY_KEY_VALUE) && ((value == null && values[i] == getDefaultReturnValue()) || EQUALS_VALUE_TYPE(values[i], value))) return true; + return false; + } + + @Override + public VALUE_TYPE REMOVE_KEY(KEY_TYPE key) { + int slot = findIndex(key); + if(slot < 0) return getDefaultReturnValue(); + return removeIndex(slot); + } + + @Override + @Deprecated + public CLASS_VALUE_TYPE remove(Object key) { + int slot = findIndex(key); + if(slot < 0) return VALUE_TO_OBJ(getDefaultReturnValue()); + return removeIndex(slot); + } + +#if !TYPE_OBJECT || !VALUE_OBJECT + @Override + public boolean remove(KEY_TYPE key, VALUE_TYPE value) { + if(strategy.equals(key, EMPTY_KEY_VALUE)) { + if(containsNull && VALUE_EQUALS(value, values[nullIndex])) { + removeNullIndex(); + return true; + } + return false; + } + int pos = HashUtil.mix(strategy.hashCode(key)) & mask; + KEY_TYPE current = keys[pos]; + if(strategy.equals(current, EMPTY_KEY_VALUE)) return false; + if(strategy.equals(current, key) && VALUE_EQUALS(value, values[pos])) { + removeIndex(pos); + return true; + } + while(true) { + if(strategy.equals((current = keys[pos = (++pos & mask)]), EMPTY_KEY_VALUE)) return false; + else if(strategy.equals(current, key) && VALUE_EQUALS(value, values[pos])) { + removeIndex(pos); + return true; + } + } + } + +#endif + @Override + public boolean remove(Object key, Object value) { + Objects.requireNonNull(value); + if(key == null) { + if(containsNull && EQUALS_VALUE_TYPE(values[nullIndex], value)) { + removeNullIndex(); + return true; + } + return false; + } + KEY_TYPE keyType = CLASS_TO_KEY(key); + int pos = HashUtil.mix(strategy.hashCode(keyType)) & mask; + KEY_TYPE current = keys[pos]; + if(strategy.equals(current, EMPTY_KEY_VALUE)) return false; + if(strategy.equals(current, keyType) && EQUALS_VALUE_TYPE(values[pos], value)) { + removeIndex(pos); + return true; + } + while(true) { + if(strategy.equals((current = keys[pos = (++pos & mask)]), EMPTY_KEY_VALUE)) return false; + else if(strategy.equals(current, keyType) && EQUALS_VALUE_TYPE(values[pos], value)){ + removeIndex(pos); + return true; + } + } + } + + @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 + @Override + public VALUE_TYPE getOrDefault(KEY_TYPE key, VALUE_TYPE defaultValue) { + int slot = findIndex(key); + return slot < 0 ? defaultValue : values[slot]; + } + +#endif + @Override + public CLASS_VALUE_TYPE getOrDefault(Object key, CLASS_VALUE_TYPE defaultValue) { + int slot = findIndex(key); + return slot < 0 ? defaultValue : VALUE_TO_OBJ(values[slot]); + } + + @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) { + if(size() <= 0) return; + if(containsNull) action.accept(keys[nullIndex], values[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) { + if(!strategy.equals(keys[i], EMPTY_KEY_VALUE)) action.accept(keys[i], values[i]); + } + } + + @Override + public void clear() { + if(size == 0) return; + size = 0; + containsNull = false; + Arrays.fill(keys, EMPTY_KEY_VALUE); + Arrays.fill(values, EMPTY_VALUE); + } + +#if !TYPE_OBJECT + protected int findIndex(KEY_TYPE key) { + if(KEY_EQUALS_NULL(key)) return containsNull ? nullIndex : -(nullIndex + 1); + int pos = HashUtil.mix(strategy.hashCode(key)) & mask; + KEY_TYPE current = keys[pos]; + if(!strategy.equals(current, EMPTY_KEY_VALUE)) { + if(strategy.equals(current, key)) return pos; + while(!strategy.equals((current = keys[pos = (++pos & mask)]), EMPTY_KEY_VALUE)) + if(strategy.equals(current, key)) return pos; + } + return -(pos + 1); + } + +#endif + protected int findIndex(Object key) { + if(key == null) return containsNull ? nullIndex : -(nullIndex + 1); + KEY_TYPE keyType = CLASS_TO_KEY(key); + int pos = HashUtil.mix(strategy.hashCode(keyType)) & mask; + KEY_TYPE current = keys[pos]; + if(!strategy.equals(current, EMPTY_KEY_VALUE)) { + if(strategy.equals(current, keyType)) return pos; + while(!strategy.equals((current = keys[pos = (++pos & mask)]), EMPTY_KEY_VALUE)) + if(strategy.equals(current, keyType)) return pos; + } + return -(pos + 1); + } + + protected VALUE_TYPE removeIndex(int pos) { + VALUE_TYPE value = values[pos]; + size--; + onNodeRemoved(pos); + shiftKeys(pos); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return value; + } + + protected VALUE_TYPE removeNullIndex() { + VALUE_TYPE value = values[nullIndex]; + containsNull = false; + keys[nullIndex] = EMPTY_KEY_VALUE; + values[nullIndex] = EMPTY_VALUE; + size--; + onNodeRemoved(nullIndex); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return value; + } + + protected void insert(int slot, KEY_TYPE key, VALUE_TYPE value) { + if(slot == nullIndex) containsNull = true; + keys[slot] = key; + values[slot] = value; + onNodeAdded(slot); + if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); + } + + 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); + for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) { + while(strategy.equals(keys[--i], EMPTY_KEY_VALUE)); + if(!strategy.equals(newKeys[pos = HashUtil.mix(strategy.hashCode(keys[i])) & newMask], EMPTY_KEY_VALUE)) + while(!strategy.equals(newKeys[pos = (++pos & newMask)], EMPTY_KEY_VALUE)); + newKeys[pos] = keys[i]; + newValues[pos] = values[i]; + } + newValues[newSize] = values[nullIndex]; + nullIndex = newSize; + mask = newMask; + maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); + keys = newKeys; + values = newValues; + } + + protected void onNodeAdded(int pos) { + + } + + protected void onNodeRemoved(int pos) { + + } + + protected void onNodeMoved(int from, int to) { + + } + + protected void shiftKeys(int startPos) { + int slot, last; + KEY_TYPE current; + while(true) { + startPos = ((last = startPos) + 1) & mask; + while(true){ + if(strategy.equals((current = keys[startPos]), EMPTY_KEY_VALUE)) { + keys[last] = EMPTY_KEY_VALUE; + values[last] = EMPTY_VALUE; + return; + } + slot = HashUtil.mix(strategy.hashCode(current)) & mask; + if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; + startPos = ++startPos & mask; + } + keys[last] = current; + values[last] = values[startPos]; + onNodeMoved(startPos, last); + } + } + + 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 strategy.hashCode(keys[index]) ^ VALUE_TO_HASH(values[index]); + } + + @Override + public String toString() { + return KEY_TO_STRING(keys[index]) + "->" + VALUE_TO_STRING(values[index]); + } + } + + private final class MapEntrySet extends AbstractObjectSet implements MAP.FastEntrySet KEY_VALUE_GENERIC_TYPE { + @Override + public ObjectIterator fastIterator() { + return new FastEntryIterator(); + } + + @Override + public ObjectIterator iterator() { + return new EntryIterator(); + } + + @Override + public void forEach(Consumer action) { + if(containsNull) action.accept(new BasicEntryKV_BRACES(keys[nullIndex], values[nullIndex])); + for(int i = nullIndex-1;i>=0;i--) + if(!strategy.equals(keys[i], EMPTY_KEY_VALUE)) action.accept(new BasicEntryKV_BRACES(keys[i], values[i])); + } + + @Override + public void fastForEach(Consumer action) { + BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES(); + if(containsNull) { + entry.set(keys[nullIndex], values[nullIndex]); + action.accept(entry); + } + for(int i = nullIndex-1;i>=0;i--) { + if(strategy.equals(keys[i], EMPTY_KEY_VALUE)) { + entry.set(keys[i], values[i]); + action.accept(entry); + } + } + } + + @Override + public int size() { + return CUSTOM_HASH_MAP.this.size(); + } + + @Override + public void clear() { + CUSTOM_HASH_MAP.this.clear(); + } + + @Override + public boolean contains(Object o) { + if(o instanceof Map.Entry) { + if(o instanceof MAP.Entry) return CUSTOM_HASH_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); + return CUSTOM_HASH_MAP.this.containsKey(((Map.Entry)o).getKey()); + } + return false; + } + + @Override + 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 CUSTOM_HASH_MAP.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (Map.Entry)o; + return CUSTOM_HASH_MAP.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + } + + private final class KeySet extends ABSTRACT_SET KEY_GENERIC_TYPE { +#if TYPE_OBJECT + @Override + 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 ITERATOR KEY_GENERIC_TYPE iterator() { + return new KeyIterator(); + } + + @Override + public int size() { + return CUSTOM_HASH_MAP.this.size(); + } + + @Override + public void clear() { + CUSTOM_HASH_MAP.this.clear(); + } + +#if TYPE_OBJECT + @Override + public void forEach(Consumer KEY_SUPER_GENERIC_TYPE action) { + if(containsNull) action.accept(keys[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) + if(strategy.equals(keys[i], EMPTY_KEY_VALUE)) action.accept(keys[i]); + } + +#else + @Override + public void forEach(CONSUMER KEY_SUPER_GENERIC_TYPE action) { + if(containsNull) action.accept(keys[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) + if(strategy.equals(keys[i], EMPTY_KEY_VALUE)) action.accept(keys[i]); + } +#endif + } + + private class Values extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC_TYPE { +#if VALUE_OBJECT + @Override + 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 CUSTOM_HASH_MAP.this.size(); + } + + @Override + public void clear() { + CUSTOM_HASH_MAP.this.clear(); + } + +#if VALUE_OBJECT + @Override + public void forEach(Consumer VALUE_SUPER_GENERIC_TYPE action) { + if(containsNull) action.accept(values[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) + if(strategy.equals(keys[i], EMPTY_KEY_VALUE)) action.accept(values[i]); + } +#else + @Override + public void forEach(VALUE_CONSUMER VALUE_SUPER_GENERIC_TYPE action) { + if(containsNull) action.accept(values[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) + if(strategy.equals(keys[i], EMPTY_KEY_VALUE)) action.accept(values[i]); + } +#endif + } + + private class FastEntryIterator extends MapIterator implements ObjectIterator { + MapEntry entry = new MapEntry(); + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { + entry.index = nextEntry(); + return entry; + } + } + + private class EntryIterator extends MapIterator implements ObjectIterator { + MapEntry entry; + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { + return entry = new MapEntry(nextEntry()); + } + + @Override + public void remove() { + super.remove(); + entry.index = -1; + } + } + + private class KeyIterator extends MapIterator implements ITERATOR KEY_GENERIC_TYPE { + @Override + public KEY_TYPE NEXT() { + return keys[nextEntry()]; + } + } + + private class ValueIterator extends MapIterator implements VALUE_ITERATOR VALUE_GENERIC_TYPE { + @Override + public VALUE_TYPE VALUE_NEXT() { + return values[nextEntry()]; + } + } + + private class MapIterator { + int pos = nullIndex; + int lastReturned = -1; + int nextIndex = Integer.MIN_VALUE; + boolean returnNull = containsNull; + LIST KEY_GENERIC_TYPE wrapped = null; + + public boolean hasNext() { + if(nextIndex == Integer.MIN_VALUE) { + if(returnNull) { + returnNull = false; + nextIndex = nullIndex; + } + else + { + while(true) { + if(--pos < 0) { + if(wrapped == null || wrapped.size() <= -pos - 1) break; + nextIndex = -pos - 1; + break; + } + if(!strategy.equals(keys[pos], EMPTY_KEY_VALUE)){ + nextIndex = pos; + break; + } + } + } + } + return nextIndex != Integer.MIN_VALUE; + } + + public int nextEntry() { + if(!hasNext()) throw new NoSuchElementException(); + if(nextIndex < 0){ + lastReturned = Integer.MAX_VALUE; + int value = findIndex(wrapped.GET_KEY(nextIndex)); + if(value < 0) throw new IllegalStateException("Entry ["+nextIndex+"] was removed during Iteration"); + nextIndex = Integer.MIN_VALUE; + return value; + } + int value = (lastReturned = nextIndex); + nextIndex = Integer.MIN_VALUE; + return value; + } + + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + if(lastReturned == nullIndex) { + containsNull = false; + keys[nullIndex] = EMPTY_KEY_VALUE; + values[nullIndex] = EMPTY_VALUE; + } + else if(pos >= 0) shiftKeys(pos); + else { + CUSTOM_HASH_MAP.this.remove(wrapped.GET_KEY(-pos - 1)); + return; + } + size--; + lastReturned = -1; + } + + private void shiftKeys(int startPos) { + int slot, last; + KEY_TYPE current; + while(true) { + startPos = ((last = startPos) + 1) & mask; + while(true){ + if(strategy.equals((current = keys[startPos]), EMPTY_KEY_VALUE)) { + keys[last] = EMPTY_KEY_VALUE; + values[last] = EMPTY_VALUE; + return; + } + slot = HashUtil.mix(strategy.hashCode(current)) & mask; + if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; + startPos = ++startPos & mask; + } + if(startPos < last) { + if(wrapped == null) wrapped = new ARRAY_LISTBRACES(2); + wrapped.add(keys[startPos]); + } + keys[last] = current; + values[last] = values[startPos]; + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template b/src/main/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template new file mode 100644 index 00000000..e912866b --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/maps/impl/hash/LinkedOpenHashMap.template @@ -0,0 +1,1001 @@ +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); + } + 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); + } + 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); + } + 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); + } + 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(values == 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 newPrev = -1; + for(int j = size, i = firstIndex, pos = 0, prev = -1;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; + } + + 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(nextEntry()); + + 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++); + } + } + } + + } +} \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/maps/impl/hash/OpenHashMap.template b/src/main/resources/speiger/assets/collections/templates/maps/impl/hash/OpenHashMap.template new file mode 100644 index 00000000..06b9b273 --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/maps/impl/hash/OpenHashMap.template @@ -0,0 +1,776 @@ +package speiger.src.collections.PACKAGE.maps.impl.hash; + +import java.util.Arrays; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Consumer; + +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.collections.ITERATOR; +import speiger.src.collections.PACKAGE.functions.CONSUMER; +#endif +import speiger.src.collections.PACKAGE.functions.consumer.BI_CONSUMER; +import speiger.src.collections.PACKAGE.lists.ARRAY_LIST; +import speiger.src.collections.PACKAGE.lists.LIST; +import speiger.src.collections.PACKAGE.maps.abstracts.ABSTRACT_MAP; +import speiger.src.collections.PACKAGE.maps.interfaces.MAP; +#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; +#if !SAME_TYPE && !VALUE_OBJECT +import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_ITERATOR; +import speiger.src.collections.VALUE_PACKAGE.functions.VALUE_CONSUMER; +#endif +import speiger.src.collections.objects.collections.ObjectIterator; +import speiger.src.collections.objects.sets.AbstractObjectSet; +import speiger.src.collections.objects.sets.ObjectSet; +import speiger.src.collections.utils.HashUtil; + +public class HASH_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE +{ + protected transient KEY_TYPE[] keys; + protected transient VALUE_TYPE[] values; + protected transient boolean containsNull; + protected transient int minCapacity; + protected transient int nullIndex; + protected transient int maxFill; + protected transient int mask; + protected transient FastEntrySet KEY_VALUE_GENERIC_TYPE entrySet; + protected transient SET KEY_GENERIC_TYPE keySet; + protected transient VALUE_COLLECTION VALUE_GENERIC_TYPE valuesC; + + protected int size; + protected final float loadFactor; + + public HASH_MAP() { + this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public HASH_MAP(int minCapacity) { + this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public HASH_MAP(int minCapacity, float loadFactor) { + if(minCapacity < 0) throw new IllegalStateException("Minimum Capacity is negative. This is not allowed"); + if(loadFactor <= 0 || loadFactor >= 1F) throw new IllegalStateException("Load Factor is not between 0 and 1"); + this.loadFactor = loadFactor; + this.minCapacity = nullIndex = HashUtil.arraySize(minCapacity, loadFactor); + mask = nullIndex - 1; + maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); + keys = NEW_KEY_ARRAY(nullIndex + 1); + values = NEW_VALUE_ARRAY(nullIndex + 1); + } + +#if !TYPE_OBJECT || !VALUE_OBJECT + public HASH_MAP(CLASS_TYPE[] keys, CLASS_VALUE_TYPE[] values) { + this(keys, values, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public 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 HASH_MAP(Map map, float loadFactor) { + this(map.size(), loadFactor); + putAll(map); + } + + public HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map) { + this(map, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public HASH_MAP(MAP KEY_VALUE_GENERIC_TYPE map, float loadFactor) { + this(map.size(), loadFactor); + putAll(map); + } + + @Override + public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { + int slot = findIndex(key); + if(slot < 0) { + insert(-slot-1, key, value); + return getDefaultReturnValue(); + } + VALUE_TYPE oldValue = values[slot]; + values[slot] = value; + return oldValue; + } + + @Override + public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { + int slot = findIndex(key); + if(slot < 0) { + insert(-slot-1, key, value); + return getDefaultReturnValue(); + } + return values[slot]; + } + +#if VALUE_PRIMITIVES + @Override + public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { + int slot = findIndex(key); + if(slot < 0) { + insert(-slot-1, key, value); + return getDefaultReturnValue(); + } + VALUE_TYPE oldValue = values[slot]; + values[slot] += value; + return oldValue; + } + +#endif +#if !TYPE_OBJECT + @Override + public boolean containsKey(KEY_TYPE key) { + return findIndex(key) >= 0; + } + +#endif + @Override + @Deprecated + 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 + @Deprecated + 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_KEY(KEY_TYPE key) { + int slot = findIndex(key); + if(slot < 0) return getDefaultReturnValue(); + return removeIndex(slot); + } + + @Override + @Deprecated + public CLASS_VALUE_TYPE remove(Object key) { + int slot = findIndex(key); + if(slot < 0) return VALUE_TO_OBJ(getDefaultReturnValue()); + return removeIndex(slot); + } + +#if !TYPE_OBJECT || !VALUE_OBJECT + @Override + public boolean remove(KEY_TYPE key, VALUE_TYPE value) { + if(KEY_EQUALS_NULL(key)) { + if(containsNull && VALUE_EQUALS(value, values[nullIndex])) { + removeNullIndex(); + return true; + } + return false; + } + int pos = HashUtil.mix(KEY_TO_HASH(key)) & mask; + KEY_TYPE current = keys[pos]; + if(KEY_EQUALS_NULL(current)) return false; + if(KEY_EQUALS(current, key) && VALUE_EQUALS(value, values[pos])) { + removeIndex(pos); + return true; + } + while(true) { + if(KEY_EQUALS_NULL((current = keys[pos = (++pos & mask)]))) return false; + else if(KEY_EQUALS(current, key) && VALUE_EQUALS(value, values[pos])) { + removeIndex(pos); + return true; + } + } + } + +#endif + @Override + public boolean remove(Object key, Object value) { + Objects.requireNonNull(value); + if(key == null) { + if(containsNull && EQUALS_VALUE_TYPE(values[nullIndex], value)) { + removeNullIndex(); + return true; + } + return false; + } + int pos = HashUtil.mix(key.hashCode()) & mask; + KEY_TYPE current = keys[pos]; + if(KEY_EQUALS_NULL(current)) return false; + if(EQUALS_KEY_TYPE(current, key) && EQUALS_VALUE_TYPE(values[pos], value)) { + removeIndex(pos); + return true; + } + while(true) { + if(KEY_EQUALS_NULL((current = keys[pos = (++pos & mask)]))) return false; + else if(EQUALS_KEY_TYPE(current, key) && EQUALS_VALUE_TYPE(values[pos], value)){ + removeIndex(pos); + return true; + } + } + } + + @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 + @Override + public VALUE_TYPE getOrDefault(KEY_TYPE key, VALUE_TYPE defaultValue) { + int slot = findIndex(key); + return slot < 0 ? defaultValue : values[slot]; + } + +#endif + @Override + public CLASS_VALUE_TYPE getOrDefault(Object key, CLASS_VALUE_TYPE defaultValue) { + int slot = findIndex(key); + return slot < 0 ? defaultValue : VALUE_TO_OBJ(values[slot]); + } + + @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) { + if(size() <= 0) return; + if(containsNull) action.accept(keys[nullIndex], values[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) { + if(KEY_EQUALS_NOT_NULL(keys[i])) action.accept(keys[i], values[i]); + } + } + + @Override + public void clear() { + if(size == 0) return; + size = 0; + containsNull = false; + Arrays.fill(keys, EMPTY_KEY_VALUE); + Arrays.fill(values, EMPTY_VALUE); + } + +#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 VALUE_TYPE removeIndex(int pos) { + VALUE_TYPE value = values[pos]; + size--; + onNodeRemoved(pos); + shiftKeys(pos); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return value; + } + + protected VALUE_TYPE removeNullIndex() { + VALUE_TYPE value = values[nullIndex]; + containsNull = false; + keys[nullIndex] = EMPTY_KEY_VALUE; + values[nullIndex] = EMPTY_VALUE; + size--; + onNodeRemoved(nullIndex); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return value; + } + + protected void insert(int slot, KEY_TYPE key, VALUE_TYPE value) { + if(slot == nullIndex) containsNull = true; + keys[slot] = key; + values[slot] = value; + onNodeAdded(slot); + if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); + } + + 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); + for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) { + while(KEY_EQUALS_NULL(keys[--i])); + if(KEY_EQUALS_NOT_NULL(newKeys[pos = HashUtil.mix(KEY_TO_HASH(keys[i])) & newMask])) + while(KEY_EQUALS_NOT_NULL(newKeys[pos = (++pos & newMask)])); + newKeys[pos] = keys[i]; + newValues[pos] = values[i]; + } + newValues[newSize] = values[nullIndex]; + nullIndex = newSize; + mask = newMask; + maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); + keys = newKeys; + values = newValues; + } + + protected void onNodeAdded(int pos) { + + } + + protected void onNodeRemoved(int pos) { + + } + + protected void onNodeMoved(int from, int to) { + + } + + protected void shiftKeys(int startPos) { + int slot, last; + 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]; + onNodeMoved(startPos, last); + } + } + + 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]); + } + } + + private final class MapEntrySet extends AbstractObjectSet implements MAP.FastEntrySet KEY_VALUE_GENERIC_TYPE { + @Override + public ObjectIterator fastIterator() { + return new FastEntryIterator(); + } + + @Override + public ObjectIterator iterator() { + return new EntryIterator(); + } + + @Override + public void forEach(Consumer action) { + if(containsNull) action.accept(new BasicEntryKV_BRACES(keys[nullIndex], values[nullIndex])); + for(int i = nullIndex-1;i>=0;i--) + if(KEY_EQUALS_NOT_NULL(keys[i])) action.accept(new BasicEntryKV_BRACES(keys[i], values[i])); + } + + @Override + public void fastForEach(Consumer action) { + BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES(); + if(containsNull) { + entry.set(keys[nullIndex], values[nullIndex]); + action.accept(entry); + } + for(int i = nullIndex-1;i>=0;i--) { + if(KEY_EQUALS_NOT_NULL(keys[i])) { + entry.set(keys[i], values[i]); + action.accept(entry); + } + } + } + + @Override + public int size() { + return HASH_MAP.this.size(); + } + + @Override + public void clear() { + HASH_MAP.this.clear(); + } + + @Override + public boolean contains(Object o) { + if(o instanceof Map.Entry) { + if(o instanceof MAP.Entry) return HASH_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); + return HASH_MAP.this.containsKey(((Map.Entry)o).getKey()); + } + return false; + } + + @Override + 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 HASH_MAP.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (Map.Entry)o; + return HASH_MAP.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + } + + private final class KeySet extends ABSTRACT_SET KEY_GENERIC_TYPE { +#if TYPE_OBJECT + @Override + 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 ITERATOR KEY_GENERIC_TYPE iterator() { + return new KeyIterator(); + } + + @Override + public int size() { + return HASH_MAP.this.size(); + } + + @Override + public void clear() { + HASH_MAP.this.clear(); + } + +#if TYPE_OBJECT + @Override + public void forEach(Consumer KEY_SUPER_GENERIC_TYPE action) { + if(containsNull) action.accept(keys[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) + if(KEY_EQUALS_NOT_NULL(keys[i])) action.accept(keys[i]); + } + +#else + @Override + public void forEach(CONSUMER KEY_SUPER_GENERIC_TYPE action) { + if(containsNull) action.accept(keys[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) + if(KEY_EQUALS_NOT_NULL(keys[i])) action.accept(keys[i]); + } +#endif + } + + private class Values extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC_TYPE { +#if VALUE_OBJECT + @Override + 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 HASH_MAP.this.size(); + } + + @Override + public void clear() { + HASH_MAP.this.clear(); + } + +#if VALUE_OBJECT + @Override + public void forEach(Consumer VALUE_SUPER_GENERIC_TYPE action) { + if(containsNull) action.accept(values[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) + if(KEY_EQUALS_NOT_NULL(keys[i])) action.accept(values[i]); + } +#else + @Override + public void forEach(VALUE_CONSUMER VALUE_SUPER_GENERIC_TYPE action) { + if(containsNull) action.accept(values[nullIndex]); + for(int i = nullIndex-1;i>=0;i--) + if(KEY_EQUALS_NOT_NULL(keys[i])) action.accept(values[i]); + } +#endif + } + + private class FastEntryIterator extends MapIterator implements ObjectIterator { + MapEntry entry = new MapEntry(); + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { + entry.index = nextEntry(); + return entry; + } + } + + private class EntryIterator extends MapIterator implements ObjectIterator { + MapEntry entry; + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { + return entry = new MapEntry(nextEntry()); + } + + @Override + public void remove() { + super.remove(); + entry.index = -1; + } + } + + private class KeyIterator extends MapIterator implements ITERATOR KEY_GENERIC_TYPE { + @Override + public KEY_TYPE NEXT() { + return keys[nextEntry()]; + } + } + + private class ValueIterator extends MapIterator implements VALUE_ITERATOR VALUE_GENERIC_TYPE { + @Override + public VALUE_TYPE VALUE_NEXT() { + return values[nextEntry()]; + } + } + + private class MapIterator { + int pos = nullIndex; + int lastReturned = -1; + int nextIndex = Integer.MIN_VALUE; + boolean returnNull = containsNull; + LIST KEY_GENERIC_TYPE wrapped = null; + + public boolean hasNext() { + if(nextIndex == Integer.MIN_VALUE) { + if(returnNull) { + returnNull = false; + nextIndex = nullIndex; + } + else + { + while(true) { + if(--pos < 0) { + if(wrapped == null || wrapped.size() <= -pos - 1) break; + nextIndex = -pos - 1; + break; + } + if(KEY_EQUALS_NOT_NULL(keys[pos])){ + nextIndex = pos; + break; + } + } + } + } + return nextIndex != Integer.MIN_VALUE; + } + + public int nextEntry() { + if(!hasNext()) throw new NoSuchElementException(); + if(nextIndex < 0){ + lastReturned = Integer.MAX_VALUE; + int value = findIndex(wrapped.GET_KEY(nextIndex)); + if(value < 0) throw new IllegalStateException("Entry ["+nextIndex+"] was removed during Iteration"); + nextIndex = Integer.MIN_VALUE; + return value; + } + int value = (lastReturned = nextIndex); + nextIndex = Integer.MIN_VALUE; + return value; + } + + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + if(lastReturned == nullIndex) { + containsNull = false; + keys[nullIndex] = EMPTY_KEY_VALUE; + values[nullIndex] = EMPTY_VALUE; + } + else if(pos >= 0) shiftKeys(pos); + else { + HASH_MAP.this.remove(wrapped.GET_KEY(-pos - 1)); + return; + } + size--; + lastReturned = -1; + } + + private void shiftKeys(int startPos) { + int slot, last; + 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; + } + if(startPos < last) { + if(wrapped == null) wrapped = new ARRAY_LISTBRACES(2); + wrapped.add(keys[startPos]); + } + keys[last] = current; + values[last] = values[startPos]; + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/maps/impl/misc/ArrayMap.template b/src/main/resources/speiger/assets/collections/templates/maps/impl/misc/ArrayMap.template new file mode 100644 index 00000000..745c0bbd --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/maps/impl/misc/ArrayMap.template @@ -0,0 +1,1653 @@ +package speiger.src.collections.PACKAGE.maps.impl.misc; + +import java.util.Arrays; +import java.util.Comparator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.function.Consumer; + +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.lists.LIST_ITERATOR; +import speiger.src.collections.PACKAGE.maps.abstracts.ABSTRACT_MAP; +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 !SAME_TYPE && !VALUE_OBJECT +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 + +public class ARRAY_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE implements SORTED_MAP KEY_VALUE_GENERIC_TYPE +{ + protected transient KEY_TYPE[] keys; + protected transient VALUE_TYPE[] values; + protected int size = 0; + protected SET KEY_GENERIC_TYPE keySet; + protected VALUE_COLLECTION VALUE_GENERIC_TYPE valuesC; + protected FastSortedSet KEY_VALUE_GENERIC_TYPE entrySet; + + @Override + public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(size++, key, value); + return getDefaultReturnValue(); + } + VALUE_TYPE oldValue = values[index]; + values[index] = value; + return oldValue; + } + + @Override + public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key); + if(index >= 0) insertIndex(size++, key, value); + return getDefaultReturnValue(); + } + +#if VALUE_PRIMITIVES + @Override + public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(size++, key, value); + return getDefaultReturnValue(); + } + VALUE_TYPE oldValue = values[index]; + values[index] += value; + return oldValue; + } + +#endif + @Override + public VALUE_TYPE putAndMoveToFirst(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(0, key, value); + size++; + return getDefaultReturnValue(); + } + VALUE_TYPE lastValue = values[index]; + values[index] = value; + moveIndexToFirst(index); + return lastValue; + } + + @Override + public VALUE_TYPE putAndMoveToLast(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(size++, key, value); + return getDefaultReturnValue(); + } + VALUE_TYPE lastValue = values[index]; + values[index] = value; + moveIndexToLast(index); + return lastValue; + } + + @Override + public boolean moveToFirst(KEY_TYPE key) { + int index = findIndex(key); + if(index >= 0) { + moveIndexToFirst(index); + return true; + } + return false; + } + + @Override + public boolean moveToLast(KEY_TYPE key) { + int index = findIndex(key); + if(index >= 0) { + moveIndexToLast(index); + return true; + } + return false; + } + +#if !TYPE_OBJECT + @Override + public boolean containsKey(KEY_TYPE key) { + return findIndex(key) >= 0; + } + +#endif +#if !VALUE_OBJECT + @Override + public boolean containsValue(VALUE_TYPE value) { + return findValue(value) >= 0; + } + +#endif + @Override + public boolean containsKey(Object key) { + return findIndex(key) >= 0; + } + + @Override + public boolean containsValue(Object value) { + return findValue(value) >= 0; + } + + @Override + public VALUE_TYPE GET_VALUE(KEY_TYPE key) { + int index = findIndex(key); + return index < 0 ? getDefaultReturnValue() : values[index]; + } + +#if !TYPE_OBJECT + @Override + public VALUE_TYPE getOrDefault(KEY_TYPE key, VALUE_TYPE defaultValue) { + int index = findIndex(key); + return index < 0 ? defaultValue : values[index]; + } + +#endif + @Override + public CLASS_VALUE_TYPE getOrDefault(Object key, CLASS_VALUE_TYPE defaultValue) { + int index = findIndex(key); + return index < 0 ? defaultValue : VALUE_TO_OBJ(values[index]); + } + + @Override + public VALUE_TYPE getAndMoveToFirst(KEY_TYPE key) { + int index = findIndex(key); + if(index >= 0) { + VALUE_TYPE value = values[index]; + moveIndexToFirst(index); + return value; + } + return getDefaultReturnValue(); + } + + @Override + public VALUE_TYPE getAndMoveToLast(KEY_TYPE key) { + int index = findIndex(key); + if(index >= 0) { + VALUE_TYPE value = values[index]; + moveIndexToLast(index); + return value; + } + return getDefaultReturnValue(); + } + + @Override + public KEY_TYPE FIRST_ENTRY_KEY() { + if(size <= 0) throw new NoSuchElementException(); + return keys[0]; + } + + @Override + public KEY_TYPE LAST_ENTRY_KEY() { + if(size <= 0) throw new NoSuchElementException(); + return keys[size-1]; + } + + @Override + public VALUE_TYPE FIRST_ENTRY_VALUE() { + if(size <= 0) throw new NoSuchElementException(); + return values[size-1]; + } + + @Override + public VALUE_TYPE LAST_ENTRY_VALUE() { + if(size <= 0) throw new NoSuchElementException(); + return values[0]; + } + + @Override + public KEY_TYPE POLL_FIRST_ENTRY_KEY() { + if(size == 0) throw new NoSuchElementException(); + KEY_TYPE result = keys[0]; + removeIndex(0); + return result; + } + + @Override + public KEY_TYPE POLL_LAST_ENTRY_KEY() { + if(size == 0) throw new NoSuchElementException(); + KEY_TYPE result = keys[size-1]; + removeIndex(size-1); + return result; + } + + @Override + public VALUE_TYPE REMOVE_KEY(KEY_TYPE key) { + int index = findIndex(key); + if(index < 0) return getDefaultReturnValue(); + VALUE_TYPE value = values[index]; + removeIndex(index); + return value; + } + +#if !TYPE_OBJECT || !VALUE_OBJECT + @Override + public boolean remove(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key, value); + if(index < 0) return false; + removeIndex(index); + return true; + } + +#endif + @Override + public CLASS_VALUE_TYPE remove(Object key) { + int index = findIndex(key); + if(index < 0) return VALUE_TO_OBJ(getDefaultReturnValue()); + VALUE_TYPE value = values[index]; + removeIndex(index); + return VALUE_TO_OBJ(value); + } + + @Override + public boolean remove(Object key, Object value) { + int index = findIndex(key, value); + if(index < 0) return false; + removeIndex(index); + return true; + } + + @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 ObjectSortedSet ENTRY_SET() { + if(entrySet == null) entrySet = new MapEntrySet(); + return entrySet; + } + + @Override + public int size() { + return size; + } + + @Override + public void clear() { + Arrays.fill(keys, 0, size, EMPTY_KEY_VALUE); + Arrays.fill(values, 0, size, EMPTY_VALUE); + size = 0; + } + + @Override + public COMPARATOR KEY_GENERIC_TYPE comparator() { + return null; + } + + @Override + public SORTED_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, KEY_TYPE toKey) { + int fromIndex = findIndex(fromKey); + int toIndex = findIndex(toKey); + if(fromIndex == -1 || toIndex == -1) throw new NoSuchElementException(); + return new SubMap(fromIndex, toIndex - fromIndex + 1); + } + + @Override + public SORTED_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey) { + int toIndex = findIndex(toKey); + if(toIndex == -1) throw new NoSuchElementException(); + return new SubMap(0, toIndex + 1); + } + + @Override + public SORTED_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey) { + int fromIndex = findIndex(fromKey); + if(fromIndex == -1) throw new NoSuchElementException(); + return new SubMap(fromIndex, size - fromIndex); + } + + protected void moveIndexToFirst(int index) { + if(index == 0) return; + KEY_TYPE key = keys[index]; + VALUE_TYPE value = values[index]; + System.arraycopy(keys, 0, keys, 1, index); + System.arraycopy(values, 0, values, 1, index); + keys[0] = key; + values[0] = value; + } + + protected void moveIndexToLast(int index) { + if(index == size-1) return; + KEY_TYPE key = keys[index]; + VALUE_TYPE value = values[index]; + System.arraycopy(keys, index+1, keys, index, size-index-1); + System.arraycopy(values, index+1, values, index, size-index-1); + keys[size-1] = key; + values[size-1] = value; + } + + protected void grow(int newSize) { + if(newSize < keys.length) return; + newSize = Math.min(newSize, keys.length == 0 ? 2 : keys.length * 2); + keys = Arrays.copyOf(keys, newSize); + values = Arrays.copyOf(values, newSize); + } + + protected void insertIndex(int index, KEY_TYPE key, VALUE_TYPE value) { + grow(size+1); + if(index != size) { + System.arraycopy(keys, index, keys, index+1, size-index); + System.arraycopy(values, index, values, index+1, size-index); + } + keys[index] = key; + values[index] = value; + } + + protected void removeRange(int from, int to) { + if(from < 0 || from >= size) throw new IllegalStateException("From Element "); + int length = to - from; + if(length <= 0) return; + if(to != size) { + System.arraycopy(keys, to, keys, from, size - to); + System.arraycopy(values, to, values, from, size - to); + } + for(int i = 0;i=0;i--) + if(KEY_EQUALS(keys[i], key) && VALUE_EQUALS(values[i], value)) return i; + return -1; + } + +#endif +#if !TYPE_OBJECT + protected int findIndex(KEY_TYPE key) { + for(int i = size-1;i>=0;i--) + if(KEY_EQUALS(keys[i], key)) return i; + return -1; + } + +#endif +#if !VALUE_OBJECT + protected int findValue(VALUE_TYPE value) { + for(int i = size-1;i>=0;i--) + if(VALUE_EQUALS(values[i], value)) return i; + return -1; + } + +#endif + protected int findIndex(Object key, Object value) { + if(key == null || value == null) return -1; + for(int i = size-1;i>=0;i--) + if(EQUALS_KEY_TYPE(keys[i], key) && EQUALS_VALUE_TYPE(values[i], value)) return i; + return -1; + } + + protected int findIndex(Object key) { + if(key == null) return -1; + for(int i = size-1;i>=0;i--) + if(EQUALS_KEY_TYPE(keys[i], key)) return i; + return -1; + } + + protected int findValue(Object value) { + if(value == null) return -1; + for(int i = size-1;i>=0;i--) + if(EQUALS_VALUE_TYPE(values[i], value)) return i; + return -1; + } + + private class SubMap extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE implements SORTED_MAP KEY_VALUE_GENERIC_TYPE { + int offset; + int length; + + SET KEY_GENERIC_TYPE keySet; + VALUE_COLLECTION VALUE_GENERIC_TYPE valuesC; + FastSortedSet KEY_VALUE_GENERIC_TYPE entrySet; + + public SubMap(int offset, int length) { + this.offset = offset; + this.length = length; + } + + int end() { return offset+length; } + + @Override + public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(end(), key, value); + length++; + return getDefaultReturnValue(); + } + VALUE_TYPE oldValue = values[index]; + values[index] = value; + return oldValue; + } + + @Override + public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key); + if(index >= 0) { + insertIndex(end(), key, value); + length++; + } + return getDefaultReturnValue(); + } + +#if VALUE_PRIMITIVES + @Override + public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(end(), key, value); + length++; + return getDefaultReturnValue(); + } + VALUE_TYPE oldValue = values[index]; + values[index] += value; + return oldValue; + } + +#endif + @Override + public VALUE_TYPE putAndMoveToFirst(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(offset, key, value); + length++; + return getDefaultReturnValue(); + } + VALUE_TYPE lastValue = values[index]; + values[index] = value; + moveIndexToFirst(index); + return lastValue; + } + + @Override + public VALUE_TYPE putAndMoveToLast(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key); + if(index < 0) { + insertIndex(end(), key, value); + length++; + return getDefaultReturnValue(); + } + VALUE_TYPE lastValue = values[index]; + values[index] = value; + moveIndexToLast(index); + return lastValue; + } + + @Override + public boolean moveToFirst(KEY_TYPE key) { + int index = findIndex(key); + if(index >= 0) { + moveIndexToFirst(index); + return true; + } + return false; + } + + @Override + public boolean moveToLast(KEY_TYPE key) { + int index = findIndex(key); + if(index >= 0) { + moveIndexToLast(index); + return true; + } + return false; + } + +#if !TYPE_OBJECT + @Override + public boolean containsKey(KEY_TYPE key) { + return findIndex(key) >= 0; + } + +#endif +#if !VALUE_OBJECT + @Override + public boolean containsValue(VALUE_TYPE value) { + return findValue(value) >= 0; + } + +#endif + @Override + public boolean containsKey(Object key) { + return findIndex(key) >= 0; + } + + @Override + public boolean containsValue(Object value) { + return findValue(value) >= 0; + } + + @Override + public VALUE_TYPE GET_VALUE(KEY_TYPE key) { + int index = findIndex(key); + return index < 0 ? getDefaultReturnValue() : values[index]; + } + +#if !TYPE_OBJECT + @Override + public VALUE_TYPE getOrDefault(KEY_TYPE key, VALUE_TYPE defaultValue) { + int index = findIndex(key); + return index < 0 ? defaultValue : values[index]; + } + +#endif + @Override + public CLASS_VALUE_TYPE get(Object key) { + int index = findIndex(key); + return VALUE_TO_OBJ(index < 0 ? getDefaultReturnValue() : values[index]); + } + + @Override + public CLASS_VALUE_TYPE getOrDefault(Object key, CLASS_VALUE_TYPE defaultValue) { + int index = findIndex(key); + return index < 0 ? defaultValue : VALUE_TO_OBJ(values[index]); + } + + @Override + public VALUE_TYPE getAndMoveToFirst(KEY_TYPE key) { + int index = findIndex(key); + if(index >= 0) { + VALUE_TYPE value = values[index]; + moveIndexToFirst(index); + return value; + } + return getDefaultReturnValue(); + } + + @Override + public VALUE_TYPE getAndMoveToLast(KEY_TYPE key) { + int index = findIndex(key); + if(index >= 0) { + VALUE_TYPE value = values[index]; + moveIndexToLast(index); + return value; + } + return getDefaultReturnValue(); + } + + @Override + public KEY_TYPE FIRST_ENTRY_KEY() { + if(length <= 0) throw new NoSuchElementException(); + return keys[offset]; + } + + @Override + public KEY_TYPE LAST_ENTRY_KEY() { + if(length <= 0) throw new NoSuchElementException(); + return keys[end()-1]; + } + + @Override + public VALUE_TYPE FIRST_ENTRY_VALUE() { + if(length <= 0) throw new NoSuchElementException(); + return values[end()-1]; + } + + @Override + public VALUE_TYPE LAST_ENTRY_VALUE() { + if(length <= 0) throw new NoSuchElementException(); + return values[offset]; + } + + @Override + public KEY_TYPE POLL_FIRST_ENTRY_KEY() { + if(length == 0) throw new NoSuchElementException(); + KEY_TYPE result = keys[offset]; + removeIndex(offset); + length--; + return result; + } + + @Override + public KEY_TYPE POLL_LAST_ENTRY_KEY() { + if(length == 0) throw new NoSuchElementException(); + KEY_TYPE result = keys[end()-1]; + removeIndex(end()-1); + length--; + return result; + } + + @Override + public VALUE_TYPE REMOVE_KEY(KEY_TYPE key) { + int index = findIndex(key); + if(index < 0) return getDefaultReturnValue(); + VALUE_TYPE value = values[index]; + removeIndex(index); + return value; + } + +#if !TYPE_OBJECT || !VALUE_OBJECT + @Override + public boolean remove(KEY_TYPE key, VALUE_TYPE value) { + int index = findIndex(key, value); + if(index < 0) return false; + removeIndex(index); + return true; + } + +#endif + @Override + public CLASS_VALUE_TYPE remove(Object key) { + int index = findIndex(key); + if(index < 0) return VALUE_TO_OBJ(getDefaultReturnValue()); + VALUE_TYPE value = values[index]; + removeIndex(index); + return VALUE_TO_OBJ(value); + } + + @Override + public boolean remove(Object key, Object value) { + int index = findIndex(key, value); + if(index < 0) return false; + removeIndex(index); + return true; + } + + @Override + public int size() { + return length; + } + + @Override + public void clear() { + removeRange(offset, offset+length); + length = 0; + } + + @Override + public SET KEY_GENERIC_TYPE keySet() { + if(keySet == null) keySet = new SubKeySet(); + return keySet; + } + + @Override + public VALUE_COLLECTION VALUE_GENERIC_TYPE values() { + if(valuesC == null) valuesC = new SubValues(); + return valuesC; + } + + @Override + public ObjectSet ENTRY_SET() { + if(entrySet == null) entrySet = new SubMapEntrySet(); + return entrySet; + } + + @Override + public COMPARATOR KEY_GENERIC_TYPE comparator() { + return null; + } + + @Override + public SORTED_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, KEY_TYPE toKey) { + int fromIndex = findIndex(fromKey); + int toIndex = findIndex(toKey); + if(fromIndex == -1 || toIndex == -1) throw new NoSuchElementException(); + return new SubMap(fromIndex, toIndex - fromIndex + 1); + } + + @Override + public SORTED_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey) { + int toIndex = findIndex(toKey); + if(toIndex == -1) throw new NoSuchElementException(); + return new SubMap(offset, toIndex + 1); + } + + @Override + public SORTED_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey) { + int fromIndex = findIndex(fromKey); + if(fromIndex == -1) throw new NoSuchElementException(); + return new SubMap(fromIndex, size - fromIndex); + } + + protected void moveIndexToFirst(int index) { + if(index == 0) return; + KEY_TYPE key = keys[index]; + VALUE_TYPE value = values[index]; + System.arraycopy(keys, offset, keys, offset+1, index); + System.arraycopy(values, offset, values, offset+1, index); + keys[offset] = key; + values[offset] = value; + } + + protected void moveIndexToLast(int index) { + if(index == length-1) return; + KEY_TYPE key = keys[index]; + VALUE_TYPE value = values[index]; + System.arraycopy(keys, offset+index+1, keys, offset+index, length-index-1); + System.arraycopy(values, offset+index+1, values, offset+index, length-index-1); + keys[end()-1] = key; + values[end()-1] = value; + } + +#if !TYPE_OBJECT || !VALUE_OBJECT + protected int findIndex(KEY_TYPE key, VALUE_TYPE value) { + for(int i = length-1;i>=0;i--) + if(KEY_EQUALS(keys[offset+i], key) && VALUE_EQUALS(values[offset+i], value)) return i; + return -1; + } + +#endif +#if !TYPE_OBJECT + protected int findIndex(KEY_TYPE key) { + for(int i = length-1;i>=0;i--) + if(KEY_EQUALS(keys[offset+i], key)) return i; + return -1; + } + +#endif +#if !VALUE_OBJECT + protected int findValue(VALUE_TYPE value) { + for(int i = length-1;i>=0;i--) + if(VALUE_EQUALS(values[offset+i], value)) return i; + return -1; + } + +#endif + protected int findIndex(Object key, Object value) { + if(key == null || value == null) return -1; + for(int i = length-1;i>=0;i--) + if(EQUALS_KEY_TYPE(keys[offset+i], key) && EQUALS_VALUE_TYPE(values[offset+i], value)) return i; + return -1; + } + + protected int findIndex(Object key) { + if(key == null) return -1; + for(int i = length-1;i>=0;i--) + if(EQUALS_KEY_TYPE(keys[offset+i], key)) return i; + return -1; + } + + protected int findValue(Object value) { + if(value == null) return -1; + for(int i = length-1;i>=0;i--) + if(EQUALS_VALUE_TYPE(values[offset+i], value)) return i; + return -1; + } + + private class SubMapEntrySet 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 SubMap.this.moveToFirst(o.ENTRY_KEY()); + } + + @Override + public boolean moveToLast(MAP.Entry KEY_VALUE_GENERIC_TYPE o) { + return SubMap.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 SubEntryIterator(); + } + + @Override + public ObjectBidirectionalIterator iterator(MAP.Entry KEY_VALUE_GENERIC_TYPE fromElement) { + return new SubEntryIterator(fromElement.ENTRY_KEY()); + } + + @Override + public ObjectBidirectionalIterator fastIterator() { + return new SubFastEntryIterator(); + } + + @Override + public ObjectBidirectionalIterator fastIterator(KEY_TYPE fromElement) { + return new SubFastEntryIterator(fromElement); + } + + @Override + public void forEach(Consumer action) { + for(int i = 0;i action) { + BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES(); + for(int i = 0;i)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 SubMap.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (Map.Entry)o; + return SubMap.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + + @Override + public int size() { + return SubMap.this.size(); + } + + @Override + public void clear() { + SubMap.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 class SubKeySet extends ABSTRACT_SET KEY_GENERIC_TYPE implements SORTED_SET KEY_GENERIC_TYPE { +#if TYPE_OBJECT + @Override + public boolean contains(Object e) { return containsKey(e); } + + @Override + public boolean remove(Object o) { + int oldSize = length; + remove(o); + return length != oldSize; + } + +#else + @Override + public boolean contains(KEY_TYPE e) { return containsKey(e); } + + @Override + public boolean remove(KEY_TYPE o) { + int oldSize = length; + remove(o); + return length != 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 SubMap.this.moveToFirst(o); } + @Override + public boolean moveToLast(KEY_TYPE o) { return SubMap.this.moveToLast(o); } + @Override + public LIST_ITERATOR KEY_GENERIC_TYPE iterator() { return new SubKeyIterator(); } + @Override + public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) { return new SubKeyIterator(fromElement); } + @Override + public int size() { return SubMap.this.size(); } + @Override + public void clear() { SubMap.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 action) { + for(int i = 0;i action) { + for(int i = 0;i { + MapEntry entry = new MapEntry(); + + public SubFastEntryIterator() {} + public SubFastEntryIterator(KEY_TYPE from) { + index = findIndex(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 e) { throw new UnsupportedOperationException(); } + @Override + public void add(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + } + + private class SubEntryIterator extends SubMapIterator implements ObjectListIterator { + MapEntry entry = null; + + public SubEntryIterator() {} + public SubEntryIterator(KEY_TYPE from) { + index = findIndex(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 e) { throw new UnsupportedOperationException(); } + @Override + public void add(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + } + + private class SubKeyIterator extends SubMapIterator implements LIST_ITERATOR KEY_GENERIC_TYPE { + public SubKeyIterator() {} + public SubKeyIterator(KEY_TYPE element) { + index = findIndex(element); + } + @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 SubValueIterator extends SubMapIterator implements VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE { + @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 SubMapIterator { + int index; + int lastReturned = -1; + + public boolean hasNext() { + return index < length; + } + + public boolean hasPrevious() { + return index > 0; + } + + public int nextIndex() { + return index; + } + + public int previousIndex() { + return index-1; + } + + public void remove() { + if(lastReturned == -1) + throw new IllegalStateException(); + removeIndex(lastReturned); + if(lastReturned < index) + index--; + lastReturned = -1; + } + + public int previousEntry() { + int returnIndex = offset+index; + lastReturned = index--; + return returnIndex; + } + + public int nextEntry() { + int returnIndex = offset+index; + lastReturned = index++; + return returnIndex; + } + + public int skip(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int steps = Math.min(amount, (size() - 1) - index); + index += steps; + return steps; + } + + public int back(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int steps = Math.min(amount, index); + index -= steps; + return steps; + } + } + } + + 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 ARRAY_MAP.this.moveToFirst(o.ENTRY_KEY()); + } + + @Override + public boolean moveToLast(MAP.Entry KEY_VALUE_GENERIC_TYPE o) { + return ARRAY_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) { + for(int i = 0;i action) { + BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES(); + for(int i = 0;i)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 ARRAY_MAP.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (Map.Entry)o; + return ARRAY_MAP.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + + @Override + public int size() { + return ARRAY_MAP.this.size(); + } + + @Override + public void clear() { + ARRAY_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 class KeySet extends ABSTRACT_SET KEY_GENERIC_TYPE implements SORTED_SET KEY_GENERIC_TYPE { +#if TYPE_OBJECT + @Override + 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 ARRAY_MAP.this.moveToFirst(o); } + @Override + public boolean moveToLast(KEY_TYPE o) { return ARRAY_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 ARRAY_MAP.this.size(); } + @Override + public void clear() { ARRAY_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 action) { + for(int i = 0;i action) { + for(int i = 0;i { + MapEntry entry = new MapEntry(); + + public FastEntryIterator() {} + public FastEntryIterator(KEY_TYPE from) { + index = findIndex(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 e) { throw new UnsupportedOperationException(); } + @Override + public void add(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + } + + private class EntryIterator extends MapIterator implements ObjectListIterator { + MapEntry entry = null; + + public EntryIterator() {} + public EntryIterator(KEY_TYPE from) { + index = findIndex(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 e) { throw new UnsupportedOperationException(); } + @Override + public void add(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + } + + private class KeyIterator extends MapIterator implements LIST_ITERATOR KEY_GENERIC_TYPE { + public KeyIterator() {} + public KeyIterator(KEY_TYPE element) { + index = findIndex(element); + } + @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 { + @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 index; + int lastReturned = -1; + + public boolean hasNext() { + return index < size; + } + + public boolean hasPrevious() { + return index > 0; + } + + public int nextIndex() { + return index; + } + + public int previousIndex() { + return index-1; + } + + public void remove() { + if(lastReturned == -1) + throw new IllegalStateException(); + removeIndex(lastReturned); + if(lastReturned < index) + index--; + lastReturned = -1; + } + + public int previousEntry() { + lastReturned = index; + return index--; + } + + public int nextEntry() { + lastReturned = index; + return index++; + } + + public int skip(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int steps = Math.min(amount, (size() - 1) - index); + index += steps; + return steps; + } + + public int back(int amount) { + if(amount < 0) throw new IllegalStateException("Negative Numbers are not allowed"); + int steps = Math.min(amount, index); + index -= steps; + return steps; + } + } + + private class MapEntry implements MAP.Entry KEY_VALUE_GENERIC_TYPE, Map.Entry { + 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 diff --git a/src/main/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template b/src/main/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template new file mode 100644 index 00000000..6c078c8d --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/maps/impl/misc/EnumMap.template @@ -0,0 +1,332 @@ +package speiger.src.collections.PACKAGE.maps.impl.misc; + +import java.util.Map; +import java.util.NoSuchElementException; +#if VALUE_OBJECT +import java.util.Objects; +#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 !VALUE_OBJECT +import speiger.src.collections.objects.collections.ObjectIterator; +#endif +import speiger.src.collections.objects.maps.abstracts.ABSTRACT_MAP; +import speiger.src.collections.objects.maps.interfaces.MAP; +import speiger.src.collections.objects.sets.AbstractObjectSet; +import speiger.src.collections.objects.sets.ObjectSet; +import sun.misc.SharedSecrets; + +public class ENUM_MAP KEY_ENUM_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE +{ + protected final Class keyType; + protected transient final T[] keys; + protected transient final VALUE_TYPE[] values; + protected transient final long[] present; + protected int size = 0; + protected transient ObjectSet entrySet; + protected transient ObjectSet keySet; + protected transient VALUE_COLLECTION VALUE_GENERIC_TYPE valuesC; + + public ENUM_MAP(Class keyType) { + this.keyType = keyType; + keys = getKeyUniverse(keyType); + values = NEW_VALUE_ARRAY(keys.length); + present = new long[((keys.length - 1) >> 6) + 1]; + } + + @Override + public VALUE_TYPE put(T key, VALUE_TYPE value) { + int index = key.ordinal(); + if(isSet(index)) { + VALUE_TYPE result = values[index]; + values[index] = value; + return result; + } + set(index); + values[index] = value; + return getDefaultReturnValue(); + } + + @Override + public VALUE_TYPE putIfAbsent(T key, VALUE_TYPE value) { + int index = key.ordinal(); + if(isSet(index)) return values[index]; + set(index); + values[index] = value; + return getDefaultReturnValue(); + } + +#if VALUE_PRIMITIVES + @Override + public VALUE_TYPE addTo(T key, VALUE_TYPE value) { + int index = key.ordinal(); + if(isSet(index)) { + VALUE_TYPE result = values[index]; + values[index] += value; + return result; + } + set(index); + values[index] = value; + return getDefaultReturnValue(); + } + +#endif + @Override + public boolean containsKey(Object key) { + return isSet(((T)key).ordinal()); + } + +#if VALUE_OBJECT + @Override + public boolean containsValue(Object value) { + for(int i = 0;i ENTRY_SET() { + if(entrySet == null) entrySet = new EntrySet(); + return entrySet; + } + + @Override + public ObjectSet 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; + } + + protected void onNodeAdded(int index) { + + } + + protected void onNodeRemoved(int index) { + + } + + protected void set(int index) { + present[index >> 6] |= (1L << index); + onNodeAdded(index); + } + protected void clear(int index) { + present[index >> 6] &= ~(1L << index); + onNodeRemoved(index); + } + protected boolean isSet(int index) { return (present[index >> 6] & (1L << index)) != 0; } + private static > K[] getKeyUniverse(Class keyType) { return SharedSecrets.getJavaLangAccess().getEnumConstantsShared(keyType); } + + class EntrySet extends AbstractObjectSet { + + @Override + public boolean contains(Object o) { + if(o instanceof Map.Entry) return containsKey(((Map.Entry)o).getKey()); + return false; + } + + @Override + 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 ENUM_MAP.this.remove(entry.getKey(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (java.util.Map.Entry)o; + return ENUM_MAP.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + + @Override + public ObjectIterator iterator() { + return new EntryIterator(); + } + + @Override + public int size() { + return ENUM_MAP.this.size(); + } + + @Override + public void clear() { + ENUM_MAP.this.clear(); + } + } + + class KeySet extends AbstractObjectSet { + + @Override + public boolean contains(Object o) { + return containsKey(o); + } + + @Override + public boolean remove(Object o) { + int size = size(); + ENUM_MAP.this.remove(o); + return size != size(); + } + + @Override + public ObjectIterator iterator() { + return new KeyIterator(); + } + + @Override + public int size() { + return ENUM_MAP.this.size(); + } + + @Override + public void clear() { + ENUM_MAP.this.clear(); + } + } + + class Values extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC_TYPE { + + @Override + public boolean add(VALUE_TYPE o) { throw new UnsupportedOperationException(); } + +#if TYPE_OBJECT + @Override + public boolean contains(Object e) { return containsValue(e); } + +#else + @Override + public boolean contains(VALUE_TYPE e) { return containsValue(e); } + +#endif + @Override + public VALUE_ITERATOR VALUE_GENERIC_TYPE iterator() { + return new ValueIterator(); + } + + @Override + public int size() { + return ENUM_MAP.this.size(); + } + + @Override + public void clear() { + ENUM_MAP.this.clear(); + } + } + + class EntryIterator extends MapIterator implements ObjectIterator { + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { + int index = nextEntry(); + return new BasicEntry<>(keys[index], values[index]); + } + } + + class KeyIterator extends MapIterator implements ObjectIterator { + @Override + public T next() { + return keys[nextEntry()]; + } + } + + class ValueIterator extends MapIterator implements VALUE_ITERATOR VALUE_GENERIC_TYPE { + @Override + public VALUE_TYPE VALUE_NEXT() { + return values[nextEntry()]; + } + } + + class MapIterator { + int index; + int lastReturnValue = -1; + int nextIndex = -1; + + public boolean hasNext() { + if(nextIndex == -1 && index < values.length) { + while(index < values.length && !isSet(index++)); + nextIndex = index-1; + if(!isSet(nextIndex)) nextIndex = -1; + } + return nextIndex != -1; + } + + public int nextEntry() { + if(!hasNext()) throw new NoSuchElementException(); + lastReturnValue = nextIndex; + return nextIndex; + } + + public void remove() { + if(lastReturnValue == -1) throw new IllegalStateException(); + clear(lastReturnValue); + values[lastReturnValue] = EMPTY_VALUE; + } + } +} diff --git a/src/main/resources/speiger/assets/collections/templates/maps/impl/tree/AVLTreeMap.template b/src/main/resources/speiger/assets/collections/templates/maps/impl/tree/AVLTreeMap.template new file mode 100644 index 00000000..20c9f48f --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/maps/impl/tree/AVLTreeMap.template @@ -0,0 +1,1688 @@ +package speiger.src.collections.PACKAGE.maps.impl.tree; + +import java.util.Map; +#if TYPE_OBJECT +import java.util.Comparator; +import java.util.Objects; +#endif +import java.util.NoSuchElementException; + +import speiger.src.collections.PACKAGE.collections.BI_ITERATOR; +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.functions.COMPARATOR; +#endif +import speiger.src.collections.PACKAGE.lists.LIST_ITERATOR; +import speiger.src.collections.PACKAGE.maps.abstracts.ABSTRACT_MAP; +import speiger.src.collections.PACKAGE.maps.interfaces.MAP; +import speiger.src.collections.PACKAGE.maps.interfaces.NAVIGABLE_MAP; +import speiger.src.collections.PACKAGE.sets.ABSTRACT_SET; +import speiger.src.collections.PACKAGE.sets.NAVIGABLE_SET; +import speiger.src.collections.PACKAGE.sets.SET; +import speiger.src.collections.PACKAGE.sets.SORTED_SET; +import speiger.src.collections.PACKAGE.utils.ITERATORS; +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.lists.VALUE_LIST_ITERATOR; +import speiger.src.collections.VALUE_PACKAGE.utils.VALUE_ITERATORS; +#endif +#if !TYPE_OBJECT && !VALUE_OBJECT +import speiger.src.collections.objects.lists.ObjectListIterator; +import speiger.src.collections.objects.utils.ObjectIterators; +#endif +#if !VALUE_OBJECT +import speiger.src.collections.objects.collections.ObjectIterator; +#endif +#if !TYPE_OBJECT +import speiger.src.collections.objects.sets.AbstractObjectSet; +import speiger.src.collections.objects.sets.ObjectSet; +#endif + +public class AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE implements NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE +{ + protected transient Entry KEY_VALUE_GENERIC_TYPE tree; + protected transient Entry KEY_VALUE_GENERIC_TYPE first; + protected transient Entry KEY_VALUE_GENERIC_TYPE last; + protected int size = 0; + protected transient COMPARATOR KEY_GENERIC_TYPE comparator; + +#if TYPE_OBJECT + protected KEY_TYPE defaultMaxNotFound = null; + protected KEY_TYPE defaultMinNotFound = null; +#else + protected KEY_TYPE defaultMaxNotFound = CLASS_TYPE.MIN_VALUE; + protected KEY_TYPE defaultMinNotFound = CLASS_TYPE.MAX_VALUE; +#endif + + protected NAVIGABLE_SET KEY_GENERIC_TYPE keySet; + protected VALUE_COLLECTION VALUE_GENERIC_TYPE values; + protected ObjectSet entrySet; +#if TYPE_OBJECT + public KEY_TYPE getDefaultMaxValue() { return defaultMaxNotFound; } + public KEY_TYPE getDefaultMinValue() { return defaultMinNotFound; } + +#else + @Override + public void setDefaultMaxValue(KEY_TYPE value) { defaultMaxNotFound = value; } + @Override + public KEY_TYPE getDefaultMaxValue() { return defaultMaxNotFound; } + @Override + public void setDefaultMinValue(KEY_TYPE value) { defaultMinNotFound = value; } + @Override + public KEY_TYPE getDefaultMinValue() { return defaultMinNotFound; } + +#endif + @Override + public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { + if(tree == null) { + tree = first = last = new EntryKV_BRACES(key, value, null); + size++; + return getDefaultReturnValue(); + } + int compare = 0; + Entry KEY_VALUE_GENERIC_TYPE parent = tree; + while(true) { + if((compare = compare(key, parent.key)) == 0) return parent.setValue(value); + if(compare < 0) { + if(parent.left == null) break; + parent = parent.left; + } + else if(compare > 0) { + if(parent.right == null) break; + parent = parent.right; + } + } + Entry KEY_VALUE_GENERIC_TYPE adding = new EntryKV_BRACES(key, value, parent); + if(compare < 0) { + parent.left = adding; + if(parent == first) first = adding; + } + else { + parent.right = adding; + if(parent == last) last = adding; + } + fixAfterInsertion(adding); + size++; + return getDefaultReturnValue(); + } + + @Override + public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { + if(tree == null) { + tree = first = last = new EntryKV_BRACES(key, value, null); + size++; + return getDefaultReturnValue(); + } + int compare = 0; + Entry KEY_VALUE_GENERIC_TYPE parent = tree; + while(true) { + if((compare = compare(key, parent.key)) == 0) return parent.value; + if(compare < 0) { + if(parent.left == null) break; + parent = parent.left; + } + else if(compare > 0) { + if(parent.right == null) break; + parent = parent.right; + } + } + Entry KEY_VALUE_GENERIC_TYPE adding = new EntryKV_BRACES(key, value, parent); + if(compare < 0) { + parent.left = adding; + if(parent == first) first = adding; + } + else { + parent.right = adding; + if(parent == last) last = adding; + } + fixAfterInsertion(adding); + size++; + return getDefaultReturnValue(); + } + +#if VALUE_PRIMITIVES + @Override + public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { + if(tree == null) { + tree = first = last = new EntryKV_BRACES(key, value, null); + size++; + return getDefaultReturnValue(); + } + int compare = 0; + Entry KEY_VALUE_GENERIC_TYPE parent = tree; + while(true) { + if((compare = compare(key, parent.key)) == 0) return parent.addTo(value); + if(compare < 0) { + if(parent.left == null) break; + parent = parent.left; + } + else if(compare > 0) { + if(parent.right == null) break; + parent = parent.right; + } + } + Entry KEY_VALUE_GENERIC_TYPE adding = new EntryKV_BRACES(key, value, parent); + if(compare < 0) { + parent.left = adding; + if(parent == first) first = adding; + } + else { + parent.right = adding; + if(parent == last) last = adding; + } + fixAfterInsertion(adding); + size++; + return getDefaultReturnValue(); + } + +#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(); } + + @Override + public COMPARATOR KEY_GENERIC_TYPE comparator() { return comparator; } + +#if TYPE_OBJECT + @Override + public boolean containsKey(Object key) { + return findNode((KEY_TYPE)key) != null; + } + +#else + @Override + public boolean containsKey(KEY_TYPE key) { + return findNode(key) != null; + } + +#endif + + @Override + public VALUE_TYPE GET_VALUE(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = findNode(key); + return node == null ? getDefaultReturnValue() : node.value; + } + +#if TYPE_OBJECT + @Override + public VALUE_TYPE getOrDefault(Object key, VALUE_TYPE defaultValue) { + Entry KEY_VALUE_GENERIC_TYPE node = findNode((CLASS_TYPE)key); + return node == null ? defaultValue : node.value; + } + +#else + @Override + public VALUE_TYPE getOrDefault(KEY_TYPE key, VALUE_TYPE defaultValue) { + Entry KEY_VALUE_GENERIC_TYPE node = findNode(key); + return node == null ? defaultValue : node.value; + } + +#endif + @Override + public KEY_TYPE FIRST_ENTRY_KEY() { + if(tree == null) throw new NoSuchElementException(); + return first.key; + } + + @Override + public KEY_TYPE POLL_FIRST_ENTRY_KEY() { + if(tree == null) throw new NoSuchElementException(); + KEY_TYPE result = first.key; + removeNode(first); + return result; + } + + @Override + public KEY_TYPE LAST_ENTRY_KEY() { + if(tree == null) throw new NoSuchElementException(); + return last.key; + } + + @Override + public KEY_TYPE POLL_LAST_ENTRY_KEY() { + if(tree == null) throw new NoSuchElementException(); + KEY_TYPE result = last.key; + removeNode(last); + return result; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE firstEntry() { + if(tree == null) throw new NoSuchElementException(); + return new BasicEntryKV_BRACES(first.key, first.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE lastEntry() { + if(tree == null) throw new NoSuchElementException(); + return new BasicEntryKV_BRACES(last.key, last.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollFirstEntry() { + if(tree == null) throw new NoSuchElementException(); + BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES(first.key, first.value); + removeNode(first); + return entry; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollLastEntry() { + if(tree == null) throw new NoSuchElementException(); + BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES(last.key, last.value); + removeNode(last); + return entry; + } + + @Override + public VALUE_TYPE FIRST_ENTRY_VALUE() { + if(tree == null) throw new NoSuchElementException(); + return first.value; + } + + @Override + public VALUE_TYPE LAST_ENTRY_VALUE() { + if(tree == null) throw new NoSuchElementException(); + return last.value; + } + + @Override + public VALUE_TYPE REMOVE_KEY(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); + if(entry == null) return getDefaultReturnValue(); + VALUE_TYPE value = entry.value; + removeNode(entry); + return value; + } + +#if TYPE_OBJECT && VALUE_OBJECT + @Override + public boolean remove(Object key, Object value) { + Entry KEY_VALUE_GENERIC_TYPE entry = findNode((CLASS_TYPE)key); + if(entry == null || !Objects.equals(value, entry.value)) return false; + removeNode(entry); + return true; + } + +#else + @Override + public boolean remove(KEY_TYPE key, VALUE_TYPE value) { + Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); + if(entry == null || entry.value != value) return false; + removeNode(entry); + return true; + } + +#endif + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(boolean descending) { + LIST_ITERATOR KEY_GENERIC_TYPE iter = new KeyIterator(descending); + return descending ? ITERATORS.invert(iter) : iter; + } + + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(KEY_TYPE key) { + return new KeyIterator(findNode(key)); + } + + @Override + public SORTED_SET KEY_GENERIC_TYPE keySet() { + return navigableKeySet(); + } + + @Override + public ObjectSet ENTRY_SET() { + if(entrySet == null) entrySet = new EntrySet(); + return entrySet; + } + + @Override + public VALUE_COLLECTION VALUE_GENERIC_TYPE values() { + if(values == null) values = new Values(); + return values; + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE navigableKeySet() { + if(keySet == null) keySet = new KeySetKV_BRACES(this); + return keySet; + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap() { + return new DescendingSubMapKV_BRACES(this, true, EMPTY_KEY_VALUE, true, true, EMPTY_KEY_VALUE, true); + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, boolean fromInclusive, KEY_TYPE toKey, boolean toInclusive) { + return new AscendingSubMapKV_BRACES(this, false, fromKey, fromInclusive, false, toKey, toInclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey, boolean inclusive) { + return new AscendingSubMapKV_BRACES(this, true, EMPTY_KEY_VALUE, true, false, toKey, inclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey, boolean inclusive) { + return new AscendingSubMapKV_BRACES(this, false, fromKey, inclusive, true, EMPTY_KEY_VALUE, true); + } + + @Override + public KEY_TYPE lowerKey(KEY_TYPE e) { + Entry KEY_VALUE_GENERIC_TYPE node = findLowerNode(e); + return node != null ? node.key : defaultMinNotFound; + } + + @Override + public KEY_TYPE floorKey(KEY_TYPE e) { + Entry KEY_VALUE_GENERIC_TYPE node = findFloorNode(e); + return node != null ? node.key : defaultMinNotFound; + } + + @Override + public KEY_TYPE higherKey(KEY_TYPE e) { + Entry KEY_VALUE_GENERIC_TYPE node = findHigherNode(e); + return node != null ? node.key : defaultMaxNotFound; + } + + @Override + public KEY_TYPE ceilingKey(KEY_TYPE e) { + Entry KEY_VALUE_GENERIC_TYPE node = findCeilingNode(e); + return node != null ? node.key : defaultMaxNotFound; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE lowerEntry(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = findLowerNode(key); + return node != null ? new BasicEntryKV_BRACES(node.key, node.value) : null; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE higherEntry(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = findHigherNode(key); + return node != null ? new BasicEntryKV_BRACES(node.key, node.value) : null; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE floorEntry(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = findFloorNode(key); + return node != null ? new BasicEntryKV_BRACES(node.key, node.value) : null; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE ceilingEntry(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = findCeilingNode(key); + return node != null ? new BasicEntryKV_BRACES(node.key, node.value) : null; + } + + protected Entry KEY_VALUE_GENERIC_TYPE findLowerNode(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE entry = tree; + while(entry != null) { + if(compare(key, entry.key) > 0) { + if(entry.right != null) entry = entry.right; + else return entry; + } + else { + if(entry.left != null) entry = entry.left; + else { + Entry KEY_VALUE_GENERIC_TYPE parent = entry.parent; + while(parent != null && parent.left == entry) { + entry = parent; + parent = parent.parent; + } + return parent; + } + } + } + return null; + } + + protected Entry KEY_VALUE_GENERIC_TYPE findFloorNode(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE entry = tree; + int compare; + while(entry != null) { + if((compare = compare(key, entry.key)) > 0) { + if(entry.right == null) break; + entry = entry.right; + continue; + } + else if(compare < 0) { + if(entry.left != null) entry = entry.left; + else { + Entry KEY_VALUE_GENERIC_TYPE parent = entry.parent; + while(parent != null && parent.left == entry) { + entry = parent; + parent = parent.parent; + } + return parent; + } + continue; + } + break; + } + return entry; + } + + protected Entry KEY_VALUE_GENERIC_TYPE findCeilingNode(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE entry = tree; + int compare; + while(entry != null) { + if((compare = compare(key, entry.key)) < 0) { + if(entry.left == null) break; + entry = entry.left; + continue; + } + else if(compare > 0) { + if(entry.right != null) entry = entry.right; + else { + Entry KEY_VALUE_GENERIC_TYPE parent = entry.parent; + while(parent != null && parent.right == entry) { + entry = parent; + parent = parent.parent; + } + return parent; + } + continue; + } + break; + } + return entry; + } + + protected Entry KEY_VALUE_GENERIC_TYPE findHigherNode(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE entry = tree; + while(entry != null) { + if(compare(key, entry.key) < 0) { + if(entry.left != null) entry = entry.left; + else return entry; + } + else { + if(entry.right != null) entry = entry.right; + else { + Entry KEY_VALUE_GENERIC_TYPE parent = entry.parent; + while(parent != null && parent.right == entry) { + entry = parent; + parent = parent.parent; + } + return parent; + } + } + } + return null; + } + + protected Entry KEY_VALUE_GENERIC_TYPE findNode(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = tree; + int compare; + while(node != null) { + if((compare = compare(key, node.key)) == 0) return node; + if(compare < 0) node = node.left; + else node = node.right; + } + return null; + } + + protected void removeNode(Entry KEY_VALUE_GENERIC_TYPE entry) { + size--; + if(entry.needsSuccessor()) { + Entry KEY_VALUE_GENERIC_TYPE successor = entry.next(); + entry.key = successor.key; + entry.value = successor.value; + entry = successor; + } + Entry KEY_VALUE_GENERIC_TYPE replacement = entry.left != null ? entry.left : entry.right; + if(replacement != null) { + if(entry.replace(replacement)) tree = replacement; + if(entry == first) first = replacement; + if(entry == last) last = entry.right != null ? entry.right : replacement; + entry.left = entry.right = entry.parent = null; + fixAfterDeletion(replacement); + } + else if(entry.parent == null) tree = first = last = null; + else { + fixAfterDeletion(entry); + entry.replace(null); + if(entry.parent != null) { + Entry KEY_VALUE_GENERIC_TYPE parent = entry.parent; + if(entry == first) first = parent.left != null ? parent.left : parent; + if(entry == last) last = entry.right != null ? parent.right : parent; + } + entry.parent = null; + } + } + + protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);} + + /** From CLR */ + protected void rotateLeft(Entry KEY_VALUE_GENERIC_TYPE entry) { + if(entry != null) { + Entry KEY_VALUE_GENERIC_TYPE right = entry.right; + entry.right = right.left; + if(right.left != null) right.left.parent = entry; + right.parent = entry.parent; + if(entry.parent == null) tree = right; + else if(entry.parent.left == entry) entry.parent.left = right; + else entry.parent.right = right; + right.left = entry; + entry.parent = right; + } + } + + /** From CLR */ + protected void rotateRight(Entry KEY_VALUE_GENERIC_TYPE entry) { + if(entry != null) { + Entry KEY_VALUE_GENERIC_TYPE left = entry.left; + entry.left = left.right; + if(left.right != null) left.right.parent = entry; + left.parent = entry.parent; + if(entry.parent == null) tree = left; + else if(entry.parent.right == entry) entry.parent.right = left; + else entry.parent.left = left; + left.right = entry; + entry.parent = left; + } + } + + /** From CLR */ + protected void fixAfterInsertion(Entry KEY_VALUE_GENERIC_TYPE entry) { + while(entry != null) { + entry.updateHeight(); + int balance = entry.getBalance(); + if(balance > 1) { + int compare = entry.left.getBalance(); + if(compare > 0) rotateRight(entry); + else if(compare < 0) { + rotateLeft(entry.left); + rotateRight(entry); + } + } + else if(balance < -1) { + int compare = entry.right.getBalance(); + if(compare < 0) rotateLeft(entry); + else if(compare > 0) { + rotateRight(entry.right); + rotateLeft(entry); + } + } + entry = entry.parent; + } + } + + /** From CLR */ + protected void fixAfterDeletion(Entry KEY_VALUE_GENERIC_TYPE entry) { + if(entry != null) { + entry.updateHeight(); + int balance = entry.getBalance(); + if(balance > 1) { + int subBalance = entry.left.getBalance(); + if(subBalance >= 0) rotateRight(entry); + else { + rotateLeft(entry.left); + rotateRight(entry); + } + } + else if(balance < -1) + { + int subBalance = entry.right.getBalance(); + if(subBalance <= 0) rotateLeft(entry); + else { + rotateRight(entry.right); + rotateLeft(entry); + } + } + entry = entry.parent; + } + } + + static final class AscendingSubMap KEY_VALUE_GENERIC_TYPE extends NavigableSubMap KEY_VALUE_GENERIC_TYPE { + + public AscendingSubMap(AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE m, boolean fromStart, KEY_TYPE low, boolean loInclusive, boolean toEnd, KEY_TYPE high, boolean hiInclusive) { + super(m, fromStart, low, loInclusive, toEnd, high, hiInclusive); + } + + @Override + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(boolean descending) { return new SubMapKeyIterator(descending); } + @Override + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(KEY_TYPE key) { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findNode(key); + return entry == null || !inClosedRange(key) ? null : new SubMapKeyIterator(entry, fromStart ? null : findLowest(), toEnd ? null : findHighest()); + } + @Override + VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE valueIterator() { return new SubMapValueIterator(false); } + @Override + ObjectListIterator entryIterator() { return new SubMapEntrySetIterator(false); } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap() { + if(descendingMap == null) descendingMap = new DescendingSubMapKV_BRACES(m, fromStart, low, loInclusive, toEnd, high, hiInclusive); + return descendingMap; + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, boolean fromInclusive, KEY_TYPE toKey, boolean toInclusive) { + if (!inRange(fromKey, fromInclusive)) throw new IllegalArgumentException("fromKey out of range"); + if (!inRange(toKey, toInclusive)) throw new IllegalArgumentException("toKey out of range"); + return new AscendingSubMapKV_BRACES(m, false, fromKey, fromInclusive, false, toKey, toInclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey, boolean inclusive) { + if (!inRange(toKey, inclusive)) throw new IllegalArgumentException("toKey out of range"); + return new AscendingSubMapKV_BRACES(m, fromStart, low, loInclusive, false, toKey, inclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey, boolean inclusive) { + if (!inRange(fromKey, inclusive)) throw new IllegalArgumentException("fromKey out of range"); + return new AscendingSubMapKV_BRACES(m, false, fromKey, inclusive, toEnd, high, hiInclusive); + } + } + + static final class DescendingSubMap KEY_VALUE_GENERIC_TYPE extends NavigableSubMap KEY_VALUE_GENERIC_TYPE { + + public DescendingSubMap(AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE m, boolean fromStart, KEY_TYPE low, boolean loInclusive, boolean toEnd, KEY_TYPE high, boolean hiInclusive) { + super(m, fromStart, low, loInclusive, toEnd, high, hiInclusive); + } + + @Override + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(boolean descending) { + LIST_ITERATOR KEY_GENERIC_TYPE iter = new SubMapKeyIterator(!descending); + return descending ? iter : ITERATORS.invert(iter); + } + + @Override + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(KEY_TYPE key) { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findNode(key); + return entry == null || !inClosedRange(key) ? null : ITERATORS.invert(new SubMapKeyIterator(entry, fromStart ? null : findLowest(), toEnd ? null : findHighest())); + } + + @Override + public COMPARATOR KEY_GENERIC_TYPE comparator() { return m.comparator().reversed(); } + + @Override + VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE valueIterator() { return VALUE_ITERATORS.invert(new SubMapValueIterator(true)); } + + @Override + ObjectListIterator entryIterator() { return ObjectIterators.invert(new SubMapEntrySetIterator(true)); } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap() { + if(descendingMap == null) descendingMap = new AscendingSubMapKV_BRACES(m, fromStart, low, loInclusive, toEnd, high, hiInclusive); + return descendingMap; + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, boolean fromInclusive, KEY_TYPE toKey, boolean toInclusive) { + if (!inRange(fromKey, fromInclusive)) throw new IllegalArgumentException("fromKey out of range"); + if (!inRange(toKey, toInclusive)) throw new IllegalArgumentException("toKey out of range"); + return new DescendingSubMapKV_BRACES(m, false, fromKey, fromInclusive, false, toKey, toInclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey, boolean inclusive) { + if (!inRange(toKey, inclusive)) throw new IllegalArgumentException("toKey out of range"); + return new DescendingSubMapKV_BRACES(m, fromStart, low, loInclusive, false, toKey, inclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey, boolean inclusive) { + if (!inRange(fromKey, inclusive)) throw new IllegalArgumentException("fromKey out of range"); + return new DescendingSubMapKV_BRACES(m, false, fromKey, inclusive, toEnd, high, hiInclusive); + } + } + + static abstract class NavigableSubMap KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE implements NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE { + final AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE m; + final KEY_TYPE low; + final KEY_TYPE high; + final boolean fromStart; + final boolean toEnd; + final boolean loInclusive; + final boolean hiInclusive; + transient NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap; + transient SubMapEntrySet entrySet; + transient KeySet KEY_VALUE_GENERIC_TYPE keySet; + transient SubMapValues values; + + NavigableSubMap(AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE m, boolean fromStart, KEY_TYPE low, boolean loInclusive, boolean toEnd, KEY_TYPE high, boolean hiInclusive) { + this.m = m; + this.low = low; + this.high = high; + this.fromStart = fromStart; + this.toEnd = toEnd; + this.loInclusive = loInclusive; + this.hiInclusive = hiInclusive; + } + + abstract LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(boolean descending); + abstract LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(KEY_TYPE key); + abstract VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE valueIterator(); + abstract ObjectListIterator entryIterator(); + + @Override + public abstract NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap(); + @Override + public abstract NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, boolean fromInclusive, KEY_TYPE toKey, boolean toInclusive); + @Override + public abstract NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey, boolean inclusive); + @Override + public abstract NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey, boolean inclusive); + + boolean tooLow(KEY_TYPE key) { return !fromStart && (loInclusive ? m.compare(key, low) < 0 : m.compare(key, low) <= 0); } + boolean tooHigh(KEY_TYPE key) { return !toEnd && (hiInclusive ? m.compare(key, high) > 0 : m.compare(key, high) >= 0); } + boolean inRange(KEY_TYPE key) { return !tooLow(key) && !tooHigh(key); } + boolean inClosedRange(KEY_TYPE key) { return (fromStart || m.compare(key, low) >= 0) && (toEnd || m.compare(high, key) >= 0); } + boolean inRange(KEY_TYPE key, boolean inclusive) { return inclusive ? inRange(key) : inClosedRange(key); } + +#if TYPE_OBJECT + public KEY_TYPE getDefaultMaxValue() { return m.getDefaultMaxValue(); } + public KEY_TYPE getDefaultMinValue() { return m.getDefaultMinValue(); } +#else + @Override + public void setDefaultMaxValue(KEY_TYPE e) { m.setDefaultMaxValue(e); } + @Override + public KEY_TYPE getDefaultMaxValue() { return m.getDefaultMaxValue(); } + @Override + public void setDefaultMinValue(KEY_TYPE e) { m.setDefaultMinValue(e); } + @Override + public KEY_TYPE getDefaultMinValue() { return m.getDefaultMinValue(); } + +#endif + @Override + public ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE setDefaultReturnValue(VALUE_TYPE v) { + m.setDefaultReturnValue(v); + return this; + } + + @Override + public VALUE_TYPE getDefaultReturnValue() { return m.getDefaultReturnValue(); } + + @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(); } + @Override + public COMPARATOR KEY_GENERIC_TYPE comparator() { return m.comparator(); } +#if TYPE_OBJECT + @Override + public boolean containsKey(Object key) { return inRange((CLASS_TYPE)key) && m.containsKey(key); } +#else + @Override + public boolean containsKey(KEY_TYPE key) { return inRange(key) && m.containsKey(key); } + +#endif + @Override + public KEY_TYPE FIRST_ENTRY_KEY() { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? getDefaultMaxValue() : entry.key; + } + + @Override + public KEY_TYPE POLL_FIRST_ENTRY_KEY() { + if(fromStart) return m.POLL_FIRST_ENTRY_KEY(); + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = loInclusive ? m.findCeilingNode(low) : m.findHigherNode(low); + if(entry != null && !tooHigh(entry.key)) { + KEY_TYPE value = entry.key; + m.removeNode(entry); + return value; + } + return getDefaultMaxValue(); + } + + @Override + public KEY_TYPE LAST_ENTRY_KEY() { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? getDefaultMinValue() : entry.key; + } + + @Override + public KEY_TYPE POLL_LAST_ENTRY_KEY() { + if(toEnd) return m.POLL_LAST_ENTRY_KEY(); + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = hiInclusive ? m.findFloorNode(high) : m.findLowerNode(high); + if(entry != null && !tooLow(entry.key)) { + KEY_TYPE value = entry.key; + m.removeNode(entry); + return value; + } + return getDefaultMinValue(); + } + + @Override + public VALUE_TYPE FIRST_ENTRY_VALUE() { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? getDefaultReturnValue() : entry.value; + } + + @Override + public VALUE_TYPE LAST_ENTRY_VALUE() { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? getDefaultReturnValue() : entry.value; + } + + protected AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE findLowest() { + if(fromStart) return m.first; + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = loInclusive ? m.findCeilingNode(low) : m.findHigherNode(low); + return entry == null || tooHigh(entry.key) ? null : entry; + } + + protected AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE findHighest() { + if(toEnd) return m.last; + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = hiInclusive ? m.findFloorNode(high) : m.findLowerNode(high); + return entry == null || tooLow(entry.key) ? null : entry; + } + + @Override + public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { + if(!inRange(key)) throw new IllegalArgumentException("key out of range"); + return m.put(key, value); + } + + @Override + public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { + if(!inRange(key)) throw new IllegalArgumentException("key out of range"); + return m.putIfAbsent(key, value); + } + +#if VALUE_PRIMITIVES + @Override + public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { + if(!inRange(key)) throw new IllegalArgumentException("key out of range"); + return m.addTo(key, value); + } + +#endif + @Override + public VALUE_TYPE GET_VALUE(KEY_TYPE key) { + return inRange(key) ? m.GET_VALUE(key) : getDefaultReturnValue(); + } + + @Override + public VALUE_TYPE REMOVE_KEY(KEY_TYPE key) { + return inRange(key) ? m.remove(key) : getDefaultReturnValue(); + } + +#if TYPE_OBJECT && VALUE_OBJECT + @Override + public boolean remove(Object key, Object value) { + return inRange((CLASS_TYPE)key) && m.remove(key, value); + } + +#else + @Override + public boolean remove(KEY_TYPE key, VALUE_TYPE value) { + return inRange(key) && m.remove(key, value); + } + +#endif + @Override + public ObjectSet ENTRY_SET() { + if(entrySet == null) entrySet = new SubMapEntrySet(); + return entrySet; + } + + @Override + public SET KEY_GENERIC_TYPE keySet() { return navigableKeySet(); } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE navigableKeySet() { + if(keySet == null) keySet = new KeySetKV_BRACES(this); + return keySet; + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + @Override + public VALUE_COLLECTION VALUE_GENERIC_TYPE values() { + if(values == null) values = new SubMapValues(); + return values; + } + + @Override + public int size() { + return (fromStart && toEnd) ? m.size() : entrySet().size(); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE firstEntry() { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE lastEntry() { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollFirstEntry() { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + if(entry == null) return null; + BasicEntry KEY_VALUE_GENERIC_TYPE result = new BasicEntryKV_BRACES(entry.key, entry.value); + m.removeNode(entry); + return result; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollLastEntry() { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + if(entry == null) return null; + BasicEntry KEY_VALUE_GENERIC_TYPE result = new BasicEntryKV_BRACES(entry.key, entry.value); + m.removeNode(entry); + return result; + } + + @Override + public KEY_TYPE lowerKey(KEY_TYPE e) { + if(tooHigh(e)) { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? getDefaultMinValue() : entry.key; + } + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findLowerNode(e); + return entry == null || tooHigh(entry.key) ? getDefaultMaxValue() : entry.key; + } + + @Override + public KEY_TYPE floorKey(KEY_TYPE e) { + if(tooHigh(e)) { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? getDefaultMinValue() : entry.key; + } + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findFloorNode(e); + return entry == null || tooHigh(entry.key) ? getDefaultMaxValue() : entry.key; + } + + @Override + public KEY_TYPE ceilingKey(KEY_TYPE e) { + if(tooLow(e)) { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? getDefaultMaxValue() : entry.key; + } + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findCeilingNode(e); + return entry == null || tooLow(entry.key) ? getDefaultMinValue() : entry.key; + } + + @Override + public KEY_TYPE higherKey(KEY_TYPE e) { + if(tooLow(e)) { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? getDefaultMaxValue() : entry.key; + } + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findHigherNode(e); + return entry == null || tooLow(entry.key) ? getDefaultMinValue() : entry.key; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE lowerEntry(KEY_TYPE e) { + if(tooHigh(e)) { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findLowerNode(e); + return entry == null || tooHigh(entry.key) ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE floorEntry(KEY_TYPE e) { + if(tooHigh(e)) { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findFloorNode(e); + return entry == null || tooHigh(entry.key) ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE ceilingEntry(KEY_TYPE e) { + if(tooLow(e)) { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findCeilingNode(e); + return entry == null || tooLow(entry.key) ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE higherEntry(KEY_TYPE e) { + if(tooLow(e)) { + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findHigherNode(e); + return entry == null || tooLow(entry.key) ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + class SubMapEntrySet extends AbstractObjectSet implements ObjectSet { + @Override + @Deprecated + public boolean contains(Object o) { + if(o instanceof Map.Entry) { + if(o instanceof MAP.Entry) return NavigableSubMap.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); + return NavigableSubMap.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 NavigableSubMap.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (Map.Entry)o; + return NavigableSubMap.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + @Override + public ObjectIterator iterator() { return entryIterator(); } + @Override + public int size() { return NavigableSubMap.this.size(); } + @Override + public void clear() { NavigableSubMap.this.clear(); } + } + + final class SubMapValues extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC_TYPE { + @Override + public boolean add(VALUE_TYPE o) { throw new UnsupportedOperationException(); } + +#if VALUE_OBJECT + @Override + public boolean contains(Object e) { + return containsValue(e); + } + +#else + @Override + public boolean contains(VALUE_TYPE e) { + return containsValue(e); + } + +#endif + @Override + public VALUE_ITERATOR VALUE_GENERIC_TYPE iterator() { return valueIterator(); } + + @Override + public int size() { + return NavigableSubMap.this.size(); + } + + @Override + public void clear() { + NavigableSubMap.this.clear(); + } + } + + final class SubMapEntrySetIterator extends SubMapEntryIterator implements ObjectListIterator { + public SubMapEntrySetIterator(boolean descending) { + super(descending); + } + + public SubMapEntrySetIterator(AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry, AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE lowerFence, AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE upperFence) { + super(entry, lowerFence, upperFence); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { return nextEntry(); } + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE previous() { return previousEntry(); } + + @Override + public void set(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + @Override + public void add(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + } + + final class SubMapKeyIterator extends SubMapEntryIterator implements LIST_ITERATOR KEY_GENERIC_TYPE { + public SubMapKeyIterator(boolean descending) { + super(descending); + } + + public SubMapKeyIterator(AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry, AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE lowerFence, AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE upperFence) { + super(entry, lowerFence, upperFence); + } + + @Override + public KEY_TYPE NEXT() { return nextEntry().key; } + @Override + public KEY_TYPE PREVIOUS() { return previousEntry().key; } + + @Override + public void set(KEY_TYPE e) { throw new UnsupportedOperationException(); } + @Override + public void add(KEY_TYPE e) { throw new UnsupportedOperationException(); } + } + + final class SubMapValueIterator extends SubMapEntryIterator implements VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE { + public SubMapValueIterator(boolean descending) { + super(descending); + } + + public SubMapValueIterator(AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry, AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE lowerFence, AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE upperFence) { + super(entry, lowerFence, upperFence); + } + + @Override + public VALUE_TYPE VALUE_NEXT() { return nextEntry().value; } + @Override + public VALUE_TYPE VALUE_PREVIOUS() { return previousEntry().value; } + + @Override + public void set(VALUE_TYPE e) { throw new UnsupportedOperationException(); } + @Override + public void add(VALUE_TYPE e) { throw new UnsupportedOperationException(); } + } + + abstract class SubMapEntryIterator { + CLASS_TYPE lowerFence; + CLASS_TYPE upperFence; + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE next; + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE previous; + AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE current; + int index = 0; + + public SubMapEntryIterator(boolean descending) { + this(descending ? findHighest() : findLowest(), fromStart ? null : findLowest(), toEnd ? null : findHighest()); + } + + public SubMapEntryIterator(AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry, AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE lowerFence, AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE upperFence) { + next = entry; + previous = entry.previous(); + this.lowerFence = lowerFence != null ? KEY_TO_OBJ(lowerFence.key) : null; + this.upperFence = upperFence != null ? KEY_TO_OBJ(upperFence.key) : null; + } + + public boolean hasNext() { + return next != null && (upperFence == null || KEY_EQUALS(next.key, OBJ_TO_KEY(upperFence))); + } + + public boolean hasPrevious() { + return previous != null && (lowerFence == null || KEY_EQUALS(next.key, OBJ_TO_KEY(lowerFence))); + } + + public int nextIndex() { + return index; + } + + public int previousIndex() { + return index - 1; + } + + protected void updateNext() { + next = current.next(); + } + + protected void updatePrevious() { + previous = current.previous(); + } + + public AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE nextEntry() { + if(!hasNext()) throw new NoSuchElementException(); + current = previous = next; + updateNext(); + index++; + return current; + } + + public AVL_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE previousEntry() { + if(!hasPrevious()) throw new NoSuchElementException(); + current = next = previous; + updatePrevious(); + index--; + return current; + } + + public void remove() { + if(current == null) throw new IllegalStateException(); + if(current == previous) index--; + updateNext(); + updatePrevious(); + if(current.needsSuccessor()) next = current; + m.removeNode(current); + current = null; + } + } + } + + private class EntrySet extends AbstractObjectSet { + + @Override + public ObjectIterator iterator() { + return new EntryIterator(false); + } + + @Override + @Deprecated + public boolean contains(Object o) { + if(o instanceof Map.Entry) { + if(o instanceof MAP.Entry) return AVL_TREE_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); + return AVL_TREE_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 AVL_TREE_MAP.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (Map.Entry)o; + return AVL_TREE_MAP.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + + @Override + public int size() { + return AVL_TREE_MAP.this.size(); + } + + @Override + public void clear() { + AVL_TREE_MAP.this.clear(); + } + } + + static final class KeySet KEY_VALUE_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE implements NAVIGABLE_SET KEY_GENERIC_TYPE { + NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE m; + + KeySet(NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE m) { + this.m = m; + } + +#if !TYPE_OBJECT + @Override + public void setDefaultMaxValue(KEY_TYPE e) { m.setDefaultMaxValue(e); } + @Override + public KEY_TYPE getDefaultMaxValue() { return m.getDefaultMaxValue(); } + @Override + public void setDefaultMinValue(KEY_TYPE e) { m.setDefaultMinValue(e); } + @Override + public KEY_TYPE getDefaultMinValue() { return m.getDefaultMinValue(); } +#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 COMPARATOR KEY_GENERIC_TYPE comparator() { return m.comparator(); } + @Override + public KEY_TYPE lower(KEY_TYPE e) { return m.lowerKey(e); } + @Override + public KEY_TYPE floor(KEY_TYPE e) { return m.floorKey(e); } + @Override + public KEY_TYPE ceiling(KEY_TYPE e) { return m.ceilingKey(e); } + @Override + public KEY_TYPE higher(KEY_TYPE e) { return m.higherKey(e); } + @Override + public KEY_TYPE FIRST_KEY() { return m.FIRST_ENTRY_KEY(); } + @Override + public KEY_TYPE POLL_FIRST_KEY() { return m.POLL_FIRST_ENTRY_KEY(); } + @Override + public KEY_TYPE LAST_KEY() { return m.LAST_ENTRY_KEY(); } + @Override + public KEY_TYPE POLL_LAST_KEY() { return m.POLL_LAST_ENTRY_KEY(); } +#if TYPE_OBJECT + @Override + public boolean remove(Object o) { + int oldSize = m.size(); + m.remove(o); + return oldSize != m.size(); + } + +#else + @Override + public boolean remove(KEY_TYPE o) { + int oldSize = m.size(); + m.remove(o); + return oldSize != m.size(); + } + +#endif + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, boolean fromInclusive, KEY_TYPE toElement, boolean toInclusive) { + return new KeySetKV_BRACES(m.subMap(fromElement, fromInclusive, toElement, toInclusive)); + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement, boolean inclusive) { + return new KeySetKV_BRACES(m.headMap(toElement, inclusive)); + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement, boolean inclusive) { + return new KeySetKV_BRACES(m.tailMap(fromElement, inclusive)); + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE descendingSet() { + return new KeySetKV_BRACES(m.descendingMap()); + } + + @Override + public BI_ITERATOR KEY_GENERIC_TYPE iterator() { + if(m instanceof AVL_TREE_MAP) return ((AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE)m).keyIterator(false); + return ((NavigableSubMap KEY_VALUE_GENERIC_TYPE)m).keyIterator(false); + } + + @Override + public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) { + if(m instanceof AVL_TREE_MAP) return ((AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE)m).keyIterator(fromElement); + return ((NavigableSubMap KEY_VALUE_GENERIC_TYPE)m).keyIterator(fromElement); + } + + @Override + public BI_ITERATOR KEY_GENERIC_TYPE descendingIterator() { + if(m instanceof AVL_TREE_MAP) return ((AVL_TREE_MAP KEY_VALUE_GENERIC_TYPE)m).keyIterator(true); + return ((NavigableSubMap KEY_VALUE_GENERIC_TYPE)m).keyIterator(true); + } + + @Override + public int size() { + return m.size(); + } + + @Override + public void clear() { + m.clear(); + } + } + + final class Values extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC_TYPE { + + @Override + public boolean add(VALUE_TYPE o) { throw new UnsupportedOperationException(); } + +#if VALUE_OBJECT + @Override + public boolean contains(Object e) { + return containsValue(e); + } + +#else + @Override + public boolean contains(VALUE_TYPE e) { + return containsValue(e); + } + +#endif + @Override + public VALUE_ITERATOR VALUE_GENERIC_TYPE iterator() { return new ValueIterator(false); } + + @Override + public int size() { + return AVL_TREE_MAP.this.size(); + } + + @Override + public void clear() { + AVL_TREE_MAP.this.clear(); + } + } + + final class EntryIterator extends MapEntryIterator implements ObjectListIterator { + + public EntryIterator(boolean descending) { + super(descending); + } + + public EntryIterator(Entry KEY_VALUE_GENERIC_TYPE entry) { + super(entry); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { + return nextEntry(); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE previous() { + return previousEntry(); + } + + @Override + public void set(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + + @Override + public void add(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + } + + final class KeyIterator extends MapEntryIterator implements LIST_ITERATOR KEY_GENERIC_TYPE { + + public KeyIterator(boolean descending) { + super(descending); + } + + public KeyIterator(Entry KEY_VALUE_GENERIC_TYPE entry) { + super(entry); + } + + @Override + public KEY_TYPE PREVIOUS() { return previousEntry().key; } + @Override + public KEY_TYPE NEXT() { return nextEntry().key; } + + @Override + public void set(KEY_TYPE e) { throw new UnsupportedOperationException(); } + @Override + public void add(KEY_TYPE e) { throw new UnsupportedOperationException(); } + } + + final class ValueIterator extends MapEntryIterator implements VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE { + + public ValueIterator(boolean descending) { + super(descending); + } + + public ValueIterator(Entry KEY_VALUE_GENERIC_TYPE entry) { + super(entry); + } + + @Override + public VALUE_TYPE VALUE_PREVIOUS() { + return previousEntry().value; + } + + @Override + public VALUE_TYPE VALUE_NEXT() { + return nextEntry().value; + } + + @Override + public void set(VALUE_TYPE e) { throw new UnsupportedOperationException(); } + + @Override + public void add(VALUE_TYPE e) { throw new UnsupportedOperationException(); } + } + + abstract class MapEntryIterator { + Entry KEY_VALUE_GENERIC_TYPE next; + Entry KEY_VALUE_GENERIC_TYPE previous; + Entry KEY_VALUE_GENERIC_TYPE current; + int index = 0; + + public MapEntryIterator(boolean descending) { + if(descending) previous = last; + else next = first; + } + + public MapEntryIterator(Entry KEY_VALUE_GENERIC_TYPE entry) { + next = entry; + previous = entry.previous(); + } + + public boolean hasNext() { + return next != null; + } + + public boolean hasPrevious() { + return previous != null; + } + + public int nextIndex() { + return index; + } + + public int previousIndex() { + return index - 1; + } + + protected void updateNext() { + next = current.next(); + } + + protected void updatePrevious() { + previous = current.previous(); + } + + public Entry KEY_VALUE_GENERIC_TYPE nextEntry() { + if(!hasNext()) throw new NoSuchElementException(); + current = previous = next; + updateNext(); + index++; + return current; + } + + public Entry KEY_VALUE_GENERIC_TYPE previousEntry() { + if(!hasPrevious()) throw new NoSuchElementException(); + current = next = previous; + updatePrevious(); + index--; + return current; + } + + public void remove() { + if(current == null) throw new IllegalStateException(); + if(current == previous) index--; + updateNext(); + updatePrevious(); + if(current.needsSuccessor()) next = current; + removeNode(current); + current = null; + } + } + + private static final class Entry KEY_VALUE_GENERIC_TYPE implements MAP.Entry KEY_VALUE_GENERIC_TYPE + { + KEY_TYPE key; + VALUE_TYPE value; + int state; + Entry KEY_VALUE_GENERIC_TYPE parent; + Entry KEY_VALUE_GENERIC_TYPE left; + Entry KEY_VALUE_GENERIC_TYPE right; + + Entry(KEY_TYPE key, VALUE_TYPE value, Entry KEY_VALUE_GENERIC_TYPE parent) { + this.key = key; + this.value = value; + this.parent = parent; + } + + @Override + public KEY_TYPE ENTRY_KEY() { + return key; + } + + @Override + public VALUE_TYPE ENTRY_VALUE() { + return value; + } + + @Override + public VALUE_TYPE setValue(VALUE_TYPE value) { + VALUE_TYPE oldValue = this.value; + this.value = value; + return oldValue; + } + +#if VALUE_PRIMITIVES + VALUE_TYPE addTo(VALUE_TYPE value) { + VALUE_TYPE oldValue = this.value; + this.value += value; + return oldValue; + } + +#endif + int getHeight() { return state; } + + void updateHeight() { state = (1 + Math.max(left == null ? 0 : left.getHeight(), right == null ? 0 : right.getHeight())); } + + int getBalance() { return (left == null ? 0 : left.getHeight()) - (right == null ? 0 : right.getBalance()); } + + boolean needsSuccessor() { return left != null && right != null; } + + boolean replace(Entry KEY_VALUE_GENERIC_TYPE entry) { + if(entry != null) entry.parent = parent; + if(parent != null) { + if(parent.left == this) parent.left = entry; + else parent.right = entry; + } + return parent == null; + } + + Entry KEY_VALUE_GENERIC_TYPE next() { + if(right != null) { + Entry KEY_VALUE_GENERIC_TYPE parent = right; + while(parent.left != null) parent = parent.left; + return parent; + } + Entry KEY_VALUE_GENERIC_TYPE parent = this.parent; + Entry KEY_VALUE_GENERIC_TYPE control = this; + while(parent != null && control == parent.right) { + control = parent; + parent = parent.parent; + } + return parent; + } + + Entry KEY_VALUE_GENERIC_TYPE previous() { + if(left != null) { + Entry KEY_VALUE_GENERIC_TYPE parent = left; + while(parent.right != null) parent = parent.right; + return parent; + } + Entry KEY_VALUE_GENERIC_TYPE parent = this.parent; + Entry KEY_VALUE_GENERIC_TYPE control = this; + while(parent != null && control == parent.left) { + control = parent; + parent = parent.parent; + } + return parent; + } + } +} \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/maps/impl/tree/RBTreeMap.template b/src/main/resources/speiger/assets/collections/templates/maps/impl/tree/RBTreeMap.template new file mode 100644 index 00000000..4117087a --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/maps/impl/tree/RBTreeMap.template @@ -0,0 +1,1750 @@ +package speiger.src.collections.PACKAGE.maps.impl.tree; + +import java.util.Map; +#if TYPE_OBJECT +import java.util.Comparator; +import java.util.Objects; +#endif +import java.util.NoSuchElementException; + +import speiger.src.collections.PACKAGE.collections.BI_ITERATOR; +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.functions.COMPARATOR; +#endif +import speiger.src.collections.PACKAGE.lists.LIST_ITERATOR; +import speiger.src.collections.PACKAGE.maps.abstracts.ABSTRACT_MAP; +import speiger.src.collections.PACKAGE.maps.interfaces.MAP; +import speiger.src.collections.PACKAGE.maps.interfaces.NAVIGABLE_MAP; +import speiger.src.collections.PACKAGE.sets.ABSTRACT_SET; +import speiger.src.collections.PACKAGE.sets.NAVIGABLE_SET; +import speiger.src.collections.PACKAGE.sets.SET; +import speiger.src.collections.PACKAGE.sets.SORTED_SET; +import speiger.src.collections.PACKAGE.utils.ITERATORS; +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.lists.VALUE_LIST_ITERATOR; +import speiger.src.collections.VALUE_PACKAGE.utils.VALUE_ITERATORS; +#endif +#if !TYPE_OBJECT && !VALUE_OBJECT +import speiger.src.collections.objects.lists.ObjectListIterator; +import speiger.src.collections.objects.utils.ObjectIterators; +#endif +#if !VALUE_OBJECT +import speiger.src.collections.objects.collections.ObjectIterator; +#endif +#if !TYPE_OBJECT +import speiger.src.collections.objects.sets.AbstractObjectSet; +import speiger.src.collections.objects.sets.ObjectSet; +#endif + +public class RB_TREE_MAP KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE implements NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE +{ + protected transient Entry KEY_VALUE_GENERIC_TYPE tree; + protected transient Entry KEY_VALUE_GENERIC_TYPE first; + protected transient Entry KEY_VALUE_GENERIC_TYPE last; + protected int size = 0; + protected transient COMPARATOR KEY_GENERIC_TYPE comparator; + +#if TYPE_OBJECT + protected KEY_TYPE defaultMaxNotFound = null; + protected KEY_TYPE defaultMinNotFound = null; +#else + protected KEY_TYPE defaultMaxNotFound = CLASS_TYPE.MIN_VALUE; + protected KEY_TYPE defaultMinNotFound = CLASS_TYPE.MAX_VALUE; +#endif + + protected NAVIGABLE_SET KEY_GENERIC_TYPE keySet; + protected VALUE_COLLECTION VALUE_GENERIC_TYPE values; + protected ObjectSet entrySet; +#if TYPE_OBJECT + public KEY_TYPE getDefaultMaxValue() { return defaultMaxNotFound; } + public KEY_TYPE getDefaultMinValue() { return defaultMinNotFound; } + +#else + @Override + public void setDefaultMaxValue(KEY_TYPE value) { defaultMaxNotFound = value; } + @Override + public KEY_TYPE getDefaultMaxValue() { return defaultMaxNotFound; } + @Override + public void setDefaultMinValue(KEY_TYPE value) { defaultMinNotFound = value; } + @Override + public KEY_TYPE getDefaultMinValue() { return defaultMinNotFound; } + +#endif + @Override + public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { + if(tree == null) { + tree = first = last = new EntryKV_BRACES(key, value, null); + size++; + return getDefaultReturnValue(); + } + int compare = 0; + Entry KEY_VALUE_GENERIC_TYPE parent = tree; + while(true) { + if((compare = compare(key, parent.key)) == 0) return parent.setValue(value); + if(compare < 0) { + if(parent.left == null) break; + parent = parent.left; + } + else if(compare > 0) { + if(parent.right == null) break; + parent = parent.right; + } + } + Entry KEY_VALUE_GENERIC_TYPE adding = new EntryKV_BRACES(key, value, parent); + if(compare < 0) { + parent.left = adding; + if(parent == first) first = adding; + } + else { + parent.right = adding; + if(parent == last) last = adding; + } + fixAfterInsertion(adding); + size++; + return getDefaultReturnValue(); + } + + @Override + public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { + if(tree == null) { + tree = first = last = new EntryKV_BRACES(key, value, null); + size++; + return getDefaultReturnValue(); + } + int compare = 0; + Entry KEY_VALUE_GENERIC_TYPE parent = tree; + while(true) { + if((compare = compare(key, parent.key)) == 0) return parent.value; + if(compare < 0) { + if(parent.left == null) break; + parent = parent.left; + } + else if(compare > 0) { + if(parent.right == null) break; + parent = parent.right; + } + } + Entry KEY_VALUE_GENERIC_TYPE adding = new EntryKV_BRACES(key, value, parent); + if(compare < 0) { + parent.left = adding; + if(parent == first) first = adding; + } + else { + parent.right = adding; + if(parent == last) last = adding; + } + fixAfterInsertion(adding); + size++; + return getDefaultReturnValue(); + } + +#if VALUE_PRIMITIVES + @Override + public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { + if(tree == null) { + tree = first = last = new EntryKV_BRACES(key, value, null); + size++; + return getDefaultReturnValue(); + } + int compare = 0; + Entry KEY_VALUE_GENERIC_TYPE parent = tree; + while(true) { + if((compare = compare(key, parent.key)) == 0) return parent.addTo(value); + if(compare < 0) { + if(parent.left == null) break; + parent = parent.left; + } + else if(compare > 0) { + if(parent.right == null) break; + parent = parent.right; + } + } + Entry KEY_VALUE_GENERIC_TYPE adding = new EntryKV_BRACES(key, value, parent); + if(compare < 0) { + parent.left = adding; + if(parent == first) first = adding; + } + else { + parent.right = adding; + if(parent == last) last = adding; + } + fixAfterInsertion(adding); + size++; + return getDefaultReturnValue(); + } + +#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(); } + + @Override + public COMPARATOR KEY_GENERIC_TYPE comparator() { return comparator; } + +#if TYPE_OBJECT + @Override + public boolean containsKey(Object key) { + return findNode((KEY_TYPE)key) != null; + } + +#else + @Override + public boolean containsKey(KEY_TYPE key) { + return findNode(key) != null; + } + +#endif + @Override + public VALUE_TYPE GET_VALUE(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = findNode(key); + return node == null ? getDefaultReturnValue() : node.value; + } + +#if TYPE_OBJECT + @Override + public VALUE_TYPE getOrDefault(Object key, VALUE_TYPE defaultValue) { + Entry KEY_VALUE_GENERIC_TYPE node = findNode((CLASS_TYPE)key); + return node == null ? defaultValue : node.value; + } + +#else + @Override + public VALUE_TYPE getOrDefault(KEY_TYPE key, VALUE_TYPE defaultValue) { + Entry KEY_VALUE_GENERIC_TYPE node = findNode(key); + return node == null ? defaultValue : node.value; + } + +#endif + @Override + public KEY_TYPE FIRST_ENTRY_KEY() { + if(tree == null) throw new NoSuchElementException(); + return first.key; + } + + @Override + public KEY_TYPE POLL_FIRST_ENTRY_KEY() { + if(tree == null) throw new NoSuchElementException(); + KEY_TYPE result = first.key; + removeNode(first); + return result; + } + + @Override + public KEY_TYPE LAST_ENTRY_KEY() { + if(tree == null) throw new NoSuchElementException(); + return last.key; + } + + @Override + public KEY_TYPE POLL_LAST_ENTRY_KEY() { + if(tree == null) throw new NoSuchElementException(); + KEY_TYPE result = last.key; + removeNode(last); + return result; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE firstEntry() { + if(tree == null) throw new NoSuchElementException(); + return new BasicEntryKV_BRACES(first.key, first.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE lastEntry() { + if(tree == null) throw new NoSuchElementException(); + return new BasicEntryKV_BRACES(last.key, last.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollFirstEntry() { + if(tree == null) throw new NoSuchElementException(); + BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES(first.key, first.value); + removeNode(first); + return entry; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollLastEntry() { + if(tree == null) throw new NoSuchElementException(); + BasicEntry KEY_VALUE_GENERIC_TYPE entry = new BasicEntryKV_BRACES(last.key, last.value); + removeNode(last); + return entry; + } + + @Override + public VALUE_TYPE FIRST_ENTRY_VALUE() { + if(tree == null) throw new NoSuchElementException(); + return first.value; + } + + @Override + public VALUE_TYPE LAST_ENTRY_VALUE() { + if(tree == null) throw new NoSuchElementException(); + return last.value; + } + + @Override + public VALUE_TYPE REMOVE_KEY(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); + if(entry == null) return getDefaultReturnValue(); + VALUE_TYPE value = entry.value; + removeNode(entry); + return value; + } + +#if TYPE_OBJECT && VALUE_OBJECT + @Override + public boolean remove(Object key, Object value) { + Entry KEY_VALUE_GENERIC_TYPE entry = findNode((CLASS_TYPE)key); + if(entry == null || !Objects.equals(value, entry.value)) return false; + removeNode(entry); + return true; + } + +#else + @Override + public boolean remove(KEY_TYPE key, VALUE_TYPE value) { + Entry KEY_VALUE_GENERIC_TYPE entry = findNode(key); + if(entry == null || entry.value != value) return false; + removeNode(entry); + return true; + } + +#endif + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(boolean descending) { + LIST_ITERATOR KEY_GENERIC_TYPE iter = new KeyIterator(descending); + return descending ? ITERATORS.invert(iter) : iter; + } + + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(KEY_TYPE key) { + return new KeyIterator(findNode(key)); + } + + @Override + public SORTED_SET KEY_GENERIC_TYPE keySet() { + return navigableKeySet(); + } + + @Override + public ObjectSet ENTRY_SET() { + if(entrySet == null) entrySet = new EntrySet(); + return entrySet; + } + + @Override + public VALUE_COLLECTION VALUE_GENERIC_TYPE values() { + if(values == null) values = new Values(); + return values; + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE navigableKeySet() { + if(keySet == null) keySet = new KeySetKV_BRACES(this); + return keySet; + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap() { + return new DescendingSubMapKV_BRACES(this, true, EMPTY_KEY_VALUE, true, true, EMPTY_KEY_VALUE, true); + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, boolean fromInclusive, KEY_TYPE toKey, boolean toInclusive) { + return new AscendingSubMapKV_BRACES(this, false, fromKey, fromInclusive, false, toKey, toInclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey, boolean inclusive) { + return new AscendingSubMapKV_BRACES(this, true, EMPTY_KEY_VALUE, true, false, toKey, inclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey, boolean inclusive) { + return new AscendingSubMapKV_BRACES(this, false, fromKey, inclusive, true, EMPTY_KEY_VALUE, true); + } + + @Override + public KEY_TYPE lowerKey(KEY_TYPE e) { + Entry KEY_VALUE_GENERIC_TYPE node = findLowerNode(e); + return node != null ? node.key : defaultMinNotFound; + } + + @Override + public KEY_TYPE floorKey(KEY_TYPE e) { + Entry KEY_VALUE_GENERIC_TYPE node = findFloorNode(e); + return node != null ? node.key : defaultMinNotFound; + } + + @Override + public KEY_TYPE higherKey(KEY_TYPE e) { + Entry KEY_VALUE_GENERIC_TYPE node = findHigherNode(e); + return node != null ? node.key : defaultMaxNotFound; + } + + @Override + public KEY_TYPE ceilingKey(KEY_TYPE e) { + Entry KEY_VALUE_GENERIC_TYPE node = findCeilingNode(e); + return node != null ? node.key : defaultMaxNotFound; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE lowerEntry(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = findLowerNode(key); + return node != null ? new BasicEntryKV_BRACES(node.key, node.value) : null; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE higherEntry(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = findHigherNode(key); + return node != null ? new BasicEntryKV_BRACES(node.key, node.value) : null; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE floorEntry(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = findFloorNode(key); + return node != null ? new BasicEntryKV_BRACES(node.key, node.value) : null; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE ceilingEntry(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = findCeilingNode(key); + return node != null ? new BasicEntryKV_BRACES(node.key, node.value) : null; + } + + protected Entry KEY_VALUE_GENERIC_TYPE findLowerNode(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE entry = tree; + while(entry != null) { + if(compare(key, entry.key) > 0) { + if(entry.right != null) entry = entry.right; + else return entry; + } + else { + if(entry.left != null) entry = entry.left; + else { + Entry KEY_VALUE_GENERIC_TYPE parent = entry.parent; + while(parent != null && parent.left == entry) { + entry = parent; + parent = parent.parent; + } + return parent; + } + } + } + return null; + } + + protected Entry KEY_VALUE_GENERIC_TYPE findFloorNode(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE entry = tree; + int compare; + while(entry != null) { + if((compare = compare(key, entry.key)) > 0) { + if(entry.right == null) break; + entry = entry.right; + continue; + } + else if(compare < 0) { + if(entry.left != null) entry = entry.left; + else { + Entry KEY_VALUE_GENERIC_TYPE parent = entry.parent; + while(parent != null && parent.left == entry) { + entry = parent; + parent = parent.parent; + } + return parent; + } + continue; + } + break; + } + return entry; + } + + protected Entry KEY_VALUE_GENERIC_TYPE findCeilingNode(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE entry = tree; + int compare; + while(entry != null) { + if((compare = compare(key, entry.key)) < 0) { + if(entry.left == null) break; + entry = entry.left; + continue; + } + else if(compare > 0) { + if(entry.right != null) entry = entry.right; + else { + Entry KEY_VALUE_GENERIC_TYPE parent = entry.parent; + while(parent != null && parent.right == entry) { + entry = parent; + parent = parent.parent; + } + return parent; + } + continue; + } + break; + } + return entry; + } + + protected Entry KEY_VALUE_GENERIC_TYPE findHigherNode(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE entry = tree; + while(entry != null) { + if(compare(key, entry.key) < 0) { + if(entry.left != null) entry = entry.left; + else return entry; + } + else { + if(entry.right != null) entry = entry.right; + else { + Entry KEY_VALUE_GENERIC_TYPE parent = entry.parent; + while(parent != null && parent.right == entry) { + entry = parent; + parent = parent.parent; + } + return parent; + } + } + } + return null; + } + + protected Entry KEY_VALUE_GENERIC_TYPE findNode(KEY_TYPE key) { + Entry KEY_VALUE_GENERIC_TYPE node = tree; + int compare; + while(node != null) { + if((compare = compare(key, node.key)) == 0) return node; + if(compare < 0) node = node.left; + else node = node.right; + } + return null; + } + + protected void removeNode(Entry KEY_VALUE_GENERIC_TYPE entry) { + size--; + if(entry.needsSuccessor()) { + Entry KEY_VALUE_GENERIC_TYPE successor = entry.next(); + entry.key = successor.key; + entry.value = successor.value; + entry = successor; + } + Entry KEY_VALUE_GENERIC_TYPE replacement = entry.left != null ? entry.left : entry.right; + if(replacement != null) { + if(entry.replace(replacement)) tree = replacement; + if(entry == first) first = replacement; + if(entry == last) last = entry.right != null ? entry.right : replacement; + entry.left = entry.right = entry.parent = null; + if(entry.isBlack()) fixAfterDeletion(replacement); + } + else if(entry.parent == null) tree = first = last = null; + else { + if(entry.isBlack()) + fixAfterDeletion(entry); + entry.replace(null); + if(entry.parent != null) { + Entry KEY_VALUE_GENERIC_TYPE parent = entry.parent; + if(entry == first) first = parent.left != null ? parent.left : parent; + if(entry == last) last = entry.right != null ? parent.right : parent; + } + entry.parent = null; + } + } + + protected int compare(KEY_TYPE k, KEY_TYPE v) { return comparator != null ? comparator.compare(k, v) : COMPAREABLE_TO_KEY(k, v);} + protected static GENERIC_KEY_VALUE_BRACES boolean isBlack(Entry KEY_VALUE_GENERIC_TYPE p) { return p == null || p.isBlack(); } + protected static GENERIC_KEY_VALUE_BRACES Entry KEY_VALUE_GENERIC_TYPE parentOf(Entry KEY_VALUE_GENERIC_TYPE p) { return (p == null ? null : p.parent); } + protected static GENERIC_KEY_VALUE_BRACES void setBlack(Entry KEY_VALUE_GENERIC_TYPE p, boolean c) { if(p != null) p.setBlack(c); } + protected static GENERIC_KEY_VALUE_BRACES Entry KEY_VALUE_GENERIC_TYPE leftOf(Entry KEY_VALUE_GENERIC_TYPE p) { return p == null ? null : p.left; } + protected static GENERIC_KEY_VALUE_BRACES Entry KEY_VALUE_GENERIC_TYPE rightOf(Entry KEY_VALUE_GENERIC_TYPE p) { return (p == null) ? null : p.right; } + + /** From CLR */ + protected void rotateLeft(Entry KEY_VALUE_GENERIC_TYPE entry) { + if(entry != null) { + Entry KEY_VALUE_GENERIC_TYPE right = entry.right; + entry.right = right.left; + if(right.left != null) right.left.parent = entry; + right.parent = entry.parent; + if(entry.parent == null) tree = right; + else if(entry.parent.left == entry) entry.parent.left = right; + else entry.parent.right = right; + right.left = entry; + entry.parent = right; + } + } + + /** From CLR */ + protected void rotateRight(Entry KEY_VALUE_GENERIC_TYPE entry) { + if(entry != null) { + Entry KEY_VALUE_GENERIC_TYPE left = entry.left; + entry.left = left.right; + if(left.right != null) left.right.parent = entry; + left.parent = entry.parent; + if(entry.parent == null) tree = left; + else if(entry.parent.right == entry) entry.parent.right = left; + else entry.parent.left = left; + left.right = entry; + entry.parent = left; + } + } + + /** From CLR */ + protected void fixAfterInsertion(Entry KEY_VALUE_GENERIC_TYPE entry) { + entry.setBlack(false); + while(entry != null && entry != tree && !entry.parent.isBlack()) { + if(parentOf(entry) == leftOf(parentOf(parentOf(entry)))) { + Entry KEY_VALUE_GENERIC_TYPE y = rightOf(parentOf(parentOf(entry))); + if(!isBlack(y)) { + setBlack(parentOf(entry), true); + setBlack(y, true); + setBlack(parentOf(parentOf(entry)), false); + entry = parentOf(parentOf(entry)); + } + else { + if(entry == rightOf(parentOf(entry))) { + entry = parentOf(entry); + rotateLeft(entry); + } + setBlack(parentOf(entry), true); + setBlack(parentOf(parentOf(entry)), false); + rotateRight(parentOf(parentOf(entry))); + } + } + else { + Entry KEY_VALUE_GENERIC_TYPE y = leftOf(parentOf(parentOf(entry))); + if(!isBlack(y)) { + setBlack(parentOf(entry), true); + setBlack(y, true); + setBlack(parentOf(parentOf(entry)), false); + entry = parentOf(parentOf(entry)); + } + else { + if(entry == leftOf(parentOf(entry))) { + entry = parentOf(entry); + rotateRight(entry); + } + setBlack(parentOf(entry), true); + setBlack(parentOf(parentOf(entry)), false); + rotateLeft(parentOf(parentOf(entry))); + } + } + } + tree.setBlack(true); + } + + /** From CLR */ + protected void fixAfterDeletion(Entry KEY_VALUE_GENERIC_TYPE entry) { + while(entry != tree && isBlack(entry)) { + if(entry == leftOf(parentOf(entry))) { + Entry KEY_VALUE_GENERIC_TYPE sib = rightOf(parentOf(entry)); + if(!isBlack(sib)) { + setBlack(sib, true); + setBlack(parentOf(entry), false); + rotateLeft(parentOf(entry)); + sib = rightOf(parentOf(entry)); + } + if(isBlack(leftOf(sib)) && isBlack(rightOf(sib))) { + setBlack(sib, false); + entry = parentOf(entry); + } + else { + if(isBlack(rightOf(sib))) { + setBlack(leftOf(sib), true); + setBlack(sib, false); + rotateRight(sib); + sib = rightOf(parentOf(entry)); + } + setBlack(sib, isBlack(parentOf(entry))); + setBlack(parentOf(entry), true); + setBlack(rightOf(sib), true); + rotateLeft(parentOf(entry)); + entry = tree; + } + } + else { + Entry KEY_VALUE_GENERIC_TYPE sib = leftOf(parentOf(entry)); + if(!isBlack(sib)) { + setBlack(sib, true); + setBlack(parentOf(entry), false); + rotateRight(parentOf(entry)); + sib = leftOf(parentOf(entry)); + } + if(isBlack(rightOf(sib)) && isBlack(leftOf(sib))) { + setBlack(sib, false); + entry = parentOf(entry); + } + else { + if(isBlack(leftOf(sib))) { + setBlack(rightOf(sib), true); + setBlack(sib, false); + rotateLeft(sib); + sib = leftOf(parentOf(entry)); + } + setBlack(sib, isBlack(parentOf(entry))); + setBlack(parentOf(entry), true); + setBlack(leftOf(sib), true); + rotateRight(parentOf(entry)); + entry = tree; + } + } + } + setBlack(entry, true); + } + + static final class AscendingSubMap KEY_VALUE_GENERIC_TYPE extends NavigableSubMap KEY_VALUE_GENERIC_TYPE { + + public AscendingSubMap(RB_TREE_MAP KEY_VALUE_GENERIC_TYPE m, boolean fromStart, KEY_TYPE low, boolean loInclusive, boolean toEnd, KEY_TYPE high, boolean hiInclusive) { + super(m, fromStart, low, loInclusive, toEnd, high, hiInclusive); + } + + @Override + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(boolean descending) { return new SubMapKeyIterator(descending); } + @Override + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(KEY_TYPE key) { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findNode(key); + return entry == null || !inClosedRange(key) ? null : new SubMapKeyIterator(entry, fromStart ? null : findLowest(), toEnd ? null : findHighest()); + } + @Override + VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE valueIterator() { return new SubMapValueIterator(false); } + @Override + ObjectListIterator entryIterator() { return new SubMapEntrySetIterator(false); } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap() { + if(descendingMap == null) descendingMap = new DescendingSubMapKV_BRACES(m, fromStart, low, loInclusive, toEnd, high, hiInclusive); + return descendingMap; + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, boolean fromInclusive, KEY_TYPE toKey, boolean toInclusive) { + if (!inRange(fromKey, fromInclusive)) throw new IllegalArgumentException("fromKey out of range"); + if (!inRange(toKey, toInclusive)) throw new IllegalArgumentException("toKey out of range"); + return new AscendingSubMapKV_BRACES(m, false, fromKey, fromInclusive, false, toKey, toInclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey, boolean inclusive) { + if (!inRange(toKey, inclusive)) throw new IllegalArgumentException("toKey out of range"); + return new AscendingSubMapKV_BRACES(m, fromStart, low, loInclusive, false, toKey, inclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey, boolean inclusive) { + if (!inRange(fromKey, inclusive)) throw new IllegalArgumentException("fromKey out of range"); + return new AscendingSubMapKV_BRACES(m, false, fromKey, inclusive, toEnd, high, hiInclusive); + } + } + + static final class DescendingSubMap KEY_VALUE_GENERIC_TYPE extends NavigableSubMap KEY_VALUE_GENERIC_TYPE { + + public DescendingSubMap(RB_TREE_MAP KEY_VALUE_GENERIC_TYPE m, boolean fromStart, KEY_TYPE low, boolean loInclusive, boolean toEnd, KEY_TYPE high, boolean hiInclusive) { + super(m, fromStart, low, loInclusive, toEnd, high, hiInclusive); + } + + @Override + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(boolean descending) { + LIST_ITERATOR KEY_GENERIC_TYPE iter = new SubMapKeyIterator(!descending); + return descending ? iter : ITERATORS.invert(iter); + } + + @Override + LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(KEY_TYPE key) { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findNode(key); + return entry == null || !inClosedRange(key) ? null : ITERATORS.invert(new SubMapKeyIterator(entry, fromStart ? null : findLowest(), toEnd ? null : findHighest())); + } + + @Override + public COMPARATOR KEY_GENERIC_TYPE comparator() { return m.comparator().reversed(); } + + @Override + VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE valueIterator() { return VALUE_ITERATORS.invert(new SubMapValueIterator(true)); } + + @Override + ObjectListIterator entryIterator() { return ObjectIterators.invert(new SubMapEntrySetIterator(true)); } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap() { + if(descendingMap == null) descendingMap = new AscendingSubMapKV_BRACES(m, fromStart, low, loInclusive, toEnd, high, hiInclusive); + return descendingMap; + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, boolean fromInclusive, KEY_TYPE toKey, boolean toInclusive) { + if (!inRange(fromKey, fromInclusive)) throw new IllegalArgumentException("fromKey out of range"); + if (!inRange(toKey, toInclusive)) throw new IllegalArgumentException("toKey out of range"); + return new DescendingSubMapKV_BRACES(m, false, fromKey, fromInclusive, false, toKey, toInclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey, boolean inclusive) { + if (!inRange(toKey, inclusive)) throw new IllegalArgumentException("toKey out of range"); + return new DescendingSubMapKV_BRACES(m, fromStart, low, loInclusive, false, toKey, inclusive); + } + + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey, boolean inclusive) { + if (!inRange(fromKey, inclusive)) throw new IllegalArgumentException("fromKey out of range"); + return new DescendingSubMapKV_BRACES(m, false, fromKey, inclusive, toEnd, high, hiInclusive); + } + } + + static abstract class NavigableSubMap KEY_VALUE_GENERIC_TYPE extends ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE implements NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE { + final RB_TREE_MAP KEY_VALUE_GENERIC_TYPE m; + final KEY_TYPE low; + final KEY_TYPE high; + final boolean fromStart; + final boolean toEnd; + final boolean loInclusive; + final boolean hiInclusive; + transient NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap; + transient SubMapEntrySet entrySet; + transient KeySet KEY_VALUE_GENERIC_TYPE keySet; + transient SubMapValues values; + + NavigableSubMap(RB_TREE_MAP KEY_VALUE_GENERIC_TYPE m, boolean fromStart, KEY_TYPE low, boolean loInclusive, boolean toEnd, KEY_TYPE high, boolean hiInclusive) { + this.m = m; + this.low = low; + this.high = high; + this.fromStart = fromStart; + this.toEnd = toEnd; + this.loInclusive = loInclusive; + this.hiInclusive = hiInclusive; + } + + abstract LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(boolean descending); + abstract LIST_ITERATOR KEY_GENERIC_TYPE keyIterator(KEY_TYPE key); + abstract VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE valueIterator(); + abstract ObjectListIterator entryIterator(); + + @Override + public abstract NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap(); + @Override + public abstract NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, boolean fromInclusive, KEY_TYPE toKey, boolean toInclusive); + @Override + public abstract NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey, boolean inclusive); + @Override + public abstract NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey, boolean inclusive); + + boolean tooLow(KEY_TYPE key) { return !fromStart && (loInclusive ? m.compare(key, low) < 0 : m.compare(key, low) <= 0); } + boolean tooHigh(KEY_TYPE key) { return !toEnd && (hiInclusive ? m.compare(key, high) > 0 : m.compare(key, high) >= 0); } + boolean inRange(KEY_TYPE key) { return !tooLow(key) && !tooHigh(key); } + boolean inClosedRange(KEY_TYPE key) { return (fromStart || m.compare(key, low) >= 0) && (toEnd || m.compare(high, key) >= 0); } + boolean inRange(KEY_TYPE key, boolean inclusive) { return inclusive ? inRange(key) : inClosedRange(key); } + +#if TYPE_OBJECT + public KEY_TYPE getDefaultMaxValue() { return m.getDefaultMaxValue(); } + public KEY_TYPE getDefaultMinValue() { return m.getDefaultMinValue(); } +#else + @Override + public void setDefaultMaxValue(KEY_TYPE e) { m.setDefaultMaxValue(e); } + @Override + public KEY_TYPE getDefaultMaxValue() { return m.getDefaultMaxValue(); } + @Override + public void setDefaultMinValue(KEY_TYPE e) { m.setDefaultMinValue(e); } + @Override + public KEY_TYPE getDefaultMinValue() { return m.getDefaultMinValue(); } + +#endif + @Override + public ABSTRACT_MAP KEY_VALUE_GENERIC_TYPE setDefaultReturnValue(VALUE_TYPE v) { + m.setDefaultReturnValue(v); + return this; + } + + @Override + public VALUE_TYPE getDefaultReturnValue() { return m.getDefaultReturnValue(); } + + @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(); } + @Override + public COMPARATOR KEY_GENERIC_TYPE comparator() { return m.comparator(); } +#if TYPE_OBJECT + @Override + public boolean containsKey(Object key) { return inRange((CLASS_TYPE)key) && m.containsKey(key); } +#else + @Override + public boolean containsKey(KEY_TYPE key) { return inRange(key) && m.containsKey(key); } + +#endif + @Override + public KEY_TYPE FIRST_ENTRY_KEY() { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? getDefaultMaxValue() : entry.key; + } + + @Override + public KEY_TYPE POLL_FIRST_ENTRY_KEY() { + if(fromStart) return m.POLL_FIRST_ENTRY_KEY(); + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = loInclusive ? m.findCeilingNode(low) : m.findHigherNode(low); + if(entry != null && !tooHigh(entry.key)) { + KEY_TYPE value = entry.key; + m.removeNode(entry); + return value; + } + return getDefaultMaxValue(); + } + + @Override + public KEY_TYPE LAST_ENTRY_KEY() { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? getDefaultMinValue() : entry.key; + } + + @Override + public KEY_TYPE POLL_LAST_ENTRY_KEY() { + if(toEnd) return m.POLL_LAST_ENTRY_KEY(); + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = hiInclusive ? m.findFloorNode(high) : m.findLowerNode(high); + if(entry != null && !tooLow(entry.key)) { + KEY_TYPE value = entry.key; + m.removeNode(entry); + return value; + } + return getDefaultMinValue(); + } + + @Override + public VALUE_TYPE FIRST_ENTRY_VALUE() { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? getDefaultReturnValue() : entry.value; + } + + @Override + public VALUE_TYPE LAST_ENTRY_VALUE() { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? getDefaultReturnValue() : entry.value; + } + + protected RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE findLowest() { + if(fromStart) return m.first; + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = loInclusive ? m.findCeilingNode(low) : m.findHigherNode(low); + return entry == null || tooHigh(entry.key) ? null : entry; + } + + protected RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE findHighest() { + if(toEnd) return m.last; + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = hiInclusive ? m.findFloorNode(high) : m.findLowerNode(high); + return entry == null || tooLow(entry.key) ? null : entry; + } + + @Override + public VALUE_TYPE put(KEY_TYPE key, VALUE_TYPE value) { + if(!inRange(key)) throw new IllegalArgumentException("key out of range"); + return m.put(key, value); + } + + @Override + public VALUE_TYPE putIfAbsent(KEY_TYPE key, VALUE_TYPE value) { + if(!inRange(key)) throw new IllegalArgumentException("key out of range"); + return m.putIfAbsent(key, value); + } + +#if VALUE_PRIMITIVES + @Override + public VALUE_TYPE addTo(KEY_TYPE key, VALUE_TYPE value) { + if(!inRange(key)) throw new IllegalArgumentException("key out of range"); + return m.addTo(key, value); + } + +#endif + @Override + public VALUE_TYPE GET_VALUE(KEY_TYPE key) { + return inRange(key) ? m.GET_VALUE(key) : getDefaultReturnValue(); + } + + @Override + public VALUE_TYPE REMOVE_KEY(KEY_TYPE key) { + return inRange(key) ? m.remove(key) : getDefaultReturnValue(); + } + +#if TYPE_OBJECT && VALUE_OBJECT + @Override + public boolean remove(Object key, Object value) { + return inRange((CLASS_TYPE)key) && m.remove(key, value); + } + +#else + @Override + public boolean remove(KEY_TYPE key, VALUE_TYPE value) { + return inRange(key) && m.remove(key, value); + } + +#endif + @Override + public ObjectSet ENTRY_SET() { + if(entrySet == null) entrySet = new SubMapEntrySet(); + return entrySet; + } + + @Override + public SET KEY_GENERIC_TYPE keySet() { return navigableKeySet(); } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE navigableKeySet() { + if(keySet == null) keySet = new KeySetKV_BRACES(this); + return keySet; + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE descendingKeySet() { + return descendingMap().navigableKeySet(); + } + + @Override + public VALUE_COLLECTION VALUE_GENERIC_TYPE values() { + if(values == null) values = new SubMapValues(); + return values; + } + + @Override + public int size() { + return (fromStart && toEnd) ? m.size() : entrySet().size(); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE firstEntry() { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE lastEntry() { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollFirstEntry() { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + if(entry == null) return null; + BasicEntry KEY_VALUE_GENERIC_TYPE result = new BasicEntryKV_BRACES(entry.key, entry.value); + m.removeNode(entry); + return result; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollLastEntry() { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + if(entry == null) return null; + BasicEntry KEY_VALUE_GENERIC_TYPE result = new BasicEntryKV_BRACES(entry.key, entry.value); + m.removeNode(entry); + return result; + } + + @Override + public KEY_TYPE lowerKey(KEY_TYPE e) { + if(tooHigh(e)) { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? getDefaultMinValue() : entry.key; + } + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findLowerNode(e); + return entry == null || tooHigh(entry.key) ? getDefaultMaxValue() : entry.key; + } + + @Override + public KEY_TYPE floorKey(KEY_TYPE e) { + if(tooHigh(e)) { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? getDefaultMinValue() : entry.key; + } + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findFloorNode(e); + return entry == null || tooHigh(entry.key) ? getDefaultMaxValue() : entry.key; + } + + @Override + public KEY_TYPE ceilingKey(KEY_TYPE e) { + if(tooLow(e)) { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? getDefaultMaxValue() : entry.key; + } + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findCeilingNode(e); + return entry == null || tooLow(entry.key) ? getDefaultMinValue() : entry.key; + } + + @Override + public KEY_TYPE higherKey(KEY_TYPE e) { + if(tooLow(e)) { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? getDefaultMaxValue() : entry.key; + } + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findHigherNode(e); + return entry == null || tooLow(entry.key) ? getDefaultMinValue() : entry.key; + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE lowerEntry(KEY_TYPE e) { + if(tooHigh(e)) { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findLowerNode(e); + return entry == null || tooHigh(entry.key) ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE floorEntry(KEY_TYPE e) { + if(tooHigh(e)) { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findHighest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findFloorNode(e); + return entry == null || tooHigh(entry.key) ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE ceilingEntry(KEY_TYPE e) { + if(tooLow(e)) { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findCeilingNode(e); + return entry == null || tooLow(entry.key) ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE higherEntry(KEY_TYPE e) { + if(tooLow(e)) { + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = findLowest(); + return entry == null ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry = m.findHigherNode(e); + return entry == null || tooLow(entry.key) ? null : new BasicEntryKV_BRACES(entry.key, entry.value); + } + + class SubMapEntrySet extends AbstractObjectSet implements ObjectSet { + @Override + @Deprecated + public boolean contains(Object o) { + if(o instanceof Map.Entry) { + if(o instanceof MAP.Entry) return NavigableSubMap.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); + return NavigableSubMap.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 NavigableSubMap.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (Map.Entry)o; + return NavigableSubMap.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + @Override + public ObjectIterator iterator() { return entryIterator(); } + @Override + public int size() { return NavigableSubMap.this.size(); } + @Override + public void clear() { NavigableSubMap.this.clear(); } + } + + final class SubMapValues extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC_TYPE { + @Override + public boolean add(VALUE_TYPE o) { throw new UnsupportedOperationException(); } + +#if VALUE_OBJECT + @Override + public boolean contains(Object e) { + return containsValue(e); + } + +#else + @Override + public boolean contains(VALUE_TYPE e) { + return containsValue(e); + } + +#endif + @Override + public VALUE_ITERATOR VALUE_GENERIC_TYPE iterator() { return valueIterator(); } + + @Override + public int size() { + return NavigableSubMap.this.size(); + } + + @Override + public void clear() { + NavigableSubMap.this.clear(); + } + } + + final class SubMapEntrySetIterator extends SubMapEntryIterator implements ObjectListIterator { + public SubMapEntrySetIterator(boolean descending) { + super(descending); + } + + public SubMapEntrySetIterator(RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry, RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE lowerFence, RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE upperFence) { + super(entry, lowerFence, upperFence); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { return nextEntry(); } + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE previous() { return previousEntry(); } + + @Override + public void set(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + @Override + public void add(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + } + + final class SubMapKeyIterator extends SubMapEntryIterator implements LIST_ITERATOR KEY_GENERIC_TYPE { + public SubMapKeyIterator(boolean descending) { + super(descending); + } + + public SubMapKeyIterator(RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry, RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE lowerFence, RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE upperFence) { + super(entry, lowerFence, upperFence); + } + + @Override + public KEY_TYPE NEXT() { return nextEntry().key; } + @Override + public KEY_TYPE PREVIOUS() { return previousEntry().key; } + + @Override + public void set(KEY_TYPE e) { throw new UnsupportedOperationException(); } + @Override + public void add(KEY_TYPE e) { throw new UnsupportedOperationException(); } + } + + final class SubMapValueIterator extends SubMapEntryIterator implements VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE { + public SubMapValueIterator(boolean descending) { + super(descending); + } + + public SubMapValueIterator(RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry, RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE lowerFence, RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE upperFence) { + super(entry, lowerFence, upperFence); + } + + @Override + public VALUE_TYPE VALUE_NEXT() { return nextEntry().value; } + @Override + public VALUE_TYPE VALUE_PREVIOUS() { return previousEntry().value; } + + @Override + public void set(VALUE_TYPE e) { throw new UnsupportedOperationException(); } + @Override + public void add(VALUE_TYPE e) { throw new UnsupportedOperationException(); } + } + + abstract class SubMapEntryIterator { + CLASS_TYPE lowerFence; + CLASS_TYPE upperFence; + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE next; + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE previous; + RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE current; + int index = 0; + + public SubMapEntryIterator(boolean descending) { + this(descending ? findHighest() : findLowest(), fromStart ? null : findLowest(), toEnd ? null : findHighest()); + } + + public SubMapEntryIterator(RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE entry, RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE lowerFence, RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE upperFence) { + next = entry; + previous = entry.previous(); + this.lowerFence = lowerFence != null ? KEY_TO_OBJ(lowerFence.key) : null; + this.upperFence = upperFence != null ? KEY_TO_OBJ(upperFence.key) : null; + } + + public boolean hasNext() { + return next != null && (upperFence == null || KEY_EQUALS(next.key, OBJ_TO_KEY(upperFence))); + } + + public boolean hasPrevious() { + return previous != null && (lowerFence == null || KEY_EQUALS(next.key, OBJ_TO_KEY(lowerFence))); + } + + public int nextIndex() { + return index; + } + + public int previousIndex() { + return index - 1; + } + + protected void updateNext() { + next = current.next(); + } + + protected void updatePrevious() { + previous = current.previous(); + } + + public RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE nextEntry() { + if(!hasNext()) throw new NoSuchElementException(); + current = previous = next; + updateNext(); + index++; + return current; + } + + public RB_TREE_MAP.Entry KEY_VALUE_GENERIC_TYPE previousEntry() { + if(!hasPrevious()) throw new NoSuchElementException(); + current = next = previous; + updatePrevious(); + index--; + return current; + } + + public void remove() { + if(current == null) throw new IllegalStateException(); + if(current == previous) index--; + updateNext(); + updatePrevious(); + if(current.needsSuccessor()) next = current; + m.removeNode(current); + current = null; + } + } + } + + private class EntrySet extends AbstractObjectSet { + + @Override + public ObjectIterator iterator() { + return new EntryIterator(false); + } + + @Override + @Deprecated + public boolean contains(Object o) { + if(o instanceof Map.Entry) { + if(o instanceof MAP.Entry) return RB_TREE_MAP.this.containsKey(((MAP.Entry KEY_VALUE_GENERIC_TYPE)o).ENTRY_KEY()); + return RB_TREE_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 RB_TREE_MAP.this.remove(entry.ENTRY_KEY(), entry.ENTRY_VALUE()); + } + Map.Entry entry = (Map.Entry)o; + return RB_TREE_MAP.this.remove(entry.getKey(), entry.getValue()); + } + return false; + } + + @Override + public int size() { + return RB_TREE_MAP.this.size(); + } + + @Override + public void clear() { + RB_TREE_MAP.this.clear(); + } + } + + static final class KeySet KEY_VALUE_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE implements NAVIGABLE_SET KEY_GENERIC_TYPE { + NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE m; + + KeySet(NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE m) { + this.m = m; + } + +#if !TYPE_OBJECT + @Override + public void setDefaultMaxValue(KEY_TYPE e) { m.setDefaultMaxValue(e); } + @Override + public KEY_TYPE getDefaultMaxValue() { return m.getDefaultMaxValue(); } + @Override + public void setDefaultMinValue(KEY_TYPE e) { m.setDefaultMinValue(e); } + @Override + public KEY_TYPE getDefaultMinValue() { return m.getDefaultMinValue(); } +#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 COMPARATOR KEY_GENERIC_TYPE comparator() { return m.comparator(); } + @Override + public KEY_TYPE lower(KEY_TYPE e) { return m.lowerKey(e); } + @Override + public KEY_TYPE floor(KEY_TYPE e) { return m.floorKey(e); } + @Override + public KEY_TYPE ceiling(KEY_TYPE e) { return m.ceilingKey(e); } + @Override + public KEY_TYPE higher(KEY_TYPE e) { return m.higherKey(e); } + @Override + public KEY_TYPE FIRST_KEY() { return m.FIRST_ENTRY_KEY(); } + @Override + public KEY_TYPE POLL_FIRST_KEY() { return m.POLL_FIRST_ENTRY_KEY(); } + @Override + public KEY_TYPE LAST_KEY() { return m.LAST_ENTRY_KEY(); } + @Override + public KEY_TYPE POLL_LAST_KEY() { return m.POLL_LAST_ENTRY_KEY(); } +#if TYPE_OBJECT + @Override + public boolean remove(Object o) { + int oldSize = m.size(); + m.remove(o); + return oldSize != m.size(); + } + +#else + @Override + public boolean remove(KEY_TYPE o) { + int oldSize = m.size(); + m.remove(o); + return oldSize != m.size(); + } + +#endif + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, boolean fromInclusive, KEY_TYPE toElement, boolean toInclusive) { + return new KeySetKV_BRACES(m.subMap(fromElement, fromInclusive, toElement, toInclusive)); + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement, boolean inclusive) { + return new KeySetKV_BRACES(m.headMap(toElement, inclusive)); + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement, boolean inclusive) { + return new KeySetKV_BRACES(m.tailMap(fromElement, inclusive)); + } + + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE descendingSet() { + return new KeySetKV_BRACES(m.descendingMap()); + } + + @Override + public BI_ITERATOR KEY_GENERIC_TYPE iterator() { + if(m instanceof RB_TREE_MAP) return ((RB_TREE_MAP KEY_VALUE_GENERIC_TYPE)m).keyIterator(false); + return ((NavigableSubMap KEY_VALUE_GENERIC_TYPE)m).keyIterator(false); + } + + @Override + public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) { + if(m instanceof RB_TREE_MAP) return ((RB_TREE_MAP KEY_VALUE_GENERIC_TYPE)m).keyIterator(fromElement); + return ((NavigableSubMap KEY_VALUE_GENERIC_TYPE)m).keyIterator(fromElement); + } + + @Override + public BI_ITERATOR KEY_GENERIC_TYPE descendingIterator() { + if(m instanceof RB_TREE_MAP) return ((RB_TREE_MAP KEY_VALUE_GENERIC_TYPE)m).keyIterator(true); + return ((NavigableSubMap KEY_VALUE_GENERIC_TYPE)m).keyIterator(true); + } + + @Override + public int size() { + return m.size(); + } + + @Override + public void clear() { + m.clear(); + } + } + + final class Values extends VALUE_ABSTRACT_COLLECTION VALUE_GENERIC_TYPE { + + @Override + public boolean add(VALUE_TYPE o) { throw new UnsupportedOperationException(); } + +#if VALUE_OBJECT + @Override + public boolean contains(Object e) { + return containsValue(e); + } + +#else + @Override + public boolean contains(VALUE_TYPE e) { + return containsValue(e); + } + +#endif + @Override + public VALUE_ITERATOR VALUE_GENERIC_TYPE iterator() { return new ValueIterator(false); } + + @Override + public int size() { + return RB_TREE_MAP.this.size(); + } + + @Override + public void clear() { + RB_TREE_MAP.this.clear(); + } + } + + final class EntryIterator extends MapEntryIterator implements ObjectListIterator { + + public EntryIterator(boolean descending) { + super(descending); + } + + public EntryIterator(Entry KEY_VALUE_GENERIC_TYPE entry) { + super(entry); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE next() { + return nextEntry(); + } + + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE previous() { + return previousEntry(); + } + + @Override + public void set(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + + @Override + public void add(MAP.Entry KEY_VALUE_GENERIC_TYPE e) { throw new UnsupportedOperationException(); } + } + + final class KeyIterator extends MapEntryIterator implements LIST_ITERATOR KEY_GENERIC_TYPE { + + public KeyIterator(boolean descending) { + super(descending); + } + + public KeyIterator(Entry KEY_VALUE_GENERIC_TYPE entry) { + super(entry); + } + + @Override + public KEY_TYPE PREVIOUS() { return previousEntry().key; } + @Override + public KEY_TYPE NEXT() { return nextEntry().key; } + + @Override + public void set(KEY_TYPE e) { throw new UnsupportedOperationException(); } + @Override + public void add(KEY_TYPE e) { throw new UnsupportedOperationException(); } + } + + final class ValueIterator extends MapEntryIterator implements VALUE_LIST_ITERATOR VALUE_GENERIC_TYPE { + + public ValueIterator(boolean descending) { + super(descending); + } + + public ValueIterator(Entry KEY_VALUE_GENERIC_TYPE entry) { + super(entry); + } + + @Override + public VALUE_TYPE VALUE_PREVIOUS() { + return previousEntry().value; + } + + @Override + public VALUE_TYPE VALUE_NEXT() { + return nextEntry().value; + } + + @Override + public void set(VALUE_TYPE e) { throw new UnsupportedOperationException(); } + + @Override + public void add(VALUE_TYPE e) { throw new UnsupportedOperationException(); } + } + + abstract class MapEntryIterator { + Entry KEY_VALUE_GENERIC_TYPE next; + Entry KEY_VALUE_GENERIC_TYPE previous; + Entry KEY_VALUE_GENERIC_TYPE current; + int index = 0; + + public MapEntryIterator(boolean descending) { + if(descending) previous = last; + else next = first; + } + + public MapEntryIterator(Entry KEY_VALUE_GENERIC_TYPE entry) { + next = entry; + previous = entry.previous(); + } + + public boolean hasNext() { + return next != null; + } + + public boolean hasPrevious() { + return previous != null; + } + + public int nextIndex() { + return index; + } + + public int previousIndex() { + return index - 1; + } + + protected void updateNext() { + next = current.next(); + } + + protected void updatePrevious() { + previous = current.previous(); + } + + public Entry KEY_VALUE_GENERIC_TYPE nextEntry() { + if(!hasNext()) throw new NoSuchElementException(); + current = previous = next; + updateNext(); + index++; + return current; + } + + public Entry KEY_VALUE_GENERIC_TYPE previousEntry() { + if(!hasPrevious()) throw new NoSuchElementException(); + current = next = previous; + updatePrevious(); + index--; + return current; + } + + public void remove() { + if(current == null) throw new IllegalStateException(); + if(current == previous) index--; + updateNext(); + updatePrevious(); + if(current.needsSuccessor()) next = current; + removeNode(current); + current = null; + } + } + + private static final class Entry KEY_VALUE_GENERIC_TYPE implements MAP.Entry KEY_VALUE_GENERIC_TYPE + { + static final int BLACK = 1; + + KEY_TYPE key; + VALUE_TYPE value; + int state; + Entry KEY_VALUE_GENERIC_TYPE parent; + Entry KEY_VALUE_GENERIC_TYPE left; + Entry KEY_VALUE_GENERIC_TYPE right; + + Entry(KEY_TYPE key, VALUE_TYPE value, Entry KEY_VALUE_GENERIC_TYPE parent) { + this.key = key; + this.value = value; + this.parent = parent; + } + + @Override + public KEY_TYPE ENTRY_KEY() { + return key; + } + + @Override + public VALUE_TYPE ENTRY_VALUE() { + return value; + } + + @Override + public VALUE_TYPE setValue(VALUE_TYPE value) { + VALUE_TYPE oldValue = this.value; + this.value = value; + return oldValue; + } + +#if VALUE_PRIMITIVES + VALUE_TYPE addTo(VALUE_TYPE value) { + VALUE_TYPE oldValue = this.value; + this.value += value; + return oldValue; + } + +#endif + boolean isBlack() { + return (state & BLACK) != 0; + } + + void setBlack(boolean value) { + if(value) state |= BLACK; + else state &= ~BLACK; + } + + boolean needsSuccessor() { return left != null && right != null; } + + boolean replace(Entry KEY_VALUE_GENERIC_TYPE entry) { + if(entry != null) entry.parent = parent; + if(parent != null) { + if(parent.left == this) parent.left = entry; + else parent.right = entry; + } + return parent == null; + } + + Entry KEY_VALUE_GENERIC_TYPE next() { + if(right != null) { + Entry KEY_VALUE_GENERIC_TYPE parent = right; + while(parent.left != null) parent = parent.left; + return parent; + } + Entry KEY_VALUE_GENERIC_TYPE parent = this.parent; + Entry KEY_VALUE_GENERIC_TYPE control = this; + while(parent != null && control == parent.right) { + control = parent; + parent = parent.parent; + } + return parent; + } + + Entry KEY_VALUE_GENERIC_TYPE previous() { + if(left != null) { + Entry KEY_VALUE_GENERIC_TYPE parent = left; + while(parent.right != null) parent = parent.right; + return parent; + } + Entry KEY_VALUE_GENERIC_TYPE parent = this.parent; + Entry KEY_VALUE_GENERIC_TYPE control = this; + while(parent != null && control == parent.left) { + control = parent; + parent = parent.parent; + } + return parent; + } + } +} \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/maps/interfaces/Map.template b/src/main/resources/speiger/assets/collections/templates/maps/interfaces/Map.template index c4cb1c28..20236fdb 100644 --- a/src/main/resources/speiger/assets/collections/templates/maps/interfaces/Map.template +++ b/src/main/resources/speiger/assets/collections/templates/maps/interfaces/Map.template @@ -30,7 +30,7 @@ public interface MAP KEY_VALUE_GENERIC_TYPE extends Map +{ + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE descendingMap(); + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE navigableKeySet(); + @Override + public NAVIGABLE_SET KEY_GENERIC_TYPE descendingKeySet(); + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE firstEntry(); + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE lastEntry(); + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollFirstEntry(); + @Override + public MAP.Entry KEY_VALUE_GENERIC_TYPE pollLastEntry(); + +#if !TYPE_OBJECT + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, boolean fromInclusive, KEY_TYPE toKey, boolean toInclusive); + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey, boolean inclusive); + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey, boolean inclusive); + + @Override + public default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, KEY_TYPE toKey) { return subMap(fromKey, true, toKey, false); } + @Override + public default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey) { return headMap(toKey, false); } + @Override + public default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey) { return tailMap(fromKey, true); } + + public void setDefaultMaxValue(KEY_TYPE e); + public KEY_TYPE getDefaultMaxValue(); + + public void setDefaultMinValue(KEY_TYPE e); + public KEY_TYPE getDefaultMinValue(); + + public KEY_TYPE lowerKey(KEY_TYPE key); + public KEY_TYPE higherKey(KEY_TYPE key); + public KEY_TYPE floorKey(KEY_TYPE key); + public KEY_TYPE ceilingKey(KEY_TYPE key); + + public MAP.Entry KEY_VALUE_GENERIC_TYPE lowerEntry(KEY_TYPE key); + public MAP.Entry KEY_VALUE_GENERIC_TYPE higherEntry(KEY_TYPE key); + public MAP.Entry KEY_VALUE_GENERIC_TYPE floorEntry(KEY_TYPE key); + public MAP.Entry KEY_VALUE_GENERIC_TYPE ceilingEntry(KEY_TYPE key); + + @Override + public default CLASS_TYPE lowerKey(CLASS_TYPE key) { return KEY_TO_OBJ(lowerKey(OBJ_TO_KEY(key)));} + @Override + public default CLASS_TYPE floorKey(CLASS_TYPE key) { return KEY_TO_OBJ(floorKey(OBJ_TO_KEY(key)));} + @Override + public default CLASS_TYPE ceilingKey(CLASS_TYPE key) { return KEY_TO_OBJ(ceilingKey(OBJ_TO_KEY(key)));} + @Override + public default CLASS_TYPE higherKey(CLASS_TYPE key) { return KEY_TO_OBJ(higherKey(OBJ_TO_KEY(key)));} + + @Override + default MAP.Entry KEY_VALUE_GENERIC_TYPE lowerEntry(CLASS_TYPE key) { return lowerEntry(OBJ_TO_KEY(key)); } + @Override + default MAP.Entry KEY_VALUE_GENERIC_TYPE floorEntry(CLASS_TYPE key) { return floorEntry(OBJ_TO_KEY(key)); } + @Override + default MAP.Entry KEY_VALUE_GENERIC_TYPE ceilingEntry(CLASS_TYPE key) { return ceilingEntry(OBJ_TO_KEY(key)); } + @Override + default MAP.Entry KEY_VALUE_GENERIC_TYPE higherEntry(CLASS_TYPE key) { return higherEntry(OBJ_TO_KEY(key)); } + + @Override + default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(CLASS_TYPE fromKey, boolean fromInclusive, CLASS_TYPE toKey, boolean toInclusive) { return subMap(OBJ_TO_KEY(fromKey), fromInclusive, OBJ_TO_KEY(toKey), toInclusive); } + @Override + default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(CLASS_TYPE toKey, boolean inclusive) { return headMap(OBJ_TO_KEY(toKey), inclusive); } + @Override + default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(CLASS_TYPE fromKey, boolean inclusive) { return tailMap(OBJ_TO_KEY(fromKey), inclusive); } + @Override + default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(CLASS_TYPE fromKey, CLASS_TYPE toKey) { return subMap(OBJ_TO_KEY(fromKey), true, OBJ_TO_KEY(toKey), false); } + @Override + default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(CLASS_TYPE toKey) { return headMap(OBJ_TO_KEY(toKey), false); } + @Override + default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(CLASS_TYPE fromKey) { return tailMap(OBJ_TO_KEY(fromKey), true); } +#else + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(CLASS_TYPE fromKey, boolean fromInclusive, CLASS_TYPE toKey, boolean toInclusive); + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(CLASS_TYPE toKey, boolean inclusive); + @Override + public NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(CLASS_TYPE fromKey, boolean inclusive); + @Override + public default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE subMap(CLASS_TYPE fromKey, CLASS_TYPE toKey) { return subMap(fromKey, true, toKey, false); } + @Override + public default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE headMap(CLASS_TYPE toKey) { return headMap(toKey, false); } + @Override + public default NAVIGABLE_MAP KEY_VALUE_GENERIC_TYPE tailMap(CLASS_TYPE fromKey) { return tailMap(fromKey, true); } +#endif +} \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/maps/interfaces/SortedMap.template b/src/main/resources/speiger/assets/collections/templates/maps/interfaces/SortedMap.template new file mode 100644 index 00000000..e5528a21 --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/maps/interfaces/SortedMap.template @@ -0,0 +1,73 @@ +package speiger.src.collections.PACKAGE.maps.interfaces; + +#if TYPE_OBJECT +import java.util.Comparator; +#endif +import java.util.SortedMap; + +import speiger.src.collections.VALUE_PACKAGE.collections.VALUE_COLLECTION; +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.functions.COMPARATOR; +#endif +import speiger.src.collections.PACKAGE.sets.SET; +import speiger.src.collections.objects.sets.ObjectSortedSet; +import speiger.src.collections.objects.collections.ObjectBidirectionalIterator; + +public interface SORTED_MAP KEY_VALUE_GENERIC_TYPE extends SortedMap, MAP KEY_VALUE_GENERIC_TYPE +{ + public VALUE_TYPE putAndMoveToFirst(KEY_TYPE key, VALUE_TYPE value); + public VALUE_TYPE putAndMoveToLast(KEY_TYPE key, VALUE_TYPE value); + + public boolean moveToFirst(KEY_TYPE key); + public boolean moveToLast(KEY_TYPE key); + + public VALUE_TYPE getAndMoveToFirst(KEY_TYPE key); + public VALUE_TYPE getAndMoveToLast(KEY_TYPE key); + + @Override + public COMPARATOR KEY_GENERIC_TYPE comparator(); + + @Override + public SET KEY_GENERIC_TYPE keySet(); + @Override + public VALUE_COLLECTION VALUE_GENERIC_TYPE values(); + +#if !TYPE_OBJECT + public SORTED_MAP KEY_VALUE_GENERIC_TYPE subMap(KEY_TYPE fromKey, KEY_TYPE toKey); + public SORTED_MAP KEY_VALUE_GENERIC_TYPE headMap(KEY_TYPE toKey); + public SORTED_MAP KEY_VALUE_GENERIC_TYPE tailMap(KEY_TYPE fromKey); + + public KEY_TYPE FIRST_ENTRY_KEY(); + public KEY_TYPE POLL_FIRST_ENTRY_KEY(); + public KEY_TYPE LAST_ENTRY_KEY(); + public KEY_TYPE POLL_LAST_ENTRY_KEY(); + + public VALUE_TYPE FIRST_ENTRY_VALUE(); + public VALUE_TYPE LAST_ENTRY_VALUE(); + + public default CLASS_TYPE firstKey() { return KEY_TO_OBJ(FIRST_ENTRY_KEY()); } + public default CLASS_TYPE lastKey() { return KEY_TO_OBJ(LAST_ENTRY_KEY()); } + + @Override + @Deprecated + public default SORTED_MAP KEY_VALUE_GENERIC_TYPE subMap(CLASS_TYPE fromKey, CLASS_TYPE toKey) { return subMap(OBJ_TO_KEY(fromKey), OBJ_TO_KEY(toKey)); } + @Override + @Deprecated + public default SORTED_MAP KEY_VALUE_GENERIC_TYPE headMap(CLASS_TYPE toKey) { return headMap(OBJ_TO_KEY(toKey)); } + @Override + @Deprecated + public default SORTED_MAP KEY_VALUE_GENERIC_TYPE tailMap(CLASS_TYPE fromKey) { return tailMap(OBJ_TO_KEY(fromKey)); } +#else + public KEY_TYPE POLL_FIRST_ENTRY_KEY(); + public KEY_TYPE POLL_LAST_ENTRY_KEY(); + + public VALUE_TYPE FIRST_ENTRY_VALUE(); + public VALUE_TYPE LAST_ENTRY_VALUE(); +#endif + + interface FastSortedSet KEY_VALUE_GENERIC_TYPE extends MAP.FastEntrySet KEY_VALUE_GENERIC_TYPE, ObjectSortedSet { + @Override + public ObjectBidirectionalIterator fastIterator(); + public ObjectBidirectionalIterator fastIterator(KEY_TYPE fromElement); + } +} \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/sets/ArraySet.template b/src/main/resources/speiger/assets/collections/templates/sets/ArraySet.template index 3d7f4080..82fe2ef6 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/ArraySet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/ArraySet.template @@ -4,15 +4,20 @@ import java.util.Arrays; import java.util.Collection; #if TYPE_OBJECT import java.util.Comparator; +import java.util.function.Consumer; #endif import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; +#if PRIMITIVES +import java.util.function.JAVA_PREDICATE; +#endif import speiger.src.collections.PACKAGE.collections.BI_ITERATOR; import speiger.src.collections.PACKAGE.collections.COLLECTION; #if !TYPE_OBJECT import speiger.src.collections.PACKAGE.functions.COMPARATOR; +import speiger.src.collections.PACKAGE.functions.CONSUMER; #endif import speiger.src.collections.PACKAGE.lists.LIST_ITERATOR; import speiger.src.collections.PACKAGE.utils.ARRAYS; @@ -191,9 +196,9 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im public KEY_TYPE POLL_FIRST_KEY() { if(size == 0) throw new NoSuchElementException(); KEY_TYPE result = data[0]; - System.arraycopy(data, 1, data, 0, size - 1); + System.arraycopy(data, 1, data, 0, --size); #if TYPE_OBJECT - data[size-1] = EMPTY_KEY_VALUE; + data[size] = EMPTY_KEY_VALUE; #endif return result; } @@ -210,7 +215,36 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im return data[size]; #endif } +#if PRIMITIVES + @Override + public boolean remIf(JAVA_PREDICATE KEY_GENERIC_TYPE filter) { + Objects.requireNonNull(filter); + boolean modified = false; + int j = 0; + for(int i = 0;i=0;i--) diff --git a/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenCustomHashSet.template b/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenCustomHashSet.template index afecbf1f..22d4c897 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenCustomHashSet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenCustomHashSet.template @@ -174,7 +174,6 @@ public class LINKED_CUSTOM_HASH_SET KEY_GENERIC_TYPE extends CUSTOM_HASH_SET KEY } pos = ++pos & mask; } - keys[pos] = o; } return false; } @@ -197,7 +196,6 @@ public class LINKED_CUSTOM_HASH_SET KEY_GENERIC_TYPE extends CUSTOM_HASH_SET KEY } pos = ++pos & mask; } - keys[pos] = o; } return false; } diff --git a/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenHashSet.template b/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenHashSet.template index 141b836b..24703396 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenHashSet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenHashSet.template @@ -176,7 +176,6 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE } pos = ++pos & mask; } - keys[pos] = o; } return false; } @@ -199,7 +198,6 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE } pos = ++pos & mask; } - keys[pos] = o; } return false; } diff --git a/src/main/resources/speiger/assets/collections/templates/sets/RBTreeSet.template b/src/main/resources/speiger/assets/collections/templates/sets/RBTreeSet.template index 08302963..b972a1ee 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/RBTreeSet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/RBTreeSet.template @@ -701,13 +701,13 @@ public class RB_TREE_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE #if !TYPE_OBJECT @Override - public void setDefaultMaxValue(KEY_TYPE value) { throw new UnsupportedOperationException(); } + public void setDefaultMaxValue(KEY_TYPE value) { set.setDefaultMaxValue(value); } @Override public KEY_TYPE getDefaultMaxValue() { return set.getDefaultMaxValue(); } @Override - public void setDefaultMinValue(KEY_TYPE value) { throw new UnsupportedOperationException(); } + public void setDefaultMinValue(KEY_TYPE value) { set.setDefaultMinValue(value); } @Override public KEY_TYPE getDefaultMinValue() { return set.getDefaultMinValue(); } diff --git a/src/main/resources/speiger/assets/collections/templates/sets/SortedSet.template b/src/main/resources/speiger/assets/collections/templates/sets/SortedSet.template index ce4f4d14..845e2ae1 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/SortedSet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/SortedSet.template @@ -12,11 +12,9 @@ import speiger.src.collections.PACKAGE.functions.COMPARATOR; public interface SORTED_SET KEY_GENERIC_TYPE extends SET KEY_GENERIC_TYPE, SortedSet { public boolean addAndMoveToFirst(KEY_TYPE o); - public boolean addAndMoveToLast(KEY_TYPE o); public boolean moveToFirst(KEY_TYPE o); - public boolean moveToLast(KEY_TYPE o); @Override @@ -24,32 +22,24 @@ public interface SORTED_SET KEY_GENERIC_TYPE extends SET KEY_GENERIC_TYPE, Sorte @Override public BI_ITERATOR KEY_GENERIC_TYPE iterator(); - public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement); #if !TYPE_OBJECT public SORTED_SET KEY_GENERIC_TYPE subSet(KEY_TYPE fromElement, KEY_TYPE toElement); - public SORTED_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement); - public SORTED_SET KEY_GENERIC_TYPE tailSet(KEY_TYPE fromElement); public KEY_TYPE FIRST_KEY(); - public KEY_TYPE POLL_FIRST_KEY(); - public KEY_TYPE LAST_KEY(); - public KEY_TYPE POLL_LAST_KEY(); @Override @Deprecated public default SORTED_SET KEY_GENERIC_TYPE subSet(CLASS_TYPE fromElement, CLASS_TYPE toElement) { return subSet(OBJ_TO_KEY(fromElement), OBJ_TO_KEY(toElement)); } - @Override @Deprecated public default SORTED_SET KEY_GENERIC_TYPE headSet(CLASS_TYPE toElement) { return headSet(OBJ_TO_KEY(toElement)); } - @Override @Deprecated public default SORTED_SET KEY_GENERIC_TYPE tailSet(CLASS_TYPE fromElement) { return tailSet(OBJ_TO_KEY(fromElement)); } @@ -57,21 +47,17 @@ public interface SORTED_SET KEY_GENERIC_TYPE extends SET KEY_GENERIC_TYPE, Sorte @Override @Deprecated public default CLASS_TYPE first() { return KEY_TO_OBJ(FIRST_KEY()); } - @Override @Deprecated default CLASS_TYPE last() { return KEY_TO_OBJ(LAST_KEY()); } #else public CLASS_TYPE pollFirst(); - public CLASS_TYPE pollLast(); @Override public SORTED_SET KEY_GENERIC_TYPE subSet(CLASS_TYPE fromElement, CLASS_TYPE toElement); - @Override public SORTED_SET KEY_GENERIC_TYPE headSet(CLASS_TYPE toElement); - @Override public SORTED_SET KEY_GENERIC_TYPE tailSet(CLASS_TYPE fromElement); #endif diff --git a/src/main/resources/speiger/assets/collections/templates/utils/Iterators.template b/src/main/resources/speiger/assets/collections/templates/utils/Iterators.template index 964e952c..ffe09658 100644 --- a/src/main/resources/speiger/assets/collections/templates/utils/Iterators.template +++ b/src/main/resources/speiger/assets/collections/templates/utils/Iterators.template @@ -24,6 +24,44 @@ public class ITERATORS #endif } + public static GENERIC_KEY_BRACES BI_ITERATOR KEY_GENERIC_TYPE invert(BI_ITERATOR KEY_GENERIC_TYPE it) { + return new BI_ITERATOR KEY_GENERIC_TYPE() { + @Override + public KEY_TYPE NEXT() { return it.PREVIOUS(); } + @Override + public boolean hasNext() { return it.hasPrevious(); } + @Override + public boolean hasPrevious() { return it.hasNext(); } + @Override + public KEY_TYPE PREVIOUS() { return it.NEXT(); } + @Override + public void remove() { it.remove(); } + }; + } + + public static GENERIC_KEY_BRACES LIST_ITERATOR KEY_GENERIC_TYPE invert(LIST_ITERATOR KEY_GENERIC_TYPE it) { + return new LIST_ITERATOR KEY_GENERIC_TYPE() { + @Override + public KEY_TYPE NEXT() { return it.PREVIOUS(); } + @Override + public boolean hasNext() { return it.hasPrevious(); } + @Override + public boolean hasPrevious() { return it.hasNext(); } + @Override + public KEY_TYPE PREVIOUS() { return it.NEXT(); } + @Override + public void remove() { it.remove(); } + @Override + public int nextIndex() { return it.previousIndex(); } + @Override + public int previousIndex() { return it.nextIndex(); } + @Override + public void set(KEY_TYPE e) { it.set(e); } + @Override + public void add(KEY_TYPE e) { it.add(e); } + }; + } + /** * Returns a Immutable Iterator instance based on the instance given. * @param l that should be made immutable/unmodifyable