changeset 14076:62c3b03ef4ed

Streams port: Eliminate use of generator functions to create arrays, in favor of new T[]; inline away some methods from PipelineHelper
author briangoetz
date Fri, 01 Jul 2016 14:51:23 -0400
parents 6ac303e36f22
children 95fc5ae64549
files src/java.base/share/classes/java/anyutil/stream/DistinctOps.java src/java.base/share/classes/java/anyutil/stream/ForEachOps.java src/java.base/share/classes/java/anyutil/stream/Node.java src/java.base/share/classes/java/anyutil/stream/Nodes.java src/java.base/share/classes/java/anyutil/stream/Pipeline.java src/java.base/share/classes/java/anyutil/stream/PipelineHelper.java src/java.base/share/classes/java/anyutil/stream/SliceOps.java src/java.base/share/classes/java/anyutil/stream/SortedOps.java src/java.base/share/classes/java/anyutil/stream/SpinedBuffer.java
diffstat 9 files changed, 61 insertions(+), 139 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/anyutil/stream/DistinctOps.java	Thu Jun 30 16:14:28 2016 -0400
+++ b/src/java.base/share/classes/java/anyutil/stream/DistinctOps.java	Fri Jul 01 14:51:23 2016 -0400
@@ -76,8 +76,7 @@
 
         @Override
         Node<T> opEvaluateParallel(PipelineHelper<E_SRC, T> helper,
-                                   Spliterator<E_SRC> spliterator,
-                                   IntFunction<T[]> generator) {
+                                   Spliterator<E_SRC> spliterator) {
             throw new UnsupportedOperationException("parallel");
         }
 
--- a/src/java.base/share/classes/java/anyutil/stream/ForEachOps.java	Thu Jun 30 16:14:28 2016 -0400
+++ b/src/java.base/share/classes/java/anyutil/stream/ForEachOps.java	Fri Jul 01 14:51:23 2016 -0400
@@ -357,11 +357,7 @@
             if (task.getPendingCount() > 0) {
                 // Cannot complete just yet so buffer elements into a Node
                 // for use when completion occurs
-                @SuppressWarnings("unchecked")
-                IntFunction<Z[]> generator = size -> (Z[])new Object[size];
-                Node.Builder<Z> nb = task.helper.makeNodeBuilder(
-                        task.helper.exactOutputSizeIfKnown(rightSplit),
-                        generator);
+                Node.Builder<Z> nb = Nodes.builder(task.helper.exactOutputSizeIfKnown(rightSplit));
                 task.node = task.helper.wrapAndCopyInto(nb, rightSplit).build();
                 task.spliterator = null;
             }
--- a/src/java.base/share/classes/java/anyutil/stream/Node.java	Thu Jun 30 16:14:28 2016 -0400
+++ b/src/java.base/share/classes/java/anyutil/stream/Node.java	Fri Jul 01 14:51:23 2016 -0400
@@ -26,10 +26,6 @@
 
 import java.anyutil.Spliterator;
 import java.anyutil.function.Consumer;
-import java.anyutil.function.DoubleConsumer;
-import java.anyutil.function.IntConsumer;
-import java.anyutil.function.IntFunction;
-import java.anyutil.function.LongConsumer;
 
 /**
  * An immutable container for describing an ordered sequence of elements of some
@@ -114,16 +110,14 @@
      *             be in range 0..count().
      * @param to The (exclusive) end offset of elements to include, must be
      *           in range 0..count().
-     * @param generator A function to be used to create a new array, if needed,
-     *                  for reference nodes.
      * @return the truncated node
      */
