diff --git a/src/main/java/speiger/src/builder/example/ClassType.java b/src/main/java/speiger/src/builder/example/ClassType.java index 0bba91ec..fa9a265c 100644 --- a/src/main/java/speiger/src/builder/example/ClassType.java +++ b/src/main/java/speiger/src/builder/example/ClassType.java @@ -79,14 +79,30 @@ public enum ClassType return this == BYTE || this == SHORT || this == CHAR || this == FLOAT; } - public String getEquals() + public boolean needsCast() + { + return this == BYTE || this == SHORT || this == CHAR; + } + + public String getComparableValue() { switch(this) { - case DOUBLE: return "Double.doubleToLongBits(%1$s) == Double.doubleToLongBits(%2$s)"; - case FLOAT: return "Float.floatToIntBits(%1$s) == Float.floatToIntBits(%2$s)"; - case OBJECT: return "Objects.equals(%1$s, %2$s)"; - default: return "%1$s == %2$s"; + case DOUBLE: return "Double.doubleToLongBits(%1$s)"; + case FLOAT: return "Float.floatToIntBits(%1$s)"; + case OBJECT: return "%1$s"; + default: return "%1$s"; + } + } + + public String getEquals(boolean not) + { + switch(this) + { + case DOUBLE: return "Double.doubleToLongBits(%1$s) "+(not ? "!=" : "==")+" Double.doubleToLongBits(%2$s)"; + case FLOAT: return "Float.floatToIntBits(%1$s) "+(not ? "!=" : "==")+" Float.floatToIntBits(%2$s)"; + case OBJECT: return (not ? "!" : "")+"Objects.equals(%1$s, %2$s)"; + default: return "%1$s "+(not ? "!=" : "==")+" %2$s"; } } diff --git a/src/main/java/speiger/src/builder/example/GlobalVariables.java b/src/main/java/speiger/src/builder/example/GlobalVariables.java index 660285c6..4fe30c25 100644 --- a/src/main/java/speiger/src/builder/example/GlobalVariables.java +++ b/src/main/java/speiger/src/builder/example/GlobalVariables.java @@ -52,13 +52,16 @@ public class GlobalVariables public GlobalVariables createHelperVariables() { addArgumentMapper("EQUALS_KEY_TYPE", type.isObject() ? "Objects.equals(%2$s, %1$s)" : "Objects.equals(%2$s, KEY_TO_OBJ(%1$s))").removeBraces(); - addArgumentMapper("EQUALS", type.getEquals()).removeBraces(); + addInjectMapper("EQUALS_NOT_NULL", type.getComparableValue()+" != "+(type.isPrimitiveBlocking() ? type.getEmptyValue() : (type.needsCast() ? type.getEmptyValue() : "0"))).removeBraces(); + addInjectMapper("EQUALS_NULL", type.getComparableValue()+" == "+(type.isPrimitiveBlocking() ? type.getEmptyValue() : (type.needsCast() ? type.getEmptyValue() : "0"))).removeBraces(); + addArgumentMapper("EQUALS_NOT", type.getEquals(true)).removeBraces(); + addArgumentMapper("EQUALS", type.getEquals(false)).removeBraces(); addArgumentMapper("COMPARE_TO", type.isObject() ? "%1$s.compareTo(%2$s)" : type.getClassType()+".compare(%1$s, %2$s)").removeBraces(); addInjectMapper("KEY_TO_OBJ", type.isObject() ? "%s" : type.getClassType()+".valueOf(%s)").removeBraces(); addInjectMapper("OBJ_TO_KEY", type.isObject() ? "%s" : "%s."+type.getKeyType()+"Value()").removeBraces(); addInjectMapper("CLASS_TO_KEY", "(("+type.getClassType()+")%s)."+type.getKeyType()+"Value()").removeBraces(); addSimpleMapper("APPLY", "applyAs"+type.getCustomJDKType().getNonFileType()); - addInjectMapper("HASH", type.getClassType()+".hashCode(%s)").removeBraces(); + addInjectMapper("TO_HASH", type.isObject() ? "%s.hashCode()" : type.getClassType()+".hashCode(%s)").removeBraces(); return this; } @@ -67,6 +70,34 @@ public class GlobalVariables addSimpleMapper("JAVA_PREDICATE", type.isPrimitiveBlocking() ? "" : type.getCustomJDKType().getFileType()+"Predicate"); addSimpleMapper("JAVA_CONSUMER", type.isPrimitiveBlocking() ? "" : "java.util.function."+type.getCustomJDKType().getFileType()+"Consumer"); addSimpleMapper("UNARY_OPERATOR", type.isObject() ? "" : type == ClassType.BOOLEAN ? "BinaryOperator" : type.getCustomJDKType().getFileType()+"UnaryOperator"); + + //Final Classes + addClassMapper("ARRAY_LIST", "ArrayList"); + addClassMapper("LINKED_HASH_SET", "LinkedOpenHashSet"); + addClassMapper("HASH_SET", "OpenHashSet"); + + //Abstract Classes + addClassMapper("ABSTRACT_COLLECTION", "AbstractCollection"); + addClassMapper("ABSTRACT_SET", "AbstractSet"); + addClassMapper("ABSTRACT_LIST", "AbstractList"); + addClassMapper("SUB_LIST", "SubList"); + + //Helper Classes + addClassMapper("LISTS", "Lists"); + addClassMapper("COLLECTIONS", "Collections"); + addClassMapper("ARRAYS", "Arrays"); + addClassMapper("ITERATORS", "Iterators"); + + //Interfaces + addClassMapper("LIST_ITERATOR", "ListIterator"); + addClassMapper("BI_ITERATOR", "BidirectionalIterator"); + addClassMapper("ITERATOR", "Iterator"); + addClassMapper("ITERABLE", "Iterable"); + addClassMapper("COLLECTION", "Collection"); + addClassMapper("LIST", "List"); + addClassMapper("SORTED_SET", "SortedSet"); + addClassMapper("SET", "Set"); + addClassMapper("STACK", "Stack"); if(type.isObject()) { addSimpleMapper("CONSUMER", "Consumer"); @@ -79,22 +110,8 @@ public class GlobalVariables addClassMapper("COMPARATOR", "Comparator"); addFunctionMappers("IARRAY", "I%sArray"); } - addClassMapper("ITERATORS", "Iterators"); - addClassMapper("BI_ITERATOR", "BidirectionalIterator"); - addClassMapper("LIST_ITERATOR", "ListIterator"); - addClassMapper("ITERATOR", "Iterator"); - addClassMapper("ITERABLE", "Iterable"); - addClassMapper("ABSTRACT_COLLECTION", "AbstractCollection"); - addClassMapper("COLLECTIONS", "Collections"); - addClassMapper("COLLECTION", "Collection"); - addClassMapper("ARRAYS", "Arrays"); - addClassMapper("ABSTRACT_LIST", "AbstractList"); + //Dependency addClassMapper("LIST_ITER", "ListIter"); - addClassMapper("LISTS", "Lists"); - addClassMapper("SUB_LIST", "SubList"); - addClassMapper("ARRAY_LIST", "ArrayList"); - addClassMapper("LIST", "List"); - addClassMapper("STACK", "Stack"); return this; } @@ -112,6 +129,10 @@ public class GlobalVariables addFunctionMapper("TOP", "top"); addFunctionMappers("REPLACE", "replace%ss"); addFunctionMappers("SORT", "sort%ss"); + addFunctionMapper("POLL_FIRST_KEY", "pollFirst"); + addFunctionMapper("FIRST_KEY", "first"); + addFunctionMapper("POLL_LAST_KEY", "pollLast"); + addFunctionMapper("LAST_KEY", "last"); return this; } diff --git a/src/main/java/speiger/src/collections/utils/HashUtil.java b/src/main/java/speiger/src/collections/utils/HashUtil.java new file mode 100644 index 00000000..ae816ddb --- /dev/null +++ b/src/main/java/speiger/src/collections/utils/HashUtil.java @@ -0,0 +1,46 @@ +package speiger.src.collections.utils; + +public class HashUtil +{ + public static final int DEFAULT_MIN_CAPACITY = 16; + public static final float DEFAULT_LOAD_FACTOR = 0.75F; + public static final float FAST_LOAD_FACTOR = 0.5F; + public static final float FASTER_LOAD_FACTOR = 0.25F; + + private static final int INT_PHI = 0x9E3779B9; + private static final int INV_INT_PHI = 0x144cbc89; + + public static int mix(final int x) { + final int h = x * INT_PHI; + return h ^ (h >>> 16); + } + + public static int invMix(final int x) { + return (x ^ x >>> 16) * INV_INT_PHI; + } + + public static int nextPowerOfTwo(int x) { + if(x == 0) return 1; + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + return (x | x >> 16) + 1; + } + + public static long nextPowerOfTwo(long x) { + if(x == 0) return 1L; + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return (x | x >> 32) + 1L; + } + + public static int arraySize(int size, float loadFactor) { + return (int)Math.min(1 << 30, Math.max(2, nextPowerOfTwo((long)Math.ceil(size / loadFactor)))); + } +} diff --git a/src/main/java/speiger/src/collections/utils/ITrimmable.java b/src/main/java/speiger/src/collections/utils/ITrimmable.java index 24d55d3c..c2cd2ba5 100644 --- a/src/main/java/speiger/src/collections/utils/ITrimmable.java +++ b/src/main/java/speiger/src/collections/utils/ITrimmable.java @@ -9,13 +9,13 @@ public interface ITrimmable /** * Trims the original collection down to the size of the current elements */ - public default void trim() { - trim(0); + public default boolean trim() { + return trim(0); } /** * Trims the original collection down to the size of the current elements or the requested size depending which is bigger * @param size the requested trim size. */ - public void trim(int size); + public boolean trim(int size); } diff --git a/src/main/resources/speiger/assets/collections/templates/functions/Comparator.template b/src/main/resources/speiger/assets/collections/templates/functions/Comparator.template index e5f9033d..ed55dc68 100644 --- a/src/main/resources/speiger/assets/collections/templates/functions/Comparator.template +++ b/src/main/resources/speiger/assets/collections/templates/functions/Comparator.template @@ -32,6 +32,6 @@ public interface COMPARATOR extends Comparator */ public static COMPARATOR of(Comparator c) { Objects.requireNonNull(c); - return (K, V) -> c.compare(KEY_TO_OBJ(K), KEY_TO_OBJ(V)) + return (K, V) -> c.compare(KEY_TO_OBJ(K), KEY_TO_OBJ(V)); } } \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/lists/AbstractList.template b/src/main/resources/speiger/assets/collections/templates/lists/AbstractList.template index 5651c3b4..35319475 100644 --- a/src/main/resources/speiger/assets/collections/templates/lists/AbstractList.template +++ b/src/main/resources/speiger/assets/collections/templates/lists/AbstractList.template @@ -192,7 +192,7 @@ public abstract class ABSTRACT_LIST KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION #if TYPE_OBJECT hashCode = 31 * hashCode + i.next().hashCode(); #else - hashCode = 31 * hashCode + HASH(i.NEXT()); + hashCode = 31 * hashCode + TO_HASH(i.NEXT()); #endif return hashCode; } diff --git a/src/main/resources/speiger/assets/collections/templates/lists/ArrayList.template b/src/main/resources/speiger/assets/collections/templates/lists/ArrayList.template index a7df1930..87514c1e 100644 --- a/src/main/resources/speiger/assets/collections/templates/lists/ArrayList.template +++ b/src/main/resources/speiger/assets/collections/templates/lists/ArrayList.template @@ -637,12 +637,17 @@ public class ARRAY_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE @Override @Primitive public void replaceAll(UnaryOperator o) { +#if PRIMITIVES Objects.requireNonNull(o); -#if TYPE_OBJECT - REPLACE(T -> KEY_TO_OBJ(o.APPLY(OBJ_TO_KEY(T)))); +#if TYPE_BYTE || TYPE_SHORT || TYPE_CHAR || TYPE_FLOAT + REPLACE(T -> OBJ_TO_KEY(o.apply(KEY_TO_OBJ(SanityChecks.SANITY_CAST(T))))); #else - for(int i = 0;i OBJ_TO_KEY(o.apply(KEY_TO_OBJ(T)))); +#endif +#else + Objects.requireNonNull(o); + for(int i = 0;i size() || size() == data.length) return; + public boolean trim(int size) { + if(size > size() || size() == data.length) return false; int value = Math.min(size, size()); #if TYPE_OBJECT data = value == 0 ? (KEY_TYPE[])ARRAYS.EMPTY_ARRAY : Arrays.copyOf(data, value); #else data = value == 0 ? ARRAYS.EMPTY_ARRAY : Arrays.copyOf(data, value); #endif + return true; } /** diff --git a/src/main/resources/speiger/assets/collections/templates/sets/AbstractSet.template b/src/main/resources/speiger/assets/collections/templates/sets/AbstractSet.template new file mode 100644 index 00000000..d0730f33 --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/sets/AbstractSet.template @@ -0,0 +1,53 @@ +package speiger.src.collections.PACKAGE.sets; + +import java.util.Iterator; +import java.util.Objects; +import java.util.Set; + +import speiger.src.collections.PACKAGE.collections.ABSTRACT_COLLECTION; +import speiger.src.collections.PACKAGE.collections.ITERATOR; + +public abstract class ABSTRACT_SET KEY_GENERIC_TYPE extends ABSTRACT_COLLECTION KEY_GENERIC_TYPE implements SET KEY_GENERIC_TYPE +{ + @Override + public int hashCode() { + int hashCode = 1; + ITERATOR KEY_GENERIC_TYPE i = iterator(); + while(i.hasNext()) +#if TYPE_OBJECT + hashCode = 31 * hashCode + i.next().hashCode(); +#else + hashCode = 31 * hashCode + TO_HASH(i.NEXT()); +#endif + return hashCode; + } + + @Override + public boolean equals(Object o) { + if (o == this) + return true; + if (!(o instanceof Set)) + return false; + Set l = (Set)o; + if(l.size() != size()) return false; +#if !TYPE_OBJECT + if(l instanceof SET) + { + ITERATOR e1 = iterator(); + ITERATOR e2 = ((SET)l).iterator(); + while (e1.hasNext() && e2.hasNext()) { + if(!(EQUALS(e1.NEXT(), e2.NEXT()))) + return false; + } + return !(e1.hasNext() || e2.hasNext()); + } +#endif + Iterator e1 = iterator(); + Iterator e2 = l.iterator(); + while (e1.hasNext() && e2.hasNext()) { + if(!Objects.equals(e1.next(), e2.next())) + return false; + } + return !(e1.hasNext() || e2.hasNext()); + } +} diff --git a/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenHashSet.template b/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenHashSet.template new file mode 100644 index 00000000..cac5381e --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenHashSet.template @@ -0,0 +1,562 @@ +package speiger.src.collections.PACKAGE.sets; + +#if TYPE_OBJECT +import java.util.Comparator; +#endif +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +#if TYPE_OBJECT +import java.util.Objects; +#endif + +import speiger.src.collections.PACKAGE.collections.COLLECTION; +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.collections.ITERATOR; +#endif +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; +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.utils.ITERATORS; +#endif +import speiger.src.collections.utils.HashUtil; +import speiger.src.collections.utils.SanityChecks; + +public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE implements SORTED_SET KEY_GENERIC_TYPE +{ + protected long[] links; + protected int firstIndex = -1; + protected int lastIndex = -1; + + public LINKED_HASH_SET() { + this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public LINKED_HASH_SET(int minCapacity) { + this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public LINKED_HASH_SET(int minCapacity, float loadFactor) { + super(minCapacity, loadFactor); + links = new long[nullIndex + 1]; + } + + public LINKED_HASH_SET(KEY_TYPE[] array) { + this(array, 0, array.length, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public LINKED_HASH_SET(KEY_TYPE[] array, float loadFactor) { + this(array, 0, array.length, loadFactor); + } + + public LINKED_HASH_SET(KEY_TYPE[] array, int offset, int length) { + this(array, offset, length, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public LINKED_HASH_SET(KEY_TYPE[] array, int offset, int length, float loadFactor) { + this(length < 0 ? 0 : length); + SanityChecks.checkArrayCapacity(array.length, offset, length); + for(int i = 0;i collection) { + this(collection, HashUtil.DEFAULT_LOAD_FACTOR); + } + + @Deprecated + public LINKED_HASH_SET(Collection collection, float loadFactor) { + this(collection.size(), loadFactor); + addAll(collection); + } + + public LINKED_HASH_SET(COLLECTION KEY_GENERIC_TYPE collection) { + this(collection, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public LINKED_HASH_SET(COLLECTION KEY_GENERIC_TYPE collection, float loadFactor) { + this(collection.size()); + addAll(collection); + } + + public LINKED_HASH_SET(Iterator iterator) { + this(iterator, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public LINKED_HASH_SET(Iterator iterator, float loadFactor) { +#if !TYPE_OBJECT + this(ITERATORS.wrap(iterator), loadFactor); +#else + this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor); + while(iterator.hasNext()) add(iterator.next()); +#endif + } + +#if !TYPE_OBJECT + public LINKED_HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator) { + this(iterator, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public LINKED_HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator, float loadFactor) { + this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor); + while(iterator.hasNext()) add(iterator.NEXT()); + } + +#endif + @Override + public boolean addAndMoveToFirst(KEY_TYPE o) { + if(EQUALS_NULL(o)) { + if(containsNull) { + moveToFirstIndex(nullIndex); + return false; + } + containsNull = true; + onNodeAdded(nullIndex); + } + else { + int pos = HashUtil.mix(TO_HASH(o)) & mask; + while(EQUALS_NOT_NULL(keys[pos])) { + if(EQUALS(keys[pos], o)) { + moveToFirstIndex(pos); + return false; + } + pos = ++pos & mask; + } + keys[pos] = o; + onNodeAdded(pos); + } + if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); + return true; + } + + @Override + public boolean addAndMoveToLast(KEY_TYPE o) { + if(EQUALS_NULL(o)) { + if(containsNull) { + moveToLastIndex(nullIndex); + return false; + } + containsNull = true; + onNodeAdded(nullIndex); + } + else { + int pos = HashUtil.mix(TO_HASH(o)) & mask; + while(EQUALS_NOT_NULL(keys[pos])) { + if(EQUALS(keys[pos], o)) { + moveToLastIndex(pos); + return false; + } + pos = ++pos & mask; + } + keys[pos] = o; + onNodeAdded(pos); + } + if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); + return true; + } + + @Override + public boolean moveToFirst(KEY_TYPE o) { + if(EQUALS_NULL(o)) { + if(containsNull) { + moveToFirstIndex(nullIndex); + return true; + } + } + else { + int pos = HashUtil.mix(TO_HASH(o)) & mask; + while(EQUALS_NOT_NULL(keys[pos])) { + if(EQUALS(keys[pos], o)) { + moveToFirstIndex(pos); + return true; + } + pos = ++pos & mask; + } + keys[pos] = o; + } + return false; + } + + @Override + public boolean moveToLast(KEY_TYPE o) { + if(EQUALS_NULL(o)) { + if(containsNull) { + moveToLastIndex(nullIndex); + return true; + } + } + else { + int pos = HashUtil.mix(TO_HASH(o)) & mask; + while(EQUALS_NOT_NULL(keys[pos])) { + if(EQUALS(keys[pos], o)) { + moveToLastIndex(pos); + return true; + } + pos = ++pos & mask; + } + keys[pos] = o; + } + return false; + } + + 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] = ((-1 & 0xFFFFFFFFL) << 32) | (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) | (-1 & 0xFFFFFFFFL); + lastIndex = startPos; + } + + @Override + public KEY_TYPE FIRST_KEY() { + if(size == 0) throw new NoSuchElementException(); + return keys[firstIndex]; + } + + @Override + public KEY_TYPE POLL_FIRST_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(EQUALS_NULL(result)) { + containsNull = false; + keys[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_KEY() { + if(size == 0) throw new NoSuchElementException(); + return keys[lastIndex]; + } + + @Override + public KEY_TYPE POLL_LAST_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(EQUALS_NULL(result)) { + containsNull = false; + keys[nullIndex] = EMPTY_VALUE; + } + else shiftKeys(pos); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return result; + } + + @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) | (-1 & 0xFFFFFFFFL); + lastIndex = pos; + } + } + + @Override + protected void onNodeRemoved(int pos) { + if(size == 0) firstIndex = lastIndex = 0; + 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; +#if TYPE_OBJECT + KEY_TYPE[] newKeys = (KEY_TYPE[])new Object[newSize + 1]; +#else + KEY_TYPE[] newKeys = new KEY_TYPE[newSize + 1]; +#endif + long[] newLinks = new long[newSize + 1]; + int newPrev = -1; + for(int j = size, i = firstIndex, pos = 0, prev = -1;j != 0;) { + if(EQUALS_NULL(keys[i])) pos = newSize; + else { + pos = HashUtil.mix(TO_HASH(keys[i])) & newMask; + while(EQUALS_NOT_NULL(newKeys[pos])) pos = ++pos & newMask; + } + newKeys[pos] = keys[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; + } + + @Override + public void clear() { + super.clear(); + firstIndex = lastIndex = -1; + } + + @Override + public LIST_ITERATOR KEY_GENERIC_TYPE iterator() { + return new SetIterator(); + } + + @Override + public BI_ITERATOR KEY_GENERIC_TYPE iterator(KEY_TYPE fromElement) { + return new SetIterator(fromElement); + } + + @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 SetIterator implements LIST_ITERATOR KEY_GENERIC_TYPE { + int previous = -1; + int next = -1; + int current = -1; + int index = 0; + + SetIterator() { + next = firstIndex; + } + + SetIterator(KEY_TYPE from) { + if(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(EQUALS(keys[lastIndex], from)) { + previous = lastIndex; + index = size; + } + else { + int pos = HashUtil.mix(TO_HASH(from)) & mask; + while(EQUALS_NOT_NULL(keys[pos])) { + if(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"); + } + } + + @Override + public boolean hasNext() { + return next != -1; + } + + @Override + public boolean hasPrevious() { + return previous != -1; + } + + @Override + public int nextIndex() { + ensureIndexKnown(); + return index; + } + + @Override + public int previousIndex() { + ensureIndexKnown(); + return index - 1; + } + + @Override + 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_VALUE; + } + else { + int slot, last, startPos = current; + current = -1; + KEY_TYPE current; + while(true) { + last = ((last = startPos) + 1) & mask; + while(true){ + if(EQUALS_NULL((current = keys[startPos]))) { + keys[last] = EMPTY_VALUE; + return; + } + slot = HashUtil.mix(TO_HASH(current)) & mask; + if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; + startPos = ++startPos & mask; + } + keys[last] = current; + if(next == startPos) next = last; + if(previous == startPos) previous = last; + onNodeMoved(startPos, last); + } + } + } + + @Override + public KEY_TYPE PREVIOUS() { + if(!hasPrevious()) throw new NoSuchElementException(); + current = previous; + previous = (int)(links[current] >> 32); + next = current; + if(index >= 0) index--; + return keys[current]; + } + + @Override + public KEY_TYPE NEXT() { + if(!hasPrevious()) throw new NoSuchElementException(); + current = next; + next = (int)(links[current]); + previous = current; + if(index >= 0) index++; + return keys[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++); + } + } + } + +#if TYPE_OBJECT + @Override + public void set(Object e) { throw new UnsupportedOperationException(); } + + @Override + public void add(Object e) { throw new UnsupportedOperationException(); } +#else + @Override + public void set(KEY_TYPE e) { throw new UnsupportedOperationException(); } + + @Override + public void add(KEY_TYPE e) { throw new UnsupportedOperationException(); } +#endif + } +} diff --git a/src/main/resources/speiger/assets/collections/templates/sets/OpenHashSet.template b/src/main/resources/speiger/assets/collections/templates/sets/OpenHashSet.template new file mode 100644 index 00000000..60bf2ea5 --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/sets/OpenHashSet.template @@ -0,0 +1,379 @@ +package speiger.src.collections.PACKAGE.sets; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +#if TYPE_OBJECT +import java.util.Objects; +#endif + +import speiger.src.collections.PACKAGE.collections.COLLECTION; +import speiger.src.collections.PACKAGE.collections.ITERATOR; +import speiger.src.collections.PACKAGE.lists.ARRAY_LIST; +import speiger.src.collections.PACKAGE.lists.LIST; +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.utils.ITERATORS; +#endif +import speiger.src.collections.utils.HashUtil; +import speiger.src.collections.utils.ITrimmable; +import speiger.src.collections.utils.SanityChecks; + +public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE implements ITrimmable +{ + protected transient KEY_TYPE[] keys; + protected transient boolean containsNull; + protected transient int minCapacity; + protected transient int nullIndex; + protected transient int maxFill; + protected transient int mask; + + protected int size; + protected final float loadFactor; + + public HASH_SET() { + this(HashUtil.DEFAULT_MIN_CAPACITY, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public HASH_SET(int minCapacity) { + this(minCapacity, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public HASH_SET(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); +#if TYPE_OBJECT + keys = (KEY_TYPE[])new Object[nullIndex + 1]; +#else + keys = new KEY_TYPE[nullIndex + 1]; +#endif + } + + public HASH_SET(KEY_TYPE[] array) { + this(array, 0, array.length, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public HASH_SET(KEY_TYPE[] array, float loadFactor) { + this(array, 0, array.length, loadFactor); + } + + public HASH_SET(KEY_TYPE[] array, int offset, int length) { + this(array, offset, length, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public HASH_SET(KEY_TYPE[] array, int offset, int length, float loadFactor) { + this(length < 0 ? 0 : length); + SanityChecks.checkArrayCapacity(array.length, offset, length); + for(int i = 0;i collection) { + this(collection, HashUtil.DEFAULT_LOAD_FACTOR); + } + + @Deprecated + public HASH_SET(Collection collection, float loadFactor) { + this(collection.size(), loadFactor); + addAll(collection); + } + + public HASH_SET(COLLECTION KEY_GENERIC_TYPE collection) { + this(collection, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public HASH_SET(COLLECTION KEY_GENERIC_TYPE collection, float loadFactor) { + this(collection.size()); + addAll(collection); + } + + public HASH_SET(Iterator iterator) { + this(iterator, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public HASH_SET(Iterator iterator, float loadFactor) { +#if !TYPE_OBJECT + this(ITERATORS.wrap(iterator), loadFactor); +#else + this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor); + while(iterator.hasNext()) add(iterator.next()); +#endif + } + +#if !TYPE_OBJECT + public HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator) { + this(iterator, HashUtil.DEFAULT_LOAD_FACTOR); + } + + public HASH_SET(ITERATOR KEY_GENERIC_TYPE iterator, float loadFactor) { + this(HashUtil.DEFAULT_MIN_CAPACITY, loadFactor); + while(iterator.hasNext()) add(iterator.NEXT()); + } + +#endif + @Override + public boolean add(KEY_TYPE o) { + if(EQUALS_NULL(o)) { + if(containsNull) return false; + containsNull = true; + onNodeAdded(nullIndex); + } + else { + int pos = HashUtil.mix(TO_HASH(o)) & mask; + KEY_TYPE current = keys[pos]; + if(EQUALS_NOT_NULL(current)) { + if(EQUALS(current, o)) return false; + while(EQUALS_NOT_NULL((current = keys[++pos & mask]))) + if(EQUALS(current, o)) return false; + } + keys[pos] = o; + onNodeAdded(pos); + } + if(size++ >= maxFill) rehash(HashUtil.arraySize(size+1, loadFactor)); + return true; + } + + @Override + @Deprecated + public boolean addAll(Collection c) { + if(loadFactor <= 0.5F) ensureCapacity(c.size()); + else ensureCapacity(c.size() + size()); + return super.addAll(c); + } + + @Override + public boolean addAll(COLLECTION KEY_GENERIC_TYPE c) { + if(loadFactor <= 0.5F) ensureCapacity(c.size()); + else ensureCapacity(c.size() + size()); + return super.addAll(c); + } + +#if TYPE_OBJECT + @Override + public boolean contains(Object o) { + if(EQUALS_NULL(o)) return containsNull; + int pos = HashUtil.mix(TO_HASH(o)) & mask; + KEY_TYPE current = keys[pos]; + if(EQUALS_NULL(current)) return false; + if(EQUALS(current, o)) return true; + while(true) { + if(EQUALS_NULL((current = keys[++pos & mask]))) return false; + else if(EQUALS(current, o)) return true; + } + } + + @Override + public boolean remove(Object o) { + if(EQUALS_NULL(o)) return (containsNull ? removeNullIndex() : false); + int pos = HashUtil.mix(TO_HASH(o)) & mask; + KEY_TYPE current = keys[pos]; + if(EQUALS_NULL(current)) return false; + if(EQUALS(current, o)) return removeIndex(pos); + while(true) { + if(EQUALS_NULL((current = keys[++pos & mask]))) return false; + else if(EQUALS(current, o)) return removeIndex(pos); + } + } + +#else + @Override + public boolean contains(KEY_TYPE o) { + if(EQUALS_NULL(o)) return containsNull; + int pos = HashUtil.mix(TO_HASH(o)) & mask; + KEY_TYPE current = keys[pos]; + if(EQUALS_NULL(current)) return false; + if(EQUALS(current, o)) return true; + while(true) { + if(EQUALS_NULL((current = keys[++pos & mask]))) return false; + else if(EQUALS(current, o)) return true; + } + } + + @Override + public boolean remove(KEY_TYPE o) { + if(EQUALS_NULL(o)) return (containsNull ? removeNullIndex() : false); + int pos = HashUtil.mix(TO_HASH(o)) & mask; + KEY_TYPE current = keys[pos]; + if(EQUALS_NULL(current)) return false; + if(EQUALS(current, o)) return removeIndex(pos); + while(true) { + if(EQUALS_NULL((current = keys[++pos & mask]))) return false; + else if(EQUALS(current, o)) return removeIndex(pos); + } + } + +#endif + @Override + public boolean trim(int size) { + int newSize = HashUtil.nextPowerOfTwo((int)Math.ceil(size / loadFactor)); + if(newSize >= nullIndex || size >= Math.min((int)Math.ceil(newSize * loadFactor), newSize - 1)) return false; + try { + rehash(newSize); + } + catch(OutOfMemoryError e) { return false; } + return true; + } + + private void ensureCapacity(int newCapacity) { + int size = HashUtil.arraySize(newCapacity, loadFactor); + if(size > nullIndex) rehash(size); + } + + protected boolean removeIndex(int pos) { + size--; + onNodeRemoved(pos); + shiftKeys(pos); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return true; + } + + protected boolean removeNullIndex() { + containsNull = false; + keys[nullIndex] = EMPTY_VALUE; + size--; + onNodeRemoved(nullIndex); + if(nullIndex > minCapacity && size < maxFill / 4 && nullIndex > HashUtil.DEFAULT_MIN_CAPACITY) rehash(nullIndex / 2); + return true; + } + + 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(EQUALS_NULL((current = keys[startPos]))) { + keys[last] = EMPTY_VALUE; + return; + } + slot = HashUtil.mix(TO_HASH(current)) & mask; + if(last <= startPos ? (last >= slot || slot > startPos) : (last >= slot && slot > startPos)) break; + startPos = ++startPos & mask; + } + keys[last] = current; + onNodeMoved(startPos, last); + } + } + + protected void rehash(int newSize) { + int newMask = newSize - 1; +#if TYPE_OBJECT + KEY_TYPE[] newKeys = (KEY_TYPE[])new Object[newSize + 1]; +#else + KEY_TYPE[] newKeys = new KEY_TYPE[newSize + 1]; +#endif + for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) { + while(EQUALS_NULL(keys[--i])); + if(EQUALS_NOT_NULL(newKeys[pos = HashUtil.mix(TO_HASH(keys[i])) & newMask])) + while(EQUALS_NOT_NULL(newKeys[++pos & newMask])); + newKeys[pos] = keys[i]; + } + nullIndex = newSize; + mask = newMask; + maxFill = Math.min((int)Math.ceil(nullIndex * loadFactor), nullIndex - 1); + keys = newKeys; + } + + @Override + public ITERATOR KEY_GENERIC_TYPE iterator() { + return new SetIterator(); + } + + @Override + public void clear() { + if(size == 0) return; + size = 0; + containsNull = false; + Arrays.fill(keys, EMPTY_VALUE); + } + + @Override + public int size() { + return size; + } + + private class SetIterator implements ITERATOR KEY_GENERIC_TYPE { + int pos = nullIndex; + int lastReturned = -1; + int count = size; + boolean returnNull = containsNull; + LIST KEY_GENERIC_TYPE wrapped = null; + + @Override + public boolean hasNext() { + return count != 0; + } + + @Override + public KEY_TYPE NEXT() { + if(count != 0) throw new NoSuchElementException(); + count--; + if(returnNull) { + returnNull = false; + lastReturned = nullIndex; + return keys[nullIndex]; + } + while(true) { + if(pos-- < 0) { + lastReturned = Integer.MAX_VALUE; + return wrapped.GET_KEY(-pos - 1); + } + if(EQUALS_NOT_NULL(keys[pos])) return keys[lastReturned = pos]; + } + } + + @Override + public void remove() { + if(lastReturned == -1) throw new IllegalStateException(); + if(lastReturned == nullIndex) { + containsNull = false; + keys[nullIndex] = EMPTY_VALUE; + } + else if(pos >= 0) shiftKeys(pos); + else { + HASH_SET.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(EQUALS_NULL((current = keys[startPos]))) { + keys[last] = EMPTY_VALUE; + return; + } + slot = HashUtil.mix(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[pos]); + } + keys[last] = current; + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/sets/Set.template b/src/main/resources/speiger/assets/collections/templates/sets/Set.template new file mode 100644 index 00000000..93505596 --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/sets/Set.template @@ -0,0 +1,39 @@ +package speiger.src.collections.PACKAGE.sets; + +import java.util.Set; + +import speiger.src.collections.PACKAGE.collections.COLLECTION; +import speiger.src.collections.PACKAGE.collections.ITERATOR; + +public interface SET KEY_GENERIC_TYPE extends Set, COLLECTION KEY_GENERIC_TYPE +{ + @Override + public ITERATOR KEY_GENERIC_TYPE iterator(); + +#if !TYPE_OBJECT + public boolean remove(KEY_TYPE o); + + @Override + public default boolean REMOVE_KEY(KEY_TYPE o) { + return remove(o); + } + + @Override + @Primitive + public default boolean add(CLASS_TYPE e) { + return COLLECTION.super.add(e); + } + + @Override + @Primitive + public default boolean contains(Object o) { + return COLLECTION.super.contains(o); + } + + @Override + @Primitive + public default boolean remove(Object o) { + return COLLECTION.super.remove(o); + } +#endif +} \ No newline at end of file diff --git a/src/main/resources/speiger/assets/collections/templates/sets/SortedSet.template b/src/main/resources/speiger/assets/collections/templates/sets/SortedSet.template new file mode 100644 index 00000000..c76db4d5 --- /dev/null +++ b/src/main/resources/speiger/assets/collections/templates/sets/SortedSet.template @@ -0,0 +1,73 @@ +package speiger.src.collections.PACKAGE.sets; + +import java.util.SortedSet; + +import speiger.src.collections.PACKAGE.collections.BI_ITERATOR; +#if TYPE_OBJECT +import java.util.Comparator; +#else +import speiger.src.collections.PACKAGE.functions.COMPARATOR; +#endif + +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 + public COMPARATOR KEY_GENERIC_TYPE comparator(); + + @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 + 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 + public default SORTED_SET KEY_GENERIC_TYPE headSet(CLASS_TYPE toElement) { return headSet(OBJ_TO_KEY(toElement)); } + + @Override + public default SORTED_SET KEY_GENERIC_TYPE tailSet(CLASS_TYPE fromElement) { return tailSet(OBJ_TO_KEY(fromElement)); } + + @Override + public default CLASS_TYPE first() { return KEY_TO_OBJ(FIRST_KEY()); } + + @Override + 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 a2ef972c..bcd10eb3 100644 --- a/src/main/resources/speiger/assets/collections/templates/utils/Iterators.template +++ b/src/main/resources/speiger/assets/collections/templates/utils/Iterators.template @@ -41,6 +41,12 @@ public class ITERATORS return iterator instanceof UnmodifiableListIterator ? iterator : new UnmodifiableListIteratorBRACES(iterator); } +#if !TYPE_OBJECT + public static ITERATOR wrap(Iterator iterator) { + return iterator instanceof ITERATOR ? (ITERATOR)iterator : new IteratorWrapper(iterator); + } + +#endif /** * Returns a Array Wrapping iterator * @param a the array that should be wrapped @@ -182,6 +188,31 @@ public class ITERATORS return index; } + private static class IteratorWrapper implements ITERATOR + { + Iterator iter; + + public IteratorWrapper(Iterator iter) { + this.iter = iter; + } + + @Override + public boolean hasNext() { + return iter.hasNext(); + } + + @Override + public KEY_TYPE NEXT() { + return OBJ_TO_KEY(iter.next()); + } + + @Override + @Deprecated + public CLASS_TYPE next() { + return iter.next(); + } + } + #endif private static class UnmodifiableListIterator KEY_GENERIC_TYPE implements LIST_ITERATOR KEY_GENERIC_TYPE { diff --git a/src/main/resources/speiger/assets/collections/templates/utils/Lists.template b/src/main/resources/speiger/assets/collections/templates/utils/Lists.template index 176a79bf..321a8eb8 100644 --- a/src/main/resources/speiger/assets/collections/templates/utils/Lists.template +++ b/src/main/resources/speiger/assets/collections/templates/utils/Lists.template @@ -77,7 +77,7 @@ public class LISTS public void ensureCapacity(int size) { synchronized(mutex) { l.ensureCapacity(size); } } @Override - public void trim(int size) { synchronized(mutex) { l.trim(size); } } + public boolean trim(int size) { synchronized(mutex) { return l.trim(size); } } @Override public KEY_TYPE[] elements() { synchronized(mutex) { return l.elements(); } }