From c0c719f2b676a15a09c6f85363d3f628d3432e77 Mon Sep 17 00:00:00 2001 From: Speiger Date: Fri, 8 Jan 2021 21:12:20 +0100 Subject: [PATCH] Next big batch of features. -Added: Tests for IntSortedSet, IntNavigableSet. -Added: Test Classes for: Open/Custom/Linked HashSet, TreeSets, ArraySet -Changed: MemFreeMergeSort got improved by a lot. -Fixed: Bugs that the tests uncovered. -Note: TreeSets still have issues. But every other collection type is fixed. --- .../src/builder/example/GlobalVariables.java | 1 + .../collections/AbstractCollection.template | 17 +- .../templates/lists/ArrayList.template | 82 +-------- .../templates/sets/AVLTreeSet.template | 40 +++- .../templates/sets/ArraySet.template | 174 +++++++++++++----- .../sets/LinkedOpenCustomHashSet.template | 18 +- .../templates/sets/LinkedOpenHashSet.template | 18 +- .../templates/sets/OpenCustomHashSet.template | 79 ++++---- .../templates/sets/OpenHashSet.template | 72 ++++---- .../templates/sets/RBTreeSet.template | 40 +++- .../templates/utils/Arrays.template | 145 +++++++++++---- .../templates/utils/Iterators.template | 6 +- .../ints/base/BaseIntCollectionTest.java | 18 +- .../ints/base/BaseIntIterableTest.java | 2 +- .../ints/base/BaseIntNavigableSetTest.java | 81 ++++++++ .../ints/base/BaseIntSortedSetTest.java | 90 +++++++++ .../ints/sets/IntAVLTreeSetTests.java | 17 ++ .../ints/sets/IntArraySetTests.java | 9 + .../ints/sets/IntHashSetTests.java | 50 +++++ .../ints/sets/IntRBTreeSetTests.java | 18 ++ .../src/collections/ints/utils/JavaTests.java | 29 +++ .../collections/tests/NavigableSetTest.java | 12 ++ .../src/collections/tests/SortedSetTest.java | 12 ++ 23 files changed, 765 insertions(+), 265 deletions(-) create mode 100644 src/test/java/speiger/src/collections/ints/base/BaseIntNavigableSetTest.java create mode 100644 src/test/java/speiger/src/collections/ints/base/BaseIntSortedSetTest.java create mode 100644 src/test/java/speiger/src/collections/ints/sets/IntAVLTreeSetTests.java create mode 100644 src/test/java/speiger/src/collections/ints/sets/IntArraySetTests.java create mode 100644 src/test/java/speiger/src/collections/ints/sets/IntHashSetTests.java create mode 100644 src/test/java/speiger/src/collections/ints/sets/IntRBTreeSetTests.java create mode 100644 src/test/java/speiger/src/collections/ints/utils/JavaTests.java create mode 100644 src/test/java/speiger/src/collections/tests/NavigableSetTest.java create mode 100644 src/test/java/speiger/src/collections/tests/SortedSetTest.java diff --git a/src/main/java/speiger/src/builder/example/GlobalVariables.java b/src/main/java/speiger/src/builder/example/GlobalVariables.java index f8e58b57..3f982fa3 100644 --- a/src/main/java/speiger/src/builder/example/GlobalVariables.java +++ b/src/main/java/speiger/src/builder/example/GlobalVariables.java @@ -63,6 +63,7 @@ public class GlobalVariables addInjectMapper("CLASS_TO_KEY", "(("+type.getClassType()+")%s)."+type.getKeyType()+"Value()").removeBraces(); addSimpleMapper("APPLY", "applyAs"+type.getCustomJDKType().getNonFileType()); addInjectMapper("TO_HASH", type.isObject() ? "%s.hashCode()" : type.getClassType()+".hashCode(%s)").removeBraces(); + addInjectMapper("NEW_KEY_ARRAY", type.isObject() ? "(KEY_TYPE[])new Object[%s]" : "new KEY_TYPE[%s]").removeBraces(); return this; } diff --git a/src/main/resources/speiger/assets/collections/templates/collections/AbstractCollection.template b/src/main/resources/speiger/assets/collections/templates/collections/AbstractCollection.template index b6a73e7f..21e0b64e 100644 --- a/src/main/resources/speiger/assets/collections/templates/collections/AbstractCollection.template +++ b/src/main/resources/speiger/assets/collections/templates/collections/AbstractCollection.template @@ -75,8 +75,8 @@ public abstract class ABSTRACT_COLLECTION KEY_GENERIC_TYPE extends AbstractColle @Override public boolean containsAll(COLLECTION KEY_GENERIC_TYPE c) { Objects.requireNonNull(c); - for(KEY_TYPE e : this) - if(!c.contains(e)) + for(KEY_TYPE e : c) + if(!contains(e)) return false; return true; } @@ -92,8 +92,8 @@ public abstract class ABSTRACT_COLLECTION KEY_GENERIC_TYPE extends AbstractColle @Primitive public boolean containsAny(Collection c) { Objects.requireNonNull(c); - for(KEY_TYPE e : this) - if(c.contains(KEY_TO_OBJ(e))) + for(Object e : c) + if(contains(e)) return true; return false; } @@ -107,8 +107,8 @@ public abstract class ABSTRACT_COLLECTION KEY_GENERIC_TYPE extends AbstractColle @Override public boolean containsAny(COLLECTION KEY_GENERIC_TYPE c) { Objects.requireNonNull(c); - for(KEY_TYPE e : this) - if(c.contains(e)) + for(KEY_TYPE e : c) + if(contains(e)) return true; return false; } @@ -168,6 +168,11 @@ public abstract class ABSTRACT_COLLECTION KEY_GENERIC_TYPE extends AbstractColle @Override public boolean retainAll(COLLECTION KEY_GENERIC_TYPE c) { Objects.requireNonNull(c); + if(c.isEmpty()) { + boolean modified = !isEmpty(); + clear(); + return modified; + } boolean modified = false; for(ITERATOR KEY_GENERIC_TYPE iter = iterator();iter.hasNext();) { if(!c.contains(iter.NEXT())) { 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 e2b5e16a..5a80a8bb 100644 --- a/src/main/resources/speiger/assets/collections/templates/lists/ArrayList.template +++ b/src/main/resources/speiger/assets/collections/templates/lists/ArrayList.template @@ -76,11 +76,7 @@ public class ARRAY_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE * Creates a new ArrayList with the specific requested size */ public ARRAY_LIST(int size) { -#if TYPE_OBJECT - data = (KEY_TYPE[])new Object[size]; -#else - data = new KEY_TYPE[size]; -#endif + data = NEW_KEY_ARRAY(size); } /** @@ -358,49 +354,6 @@ public class ARRAY_LIST KEY_GENERIC_TYPE extends ABSTRACT_LIST KEY_GENERIC_TYPE } #endif - /** - * A function to check if all elements requested are present in the other collection. - * This function might delegate to a more appropiate function if nessesary - * @param c the collection that should be checked - * @return true if the collection contains all elements in this list - * @throws NullPointerException if the collection is null - * @deprecated if the collection is type-specific - */ - @Override - @Primitive - public boolean containsAll(Collection c) { - Objects.requireNonNull(c); - for(int i = 0,m=size;i c) { - Objects.requireNonNull(c); - for(int i = 0,m=size;i collection) { + addAll(collection); + } + + public AVL_TREE_SET(COLLECTION KEY_GENERIC_TYPE collection) { + addAll(collection); + } + + public AVL_TREE_SET(Iterator iterator) { +#if !TYPE_OBJECT + this(ITERATORS.wrap(iterator)); +#else + while(iterator.hasNext()) add(iterator.next()); +#endif + } + + public AVL_TREE_SET(ITERATOR KEY_GENERIC_TYPE iterator) { + while(iterator.hasNext()) add(iterator.NEXT()); + } + #if !TYPE_OBJECT @Override public void setDefaultMaxValue(KEY_TYPE value) { defaultMaxNotFound = value; } 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 c8350058..3d9ce424 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/ArraySet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/ArraySet.template @@ -31,11 +31,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im } public ARRAY_SET(int capacity) { -#if TYPE_OBJECT - data = (KEY_TYPE[])new Object[capacity]; -#else - data = new KEY_TYPE[capacity]; -#endif + data = NEW_KEY_ARRAY(capacity); } public ARRAY_SET(KEY_TYPE[] array) { @@ -43,7 +39,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im } public ARRAY_SET(KEY_TYPE[] array, int length) { - data = array; + data = Arrays.copyOf(array, length); size = length; } @@ -94,7 +90,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im else if(index != 0) { o = data[index]; System.arraycopy(data, 0, data, 1, index); - data[index] = o; + data[0] = o; } return false; } @@ -110,7 +106,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im else if(index != size - 1) { o = data[index]; System.arraycopy(data, index+1, data, index, size - index); - data[size] = o; + data[size-1] = o; } return false; } @@ -121,7 +117,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im if(index > 0) { o = data[index]; System.arraycopy(data, 0, data, 1, index); - data[index] = o; + data[0] = o; return true; } return false; @@ -132,8 +128,8 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im int index = findIndex(o); if(index != -1 && index != size - 1) { o = data[index]; - System.arraycopy(data, index+1, data, index, size - index); - data[size] = o; + System.arraycopy(data, index+1, data, index, size - index - 1); + data[size-1] = o; return true; } return false; @@ -169,7 +165,11 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im public boolean remove(KEY_TYPE o) { int index = findIndex(o); if(index != -1) { - System.arraycopy(data, index+1, data, index, size - index); + size--; + if(index != size) System.arraycopy(data, index+1, data, index, size - index); +#if TYPE_OBJECT + data[size] = EMPTY_VALUE; +#endif return true; } return false; @@ -180,8 +180,11 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im public boolean remove(Object o) { int index = findIndex(o); if(index != -1) { - System.arraycopy(data, index+1, data, index, size - index); - data[size-1] = EMPTY_VALUE; + size--; + if(index != size) System.arraycopy(data, index+1, data, index, size - index); +#if TYPE_OBJECT + data[size] = EMPTY_VALUE; +#endif return true; } return false; @@ -192,7 +195,7 @@ 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); + System.arraycopy(data, 1, data, 0, size - 1); #if TYPE_OBJECT data[size-1] = EMPTY_VALUE; #endif @@ -202,12 +205,13 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im @Override public KEY_TYPE POLL_LAST_KEY() { if(size == 0) throw new NoSuchElementException(); + size--; #if TYPE_OBJECT - KEY_TYPE result = data[size-1]; - data[size-1] = EMPTY_VALUE; + KEY_TYPE result = data[size]; + data[size] = EMPTY_VALUE; return result; #else - return data[--size]; + return data[size]; #endif } @@ -242,14 +246,14 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im int fromIndex = findIndex(fromElement); int toIndex = findIndex(toElement); if(fromIndex == -1 || toIndex == -1) throw new NoSuchElementException(); - return new SubSet(fromIndex, toIndex - fromIndex); + return new SubSet(fromIndex, toIndex - fromIndex + 1); } @Override public SORTED_SET KEY_GENERIC_TYPE headSet(KEY_TYPE toElement) { int toIndex = findIndex(toElement); if(toIndex == -1) throw new NoSuchElementException(); - return new SubSet(0, toIndex); + return new SubSet(0, toIndex+1); } @Override @@ -282,14 +286,16 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im this.offset = offset; this.length = length; } + + int end() { return offset+length; } @Override public boolean add(KEY_TYPE o) { int index = findIndex(o); - if(index != -1) { + if(index == -1) { if(data.length == size) data = Arrays.copyOf(data, size == 0 ? 2 : size * 2); - System.arraycopy(data, (offset+length), data, (offset+length)+1, size-(offset+length)); - data[offset+length] = o; + if(end() != size) System.arraycopy(data, end(), data, end()+1, size-(offset+length)); + data[end()] = o; size++; length++; return true; @@ -321,8 +327,8 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im int index = findIndex(o); if(index == -1) { if(data.length == size) data = Arrays.copyOf(data, size == 0 ? 2 : size * 2); - System.arraycopy(data, (offset+length)+1, data, (offset+length), size-(offset+length)); - data[offset+length] = o; + System.arraycopy(data, end()+1, data, end(), size-end()); + data[end()] = o; size++; length++; return true; @@ -338,7 +344,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im @Override public boolean moveToFirst(KEY_TYPE o) { int index = findIndex(o); - if(index != -1 && index != offset) { + if(index > offset) { o = data[index]; System.arraycopy(data, offset, data, offset+1, index-offset); data[offset] = o; @@ -350,10 +356,10 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im @Override public boolean moveToLast(KEY_TYPE o) { int index = findIndex(o); - if(index != -1 && index != (offset+length) - 1) { + if(index != -1 && index < end()-1) { o = data[index]; - System.arraycopy(data, offset+1, data, offset, index-offset); - data[offset+length] = o; + System.arraycopy(data, index+1, data, index, end()-index-1); + data[end()-1] = o; return true; } return false; @@ -380,7 +386,7 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im @Override public KEY_TYPE LAST_KEY() { if(length == 0) throw new NoSuchElementException(); - return data[(offset + length) - 1]; + return data[end()-1]; } #if !TYPE_OBJECT @@ -388,9 +394,9 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im public boolean remove(KEY_TYPE o) { int index = findIndex(o); if(index != -1) { - System.arraycopy(data, index+1, data, index, size - index); size--; length--; + if(index != size) System.arraycopy(data, index+1, data, index, size - index); return true; } return false; @@ -401,10 +407,12 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im public boolean remove(Object o) { int index = findIndex(o); if(index != -1) { - System.arraycopy(data, index+1, data, index, size - index); - data[size-1] = EMPTY_VALUE; size--; length--; + if(index != size) System.arraycopy(data, index+1, data, index, size - index); +#if TYPE_OBJECT + data[size] = EMPTY_VALUE; +#endif return true; } return false; @@ -413,13 +421,13 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im @Override public KEY_TYPE POLL_FIRST_KEY() { if(length == 0) throw new NoSuchElementException(); + size--; + length--; KEY_TYPE result = data[offset]; System.arraycopy(data, offset+1, data, offset, size-offset); #if TYPE_OBJECT - data[size-1] = EMPTY_VALUE; + data[size] = EMPTY_VALUE; #endif - size--; - length--; return result; } @@ -427,12 +435,12 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im public KEY_TYPE POLL_LAST_KEY() { if(length == 0) throw new NoSuchElementException(); KEY_TYPE result = data[offset+length]; - System.arraycopy(data, (offset+length)+1, data, (offset+length), size-(offset+length)); -#if TYPE_OBJECT - data[size-1] = EMPTY_VALUE; -#endif size--; length--; + System.arraycopy(data, end()+1, data, end(), size-end()); +#if TYPE_OBJECT + data[size] = EMPTY_VALUE; +#endif return result; } @@ -482,17 +490,99 @@ public class ARRAY_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE im #if !TYPE_OBJECT protected int findIndex(KEY_TYPE o) { - for(int i = size-1;i>=0;i--) + for(int i = length-1;i>=0;i--) if(EQUALS(data[offset+i], o)) return i + offset; return -1; } #endif protected int findIndex(Object o) { - for(int i = size-1;i>=0;i--) + for(int i = length-1;i>=0;i--) if(EQUALS_KEY_TYPE(data[offset+i], o)) return i + offset; return -1; } + + private class SetIterator implements LIST_ITERATOR KEY_GENERIC_TYPE { + int index; + int lastReturned = -1; + + public SetIterator(int index) { + this.index = index; + } + + @Override + public boolean hasNext() { + return index < size(); + } + + @Override + public KEY_TYPE NEXT() { + lastReturned = index; + return data[index++]; + } + + @Override + public boolean hasPrevious() { + return index > 0; + } + + @Override + public KEY_TYPE PREVIOUS() { + lastReturned = index; + return data[index--]; + } + + @Override + public int nextIndex() { + return index; + } + + @Override + public int previousIndex() { + return index-1; + } + + @Override + public void remove() { + if(lastReturned == -1) + throw new IllegalStateException(); + SubSet.this.remove(data[lastReturned]); + if(lastReturned < index) + index--; + lastReturned = -1; + } + + #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 + @Override + 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; + } + + @Override + 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 SetIterator implements LIST_ITERATOR KEY_GENERIC_TYPE { 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 8381f0e3..e35d63d6 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenCustomHashSet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenCustomHashSet.template @@ -158,6 +158,7 @@ public class LINKED_CUSTOM_HASH_SET KEY_GENERIC_TYPE extends CUSTOM_HASH_SET KEY @Override public boolean moveToFirst(KEY_TYPE o) { + if(strategy.equals(FIRST_KEY(), o)) return false; if(strategy.equals(o, EMPTY_VALUE)) { if(containsNull) { moveToFirstIndex(nullIndex); @@ -180,6 +181,7 @@ public class LINKED_CUSTOM_HASH_SET KEY_GENERIC_TYPE extends CUSTOM_HASH_SET KEY @Override public boolean moveToLast(KEY_TYPE o) { + if(strategy.equals(LAST_KEY(), o)) return false; if(strategy.equals(o, EMPTY_VALUE)) { if(containsNull) { moveToLastIndex(nullIndex); @@ -290,14 +292,14 @@ public class LINKED_CUSTOM_HASH_SET KEY_GENERIC_TYPE extends CUSTOM_HASH_SET KEY } else { links[lastIndex] ^= ((links[lastIndex] ^ (pos & 0xFFFFFFFFL)) & 0xFFFFFFFFL); - links[pos] = ((lastIndex & 0xFFFFFFFFL) << 32) | (-1 & 0xFFFFFFFFL); + links[pos] = ((lastIndex & 0xFFFFFFFFL) << 32) | 0xFFFFFFFFL; lastIndex = pos; } } @Override protected void onNodeRemoved(int pos) { - if(size == 0) firstIndex = lastIndex = 0; + if(size == 0) firstIndex = lastIndex = -1; else if(firstIndex == pos) { firstIndex = (int)links[pos]; if(0 <= firstIndex) links[firstIndex] |= 0xFFFFFFFF00000000L; @@ -344,11 +346,7 @@ public class LINKED_CUSTOM_HASH_SET KEY_GENERIC_TYPE extends CUSTOM_HASH_SET KEY @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 + KEY_TYPE[] newKeys = NEW_KEY_ARRAY(newSize + 1); long[] newLinks = new long[newSize + 1]; int newPrev = -1; for(int j = size, i = firstIndex, pos = 0, prev = -1;j != 0;) { @@ -471,7 +469,7 @@ public class LINKED_CUSTOM_HASH_SET KEY_GENERIC_TYPE extends CUSTOM_HASH_SET KEY ensureIndexKnown(); if(current == previous) { index--; - previous = (int)(links[current] >> 32); + previous = (int)(links[current] >>> 32); } else next = (int)links[current]; size--; @@ -490,7 +488,7 @@ public class LINKED_CUSTOM_HASH_SET KEY_GENERIC_TYPE extends CUSTOM_HASH_SET KEY current = -1; KEY_TYPE current; while(true) { - last = ((last = startPos) + 1) & mask; + startPos = ((last = startPos) + 1) & mask; while(true){ if(strategy.equals((current = keys[startPos]), EMPTY_VALUE)) { keys[last] = EMPTY_VALUE; @@ -520,7 +518,7 @@ public class LINKED_CUSTOM_HASH_SET KEY_GENERIC_TYPE extends CUSTOM_HASH_SET KEY @Override public KEY_TYPE NEXT() { - if(!hasPrevious()) throw new NoSuchElementException(); + if(!hasNext()) throw new NoSuchElementException(); current = next; next = (int)(links[current]); previous = current; 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 e212a4a8..fd3df0f0 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenHashSet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/LinkedOpenHashSet.template @@ -160,6 +160,7 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE @Override public boolean moveToFirst(KEY_TYPE o) { + if(EQUALS(FIRST_KEY(), o)) return false; if(EQUALS_NULL(o)) { if(containsNull) { moveToFirstIndex(nullIndex); @@ -182,6 +183,7 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE @Override public boolean moveToLast(KEY_TYPE o) { + if(EQUALS(LAST_KEY(), o)) return false; if(EQUALS_NULL(o)) { if(containsNull) { moveToLastIndex(nullIndex); @@ -292,14 +294,14 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE } else { links[lastIndex] ^= ((links[lastIndex] ^ (pos & 0xFFFFFFFFL)) & 0xFFFFFFFFL); - links[pos] = ((lastIndex & 0xFFFFFFFFL) << 32) | (-1 & 0xFFFFFFFFL); + links[pos] = ((lastIndex & 0xFFFFFFFFL) << 32) | 0xFFFFFFFFL; lastIndex = pos; } } @Override protected void onNodeRemoved(int pos) { - if(size == 0) firstIndex = lastIndex = 0; + if(size == 0) firstIndex = lastIndex = -1; else if(firstIndex == pos) { firstIndex = (int)links[pos]; if(0 <= firstIndex) links[firstIndex] |= 0xFFFFFFFF00000000L; @@ -346,11 +348,7 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE @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 + KEY_TYPE[] newKeys = NEW_KEY_ARRAY(newSize + 1); long[] newLinks = new long[newSize + 1]; int newPrev = -1; for(int j = size, i = firstIndex, pos = 0, prev = -1;j != 0;) { @@ -473,7 +471,7 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE ensureIndexKnown(); if(current == previous) { index--; - previous = (int)(links[current] >> 32); + previous = (int)(links[current] >>> 32); } else next = (int)links[current]; size--; @@ -492,7 +490,7 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE current = -1; KEY_TYPE current; while(true) { - last = ((last = startPos) + 1) & mask; + startPos = ((last = startPos) + 1) & mask; while(true){ if(EQUALS_NULL((current = keys[startPos]))) { keys[last] = EMPTY_VALUE; @@ -522,7 +520,7 @@ public class LINKED_HASH_SET KEY_GENERIC_TYPE extends HASH_SET KEY_GENERIC_TYPE @Override public KEY_TYPE NEXT() { - if(!hasPrevious()) throw new NoSuchElementException(); + if(!hasNext()) throw new NoSuchElementException(); current = next; next = (int)(links[current]); previous = current; diff --git a/src/main/resources/speiger/assets/collections/templates/sets/OpenCustomHashSet.template b/src/main/resources/speiger/assets/collections/templates/sets/OpenCustomHashSet.template index ad15878b..9c20c5bb 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/OpenCustomHashSet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/OpenCustomHashSet.template @@ -46,11 +46,7 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T 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 + keys = NEW_KEY_ARRAY(nullIndex + 1); this.strategy = strategy; } @@ -132,7 +128,7 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T KEY_TYPE current = keys[pos]; if(!strategy.equals(current, EMPTY_VALUE)) { if(strategy.equals(current, o)) return false; - while(!strategy.equals((current = keys[++pos & mask]), EMPTY_VALUE)) + while(!strategy.equals((current = keys[pos = (++pos & mask)]), EMPTY_VALUE)) if(strategy.equals(current, o)) return false; } keys[pos] = o; @@ -163,10 +159,10 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T if(strategy.equals((KEY_TYPE)o, EMPTY_VALUE)) return containsNull; int pos = HashUtil.mix(strategy.hashCode((KEY_TYPE)o)) & mask; KEY_TYPE current = keys[pos]; - if(!strategy.equals(current, EMPTY_VALUE)) return false; + if(strategy.equals(current, EMPTY_VALUE)) return false; if(strategy.equals(current, (KEY_TYPE)o)) return true; while(true) { - if(strategy.equals((current = keys[++pos & mask]), EMPTY_VALUE)) return false; + if(strategy.equals((current = keys[pos = (++pos & mask)]), EMPTY_VALUE)) return false; else if(strategy.equals(current, (KEY_TYPE)o)) return true; } } @@ -176,10 +172,10 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T if(strategy.equals((KEY_TYPE)o, EMPTY_VALUE)) return (containsNull ? removeNullIndex() : false); int pos = HashUtil.mix(strategy.hashCode((KEY_TYPE)o)) & mask; KEY_TYPE current = keys[pos]; - if(!strategy.equals(current, EMPTY_VALUE)) return false; + if(strategy.equals(current, EMPTY_VALUE)) return false; if(strategy.equals(current, (KEY_TYPE)o)) return removeIndex(pos); while(true) { - if(strategy.equals((current = keys[++pos & mask]), EMPTY_VALUE)) return false; + if(strategy.equals((current = keys[pos = (++pos & mask)]), EMPTY_VALUE)) return false; else if(strategy.equals(current, (KEY_TYPE)o)) return removeIndex(pos); } } @@ -190,10 +186,10 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T if(strategy.equals(o, EMPTY_VALUE)) return containsNull; int pos = HashUtil.mix(strategy.hashCode(o)) & mask; KEY_TYPE current = keys[pos]; - if(!strategy.equals(current, EMPTY_VALUE)) return false; + if(strategy.equals(current, EMPTY_VALUE)) return false; if(strategy.equals(current, o)) return true; while(true) { - if(strategy.equals((current = keys[++pos & mask]), EMPTY_VALUE)) return false; + if(strategy.equals((current = keys[pos = (++pos & mask)]), EMPTY_VALUE)) return false; else if(strategy.equals(current, o)) return true; } } @@ -203,10 +199,10 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T if(strategy.equals(o, EMPTY_VALUE)) return (containsNull ? removeNullIndex() : false); int pos = HashUtil.mix(strategy.hashCode(o)) & mask; KEY_TYPE current = keys[pos]; - if(!strategy.equals(current, EMPTY_VALUE)) return false; + if(strategy.equals(current, EMPTY_VALUE)) return false; if(strategy.equals(current, o)) return removeIndex(pos); while(true) { - if(strategy.equals((current = keys[++pos & mask]), EMPTY_VALUE)) return false; + if(strategy.equals((current = keys[pos = (++pos & mask)]), EMPTY_VALUE)) return false; else if(strategy.equals(current, o)) return removeIndex(pos); } } @@ -278,15 +274,11 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T 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 + KEY_TYPE[] newKeys = NEW_KEY_ARRAY(newSize + 1); for(int i = nullIndex, pos = 0, j = (size - (containsNull ? 1 : 0));j-- != 0;) { while(strategy.equals(keys[--i], EMPTY_VALUE)); if(!strategy.equals(newKeys[pos = HashUtil.mix(TO_HASH(keys[i])) & newMask], EMPTY_VALUE)) - while(!strategy.equals(newKeys[++pos & newMask], EMPTY_VALUE)); + while(!strategy.equals(newKeys[pos = (++pos & newMask)], EMPTY_VALUE)); newKeys[pos] = keys[i]; } nullIndex = newSize; @@ -316,31 +308,46 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T private class SetIterator implements ITERATOR KEY_GENERIC_TYPE { int pos = nullIndex; int lastReturned = -1; - int count = size; + int nextIndex = Integer.MIN_VALUE; boolean returnNull = containsNull; LIST KEY_GENERIC_TYPE wrapped = null; @Override public boolean hasNext() { - return count != 0; + 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(EQUALS_NOT_NULL(keys[pos])){ + nextIndex = pos; + break; + } + } + } + } + return nextIndex != Integer.MIN_VALUE; } @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(!strategy.equals(keys[pos], EMPTY_VALUE)) return keys[lastReturned = pos]; + if(!hasNext()) throw new NoSuchElementException(); + if(nextIndex < 0){ + lastReturned = Integer.MAX_VALUE; + KEY_TYPE value = wrapped.GET_KEY(nextIndex); + nextIndex = Integer.MIN_VALUE; + return value; } + KEY_TYPE value = keys[(lastReturned = nextIndex)]; + nextIndex = Integer.MIN_VALUE; + return value; } @Override @@ -375,7 +382,7 @@ public class CUSTOM_HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_T } if(startPos < last) { if(wrapped == null) wrapped = new ARRAY_LISTBRACES(2); - wrapped.add(keys[pos]); + wrapped.add(keys[startPos]); } keys[last] = current; } diff --git a/src/main/resources/speiger/assets/collections/templates/sets/OpenHashSet.template b/src/main/resources/speiger/assets/collections/templates/sets/OpenHashSet.template index 60f10ee6..9d53a9d2 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/OpenHashSet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/OpenHashSet.template @@ -44,11 +44,7 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp 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 + keys = NEW_KEY_ARRAY(nullIndex + 1); } public HASH_SET(KEY_TYPE[] array) { @@ -125,7 +121,7 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp KEY_TYPE current = keys[pos]; if(EQUALS_NOT_NULL(current)) { if(EQUALS(current, o)) return false; - while(EQUALS_NOT_NULL((current = keys[++pos & mask]))) + while(EQUALS_NOT_NULL((current = keys[pos = (++pos & mask)]))) if(EQUALS(current, o)) return false; } keys[pos] = o; @@ -158,7 +154,7 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp if(EQUALS_NULL(current)) return false; if(EQUALS_KEY_TYPE(current, o)) return true; while(true) { - if(EQUALS_NULL((current = keys[++pos & mask]))) return false; + if(EQUALS_NULL((current = keys[pos = (++pos & mask)]))) return false; else if(EQUALS_KEY_TYPE(current, o)) return true; } } @@ -171,7 +167,7 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp if(EQUALS_NULL(current)) return false; if(EQUALS_KEY_TYPE(current, o)) return removeIndex(pos); while(true) { - if(EQUALS_NULL((current = keys[++pos & mask]))) return false; + if(EQUALS_NULL((current = keys[pos = (++pos & mask)]))) return false; else if(EQUALS_KEY_TYPE(current, o)) return removeIndex(pos); } } @@ -185,7 +181,7 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp if(EQUALS_NULL(current)) return false; if(EQUALS(current, o)) return true; while(true) { - if(EQUALS_NULL((current = keys[++pos & mask]))) return false; + if(EQUALS_NULL((current = keys[pos = (++pos & mask)]))) return false; else if(EQUALS(current, o)) return true; } } @@ -198,7 +194,7 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp if(EQUALS_NULL(current)) return false; if(EQUALS(current, o)) return removeIndex(pos); while(true) { - if(EQUALS_NULL((current = keys[++pos & mask]))) return false; + if(EQUALS_NULL((current = keys[pos = (++pos & mask)]))) return false; else if(EQUALS(current, o)) return removeIndex(pos); } } @@ -270,15 +266,11 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp 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 + KEY_TYPE[] newKeys = NEW_KEY_ARRAY(newSize + 1); 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])); + while(EQUALS_NOT_NULL(newKeys[pos = (++pos & newMask)])); newKeys[pos] = keys[i]; } nullIndex = newSize; @@ -308,31 +300,47 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp private class SetIterator implements ITERATOR KEY_GENERIC_TYPE { int pos = nullIndex; int lastReturned = -1; - int count = size; + int nextIndex = Integer.MIN_VALUE; boolean returnNull = containsNull; LIST KEY_GENERIC_TYPE wrapped = null; @Override public boolean hasNext() { - return count != 0; + 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(EQUALS_NOT_NULL(keys[pos])){ + nextIndex = pos; + break; + } + } + } + } + return nextIndex != Integer.MIN_VALUE; } @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]; + if(!hasNext()) throw new NoSuchElementException(); + if(nextIndex < 0){ + lastReturned = Integer.MAX_VALUE; + KEY_TYPE value = wrapped.GET_KEY(nextIndex); + nextIndex = Integer.MIN_VALUE; + return value; } + KEY_TYPE value = keys[(lastReturned = nextIndex)]; + nextIndex = Integer.MIN_VALUE; + return value; } @Override @@ -367,7 +375,7 @@ public class HASH_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE imp } if(startPos < last) { if(wrapped == null) wrapped = new ARRAY_LISTBRACES(2); - wrapped.add(keys[pos]); + wrapped.add(keys[startPos]); } keys[last] = current; } 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 02171b8e..068dc59c 100644 --- a/src/main/resources/speiger/assets/collections/templates/sets/RBTreeSet.template +++ b/src/main/resources/speiger/assets/collections/templates/sets/RBTreeSet.template @@ -1,14 +1,22 @@ package speiger.src.collections.PACKAGE.sets; -import java.util.NoSuchElementException; +import java.util.Collection; #if TYPE_OBJECT import java.util.Comparator; #endif +import java.util.Iterator; +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.collections.COLLECTION; +import speiger.src.collections.PACKAGE.collections.ITERATOR; import speiger.src.collections.PACKAGE.lists.LIST_ITERATOR; +#if !TYPE_OBJECT +import speiger.src.collections.PACKAGE.utils.ITERATORS; +#endif +import speiger.src.collections.utils.SanityChecks; public class RB_TREE_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE implements NAVIGABLE_SET KEY_GENERIC_TYPE { @@ -30,6 +38,36 @@ public class RB_TREE_SET KEY_GENERIC_TYPE extends ABSTRACT_SET KEY_GENERIC_TYPE public RB_TREE_SET() { } + public RB_TREE_SET(KEY_TYPE[] array) { + this(array, 0, array.length); + } + + public RB_TREE_SET(KEY_TYPE[] array, int offset, int length) { + SanityChecks.checkArrayCapacity(array.length, offset, length); + for(int i = 0;i collection) { + addAll(collection); + } + + public RB_TREE_SET(COLLECTION KEY_GENERIC_TYPE collection) { + addAll(collection); + } + + public RB_TREE_SET(Iterator iterator) { +#if !TYPE_OBJECT + this(ITERATORS.wrap(iterator)); +#else + while(iterator.hasNext()) add(iterator.next()); +#endif + } + + public RB_TREE_SET(ITERATOR KEY_GENERIC_TYPE iterator) { + while(iterator.hasNext()) add(iterator.NEXT()); + } + #if !TYPE_OBJECT @Override public void setDefaultMaxValue(KEY_TYPE value) { defaultMaxNotFound = value; } diff --git a/src/main/resources/speiger/assets/collections/templates/utils/Arrays.template b/src/main/resources/speiger/assets/collections/templates/utils/Arrays.template index 9cfcaeb1..020c0d68 100644 --- a/src/main/resources/speiger/assets/collections/templates/utils/Arrays.template +++ b/src/main/resources/speiger/assets/collections/templates/utils/Arrays.template @@ -624,21 +624,36 @@ public class ARRAYS i++; else if(compare == 0) swap(array, ++i, j); else { - swap(array, i++, j); int k = j; - for(;k < to - 1 && comp.compare(array[j], array[k + 1]) > 0;k++); - if(j == k) + for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); continue; - KEY_TYPE value = array[j]; - System.arraycopy(array, j + 1, array, j, k - j); - array[k] = value; + } + else if(j + 1 == k) { + KEY_TYPE value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + KEY_TYPE[] data = NEW_KEY_ARRAY(k - j); + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; } } } /** * Sorts an array according to the natural ascending order using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger * @param array the array that needs to be sorted */ public static COMPAREABLE_BRACES void memFreeMergeSort(KEY_TYPE[] array) { @@ -646,8 +661,11 @@ public class ARRAYS } /** - * Sorts an array according to the natural ascending order using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * Sorts an array according to the natural ascending order using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger * @param array the array that needs to be sorted * @param length the maxmium size of the array to be sorted */ @@ -656,8 +674,11 @@ public class ARRAYS } /** - * Sorts an array according to the natural ascending order using Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * Sorts an array according to the natural ascending order using Memory Free Merge Sort, + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger * @param array the array that needs to be sorted * @param from where the array should be sorted from * @param to where the array should be sorted to @@ -677,21 +698,36 @@ public class ARRAYS i++; else if(comp == 0) swap(array, ++i, j); else { - swap(array, i++, j); int k = j; - for(;k < to - 1 && COMPARE_TO(array[j], array[k + 1]) > 0;k++); - if(j == k) + for(;k < to - 1 && COMPARE_TO(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); continue; - KEY_TYPE value = array[j]; - System.arraycopy(array, j + 1, array, j, k - j); - array[k] = value; + } + else if(j + 1 == k) { + KEY_TYPE value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + KEY_TYPE[] data = NEW_KEY_ARRAY(k - j); + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; } } } /** * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger * @param array the array that needs to be sorted * @param comp the Comparator that decides the sorting order * @Note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed @@ -702,7 +738,10 @@ public class ARRAYS /** * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger * @param array the array that needs to be sorted * @param length the maxmium size of the array to be sorted * @param comp the Comparator that decides the sorting order @@ -714,7 +753,10 @@ public class ARRAYS /** * Sorts the specified range of elements according to the order induced by the specified comparator using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger * @param array the array that needs to be sorted * @param from where the array should be sorted from * @param to where the array should be sorted to @@ -731,7 +773,10 @@ public class ARRAYS /** * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger * @param array the array that needs to be sorted * @Note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed */ @@ -741,7 +786,10 @@ public class ARRAYS /** * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger * @param array the array that needs to be sorted * @param length the maxmium size of the array to be sorted * @Note This parallelization is invoked through {@link SanityChecks#invokeTask} which the threadpool can be changed as needed @@ -752,7 +800,10 @@ public class ARRAYS /** * Sorts an array according to the natural ascending order using Parallel Memory Free Merge Sort, - * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. It is in Very Unsorted Instances 50% slower then Mergesort, otherwise it as fast. + * This implementation is inspired by FastUtil original merge sort, but without the need to allocate a copy of the original Array. + * It is depending on the size and the unsorted level of the input array slower or almost as fast as normal merge sort. Depending on the test size i can be 0.5x slower (5000 elements) or 4x slower (50000 elements) under the assumtion that the array is in its worst case scenario. + * It does stack allocate tiny amounts of data for shifting around elements. + * @author Speiger * @param array the array that needs to be sorted * @param from where the array should be sorted from * @param to where the array should be sorted to @@ -1174,14 +1225,26 @@ public class ARRAYS i++; else if(comp == 0) swap(array, ++i, j); else { - swap(array, i++, j); int k = j; - for(;k < to - 1 && COMPARE_TO(array[j], array[k + 1]) > 0;k++); - if(j == k) + for(;k < to - 1 && COMPARE_TO(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); continue; - KEY_TYPE value = array[j]; - System.arraycopy(array, j + 1, array, j, k - j); - array[k] = value; + } + else if(j + 1 == k) { + KEY_TYPE value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + KEY_TYPE[] data = NEW_KEY_ARRAY(k - j); + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; } } } @@ -1219,14 +1282,26 @@ public class ARRAYS i++; else if(compare == 0) swap(array, ++i, j); else { - swap(array, i++, j); int k = j; - for(;k < to - 1 && comp.compare(array[j], array[k + 1]) > 0;k++); - if(j == k) + for(;k < to - 1 && comp.compare(array[i], array[k + 1]) > 0;k++); + if(j == k) { + swap(array, i++, j); continue; - KEY_TYPE value = array[j]; - System.arraycopy(array, j + 1, array, j, k - j); - array[k] = value; + } + else if(j + 1 == k) { + KEY_TYPE value = array[j]; + System.arraycopy(array, i, array, i+1, j - i); + array[i] = value; + i++; + j++; + continue; + } + KEY_TYPE[] data = NEW_KEY_ARRAY(k - j); + System.arraycopy(array, j, data, 0, data.length); + System.arraycopy(array, i, array, i+data.length, j - i); + System.arraycopy(data, 0, array, i, data.length); + i+=data.length; + j+=data.length; } } } 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 f51c16e0..11483957 100644 --- a/src/main/resources/speiger/assets/collections/templates/utils/Iterators.template +++ b/src/main/resources/speiger/assets/collections/templates/utils/Iterators.template @@ -104,7 +104,7 @@ public class ITERATORS */ public static GENERIC_BRACES int unwrap(KEY_TYPE[] a, Iterator i, int offset, int max) { if(max < 0) throw new IllegalStateException("The max size is smaller then 0"); - if(offset + max >= a.length) throw new IllegalStateException("largest array index exceeds array size"); + if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size"); int index = 0; for(;index= a.length) throw new IllegalStateException("largest array index exceeds array size"); + if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size"); int index = 0; for(;index= a.length) throw new IllegalStateException("largest array index exceeds array size"); + if(offset + max > a.length) throw new IllegalStateException("largest array index exceeds array size"); int index = 0; for(;index getValidNavigableSetTests() { return EnumSet.allOf(NavigableSetTest.class); } + + @Test + public void lowerTest() { + if(getValidNavigableSetTests().contains(NavigableSetTest.LOWER)) { + Assert.assertTrue(create(TEST_ARRAY).lower(50) < 50); + } + } + + @Test + public void higherTest() { + if(getValidNavigableSetTests().contains(NavigableSetTest.HIGHER)) { + Assert.assertTrue(create(TEST_ARRAY).higher(50) > 50); + } + } + + @Test + public void ceilTest() { + if(getValidNavigableSetTests().contains(NavigableSetTest.CEILING)) { + Assert.assertTrue(create(TEST_ARRAY).ceiling(50) >= 50); + } + } + + @Test + public void floorTest() { + if(getValidNavigableSetTests().contains(NavigableSetTest.FLOOR)) { + Assert.assertTrue(create(TEST_ARRAY).floor(50) <= 50); + } + } + + @Test + public void naviSubSetTest() { + if(getValidNavigableSetTests().contains(NavigableSetTest.SUB_SET)) { + IntNavigableSet set = create(TEST_ARRAY); + IntNavigableSet subSet = set.subSet(25, 75); + Assert.assertTrue(subSet.lower(50) < 50); + Assert.assertTrue(subSet.higher(50) > 50); + Assert.assertTrue(subSet.ceiling(50) >= 50); + Assert.assertTrue(subSet.floor(50) <= 50); + } + } + + @Test + public void naviHeadSetTest() { + if(getValidNavigableSetTests().contains(NavigableSetTest.HEAD_SET)) { + IntNavigableSet set = create(TEST_ARRAY); + IntNavigableSet subSet = set.headSet(75); + Assert.assertTrue(subSet.lower(50) < 50); + Assert.assertTrue(subSet.higher(50) > 50); + Assert.assertTrue(subSet.ceiling(50) >= 50); + Assert.assertTrue(subSet.floor(50) <= 50); + } + } + + @Test + public void naviTailSetTest() { + if(getValidNavigableSetTests().contains(NavigableSetTest.TAIL_SET)) { + IntNavigableSet set = create(TEST_ARRAY); + IntNavigableSet subSet = set.tailSet(25); + Assert.assertTrue(subSet.lower(50) < 50); + Assert.assertTrue(subSet.higher(50) > 50); + Assert.assertTrue(subSet.ceiling(50) >= 50); + Assert.assertTrue(subSet.floor(50) <= 50); + } + } +} \ No newline at end of file diff --git a/src/test/java/speiger/src/collections/ints/base/BaseIntSortedSetTest.java b/src/test/java/speiger/src/collections/ints/base/BaseIntSortedSetTest.java new file mode 100644 index 00000000..87bd132c --- /dev/null +++ b/src/test/java/speiger/src/collections/ints/base/BaseIntSortedSetTest.java @@ -0,0 +1,90 @@ +package speiger.src.collections.ints.base; + +import java.util.EnumSet; + +import org.junit.Assert; +import org.junit.Test; + +import speiger.src.collections.ints.sets.IntSortedSet; +import speiger.src.collections.tests.SortedSetTest; + +public abstract class BaseIntSortedSetTest extends BaseIntCollectionTest +{ + @Override + protected abstract IntSortedSet create(int[] data); + + protected EnumSet getValidSortedSetTests() { return EnumSet.allOf(SortedSetTest.class); } + + @Test + public void addMoveTest() { + if(getValidSortedSetTests().contains(SortedSetTest.ADD_MOVE)) { + IntSortedSet set = create(TEST_ARRAY); + Assert.assertTrue(set.addAndMoveToFirst(1050)); + Assert.assertFalse(set.addAndMoveToLast(5)); + } + } + + @Test + public void moveTest() { + if(getValidSortedSetTests().contains(SortedSetTest.MOVE)) { + IntSortedSet set = create(TEST_ARRAY); + Assert.assertTrue(set.moveToFirst(5)); + Assert.assertFalse(set.moveToFirst(5)); + Assert.assertTrue(set.moveToLast(5)); + Assert.assertFalse(set.moveToLast(5)); + } + } + + @Test + public void peekTest() { + if(getValidSortedSetTests().contains(SortedSetTest.PEEK)) { + IntSortedSet set = create(TEST_ARRAY); + Assert.assertEquals(set.firstInt(), 0); + Assert.assertEquals(set.lastInt(), 99); + } + } + + @Test + public void pollTest() { + if(getValidSortedSetTests().contains(SortedSetTest.POLL)) { + IntSortedSet set = create(TEST_ARRAY); + Assert.assertEquals(set.pollFirstInt(), 0); + Assert.assertEquals(set.pollLastInt(), 99); + + } + } + + @Test + public void subSetTest() { + if(getValidSortedSetTests().contains(SortedSetTest.SUB_SET)) { + IntSortedSet set = create(TEST_ARRAY); + IntSortedSet subSet = set.subSet(25, 75); + Assert.assertTrue(subSet.remove(50)); + Assert.assertFalse(subSet.remove(50)); + Assert.assertFalse(subSet.contains(20)); + Assert.assertFalse(subSet.contains(80)); + } + } + + @Test + public void headSetTest() { + if(getValidSortedSetTests().contains(SortedSetTest.HEAD_SET)) { + IntSortedSet set = create(TEST_ARRAY); + IntSortedSet subSet = set.headSet(75); + Assert.assertTrue(subSet.remove(50)); + Assert.assertFalse(subSet.remove(50)); + Assert.assertFalse(subSet.contains(80)); + } + } + + @Test + public void tailSetTest() { + if(getValidSortedSetTests().contains(SortedSetTest.TAIL_SET)) { + IntSortedSet set = create(TEST_ARRAY); + IntSortedSet subSet = set.tailSet(25); + Assert.assertTrue(subSet.remove(50)); + Assert.assertFalse(subSet.remove(50)); + Assert.assertFalse(subSet.contains(20)); + } + } +} \ No newline at end of file diff --git a/src/test/java/speiger/src/collections/ints/sets/IntAVLTreeSetTests.java b/src/test/java/speiger/src/collections/ints/sets/IntAVLTreeSetTests.java new file mode 100644 index 00000000..6c2da68b --- /dev/null +++ b/src/test/java/speiger/src/collections/ints/sets/IntAVLTreeSetTests.java @@ -0,0 +1,17 @@ +package speiger.src.collections.ints.sets; + +import java.util.EnumSet; + +import speiger.src.collections.ints.base.BaseIntNavigableSetTest; +import speiger.src.collections.tests.SortedSetTest; + +public class IntAVLTreeSetTests extends BaseIntNavigableSetTest +{ + @Override + protected IntNavigableSet create(int[] data) { + return new IntAVLTreeSet(data); + } + + @Override + protected EnumSet getValidSortedSetTests() { return EnumSet.of(SortedSetTest.PEEK, SortedSetTest.POLL, SortedSetTest.HEAD_SET, SortedSetTest.SUB_SET, SortedSetTest.TAIL_SET);} +} diff --git a/src/test/java/speiger/src/collections/ints/sets/IntArraySetTests.java b/src/test/java/speiger/src/collections/ints/sets/IntArraySetTests.java new file mode 100644 index 00000000..05ba680e --- /dev/null +++ b/src/test/java/speiger/src/collections/ints/sets/IntArraySetTests.java @@ -0,0 +1,9 @@ +package speiger.src.collections.ints.sets; + +import speiger.src.collections.ints.base.BaseIntSortedSetTest; + +public class IntArraySetTests extends BaseIntSortedSetTest +{ + @Override + protected IntSortedSet create(int[] data) { return new IntArraySet(data.clone()); } +} diff --git a/src/test/java/speiger/src/collections/ints/sets/IntHashSetTests.java b/src/test/java/speiger/src/collections/ints/sets/IntHashSetTests.java new file mode 100644 index 00000000..276286da --- /dev/null +++ b/src/test/java/speiger/src/collections/ints/sets/IntHashSetTests.java @@ -0,0 +1,50 @@ +package speiger.src.collections.ints.sets; + +import java.util.EnumSet; + +import speiger.src.collections.ints.base.BaseIntCollectionTest; +import speiger.src.collections.ints.base.BaseIntSortedSetTest; +import speiger.src.collections.ints.collections.IntCollection; +import speiger.src.collections.ints.utils.IntStrategy; +import speiger.src.collections.tests.SortedSetTest; + +public class IntHashSetTests +{ + public static abstract class BaseIntOpenHashSetTests extends BaseIntSortedSetTest + { + @Override + protected EnumSet getValidSortedSetTests() { return EnumSet.of(SortedSetTest.ADD_MOVE, SortedSetTest.MOVE, SortedSetTest.PEEK, SortedSetTest.POLL); } + } + + public static class IntOpenHashSetTests extends BaseIntCollectionTest + { + @Override + protected IntCollection create(int[] data) { return new IntOpenHashSet(data); } + } + + public static class IntLinkedOpenHashSetTests extends BaseIntOpenHashSetTests + { + @Override + protected IntSortedSet create(int[] data) { return new IntLinkedOpenHashSet(data); } + } + + public static class IntOpenCustomHashSetTests extends BaseIntCollectionTest + { + @Override + protected IntCollection create(int[] data) { return new IntOpenCustomHashSet(data, new DefaultStrategy()); } + } + + public static class IntLinkedOpenCustomHashSetTests extends BaseIntOpenHashSetTests + { + @Override + protected IntSortedSet create(int[] data) { return new IntLinkedOpenCustomHashSet(data, new DefaultStrategy()); } + } + + public static class DefaultStrategy implements IntStrategy + { + @Override + public int hashCode(int o) { return Integer.hashCode(o); } + @Override + public boolean equals(int key, int value) { return key == value; } + } +} diff --git a/src/test/java/speiger/src/collections/ints/sets/IntRBTreeSetTests.java b/src/test/java/speiger/src/collections/ints/sets/IntRBTreeSetTests.java new file mode 100644 index 00000000..038f3593 --- /dev/null +++ b/src/test/java/speiger/src/collections/ints/sets/IntRBTreeSetTests.java @@ -0,0 +1,18 @@ +package speiger.src.collections.ints.sets; + +import java.util.EnumSet; + +import speiger.src.collections.ints.base.BaseIntNavigableSetTest; +import speiger.src.collections.tests.SortedSetTest; + +public class IntRBTreeSetTests extends BaseIntNavigableSetTest +{ + + @Override + protected IntNavigableSet create(int[] data) { + return new IntRBTreeSet(data); + } + + @Override + protected EnumSet getValidSortedSetTests() { return EnumSet.of(SortedSetTest.PEEK, SortedSetTest.POLL, SortedSetTest.HEAD_SET, SortedSetTest.SUB_SET, SortedSetTest.TAIL_SET);} +} diff --git a/src/test/java/speiger/src/collections/ints/utils/JavaTests.java b/src/test/java/speiger/src/collections/ints/utils/JavaTests.java new file mode 100644 index 00000000..64a1d5ec --- /dev/null +++ b/src/test/java/speiger/src/collections/ints/utils/JavaTests.java @@ -0,0 +1,29 @@ +package speiger.src.collections.ints.utils; + +import java.util.Arrays; +import java.util.TreeSet; +import java.util.stream.IntStream; + +import org.junit.Assert; +import org.junit.Test; + +public class JavaTests +{ + protected static final Integer[] CONTAINS_ARRAY = new Integer[]{23, 45, 63, 89, 32}; + protected static final Integer[] TEST_ARRAY = IntStream.range(0, 100).mapToObj(Integer::valueOf).toArray(Integer[]::new); + + private TreeSet create(Integer[] array) + { + TreeSet tree = new TreeSet(); + tree.addAll(Arrays.asList(array)); + return tree; + } + + @Test + public void simpleTest() + { + TreeSet collection = create(TEST_ARRAY); + Assert.assertTrue(collection.removeAll(create(CONTAINS_ARRAY))); + Assert.assertFalse(collection.removeAll(create(CONTAINS_ARRAY))); + } +} diff --git a/src/test/java/speiger/src/collections/tests/NavigableSetTest.java b/src/test/java/speiger/src/collections/tests/NavigableSetTest.java new file mode 100644 index 00000000..93da51b9 --- /dev/null +++ b/src/test/java/speiger/src/collections/tests/NavigableSetTest.java @@ -0,0 +1,12 @@ +package speiger.src.collections.tests; + +public enum NavigableSetTest +{ + LOWER, + HIGHER, + CEILING, + FLOOR, + SUB_SET, + HEAD_SET, + TAIL_SET; +} diff --git a/src/test/java/speiger/src/collections/tests/SortedSetTest.java b/src/test/java/speiger/src/collections/tests/SortedSetTest.java new file mode 100644 index 00000000..6eaeb7da --- /dev/null +++ b/src/test/java/speiger/src/collections/tests/SortedSetTest.java @@ -0,0 +1,12 @@ +package speiger.src.collections.tests; + +public enum SortedSetTest +{ + ADD_MOVE, + MOVE, + PEEK, + POLL, + SUB_SET, + HEAD_SET, + TAIL_SET; +}