From 413a2949156b488c7874a9e79b1f49c05c406278 Mon Sep 17 00:00:00 2001 From: Speiger Date: Tue, 27 Apr 2021 02:28:57 +0200 Subject: [PATCH] Added Primitive Streams into the Collection Interface --- .../speiger/src/builder/GlobalVariables.java | 5 + .../builder/PrimitiveCollectionsBuilder.java | 2 +- .../templates/collections/Collection.template | 29 +- .../templates/utils/SplitIterators.template | 282 ++++++++++++++++++ 4 files changed, 316 insertions(+), 2 deletions(-) create mode 100644 src/builder/resources/speiger/assets/collections/templates/utils/SplitIterators.template diff --git a/src/builder/java/speiger/src/builder/GlobalVariables.java b/src/builder/java/speiger/src/builder/GlobalVariables.java index 47fca8e6..3c724d9a 100644 --- a/src/builder/java/speiger/src/builder/GlobalVariables.java +++ b/src/builder/java/speiger/src/builder/GlobalVariables.java @@ -66,6 +66,7 @@ public class GlobalVariables addSimpleMapper("JAVA_TYPE", type.getCustomJDKType().getKeyType()); addSimpleMapper("SANITY_CAST", "castTo"+type.getFileType()); } + addSimpleMapper("JAVA_CLASS", type.getCustomJDKType().getClassType()); if(valueType.needsCustomJDKType()) { addSimpleMapper("SANITY_CAST_VALUE", "castTo"+valueType.getFileType()); @@ -124,6 +125,8 @@ public class GlobalVariables addSimpleMapper("JAVA_FUNCTION", type.getFunctionClass(valueType)); addSimpleMapper("JAVA_BINARY_OPERATOR", type == ClassType.BOOLEAN ? "" : (type.isObject() ? "java.util.function.BinaryOperator" : "java.util.function."+type.getCustomJDKType().getFileType()+"BinaryOperator")); addSimpleMapper("JAVA_UNARY_OPERATOR", type.isObject() ? "BinaryOperator" : type == ClassType.BOOLEAN ? "" : type.getCustomJDKType().getFileType()+"UnaryOperator"); + addSimpleMapper("JAVA_SPLIT_ITERATOR", type.isPrimitiveBlocking() ? "Spliterator" : "Of"+type.getCustomJDKType().getFileType()); + addSimpleMapper("JAVA_STREAM", type.isPrimitiveBlocking() ? "" : type.getCustomJDKType().getFileType()+"Stream"); //Final Classes addClassMapper("ARRAY_LIST", "ArrayList"); @@ -158,6 +161,7 @@ public class GlobalVariables addClassMapper("SETS", "Sets"); addClassMapper("COLLECTIONS", "Collections"); addClassMapper("ARRAYS", "Arrays"); + addClassMapper("SPLIT_ITERATORS", "SplitIterators"); addClassMapper("ITERATORS", "Iterators"); addBiClassMapper("MAPS", "Maps", "2"); @@ -239,6 +243,7 @@ public class GlobalVariables addFunctionValueMappers("REPLACE_VALUES", valueType.isObject() ? "replaceObjects" : "replace%ss"); addFunctionMappers("REPLACE", type.isObject() ? "replaceObjects" : "replace%ss"); addFunctionMappers("SORT", "sort%ss"); + addSimpleMapper("NEW_STREAM", type.isPrimitiveBlocking() ? "" : type.getCustomJDKType().getKeyType()+"Stream"); addSimpleMapper("TO_ARRAY", "to"+type.getNonFileType()+"Array"); addFunctionMapper("TOP", "top"); return this; diff --git a/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java b/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java index 5847ef4f..57cb0e74 100644 --- a/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java +++ b/src/builder/java/speiger/src/builder/PrimitiveCollectionsBuilder.java @@ -79,7 +79,7 @@ public class PrimitiveCollectionsBuilder extends TemplateProcessor nameRemapper.put("EnumMap", "Enum2%sMap"); addBlockage(ClassType.OBJECT, "Consumer", "Comparator", "Stack"); addBlockage(ClassType.BOOLEAN, "ArraySet", "AVLTreeSet", "RBTreeSet", "SortedSet", "NavigableSet", "OpenHashSet", "OpenCustomHashSet", "LinkedOpenHashSet", "LinkedOpenCustomHashSet"); - addBlockage(ClassType.BOOLEAN, "SortedMap", "NavigableMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap"); + addBlockage(ClassType.BOOLEAN, "SplitIterators", "SortedMap", "NavigableMap", "OpenHashMap", "LinkedOpenHashMap", "OpenCustomHashMap", "LinkedOpenCustomHashMap", "ArrayMap", "RBTreeMap", "AVLTreeMap"); } protected void create(ClassType mainType, ClassType subType) diff --git a/src/builder/resources/speiger/assets/collections/templates/collections/Collection.template b/src/builder/resources/speiger/assets/collections/templates/collections/Collection.template index 12746921..97e84c1e 100644 --- a/src/builder/resources/speiger/assets/collections/templates/collections/Collection.template +++ b/src/builder/resources/speiger/assets/collections/templates/collections/Collection.template @@ -5,8 +5,17 @@ import java.util.Collection; import java.util.Objects; import java.util.function.JAVA_PREDICATE; import java.util.function.Predicate; -#endif +import java.util.stream.JAVA_STREAM; +#endif +#if !TYPE_BOOLEAN +#if !PRIMITIVES +import java.util.stream.Stream; +#endif +import java.util.stream.StreamSupport; +import speiger.src.collections.PACKAGE.utils.SPLIT_ITERATORS; + +#endif #if TYPE_BYTE || TYPE_SHORT || TYPE_CHAR || TYPE_FLOAT import speiger.src.collections.utils.SanityChecks; @@ -177,4 +186,22 @@ public interface COLLECTION KEY_GENERIC_TYPE extends Collection, ITE */ @Override public ITERATOR KEY_GENERIC_TYPE iterator(); + +#if !TYPE_BOOLEAN +#if !TYPE_OBJECT + /** + * Returns a Java-Type-Specific Stream to reduce boxing/unboxing. + * @return a Stream of the closest java type + */ + default JAVA_STREAM primitiveStream() { return StreamSupport.NEW_STREAM(SPLIT_ITERATORS.createCollectionSplit(this, 0), false); } + +#else + /** + * Returns a Boxed Stream + * @return Stream of the type of collection + */ + @Override + default Stream stream() { return StreamSupport.stream(ObjectSplitIterators.createCollectionSplit(this, 0), false); } +#endif +#endif } \ No newline at end of file diff --git a/src/builder/resources/speiger/assets/collections/templates/utils/SplitIterators.template b/src/builder/resources/speiger/assets/collections/templates/utils/SplitIterators.template new file mode 100644 index 00000000..c59dc013 --- /dev/null +++ b/src/builder/resources/speiger/assets/collections/templates/utils/SplitIterators.template @@ -0,0 +1,282 @@ +package speiger.src.collections.PACKAGE.utils; + +import java.util.Comparator; +import java.util.Spliterator; +#if PRIMITIVES +import java.util.Spliterator.JAVA_SPLIT_ITERATOR; +#else +import java.util.function.Consumer; +#endif + +import speiger.src.collections.PACKAGE.collections.COLLECTION; +import speiger.src.collections.PACKAGE.collections.ITERATOR; +import speiger.src.collections.utils.SanityChecks; + +/** + * Helper class that provides SplitIterators for normal and stream usage + */ +public class SPLIT_ITERATORS +{ + /** + * Creates A stream compatible split iterator without copying the original array or boxing + * @param array that should be wrapped into a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @Type(T) + * @return a split iterator of a Stream compatible type + */ + public static GENERIC_KEY_BRACES JAVA_SPLIT_ITERATOR KEY_GENERIC_TYPE createArraySplit(KEY_TYPE[] array, int characteristics) { return createArraySplit(array, 0, array.length, characteristics);} + /** + * Creates A stream compatible split iterator without copying the original array or boxing + * @param array that should be wrapped into a split iterator + * @param size the maximum index within the array + * @param characteristics characteristics properties of this spliterator's source or elements. + * @Type(T) + * @return a split iterator of a Stream compatible type + * @throws IllegalStateException if the size is outside of the array size + */ + public static GENERIC_KEY_BRACES JAVA_SPLIT_ITERATOR KEY_GENERIC_TYPE createArraySplit(KEY_TYPE[] array, int size, int characteristics) { return createArraySplit(array, 0, size, characteristics);} + /** + * Creates A stream compatible split iterator without copying the original array or boxing + * @param array that should be wrapped into a split iterator + * @param offset the starting index of the array + * @param size the maximum index within the array + * @param characteristics characteristics properties of this spliterator's source or elements. + * @Type(T) + * @return a split iterator of a Stream compatible type + * @throws IllegalStateException the offset and size are outside of the arrays range + */ + public static GENERIC_KEY_BRACES JAVA_SPLIT_ITERATOR KEY_GENERIC_TYPE createArraySplit(KEY_TYPE[] array, int offset, int size, int characteristics) { + SanityChecks.checkArrayCapacity(array.length, offset, size); + return new ArraySplitIteratorBRACES(array, offset, size, characteristics); + } + + /** + * Creates a stream compatible split iterator without copying it or boxing it + * @param collection the collection that should be wrapped in a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @Type(T) + * @return a split iterator of a Stream compatible type + */ + public static GENERIC_KEY_BRACES JAVA_SPLIT_ITERATOR KEY_GENERIC_TYPE createCollectionSplit(COLLECTION KEY_GENERIC_TYPE collection, int characteristics) { + return new IteratorSpliteratorBRACES(collection, characteristics); + } + + /** + * Creates a stream compatible split iterator without copying it or boxing it + * @param iterator the Iterator that should be wrapped in a split iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @Type(T) + * @return a split iterator of a Stream compatible type + */ + public static GENERIC_KEY_BRACES JAVA_SPLIT_ITERATOR KEY_GENERIC_TYPE createUnknownIterator(ITERATOR KEY_GENERIC_TYPE iterator, int characteristics) { + return new IteratorSpliteratorBRACES(iterator, characteristics); + } + + /** + * Creates a stream compatible split iterator without copying it or boxing it + * @param iterator the collection that should be wrapped in a split iterator + * @param size the amount of elements in the iterator + * @param characteristics characteristics properties of this spliterator's source or elements. + * @Type(T) + * @return a split iterator of a Stream compatible type + */ + public static GENERIC_KEY_BRACES JAVA_SPLIT_ITERATOR KEY_GENERIC_TYPE createSizedIterator(ITERATOR KEY_GENERIC_TYPE iterator, long size, int characteristics) { + return new IteratorSpliteratorBRACES(iterator, size, characteristics); + } + + static class IteratorSpliterator KEY_GENERIC_TYPE implements JAVA_SPLIT_ITERATOR KEY_GENERIC_TYPE { + static final int BATCH_UNIT = 1 << 10; + static final int MAX_BATCH = 1 << 25; + private final COLLECTION KEY_GENERIC_TYPE collection; + private ITERATOR KEY_GENERIC_TYPE it; + private final int characteristics; + private long est; + private int batch; + + IteratorSpliterator(COLLECTION KEY_GENERIC_TYPE collection, int characteristics) { + this.collection = collection; + it = null; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; + } + + IteratorSpliterator(ITERATOR KEY_GENERIC_TYPE iterator, long size, int characteristics) { + collection = null; + it = iterator; + est = size; + this.characteristics = (characteristics & Spliterator.CONCURRENT) == 0 + ? characteristics | Spliterator.SIZED | Spliterator.SUBSIZED + : characteristics; + } + + IteratorSpliterator(ITERATOR KEY_GENERIC_TYPE iterator, int characteristics) { + collection = null; + it = iterator; + est = Long.MAX_VALUE; + this.characteristics = characteristics & ~(Spliterator.SIZED | Spliterator.SUBSIZED); + } + + private ITERATOR KEY_GENERIC_TYPE iterator() + { + if (it == null) { + it = collection.iterator(); + est = collection.size(); + } + return it; + } + + @Override + public JAVA_SPLIT_ITERATOR KEY_GENERIC_TYPE trySplit() { + ITERATOR KEY_GENERIC_TYPE i = iterator(); + if (est > 1 && i.hasNext()) { + int n = Math.min(batch + BATCH_UNIT, Math.min((int)est, MAX_BATCH)); + KEY_TYPE[] a = NEW_KEY_ARRAY(n); + int j = 0; + do { a[j] = i.NEXT(); } while (++j < n && i.hasNext()); + batch = j; + if (est != Long.MAX_VALUE) + est -= j; + return new ArraySplitIteratorBRACES(a, 0, j, characteristics); + } + return null; + } + +#if TYPE_OBJECT + @Override + public void forEachRemaining(Consumer action) { + if (action == null) throw new NullPointerException(); + iterator().forEachRemaining(action); + } + + @Override + public boolean tryAdvance(Consumer action) { + if (action == null) throw new NullPointerException(); + ITERATOR KEY_GENERIC_TYPE iter = iterator(); + if (iter.hasNext()) { + action.accept(iter.NEXT()); + return true; + } + return false; + } + +#else + @Override + public void forEachRemaining(JAVA_CONSUMER action) { + if (action == null) throw new NullPointerException(); + iterator().forEachRemaining(T -> action.accept(T)); + } + + @Override + public boolean tryAdvance(JAVA_CONSUMER action) { + if (action == null) throw new NullPointerException(); + ITERATOR KEY_GENERIC_TYPE iter = iterator(); + if (iter.hasNext()) { + action.accept(iter.NEXT()); + return true; + } + return false; + } + +#endif + @Override + public long estimateSize() { + iterator(); + return est; + } + + @Override + public int characteristics() { return characteristics; } + + @Override +#if TYPE_OBJECT + public Comparator getComparator() { +#else + public Comparator getComparator() { +#endif + if (hasCharacteristics(4)) //Sorted + return null; + throw new IllegalStateException(); + } + } + + static final class ArraySplitIterator KEY_GENERIC_TYPE implements JAVA_SPLIT_ITERATOR KEY_GENERIC_TYPE { + private final KEY_TYPE[] array; + private int index; + private final int fence; + private final int characteristics; + + public ArraySplitIterator(KEY_TYPE[] array, int origin, int fence, int additionalCharacteristics) { + this.array = array; + index = origin; + this.fence = fence; + characteristics = additionalCharacteristics | Spliterator.SIZED | Spliterator.SUBSIZED; + } + + @Override + public JAVA_SPLIT_ITERATOR KEY_GENERIC_TYPE trySplit() { + int lo = index, mid = (lo + fence) >>> 1; + return (lo >= mid) ? null : new ArraySplitIteratorBRACES(array, lo, index = mid, characteristics); + } + +#if TYPE_OBJECT + @Override + public void forEachRemaining(Consumer action) { + if (action == null) throw new NullPointerException(); + T[] a; int i, hi; + if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { + do { action.accept(a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(Consumer action) { + if (action == null) throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(array[index++]); + return true; + } + return false; + } + +#else + @Override + public void forEachRemaining(JAVA_CONSUMER action) { + if (action == null) throw new NullPointerException(); + KEY_TYPE[] a; int i, hi; + if ((a = array).length >= (hi = fence) && (i = index) >= 0 && i < (index = hi)) { + do { action.accept(a[i]); } while (++i < hi); + } + } + + @Override + public boolean tryAdvance(JAVA_CONSUMER action) { + if (action == null) throw new NullPointerException(); + if (index >= 0 && index < fence) { + action.accept(array[index++]); + return true; + } + return false; + } + +#endif + @Override + public long estimateSize() { return fence - index; } + + @Override + public int characteristics() { + return characteristics; + } + + @Override +#if TYPE_OBJECT + public Comparator getComparator() { +#else + public Comparator getComparator() { +#endif + if (hasCharacteristics(4)) //Sorted + return null; + throw new IllegalStateException(); + } + } +}