-    default Node<T> truncate(long from, long to, IntFunction<T[]> generator) {
+    default Node<T> truncate(long from, long to) {
         if (from == 0 && to == count())
             return this;
         Spliterator<T> spliterator = spliterator();
         long size = to - from;
-        Node.Builder<T> nodeBuilder = Nodes.builder(size, generator);
+        Node.Builder<T> nodeBuilder = Nodes.builder(size);
         nodeBuilder.begin(size);
         for (int i = 0; i < from && spliterator.tryAdvance(e -> { }); i++) { }
         for (int i = 0; (i < size) && spliterator.tryAdvance(nodeBuilder); i++) { }
@@ -136,16 +130,11 @@
      *
      * <p>Depending on the underlying implementation, this may return a
      * reference to an internal array rather than a copy.  Since the returned
-     * array may be shared, the returned array should not be modified.  The
-     * {@code generator} function may be consulted to create the array if a new
-     * array needs to be created.
+     * array may be shared, the returned array should not be modified.
      *
-     * @param generator a factory function which takes an integer parameter and
-     *        returns a new, empty array of that size and of the appropriate
-     *        array type
      * @return an array containing the contents of this {@code Node}
      */
-    T[] asArray(IntFunction<T[]> generator);
+    T[] asArray();
 
     /**
      * Copies the content of this {@code Node} into an array, starting at a
--- a/src/java.base/share/classes/java/anyutil/stream/Nodes.java	Thu Jun 30 16:14:28 2016 -0400
+++ b/src/java.base/share/classes/java/anyutil/stream/Nodes.java	Fri Jul 01 14:51:23 2016 -0400
@@ -37,8 +37,7 @@
  *
  * @since 1.8
  */
-//@@@Valhalla: temporarily public
-public final class Nodes {
+final class Nodes {
 
     private Nodes() {
         throw new Error("no instances");
@@ -121,24 +120,13 @@
      * @param exactSizeIfKnown -1 if a variable size builder is requested,
      * otherwise the exact capacity desired.  A fixed capacity builder will
      * fail if the wrong number of elements are added to the builder.
-     * @param generator the array factory
      * @param <T> the type of elements of the node builder
      * @return a {@code Node.Builder}
      */
-    public static <any T> Node.Builder<T> builder(long exactSizeIfKnown, IntFunction<T[]> generator) {
+    public static <any T> Node.Builder<T> builder(long exactSizeIfKnown) {
         return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE)
-               ? new FixedNodeBuilder<>(exactSizeIfKnown, generator)
-               : builder();
-    }
-
-    /**
-     * Produces a variable size @{link Node.Builder}.
-     *
-     * @param <T> the type of elements of the node builder
-     * @return a {@code Node.Builder}
-     */
-    public static <any T> Node.Builder<T> builder() {
-        return new SpinedNodeBuilder<>();
+               ? new FixedNodeBuilder<>(exactSizeIfKnown)
+               : new SpinedNodeBuilder<>();
     }
 
     // Parallel evaluation of pipelines to nodes
@@ -161,24 +149,23 @@
      * @param helper the pipeline helper describing the pipeline
      * @param flattenTree whether a conc node should be flattened into a node
      *                    describing an array before returning
-     * @param generator the array generator
      * @return a {@link Node} describing the output elements
      */
     public static <any E_SRC, any P_OUT> Node<P_OUT>
             collect(PipelineHelper<E_SRC, P_OUT> helper,
                     Spliterator<E_SRC> spliterator,
-                    boolean flattenTree,
-                    IntFunction<P_OUT[]> generator) {
+                    boolean flattenTree) {
         long size = helper.exactOutputSizeIfKnown(spliterator);
         if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
             if (size >= MAX_ARRAY_SIZE)
                 throw new IllegalArgumentException(BAD_SIZE);
-            P_OUT[] array = generator.apply((int) size);
+            @SuppressWarnings("unchecked")
+            P_OUT[] array = new P_OUT[(int) size];
             new SizedCollectorTask<>(spliterator, helper, array).invoke();
             return node(array);
         } else {
-            Node<P_OUT> node = new CollectorTask<>(helper, generator, spliterator).invoke();
-            return flattenTree ? flatten(node, generator) : node;
+            Node<P_OUT> node = new CollectorTask<>(helper, spliterator).invoke();
+            return flattenTree ? flatten(node) : node;
         }
     }
 
@@ -196,15 +183,15 @@
      *
      * @param <T> type of elements contained by the node
      * @param node the node to flatten
-     * @param generator the array factory used to create array instances
      * @return a flat {@code Node}
      */
-    public static <any T> Node<T> flatten(Node<T> node, IntFunction<T[]> generator) {
+    public static <any T> Node<T> flatten(Node<T> node) {
         if (node.getChildCount() > 0) {
             long size = node.count();
             if (size >= MAX_ARRAY_SIZE)
                 throw new IllegalArgumentException(BAD_SIZE);
-            T[] array = generator.apply((int) size);
+            @SuppressWarnings("unchecked")
+            T[] array = new T[(int) size];
             new ToArrayTask<>(node, array, 0).invoke();
             return node(array);
         } else {
@@ -218,8 +205,10 @@
         EmptyNode() { }
 
         @Override
-        public T[] asArray(IntFunction<T[]> generator) {
-            return generator.apply(0);
+        public T[] asArray() {
+            @SuppressWarnings("unchecked")
+            T[] array = new T[0];
+            return array;
         }
 
         public void copyInto(T[] array, int offset) { }
@@ -243,10 +232,10 @@
         int curSize;
 
         @SuppressWarnings("unchecked")
-        ArrayNode(long size, IntFunction<T[]> generator) {
+        ArrayNode(long size) {
             if (size >= MAX_ARRAY_SIZE)
                 throw new IllegalArgumentException(BAD_SIZE);
-            this.array = generator.apply((int) size);
+            this.array = new T[(int) size];
             this.curSize = 0;
         }
 
@@ -268,7 +257,7 @@
         }
 
         @Override
-        public T[] asArray(IntFunction<T[]> generator) {
+        public T[] asArray() {
             if (array.length == curSize) {
                 return array;
             } else {
@@ -320,9 +309,10 @@
         }
 
         @Override
-        public T[] asArray(IntFunction<T[]> generator) {
+        public T[] asArray() {
             // @@@ Valhalla Should use c.toArray()
-            T[] array = generator.apply(c.size());
+            @SuppressWarnings("unchecked")
+            T[] array = new T[c.size()];
             int index = 0;
             for (Iterator<T> iterator = c.iterator();
                  iterator.hasNext(); ) {
@@ -399,11 +389,12 @@
         }
 
         @Override
-        public T[] asArray(IntFunction<T[]> generator) {
+        public T[] asArray() {
             long size = count();
             if (size >= MAX_ARRAY_SIZE)
                 throw new IllegalArgumentException(BAD_SIZE);
-            T[] array = generator.apply((int) size);
+            @SuppressWarnings("unchecked")
+            T[] array = new T[(int) size];
             copyInto(array, 0);
             return array;
         }
@@ -415,17 +406,17 @@
         }
 
         @Override
-        public Node<T> truncate(long from, long to, IntFunction<T[]> generator) {
+        public Node<T> truncate(long from, long to) {
             if (from == 0 && to == count())
                 return this;
             long leftCount = left.count();
             if (from >= leftCount)
-                return right.truncate(from - leftCount, to - leftCount, generator);
+                return right.truncate(from - leftCount, to - leftCount);
             else if (to <= leftCount)
-                return left.truncate(from, to, generator);
+                return left.truncate(from, to);
             else {
-                return new ConcNode<>(left.truncate(from, leftCount, generator),
-                                      right.truncate(0, to - leftCount, generator));
+                return new ConcNode<>(left.truncate(from, leftCount),
+                                      right.truncate(0, to - leftCount));
             }
         }
 
@@ -623,8 +614,8 @@
             extends ArrayNode<T>
             implements Node.Builder<T> {
 
-        FixedNodeBuilder(long size, IntFunction<T[]> generator) {
-            super(size, generator);
+        FixedNodeBuilder(long size) {
+            super(size);
             assert size < MAX_ARRAY_SIZE;
         }
 
@@ -720,9 +711,9 @@
         }
 
         @Override
-        public T[] asArray(IntFunction<T[]> arrayFactory) {
+        public T[] asArray() {
             assert !building : "during building";
-            return super.asArray(arrayFactory);
+            return super.asArray();
         }
 
         @Override
@@ -890,9 +881,8 @@
         }
 
         CollectorTask(PipelineHelper<P_SRC, P_OUT> helper,
-                      IntFunction<P_OUT[]> generator,
                       Spliterator<P_SRC> spliterator) {
-            this(helper, spliterator, s -> builder(s, generator), ConcNode::new);
+            this(helper, spliterator, s -> builder(s), ConcNode::new);
         }
 
         @Override
--- a/src/java.base/share/classes/java/anyutil/stream/Pipeline.java	Thu Jun 30 16:14:28 2016 -0400
+++ b/src/java.base/share/classes/java/anyutil/stream/Pipeline.java	Fri Jul 01 14:51:23 2016 -0400
@@ -351,15 +351,13 @@
 
     @Override
     final Node<E_OUT> evaluate(Spliterator<E_SRC> spliterator,
-                               boolean flatten,
-                               IntFunction<E_OUT[]> generator) {
+                               boolean flatten) {
         if (isParallel()) {
             // @@@ Optimize if op of this pipeline stage is a stateful op
-            return evaluateToNode(this, spliterator, flatten, generator);
+            return evaluateToNode(this, spliterator, flatten);
         }
         else {
-            Node.Builder<E_OUT> nb = makeNodeBuilder(
-                    exactOutputSizeIfKnown(spliterator), generator);
+            Node.Builder<E_OUT> nb = Nodes.builder(exactOutputSizeIfKnown(spliterator));
             return wrapAndCopyInto(nb, spliterator).build();
         }
     }
@@ -374,14 +372,12 @@
      * @param helper the pipeline helper describing the pipeline stages
      * @param spliterator the source spliterator
      * @param flattenTree true if the returned node should be flattened
-     * @param generator the array generator
      * @return a Node holding the output of the pipeline
      */
     private Node<E_OUT> evaluateToNode(PipelineHelper<E_SRC, E_OUT> helper,
                                        Spliterator<E_SRC> spliterator,
-                                       boolean flattenTree,
-                                       IntFunction<E_OUT[]> generator) {
-        return Nodes.collect(helper, spliterator, flattenTree, generator);
+                                       boolean flattenTree) {
+        return Nodes.collect(helper, spliterator, flattenTree);
     }
 
     /**
@@ -408,27 +404,6 @@
         return new StreamSpliterators.DelegatingSpliterator<>(supplier);
     }
 
-    /**
-     * Make a node builder compatible with this stream shape.
-     *
-     * @param exactSizeIfKnown if {@literal >=0}, then a node builder will be
-     * created that has a fixed capacity of at most sizeIfKnown elements. If
-     * {@literal < 0}, then the node builder has an unfixed capacity. A fixed
-     * capacity node builder will throw exceptions if an element is added after
-     * builder has reached capacity, or is built before the builder has reached
-     * capacity.
-     *
-     * @param generator the array generator to be used to create instances of a
-     * T[] array. For implementations supporting primitive nodes, this parameter
-     * may be ignored.
-     * @return a node builder
-     */
-    @Override
-    Node.Builder<E_OUT> makeNodeBuilder(long exactSizeIfKnown,
-                                        IntFunction<E_OUT[]> generator) {
-        return Nodes.builder(exactSizeIfKnown, generator);
-    }
-
 
     // Op-specific abstract methods, implemented by the operation class
 
@@ -475,12 +450,10 @@
      *
      * @param helper the pipeline helper describing the pipeline stages
      * @param spliterator the source {@code Spliterator}
-     * @param generator the array generator
      * @return a {@code Node} describing the result of the evaluation
      */
     Node<E_OUT> opEvaluateParallel(PipelineHelper<E_SRC, E_OUT> helper,
-                                   Spliterator<E_SRC> spliterator,
-                                   IntFunction<E_OUT[]> generator) {
+                                   Spliterator<E_SRC> spliterator) {
         throw new UnsupportedOperationException("Parallel evaluation is not supported");
     }
 
@@ -507,7 +480,7 @@
     @SuppressWarnings("unchecked")
     Spliterator<E_OUT> opEvaluateParallelLazy(PipelineHelper<E_SRC, E_OUT> helper,
                                               Spliterator<E_SRC> spliterator) {
-        return opEvaluateParallel(helper, spliterator, i -> new E_OUT[i]).spliterator();
+        return opEvaluateParallel(helper, spliterator).spliterator();
     }
 
     @Override
@@ -1009,8 +982,7 @@
 
         @Override
         abstract Node<E_OUT> opEvaluateParallel(PipelineHelper<E_SRC, E_OUT> helper,
-                                                Spliterator<E_SRC> spliterator,
-                                                IntFunction<E_OUT[]> generator);
+                                                Spliterator<E_SRC> spliterator);
     }
 
 }
--- a/src/java.base/share/classes/java/anyutil/stream/PipelineHelper.java	Thu Jun 30 16:14:28 2016 -0400
+++ b/src/java.base/share/classes/java/anyutil/stream/PipelineHelper.java	Fri Jul 01 14:51:23 2016 -0400
@@ -25,7 +25,6 @@
 package java.anyutil.stream;
 
 import java.anyutil.Spliterator;
-import java.anyutil.function.IntFunction;
 
 /**
  * Helper class for executing <a href="package-summary.html#StreamOps">
@@ -136,21 +135,6 @@
     abstract Spliterator<P_OUT> wrapSpliterator(Spliterator<P_SRC> spliterator);
 
     /**
-     * Constructs a @{link Node.Builder} compatible with the output shape of
-     * this {@code PipelineHelper}.
-     *
-     * @param exactSizeIfKnown if >=0 then a builder will be created that has a
-     *        fixed capacity of exactly sizeIfKnown elements; if < 0 then the
-     *        builder has variable capacity.  A fixed capacity builder will fail
-     *        if an element is added after the builder has reached capacity.
-     * @param generator a factory function for array instances
-     * @return a {@code Node.Builder} compatible with the output shape of this
-     *         {@code PipelineHelper}
-     */
-    abstract Node.Builder<P_OUT> makeNodeBuilder(long exactSizeIfKnown,
-                                                 IntFunction<P_OUT[]> generator);
-
-    /**
      * Collects all output elements resulting from applying the pipeline stages
      * to the source {@code Spliterator} into a {@code Node}.
      *
@@ -169,10 +153,8 @@
      *        {@code Node} returned will contain no children, otherwise the
      *        {@code Node} may represent the root in a tree that reflects the
      *        shape of the computation tree.
-     * @param generator a factory function for array instances
      * @return the {@code Node} containing all output elements
      */
     abstract Node<P_OUT> evaluate(Spliterator<P_SRC> spliterator,
-                                  boolean flatten,
-                                  IntFunction<P_OUT[]> generator);
+                                  boolean flatten);
 }
--- a/src/java.base/share/classes/java/anyutil/stream/SliceOps.java	Thu Jun 30 16:14:28 2016 -0400
+++ b/src/java.base/share/classes/java/anyutil/stream/SliceOps.java	Fri Jul 01 14:51:23 2016 -0400
@@ -118,14 +118,13 @@
                 //     cancellation will be more aggressive cancelling later tasks
                 //     if the target slice size has been reached from a given task,
                 //     cancellation should also clear local results if any
-                return new SliceTask<>(this, helper, spliterator, castingArray(), skip, limit).invoke().spliterator();
+                return new SliceTask<>(this, helper, spliterator, skip, limit).invoke().spliterator();
             }
         }
 
         @Override
         Node<T> opEvaluateParallel(PipelineHelper<E_SRC, T> helper,
-                                   Spliterator<E_SRC> spliterator,
-                                   IntFunction<T[]> generator) {
+                                   Spliterator<E_SRC> spliterator) {
             long size = helper.exactOutputSizeIfKnown(spliterator);
             if (size > 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
                 // Because the pipeline is SIZED the slice spliterator
@@ -134,7 +133,7 @@
                 // than creating the slice spliterator from the pipeline
                 // wrapping spliterator
                 Spliterator<E_SRC> s = new StreamSpliterators.SliceSpliterator<>(spliterator, skip, calcSliceFence(skip, limit));
-                return Nodes.collect(helper, s, true, generator);
+                return Nodes.collect(helper, s, true);
                 // @@@Valhalla: Temporarily disable optimization
 //            } else if (!StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
 //                Spliterator<T> s =  unorderedSkipLimitSpliterator(
@@ -147,7 +146,7 @@
 //                return Nodes.collect(this, s, true, generator);
             }
             else {
-                return new SliceTask<>(this, helper, spliterator, generator, skip, limit).invoke();
+                return new SliceTask<>(this, helper, spliterator, skip, limit).invoke();
             }
         }
 
@@ -214,7 +213,6 @@
     private static final class SliceTask<any E_SRC, any E_OUT>
             extends AbstractShortCircuitTask<E_SRC, E_OUT, Node<E_OUT>, SliceTask<E_SRC, E_OUT>> {
         private final Pipeline<E_SRC, E_OUT, E_OUT> op;
-        private final IntFunction<E_OUT[]> generator;
         private final long targetOffset, targetSize;
         private long thisNodeSize;
 
@@ -223,11 +221,9 @@
         SliceTask(Pipeline<E_SRC, E_OUT, E_OUT> op,
                   PipelineHelper<E_SRC, E_OUT> helper,
                   Spliterator<E_SRC> spliterator,
-                  IntFunction<E_OUT[]> generator,
                   long offset, long size) {
             super(helper, spliterator);
             this.op = op;
-            this.generator = generator;
             this.targetOffset = offset;
             this.targetSize = size;
         }
@@ -235,7 +231,6 @@
         SliceTask(SliceTask<E_SRC, E_OUT> parent, Spliterator<E_SRC> spliterator) {
             super(parent, spliterator);
             this.op = parent.op;
-            this.generator = parent.generator;
             this.targetOffset = parent.targetOffset;
             this.targetSize = parent.targetSize;
         }
@@ -256,7 +251,7 @@
                 long sizeIfKnown = StreamOpFlag.SIZED.isPreserved(op.sourceOrOpFlags)
                                    ? op.exactOutputSizeIfKnown(spliterator)
                                    : -1;
-                final Node.Builder<E_OUT> nb = op.makeNodeBuilder(sizeIfKnown, generator);
+                final Node.Builder<E_OUT> nb = Nodes.builder(sizeIfKnown);
                 Sink<E_OUT> opSink = op.opWrapSink(helper.getStreamAndOpFlags(), nb);
                 helper.copyInto(helper.wrapSink(opSink), spliterator);
                 // There is no need to truncate since the op performs the
@@ -264,8 +259,7 @@
                 return nb.build();
             }
             else {
-                Node<E_OUT> node = helper.wrapAndCopyInto(helper.makeNodeBuilder(-1, generator),
-                                                          spliterator).build();
+                Node<E_OUT> node = helper.wrapAndCopyInto(Nodes.builder(-1), spliterator).build();
                 thisNodeSize = node.count();
                 completed = true;
                 spliterator = null;
@@ -309,7 +303,7 @@
 
         private Node<E_OUT> doTruncate(Node<E_OUT> input) {
             long to = targetSize >= 0 ? Math.min(input.count(), targetOffset + targetSize) : thisNodeSize;
-            return input.truncate(targetOffset, to, generator);
+            return input.truncate(targetOffset, to);
         }
 
         /**
--- a/src/java.base/share/classes/java/anyutil/stream/SortedOps.java	Thu Jun 30 16:14:28 2016 -0400
+++ b/src/java.base/share/classes/java/anyutil/stream/SortedOps.java	Fri Jul 01 14:51:23 2016 -0400
@@ -101,8 +101,7 @@
 
         @Override
         public Node<T> opEvaluateParallel(PipelineHelper<E_SRC, T> helper,
-                                          Spliterator<E_SRC> spliterator,
-                                          IntFunction<T[]> generator) {
+                                          Spliterator<E_SRC> spliterator) {
             throw new UnsupportedOperationException("parallel");
         }
     }
--- a/src/java.base/share/classes/java/anyutil/stream/SpinedBuffer.java	Thu Jun 30 16:14:28 2016 -0400
+++ b/src/java.base/share/classes/java/anyutil/stream/SpinedBuffer.java	Fri Jul 01 14:51:23 2016 -0400
@@ -274,11 +274,12 @@
      * Create a new array using the specified array factory, and copy the
      * elements into it.
      */
-    public E[] asArray(IntFunction<E[]> arrayFactory) {
+    public E[] asArray() {
         long size = count();
         if (size >= Nodes.MAX_ARRAY_SIZE)
             throw new IllegalArgumentException(Nodes.BAD_SIZE);
-        E[] result = arrayFactory.apply((int) size);
+        @SuppressWarnings("unchecked")
+        E[] result = new E[(int) size];
         copyInto(result, 0);
         return result;
     }