changeset 7051:ed7fd1baaab2

Consolidate java.util.stream.op into java.util.stream; make some classes package-private
author briangoetz
date Thu, 10 Jan 2013 21:50:21 -0500
parents ca8730a515e5
children 6faa77cd3045
files src/share/classes/java/util/stream/AbstractPipeline.java src/share/classes/java/util/stream/AbstractShortCircuitTask.java src/share/classes/java/util/stream/AbstractSpinedBuffer.java src/share/classes/java/util/stream/AbstractTask.java src/share/classes/java/util/stream/ConcurrentCollectors.java src/share/classes/java/util/stream/FindOp.java src/share/classes/java/util/stream/FoldOp.java src/share/classes/java/util/stream/ForEachOp.java src/share/classes/java/util/stream/ForEachUntilOp.java src/share/classes/java/util/stream/IntPipeline.java src/share/classes/java/util/stream/IntStream.java src/share/classes/java/util/stream/IntermediateOp.java src/share/classes/java/util/stream/MatchOp.java src/share/classes/java/util/stream/Node.java src/share/classes/java/util/stream/NodeFactory.java src/share/classes/java/util/stream/NodeUtils.java src/share/classes/java/util/stream/Nodes.java src/share/classes/java/util/stream/OpUtils.java src/share/classes/java/util/stream/Ops.java src/share/classes/java/util/stream/PipelineHelper.java src/share/classes/java/util/stream/ReferencePipeline.java src/share/classes/java/util/stream/SliceOp.java src/share/classes/java/util/stream/SortedOp.java src/share/classes/java/util/stream/SpinedBuffer.java src/share/classes/java/util/stream/StatefulOp.java src/share/classes/java/util/stream/Stream.java src/share/classes/java/util/stream/StreamOp.java src/share/classes/java/util/stream/StreamOpFlag.java src/share/classes/java/util/stream/StreamShape.java src/share/classes/java/util/stream/StreamShapeImpls.java src/share/classes/java/util/stream/Streams.java src/share/classes/java/util/stream/TerminalOp.java src/share/classes/java/util/stream/UniqOp.java src/share/classes/java/util/stream/op/AbstractShortCircuitTask.java src/share/classes/java/util/stream/op/AbstractSpinedBuffer.java src/share/classes/java/util/stream/op/AbstractTask.java src/share/classes/java/util/stream/op/FindOp.java src/share/classes/java/util/stream/op/FoldOp.java src/share/classes/java/util/stream/op/ForEachOp.java src/share/classes/java/util/stream/op/ForEachUntilOp.java src/share/classes/java/util/stream/op/IntermediateOp.java src/share/classes/java/util/stream/op/MatchOp.java src/share/classes/java/util/stream/op/Node.java src/share/classes/java/util/stream/op/NodeUtils.java src/share/classes/java/util/stream/op/Nodes.java src/share/classes/java/util/stream/op/OpUtils.java src/share/classes/java/util/stream/op/Ops.java src/share/classes/java/util/stream/op/SliceOp.java src/share/classes/java/util/stream/op/SortedOp.java src/share/classes/java/util/stream/op/SpinedBuffer.java src/share/classes/java/util/stream/op/StatefulOp.java src/share/classes/java/util/stream/op/StreamOp.java src/share/classes/java/util/stream/op/TerminalOp.java src/share/classes/java/util/stream/op/UniqOp.java test-ng/tests/org/openjdk/tests/java/util/stream/OpTestCase.java test-ng/tests/org/openjdk/tests/java/util/stream/StreamLinkTest.java test-ng/tests/org/openjdk/tests/java/util/stream/StreamTestData.java test-ng/tests/org/openjdk/tests/java/util/stream/StreamTestDataProvider.java test-ng/tests/org/openjdk/tests/java/util/stream/op/CollectorOps.java test-ng/tests/org/openjdk/tests/java/util/stream/op/FilterOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/FlagDeclaringOp.java test-ng/tests/org/openjdk/tests/java/util/stream/op/FlagOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/ForEachOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/IntNodeTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/MapOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/MatchOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/MultiMapOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/NodeBuilderTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/NodeTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/PrimitiveOpsTests.java test-ng/tests/org/openjdk/tests/java/util/stream/op/SliceOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/SortedOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/SpinedBufferTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/ToArrayOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/op/UniqOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/primitive/IntFilterOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/primitive/IntMultiMapOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/primitive/IntSliceOpTest.java test-ng/tests/org/openjdk/tests/java/util/stream/primitive/IntStreamTestData.java test-ng/tests/org/openjdk/tests/java/util/stream/primitive/IntStreamTestDataProvider.java test-ng/tests/org/openjdk/tests/java/util/stream/primitive/IntUniqOpTest.java
diffstat 81 files changed, 4950 insertions(+), 4981 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/stream/AbstractPipeline.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/AbstractPipeline.java	Thu Jan 10 21:50:21 2013 -0500
@@ -24,12 +24,13 @@
  */
 package java.util.stream;
 
-import java.util.*;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Spliterator;
 import java.util.function.ObjIntFunction;
 import java.util.function.Supplier;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import java.util.stream.op.*;
 
 /**
  * The abstract pipeline implementation from which concrete implementations extend from.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/AbstractShortCircuitTask.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Abstract class for fork-join tasks used to implement short-circuiting
+ * stream ops that can produce a result without processing all elements of the stream.
+ *
+ * @param <P_IN> Type of elements input to the pipeline
+ * @param <P_OUT> Type of elements output from the pipeline
+ * @param <R> Type of intermediate result, may be different from operation result type
+ * @param <T> Type of child and sibling tasks.
+ */
+abstract class AbstractShortCircuitTask<P_IN, P_OUT, R, T extends AbstractShortCircuitTask<P_IN, P_OUT, R, T>>
+        extends AbstractTask<P_IN, P_OUT, R, T> {
+    protected final AtomicReference<R> sharedResult;
+    protected volatile boolean canceled;
+
+    protected AbstractShortCircuitTask(PipelineHelper<P_IN, P_OUT> helper) {
+        super(helper);
+        sharedResult = new AtomicReference<>(null);
+    }
+
+    protected AbstractShortCircuitTask(T parent, Spliterator<P_IN> spliterator) {
+        super(parent, spliterator);
+        sharedResult = parent.sharedResult;
+    }
+
+    protected abstract R getEmptyResult();
+
+    @Override
+    public void compute() {
+        // Have we already found an answer?
+        if (sharedResult.get() != null)
+            tryComplete();
+        else if (taskCancelled()) {
+            setLocalResult(getEmptyResult());
+            tryComplete();
+        }
+        else
+            super.compute();
+    }
+
+    protected void shortCircuit(R r) {
+        if (r != null)
+            sharedResult.compareAndSet(null, r);
+    }
+
+    @Override
+    protected void setLocalResult(R r) {
+        if (isRoot()) {
+            if (r != null)
+                sharedResult.compareAndSet(null, r);
+        }
+        else
+            super.setLocalResult(r);
+    }
+
+    @Override
+    public R getRawResult() {
+        return getLocalResult();
+    }
+
+    @Override
+    public R getLocalResult() {
+        if (isRoot()) {
+            R answer = sharedResult.get();
+            return (answer == null) ? getEmptyResult() : answer;
+        }
+        else
+            return super.getLocalResult();
+    }
+
+    protected void cancel() {
+        canceled = true;
+    }
+
+    protected boolean taskCancelled() {
+        boolean cancel = canceled;
+        if (!cancel)
+            for (T parent = getParent(); !cancel && parent != null; parent = parent.getParent())
+                cancel = parent.canceled;
+        return cancel;
+    }
+
+    protected void cancelLaterNodes() {
+        T parent = getParent();
+        for (T sibling = this.nextSibling; sibling != null; sibling = sibling.nextSibling)
+            if (!sibling.canceled)
+                sibling.canceled = true;
+        // Go up the tree, cancel later siblings of all parents
+        if (parent != null)
+            parent.cancelLaterNodes();
+    }
+
+    protected boolean isLeftSpine() {
+        T node = (T) this;
+        while (node != null) {
+            T parent = node.getParent();
+            if (parent != null && parent.children != node)
+                return false;
+            node = parent;
+        }
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/AbstractSpinedBuffer.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * AbstractSpinedBuffer
+ *
+ * @author Brian Goetz
+ */
+abstract class AbstractSpinedBuffer<E> {
+    public static final int MIN_CHUNK_POWER = 4;
+    public static final int MIN_CHUNK_SIZE = 1 << MIN_CHUNK_POWER;
+    public static final int MAX_CHUNK_POWER = 30;
+    public static final int MIN_SPINE_SIZE = 8;
+
+    // log2 of the size of the first chunk
+    protected final int initialChunkPower;
+
+    // Index of the *next* element to write; may be outside the current chunk
+    protected int elementIndex;
+
+    // Index of the *current* chunk in the spine array
+    protected int spineIndex;
+
+    // Count of elements in all prior chunks
+    protected long[] priorElementCount;
+
+    public AbstractSpinedBuffer(int initialCapacity) {
+        if (initialCapacity < 0)
+            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
+
+        this.initialChunkPower = Math.max(MIN_CHUNK_POWER,
+                                          Integer.SIZE - Integer.numberOfLeadingZeros(initialCapacity - 1));
+    }
+
+    public boolean isEmpty() {
+        return (spineIndex == 0) && (elementIndex == 0);
+    }
+
+    public long count() {
+        return (spineIndex == 0)
+               ? elementIndex
+               : priorElementCount[spineIndex] + elementIndex;
+    }
+
+    protected int chunkSize(int n) {
+        int power = (n == 0 || n == 1)
+                    ? initialChunkPower
+                    : Math.min(initialChunkPower + n - 1, AbstractSpinedBuffer.MAX_CHUNK_POWER);
+        return 1 << power;
+    }
+
+    public abstract void clear();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/AbstractTask.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinPool;
+
+/**
+ * Abstract base class for most fork-join tasks used to implement stream ops.
+ * Manages splitting logic, tracking of child tasks, and intermediate results.
+ * While the <code>getRawResult</code> and <code>setRawResult</code> methods of
+ * <code>CountedCompleter</code> are initially unwired, this class uses them to
+ * manage per-task result storage.
+ *
+ * Splitting and setting up the child task links is done at <code>compute()</code> time
+ * for non-leaf nodes.  At <code>compute()</code> time for leaf nodes, it is guaranteed
+ * that the parent's child-related fields (including sibling links for the parent's children)
+ * will be set up for all children.
+ *
+ * @param <P_IN> Type of elements input to the pipeline
+ * @param <P_OUT> Type of elements output from the pipeline
+ * @param <R> Type of intermediate result, may be different from operation result type
+ * @param <T> Type of child and sibling tasks.
+ *
+ * @author Brian Goetz
+ */
+abstract class AbstractTask<P_IN, P_OUT, R, T extends AbstractTask<P_IN, P_OUT, R, T>>
+        extends CountedCompleter<R> {
+
+    /** The pipeline helper, common to all tasks in a computation */
+    protected final PipelineHelper<P_IN, P_OUT> helper;
+
+    /** The spliterator for the portion of the input associated with the subtree rooted at this task */
+    protected final Spliterator<P_IN> spliterator;
+
+    protected final long targetSize;
+
+    /** How many children does this task have? */
+    protected int numChildren;
+
+    /** This task's first child.  Children are stored in a linked list, using the <code>nextSibling</code> field
+     * as the link to the next child. */
+    protected T children;
+
+    /** Next sibling of this task */
+    protected T nextSibling;
+
+    private R localResult;
+
+    protected AbstractTask(PipelineHelper<P_IN, P_OUT> helper) {
+        super(null);
+        this.helper = helper;
+        this.spliterator = helper.sourceSpliterator();
+        this.targetSize = suggestTargetSize(spliterator.estimateSize());
+    }
+
+    protected AbstractTask(T parent, Spliterator<P_IN> spliterator) {
+        super(parent);
+        this.spliterator = spliterator;
+        this.helper = parent.helper;
+        this.targetSize = parent.targetSize;
+    }
+
+    /** Construct a new node of type T whose parent is the receiver; must call
+     * the AbstractTask(T, Spliterator) constructor with the receiver and the provided Spliterator. */
+    protected abstract T makeChild(Spliterator<P_IN> spliterator);
+
+    /** Compute the result associated with a leaf node */
+    protected abstract R doLeaf();
+
+    public static long suggestTargetSize(long sizeEstimate) {
+        if (sizeEstimate < 0)
+            sizeEstimate = 1000;  // @@@ SWAG
+        return 1 + ((sizeEstimate + 7) >>> 3) / ForkJoinPool.getCommonPoolParallelism();
+    }
+
+    public static<P_IN, P_OUT> boolean suggestSplit(PipelineHelper<P_IN, P_OUT> helper,
+                                                    Spliterator spliterator,
+                                                    long targetSize) {
+        long remaining = spliterator.estimateSize();
+        return (remaining > targetSize || remaining < 0);
+        // @@@ May want to fold in pool characteristics such as surplus task count
+    }
+
+    public boolean suggestSplit() {
+        return suggestSplit(helper, spliterator, targetSize);
+    }
+
+    @Override
+    public R getRawResult() {
+        return localResult;
+    }
+
+    @Override
+    protected void setRawResult(R r) {
+        if (r != null)
+            throw new IllegalStateException();
+    }
+
+    /**
+     * Retrieve a result previously stored with <code>setLocalResult</code>
+     */
+    protected R getLocalResult() {
+        return localResult;
+    }
+
+    /**
+     * Associate the result with the task, can be retrieved with <code>getLocalResult</code>
+     */
+    protected void setLocalResult(R localResult) {
+        this.localResult = localResult;
+    }
+
+    /** Is this task a leaf node?  (Only valid after <code>compute()</code> has been called on this node).
+     * If the node is not a leaf node, then children will be non-null and numChildren will be positive. */
+    protected boolean isLeaf() {
+        return children == null;
+    }
+
+    /** Is this task the root node? */
+    protected boolean isRoot() {
+        return getParent() == null;
+    }
+
+    /**
+     * Return the parent of this task, or null if this task is the root
+     */
+    protected T getParent() {
+        return (T) getCompleter();
+    }
+
+    /**
+     * Decide whether or not to split this task further or compute it directly.
+     * If computing directly, call <code>doLeaf</code> and pass the result to
+     * <code>setRawResult</code>.  If splitting, set up the child-related fields,
+     * create the child tasks, fork the rightmost child tasks, and compute the leftmost
+     * child task.
+     */
+    @Override
+    public void compute() {
+        Spliterator<P_IN> split = null;
+        if (!suggestSplit() || (split = spliterator.trySplit()) == null) {
+            setLocalResult(doLeaf());
+            tryComplete();
+        }
+        else {
+            // Common case -- binary splits
+            T leftChild = makeChild(split);
+            T rightChild = makeChild(spliterator);
+            setPendingCount(1);
+            numChildren = 2;
+            children = leftChild;
+            leftChild.nextSibling = rightChild;
+            rightChild.fork();
+            leftChild.compute();
+        }
+    }
+}
+
--- a/src/share/classes/java/util/stream/ConcurrentCollectors.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/ConcurrentCollectors.java	Thu Jan 10 21:50:21 2013 -0500
@@ -24,7 +24,9 @@
  */
 package java.util.stream;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.function.BinaryOperator;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/FindOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Optional;
+import java.util.OptionalInt;
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+
+abstract class FindOp<T, O> implements TerminalOp<T, O> {
+    public static final class OfReference<T> extends FindOp<T, Optional<T>> {
+
+        public static <T> FindOp<T, Optional<T>> any() {
+            return new OfReference<>(FindKind.ANY);
+        }
+
+        public static <T> FindOp<T, Optional<T>> first() {
+            return new OfReference<>(FindKind.FIRST);
+        }
+
+        private OfReference(FindKind findKind) {
+            super(findKind, StreamShape.REFERENCE);
+        }
+
+        @Override
+        protected Optional<T> emptyResult() {
+            return Optional.<T>empty();
+        }
+
+        @Override
+        protected Optional<T> find(Spliterator<T> spliterator) {
+            OpUtils.ValueHolder<T> vh = new OpUtils.ValueHolder<>();
+            if (spliterator.tryAdvance(vh))
+                return Optional.of(vh.get());
+            return null;
+        }
+
+        @Override
+        protected boolean isPresent(Optional<T> optional) {
+            return optional.isPresent();
+        }
+    }
+
+    public static final class OfInt extends FindOp<Integer, OptionalInt> {
+
+        public static FindOp<Integer, OptionalInt> any() {
+            return new OfInt(FindKind.ANY);
+        }
+
+        public static FindOp<Integer, OptionalInt> first() {
+            return new OfInt(FindKind.FIRST);
+        }
+
+        private OfInt(FindKind findKind) {
+            super(findKind, StreamShape.INT_VALUE);
+        }
+
+        @Override
+        protected OptionalInt emptyResult() {
+            return OptionalInt.empty();
+        }
+
+        @Override
+        protected OptionalInt find(Spliterator<Integer> spliterator) {
+            OpUtils.PrimitiveValueHolder.OfInt vh = new OpUtils.PrimitiveValueHolder.OfInt();
+            if (AbstractPipeline.adapt(spliterator).tryAdvance(vh))
+                return OptionalInt.of(vh.getAsInt());
+            return null;
+        }
+
+        @Override
+        protected boolean isPresent(OptionalInt optional) {
+            return optional.isPresent();
+        }
+    }
+
+    private enum FindKind {
+        ANY,
+        FIRST
+    }
+
+    private final FindKind findKind;
+
+    private final StreamShape shape;
+
+    private FindOp(FindKind findKind, StreamShape shape) {
+        this.findKind = findKind;
+        this.shape = shape;
+    }
+
+    protected abstract O emptyResult();
+
+    protected abstract O find(Spliterator<T> spliterator);
+
+    protected abstract boolean isPresent(O optional);
+
+    @Override
+    public StreamShape inputShape() {
+        return shape;
+    }
+
+    @Override
+    public <S> O evaluateSequential(PipelineHelper<S, T> helper) {
+        Spliterator<T> spliterator = helper.wrapSequential(helper.sourceSpliterator());
+        O result = find(spliterator);
+        return result != null ? result : emptyResult();
+    }
+
+    @Override
+    public <P_IN> O evaluateParallel(PipelineHelper<P_IN, T> helper) {
+        return new FindTask<>(helper, this).invoke();
+    }
+
+    private static class FindTask<S, T, O> extends AbstractShortCircuitTask<S, T, O, FindTask<S, T, O>> {
+        private final FindOp<T, O> op;
+
+        private FindTask(PipelineHelper<S, T> helper, FindOp<T, O> op) {
+            super(helper);
+            this.op = op;
+        }
+
+        private FindTask(FindTask<S, T, O> parent, Spliterator<S> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+        }
+
+        @Override
+        protected FindTask<S, T, O> makeChild(Spliterator<S> spliterator) {
+            return new FindTask<>(this, spliterator);
+        }
+
+        @Override
+        protected O getEmptyResult() {
+            return op.emptyResult();
+        }
+
+        private void foundResult(O answer) {
+            if (isLeftSpine())
+                shortCircuit(answer);
+            else
+                cancelLaterNodes();
+        }
+
+        @Override
+        protected O doLeaf() {
+            Spliterator<T> wrapped = helper.wrapSequential(spliterator);
+            if (op.findKind == FindKind.ANY) {
+                O result = op.find(wrapped);
+                if (result != null)
+                    shortCircuit(result);
+                return null;
+            }
+            else {
+                O result = op.find(wrapped);
+                if (result != null) {
+                    foundResult(result);
+                    return result;
+                }
+                else
+                    return null;
+            }
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (op.findKind == FindKind.FIRST) {
+                for (FindTask<S, T, O> child = children; child != null; child = child.nextSibling) {
+                    O result = child.getLocalResult();
+                    if (result != null && op.isPresent(result)) {
+                        setLocalResult(result);
+                        foundResult(result);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/FoldOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Optional;
+import java.util.OptionalInt;
+import java.util.function.*;
+
+/**
+ * FoldOp
+ *
+ * @author Brian Goetz
+ */
+class FoldOp<T, R, S extends OpUtils.AccumulatingSink<T, R, S>> implements TerminalOp<T, R> {
+    private final Supplier<S> sinkSupplier;
+    private final StreamShape inputShape;
+
+    public FoldOp(StreamShape shape, Supplier<S> supplier) {
+        sinkSupplier = supplier;
+        inputShape = shape;
+    }
+
+    public FoldOp(Supplier<S> supplier) {
+        this(StreamShape.REFERENCE, supplier);
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return inputShape;
+    }
+
+    public <S> R evaluateSequential(PipelineHelper<S, T> helper) {
+        return helper.into(sinkSupplier.get(), helper.sourceSpliterator()).getAndClearState();
+    }
+
+    @Override
+    public <S> R evaluateParallel(PipelineHelper<S, T> helper) {
+        return OpUtils.parallelReduce(helper, sinkSupplier);
+    }
+
+
+    private static abstract class Box<U> {
+        protected U state;
+
+        public void clearState() {
+            state = null;
+        }
+
+        public U getAndClearState() {
+            try { return state; }
+            finally { state = null; }
+        }
+    }
+
+    private static abstract class OptionalBox<U> {
+        protected boolean empty;
+        protected U state;
+
+        public void begin(long size) {
+            empty = true;
+            state = null;
+        }
+
+        public void clearState() {
+            empty = true;
+            state = null;
+        }
+
+        public Optional<U> getAndClearState() {
+            try { return empty ? Optional.<U>empty() : Optional.of(state); }
+            finally { clearState(); }
+        }
+    }
+
+    private static abstract class IntBox {
+        protected int state;
+
+        public void begin(long size) {
+            state = 0;
+        }
+
+        public void clearState() {
+            state = 0;
+        }
+
+        public Integer getAndClearState() {
+            try { return state; }
+            finally { state = 0; }
+        }
+    }
+
+    private static abstract class OptionalIntBox {
+        protected boolean empty;
+        protected int state;
+
+        public void begin(long size) {
+            empty = true;
+            state = 0;
+        }
+
+        public void clearState() {
+            state = 0;
+        }
+
+        public OptionalInt getAndClearState() {
+            try { return empty ? OptionalInt.empty() : OptionalInt.of(state); }
+            finally { state = 0; }
+        }
+    }
+
+    public static<T, U> TerminalOp<T, U>
+    makeRef(U seed, BiFunction<U, ? super T, U> reducer, BinaryOperator<U> combiner) {
+        class FoldingSink extends Box<U> implements OpUtils.AccumulatingSink<T, U, FoldingSink>, Sink.OfReference<T> {
+            @Override
+            public void begin(long size) {
+                state = seed;
+            }
+
+            @Override
+            public void accept(T t) {
+                state = reducer.apply(state, t);
+            }
+
+            @Override
+            public void combine(FoldingSink other) {
+                state = combiner.apply(state, other.state);
+            }
+        }
+        // @@@ Replace inner class suppliers with ctor refs or lambdas pending fix of compiler bug(s)
+        return new FoldOp<>(new Supplier<FoldingSink>() {
+            @Override
+            public FoldingSink get() {return new FoldingSink();}
+        });
+    }
+
+    public static<T> TerminalOp<T, Optional<T>>
+    makeRef(BinaryOperator<T> operator) {
+        class FoldingSink extends OptionalBox<T> implements OpUtils.AccumulatingSink<T, Optional<T>, FoldingSink> {
+
+            @Override
+            public void accept(T t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                } else {
+                    state = operator.apply(state, t);
+                }
+            }
+
+            @Override
+            public void combine(FoldingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+        return new FoldOp<>(new Supplier<FoldingSink>() {
+            @Override
+            public FoldingSink get() {return new FoldingSink();}
+        });
+    }
+
+    public static<T,R> TerminalOp<T, R>
+    makeRef(Collector<? super T,R> collector) {
+        class FoldingSink extends Box<R> implements OpUtils.AccumulatingSink<T, R, FoldingSink> {
+            @Override
+            public void begin(long size) {
+                state = collector.makeResult();
+            }
+
+            @Override
+            public void accept(T t) {
+                collector.accumulate(state, t);
+            }
+
+            @Override
+            public void combine(FoldingSink other) {
+                state = collector.combine(state, other.state);
+            }
+        }
+        return new FoldOp<>(new Supplier<FoldingSink>() {
+            @Override
+            public FoldingSink get() {return new FoldingSink();}
+        });
+    }
+
+    public static<T, R> TerminalOp<T, R>
+    makeRef(Supplier<R> seedFactory, BiBlock<R, ? super T> accumulator, BiBlock<R,R> reducer) {
+        class FoldingSink extends Box<R> implements OpUtils.AccumulatingSink<T, R, FoldingSink> {
+            @Override
+            public void begin(long size) {
+                state = seedFactory.get();
+            }
+
+            @Override
+            public void accept(T t) {
+                accumulator.accept(state, t);
+            }
+
+            @Override
+            public void combine(FoldingSink other) {
+                reducer.accept(state, other.state);
+            }
+        }
+        return new FoldOp<>(new Supplier<FoldingSink>() {
+            @Override
+            public FoldingSink get() {return new FoldingSink();}
+        });
+    }
+
+    public static TerminalOp<Integer, Integer>
+    makeInt(int identity, IntBinaryOperator operator) {
+        class FoldingSink extends IntBox implements OpUtils.AccumulatingSink<Integer, Integer, FoldingSink>, Sink.OfInt {
+            @Override
+            public void begin(long size) {
+                state = identity;
+            }
+
+            @Override
+            public void accept(int t) {
+                state = operator.applyAsInt(state, t);
+            }
+
+            @Override
+            public void combine(FoldingSink other) {
+                accept(other.state);
+            }
+        }
+        return new FoldOp<>(StreamShape.INT_VALUE, new Supplier<FoldingSink>() {
+            @Override
+            public FoldingSink get() {
+                return new FoldingSink();
+            }
+        });
+    }
+
+    public static TerminalOp<Integer, OptionalInt>
+    makeInt(IntBinaryOperator operator) {
+        class FoldingSink extends OptionalIntBox implements OpUtils.AccumulatingSink<Integer, OptionalInt, FoldingSink>, Sink.OfInt {
+            @Override
+            public void accept(int t) {
+                if (empty) {
+                    empty = false;
+                    state = t;
+                }
+                else {
+                    state = operator.applyAsInt(state, t);
+                }
+            }
+
+            @Override
+            public void combine(FoldingSink other) {
+                if (!other.empty)
+                    accept(other.state);
+            }
+        }
+
+        return new FoldOp<>(StreamShape.INT_VALUE, new Supplier<FoldingSink>() {
+            @Override
+            public FoldingSink get() {
+                return new FoldingSink();
+            }
+        });
+    }
+
+    public static <R> TerminalOp<Integer, R>
+    makeInt(Collector.OfInt<R> reducer) {
+        class FoldingSink extends Box<R> implements OpUtils.AccumulatingSink<Integer, R, FoldingSink>, Sink.OfInt {
+            @Override
+            public void begin(long size) {
+                state = reducer.makeResult();
+            }
+
+            @Override
+            public void accept(int t) {
+                reducer.accumulateAsInt(state, t);
+            }
+
+            @Override
+            public void combine(FoldingSink other) {
+                state = reducer.combine(state, other.state);
+            }
+        }
+
+        return new FoldOp<>(StreamShape.INT_VALUE, new Supplier<FoldingSink>() {
+            @Override
+            public FoldingSink get() {
+                return new FoldingSink();
+            }
+        });
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/ForEachOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.function.Block;
+import java.util.function.IntBlock;
+
+/**
+ * ForEachOp
+ *
+ * @author Brian Goetz
+ */
+class ForEachOp<T> implements TerminalOp<T, Void> {
+    protected final TerminalSink<T, Void> sink;
+    protected final StreamShape shape;
+
+    protected ForEachOp(TerminalSink<T, Void> sink, StreamShape shape) {
+        this.shape = Objects.requireNonNull(shape);
+        this.sink = Objects.requireNonNull(sink);
+    }
+
+    protected interface VoidTerminalSink<T> extends TerminalSink<T, Void> {
+        @Override
+        default public Void getAndClearState() {
+            return null;
+        }
+
+        public interface OfInt extends VoidTerminalSink<Integer>, Sink.OfInt { }
+    }
+
+    public static <T> ForEachOp<T> make(final Block<? super T> block) {
+        Objects.requireNonNull(block);
+        return new ForEachOp<>((VoidTerminalSink<T>) block::accept, StreamShape.REFERENCE);
+    }
+
+    public static ForEachOp<Integer> make(final IntBlock block) {
+        Objects.requireNonNull(block);
+        // @@@ Should use lambda, but there's a translation bug
+        return new ForEachOp<>(new VoidTerminalSink.OfInt() {
+            @Override
+            public void accept(int i) {block.accept(i);}
+        }, StreamShape.INT_VALUE);
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return shape;
+    }
+
+    @Override
+    public <S> Void evaluateSequential(PipelineHelper<S, T> helper) {
+        return helper.into(sink, helper.sourceSpliterator()).getAndClearState();
+    }
+
+    @Override
+    public <S> Void evaluateParallel(PipelineHelper<S, T> helper) {
+        OpUtils.parallelForEach(helper, helper.wrapSink(sink), false);
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/ForEachUntilOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Objects;
+import java.util.function.Block;
+import java.util.function.BooleanSupplier;
+import java.util.function.IntBlock;
+
+/**
+ * ForEachWhileOp
+ *
+ * @author Brian Goetz
+ */
+class ForEachUntilOp<T> extends ForEachOp<T> implements TerminalOp<T, Void> {
+    public ForEachUntilOp(TerminalSink<T, Void> sink, StreamShape shape) {
+        super(sink, shape);
+    }
+
+    public static <T> ForEachUntilOp<T> make(final Block<? super T> block, BooleanSupplier until) {
+        Objects.requireNonNull(block);
+        return new ForEachUntilOp<>(new VoidTerminalSink<T>() {
+            @Override
+            public void accept(T t) {
+                block.accept(t);
+            }
+
+            @Override
+            public boolean cancellationRequested() {
+                return until.getAsBoolean();
+            }
+        }, StreamShape.REFERENCE);
+    }
+
+    public static ForEachUntilOp make(final IntBlock block, BooleanSupplier until) {
+        Objects.requireNonNull(block);
+        return new ForEachUntilOp<>(new VoidTerminalSink.OfInt() {
+            @Override
+            public void accept(int i) {
+                block.accept(i);
+            }
+
+            @Override
+            public boolean cancellationRequested() {
+                return until.getAsBoolean();
+            }
+        }, StreamShape.INT_VALUE);
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlag.IS_SHORT_CIRCUIT;
+    }
+
+    @Override
+    public <S> Void evaluateSequential(PipelineHelper<S, T> helper) {
+        Sink<S> wrappedSink = helper.wrapSink(sink);
+        wrappedSink.begin(-1); // Size unknown, since we might stop early
+        inputShape().forEachWithCancel(helper.sourceSpliterator(), wrappedSink);
+        wrappedSink.end();
+        return null;
+    }
+
+    @Override
+    public <S> Void evaluateParallel(PipelineHelper<S, T> helper) {
+        OpUtils.parallelForEach(helper, helper.wrapSink(sink), true);
+        return null;
+    }
+}
--- a/src/share/classes/java/util/stream/IntPipeline.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/IntPipeline.java	Thu Jan 10 21:50:21 2013 -0500
@@ -24,11 +24,13 @@
  */
 package java.util.stream;
 
-import java.util.*;
+import java.util.Objects;
+import java.util.OptionalInt;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
 import java.util.function.*;
-import java.util.stream.op.*;
 
-public class IntPipeline<E_IN> extends AbstractPipeline<E_IN, Integer, IntStream> implements IntStream {
+class IntPipeline<E_IN> extends AbstractPipeline<E_IN, Integer, IntStream> implements IntStream {
 
     public IntPipeline(Supplier<? extends Spliterator<Integer>> source, int sourceFlags) {
         super((Supplier) source, sourceFlags);
--- a/src/share/classes/java/util/stream/IntStream.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/IntStream.java	Thu Jan 10 21:50:21 2013 -0500
@@ -24,7 +24,10 @@
  */
 package java.util.stream;
 
-import java.util.*;
+import java.util.OptionalDouble;
+import java.util.OptionalInt;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
 import java.util.function.*;
 
 public interface IntStream extends BaseStream<Integer> {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/IntermediateOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * An operation performed upon elements from an input stream to produce elements to
+ * an output stream.
+ * <p>By default the operation is stateless and not short-circuiting.</p>
+ *
+ * @param <E_IN>  Type of input elements to the operation.
+ * @param <E_OUT> Type of output elements to the operation.
+ * @author Brian Goetz
+ */
+public interface IntermediateOp<E_IN, E_OUT> extends StreamOp<E_IN, Node<E_OUT>> {
+
+    /**
+     *
+     * @return the output shape of this operation.
+     */
+    default StreamShape outputShape() { return StreamShape.REFERENCE; }
+
+    /**
+     * If {@code true} then operation is stateful and accumulates state.
+     *
+     * @return {@code true} then operation is stateful and accumulates state.
+     */
+    default boolean isStateful() { return false; }
+
+    /**
+     * Return a sink which will accept elements, perform the operation upon
+     * each element and send it to the provided sink.
+     *
+     *
+     * @param flags the combined stream and operation flags up to but not including this operation.
+     * @param sink elements will be sent to this sink after the processing.
+     * @return a sink which will accept elements and perform the operation upon
+     *         each element.
+     */
+    Sink<E_IN> wrapSink(int flags, Sink<E_OUT> sink);
+
+    @Override
+    default <P_IN> Node<E_OUT> evaluateSequential(PipelineHelper<P_IN, E_IN> helper) {
+        // If this operation preserves the size then defer to the size, if known, from the helper
+        long size = StreamOpFlag.SIZED.isPreserved(getOpFlags()) ? helper.getOutputSizeIfKnown() : -1;
+        final Node.Builder<E_OUT> nb = outputShape().nodeFactory().makeNodeBuilder(size, helper.arrayGenerator());
+        Sink<E_IN> wrapped = wrapSink(helper.getStreamAndOpFlags(), nb);
+        helper.into(wrapped, helper.sourceSpliterator());
+        return nb.build();
+    }
+
+    interface OfInt extends IntermediateOp<Integer, Integer> {
+        @Override
+        public default StreamShape inputShape() {
+            return StreamShape.INT_VALUE;
+        }
+
+        @Override
+        public default StreamShape outputShape() {
+            return StreamShape.INT_VALUE;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/MatchOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.function.Block;
+import java.util.function.IntBlock;
+import java.util.function.IntPredicate;
+import java.util.function.Predicate;
+
+/**
+ * MatchOp
+ *
+ * @author Brian Goetz
+ */
+public abstract class MatchOp<T> implements TerminalOp<T, Boolean> {
+    protected final MatchKind matchKind;
+    private final StreamShape inputShape;
+
+    private MatchOp(MatchKind matchKind, StreamShape shape) {
+        this.matchKind = matchKind;
+        this.inputShape = shape;
+    }
+
+    public static final class OfReference<T> extends MatchOp<T>  {
+        private final Predicate<? super T> predicate;
+
+        public static <T> MatchOp<T> match(Predicate<? super T> predicate, MatchKind matchKind) {
+            return new OfReference<>(predicate, matchKind);
+        }
+
+        private OfReference(Predicate<? super T> predicate, MatchKind matchKind) {
+            super(matchKind, StreamShape.REFERENCE);
+            this.predicate = predicate;
+        }
+
+        protected Boolean evaluateMatch(Spliterator<T> spliterator) {
+            class Matcher implements Block<T> {
+                private boolean stop;
+
+                @Override
+                public void accept(T t) {
+                    if (predicate.test(t) == matchKind.stopOnPredicateMatches)
+                        stop = true;
+                }
+            }
+            Matcher m = new Matcher();
+            while (spliterator.tryAdvance(m)) {
+                if (m.stop)
+                    return matchKind.shortCircuitResult;
+            }
+
+            return !matchKind.shortCircuitResult;
+        }
+    }
+
+    public static final class OfInt extends MatchOp<Integer> {
+        private final IntPredicate predicate;
+
+        public static MatchOp<Integer> match(IntPredicate predicate, MatchKind matchKind) {
+            return new OfInt(predicate, matchKind);
+        }
+
+        private OfInt(IntPredicate predicate, MatchKind matchKind) {
+            super(matchKind, StreamShape.INT_VALUE);
+            this.predicate = predicate;
+        }
+
+        protected Boolean evaluateMatch(Spliterator<Integer> spliterator) {
+            class Matcher implements IntBlock {
+                private boolean stop;
+
+                @Override
+                public void accept(int t) {
+                    if (predicate.test(t) == matchKind.stopOnPredicateMatches)
+                        stop = true;
+                }
+            }
+            Spliterator.OfPrimitive<Integer> intIterator = AbstractPipeline.adapt(spliterator);
+            Matcher m = new Matcher();
+            while (intIterator.tryAdvance(m)) {
+                if (m.stop)
+                    return matchKind.shortCircuitResult;
+            }
+
+            return !matchKind.shortCircuitResult;
+        }
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return inputShape;
+    }
+
+    @Override
+    public <S> Boolean evaluateSequential(PipelineHelper<S, T> helper) {
+        return evaluateMatch(helper.wrapSequential(helper.sourceSpliterator()));
+    }
+
+    protected abstract Boolean evaluateMatch(Spliterator<T> spliterator);
+
+    @Override
+    public <S> Boolean evaluateParallel(PipelineHelper<S, T> helper) {
+        // Approach for parallel implementation:
+        // - Decompose as per usual
+        // - run match on leaf chunks, call result "b"
+        // - if b == matchKind.shortCircuitOn, complete early and return b
+        // - else if we complete normally, return !shortCircuitOn
+
+        return new MatchTask<>(this, helper).invoke();
+    }
+
+    private static class MatchTask<S, T> extends AbstractShortCircuitTask<S, T, Boolean, MatchTask<S, T>> {
+        private final MatchOp<T> op;
+
+        private MatchTask(MatchOp<T> op, PipelineHelper<S, T> helper) {
+            super(helper);
+            this.op = op;
+        }
+
+        private MatchTask(MatchTask<S, T> parent, Spliterator<S> spliterator) {
+            super(parent, spliterator);
+            this.op = parent.op;
+        }
+
+        @Override
+        protected MatchTask<S, T> makeChild(Spliterator<S> spliterator) {
+            return new MatchTask<>(this, spliterator);
+        }
+
+        @Override
+        protected Boolean doLeaf() {
+            boolean b = op.evaluateMatch(helper.wrapSequential(spliterator));
+            if (b == op.matchKind.shortCircuitResult)
+                shortCircuit(b);
+            return null;
+        }
+
+        @Override
+        protected Boolean getEmptyResult() {
+            return !op.matchKind.shortCircuitResult;
+        }
+    }
+
+    public enum MatchKind {
+        ANY(true, true),
+        ALL(false, false),
+        NONE(true, false);
+
+        private final boolean stopOnPredicateMatches;
+        private final boolean shortCircuitResult;
+
+        private MatchKind(boolean stopOnPredicateMatches, boolean shortCircuitResult) {
+            this.stopOnPredicateMatches = stopOnPredicateMatches;
+            this.shortCircuitResult = shortCircuitResult;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/Node.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Iterator;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.function.Block;
+import java.util.function.IntBlock;
+import java.util.function.ObjIntFunction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * An immutable container of elements.
+ * <p>The container may be flat, and have no children, or a tree whose shape corresponds to the computation
+ * tree that produced the tree where the elements are contained in the leaf nodes.</p>
+ * @param <T> the type of elements.
+ */
+public interface Node<T> extends Iterable<T> {
+
+    /**
+     *
+     * @return the spliterator for this node.
+     */
+    Spliterator<T> spliterator();
+
+    @Override
+    default Iterator<T> iterator() {
+        return spliterator().iterator();
+    }
+
+    /**
+     *
+     * @return the number of child nodes
+     */
+    default int getChildCount() {
+        return 0;
+    }
+
+    /**
+     * Get a child node at a given index.
+     *
+     * @param i the index to the child node
+     * @return the child node.
+     * @throws IndexOutOfBoundsException if the index is less than 0 or greater than or equal to the
+     * number of child nodes.
+     */
+    default Node<T> getChild(int i) {
+        throw new IndexOutOfBoundsException();
+    }
+
+    /**
+     * View this node as an array.
+     * <p/>
+     * <p>Depending on the underlying implementation this may return a reference to an internal array rather than
+     * a copy. It is the callers responsibility to decide if either this node or the array is
+     * utilized as the primary reference for the data.</p>
+     *
+     * @return the array.
+     */
+    T[] asArray(ObjIntFunction<T[]> generator);
+
+    /**
+     * Copy the content of this node into an array at an offset.
+     *
+     * @param array the array to copy the data into.
+     * @param offset the offset into the array.
+     * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds.
+     * @throws NullPointerException if <code>array</code> is <code>null</code>.
+     */
+    void copyInto(T[] array, int offset);
+
+    /**
+     * Return the number of elements contained by this node
+     */
+    long count();
+
+    /**
+     * A specialization of a {@link java.util.stream.Sink} to build a flat node whose contents
+     * is all the pushed elements.
+     *
+     */
+    interface Builder<T> extends Sink.OfReference<T> {
+
+        /**
+         * Build the node.
+         * <p>This method should be called after all elements have been pushed and signalled with
+         * an invocation of {@link java.util.stream.Sink#end()}.</p>
+         *
+         * @return the built node.
+         */
+        Node<T> build();
+    }
+
+    /**
+     * An immutable container of values.
+     * <p>The container may be flat, and have no children, or a tree whose shape corresponds to the computation
+     * tree that produced the tree where the values are contained in the leaf nodes.</p>
+     */
+    interface OfPrimitive<E> extends Node<E> {
+
+        // Iterable
+
+        @Override
+        default PrimitiveIterator<E> iterator() {
+            return spliterator().iterator();
+        }
+
+        @Override
+        void forEach(Block<? super E> block);
+
+        default void forEach(IntBlock block) {
+            throw new UnsupportedOperationException();
+        }
+
+        //
+
+        @Override
+        default Node.OfPrimitive<E> getChild(int i) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        @Override
+        Spliterator.OfPrimitive<E> spliterator();
+
+        @Override
+        default E[] asArray(ObjIntFunction<E[]> generator) {
+            throw new UnsupportedOperationException();
+        }
+
+        default int[] asIntArray() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        default void copyInto(E[] array, int offset) throws IndexOutOfBoundsException {
+            throw new UnsupportedOperationException();
+        }
+
+        default void copyInto(int[] array, int offset) {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * A specialization of a {@link java.util.stream.Sink} to build a flat primitive node whose contents
+         * is all the pushed values.
+         *
+         */
+        interface Builder<E> extends Node.Builder<E> {
+
+            @Override
+            Node.OfPrimitive<E> build();
+
+            interface OfInt extends Builder<Integer>, Sink.OfInt {
+            }
+        }
+    }
+
+    interface OfInt extends OfPrimitive<Integer> {
+
+        @Override
+        default void forEach(Block<? super Integer> sink) {
+            if (sink instanceof IntBlock) {
+                forEach((IntBlock) sink);
+            }
+            else {
+                Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using boxed int", getClass().getName());
+                spliterator().forEach(sink);
+            }
+        }
+
+        @Override
+        default void forEach(IntBlock block) {
+            spliterator().forEach(block);
+        }
+
+        //
+
+        int[] asIntArray();
+
+        void copyInto(int[] array, int offset) throws IndexOutOfBoundsException;
+    }
+}
--- a/src/share/classes/java/util/stream/NodeFactory.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/NodeFactory.java	Thu Jan 10 21:50:21 2013 -0500
@@ -27,7 +27,6 @@
 import java.util.List;
 import java.util.Spliterator;
 import java.util.function.ObjIntFunction;
-import java.util.stream.op.Node;
 
 public interface NodeFactory<T> {
     Node<T> emptyNode();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/NodeUtils.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Arrays;
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.ObjIntFunction;
+
+/**
+ * Utilities for generating and operating on reference-based Nodes.
+ *
+ * @author Brian Goetz
+ */
+public final class NodeUtils {
+
+    private NodeUtils() {
+        throw new Error("no instances");
+    }
+
+    public static <P_IN, P_OUT> Node<P_OUT> collect(PipelineHelper<P_IN, P_OUT> helper,
+                                                    boolean flattenTree) {
+        Spliterator<P_IN> spliterator = helper.sourceSpliterator();
+        long size = spliterator.exactSizeIfKnown();
+        if (size >= 0 && helper.getOutputSizeIfKnown() == size && spliterator.hasExactSplits()) {
+            if (size >= Streams.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException("Stream size exceeds max array size");
+            P_OUT[] array = helper.arrayGenerator().apply((int) size);
+            new SizedCollectorTask<>(spliterator, helper, array).invoke();
+            return Nodes.node(array);
+        } else {
+            Node<P_OUT> node = new CollectorTask<>(helper).invoke();
+
+            // @@@ using default F/J pool, will that be different from that used by helper.invoke?
+            return flattenTree ? flatten(node, helper.arrayGenerator()) : node;
+        }
+    }
+
+    public static <T> Node<T> flatten(Node<T> node, ObjIntFunction<T[]> generator) {
+        if (node.getChildCount() > 0) {
+            T[] array = generator.apply((int) node.count());
+            new ToArrayTask<>(node, array, 0).invoke();
+            return Nodes.node(array);
+        } else {
+            return node;
+        }
+    }
+
+    public static <P_IN> Node.OfPrimitive<Integer> intCollect(PipelineHelper<P_IN, Integer> helper,
+                                                           boolean flattenTree) {
+        Spliterator<P_IN> spliterator = helper.sourceSpliterator();
+        long size = spliterator.exactSizeIfKnown();
+        if (size >= 0 && helper.getOutputSizeIfKnown() == size && spliterator.hasExactSplits()) {
+            if (size >= Streams.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException("Stream size exceeds max array size");
+            int[] array = new int[(int) size];
+            new SizedIntCollectorTask<>(spliterator, helper, array).invoke();
+            return Nodes.intNode(array);
+        }
+        else {
+            Node.OfPrimitive<Integer> node = new IntCollectorTask<>(helper).invoke();
+
+            // @@@ using default F/J pool, will that be different from that used by helper.invoke?
+            return flattenTree ? intFlatten(node) : node;
+        }
+    }
+
+    public static Node.OfPrimitive<Integer> intFlatten(Node.OfPrimitive<Integer> node) {
+        if (node.getChildCount() > 0) {
+            int[] array = new int[(int) node.count()];
+            new IntToArrayTask(node, array, 0).invoke();
+            return Nodes.intNode(array);
+        } else {
+            return node;
+        }
+    }
+
+    // Reference implementations
+
+    private static class CollectorTask<T, U> extends AbstractTask<T, U, Node<U>, CollectorTask<T, U>> {
+        private final PipelineHelper<T, U> helper;
+
+        private CollectorTask(PipelineHelper<T, U> helper) {
+            super(helper);
+            this.helper = helper;
+        }
+
+        private CollectorTask(CollectorTask<T, U> parent, Spliterator<T> spliterator) {
+            super(parent, spliterator);
+            helper = parent.helper;
+        }
+
+        @Override
+        protected CollectorTask<T, U> makeChild(Spliterator<T> spliterator) {
+            return new CollectorTask<>(this, spliterator);
+        }
+
+        @Override
+        protected Node<U> doLeaf() {
+            Node.Builder<U> builder = Nodes.makeBuilder(helper.getOutputSizeIfKnown() >= 0 ? spliterator.exactSizeIfKnown() : -1,
+                                                        helper.arrayGenerator());
+            OpUtils.intoWrapped(spliterator, helper.wrapSink(builder));
+            return builder.build();
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter caller) {
+            if (!isLeaf()) {
+                @SuppressWarnings("unchecked")
+                Node<U>[] nodes = (Node<U>[]) new Node[numChildren];
+                int idx = 0;
+                for (CollectorTask<T, U> cur = children; cur != null; cur = cur.nextSibling)
+                    nodes[idx++] = cur.getLocalResult();
+                setLocalResult(Nodes.node(nodes));
+            }
+        }
+    }
+
+    private static class SizedCollectorTask<T, U> extends CountedCompleter<Void> {
+        private final Spliterator<T> spliterator;
+        private final PipelineHelper<T, U> helper;
+        private final U[] array;
+        private final long targetSize;
+        private long offset;
+        private long length;
+
+        private SizedCollectorTask(Spliterator<T> spliterator, PipelineHelper<T, U> helper, U[] array) {
+            this.spliterator = spliterator;
+            this.helper = helper;
+            this.array = array;
+            this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
+            this.offset = 0;
+            this.length = array.length;
+        }
+
+        private SizedCollectorTask(SizedCollectorTask<T, U> parent, Spliterator<T> spliterator, long offset, long length) {
+            super(parent);
+            this.spliterator = spliterator;
+            this.helper = parent.helper;
+            this.array = parent.array;
+            this.targetSize = parent.targetSize;
+            this.offset = offset;
+            this.length = length;
+
+            if (offset < 0 || length < 0 || (offset + length - 1 >= array.length)) {
+                throw new IllegalArgumentException(
+                        String.format("offset and length interval [%d, %d + %d) is not within array size interval [0, %d)",
+                                      offset, offset, length, array.length));
+            }
+        }
+
+        @Override
+        public void compute() {
+            Spliterator<T> split;
+            if (!AbstractTask.suggestSplit(helper, spliterator, targetSize) || ((split = spliterator.trySplit()) == null)) {
+                if (offset+length >= Streams.MAX_ARRAY_SIZE)
+                    throw new IllegalArgumentException("Stream size exceeds max array size");
+                OpUtils.intoUnwrapped(helper, spliterator, Arrays.sink(array, (int) offset, (int) length));
+                tryComplete();
+            }
+            else {
+                setPendingCount(1);
+                long thisSplitSize = split.exactSizeIfKnown();
+                new SizedCollectorTask<>(this, split, offset, thisSplitSize).fork();
+                new SizedCollectorTask<>(this, spliterator, offset + thisSplitSize, length - thisSplitSize).compute();
+            }
+        }
+    }
+
+    private static class ToArrayTask<T> extends CountedCompleter<Void> {
+        private final T[] array;
+        private final Node<T> node;
+        private final int offset;
+
+        private ToArrayTask(Node<T> node, T[] array, int offset) {
+            this.array = array;
+            this.node = node;
+            this.offset = offset;
+        }
+
+        private ToArrayTask(ToArrayTask<T> parent, Node<T> node, int offset) {
+            super(parent);
+            this.array = parent.array;
+            this.node = node;
+            this.offset = offset;
+        }
+
+        @Override
+        public void compute() {
+            if (node.getChildCount() > 0) {
+                setPendingCount(node.getChildCount() - 1);
+
+                final ToArrayTask<T> firstTask = new ToArrayTask<>(this, node.getChild(0), offset);
+                int size = (int) firstTask.node.count();
+
+                for (int i = 1; i < node.getChildCount(); i++) {
+                    final ToArrayTask<T> task = new ToArrayTask<>(this, node.getChild(i), offset + size);
+                    size += task.node.count();
+                    task.fork();
+                }
+                firstTask.compute();
+            } else {
+                node.copyInto(array, offset);
+                tryComplete();
+            }
+        }
+    }
+
+    // Int value implementations
+
+    // @@@ Note that the size collector task and to array task for references and
+    // primitives can unified with appropriate SAMs abstracting the details
+    // of push leaf data to an array or copying node data to an array at an offset.
+
+    private static class IntCollectorTask<T> extends AbstractTask<T, Integer, Node.OfPrimitive<Integer>, IntCollectorTask<T>> {
+        private final PipelineHelper<T, Integer> helper;
+
+        private IntCollectorTask(PipelineHelper<T, Integer> helper) {
+            super(helper);
+            this.helper = helper;
+        }
+
+        private IntCollectorTask(IntCollectorTask<T> parent, Spliterator<T> spliterator) {
+            super(parent, spliterator);
+            helper = parent.helper;
+        }
+
+        @Override
+        protected IntCollectorTask<T> makeChild(Spliterator<T> spliterator) {
+            return new IntCollectorTask<>(this, spliterator);
+        }
+
+        @Override
+        protected Node.OfPrimitive<Integer> doLeaf() {
+            Node.OfPrimitive.Builder<Integer> builder = Nodes.makeIntBuilder(helper.getOutputSizeIfKnown() >= 0 ? spliterator.exactSizeIfKnown() : -1);
+            OpUtils.intoWrapped(spliterator, helper.wrapSink(builder));
+            return builder.build();
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter caller) {
+            if (!isLeaf()) {
+                Node.OfPrimitive<Integer>[] nodes = new Node.OfInt[numChildren];
+                int idx = 0;
+                for (IntCollectorTask<T> cur = children; cur != null; cur = cur.nextSibling)
+                    nodes[idx++] = cur.getLocalResult();
+
+                setLocalResult(Nodes.intNode(nodes));
+            }
+        }
+    }
+
+    private static class SizedIntCollectorTask<T> extends CountedCompleter<Void> {
+        private final Spliterator<T> spliterator;
+        private final PipelineHelper<T, Integer> helper;
+        private final int[] array;
+        private final long targetSize;
+        private long offset;
+        private long length;
+
+        private SizedIntCollectorTask(Spliterator<T> spliterator, PipelineHelper<T, Integer> helper, int[] array) {
+            this.spliterator = spliterator;
+            this.helper = helper;
+            this.array = array;
+            this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
+            this.offset = 0;
+            this.length = array.length;
+        }
+
+        private SizedIntCollectorTask(SizedIntCollectorTask<T> parent, Spliterator<T> spliterator, long offset, long length) {
+            super(parent);
+            this.spliterator = spliterator;
+            this.helper = parent.helper;
+            this.array = parent.array;
+            this.targetSize = parent.targetSize;
+            this.offset = offset;
+            this.length = length;
+
+            if (offset < 0 || length < 0 || (offset + length - 1 >= array.length)) {
+                throw new IllegalArgumentException(
+                        String.format("offset and length interval [%d, %d + %d) is not within array size interval [0, %d)",
+                                      offset, offset, length, array.length));
+            }
+        }
+
+        @Override
+        public void compute() {
+            Spliterator<T> split = null;
+            if (!AbstractTask.suggestSplit(helper, spliterator, targetSize) || ((split = spliterator.trySplit()) == null)) {
+                if (offset+length >= Streams.MAX_ARRAY_SIZE)
+                    throw new IllegalArgumentException("Stream size exceeds max array size");
+                OpUtils.intoUnwrapped(helper, spliterator, Arrays.sink(array, (int) offset, (int) length));
+                tryComplete();
+            }
+            else {
+                setPendingCount(1);
+                long thisSplitSize = split.exactSizeIfKnown();
+                new SizedIntCollectorTask<>(this, split, offset, thisSplitSize).fork();
+                new SizedIntCollectorTask<>(this, spliterator, offset + thisSplitSize, length - thisSplitSize).compute();
+            }
+        }
+    }
+
+    private static class IntToArrayTask extends CountedCompleter<Void> {
+        private final int[] array;
+        private final Node.OfPrimitive<Integer> node;
+        private final int offset;
+
+        private IntToArrayTask(Node.OfPrimitive<Integer> node, int[] array, int offset) {
+            this.array = array;
+            this.node = node;
+            this.offset = offset;
+        }
+
+        private IntToArrayTask(IntToArrayTask parent, Node.OfPrimitive<Integer> node, int offset) {
+            super(parent);
+            this.array = parent.array;
+            this.node = node;
+            this.offset = offset;
+        }
+
+        @Override
+        public void compute() {
+            if (node.getChildCount() > 0) {
+                setPendingCount(node.getChildCount() - 1);
+
+                final IntToArrayTask firstTask = new IntToArrayTask(this, node.getChild(0), offset);
+                int size = (int) firstTask.node.count();
+
+                for (int i = 1; i < node.getChildCount(); i++) {
+                    final IntToArrayTask task = new IntToArrayTask(this, node.getChild(i), offset + size);
+                    size += task.node.count();
+                    task.fork();
+                }
+                firstTask.compute();
+            }
+            else {
+                node.copyInto(array, offset);
+                tryComplete();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/Nodes.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,933 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.*;
+import java.util.function.Block;
+import java.util.function.IntBlock;
+import java.util.function.ObjIntFunction;
+
+import static java.util.stream.Collectors.toStringJoiner;
+
+public final class Nodes {
+
+    private Nodes() {
+        throw new Error("no instances");
+    }
+
+    public static<T> Node<T> emptyNode() {
+        return (Node<T>) EMPTY_NODE;
+    }
+
+    public static<T> Node<T> node(final T[] array) {
+        return new ArrayNode<>(array);
+    }
+
+    public static<T> Node<T> node(Collection<T> c) {
+        return new CollectionNode<>(c);
+    }
+
+    /**
+     * Make a fixed size node builder of known size, unless the size is negative, in which case make a variable size
+     * node builder.
+     *
+     *
+     * @param size the known size, or -1 if the size is not known.
+     * @return the node builder.
+     */
+    public static <T> Node.Builder<T> makeBuilder(long size, ObjIntFunction<T[]> generator) {
+        return (size >= 0 && size < Streams.MAX_ARRAY_SIZE) ? Nodes.<T>makeFixedSizeBuilder(size, generator)
+                                                            : Nodes.<T>makeVariableSizeBuilder();
+    }
+
+    /**
+     * Make a fixed size builder.
+     *
+     *
+     * @param size the fixed size of the builder.
+     * @return the node builder.
+     */
+    public static <T> Node.Builder<T> makeFixedSizeBuilder(long size, ObjIntFunction<T[]> generator) {
+        assert size < Streams.MAX_ARRAY_SIZE;
+        return new FixedNodeBuilder<>(size, generator);
+    }
+
+    /**
+     * Make a variable size node builder.
+     *
+     * @return the node builder.
+     */
+    public static <T> Node.Builder<T> makeVariableSizeBuilder() {
+        return new SpinedNodeBuilder<>();
+    }
+
+    @SafeVarargs
+    public static<T> Node<T> node(Node<T>... nodes) {
+        Objects.requireNonNull(nodes);
+        if (nodes.length < 2) {
+            // @@@ The signature could be (Node<T> n1, Node<T> n2, Node<T>... rest)
+            //     but requires more work to create the final array
+            throw new IllegalArgumentException("The number of nodes must be > 1");
+        }
+        return new ConcNode<>(nodes);
+    }
+
+    //
+
+    @SuppressWarnings("unchecked")
+    public static <E> Node.OfPrimitive<E> emptyPrimitiveNode() {
+        return (Node.OfPrimitive<E>) EMPTY_PRIMITIVE_NODE;
+    }
+
+    public static Node.OfPrimitive<Integer> intNode(final int[] array) {
+        return new IntArrayNode(array);
+    }
+
+    @SafeVarargs
+    public static Node.OfPrimitive<Integer> intNode(Node.OfPrimitive<Integer>... nodes) {
+        Objects.requireNonNull(nodes);
+        if (nodes.length > 1) {
+            return new IntConcNode(nodes);
+        }
+        else if (nodes.length == 1) {
+            return nodes[0];
+        }
+        else {
+            return emptyPrimitiveNode();
+        }
+    }
+
+    /**
+     * Make a fixed size node builder of known size, unless the size is negative, in which case make a variable size
+     * node builder.
+     *
+     * @param size the known size, or -1 if the size is not known.
+     * @return the node builder.
+     */
+    public static Node.OfPrimitive.Builder<Integer> makeIntBuilder(long size) {
+        return (size >= 0 && size < Streams.MAX_ARRAY_SIZE) ? makeFixedSizeIntBuilder(size)
+                                                            : makeVariableSizeIntBuilder();
+    }
+
+    /**
+     * Make a fixed size builder.
+     *
+     * @param size the fixed size of the builder.
+     * @return the node builder.
+     */
+    public static Node.OfPrimitive.Builder<Integer> makeFixedSizeIntBuilder(long size) {
+        assert size < Streams.MAX_ARRAY_SIZE;
+        return new FixedIntNodeBuilder(size);
+    }
+
+    /**
+     * Make a variable size node builder.
+     *
+     * @return the node builder.
+     */
+    public static Node.OfPrimitive.Builder<Integer> makeVariableSizeIntBuilder() {
+        return new IntSpinedNodeBuilder();
+    }
+
+    //
+
+    private static final Node EMPTY_NODE = new EmptyNode();
+
+    private static class EmptyNode<T> implements Node<T> {
+        @Override
+        public Spliterator<T> spliterator() {
+            return Streams.emptySpliterator();
+        }
+
+        @Override
+        public T[] asArray(ObjIntFunction<T[]> generator) {
+            return generator.apply(0);
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) throws IndexOutOfBoundsException { }
+
+        @Override
+        public long count() {
+            return 0;
+        }
+
+        @Override
+        public Iterator<T> iterator() {
+            return Collections.emptyIterator();
+        }
+
+        @Override
+        public void forEach(Block<? super T> block) { }
+    }
+
+    private static class ArrayNode<T> implements Node<T> {
+
+        protected final T[] array;
+        protected int curSize;
+
+        @SuppressWarnings("unchecked")
+        ArrayNode(long size, ObjIntFunction<T[]> generator) {
+            if (size >= Streams.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException("Stream size exceeds max array size");
+            this.array = generator.apply((int) size);
+            this.curSize = 0;
+        }
+
+        ArrayNode(T[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public void copyInto(T[] dest, int destOffset) {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public T[] asArray(ObjIntFunction<T[]> generator) {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                throw new IllegalStateException();
+            }
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        // Traversable
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            for (int i = 0; i < curSize; i++) {
+                block.accept(array[i]);
+            }
+        }
+
+        // Iterable
+
+        @Override
+        public Iterator<T> iterator() {
+            return Arrays.iterator(array, 0, curSize);
+        }
+
+        //
+
+        @Override
+        public String toString() {
+            return String.format("ArrayNode[%d][%s]", array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static class CollectionNode<T> implements Node<T> {
+
+        final Collection<T> c;
+
+        CollectionNode(Collection<T> c) {
+            this.c = c;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return c.stream().spliterator();
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            for (T t : c)
+                array[offset++] = t;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public T[] asArray(ObjIntFunction<T[]> generator) {
+            return c.toArray(generator.apply(c.size()));
+        }
+
+        @Override
+        public long count() {
+            return c.size();
+        }
+
+        // Iterable
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            c.forEach(block);
+        }
+
+        @Override
+        public Iterator<T> iterator() {
+            return c.iterator();
+        }
+        //
+
+        @Override
+        public String toString() {
+            return String.format("CollectionNode[%d][%s]", c.size(), c);
+        }
+    }
+
+    private static class ConcNode<T> implements Node<T> {
+        final Node<T>[] nodes;
+        int size = 0;
+
+        private ConcNode(Node<T>[] nodes) {
+            this.nodes = nodes;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator<T> spliterator() {
+            return new Nodes.InternalNodeSpliterator.OfRef<>(this);
+        }
+
+        @Override
+        public int getChildCount() {
+            return nodes.length;
+        }
+
+        @Override
+        public Node<T> getChild(int i) {
+            return nodes[i];
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            Objects.requireNonNull(array);
+            for (Node<T> n : nodes) {
+                n.copyInto(array, offset);
+                offset += n.count();
+            }
+        }
+
+        @Override
+        public T[] asArray(ObjIntFunction<T[]> generator) {
+            T[] array = generator.apply((int) count());
+            copyInto(array, 0);
+            return array;
+        }
+
+        @Override
+        public long count() {
+            if (size == 0) {
+                for (Node<T> n : nodes)
+                    size += n.count();
+            }
+            return size;
+        }
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            for (Node<T> n : nodes)
+                n.forEach(block);
+        }
+
+        @Override
+        public String toString() {
+            if (count() < 32) {
+                return String.format("ConcNode[%s]", Arrays.stream(nodes).map(Object::toString).collect(toStringJoiner(",")).toString());
+            } else {
+                return String.format("ConcNode[size=%d]", count());
+            }
+        }
+    }
+
+    private static abstract class InternalNodeSpliterator<T, S extends Spliterator<T>> extends AbstractSpliterator<T> {
+        // Node we are pointing to
+        protected Node<T> curNode;
+
+        // next child of curNode to consume
+        protected int curChildIndex;
+
+        // if we get to the last child, and it has no children, we get its spliterator and delegate
+        protected S lastNodeSpliterator;
+
+        // spliterator used while traversing
+        protected S curSpliterator;
+
+        private InternalNodeSpliterator(Node<T> curNode) {
+            this.curNode = curNode;
+        }
+
+        protected abstract S spliterator(Node<T> node);
+
+        protected interface BlockPusher<S> {
+            public boolean tryPush(S spliterator);
+        }
+
+        protected boolean doAdvance(BlockPusher<S> pusher) {
+            switch (state) {
+                case SPLITTING:
+                    curSpliterator = lastNodeSpliterator != null
+                                     ? lastNodeSpliterator
+                                     : spliterator(curNode.getChild(curChildIndex));
+                    state = State.TRAVERSING;
+                    // fall through
+
+                case TRAVERSING:
+                    boolean hasNext = pusher.tryPush(curSpliterator);
+                    while (!hasNext && ++curChildIndex < curNode.getChildCount()) {
+                        curSpliterator = spliterator(curNode.getChild(curChildIndex));
+                        hasNext = pusher.tryPush(curSpliterator);
+                    }
+                    if (!hasNext)
+                        state = State.FINISHED;
+                    else
+                        return hasNext;
+
+                case FINISHED:
+                    return false;
+
+                default:
+                    throw illegalState();
+            }
+        }
+
+        @Override
+        public S trySplit() {
+            if (state != State.SPLITTING)
+                throw illegalState();
+            if (lastNodeSpliterator != null)
+                return (S) lastNodeSpliterator.trySplit();
+            else if (curChildIndex < curNode.getChildCount() - 1)
+                return spliterator(curNode.getChild(curChildIndex++));
+            else {
+                curNode = curNode.getChild(curChildIndex);
+                if (curNode.getChildCount() == 0) {
+                    lastNodeSpliterator = spliterator(curNode);
+                    return (S) lastNodeSpliterator.trySplit();
+                }
+                else {
+                    curChildIndex = 0;
+                    return spliterator(curNode.getChild(curChildIndex++));
+                }
+            }
+        }
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            if (state != State.SPLITTING)
+                throw illegalState();
+            if (lastNodeSpliterator != null)
+                lastNodeSpliterator.forEach(block);
+            else
+                for (int i=curChildIndex; i < curNode.getChildCount(); i++)
+                    curNode.getChild(i).forEach(block);
+            state = State.FINISHED;
+        }
+
+        @Override
+        public long estimateSize() {
+            if (lastNodeSpliterator != null)
+                return lastNodeSpliterator.estimateSize();
+            else {
+                long size = 0;
+                for (int i=curChildIndex; i < curNode.getChildCount(); i++) {
+                    long thisSize = curNode.getChild(i).count();
+                    if (thisSize == -1)
+                        return -1;
+                    size += curNode.getChild(i).count();
+                }
+                return size;
+            }
+        }
+
+        @Override
+        public boolean hasExactSplits() {
+            return true;
+        }
+
+        static class OfRef<T> extends InternalNodeSpliterator<T, Spliterator<T>> {
+            OfRef(Node<T> curNode) {
+                super(curNode);
+            }
+
+            @Override
+            protected Spliterator<T> spliterator(Node<T> node) {
+                return node.spliterator();
+            }
+
+            @Override
+            public boolean tryAdvance(Block<? super T> block) {
+                return doAdvance(s -> s.tryAdvance(block));
+            }
+
+            // @@@ Push down forEach(Block)
+        }
+
+        private static class OfInt extends InternalNodeSpliterator<Integer, Spliterator.OfPrimitive<Integer>>
+                implements Spliterator.OfInt {
+
+            public OfInt(Node.OfPrimitive<Integer> cur) {
+                super(cur);
+            }
+
+            @Override
+            protected Spliterator.OfPrimitive<Integer> spliterator(Node<Integer> node) {
+                return ((Node.OfPrimitive<Integer>) node).spliterator();
+            }
+
+            @Override
+            public boolean tryAdvance(IntBlock block) {
+                // @@@ Potentially inefficient, since it will do a capture per try
+                return doAdvance(s -> s.tryAdvance(block));
+            }
+
+            // @@@ Need forEach(IntBlock) too
+        }
+    }
+
+    private static class FixedNodeBuilder<T> extends ArrayNode<T> implements Node.Builder<T> {
+
+        private FixedNodeBuilder(long size, ObjIntFunction<T[]> generator) {
+            super(size, generator);
+            assert size < Streams.MAX_ARRAY_SIZE;
+        }
+
+        //
+
+        @Override
+        public Node<T> build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d", curSize, array.length));
+            }
+
+            return this;
+        }
+
+        //
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d", size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(T t) {
+            if (curSize < array.length) {
+                array[curSize++] = t;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d", array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d", curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("FixedNodeBuilder[%d][%s]", array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static class SpinedNodeBuilder<T> extends SpinedBuffer<T> implements Node<T>, Node.Builder<T> {
+
+        private boolean building = false;
+
+        @Override
+        public Stream<T> stream() {
+            assert !building : "during building";
+            return super.stream();
+        }
+
+        @Override
+        public Stream<T> parallelStream() {
+            assert !building : "during building";
+            return super.parallelStream();
+        }
+
+        @Override
+        public Spliterator<T> spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            assert !building : "during building";
+            super.forEach(block);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(T t) {
+            assert building : "not building";
+            super.accept(t);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public T[] asArray(ObjIntFunction<T[]> generator) {
+            assert !building : "during building";
+            return super.asArray(generator);
+        }
+
+        @Override
+        public Node<T> build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+
+    //
+
+    private static final int[] EMPTY_INT_ARRAY = new int[0];
+
+    private static final Node.OfPrimitive<?> EMPTY_PRIMITIVE_NODE = new Node.OfPrimitive<Object>() {
+
+        @Override
+        public Spliterator.OfPrimitive spliterator() {
+            return Streams.emptyPrimitiveSpliterator();
+        }
+
+        @Override
+        public int[] asIntArray() {
+            return EMPTY_INT_ARRAY;
+        }
+
+        @Override
+        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
+        }
+
+        @Override
+        public void forEach(Block<? super Object> block) {
+        }
+
+        @Override
+        public void forEach(IntBlock sink) {
+        }
+
+        @Override
+        public long count() {
+            return 0;
+        }
+    };
+
+    private abstract static class AbstractPrimitiveConcNode<E> implements Node.OfPrimitive<E> {
+        final Node.OfPrimitive<E>[] nodes;
+        int size = 0;
+
+        public AbstractPrimitiveConcNode(Node.OfPrimitive<E>[] nodes) {
+            this.nodes = nodes;
+        }
+
+        // Node
+
+        @Override
+        public int getChildCount() {
+            return nodes.length;
+        }
+
+        @Override
+        public Node.OfPrimitive<E> getChild(int i) {
+            return nodes[i];
+        }
+
+        @Override
+        public long count() {
+            if (size == 0) {
+                for (Node.OfPrimitive<E> n : nodes)
+                    size += n.count();
+            }
+            return size;
+        }
+
+        @Override
+        public String toString() {
+            if (count() < 32)
+                return String.format("%s[%s]", this.getClass().getName(),
+                                     Arrays.stream(nodes).map(Object::toString).collect(toStringJoiner(",")).toString());
+            else
+                return String.format("%s[size=%d]", this.getClass().getName(), count());
+        }
+
+        //
+
+        @Override
+        public abstract Spliterator.OfPrimitive spliterator();
+
+        @Override
+        public abstract int[] asIntArray();
+
+        @Override
+        public abstract void copyInto(int[] array, int offset) throws IndexOutOfBoundsException;
+    }
+
+    private static class IntArrayNode implements Node.OfInt {
+
+        final int[] array;
+        int curSize;
+
+        IntArrayNode(long size) {
+            if (size >= Streams.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException("Stream size exceeds max array size");
+            this.array = new int[(int) size];
+            this.curSize = 0;
+        }
+
+        IntArrayNode(int[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        // Node
+
+        @Override
+        public Spliterator.OfPrimitive spliterator() {
+            return Arrays.spliterator(array, 0, curSize);
+        }
+
+        @Override
+        public int[] asIntArray() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        @Override
+        public void copyInto(int[] dest, int destOffset) throws IndexOutOfBoundsException {
+            System.arraycopy(array, 0, dest, destOffset, curSize);
+        }
+
+        @Override
+        public long count() {
+            return curSize;
+        }
+
+        // Traversable
+
+        @Override
+        public void forEach(IntBlock sink) {
+            for (int i = 0; i < curSize; i++) {
+                sink.accept(array[i]);
+            }
+        }
+
+        // Iterable
+
+        //
+
+        @Override
+        public String toString() {
+            return String.format("IntArrayNode[%d][%s]", array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static class IntConcNode extends AbstractPrimitiveConcNode<Integer> implements Node.OfInt {
+
+        public IntConcNode(OfPrimitive<Integer>[] nodes) {
+            super(nodes);
+        }
+
+        @Override
+        public void forEach(IntBlock sink) {
+            for (OfPrimitive<Integer> n : nodes)
+                n.forEach(sink);
+        }
+
+        @Override
+        public Spliterator.OfPrimitive spliterator() {
+            return new InternalNodeSpliterator.OfInt(this);
+        }
+
+        @Override
+        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
+            for (OfPrimitive<Integer> n : nodes) {
+                n.copyInto(array, offset);
+                offset += n.count();
+            }
+        }
+
+        @Override
+        public int[] asIntArray() {
+            int[] array = new int[(int) count()];
+            copyInto(array, 0);
+            return array;
+        }
+    }
+
+    private static class FixedIntNodeBuilder extends IntArrayNode implements Node.OfPrimitive.Builder.OfInt {
+
+        private FixedIntNodeBuilder(long size) {
+            super(size);
+            assert size < Streams.MAX_ARRAY_SIZE;
+        }
+
+        //
+
+        @Override
+        public Node.OfInt build() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d", curSize, array.length));
+            }
+
+            return this;
+        }
+
+        //
+
+        @Override
+        public void begin(long size) {
+            if (size != array.length) {
+                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d", size, array.length));
+            }
+
+            curSize = 0;
+        }
+
+        @Override
+        public void accept(int i) {
+            if (curSize < array.length) {
+                array[curSize++] = i;
+            } else {
+                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d", array.length));
+            }
+        }
+
+        @Override
+        public void end() {
+            if (curSize < array.length) {
+                throw new IllegalStateException(String.format("End size %d is less than fixed size %d", curSize, array.length));
+            }
+        }
+
+        @Override
+        public String toString() {
+            return String.format("IntFixedNodeBuilder[%d][%s]", array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    private static class IntSpinedNodeBuilder extends SpinedBuffer.OfInt implements Node.OfInt, Node.OfPrimitive.Builder.OfInt {
+        private boolean building = false;
+
+        @Override
+        public IntStream stream() {
+            assert !building : "during building";
+            return super.stream();
+        }
+
+        @Override
+        public IntStream parallelStream() {
+            assert !building : "during building";
+            return super.parallelStream();
+        }
+
+        @Override
+        public Spliterator.OfInt spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(IntBlock block) {
+            assert !building : "during building";
+            super.forEach(block);
+        }
+
+        //
+        @Override
+        public void begin(long size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void accept(int i) {
+            assert building : "not building";
+            super.accept(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
+            assert !building : "during building";
+            super.copyInto(array, offset);
+        }
+
+        @Override
+        public int[] asIntArray() {
+            assert !building : "during building";
+            return super.asIntArray();
+        }
+
+        @Override
+        public Node.OfInt build() {
+            assert !building : "during building";
+            return this;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/OpUtils.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.function.Block;
+import java.util.function.IntBlock;
+import java.util.function.IntSupplier;
+import java.util.function.Supplier;
+
+/**
+ * OpUtils
+ *
+ * @author Brian Goetz
+ */
+class OpUtils {
+    private OpUtils() {
+        throw new IllegalStateException("no instances");
+    }
+
+    /**
+     * Accepts a Sink, wraps it with upstream stages (see {@link java.util.stream.PipelineHelper#wrapSink(Sink)}, and
+     * then push all elements obtained from the Spliterator into that wrapped Sink.
+     * <p>This method performs the equivalent of <code>intoWrapped(sp, helper.wrapSink(sink))</code>.</p>
+     *
+     * @param helper the pipeline helper.
+     * @param sp   the source of elements to push into the wrapped sink.
+     * @param sink the sink in which to wrap.
+     */
+    public static<P_IN, P_OUT, S extends Sink<P_OUT>>
+    S intoUnwrapped(PipelineHelper<P_IN, P_OUT> helper, Spliterator<P_IN> sp, S sink) {
+        intoWrapped(sp, helper.wrapSink(sink));
+        return sink;
+    }
+
+    /**
+     * Push all elements obtained from a spliterator into a sink.
+     *
+     * @param sp   the source of elements to push into the sink
+     * @param sink the sink that accepts elements.
+     */
+    public static<P_IN> void intoWrapped(Spliterator<P_IN> sp, Sink<P_IN> sink) {
+        sink.begin(sp.exactSizeIfKnown());
+        sp.forEach(sink);
+        sink.end();
+    }
+
+    public static<P_IN, P_OUT> void parallelForEach(PipelineHelper<P_IN, P_OUT> helper,
+                                                    Sink<P_IN> sink,
+                                                    boolean shortCircuit) {
+        new ForEachTask<>(helper, sink, shortCircuit).invoke();
+    }
+
+    private static class ForEachTask<S, T> extends AbstractTask<S, T, Void, ForEachTask<S, T>> {
+        // @@@ Extending AbstractTask here is probably inefficient, since we don't really need to
+        // keep track of the structure of the computation tree
+        private final Sink<S> sink;
+        private final boolean shortCircuit;
+
+        private ForEachTask(PipelineHelper<S, T> helper, Sink<S> sink, boolean shortCircuit) {
+            super(helper);
+            this.sink = sink;
+            this.shortCircuit = shortCircuit;
+        }
+
+        private ForEachTask(ForEachTask<S, T> parent, Spliterator<S> spliterator, Sink<S> sink) {
+            super(parent, spliterator);
+            this.sink = sink;
+            this.shortCircuit = parent.shortCircuit;
+        }
+
+        @Override
+        public boolean suggestSplit() {
+            boolean suggest = super.suggestSplit();
+            if (shortCircuit)
+                suggest = suggest && !sink.cancellationRequested();
+            return suggest;
+        }
+
+        @Override
+        protected ForEachTask<S, T> makeChild(Spliterator<S> spliterator) {
+            return new ForEachTask<>(this, spliterator, sink);
+        }
+
+        @Override
+        protected Void doLeaf() {
+            if (shortCircuit)
+                helper.getInputShape().forEachWithCancel(spliterator, sink);
+            else
+                spliterator.forEach(sink);
+            return null;
+        }
+    }
+
+
+    public interface AccumulatingSink<T, R, K extends AccumulatingSink<T, R, K>> extends TerminalSink<T, R> {
+
+        public void combine(K other);
+        public void clearState();
+    }
+
+    public static<P_IN, P_OUT, R, S extends AccumulatingSink<P_OUT, R, S>>
+    R parallelReduce(PipelineHelper<P_IN, P_OUT> helper, Supplier<S> factory) {
+        S sink = new ReduceTask<>(helper, factory).invoke();
+        return sink.getAndClearState();
+    }
+
+    private static class ReduceTask<P_IN, P_OUT, R, S extends AccumulatingSink<P_OUT, R, S>>
+            extends AbstractTask<P_IN, P_OUT, S, ReduceTask<P_IN, P_OUT, R, S>> {
+        private final Supplier<S> sinkFactory;
+
+        private ReduceTask(PipelineHelper<P_IN, P_OUT> helper, Supplier<S> sinkFactory) {
+            super(helper);
+            this.sinkFactory = sinkFactory;
+        }
+
+        private ReduceTask(ReduceTask<P_IN, P_OUT, R, S> parent, Spliterator<P_IN> spliterator) {
+            super(parent, spliterator);
+            this.sinkFactory = parent.sinkFactory;
+        }
+
+        @Override
+        protected ReduceTask<P_IN, P_OUT, R, S> makeChild(Spliterator<P_IN> spliterator) {
+            return new ReduceTask<>(this, spliterator);
+        }
+
+        @Override
+        protected S doLeaf() {
+            return intoUnwrapped(helper, spliterator, sinkFactory.get());
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter caller) {
+            if (!isLeaf()) {
+                ReduceTask<P_IN, P_OUT, R, S> child = children;
+                S result = child.getLocalResult();
+                child = child.nextSibling;
+                for (; child != null; child = child.nextSibling) {
+                    S otherResult = child.getLocalResult();
+                    result.combine(otherResult);
+                    otherResult.clearState();
+                }
+                setLocalResult(result);
+            }
+        }
+    }
+
+    public static class ValueHolder<T> implements Block<T>, Supplier<T> {
+        private T value;
+
+        @Override
+        public void accept(T t) {
+            this.value = t;
+        }
+
+        @Override
+        public T get() {
+            return value;
+        }
+    }
+
+    public static class PrimitiveValueHolder {
+        public static class OfInt implements IntBlock, IntSupplier {
+            private int value;
+
+            public int getAsInt() {
+                return value;
+            }
+
+            public void accept(int value) {
+                this.value = value;
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/Ops.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * Ops
+ *
+ * @author Brian Goetz
+ */
+class Ops {
+    private static class OpBase<T,U> implements IntermediateOp<T,U> {
+        private final int opFlags;
+        private final StreamShape inputShape, outputShape;
+        private final SinkWrapper<T> sinkWrapper;
+
+        protected OpBase(int opFlags, StreamShape inputShape, StreamShape outputShape, SinkWrapper<T> wrapper) {
+            this.opFlags = opFlags;
+            this.inputShape = inputShape;
+            this.outputShape = outputShape;
+            sinkWrapper = wrapper;
+        }
+
+        public StreamShape outputShape() {
+            return outputShape;
+        }
+
+        public StreamShape inputShape() {
+            return inputShape;
+        }
+
+        public int getOpFlags() {
+            return opFlags;
+        }
+
+        @Override
+        public Sink<T> wrapSink(int flags, Sink<U> sink) {
+            return sinkWrapper.wrapSink(flags, sink);
+        }
+    }
+
+    private static class IntOpBase extends OpBase<Integer, Integer> implements IntermediateOp.OfInt {
+        protected IntOpBase(int opFlags, StreamShape inputShape, StreamShape outputShape, SinkWrapper<Integer> wrapper) {
+            super(opFlags, inputShape, outputShape, wrapper);
+        }
+    }
+
+    public interface SinkWrapper<T> {
+        public Sink<T> wrapSink(int flags, Sink sink);
+    }
+
+    public static<T,U> IntermediateOp<T,U> chainedRef(int opFlags,
+                                                      StreamShape outputShape,
+                                                      SinkWrapper<T> sinkWrapper) {
+        return new OpBase<>(opFlags, StreamShape.REFERENCE, outputShape, sinkWrapper);
+    }
+
+    public static<T,U> IntermediateOp<T,U> chainedRef(int opFlags,
+                                                      SinkWrapper<T> sinkWrapper) {
+        return new OpBase<>(opFlags, StreamShape.REFERENCE, StreamShape.REFERENCE, sinkWrapper);
+    }
+
+    public static<T> IntermediateOp<T,T> flagOp(int opFlags) {
+        return new OpBase<T, T>(opFlags, StreamShape.REFERENCE, StreamShape.REFERENCE, (flags, sink) -> sink);
+    }
+
+    public static IntermediateOp.OfInt chainedInt(int opFlags,
+                                                  SinkWrapper<Integer> sinkWrapper) {
+        return new IntOpBase(opFlags, StreamShape.INT_VALUE, StreamShape.INT_VALUE, sinkWrapper);
+    }
+
+    public static<U> IntermediateOp<Integer, U> chainedInt(int opFlags,
+                                                           StreamShape outputShape,
+                                                           SinkWrapper<Integer> sinkWrapper) {
+        return new OpBase<>(opFlags, StreamShape.INT_VALUE, outputShape, sinkWrapper);
+    }
+
+    public static IntermediateOp.OfInt intFlagOp(int opFlags) {
+        return new IntOpBase(opFlags, StreamShape.INT_VALUE, StreamShape.INT_VALUE, (flags, sink) -> sink);
+    }
+}
--- a/src/share/classes/java/util/stream/PipelineHelper.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/PipelineHelper.java	Thu Jan 10 21:50:21 2013 -0500
@@ -26,7 +26,6 @@
 
 import java.util.Spliterator;
 import java.util.function.ObjIntFunction;
-import java.util.stream.op.Node;
 
 /**
  * @param <P_IN>  Type of elements input to the pipeline.
--- a/src/share/classes/java/util/stream/ReferencePipeline.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/ReferencePipeline.java	Thu Jan 10 21:50:21 2013 -0500
@@ -24,14 +24,11 @@
  */
 package java.util.stream;
 
+import java.util.Comparator;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Spliterator;
 import java.util.function.*;
-import java.util.Comparator;
-import java.util.Optional;
-import java.util.stream.op.*;
-
-import static java.util.stream.op.FoldOp.makeRef;
 
 /**
  * A pipeline of elements that are references to objects of type <code>T</code>.
@@ -41,7 +38,7 @@
  *
  * @author Brian Goetz
  */
-public class ReferencePipeline<T, U> extends AbstractPipeline<T, U, Stream<U>> implements Stream<U>  {
+class ReferencePipeline<T, U> extends AbstractPipeline<T, U, Stream<U>> implements Stream<U>  {
 
     public<S> ReferencePipeline(Supplier<? extends Spliterator<S>> supplier, int sourceFlags) {
         super((Supplier) supplier, sourceFlags);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/SliceOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.ArrayList;
+import java.util.Spliterator;
+import java.util.concurrent.CountedCompleter;
+
+/**
+ * SliceOp
+ *
+ * @author Brian Goetz
+ */
+class SliceOp<T> implements StatefulOp<T> {
+    protected final long skip;
+    protected final long limit; // -1 means infinite
+    protected final StreamShape shape;
+    protected final Ops.SinkWrapper sinkWrapper;
+
+    public SliceOp(long skip, long limit, StreamShape shape) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+        this.skip = skip;
+        this.limit = limit;
+        this.shape = shape;
+        switch (shape.kind) {
+            case REFERENCE: sinkWrapper = this::wrapSinkRef; break;
+            case INT_VALUE: sinkWrapper = this::wrapSinkInt; break;
+            default:
+                throw new IllegalStateException("Unknown shape: " + shape.kind);
+        }
+    }
+
+    public SliceOp(long skip, StreamShape shape) {
+        this(skip, -1, shape);
+    }
+
+    private<T> Sink<T> wrapSinkRef(int flags, Sink sink) {
+        return new Sink.ChainedReference<T>(sink) {
+            long n = skip;
+            long m = limit >= 0 ? limit : Long.MAX_VALUE;
+
+            @Override
+            public void accept(T t) {
+                if (n == 0) {
+                    if (m > 0) {
+                        m--;
+                        downstream.accept(t);
+                    }
+                }
+                else {
+                    n--;
+                }
+            }
+
+            @Override
+            public boolean cancellationRequested() {
+                return m == 0 || downstream.cancellationRequested();
+            }
+        };
+    }
+
+    private Sink<Integer> wrapSinkInt(int flags, Sink sink) {
+        return new Sink.ChainedInt(sink) {
+            long n = skip;
+            long m = limit >= 0 ? limit : Long.MAX_VALUE;
+
+            @Override
+            public void accept(int t) {
+                if (n == 0) {
+                    if (m > 0) {
+                        m--;
+                        downstream.accept(t);
+                    }
+                }
+                else {
+                    n--;
+                }
+            }
+
+            @Override
+            public boolean cancellationRequested() {
+                return m == 0 || downstream.cancellationRequested();
+            }
+        };
+    }
+
+    @Override
+    public StreamShape outputShape() {
+        return shape;
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return shape;
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlag.NOT_SIZED | ((limit != -1) ? StreamOpFlag.IS_SHORT_CIRCUIT : 0);
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, Sink sink) {
+        return sinkWrapper.wrapSink(flags, sink);
+    }
+
+    private long getFinalSize(PipelineHelper helper) {
+        long size = helper.getOutputSizeIfKnown();
+        if (size >= 0) {
+            size = Math.max(0, size - skip);
+            if (limit >= 0)
+                size = Math.min(size, limit);
+        }
+        return size;
+    }
+
+    @Override
+    public <S> Node<T> evaluateParallel(PipelineHelper<S, T> helper) {
+        // Parallel strategy -- two cases
+        // IF we have full size information
+        // - decompose, keeping track of each leaf's (offset, size)
+        // - calculate leaf only if intersection between (offset, size) and desired slice
+        // - Construct a Node containing the appropriate sections of the appropriate leaves
+        // IF we don't
+        // - decompose, and calculate size of each leaf
+        // - on complete of any node, compute completed initial size from the root, and if big enough, cancel later nodes
+        // - @@@ this can be significantly improved
+
+        // @@@ Currently we don't do the sized version at all
+
+        // @@@ Should take into account ORDERED flag; if not ORDERED, we can limit in temporal order instead
+
+//        Spliterator<S> spliterator = helper.spliterator();
+//        int size = spliterator.getSizeIfKnown();
+//        if (size >= 0 && helper.getOutputSizeIfKnown() == size && spliterator.isPredictableSplits())
+//            return helper.invoke(new SizedSliceTask<>(helper, skip, getFinalSize(helper)));
+//        else
+            return new SliceTask<>(helper, skip, limit).invoke();
+    }
+
+    @Override
+    public String toString() {
+        return String.format("SliceOp[skip=%d,limit=%d]", skip, limit);
+    }
+
+    private static class SliceTask<S, T> extends AbstractShortCircuitTask<S, T, Node<T>, SliceTask<S, T>> {
+        private final long targetOffset, targetSize;
+        private long thisNodeSize;
+
+        private volatile boolean completed;
+
+        private SliceTask(PipelineHelper<S, T> helper, long offset, long size) {
+            super(helper);
+            this.targetOffset = offset;
+            this.targetSize = size;
+        }
+
+        private SliceTask(SliceTask<S, T> parent, Spliterator<S> spliterator) {
+            super(parent, spliterator);
+            this.targetOffset = parent.targetOffset;
+            this.targetSize = parent.targetSize;
+        }
+
+        @Override
+        protected SliceTask<S, T> makeChild(Spliterator<S> spliterator) {
+            return new SliceTask<>(this, spliterator);
+        }
+
+        @Override
+        protected final Node<T> getEmptyResult() {
+            return helper.getOutputNodeFactory().emptyNode();
+        }
+
+        @Override
+        protected final Node<T> doLeaf() {
+            if (isRoot()) {
+                Spliterator<T> wrapped = helper.wrapSequential(spliterator);
+                return helper.getOutputNodeFactory().truncateToNode(-1, wrapped, targetOffset, targetSize, helper.arrayGenerator());
+            }
+            else {
+                Node<T> node = OpUtils.intoUnwrapped(helper, spliterator,
+                                                     helper.getOutputNodeFactory().makeNodeBuilder(-1, helper.arrayGenerator())).build();
+                thisNodeSize = node.count();
+                completed = true;
+                return node;
+            }
+        }
+
+        @Override
+        public final void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf()) {
+                thisNodeSize = 0;
+                for (SliceTask<S, T> child = children; child != null; child = child.nextSibling)
+                    thisNodeSize += child.thisNodeSize;
+                completed = true;
+                ArrayList<Node<T>> nodes = new ArrayList<>();
+                visit(nodes, 0);
+                Node<T> result;
+                if (nodes.size() == 0)
+                    result = helper.getOutputNodeFactory().emptyNode();
+                else if (nodes.size() == 1)
+                    result = nodes.get(0);
+                else
+                    result = helper.getOutputNodeFactory().concNodes(nodes);
+                setLocalResult(result);
+            }
+            if (targetSize >= 0) {
+                if (((SliceTask<S,T>) getRoot()).leftSize() >= targetOffset + targetSize)
+                    cancelLaterNodes();
+            }
+        }
+
+        private final long leftSize() {
+            if (completed)
+                return thisNodeSize;
+            else if (isLeaf())
+                return 0;
+            else {
+                long leftSize = 0;
+                for (SliceTask<S, T> child = children; child != null; child = child.nextSibling) {
+                    if (child.completed)
+                        leftSize += child.thisNodeSize;
+                    else {
+                        leftSize += child.leftSize();
+                        break;
+                    }
+                }
+                return leftSize;
+            }
+        }
+
+        private void visit(ArrayList<Node<T>> results, int offset) {
+            if (!isLeaf()) {
+                for (SliceTask<S, T> child = children; child != null; child = child.nextSibling) {
+                    child.visit(results, offset);
+                    offset += child.thisNodeSize;
+                }
+            }
+            else {
+                if (results.size() == 0) {
+                    if (offset+thisNodeSize >= targetOffset)
+                        results.add(truncateNode(getLocalResult(),
+                                                 Math.max(0, targetOffset - offset),
+                                                 targetSize >= 0 ? Math.max(0, offset + thisNodeSize - (targetOffset + targetSize)) : 0));
+                }
+                else {
+                    if (targetSize == -1 || offset < targetOffset+targetSize) {
+                        results.add(truncateNode(getLocalResult(), 0,
+                                                 targetSize >= 0 ? Math.max(0, offset+thisNodeSize - (targetOffset + targetSize)) : 0));
+                    }
+                }
+            }
+        }
+
+        private Node<T> truncateNode(Node<T> input, long skipLeft, long skipRight) {
+            if (skipLeft == 0 && skipRight == 0)
+                return input;
+            else {
+                // @@@ Implement Node.truncate which will be more efficient
+                long truncatedSize = thisNodeSize - skipLeft - skipRight;
+                return helper.getOutputNodeFactory().truncateToNode(truncatedSize, input.spliterator(), skipLeft, truncatedSize, helper.arrayGenerator());
+            }
+        }
+    }
+
+    // @@@ Currently unused -- optimization for when all sizes are known
+//    private static class SizedSliceTask<S, T> extends AbstractShortCircuitTask<S, T, Node<T>, SizedSliceTask<S, T>> {
+//        private final int targetOffset, targetSize;
+//        private final int offset, size;
+//
+//        private SizedSliceTask(ParallelPipelineHelper<S, T> helper, int offset, int size) {
+//            super(helper);
+//            targetOffset = offset;
+//            targetSize = size;
+//            this.offset = 0;
+//            this.size = spliterator.getSizeIfKnown();
+//        }
+//
+//        private SizedSliceTask(SizedSliceTask<S, T> parent, Spliterator<S> spliterator) {
+//            // Makes assumptions about order in which siblings are created and linked into parent!
+//            super(parent, spliterator);
+//            targetOffset = parent.targetOffset;
+//            targetSize = parent.targetSize;
+//            int siblingSizes = 0;
+//            for (SizedSliceTask<S, T> sibling = parent.children; sibling != null; sibling = sibling.nextSibling)
+//                siblingSizes += sibling.size;
+//            size = spliterator.getSizeIfKnown();
+//            offset = parent.offset + siblingSizes;
+//        }
+//
+//        @Override
+//        protected SizedSliceTask<S, T> makeChild(Spliterator<S> spliterator) {
+//            return new SizedSliceTask<>(this, spliterator);
+//        }
+//
+//        @Override
+//        protected Node<T> getEmptyResult() {
+//            return Nodes.emptyNode();
+//        }
+//
+//        @Override
+//        public boolean taskCancelled() {
+//            if (offset > targetOffset+targetSize || offset+size < targetOffset)
+//                return true;
+//            else
+//                return super.taskCancelled();
+//        }
+//
+//        @Override
+//        protected Node<T> doLeaf() {
+//            int skipLeft = Math.max(0, targetOffset - offset);
+//            int skipRight = Math.max(0, offset + size - (targetOffset + targetSize));
+//            if (skipLeft == 0 && skipRight == 0)
+//                return helper.into(Nodes.<T>makeBuilder(spliterator.getSizeIfKnown())).build();
+//            else {
+//                // If we're the first or last node that intersects the target range, peel off irrelevant elements
+//                int truncatedSize = size - skipLeft - skipRight;
+//                NodeBuilder<T> builder = Nodes.<T>makeBuilder(truncatedSize);
+//                Sink<S> wrappedSink = helper.wrapSink(builder);
+//                wrappedSink.begin(truncatedSize);
+//                Iterator<S> iterator = spliterator.iterator();
+//                for (int i=0; i<skipLeft; i++)
+//                    iterator.next();
+//                for (int i=0; i<truncatedSize; i++)
+//                    wrappedSink.apply(iterator.next());
+//                wrappedSink.end();
+//                return builder.build();
+//            }
+//        }
+//
+//        @Override
+//        public void onCompletion(CountedCompleter<?> caller) {
+//            if (!isLeaf()) {
+//                Node<T> result = null;
+//                for (SizedSliceTask<S, T> child = children.nextSibling; child != null; child = child.nextSibling) {
+//                    Node<T> childResult = child.getRawResult();
+//                    if (childResult == null)
+//                        continue;
+//                    else if (result == null)
+//                        result = childResult;
+//                    else
+//                        result = Nodes.node(result, childResult);
+//                }
+//                setRawResult(result);
+//                if (offset <= targetOffset && offset+size >= targetOffset+targetSize)
+//                    shortCircuit(result);
+//            }
+//        }
+//    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/SortedOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.*;
+
+
+/**
+ * An operation which sorts elements.
+ *
+ * @param <T> Type of elements to be sorted.
+ *
+ * @author Brian Goetz
+ */
+public abstract class SortedOp<T> implements StatefulOp<T> {
+
+    public static class OfRef<T> extends SortedOp<T> {
+        /** Comparator used for sorting */
+        private final Comparator<? super T> comparator;
+
+        /**
+         * Sort using natural order of {@literal <T>} which must be
+         * {@code Comparable}.
+         */
+        public OfRef() {
+            // Will throw CCE when we try to sort if T is not Comparable
+            this((Comparator<? super T>) Comparators.naturalOrder());
+        }
+
+        /**
+         * Sort using the provided comparator.
+         *
+         * @param comparator The comparator to be used to evaluate ordering.
+         */
+        public OfRef(Comparator<? super T> comparator) {
+            this.comparator = Objects.requireNonNull(comparator);
+        }
+
+        @Override
+        public Sink<T> wrapSink(int flags, Sink sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedRefSortingSink<>(sink, comparator);
+            else
+                return new RefSortingSink<>(sink, comparator);
+        }
+
+        public <P_IN> Node<T> evaluateParallel(PipelineHelper<P_IN, T> helper) {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                return helper.collectOutput(false);
+            }
+            else {
+                // @@@ Weak two-pass parallel implementation; parallel collect, parallel sort
+                T[] flattenedData = helper.collectOutput(true).asArray(helper.arrayGenerator());
+                Arrays.parallelSort(flattenedData, comparator);
+                return Nodes.node(flattenedData);
+            }
+        }
+    }
+
+    public static class OfInt extends SortedOp<Integer> implements StatefulOp.OfInt {
+        @Override
+        public Sink<Integer> wrapSink(int flags, Sink sink) {
+            Objects.requireNonNull(sink);
+
+            if (StreamOpFlag.SORTED.isKnown(flags))
+                return sink;
+            else if (StreamOpFlag.SIZED.isKnown(flags))
+                return new SizedIntSortingSink(sink);
+            else
+                return new IntSortingSink(sink);
+        }
+
+        @Override
+        public <P_IN> Node<Integer> evaluateSequential(PipelineHelper<P_IN, Integer> helper) {
+            Node.OfInt n = (Node.OfPrimitive.OfInt) helper.collectOutput(true);
+
+            int[] content = n.asIntArray();
+            Arrays.sort(content);
+
+            return Nodes.intNode(content);
+        }
+
+        @Override
+        public <P_IN> Node<Integer> evaluateParallel(PipelineHelper<P_IN, Integer> helper) {
+            Node.OfInt n = (Node.OfPrimitive.OfInt) helper.collectOutput(true);
+
+            int[] content = n.asIntArray();
+            Arrays.parallelSort(content);
+
+            return Nodes.intNode(content);
+        }
+
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlag.IS_SORTED | StreamOpFlag.IS_ORDERED;
+    }
+
+
+    private static class SizedRefSortingSink<T> extends Sink.ChainedReference<T> {
+        private final Comparator<? super T> comparator;
+        T[] array;
+        int offset;
+
+        public SizedRefSortingSink(Sink sink, Comparator<? super T> comparator) {
+            super(sink);
+            this.comparator = comparator;
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Streams.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException("Stream size exceeds max array size");
+            array = (T[]) new Object[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array, comparator);
+            downstream.begin(array.length);
+            for (T t : array)
+                downstream.accept(t);
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(T t) {
+            array[offset++] = t;
+        }
+    }
+
+    private static class RefSortingSink<T> extends Sink.ChainedReference<T> {
+        private final Comparator<? super T> comparator;
+        ArrayList<T> list;
+
+        public RefSortingSink(Sink sink, Comparator<? super T> comparator) {
+            super(sink);
+            this.comparator = comparator;
+        }
+
+        @Override
+        public void begin(long size) {
+            list = (size >= 0) ? new ArrayList<T>((int) size) : new ArrayList<T>();
+        }
+
+        @Override
+        public void end() {
+            list.sort(comparator);
+            downstream.begin(list.size());
+            list.forEach(downstream::accept);
+            downstream.end();
+            list = null;
+        }
+
+        @Override
+        public void accept(T t) {
+            list.add(t);
+        }
+    }
+
+    private static class SizedIntSortingSink extends Sink.ChainedInt {
+        int[] array;
+        int offset;
+
+        public SizedIntSortingSink(Sink downstream) {
+            super(downstream);
+        }
+
+        @Override
+        public void begin(long size) {
+            if (size >= Streams.MAX_ARRAY_SIZE)
+                throw new IllegalArgumentException("Stream size exceeds max array size");
+            array = new int[(int) size];
+        }
+
+        @Override
+        public void end() {
+            Arrays.sort(array);
+            downstream.begin(array.length);
+            for (int t : array)
+                downstream.accept(t);
+            downstream.end();
+            array = null;
+        }
+
+        @Override
+        public void accept(int t) {
+            array[offset++] = t;
+        }
+    }
+
+    private static class IntSortingSink extends Sink.ChainedInt {
+        SpinedBuffer.OfInt b;
+
+        public IntSortingSink(Sink sink) {super(sink);}
+
+        @Override
+        public void begin(long size) {
+            b = (size > 0) ? new SpinedBuffer.OfInt((int) size) : new SpinedBuffer.OfInt();
+        }
+
+        @Override
+        public void end() {
+            int[] ints = b.asIntArray();
+            Arrays.sort(ints);
+            downstream.begin(ints.length);
+            for (int anInt : ints)
+                downstream.accept(anInt);
+            downstream.end();
+        }
+
+        @Override
+        public void accept(int t) {
+            b.accept(t);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/SpinedBuffer.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,740 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.*;
+import java.util.function.Block;
+import java.util.function.IntBlock;
+import java.util.function.ObjIntFunction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * An ordered collection of elements.
+ * Elements can be added, no elements can be removed.
+ * <p>
+ * One or more arrays are used to store elements.
+ * The use of a multiple arrays has better performance characteristics than a single array used by {@link ArrayList}
+ * when the capacity of the list needs to be increased. No copying of arrays of elements is required.
+ * The trade-off is the elements may be fragmented over two or more arrays. However, for the purposes
+ * of adding elements, iterating and splitting this trade-off is acceptable.
+ * </p>
+ *
+ * @param <E> the type of elements in this list
+ */
+public class SpinedBuffer<E> extends AbstractSpinedBuffer<E> implements Block<E>, Iterable<E> {
+
+    /*
+     * We optimistically hope that all the data will fit into the first chunk, so we try to avoid
+     * inflating the spine[] and priorElementCount[] arrays prematurely.  So methods must be prepared
+     * to deal with these arrays being null.  If spine is non-null, then spineIndex points to the current
+     * chunk within the spine, otherwise it is zero.  The spine and priorElementCount arrays are always
+     * the same size, and for any i <= spineIndex, priorElementCount[i] is the sum of the sizes of all
+     * the prior chunks.
+     *
+     * The curChunk pointer is always valid.  The elementIndex is the index of the next element to be
+     * written in curChunk; this may be past the end of curChunk so we have to check before writing.
+     * When we inflate the spine array, curChunk becomes the first element in it.  When we clear the
+     * buffer, we discard all chunks except the first one, which we clear, restoring it to the initial
+     * single-chunk state.
+     *
+     */
+
+    // The chunk we're currently writing into
+    protected E[] curChunk;
+
+    // All chunks, or null if there is only one chunk
+    protected E[][] spine;
+
+    /**
+     * Constructs an empty list with the specified initial capacity.
+     *
+     * @param  initialCapacity  the initial capacity of the list
+     * @throws IllegalArgumentException if the specified initial capacity
+     *         is negative
+     */
+    public SpinedBuffer(int initialCapacity) {
+        super(initialCapacity);
+        curChunk = (E[]) new Object[1 << initialChunkPower];
+    }
+
+    /**
+     * Constructs an empty list with an initial capacity of sixteen.
+     */
+    public SpinedBuffer() {
+        this(MIN_CHUNK_SIZE);
+    }
+
+    /**
+     * Constructs a list containing the elements of the specified
+     * iterable, in the order they are returned by the iterables's
+     * iterator.
+     *
+     * @param i the iterable whose elements are to be placed into this list
+     * @throws NullPointerException if the specified iterable is null
+     */
+    public SpinedBuffer(Iterable<E> i) {
+        this();
+
+        // @@@ This can be more efficient if c.toArray() is used
+        i.forEach(this);
+
+        // @@@ Note for testing purposes we need to simulate the contents as if
+        //     elements are added individually, if this method is modified check usage in tests and
+        //     as data source
+    }
+
+    protected long capacity() {
+        return (spineIndex == 0)
+               ? curChunk.length
+               : priorElementCount[spineIndex] + spine[spineIndex].length;
+    }
+
+    private void inflateSpine() {
+        if (spine == null) {
+            spine = (E[][]) new Object[MIN_SPINE_SIZE][];
+            priorElementCount = new long[MIN_SPINE_SIZE];
+            spine[0] = curChunk;
+        }
+    }
+
+    protected final void ensureCapacity(long targetSize) {
+        long capacity = capacity();
+        if (targetSize > capacity) {
+            inflateSpine();
+            for (int i=spineIndex+1; targetSize > capacity; i++) {
+                if (i >= spine.length) {
+                    int newSpineSize = spine.length * 2;
+                    spine = Arrays.copyOf(spine, newSpineSize);
+                    priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize);
+                }
+                int nextChunkSize = chunkSize(i);
+                spine[i] = (E[]) new Object[nextChunkSize];
+                priorElementCount[i] = priorElementCount[i-1] + spine[i-1].length;
+                capacity += nextChunkSize;
+            }
+        }
+    }
+
+    protected void increaseCapacity() {
+        ensureCapacity(capacity() + 1);
+    }
+
+    public E get(long index) {
+        // @@@ can further optimize by caching last seen spineIndex, which is going to be right most of the time
+        if (spineIndex == 0) {
+            if (index < elementIndex)
+                return curChunk[((int) index)];
+            else
+                throw new IndexOutOfBoundsException(Long.toString(index));
+        }
+
+        if (index >= count())
+            throw new IndexOutOfBoundsException(Long.toString(index));
+
+        for (int j=0; j <= spineIndex; j++)
+            if (index < priorElementCount[j] + spine[j].length)
+                return spine[j][((int) (index - priorElementCount[j]))];
+
+        throw new IndexOutOfBoundsException(Long.toString(index));
+    }
+
+    public void copyInto(E[] array, int offset) {
+        long finalOffset = offset + count();
+        if (finalOffset > array.length || finalOffset < offset) {
+            throw new IndexOutOfBoundsException("does not fit");
+        }
+
+        if (spineIndex == 0)
+            System.arraycopy(curChunk, 0, array, offset, elementIndex);
+        else {
+            // full chunks
+            for (int i=0; i < spineIndex; i++) {
+                System.arraycopy(spine[i], 0, array, offset, spine[i].length);
+                offset += spine[i].length;
+            }
+            if (elementIndex > 0)
+                System.arraycopy(curChunk, 0, array, offset, elementIndex);
+        }
+    }
+
+    public E[] asArray(ObjIntFunction<E[]> generator) {
+        // @@@ will fail for size == MAX_VALUE
+        E[] result = generator.apply((int) count());
+
+        copyInto(result, 0);
+
+        return result;
+    }
+
+    @Override
+    public void clear() {
+        if (spine != null) {
+            curChunk = spine[0];
+            for (int i=0; i<curChunk.length; i++)
+                curChunk[i] = null;
+            spine = null;
+            priorElementCount = null;
+        }
+        else {
+            for (int i=0; i<elementIndex; i++)
+                curChunk[i] = null;
+        }
+        elementIndex = 0;
+        spineIndex = 0;
+    }
+
+    // Iterable
+
+    public Iterator<E> iterator() {
+        return spliterator().iterator();
+    }
+
+    public void forEach(Block<? super E> block) {
+        // completed chunks, if any
+        for (int j = 0; j < spineIndex; j++)
+            for (E t : spine[j])
+                block.accept(t);
+
+        // current chunk
+        for (int i=0; i<elementIndex; i++)
+            block.accept(curChunk[i]);
+    }
+
+    // Block
+
+    @Override
+    public void accept(E e) {
+        if (elementIndex == curChunk.length) {
+            inflateSpine();
+            if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null)
+                increaseCapacity();
+            elementIndex = 0;
+            ++spineIndex;
+            curChunk = spine[spineIndex];
+        }
+        curChunk[elementIndex++] = e;
+    }
+
+    // Object
+
+    public String toString() {
+        List<E> list = new ArrayList<>();
+        forEach(list::add);
+        return "SpinedBuffer:" + list.toString();
+    }
+
+    // Streamable
+
+    public Stream<E> stream() {
+        return Streams.stream(this::spliterator,
+                              StreamOpFlag.IS_SIZED | StreamOpFlag.IS_ORDERED);
+    }
+
+    public Stream<E> parallelStream() {
+        return Streams.parallelStream(this::spliterator,
+                                      StreamOpFlag.IS_SIZED | StreamOpFlag.IS_ORDERED);
+    }
+
+    public Spliterator<E> spliterator() {
+        return new AbstractSpliterator<E>() {
+            int splSpineIndex;
+            int splElementIndex;
+            E[] splChunk;
+
+            @Override
+            public long estimateSize() {
+                switch (state) {
+                    case FINISHED:
+                        return 0;
+                    case TRAVERSING:
+                    case SPLITTING:
+                        return (spine == null)
+                               ? (elementIndex - splElementIndex)
+                               : count() - (priorElementCount[splSpineIndex] + splElementIndex);
+                    default:
+                        throw illegalState();
+                }
+            }
+
+            @Override
+            public boolean tryAdvance(Block<? super E> block) {
+                switch (state) {
+                    case SPLITTING: {
+                        // @@@ combine
+                        splChunk = (spine == null) ? curChunk : spine[splSpineIndex];
+                        boolean hasNext = (splSpineIndex < spineIndex) ||
+                                          (splSpineIndex == spineIndex && splElementIndex < elementIndex);
+                        state = hasNext ? State.TRAVERSING : State.FINISHED;
+                        if (hasNext)
+                            block.accept(splChunk[splElementIndex]);
+                        return hasNext;
+                    }
+
+                    case TRAVERSING: {
+                        if (++splElementIndex == splChunk.length) {
+                            splElementIndex = 0;
+                            ++splSpineIndex;
+                            if (spine != null && splSpineIndex < spine.length)
+                                splChunk = spine[splSpineIndex];
+                        }
+                        boolean hasNext = (splSpineIndex < spineIndex) ||
+                                          (splSpineIndex == spineIndex && splElementIndex < elementIndex);
+                        if (!hasNext)
+                            state = State.FINISHED;
+                        else
+                            block.accept(splChunk[splElementIndex]);
+                        return hasNext;
+                    }
+
+                    case FINISHED:
+                        return false;
+
+                    default:
+                        throw illegalState();
+                }
+            }
+
+            @Override
+            public void forEach(Block<? super E> block) {
+                if (state != State.SPLITTING)
+                    throw illegalState();
+                while (tryAdvance(block)) { }
+                state = State.FINISHED;
+            }
+
+            @Override
+            public boolean hasExactSplits() {
+                return true;
+            }
+
+            @Override
+            public Spliterator<E> trySplit() {
+                if (state != State.SPLITTING)
+                    throw illegalState();
+
+                if (splSpineIndex == spineIndex) {
+                    int t = (elementIndex - splElementIndex) / 2;
+                    if (t == 0)
+                        return null;
+                    else {
+                        Spliterator<E> ret = Arrays.spliterator(curChunk, splElementIndex, t);
+                        splElementIndex += t;
+                        return ret;
+                    }
+                }
+                else {
+                    Spliterator<E> ret = Arrays.spliterator(spine[splSpineIndex], 0, spine[splSpineIndex].length);
+                    ++splSpineIndex;
+                    return ret;
+                }
+            }
+        };
+    }
+
+    /**
+     * An ordered collection of primitive values.
+     * Values can be added, no values can be removed.
+     * <p>
+     * One or more arrays are used to store values.
+     * The use of a multiple arrays has better performance characteristics than a single array used by {@link java.util.ArrayList}
+     * when the capacity of the list needs to be increased. No copying of arrays of values is required.
+     * The trade-off is the values may be fragmented over two or more arrays. However, for the purposes
+     * of adding values, iterating and splitting this trade-off is acceptable.
+     * </p>
+     *
+     * @param <E> the type of primitive value.
+     * @param <A> the type primitive array of values.
+     * @param <B> the type of primitive block.
+     */
+    public abstract static class OfPrimitive<E, A, B>
+            extends AbstractSpinedBuffer<E> implements Iterable<E> {
+
+        /*
+         * We optimistically hope that all the data will fit into the first chunk, so we try to avoid
+         * inflating the spine[] and priorElementCount[] arrays prematurely.  So methods must be prepared
+         * to deal with these arrays being null.  If spine is non-null, then spineIndex points to the current
+         * chunk within the spine, otherwise it is zero.  The spine and priorElementCount arrays are always
+         * the same size, and for any i <= spineIndex, priorElementCount[i] is the sum of the sizes of all
+         * the prior chunks.
+         *
+         * The curChunk pointer is always valid.  The elementIndex is the index of the next element to be
+         * written in curChunk; this may be past the end of curChunk so we have to check before writing.
+         * When we inflate the spine array, curChunk becomes the first element in it.  When we clear the
+         * buffer, we discard all chunks except the first one, which we clear, restoring it to the initial
+         * single-chunk state.
+         *
+         */
+
+        // The chunk we're currently writing into
+        protected A curChunk;
+
+        // All chunks, or null if there is only one chunk
+        protected A[] spine;
+
+        /**
+         * Constructs an empty list with the specified initial capacity.
+         *
+         * @param  initialCapacity  the initial capacity of the list
+         * @throws IllegalArgumentException if the specified initial capacity
+         *         is negative
+         */
+        public OfPrimitive(int initialCapacity) {
+            super(initialCapacity);
+            curChunk = newArray(1 << initialChunkPower);
+        }
+
+        /**
+         * Constructs an empty list with an initial capacity of sixteen.
+         */
+        public OfPrimitive() {
+            this(MIN_CHUNK_SIZE);
+        }
+
+        // Iterable
+
+        @Override
+        public abstract PrimitiveIterator<E> iterator();
+
+        @Override
+        public abstract void forEach(Block<? super E> block);
+
+        //
+
+        protected abstract A[] newArrayArray(int size);
+        protected abstract A newArray(int size);
+        protected abstract int length(A array);
+        protected abstract void forEach(A array, int upTo, B block);
+
+        protected long capacity() {
+            return (spineIndex == 0)
+                   ? length(curChunk)
+                   : priorElementCount[spineIndex] + length(spine[spineIndex]);
+        }
+
+        private void inflateSpine() {
+            if (spine == null) {
+                spine = newArrayArray(MIN_SPINE_SIZE);
+                priorElementCount = new long[MIN_SPINE_SIZE];
+                spine[0] = curChunk;
+            }
+        }
+
+        protected final void ensureCapacity(long targetSize) {
+            long capacity = capacity();
+            if (targetSize > capacity) {
+                inflateSpine();
+                for (int i=spineIndex+1; targetSize > capacity; i++) {
+                    if (i >= spine.length) {
+                        int newSpineSize = spine.length * 2;
+                        spine = Arrays.copyOf(spine, newSpineSize);
+                        priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize);
+                    }
+                    int nextChunkSize = chunkSize(i);
+                    spine[i] = newArray(nextChunkSize);
+                    priorElementCount[i] = priorElementCount[i-1] + length(spine[i-1]);
+                    capacity += nextChunkSize;
+                }
+            }
+        }
+
+        protected void increaseCapacity() {
+            ensureCapacity(capacity() + 1);
+        }
+
+        protected int chunkFor(long index) {
+            if (spineIndex == 0) {
+                if (index < elementIndex)
+                    return 0;
+                else
+                    throw new IndexOutOfBoundsException(Long.toString(index));
+            }
+
+            if (index >= count())
+                throw new IndexOutOfBoundsException(Long.toString(index));
+
+            for (int j=0; j <= spineIndex; j++)
+                if (index < priorElementCount[j] + length(spine[j]))
+                    return j;
+
+            throw new IndexOutOfBoundsException(Long.toString(index));
+        }
+
+        public void copyInto(A array, int offset) {
+            long finalOffset = offset + count();
+            if (finalOffset > length(array) || finalOffset < offset) {
+                throw new IndexOutOfBoundsException("does not fit");
+            }
+
+            if (spineIndex == 0)
+                System.arraycopy(curChunk, 0, array, offset, elementIndex);
+            else {
+                // full chunks
+                for (int i=0; i < spineIndex; i++) {
+                    System.arraycopy(spine[i], 0, array, offset, length(spine[i]));
+                    offset += length(spine[i]);
+                }
+                if (elementIndex > 0)
+                    System.arraycopy(curChunk, 0, array, offset, elementIndex);
+            }
+        }
+
+        public A asPrimitiveArray() {
+            // @@@ will fail for size == MAX_VALUE
+            A result = newArray((int) count());
+            copyInto(result, 0);
+            return result;
+        }
+
+        protected void preAccept() {
+            if (elementIndex == length(curChunk)) {
+                inflateSpine();
+                if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null)
+                    increaseCapacity();
+                elementIndex = 0;
+                ++spineIndex;
+                curChunk = spine[spineIndex];
+            }
+        }
+
+        public void clear() {
+            if (spine != null) {
+                curChunk = spine[0];
+                spine = null;
+                priorElementCount = null;
+            }
+            elementIndex = 0;
+            spineIndex = 0;
+        }
+
+        // Iterable
+
+        protected abstract class BaseSpliterator<T_SPLITER extends Spliterator<E>>
+                extends AbstractSpliterator<E> {
+            int splSpineIndex;
+            int splElementIndex;
+            A splChunk;
+
+            abstract T_SPLITER arraySpliterator(A array, int offset, int len);
+
+            @Override
+            public long estimateSize() {
+                switch (state) {
+                    case FINISHED:
+                        return 0;
+                    case TRAVERSING:
+                    case SPLITTING:
+                        return (spine == null)
+                               ? (elementIndex - splElementIndex)
+                               : count() - (priorElementCount[splSpineIndex] + splElementIndex);
+                    default:
+                        throw illegalState();
+                }
+            }
+
+            @Override
+            public boolean hasExactSplits() {
+                return true;
+            }
+
+            protected boolean doAdvance() {
+                switch (state) {
+                    case SPLITTING: {
+                        splChunk = (spine == null) ? curChunk : spine[splSpineIndex];
+                        boolean hasNext = (splSpineIndex < spineIndex) ||
+                                          (splSpineIndex == spineIndex && splElementIndex < elementIndex);
+                        state = hasNext ? State.TRAVERSING : State.FINISHED;
+                        return hasNext;
+                    }
+
+                    case TRAVERSING: {
+                        if (++splElementIndex == length(splChunk)) {
+                            splElementIndex = 0;
+                            ++splSpineIndex;
+                            if (spine != null && splSpineIndex < spine.length)
+                                splChunk = spine[splSpineIndex];
+                        }
+                        boolean hasNext = (splSpineIndex < spineIndex) ||
+                                          (splSpineIndex == spineIndex && splElementIndex < elementIndex);
+                        if (!hasNext)
+                            state = State.FINISHED;
+                        return hasNext;
+                    }
+
+                    case FINISHED:
+                        return false;
+
+                    default:
+                        throw illegalState();
+                }
+            }
+
+            @Override
+            public T_SPLITER trySplit() {
+                if (state != State.SPLITTING)
+                    throw illegalState();
+
+                if (splSpineIndex == spineIndex) {
+                    int t = (elementIndex - splElementIndex) / 2;
+                    if (t == 0)
+                        return null;
+                    else {
+                        T_SPLITER ret = arraySpliterator(curChunk, splElementIndex, t);
+                        splElementIndex += t;
+                        return ret;
+                    }
+                }
+                else {
+                    T_SPLITER ret = arraySpliterator(spine[splSpineIndex], 0, length(spine[splSpineIndex]));
+                    ++splSpineIndex;
+                    return ret;
+                }
+            }
+        }
+
+        public void forEach(B block) {
+            // completed chunks, if any
+            for (int j = 0; j < spineIndex; j++)
+                forEach(spine[j], length(spine[j]), block);
+
+            // current chunk
+            forEach(curChunk, elementIndex, block);
+        }
+
+    }
+
+    /**
+     * An ordered collection of <code>int</code> values.
+     */
+    public static class OfInt extends SpinedBuffer.OfPrimitive<Integer, int[], IntBlock> implements IntBlock {
+        public OfInt() { }
+
+        @Override
+        public void forEach(Block<? super Integer> sink) {
+            if (sink instanceof IntBlock) {
+                forEach((IntBlock) sink);
+            }
+            else {
+                Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using boxed int in forEach", getClass().getName());
+                spliterator().forEach(sink);
+            }
+        }
+
+        @Override
+        protected int[][] newArrayArray(int size) {
+            return new int[size][];
+        }
+
+        public OfInt(int initialCapacity) {
+            super(initialCapacity);
+        }
+
+        @Override
+        protected int[] newArray(int size) {
+            return new int[size];
+        }
+
+        @Override
+        protected void forEach(int[] array, int upTo, IntBlock block) {
+            for (int i=0; i<upTo; i++)
+                block.accept(array[i]);
+        }
+
+        @Override
+        protected int length(int[] array) {
+            return array.length;
+        }
+
+        @Override
+        public void accept(int i) {
+            preAccept();
+            curChunk[elementIndex++] = i;
+        }
+
+        public int get(long index) {
+            int ch = chunkFor(index);
+            if (spineIndex == 0 && ch == 0)
+                return curChunk[(int) index];
+            else
+                return spine[ch][(int) (index-priorElementCount[ch])];
+        }
+
+        public int[] asIntArray() {
+            return asPrimitiveArray();
+        }
+
+        @Override
+        public PrimitiveIterator<Integer> iterator() {
+            return spliterator().iterator();
+        }
+
+        private class Splitr
+                extends BaseSpliterator<Spliterator.OfPrimitive<Integer>>
+                implements Spliterator.OfInt {
+            @Override
+            Spliterator.OfPrimitive<Integer> arraySpliterator(int[] array, int offset, int len) {
+                return Arrays.spliterator(array, offset, len);
+            }
+
+            @Override
+            public boolean tryAdvance(IntBlock block) {
+                boolean hasNext = doAdvance();
+                if (hasNext)
+                    block.accept(splChunk[splElementIndex]);
+                return hasNext;
+            }
+
+        }
+
+        public Spliterator.OfInt spliterator() {
+            return new Splitr();
+        }
+
+        public IntStream stream() {
+            return Streams.intStream(this::spliterator,
+                                     StreamOpFlag.IS_SIZED | StreamOpFlag.IS_ORDERED);
+        }
+
+        public IntStream parallelStream() {
+            return Streams.intParallelStream(this::spliterator,
+                                             StreamOpFlag.IS_SIZED | StreamOpFlag.IS_ORDERED);
+        }
+
+        @Override
+        public String toString() {
+            int[] array = asIntArray();
+            if (array.length < 200) {
+                return String.format("%s[length=%d, chunks=%d]%s", getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array));
+            }
+            else {
+                int[] array2 = Arrays.copyOf(array, 200);
+                return String.format("%s[length=%d, chunks=%d]%s...", getClass().getSimpleName(), array.length,
+                                     spineIndex, Arrays.toString(array2));
+            }
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/StatefulOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,21 @@
+package java.util.stream;
+
+/**
+ * A stateful operation. State is accumulated as elements are processed.
+ * <p>The parallel evaluation returns a conc-tree of output elements.</p>
+ *
+ * @param <E> Type of input and output elements.
+ *
+ */
+public interface StatefulOp<E> extends IntermediateOp<E, E> {
+
+    @Override
+    public default boolean isStateful() {
+        return true;
+    }
+
+    // @@@ re-abstract evaluateParallel?
+
+    interface OfInt extends IntermediateOp.OfInt, StatefulOp<Integer> {
+    }
+}
--- a/src/share/classes/java/util/stream/Stream.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/Stream.java	Thu Jan 10 21:50:21 2013 -0500
@@ -24,8 +24,11 @@
  */
 package java.util.stream;
 
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Comparators;
+import java.util.Optional;
 import java.util.function.*;
-import java.util.*;
 
 /**
  * A potentially infinite sequence of elements. A stream is a consumable data
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/StreamOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * An Op whose results can be evaluated directly.  This includes terminal operations, as well as intermediate
+ * stateless and stateful operations.
+ *
+ * @param <E_IN> Type of input elements.
+ * @param <R> Type of result.
+ * @author Brian Goetz
+ */
+public interface StreamOp<E_IN, R> {
+
+    /**
+     *
+     * @return the input shape of this operation.
+     */
+    default StreamShape inputShape() { return StreamShape.REFERENCE; }
+
+    /**
+     * Get the properties of the operation.
+     * <p>The properties correspond to the properties the output stream is
+     * known to have or is not known to have when this operation is applied, in
+     * encounter order, to elements of an input stream.</p>
+     *
+     * @return the properties of the operation.
+     * @see {@link java.util.stream.StreamOpFlag}
+     */
+    default int getOpFlags() { return 0; }
+
+    /**
+     * Evaluate the result of the operation in parallel.
+     *
+     *
+     * @param helper
+     * @return the result of the operation.
+     */
+    default <P_IN> R evaluateParallel(PipelineHelper<P_IN, E_IN> helper) {
+        Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using computeParallel serial default", getClass().getSimpleName());
+        return evaluateSequential(helper);
+    }
+
+    /**
+     * Evaluate the result of the operation sequentially.
+     *
+     * @param helper
+     * @return the result of the operation.
+     */
+    <P_IN> R evaluateSequential(PipelineHelper<P_IN, E_IN> helper);
+
+}
--- a/src/share/classes/java/util/stream/StreamOpFlag.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/StreamOpFlag.java	Thu Jan 10 21:50:21 2013 -0500
@@ -60,8 +60,7 @@
  *
  * The first method is recommended when the stream and operation flags are all known, and
  * is required when flags of the combined stream and operation form are to be passed to
- * {@link java.util.stream.op.IntermediateOp#wrapIterator(int, java.util.Iterator)}
- * and {@link java.util.stream.op.IntermediateOp#wrapSink(int, Sink)}.
+ * {@link IntermediateOp#wrapSink(int, Sink)}.
  *
  * The second method is recommended when operation flags are known before the stream flags and
  * output stream flags are required.
--- a/src/share/classes/java/util/stream/StreamShape.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/StreamShape.java	Thu Jan 10 21:50:21 2013 -0500
@@ -26,8 +26,6 @@
 
 import java.util.Spliterator;
 import java.util.function.Supplier;
-import java.util.stream.op.IntermediateOp;
-import java.util.stream.op.Node;
 
 /**
  * StreamShape
--- a/src/share/classes/java/util/stream/StreamShapeImpls.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/StreamShapeImpls.java	Thu Jan 10 21:50:21 2013 -0500
@@ -24,9 +24,9 @@
  */
 package java.util.stream;
 
-import java.util.*;
+import java.util.List;
+import java.util.Spliterator;
 import java.util.function.*;
-import java.util.stream.op.*;
 
 final class StreamShapeImpls {
 
--- a/src/share/classes/java/util/stream/Streams.java	Thu Jan 10 16:54:38 2013 -0800
+++ b/src/share/classes/java/util/stream/Streams.java	Thu Jan 10 21:50:21 2013 -0500
@@ -26,7 +26,6 @@
 
 import java.util.*;
 import java.util.function.*;
-import java.util.PrimitiveIterator;
 
 /**
  * Streams
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/TerminalOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+/**
+ * A terminal operation.
+ *
+ * @param <E_IN> The type of input elements.
+ * @param <R>    The type of the result.
+ * @author Brian Goetz
+ */
+public interface TerminalOp<E_IN, R> extends StreamOp<E_IN, R> {
+
+    // @@@ re-abstract evaluateParallel?
+
+
+    interface OfInt<R> extends TerminalOp<Integer, R> {
+        @Override
+        public default StreamShape inputShape() {
+            return StreamShape.INT_VALUE;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/UniqOp.java	Thu Jan 10 21:50:21 2013 -0500
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.stream;
+
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * An stateful operation which eliminates duplicates from the stream.
+ *
+ * @param <T> Type of elements to be processed.
+ *
+ * @author Brian Goetz
+ */
+// @@@ Does not support null elements
+public class UniqOp<T> implements StatefulOp<T> {
+    private static UniqOp<?> INSTANCE = new UniqOp<>();
+
+    public UniqOp() {
+    }
+
+    public static <T> UniqOp<T> singleton() {
+        return (UniqOp<T>) INSTANCE;
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlag.IS_DISTINCT | StreamOpFlag.NOT_SIZED;
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, Sink sink) {
+        Objects.requireNonNull(sink);
+
+        if (StreamOpFlag.DISTINCT.isKnown(flags)) {
+            return sink;
+        }
+        else if (StreamOpFlag.SORTED.isKnown(flags)) {
+            return new Sink.ChainedReference<T>(sink) {
+                boolean seenNull;
+                T lastSeen;
+
+                @Override
+                public void begin(long size) {
+                    seenNull = false;
+                    lastSeen = null;
+                    downstream.begin(-1);
+                }
+
+                @Override
+                public void end() {
+                    seenNull = false;
+                    lastSeen = null;
+                    downstream.end();
+                }
+
+                @Override
+                public void accept(T t) {
+                    if (t == null) {
+                        if (!seenNull) {
+                            seenNull = true;
+                            downstream.accept(lastSeen = null);
+                        }
+                    } else if (lastSeen == null || !t.equals(lastSeen)) {
+                        downstream.accept(lastSeen = t);
+                    }
+                }
+            };
+        }
+        else {
+            return new Sink.ChainedReference<T>(sink) {
+                Set<T> seen;
+
+                @Override
+                public void begin(long size) {
+                    seen = new HashSet<>();
+                    downstream.begin(-1);
+                }
+
+                @Override
+                public void end() {
+                    seen = null;
+                    downstream.end();
+                }
+
+                @Override
+                public void accept(T t) {
+                    if (!seen.contains(t)) {
+                        seen.add(t);
+                        downstream.accept(t);
+                    }
+                }
+            };
+        }
+    }
+
+    @Override
+    public <S> Node<T> evaluateParallel(PipelineHelper<S, T> helper) {
+        if (StreamOpFlag.DISTINCT.isKnown(helper.getStreamAndOpFlags())) {
+            // No-op
+            return helper.collectOutput(false);
+        }
+        else {
+            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
+                // @@@ Method ref
+                Set<T> s = OpUtils.parallelReduce(helper, () -> new UniqOrderedSortedSink<T>());
+                return Nodes.node(s);
+            }
+            else {
+                if (StreamOpFlag.ORDERED.isKnown(helper.getStreamAndOpFlags())) {
+                    // @@@ Method ref
+                    Set<T> s = OpUtils.parallelReduce(helper, () -> new UniqOrderedSink<T>());
+                    return Nodes.node(s);
+                }
+                else {
+                    final AtomicBoolean seenNull = new AtomicBoolean(false);
+                    final ConcurrentHashMap<T, Boolean> map = new ConcurrentHashMap<>();
+
+                    // Cache the sink chain, so it can be reused by all F/J leaf tasks
+                    Sink<S> sinkChain = helper.wrapSink(new Sink.OfReference<T>() {
+                        @Override
+                        public void accept(T t) {
+                            if (t == null)
+                                seenNull.set(true);
+                            else
+                                map.putIfAbsent(t, Boolean.TRUE);
+                        }
+                    });
+
+                    OpUtils.parallelForEach(helper, sinkChain, false);
+
+                    Set<T> keys = map.keySet();
+                    if (seenNull.get()) {
+                        keys = new HashSet<>(keys);
+                        keys.add(null);
+                    }
+                    return Nodes.node(keys);
+                }
+            }
+        }
+    }
+
+    private static abstract class AbstractUniqOrderedSink<T, S extends AbstractUniqOrderedSink<T, S>>
+            implements OpUtils.AccumulatingSink<T, Set<T>, S> {
+        Set<T> set;
+
+        @Override
+        public void begin(long size) {
+            set = new LinkedHashSet<>();
+        }
+
+        @Override
+        public void clearState() {
+            set = null;
+        }
+
+        @Override
+        public Set<T> getAndClearState() {
+            Set<T> result = set;
+            set = null;
+            return result;
+        }
+
+        @Override
+        public void accept(T t) {
+            set.add(t);
+        }
+
+        @Override
+        public void combine(S other) {
+            set.addAll(other.set);
+        }
+    }
+
+    // Keep the type system happy
+    private static class UniqOrderedSink<T>
+            extends AbstractUniqOrderedSink<T, UniqOrderedSink<T>> { }
+
+    private static class UniqOrderedSortedSink<T>
+            extends AbstractUniqOrderedSink<T, UniqOrderedSortedSink<T>> {
+        boolean seenNull;
+        T lastSeen;
+
+        @Override
+        public void begin(long size) {
+            seenNull = false;
+            lastSeen = null;
+            super.begin(size);
+        }
+
+        @Override
+        public void clearState() {
+            seenNull = false;
+            lastSeen = null;
+            super.clearState();
+        }
+
+        @Override
+        public Set<T> getAndClearState() {
+            seenNull = false;
+            lastSeen = null;
+            return super.getAndClearState();
+        }
+
+        @Override
+        public void accept(T t) {
+            if (t == null) {
+                if (!seenNull) {
+                    seenNull = true;
+                    super.accept(lastSeen = null);
+                }
+            }
+            else if (lastSeen == null || !t.equals(lastSeen)) {
+                super.accept(lastSeen = t);
+            }
+        }
+    }
+}
--- a/src/share/classes/java/util/stream/op/AbstractShortCircuitTask.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.PipelineHelper;
-import java.util.Spliterator;
-
-/**
- * Abstract class for fork-join tasks used to implement short-circuiting
- * stream ops that can produce a result without processing all elements of the stream.
- *
- * @param <P_IN> Type of elements input to the pipeline
- * @param <P_OUT> Type of elements output from the pipeline
- * @param <R> Type of intermediate result, may be different from operation result type
- * @param <T> Type of child and sibling tasks.
- */
-public abstract class AbstractShortCircuitTask<P_IN, P_OUT, R, T extends AbstractShortCircuitTask<P_IN, P_OUT, R, T>>
-        extends AbstractTask<P_IN, P_OUT, R, T> {
-    protected final AtomicReference<R> sharedResult;
-    protected volatile boolean canceled;
-
-    protected AbstractShortCircuitTask(PipelineHelper<P_IN, P_OUT> helper) {
-        super(helper);
-        sharedResult = new AtomicReference<>(null);
-    }
-
-    protected AbstractShortCircuitTask(T parent, Spliterator<P_IN> spliterator) {
-        super(parent, spliterator);
-        sharedResult = parent.sharedResult;
-    }
-
-    protected abstract R getEmptyResult();
-
-    @Override
-    public void compute() {
-        // Have we already found an answer?
-        if (sharedResult.get() != null)
-            tryComplete();
-        else if (taskCancelled()) {
-            setLocalResult(getEmptyResult());
-            tryComplete();
-        }
-        else
-            super.compute();
-    }
-
-    protected void shortCircuit(R r) {
-        if (r != null)
-            sharedResult.compareAndSet(null, r);
-    }
-
-    @Override
-    protected void setLocalResult(R r) {
-        if (isRoot()) {
-            if (r != null)
-                sharedResult.compareAndSet(null, r);
-        }
-        else
-            super.setLocalResult(r);
-    }
-
-    @Override
-    public R getRawResult() {
-        return getLocalResult();
-    }
-
-    @Override
-    public R getLocalResult() {
-        if (isRoot()) {
-            R answer = sharedResult.get();
-            return (answer == null) ? getEmptyResult() : answer;
-        }
-        else
-            return super.getLocalResult();
-    }
-
-    protected void cancel() {
-        canceled = true;
-    }
-
-    protected boolean taskCancelled() {
-        boolean cancel = canceled;
-        if (!cancel)
-            for (T parent = getParent(); !cancel && parent != null; parent = parent.getParent())
-                cancel = parent.canceled;
-        return cancel;
-    }
-
-    protected void cancelLaterNodes() {
-        T parent = getParent();
-        for (T sibling = this.nextSibling; sibling != null; sibling = sibling.nextSibling)
-            if (!sibling.canceled)
-                sibling.canceled = true;
-        // Go up the tree, cancel later siblings of all parents
-        if (parent != null)
-            parent.cancelLaterNodes();
-    }
-
-    protected boolean isLeftSpine() {
-        T node = (T) this;
-        while (node != null) {
-            T parent = node.getParent();
-            if (parent != null && parent.children != node)
-                return false;
-            node = parent;
-        }
-        return true;
-    }
-}
--- a/src/share/classes/java/util/stream/op/AbstractSpinedBuffer.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-/**
- * AbstractSpinedBuffer
- *
- * @author Brian Goetz
- */
-public abstract class AbstractSpinedBuffer<E> {
-    public static final int MIN_CHUNK_POWER = 4;
-    public static final int MIN_CHUNK_SIZE = 1 << MIN_CHUNK_POWER;
-    public static final int MAX_CHUNK_POWER = 30;
-    public static final int MIN_SPINE_SIZE = 8;
-
-    // log2 of the size of the first chunk
-    protected final int initialChunkPower;
-
-    // Index of the *next* element to write; may be outside the current chunk
-    protected int elementIndex;
-
-    // Index of the *current* chunk in the spine array
-    protected int spineIndex;
-
-    // Count of elements in all prior chunks
-    protected long[] priorElementCount;
-
-    public AbstractSpinedBuffer(int initialCapacity) {
-        if (initialCapacity < 0)
-            throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);
-
-        this.initialChunkPower = Math.max(MIN_CHUNK_POWER,
-                                          Integer.SIZE - Integer.numberOfLeadingZeros(initialCapacity - 1));
-    }
-
-    public boolean isEmpty() {
-        return (spineIndex == 0) && (elementIndex == 0);
-    }
-
-    public long count() {
-        return (spineIndex == 0)
-               ? elementIndex
-               : priorElementCount[spineIndex] + elementIndex;
-    }
-
-    protected int chunkSize(int n) {
-        int power = (n == 0 || n == 1)
-                    ? initialChunkPower
-                    : Math.min(initialChunkPower + n - 1, AbstractSpinedBuffer.MAX_CHUNK_POWER);
-        return 1 << power;
-    }
-
-    public abstract void clear();
-}
--- a/src/share/classes/java/util/stream/op/AbstractTask.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,183 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.concurrent.CountedCompleter;
-import java.util.concurrent.ForkJoinPool;
-import java.util.stream.PipelineHelper;
-import java.util.Spliterator;
-
-/**
- * Abstract base class for most fork-join tasks used to implement stream ops.
- * Manages splitting logic, tracking of child tasks, and intermediate results.
- * While the <code>getRawResult</code> and <code>setRawResult</code> methods of
- * <code>CountedCompleter</code> are initially unwired, this class uses them to
- * manage per-task result storage.
- *
- * Splitting and setting up the child task links is done at <code>compute()</code> time
- * for non-leaf nodes.  At <code>compute()</code> time for leaf nodes, it is guaranteed
- * that the parent's child-related fields (including sibling links for the parent's children)
- * will be set up for all children.
- *
- * @param <P_IN> Type of elements input to the pipeline
- * @param <P_OUT> Type of elements output from the pipeline
- * @param <R> Type of intermediate result, may be different from operation result type
- * @param <T> Type of child and sibling tasks.
- *
- * @author Brian Goetz
- */
-public abstract class AbstractTask<P_IN, P_OUT, R, T extends AbstractTask<P_IN, P_OUT, R, T>>
-        extends CountedCompleter<R> {
-
-    /** The pipeline helper, common to all tasks in a computation */
-    protected final PipelineHelper<P_IN, P_OUT> helper;
-
-    /** The spliterator for the portion of the input associated with the subtree rooted at this task */
-    protected final Spliterator<P_IN> spliterator;
-
-    protected final long targetSize;
-
-    /** How many children does this task have? */
-    protected int numChildren;
-
-    /** This task's first child.  Children are stored in a linked list, using the <code>nextSibling</code> field
-     * as the link to the next child. */
-    protected T children;
-
-    /** Next sibling of this task */
-    protected T nextSibling;
-
-    private R localResult;
-
-    protected AbstractTask(PipelineHelper<P_IN, P_OUT> helper) {
-        super(null);
-        this.helper = helper;
-        this.spliterator = helper.sourceSpliterator();
-        this.targetSize = suggestTargetSize(spliterator.estimateSize());
-    }
-
-    protected AbstractTask(T parent, Spliterator<P_IN> spliterator) {
-        super(parent);
-        this.spliterator = spliterator;
-        this.helper = parent.helper;
-        this.targetSize = parent.targetSize;
-    }
-
-    /** Construct a new node of type T whose parent is the receiver; must call
-     * the AbstractTask(T, Spliterator) constructor with the receiver and the provided Spliterator. */
-    protected abstract T makeChild(Spliterator<P_IN> spliterator);
-
-    /** Compute the result associated with a leaf node */
-    protected abstract R doLeaf();
-
-    public static long suggestTargetSize(long sizeEstimate) {
-        if (sizeEstimate < 0)
-            sizeEstimate = 1000;  // @@@ SWAG
-        return 1 + ((sizeEstimate + 7) >>> 3) / ForkJoinPool.getCommonPoolParallelism();
-    }
-
-    public static<P_IN, P_OUT> boolean suggestSplit(PipelineHelper<P_IN, P_OUT> helper,
-                                                    Spliterator spliterator,
-                                                    long targetSize) {
-        long remaining = spliterator.estimateSize();
-        return (remaining > targetSize || remaining < 0);
-        // @@@ May want to fold in pool characteristics such as surplus task count
-    }
-
-    public boolean suggestSplit() {
-        return suggestSplit(helper, spliterator, targetSize);
-    }
-
-    @Override
-    public R getRawResult() {
-        return localResult;
-    }
-
-    @Override
-    protected void setRawResult(R r) {
-        if (r != null)
-            throw new IllegalStateException();
-    }
-
-    /**
-     * Retrieve a result previously stored with <code>setLocalResult</code>
-     */
-    protected R getLocalResult() {
-        return localResult;
-    }
-
-    /**
-     * Associate the result with the task, can be retrieved with <code>getLocalResult</code>
-     */
-    protected void setLocalResult(R localResult) {
-        this.localResult = localResult;
-    }
-
-    /** Is this task a leaf node?  (Only valid after <code>compute()</code> has been called on this node).
-     * If the node is not a leaf node, then children will be non-null and numChildren will be positive. */
-    protected boolean isLeaf() {
-        return children == null;
-    }
-
-    /** Is this task the root node? */
-    protected boolean isRoot() {
-        return getParent() == null;
-    }
-
-    /**
-     * Return the parent of this task, or null if this task is the root
-     */
-    protected T getParent() {
-        return (T) getCompleter();
-    }
-
-    /**
-     * Decide whether or not to split this task further or compute it directly.
-     * If computing directly, call <code>doLeaf</code> and pass the result to
-     * <code>setRawResult</code>.  If splitting, set up the child-related fields,
-     * create the child tasks, fork the rightmost child tasks, and compute the leftmost
-     * child task.
-     */
-    @Override
-    public void compute() {
-        Spliterator<P_IN> split = null;
-        if (!suggestSplit() || (split = spliterator.trySplit()) == null) {
-            setLocalResult(doLeaf());
-            tryComplete();
-        }
-        else {
-            // Common case -- binary splits
-            T leftChild = makeChild(split);
-            T rightChild = makeChild(spliterator);
-            setPendingCount(1);
-            numChildren = 2;
-            children = leftChild;
-            leftChild.nextSibling = rightChild;
-            rightChild.fork();
-            leftChild.compute();
-        }
-    }
-}
-
--- a/src/share/classes/java/util/stream/op/FindOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.Optional;
-import java.util.OptionalInt;
-import java.util.concurrent.CountedCompleter;
-import java.util.stream.AbstractPipeline;
-import java.util.stream.PipelineHelper;
-import java.util.Spliterator;
-import java.util.stream.StreamShape;
-
-public abstract class FindOp<T, O> implements TerminalOp<T, O> {
-    public static final class OfReference<T> extends FindOp<T, Optional<T>> {
-
-        public static <T> FindOp<T, Optional<T>> any() {
-            return new OfReference<>(FindKind.ANY);
-        }
-
-        public static <T> FindOp<T, Optional<T>> first() {
-            return new OfReference<>(FindKind.FIRST);
-        }
-
-        private OfReference(FindKind findKind) {
-            super(findKind, StreamShape.REFERENCE);
-        }
-
-        @Override
-        protected Optional<T> emptyResult() {
-            return Optional.<T>empty();
-        }
-
-        @Override
-        protected Optional<T> find(Spliterator<T> spliterator) {
-            OpUtils.ValueHolder<T> vh = new OpUtils.ValueHolder<>();
-            if (spliterator.tryAdvance(vh))
-                return Optional.of(vh.get());
-            return null;
-        }
-
-        @Override
-        protected boolean isPresent(Optional<T> optional) {
-            return optional.isPresent();
-        }
-    }
-
-    public static final class OfInt extends FindOp<Integer, OptionalInt> {
-
-        public static FindOp<Integer, OptionalInt> any() {
-            return new OfInt(FindKind.ANY);
-        }
-
-        public static FindOp<Integer, OptionalInt> first() {
-            return new OfInt(FindKind.FIRST);
-        }
-
-        private OfInt(FindKind findKind) {
-            super(findKind, StreamShape.INT_VALUE);
-        }
-
-        @Override
-        protected OptionalInt emptyResult() {
-            return OptionalInt.empty();
-        }
-
-        @Override
-        protected OptionalInt find(Spliterator<Integer> spliterator) {
-            OpUtils.PrimitiveValueHolder.OfInt vh = new OpUtils.PrimitiveValueHolder.OfInt();
-            if (AbstractPipeline.adapt(spliterator).tryAdvance(vh))
-                return OptionalInt.of(vh.getAsInt());
-            return null;
-        }
-
-        @Override
-        protected boolean isPresent(OptionalInt optional) {
-            return optional.isPresent();
-        }
-    }
-
-    private enum FindKind {
-        ANY,
-        FIRST
-    }
-
-    private final FindKind findKind;
-
-    private final StreamShape shape;
-
-    private FindOp(FindKind findKind, StreamShape shape) {
-        this.findKind = findKind;
-        this.shape = shape;
-    }
-
-    protected abstract O emptyResult();
-
-    protected abstract O find(Spliterator<T> spliterator);
-
-    protected abstract boolean isPresent(O optional);
-
-    @Override
-    public StreamShape inputShape() {
-        return shape;
-    }
-
-    @Override
-    public <S> O evaluateSequential(PipelineHelper<S, T> helper) {
-        Spliterator<T> spliterator = helper.wrapSequential(helper.sourceSpliterator());
-        O result = find(spliterator);
-        return result != null ? result : emptyResult();
-    }
-
-    @Override
-    public <P_IN> O evaluateParallel(PipelineHelper<P_IN, T> helper) {
-        return new FindTask<>(helper, this).invoke();
-    }
-
-    private static class FindTask<S, T, O> extends AbstractShortCircuitTask<S, T, O, FindTask<S, T, O>> {
-        private final FindOp<T, O> op;
-
-        private FindTask(PipelineHelper<S, T> helper, FindOp<T, O> op) {
-            super(helper);
-            this.op = op;
-        }
-
-        private FindTask(FindTask<S, T, O> parent, Spliterator<S> spliterator) {
-            super(parent, spliterator);
-            this.op = parent.op;
-        }
-
-        @Override
-        protected FindTask<S, T, O> makeChild(Spliterator<S> spliterator) {
-            return new FindTask<>(this, spliterator);
-        }
-
-        @Override
-        protected O getEmptyResult() {
-            return op.emptyResult();
-        }
-
-        private void foundResult(O answer) {
-            if (isLeftSpine())
-                shortCircuit(answer);
-            else
-                cancelLaterNodes();
-        }
-
-        @Override
-        protected O doLeaf() {
-            Spliterator<T> wrapped = helper.wrapSequential(spliterator);
-            if (op.findKind == FindKind.ANY) {
-                O result = op.find(wrapped);
-                if (result != null)
-                    shortCircuit(result);
-                return null;
-            }
-            else {
-                O result = op.find(wrapped);
-                if (result != null) {
-                    foundResult(result);
-                    return result;
-                }
-                else
-                    return null;
-            }
-        }
-
-        @Override
-        public void onCompletion(CountedCompleter<?> caller) {
-            if (op.findKind == FindKind.FIRST) {
-                for (FindTask<S, T, O> child = children; child != null; child = child.nextSibling) {
-                    O result = child.getLocalResult();
-                    if (result != null && op.isPresent(result)) {
-                        setLocalResult(result);
-                        foundResult(result);
-                        break;
-                    }
-                }
-            }
-        }
-    }
-}
--- a/src/share/classes/java/util/stream/op/FoldOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,315 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.Optional;
-import java.util.OptionalInt;
-import java.util.function.*;
-import java.util.stream.*;
-import java.util.stream.Collector;
-
-/**
- * FoldOp
- *
- * @author Brian Goetz
- */
-public class FoldOp<T, R, S extends OpUtils.AccumulatingSink<T, R, S>> implements TerminalOp<T, R> {
-    private final Supplier<S> sinkSupplier;
-    private final StreamShape inputShape;
-
-    public FoldOp(StreamShape shape, Supplier<S> supplier) {
-        sinkSupplier = supplier;
-        inputShape = shape;
-    }
-
-    public FoldOp(Supplier<S> supplier) {
-        this(StreamShape.REFERENCE, supplier);
-    }
-
-    @Override
-    public StreamShape inputShape() {
-        return inputShape;
-    }
-
-    public <S> R evaluateSequential(PipelineHelper<S, T> helper) {
-        return helper.into(sinkSupplier.get(), helper.sourceSpliterator()).getAndClearState();
-    }
-
-    @Override
-    public <S> R evaluateParallel(PipelineHelper<S, T> helper) {
-        return OpUtils.parallelReduce(helper, sinkSupplier);
-    }
-
-
-    private static abstract class Box<U> {
-        protected U state;
-
-        public void clearState() {
-            state = null;
-        }
-
-        public U getAndClearState() {
-            try { return state; }
-            finally { state = null; }
-        }
-    }
-
-    private static abstract class OptionalBox<U> {
-        protected boolean empty;
-        protected U state;
-
-        public void begin(long size) {
-            empty = true;
-            state = null;
-        }
-
-        public void clearState() {
-            empty = true;
-            state = null;
-        }
-
-        public Optional<U> getAndClearState() {
-            try { return empty ? Optional.<U>empty() : Optional.of(state); }
-            finally { clearState(); }
-        }
-    }
-
-    private static abstract class IntBox {
-        protected int state;
-
-        public void begin(long size) {
-            state = 0;
-        }
-
-        public void clearState() {
-            state = 0;
-        }
-
-        public Integer getAndClearState() {
-            try { return state; }
-            finally { state = 0; }
-        }
-    }
-
-    private static abstract class OptionalIntBox {
-        protected boolean empty;
-        protected int state;
-
-        public void begin(long size) {
-            empty = true;
-            state = 0;
-        }
-
-        public void clearState() {
-            state = 0;
-        }
-
-        public OptionalInt getAndClearState() {
-            try { return empty ? OptionalInt.empty() : OptionalInt.of(state); }
-            finally { state = 0; }
-        }
-    }
-
-    public static<T, U> TerminalOp<T, U>
-    makeRef(U seed, BiFunction<U, ? super T, U> reducer, BinaryOperator<U> combiner) {
-        class FoldingSink extends Box<U> implements OpUtils.AccumulatingSink<T, U, FoldingSink>, Sink.OfReference<T> {
-            @Override
-            public void begin(long size) {
-                state = seed;
-            }
-
-            @Override
-            public void accept(T t) {
-                state = reducer.apply(state, t);
-            }
-
-            @Override
-            public void combine(FoldingSink other) {
-                state = combiner.apply(state, other.state);
-            }
-        }
-        // @@@ Replace inner class suppliers with ctor refs or lambdas pending fix of compiler bug(s)
-        return new FoldOp<>(new Supplier<FoldingSink>() {
-            @Override
-            public FoldingSink get() {return new FoldingSink();}
-        });
-    }
-
-    public static<T> TerminalOp<T, Optional<T>>
-    makeRef(BinaryOperator<T> operator) {
-        class FoldingSink extends OptionalBox<T> implements OpUtils.AccumulatingSink<T, Optional<T>, FoldingSink> {
-
-            @Override
-            public void accept(T t) {
-                if (empty) {
-                    empty = false;
-                    state = t;
-                } else {
-                    state = operator.apply(state, t);
-                }
-            }
-
-            @Override
-            public void combine(FoldingSink other) {
-                if (!other.empty)
-                    accept(other.state);
-            }
-        }
-        return new FoldOp<>(new Supplier<FoldingSink>() {
-            @Override
-            public FoldingSink get() {return new FoldingSink();}
-        });
-    }
-
-    public static<T,R> TerminalOp<T, R>
-    makeRef(Collector<? super T,R> collector) {
-        class FoldingSink extends Box<R> implements OpUtils.AccumulatingSink<T, R, FoldingSink> {
-            @Override
-            public void begin(long size) {
-                state = collector.makeResult();
-            }
-
-            @Override
-            public void accept(T t) {
-                collector.accumulate(state, t);
-            }
-
-            @Override
-            public void combine(FoldingSink other) {
-                state = collector.combine(state, other.state);
-            }
-        }
-        return new FoldOp<>(new Supplier<FoldingSink>() {
-            @Override
-            public FoldingSink get() {return new FoldingSink();}
-        });
-    }
-
-    public static<T, R> TerminalOp<T, R>
-    makeRef(Supplier<R> seedFactory, BiBlock<R, ? super T> accumulator, BiBlock<R,R> reducer) {
-        class FoldingSink extends Box<R> implements OpUtils.AccumulatingSink<T, R, FoldingSink> {
-            @Override
-            public void begin(long size) {
-                state = seedFactory.get();
-            }
-
-            @Override
-            public void accept(T t) {
-                accumulator.accept(state, t);
-            }
-
-            @Override
-            public void combine(FoldingSink other) {
-                reducer.accept(state, other.state);
-            }
-        }
-        return new FoldOp<>(new Supplier<FoldingSink>() {
-            @Override
-            public FoldingSink get() {return new FoldingSink();}
-        });
-    }
-
-    public static TerminalOp<Integer, Integer>
-    makeInt(int identity, IntBinaryOperator operator) {
-        class FoldingSink extends IntBox implements OpUtils.AccumulatingSink<Integer, Integer, FoldingSink>, Sink.OfInt {
-            @Override
-            public void begin(long size) {
-                state = identity;
-            }
-
-            @Override
-            public void accept(int t) {
-                state = operator.applyAsInt(state, t);
-            }
-
-            @Override
-            public void combine(FoldingSink other) {
-                accept(other.state);
-            }
-        }
-        return new FoldOp<>(StreamShape.INT_VALUE, new Supplier<FoldingSink>() {
-            @Override
-            public FoldingSink get() {
-                return new FoldingSink();
-            }
-        });
-    }
-
-    public static TerminalOp<Integer, OptionalInt>
-    makeInt(IntBinaryOperator operator) {
-        class FoldingSink extends OptionalIntBox implements OpUtils.AccumulatingSink<Integer, OptionalInt, FoldingSink>, Sink.OfInt {
-            @Override
-            public void accept(int t) {
-                if (empty) {
-                    empty = false;
-                    state = t;
-                }
-                else {
-                    state = operator.applyAsInt(state, t);
-                }
-            }
-
-            @Override
-            public void combine(FoldingSink other) {
-                if (!other.empty)
-                    accept(other.state);
-            }
-        }
-
-        return new FoldOp<>(StreamShape.INT_VALUE, new Supplier<FoldingSink>() {
-            @Override
-            public FoldingSink get() {
-                return new FoldingSink();
-            }
-        });
-    }
-
-    public static <R> TerminalOp<Integer, R>
-    makeInt(Collector.OfInt<R> reducer) {
-        class FoldingSink extends Box<R> implements OpUtils.AccumulatingSink<Integer, R, FoldingSink>, Sink.OfInt {
-            @Override
-            public void begin(long size) {
-                state = reducer.makeResult();
-            }
-
-            @Override
-            public void accept(int t) {
-                reducer.accumulateAsInt(state, t);
-            }
-
-            @Override
-            public void combine(FoldingSink other) {
-                state = reducer.combine(state, other.state);
-            }
-        }
-
-        return new FoldOp<>(StreamShape.INT_VALUE, new Supplier<FoldingSink>() {
-            @Override
-            public FoldingSink get() {
-                return new FoldingSink();
-            }
-        });
-    }
-}
--- a/src/share/classes/java/util/stream/op/ForEachOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.Objects;
-import java.util.function.Block;
-import java.util.function.IntBlock;
-import java.util.stream.*;
-
-/**
- * ForEachOp
- *
- * @author Brian Goetz
- */
-public class ForEachOp<T> implements TerminalOp<T, Void> {
-    protected final TerminalSink<T, Void> sink;
-    protected final StreamShape shape;
-
-    protected ForEachOp(TerminalSink<T, Void> sink, StreamShape shape) {
-        this.shape = Objects.requireNonNull(shape);
-        this.sink = Objects.requireNonNull(sink);
-    }
-
-    protected interface VoidTerminalSink<T> extends TerminalSink<T, Void> {
-        @Override
-        default public Void getAndClearState() {
-            return null;
-        }
-
-        public interface OfInt extends VoidTerminalSink<Integer>, Sink.OfInt { }
-    }
-
-    public static <T> ForEachOp<T> make(final Block<? super T> block) {
-        Objects.requireNonNull(block);
-        return new ForEachOp<>((VoidTerminalSink<T>) block::accept, StreamShape.REFERENCE);
-    }
-
-    public static ForEachOp<Integer> make(final IntBlock block) {
-        Objects.requireNonNull(block);
-        // @@@ Should use lambda, but there's a translation bug
-        return new ForEachOp<>(new VoidTerminalSink.OfInt() {
-            @Override
-            public void accept(int i) {block.accept(i);}
-        }, StreamShape.INT_VALUE);
-    }
-
-    @Override
-    public StreamShape inputShape() {
-        return shape;
-    }
-
-    @Override
-    public <S> Void evaluateSequential(PipelineHelper<S, T> helper) {
-        return helper.into(sink, helper.sourceSpliterator()).getAndClearState();
-    }
-
-    @Override
-    public <S> Void evaluateParallel(PipelineHelper<S, T> helper) {
-        OpUtils.parallelForEach(helper, helper.wrapSink(sink), false);
-        return null;
-    }
-}
--- a/src/share/classes/java/util/stream/op/ForEachUntilOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.Objects;
-import java.util.function.Block;
-import java.util.function.BooleanSupplier;
-import java.util.function.IntBlock;
-import java.util.stream.*;
-
-/**
- * ForEachWhileOp
- *
- * @author Brian Goetz
- */
-public class ForEachUntilOp<T> extends ForEachOp<T> implements TerminalOp<T, Void> {
-    public ForEachUntilOp(TerminalSink<T, Void> sink, StreamShape shape) {
-        super(sink, shape);
-    }
-
-    public static <T> ForEachUntilOp<T> make(final Block<? super T> block, BooleanSupplier until) {
-        Objects.requireNonNull(block);
-        return new ForEachUntilOp<>(new VoidTerminalSink<T>() {
-            @Override
-            public void accept(T t) {
-                block.accept(t);
-            }
-
-            @Override
-            public boolean cancellationRequested() {
-                return until.getAsBoolean();
-            }
-        }, StreamShape.REFERENCE);
-    }
-
-    public static ForEachUntilOp make(final IntBlock block, BooleanSupplier until) {
-        Objects.requireNonNull(block);
-        return new ForEachUntilOp<>(new VoidTerminalSink.OfInt() {
-            @Override
-            public void accept(int i) {
-                block.accept(i);
-            }
-
-            @Override
-            public boolean cancellationRequested() {
-                return until.getAsBoolean();
-            }
-        }, StreamShape.INT_VALUE);
-    }
-
-    @Override
-    public int getOpFlags() {
-        return StreamOpFlag.IS_SHORT_CIRCUIT;
-    }
-
-    @Override
-    public <S> Void evaluateSequential(PipelineHelper<S, T> helper) {
-        Sink<S> wrappedSink = helper.wrapSink(sink);
-        wrappedSink.begin(-1); // Size unknown, since we might stop early
-        inputShape().forEachWithCancel(helper.sourceSpliterator(), wrappedSink);
-        wrappedSink.end();
-        return null;
-    }
-
-    @Override
-    public <S> Void evaluateParallel(PipelineHelper<S, T> helper) {
-        OpUtils.parallelForEach(helper, helper.wrapSink(sink), true);
-        return null;
-    }
-}
--- a/src/share/classes/java/util/stream/op/IntermediateOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.stream.*;
-
-/**
- * An operation performed upon elements from an input stream to produce elements to
- * an output stream.
- * <p>By default the operation is stateless and not short-circuiting.</p>
- *
- * @param <E_IN>  Type of input elements to the operation.
- * @param <E_OUT> Type of output elements to the operation.
- * @author Brian Goetz
- */
-public interface IntermediateOp<E_IN, E_OUT> extends StreamOp<E_IN, Node<E_OUT>> {
-
-    /**
-     *
-     * @return the output shape of this operation.
-     */
-    default StreamShape outputShape() { return StreamShape.REFERENCE; }
-
-    /**
-     * If {@code true} then operation is stateful and accumulates state.
-     *
-     * @return {@code true} then operation is stateful and accumulates state.
-     */
-    default boolean isStateful() { return false; }
-
-    /**
-     * Return a sink which will accept elements, perform the operation upon
-     * each element and send it to the provided sink.
-     *
-     *
-     * @param flags the combined stream and operation flags up to but not including this operation.
-     * @param sink elements will be sent to this sink after the processing.
-     * @return a sink which will accept elements and perform the operation upon
-     *         each element.
-     */
-    Sink<E_IN> wrapSink(int flags, Sink<E_OUT> sink);
-
-    @Override
-    default <P_IN> Node<E_OUT> evaluateSequential(PipelineHelper<P_IN, E_IN> helper) {
-        // If this operation preserves the size then defer to the size, if known, from the helper
-        long size = StreamOpFlag.SIZED.isPreserved(getOpFlags()) ? helper.getOutputSizeIfKnown() : -1;
-        final Node.Builder<E_OUT> nb = outputShape().nodeFactory().makeNodeBuilder(size, helper.arrayGenerator());
-        Sink<E_IN> wrapped = wrapSink(helper.getStreamAndOpFlags(), nb);
-        helper.into(wrapped, helper.sourceSpliterator());
-        return nb.build();
-    }
-
-    interface OfInt extends IntermediateOp<Integer, Integer> {
-        @Override
-        public default StreamShape inputShape() {
-            return StreamShape.INT_VALUE;
-        }
-
-        @Override
-        public default StreamShape outputShape() {
-            return StreamShape.INT_VALUE;
-        }
-    }
-}
--- a/src/share/classes/java/util/stream/op/MatchOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,181 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.Spliterator;
-import java.util.function.Block;
-import java.util.function.IntBlock;
-import java.util.function.IntPredicate;
-import java.util.function.Predicate;
-import java.util.stream.*;
-
-/**
- * MatchOp
- *
- * @author Brian Goetz
- */
-public abstract class MatchOp<T> implements TerminalOp<T, Boolean> {
-    protected final MatchKind matchKind;
-    private final StreamShape inputShape;
-
-    private MatchOp(MatchKind matchKind, StreamShape shape) {
-        this.matchKind = matchKind;
-        this.inputShape = shape;
-    }
-
-    public static final class OfReference<T> extends MatchOp<T>  {
-        private final Predicate<? super T> predicate;
-
-        public static <T> MatchOp<T> match(Predicate<? super T> predicate, MatchKind matchKind) {
-            return new OfReference<>(predicate, matchKind);
-        }
-
-        private OfReference(Predicate<? super T> predicate, MatchKind matchKind) {
-            super(matchKind, StreamShape.REFERENCE);
-            this.predicate = predicate;
-        }
-
-        protected Boolean evaluateMatch(Spliterator<T> spliterator) {
-            class Matcher implements Block<T> {
-                private boolean stop;
-
-                @Override
-                public void accept(T t) {
-                    if (predicate.test(t) == matchKind.stopOnPredicateMatches)
-                        stop = true;
-                }
-            }
-            Matcher m = new Matcher();
-            while (spliterator.tryAdvance(m)) {
-                if (m.stop)
-                    return matchKind.shortCircuitResult;
-            }
-
-            return !matchKind.shortCircuitResult;
-        }
-    }
-
-    public static final class OfInt extends MatchOp<Integer> {
-        private final IntPredicate predicate;
-
-        public static MatchOp<Integer> match(IntPredicate predicate, MatchKind matchKind) {
-            return new OfInt(predicate, matchKind);
-        }
-
-        private OfInt(IntPredicate predicate, MatchKind matchKind) {
-            super(matchKind, StreamShape.INT_VALUE);
-            this.predicate = predicate;
-        }
-
-        protected Boolean evaluateMatch(Spliterator<Integer> spliterator) {
-            class Matcher implements IntBlock {
-                private boolean stop;
-
-                @Override
-                public void accept(int t) {
-                    if (predicate.test(t) == matchKind.stopOnPredicateMatches)
-                        stop = true;
-                }
-            }
-            Spliterator.OfPrimitive<Integer> intIterator = AbstractPipeline.adapt(spliterator);
-            Matcher m = new Matcher();
-            while (intIterator.tryAdvance(m)) {
-                if (m.stop)
-                    return matchKind.shortCircuitResult;
-            }
-
-            return !matchKind.shortCircuitResult;
-        }
-    }
-
-    @Override
-    public StreamShape inputShape() {
-        return inputShape;
-    }
-
-    @Override
-    public <S> Boolean evaluateSequential(PipelineHelper<S, T> helper) {
-        return evaluateMatch(helper.wrapSequential(helper.sourceSpliterator()));
-    }
-
-    protected abstract Boolean evaluateMatch(Spliterator<T> spliterator);
-
-    @Override
-    public <S> Boolean evaluateParallel(PipelineHelper<S, T> helper) {
-        // Approach for parallel implementation:
-        // - Decompose as per usual
-        // - run match on leaf chunks, call result "b"
-        // - if b == matchKind.shortCircuitOn, complete early and return b
-        // - else if we complete normally, return !shortCircuitOn
-
-        return new MatchTask<>(this, helper).invoke();
-    }
-
-    private static class MatchTask<S, T> extends AbstractShortCircuitTask<S, T, Boolean, MatchTask<S, T>> {
-        private final MatchOp<T> op;
-
-        private MatchTask(MatchOp<T> op, PipelineHelper<S, T> helper) {
-            super(helper);
-            this.op = op;
-        }
-
-        private MatchTask(MatchTask<S, T> parent, Spliterator<S> spliterator) {
-            super(parent, spliterator);
-            this.op = parent.op;
-        }
-
-        @Override
-        protected MatchTask<S, T> makeChild(Spliterator<S> spliterator) {
-            return new MatchTask<>(this, spliterator);
-        }
-
-        @Override
-        protected Boolean doLeaf() {
-            boolean b = op.evaluateMatch(helper.wrapSequential(spliterator));
-            if (b == op.matchKind.shortCircuitResult)
-                shortCircuit(b);
-            return null;
-        }
-
-        @Override
-        protected Boolean getEmptyResult() {
-            return !op.matchKind.shortCircuitResult;
-        }
-    }
-
-    public enum MatchKind {
-        ANY(true, true),
-        ALL(false, false),
-        NONE(true, false);
-
-        private final boolean stopOnPredicateMatches;
-        private final boolean shortCircuitResult;
-
-        private MatchKind(boolean stopOnPredicateMatches, boolean shortCircuitResult) {
-            this.stopOnPredicateMatches = stopOnPredicateMatches;
-            this.shortCircuitResult = shortCircuitResult;
-        }
-    }
-}
--- a/src/share/classes/java/util/stream/op/Node.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,207 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.Iterator;
-import java.util.PrimitiveIterator;
-import java.util.function.Block;
-import java.util.function.IntBlock;
-import java.util.function.ObjIntFunction;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.stream.Sink;
-import java.util.Spliterator;
-
-/**
- * An immutable container of elements.
- * <p>The container may be flat, and have no children, or a tree whose shape corresponds to the computation
- * tree that produced the tree where the elements are contained in the leaf nodes.</p>
- * @param <T> the type of elements.
- */
-public interface Node<T> extends Iterable<T> {
-
-    /**
-     *
-     * @return the spliterator for this node.
-     */
-    Spliterator<T> spliterator();
-
-    @Override
-    default Iterator<T> iterator() {
-        return spliterator().iterator();
-    }
-
-    /**
-     *
-     * @return the number of child nodes
-     */
-    default int getChildCount() {
-        return 0;
-    }
-
-    /**
-     * Get a child node at a given index.
-     *
-     * @param i the index to the child node
-     * @return the child node.
-     * @throws IndexOutOfBoundsException if the index is less than 0 or greater than or equal to the
-     * number of child nodes.
-     */
-    default Node<T> getChild(int i) {
-        throw new IndexOutOfBoundsException();
-    }
-
-    /**
-     * View this node as an array.
-     * <p/>
-     * <p>Depending on the underlying implementation this may return a reference to an internal array rather than
-     * a copy. It is the callers responsibility to decide if either this node or the array is
-     * utilized as the primary reference for the data.</p>
-     *
-     * @return the array.
-     */
-    T[] asArray(ObjIntFunction<T[]> generator);
-
-    /**
-     * Copy the content of this node into an array at an offset.
-     *
-     * @param array the array to copy the data into.
-     * @param offset the offset into the array.
-     * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds.
-     * @throws NullPointerException if <code>array</code> is <code>null</code>.
-     */
-    void copyInto(T[] array, int offset);
-
-    /**
-     * Return the number of elements contained by this node
-     */
-    long count();
-
-    /**
-     * A specialization of a {@link java.util.stream.Sink} to build a flat node whose contents
-     * is all the pushed elements.
-     *
-     */
-    interface Builder<T> extends Sink.OfReference<T> {
-
-        /**
-         * Build the node.
-         * <p>This method should be called after all elements have been pushed and signalled with
-         * an invocation of {@link java.util.stream.Sink#end()}.</p>
-         *
-         * @return the built node.
-         */
-        Node<T> build();
-    }
-
-    /**
-     * An immutable container of values.
-     * <p>The container may be flat, and have no children, or a tree whose shape corresponds to the computation
-     * tree that produced the tree where the values are contained in the leaf nodes.</p>
-     */
-    interface OfPrimitive<E> extends Node<E> {
-
-        // Iterable
-
-        @Override
-        default PrimitiveIterator<E> iterator() {
-            return spliterator().iterator();
-        }
-
-        @Override
-        void forEach(Block<? super E> block);
-
-        default void forEach(IntBlock block) {
-            throw new UnsupportedOperationException();
-        }
-
-        //
-
-        @Override
-        default Node.OfPrimitive<E> getChild(int i) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        @Override
-        Spliterator.OfPrimitive<E> spliterator();
-
-        @Override
-        default E[] asArray(ObjIntFunction<E[]> generator) {
-            throw new UnsupportedOperationException();
-        }
-
-        default int[] asIntArray() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        default void copyInto(E[] array, int offset) throws IndexOutOfBoundsException {
-            throw new UnsupportedOperationException();
-        }
-
-        default void copyInto(int[] array, int offset) {
-            throw new UnsupportedOperationException();
-        }
-
-        /**
-         * A specialization of a {@link java.util.stream.Sink} to build a flat primitive node whose contents
-         * is all the pushed values.
-         *
-         */
-        interface Builder<E> extends Node.Builder<E> {
-
-            @Override
-            Node.OfPrimitive<E> build();
-
-            interface OfInt extends Builder<Integer>, Sink.OfInt {
-            }
-        }
-    }
-
-    interface OfInt extends OfPrimitive<Integer> {
-
-        @Override
-        default void forEach(Block<? super Integer> sink) {
-            if (sink instanceof IntBlock) {
-                forEach((IntBlock) sink);
-            }
-            else {
-                Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using boxed int", getClass().getName());
-                spliterator().forEach(sink);
-            }
-        }
-
-        @Override
-        default void forEach(IntBlock block) {
-            spliterator().forEach(block);
-        }
-
-        //
-
-        int[] asIntArray();
-
-        void copyInto(int[] array, int offset) throws IndexOutOfBoundsException;
-    }
-}
--- a/src/share/classes/java/util/stream/op/NodeUtils.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,367 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.Arrays;
-import java.util.concurrent.CountedCompleter;
-import java.util.function.ObjIntFunction;
-import java.util.stream.PipelineHelper;
-import java.util.Spliterator;
-import java.util.stream.Streams;
-
-/**
- * Utilities for generating and operating on reference-based Nodes.
- *
- * @author Brian Goetz
- */
-public final class NodeUtils {
-
-    private NodeUtils() {
-        throw new Error("no instances");
-    }
-
-    public static <P_IN, P_OUT> Node<P_OUT> collect(PipelineHelper<P_IN, P_OUT> helper,
-                                                    boolean flattenTree) {
-        Spliterator<P_IN> spliterator = helper.sourceSpliterator();
-        long size = spliterator.exactSizeIfKnown();
-        if (size >= 0 && helper.getOutputSizeIfKnown() == size && spliterator.hasExactSplits()) {
-            if (size >= Streams.MAX_ARRAY_SIZE)
-                throw new IllegalArgumentException("Stream size exceeds max array size");
-            P_OUT[] array = helper.arrayGenerator().apply((int) size);
-            new SizedCollectorTask<>(spliterator, helper, array).invoke();
-            return Nodes.node(array);
-        } else {
-            Node<P_OUT> node = new CollectorTask<>(helper).invoke();
-
-            // @@@ using default F/J pool, will that be different from that used by helper.invoke?
-            return flattenTree ? flatten(node, helper.arrayGenerator()) : node;
-        }
-    }
-
-    public static <T> Node<T> flatten(Node<T> node, ObjIntFunction<T[]> generator) {
-        if (node.getChildCount() > 0) {
-            T[] array = generator.apply((int) node.count());
-            new ToArrayTask<>(node, array, 0).invoke();
-            return Nodes.node(array);
-        } else {
-            return node;
-        }
-    }
-
-    public static <P_IN> Node.OfPrimitive<Integer> intCollect(PipelineHelper<P_IN, Integer> helper,
-                                                           boolean flattenTree) {
-        Spliterator<P_IN> spliterator = helper.sourceSpliterator();
-        long size = spliterator.exactSizeIfKnown();
-        if (size >= 0 && helper.getOutputSizeIfKnown() == size && spliterator.hasExactSplits()) {
-            if (size >= Streams.MAX_ARRAY_SIZE)
-                throw new IllegalArgumentException("Stream size exceeds max array size");
-            int[] array = new int[(int) size];
-            new SizedIntCollectorTask<>(spliterator, helper, array).invoke();
-            return Nodes.intNode(array);
-        }
-        else {
-            Node.OfPrimitive<Integer> node = new IntCollectorTask<>(helper).invoke();
-
-            // @@@ using default F/J pool, will that be different from that used by helper.invoke?
-            return flattenTree ? intFlatten(node) : node;
-        }
-    }
-
-    public static Node.OfPrimitive<Integer> intFlatten(Node.OfPrimitive<Integer> node) {
-        if (node.getChildCount() > 0) {
-            int[] array = new int[(int) node.count()];
-            new IntToArrayTask(node, array, 0).invoke();
-            return Nodes.intNode(array);
-        } else {
-            return node;
-        }
-    }
-
-    // Reference implementations
-
-    private static class CollectorTask<T, U> extends AbstractTask<T, U, Node<U>, CollectorTask<T, U>> {
-        private final PipelineHelper<T, U> helper;
-
-        private CollectorTask(PipelineHelper<T, U> helper) {
-            super(helper);
-            this.helper = helper;
-        }
-
-        private CollectorTask(CollectorTask<T, U> parent, Spliterator<T> spliterator) {
-            super(parent, spliterator);
-            helper = parent.helper;
-        }
-
-        @Override
-        protected CollectorTask<T, U> makeChild(Spliterator<T> spliterator) {
-            return new CollectorTask<>(this, spliterator);
-        }
-
-        @Override
-        protected Node<U> doLeaf() {
-            Node.Builder<U> builder = Nodes.makeBuilder(helper.getOutputSizeIfKnown() >= 0 ? spliterator.exactSizeIfKnown() : -1,
-                                                        helper.arrayGenerator());
-            OpUtils.intoWrapped(spliterator, helper.wrapSink(builder));
-            return builder.build();
-        }
-
-        @Override
-        public void onCompletion(CountedCompleter caller) {
-            if (!isLeaf()) {
-                @SuppressWarnings("unchecked")
-                Node<U>[] nodes = (Node<U>[]) new Node[numChildren];
-                int idx = 0;
-                for (CollectorTask<T, U> cur = children; cur != null; cur = cur.nextSibling)
-                    nodes[idx++] = cur.getLocalResult();
-                setLocalResult(Nodes.node(nodes));
-            }
-        }
-    }
-
-    private static class SizedCollectorTask<T, U> extends CountedCompleter<Void> {
-        private final Spliterator<T> spliterator;
-        private final PipelineHelper<T, U> helper;
-        private final U[] array;
-        private final long targetSize;
-        private long offset;
-        private long length;
-
-        private SizedCollectorTask(Spliterator<T> spliterator, PipelineHelper<T, U> helper, U[] array) {
-            this.spliterator = spliterator;
-            this.helper = helper;
-            this.array = array;
-            this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
-            this.offset = 0;
-            this.length = array.length;
-        }
-
-        private SizedCollectorTask(SizedCollectorTask<T, U> parent, Spliterator<T> spliterator, long offset, long length) {
-            super(parent);
-            this.spliterator = spliterator;
-            this.helper = parent.helper;
-            this.array = parent.array;
-            this.targetSize = parent.targetSize;
-            this.offset = offset;
-            this.length = length;
-
-            if (offset < 0 || length < 0 || (offset + length - 1 >= array.length)) {
-                throw new IllegalArgumentException(
-                        String.format("offset and length interval [%d, %d + %d) is not within array size interval [0, %d)",
-                                      offset, offset, length, array.length));
-            }
-        }
-
-        @Override
-        public void compute() {
-            Spliterator<T> split;
-            if (!AbstractTask.suggestSplit(helper, spliterator, targetSize) || ((split = spliterator.trySplit()) == null)) {
-                if (offset+length >= Streams.MAX_ARRAY_SIZE)
-                    throw new IllegalArgumentException("Stream size exceeds max array size");
-                OpUtils.intoUnwrapped(helper, spliterator, Arrays.sink(array, (int) offset, (int) length));
-                tryComplete();
-            }
-            else {
-                setPendingCount(1);
-                long thisSplitSize = split.exactSizeIfKnown();
-                new SizedCollectorTask<>(this, split, offset, thisSplitSize).fork();
-                new SizedCollectorTask<>(this, spliterator, offset + thisSplitSize, length - thisSplitSize).compute();
-            }
-        }
-    }
-
-    private static class ToArrayTask<T> extends CountedCompleter<Void> {
-        private final T[] array;
-        private final Node<T> node;
-        private final int offset;
-
-        private ToArrayTask(Node<T> node, T[] array, int offset) {
-            this.array = array;
-            this.node = node;
-            this.offset = offset;
-        }
-
-        private ToArrayTask(ToArrayTask<T> parent, Node<T> node, int offset) {
-            super(parent);
-            this.array = parent.array;
-            this.node = node;
-            this.offset = offset;
-        }
-
-        @Override
-        public void compute() {
-            if (node.getChildCount() > 0) {
-                setPendingCount(node.getChildCount() - 1);
-
-                final ToArrayTask<T> firstTask = new ToArrayTask<>(this, node.getChild(0), offset);
-                int size = (int) firstTask.node.count();
-
-                for (int i = 1; i < node.getChildCount(); i++) {
-                    final ToArrayTask<T> task = new ToArrayTask<>(this, node.getChild(i), offset + size);
-                    size += task.node.count();
-                    task.fork();
-                }
-                firstTask.compute();
-            } else {
-                node.copyInto(array, offset);
-                tryComplete();
-            }
-        }
-    }
-
-    // Int value implementations
-
-    // @@@ Note that the size collector task and to array task for references and
-    // primitives can unified with appropriate SAMs abstracting the details
-    // of push leaf data to an array or copying node data to an array at an offset.
-
-    private static class IntCollectorTask<T> extends AbstractTask<T, Integer, Node.OfPrimitive<Integer>, IntCollectorTask<T>> {
-        private final PipelineHelper<T, Integer> helper;
-
-        private IntCollectorTask(PipelineHelper<T, Integer> helper) {
-            super(helper);
-            this.helper = helper;
-        }
-
-        private IntCollectorTask(IntCollectorTask<T> parent, Spliterator<T> spliterator) {
-            super(parent, spliterator);
-            helper = parent.helper;
-        }
-
-        @Override
-        protected IntCollectorTask<T> makeChild(Spliterator<T> spliterator) {
-            return new IntCollectorTask<>(this, spliterator);
-        }
-
-        @Override
-        protected Node.OfPrimitive<Integer> doLeaf() {
-            Node.OfPrimitive.Builder<Integer> builder = Nodes.makeIntBuilder(helper.getOutputSizeIfKnown() >= 0 ? spliterator.exactSizeIfKnown() : -1);
-            OpUtils.intoWrapped(spliterator, helper.wrapSink(builder));
-            return builder.build();
-        }
-
-        @Override
-        public void onCompletion(CountedCompleter caller) {
-            if (!isLeaf()) {
-                Node.OfPrimitive<Integer>[] nodes = new Node.OfInt[numChildren];
-                int idx = 0;
-                for (IntCollectorTask<T> cur = children; cur != null; cur = cur.nextSibling)
-                    nodes[idx++] = cur.getLocalResult();
-
-                setLocalResult(Nodes.intNode(nodes));
-            }
-        }
-    }
-
-    private static class SizedIntCollectorTask<T> extends CountedCompleter<Void> {
-        private final Spliterator<T> spliterator;
-        private final PipelineHelper<T, Integer> helper;
-        private final int[] array;
-        private final long targetSize;
-        private long offset;
-        private long length;
-
-        private SizedIntCollectorTask(Spliterator<T> spliterator, PipelineHelper<T, Integer> helper, int[] array) {
-            this.spliterator = spliterator;
-            this.helper = helper;
-            this.array = array;
-            this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize());
-            this.offset = 0;
-            this.length = array.length;
-        }
-
-        private SizedIntCollectorTask(SizedIntCollectorTask<T> parent, Spliterator<T> spliterator, long offset, long length) {
-            super(parent);
-            this.spliterator = spliterator;
-            this.helper = parent.helper;
-            this.array = parent.array;
-            this.targetSize = parent.targetSize;
-            this.offset = offset;
-            this.length = length;
-
-            if (offset < 0 || length < 0 || (offset + length - 1 >= array.length)) {
-                throw new IllegalArgumentException(
-                        String.format("offset and length interval [%d, %d + %d) is not within array size interval [0, %d)",
-                                      offset, offset, length, array.length));
-            }
-        }
-
-        @Override
-        public void compute() {
-            Spliterator<T> split = null;
-            if (!AbstractTask.suggestSplit(helper, spliterator, targetSize) || ((split = spliterator.trySplit()) == null)) {
-                if (offset+length >= Streams.MAX_ARRAY_SIZE)
-                    throw new IllegalArgumentException("Stream size exceeds max array size");
-                OpUtils.intoUnwrapped(helper, spliterator, Arrays.sink(array, (int) offset, (int) length));
-                tryComplete();
-            }
-            else {
-                setPendingCount(1);
-                long thisSplitSize = split.exactSizeIfKnown();
-                new SizedIntCollectorTask<>(this, split, offset, thisSplitSize).fork();
-                new SizedIntCollectorTask<>(this, spliterator, offset + thisSplitSize, length - thisSplitSize).compute();
-            }
-        }
-    }
-
-    private static class IntToArrayTask extends CountedCompleter<Void> {
-        private final int[] array;
-        private final Node.OfPrimitive<Integer> node;
-        private final int offset;
-
-        private IntToArrayTask(Node.OfPrimitive<Integer> node, int[] array, int offset) {
-            this.array = array;
-            this.node = node;
-            this.offset = offset;
-        }
-
-        private IntToArrayTask(IntToArrayTask parent, Node.OfPrimitive<Integer> node, int offset) {
-            super(parent);
-            this.array = parent.array;
-            this.node = node;
-            this.offset = offset;
-        }
-
-        @Override
-        public void compute() {
-            if (node.getChildCount() > 0) {
-                setPendingCount(node.getChildCount() - 1);
-
-                final IntToArrayTask firstTask = new IntToArrayTask(this, node.getChild(0), offset);
-                int size = (int) firstTask.node.count();
-
-                for (int i = 1; i < node.getChildCount(); i++) {
-                    final IntToArrayTask task = new IntToArrayTask(this, node.getChild(i), offset + size);
-                    size += task.node.count();
-                    task.fork();
-                }
-                firstTask.compute();
-            }
-            else {
-                node.copyInto(array, offset);
-                tryComplete();
-            }
-        }
-    }
-}
--- a/src/share/classes/java/util/stream/op/Nodes.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,934 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.*;
-import java.util.function.Block;
-import java.util.function.IntBlock;
-import java.util.function.ObjIntFunction;
-import java.util.stream.*;
-
-import static java.util.stream.Collectors.toStringJoiner;
-
-public final class Nodes {
-
-    private Nodes() {
-        throw new Error("no instances");
-    }
-
-    public static<T> Node<T> emptyNode() {
-        return (Node<T>) EMPTY_NODE;
-    }
-
-    public static<T> Node<T> node(final T[] array) {
-        return new ArrayNode<>(array);
-    }
-
-    public static<T> Node<T> node(Collection<T> c) {
-        return new CollectionNode<>(c);
-    }
-
-    /**
-     * Make a fixed size node builder of known size, unless the size is negative, in which case make a variable size
-     * node builder.
-     *
-     *
-     * @param size the known size, or -1 if the size is not known.
-     * @return the node builder.
-     */
-    public static <T> Node.Builder<T> makeBuilder(long size, ObjIntFunction<T[]> generator) {
-        return (size >= 0 && size < Streams.MAX_ARRAY_SIZE) ? Nodes.<T>makeFixedSizeBuilder(size, generator)
-                                                            : Nodes.<T>makeVariableSizeBuilder();
-    }
-
-    /**
-     * Make a fixed size builder.
-     *
-     *
-     * @param size the fixed size of the builder.
-     * @return the node builder.
-     */
-    public static <T> Node.Builder<T> makeFixedSizeBuilder(long size, ObjIntFunction<T[]> generator) {
-        assert size < Streams.MAX_ARRAY_SIZE;
-        return new FixedNodeBuilder<>(size, generator);
-    }
-
-    /**
-     * Make a variable size node builder.
-     *
-     * @return the node builder.
-     */
-    public static <T> Node.Builder<T> makeVariableSizeBuilder() {
-        return new SpinedNodeBuilder<>();
-    }
-
-    @SafeVarargs
-    public static<T> Node<T> node(Node<T>... nodes) {
-        Objects.requireNonNull(nodes);
-        if (nodes.length < 2) {
-            // @@@ The signature could be (Node<T> n1, Node<T> n2, Node<T>... rest)
-            //     but requires more work to create the final array
-            throw new IllegalArgumentException("The number of nodes must be > 1");
-        }
-        return new ConcNode<>(nodes);
-    }
-
-    //
-
-    @SuppressWarnings("unchecked")
-    public static <E> Node.OfPrimitive<E> emptyPrimitiveNode() {
-        return (Node.OfPrimitive<E>) EMPTY_PRIMITIVE_NODE;
-    }
-
-    public static Node.OfPrimitive<Integer> intNode(final int[] array) {
-        return new IntArrayNode(array);
-    }
-
-    @SafeVarargs
-    public static Node.OfPrimitive<Integer> intNode(Node.OfPrimitive<Integer>... nodes) {
-        Objects.requireNonNull(nodes);
-        if (nodes.length > 1) {
-            return new IntConcNode(nodes);
-        }
-        else if (nodes.length == 1) {
-            return nodes[0];
-        }
-        else {
-            return emptyPrimitiveNode();
-        }
-    }
-
-    /**
-     * Make a fixed size node builder of known size, unless the size is negative, in which case make a variable size
-     * node builder.
-     *
-     * @param size the known size, or -1 if the size is not known.
-     * @return the node builder.
-     */
-    public static Node.OfPrimitive.Builder<Integer> makeIntBuilder(long size) {
-        return (size >= 0 && size < Streams.MAX_ARRAY_SIZE) ? makeFixedSizeIntBuilder(size)
-                                                            : makeVariableSizeIntBuilder();
-    }
-
-    /**
-     * Make a fixed size builder.
-     *
-     * @param size the fixed size of the builder.
-     * @return the node builder.
-     */
-    public static Node.OfPrimitive.Builder<Integer> makeFixedSizeIntBuilder(long size) {
-        assert size < Streams.MAX_ARRAY_SIZE;
-        return new FixedIntNodeBuilder(size);
-    }
-
-    /**
-     * Make a variable size node builder.
-     *
-     * @return the node builder.
-     */
-    public static Node.OfPrimitive.Builder<Integer> makeVariableSizeIntBuilder() {
-        return new IntSpinedNodeBuilder();
-    }
-
-    //
-
-    private static final Node EMPTY_NODE = new EmptyNode();
-
-    private static class EmptyNode<T> implements Node<T> {
-        @Override
-        public Spliterator<T> spliterator() {
-            return Streams.emptySpliterator();
-        }
-
-        @Override
-        public T[] asArray(ObjIntFunction<T[]> generator) {
-            return generator.apply(0);
-        }
-
-        @Override
-        public void copyInto(T[] array, int offset) throws IndexOutOfBoundsException { }
-
-        @Override
-        public long count() {
-            return 0;
-        }
-
-        @Override
-        public Iterator<T> iterator() {
-            return Collections.emptyIterator();
-        }
-
-        @Override
-        public void forEach(Block<? super T> block) { }
-    }
-
-    private static class ArrayNode<T> implements Node<T> {
-
-        protected final T[] array;
-        protected int curSize;
-
-        @SuppressWarnings("unchecked")
-        ArrayNode(long size, ObjIntFunction<T[]> generator) {
-            if (size >= Streams.MAX_ARRAY_SIZE)
-                throw new IllegalArgumentException("Stream size exceeds max array size");
-            this.array = generator.apply((int) size);
-            this.curSize = 0;
-        }
-
-        ArrayNode(T[] array) {
-            this.array = array;
-            this.curSize = array.length;
-        }
-
-        // Node
-
-        @Override
-        public Spliterator<T> spliterator() {
-            return Arrays.spliterator(array, 0, curSize);
-        }
-
-        @Override
-        public void copyInto(T[] dest, int destOffset) {
-            System.arraycopy(array, 0, dest, destOffset, curSize);
-        }
-
-        @Override
-        public T[] asArray(ObjIntFunction<T[]> generator) {
-            if (array.length == curSize) {
-                return array;
-            } else {
-                throw new IllegalStateException();
-            }
-        }
-
-        @Override
-        public long count() {
-            return curSize;
-        }
-
-        // Traversable
-
-        @Override
-        public void forEach(Block<? super T> block) {
-            for (int i = 0; i < curSize; i++) {
-                block.accept(array[i]);
-            }
-        }
-
-        // Iterable
-
-        @Override
-        public Iterator<T> iterator() {
-            return Arrays.iterator(array, 0, curSize);
-        }
-
-        //
-
-        @Override
-        public String toString() {
-            return String.format("ArrayNode[%d][%s]", array.length - curSize, Arrays.toString(array));
-        }
-    }
-
-    private static class CollectionNode<T> implements Node<T> {
-
-        final Collection<T> c;
-
-        CollectionNode(Collection<T> c) {
-            this.c = c;
-        }
-
-        // Node
-
-        @Override
-        public Spliterator<T> spliterator() {
-            return c.stream().spliterator();
-        }
-
-        @Override
-        public void copyInto(T[] array, int offset) {
-            for (T t : c)
-                array[offset++] = t;
-        }
-
-        @Override
-        @SuppressWarnings("unchecked")
-        public T[] asArray(ObjIntFunction<T[]> generator) {
-            return c.toArray(generator.apply(c.size()));
-        }
-
-        @Override
-        public long count() {
-            return c.size();
-        }
-
-        // Iterable
-
-        @Override
-        public void forEach(Block<? super T> block) {
-            c.forEach(block);
-        }
-
-        @Override
-        public Iterator<T> iterator() {
-            return c.iterator();
-        }
-        //
-
-        @Override
-        public String toString() {
-            return String.format("CollectionNode[%d][%s]", c.size(), c);
-        }
-    }
-
-    private static class ConcNode<T> implements Node<T> {
-        final Node<T>[] nodes;
-        int size = 0;
-
-        private ConcNode(Node<T>[] nodes) {
-            this.nodes = nodes;
-        }
-
-        // Node
-
-        @Override
-        public Spliterator<T> spliterator() {
-            return new Nodes.InternalNodeSpliterator.OfRef<>(this);
-        }
-
-        @Override
-        public int getChildCount() {
-            return nodes.length;
-        }
-
-        @Override
-        public Node<T> getChild(int i) {
-            return nodes[i];
-        }
-
-        @Override
-        public void copyInto(T[] array, int offset) {
-            Objects.requireNonNull(array);
-            for (Node<T> n : nodes) {
-                n.copyInto(array, offset);
-                offset += n.count();
-            }
-        }
-
-        @Override
-        public T[] asArray(ObjIntFunction<T[]> generator) {
-            T[] array = generator.apply((int) count());
-            copyInto(array, 0);
-            return array;
-        }
-
-        @Override
-        public long count() {
-            if (size == 0) {
-                for (Node<T> n : nodes)
-                    size += n.count();
-            }
-            return size;
-        }
-
-        @Override
-        public void forEach(Block<? super T> block) {
-            for (Node<T> n : nodes)
-                n.forEach(block);
-        }
-
-        @Override
-        public String toString() {
-            if (count() < 32) {
-                return String.format("ConcNode[%s]", Arrays.stream(nodes).map(Object::toString).collect(toStringJoiner(",")).toString());
-            } else {
-                return String.format("ConcNode[size=%d]", count());
-            }
-        }
-    }
-
-    private static abstract class InternalNodeSpliterator<T, S extends Spliterator<T>> extends AbstractSpliterator<T> {
-        // Node we are pointing to
-        protected Node<T> curNode;
-
-        // next child of curNode to consume
-        protected int curChildIndex;
-
-        // if we get to the last child, and it has no children, we get its spliterator and delegate
-        protected S lastNodeSpliterator;
-
-        // spliterator used while traversing
-        protected S curSpliterator;
-
-        private InternalNodeSpliterator(Node<T> curNode) {
-            this.curNode = curNode;
-        }
-
-        protected abstract S spliterator(Node<T> node);
-
-        protected interface BlockPusher<S> {
-            public boolean tryPush(S spliterator);
-        }
-
-        protected boolean doAdvance(BlockPusher<S> pusher) {
-            switch (state) {
-                case SPLITTING:
-                    curSpliterator = lastNodeSpliterator != null
-                                     ? lastNodeSpliterator
-                                     : spliterator(curNode.getChild(curChildIndex));
-                    state = State.TRAVERSING;
-                    // fall through
-
-                case TRAVERSING:
-                    boolean hasNext = pusher.tryPush(curSpliterator);
-                    while (!hasNext && ++curChildIndex < curNode.getChildCount()) {
-                        curSpliterator = spliterator(curNode.getChild(curChildIndex));
-                        hasNext = pusher.tryPush(curSpliterator);
-                    }
-                    if (!hasNext)
-                        state = State.FINISHED;
-                    else
-                        return hasNext;
-
-                case FINISHED:
-                    return false;
-
-                default:
-                    throw illegalState();
-            }
-        }
-
-        @Override
-        public S trySplit() {
-            if (state != State.SPLITTING)
-                throw illegalState();
-            if (lastNodeSpliterator != null)
-                return (S) lastNodeSpliterator.trySplit();
-            else if (curChildIndex < curNode.getChildCount() - 1)
-                return spliterator(curNode.getChild(curChildIndex++));
-            else {
-                curNode = curNode.getChild(curChildIndex);
-                if (curNode.getChildCount() == 0) {
-                    lastNodeSpliterator = spliterator(curNode);
-                    return (S) lastNodeSpliterator.trySplit();
-                }
-                else {
-                    curChildIndex = 0;
-                    return spliterator(curNode.getChild(curChildIndex++));
-                }
-            }
-        }
-
-        @Override
-        public void forEach(Block<? super T> block) {
-            if (state != State.SPLITTING)
-                throw illegalState();
-            if (lastNodeSpliterator != null)
-                lastNodeSpliterator.forEach(block);
-            else
-                for (int i=curChildIndex; i < curNode.getChildCount(); i++)
-                    curNode.getChild(i).forEach(block);
-            state = State.FINISHED;
-        }
-
-        @Override
-        public long estimateSize() {
-            if (lastNodeSpliterator != null)
-                return lastNodeSpliterator.estimateSize();
-            else {
-                long size = 0;
-                for (int i=curChildIndex; i < curNode.getChildCount(); i++) {
-                    long thisSize = curNode.getChild(i).count();
-                    if (thisSize == -1)
-                        return -1;
-                    size += curNode.getChild(i).count();
-                }
-                return size;
-            }
-        }
-
-        @Override
-        public boolean hasExactSplits() {
-            return true;
-        }
-
-        static class OfRef<T> extends InternalNodeSpliterator<T, Spliterator<T>> {
-            OfRef(Node<T> curNode) {
-                super(curNode);
-            }
-
-            @Override
-            protected Spliterator<T> spliterator(Node<T> node) {
-                return node.spliterator();
-            }
-
-            @Override
-            public boolean tryAdvance(Block<? super T> block) {
-                return doAdvance(s -> s.tryAdvance(block));
-            }
-
-            // @@@ Push down forEach(Block)
-        }
-
-        private static class OfInt extends InternalNodeSpliterator<Integer, Spliterator.OfPrimitive<Integer>>
-                implements Spliterator.OfInt {
-
-            public OfInt(Node.OfPrimitive<Integer> cur) {
-                super(cur);
-            }
-
-            @Override
-            protected Spliterator.OfPrimitive<Integer> spliterator(Node<Integer> node) {
-                return ((Node.OfPrimitive<Integer>) node).spliterator();
-            }
-
-            @Override
-            public boolean tryAdvance(IntBlock block) {
-                // @@@ Potentially inefficient, since it will do a capture per try
-                return doAdvance(s -> s.tryAdvance(block));
-            }
-
-            // @@@ Need forEach(IntBlock) too
-        }
-    }
-
-    private static class FixedNodeBuilder<T> extends ArrayNode<T> implements Node.Builder<T> {
-
-        private FixedNodeBuilder(long size, ObjIntFunction<T[]> generator) {
-            super(size, generator);
-            assert size < Streams.MAX_ARRAY_SIZE;
-        }
-
-        //
-
-        @Override
-        public Node<T> build() {
-            if (curSize < array.length) {
-                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d", curSize, array.length));
-            }
-
-            return this;
-        }
-
-        //
-
-        @Override
-        public void begin(long size) {
-            if (size != array.length) {
-                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d", size, array.length));
-            }
-
-            curSize = 0;
-        }
-
-        @Override
-        public void accept(T t) {
-            if (curSize < array.length) {
-                array[curSize++] = t;
-            } else {
-                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d", array.length));
-            }
-        }
-
-        @Override
-        public void end() {
-            if (curSize < array.length) {
-                throw new IllegalStateException(String.format("End size %d is less than fixed size %d", curSize, array.length));
-            }
-        }
-
-        @Override
-        public String toString() {
-            return String.format("FixedNodeBuilder[%d][%s]", array.length - curSize, Arrays.toString(array));
-        }
-    }
-
-    private static class SpinedNodeBuilder<T> extends SpinedBuffer<T> implements Node<T>, Node.Builder<T> {
-
-        private boolean building = false;
-
-        @Override
-        public Stream<T> stream() {
-            assert !building : "during building";
-            return super.stream();
-        }
-
-        @Override
-        public Stream<T> parallelStream() {
-            assert !building : "during building";
-            return super.parallelStream();
-        }
-
-        @Override
-        public Spliterator<T> spliterator() {
-            assert !building : "during building";
-            return super.spliterator();
-        }
-
-        @Override
-        public void forEach(Block<? super T> block) {
-            assert !building : "during building";
-            super.forEach(block);
-        }
-
-        //
-        @Override
-        public void begin(long size) {
-            assert !building : "was already building";
-            building = true;
-            clear();
-            ensureCapacity(size);
-        }
-
-        @Override
-        public void accept(T t) {
-            assert building : "not building";
-            super.accept(t);
-        }
-
-        @Override
-        public void end() {
-            assert building : "was not building";
-            building = false;
-            // @@@ check begin(size) and size
-        }
-
-        @Override
-        public void copyInto(T[] array, int offset) {
-            assert !building : "during building";
-            super.copyInto(array, offset);
-        }
-
-        @Override
-        public T[] asArray(ObjIntFunction<T[]> generator) {
-            assert !building : "during building";
-            return super.asArray(generator);
-        }
-
-        @Override
-        public Node<T> build() {
-            assert !building : "during building";
-            return this;
-        }
-    }
-
-    //
-
-    private static final int[] EMPTY_INT_ARRAY = new int[0];
-
-    private static final Node.OfPrimitive<?> EMPTY_PRIMITIVE_NODE = new Node.OfPrimitive<Object>() {
-
-        @Override
-        public Spliterator.OfPrimitive spliterator() {
-            return Streams.emptyPrimitiveSpliterator();
-        }
-
-        @Override
-        public int[] asIntArray() {
-            return EMPTY_INT_ARRAY;
-        }
-
-        @Override
-        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
-        }
-
-        @Override
-        public void forEach(Block<? super Object> block) {
-        }
-
-        @Override
-        public void forEach(IntBlock sink) {
-        }
-
-        @Override
-        public long count() {
-            return 0;
-        }
-    };
-
-    private abstract static class AbstractPrimitiveConcNode<E> implements Node.OfPrimitive<E> {
-        final Node.OfPrimitive<E>[] nodes;
-        int size = 0;
-
-        public AbstractPrimitiveConcNode(Node.OfPrimitive<E>[] nodes) {
-            this.nodes = nodes;
-        }
-
-        // Node
-
-        @Override
-        public int getChildCount() {
-            return nodes.length;
-        }
-
-        @Override
-        public Node.OfPrimitive<E> getChild(int i) {
-            return nodes[i];
-        }
-
-        @Override
-        public long count() {
-            if (size == 0) {
-                for (Node.OfPrimitive<E> n : nodes)
-                    size += n.count();
-            }
-            return size;
-        }
-
-        @Override
-        public String toString() {
-            if (count() < 32)
-                return String.format("%s[%s]", this.getClass().getName(),
-                                     Arrays.stream(nodes).map(Object::toString).collect(toStringJoiner(",")).toString());
-            else
-                return String.format("%s[size=%d]", this.getClass().getName(), count());
-        }
-
-        //
-
-        @Override
-        public abstract Spliterator.OfPrimitive spliterator();
-
-        @Override
-        public abstract int[] asIntArray();
-
-        @Override
-        public abstract void copyInto(int[] array, int offset) throws IndexOutOfBoundsException;
-    }
-
-    private static class IntArrayNode implements Node.OfInt {
-
-        final int[] array;
-        int curSize;
-
-        IntArrayNode(long size) {
-            if (size >= Streams.MAX_ARRAY_SIZE)
-                throw new IllegalArgumentException("Stream size exceeds max array size");
-            this.array = new int[(int) size];
-            this.curSize = 0;
-        }
-
-        IntArrayNode(int[] array) {
-            this.array = array;
-            this.curSize = array.length;
-        }
-
-        // Node
-
-        @Override
-        public Spliterator.OfPrimitive spliterator() {
-            return Arrays.spliterator(array, 0, curSize);
-        }
-
-        @Override
-        public int[] asIntArray() {
-            if (array.length == curSize) {
-                return array;
-            } else {
-                return Arrays.copyOf(array, curSize);
-            }
-        }
-
-        @Override
-        public void copyInto(int[] dest, int destOffset) throws IndexOutOfBoundsException {
-            System.arraycopy(array, 0, dest, destOffset, curSize);
-        }
-
-        @Override
-        public long count() {
-            return curSize;
-        }
-
-        // Traversable
-
-        @Override
-        public void forEach(IntBlock sink) {
-            for (int i = 0; i < curSize; i++) {
-                sink.accept(array[i]);
-            }
-        }
-
-        // Iterable
-
-        //
-
-        @Override
-        public String toString() {
-            return String.format("IntArrayNode[%d][%s]", array.length - curSize, Arrays.toString(array));
-        }
-    }
-
-    private static class IntConcNode extends AbstractPrimitiveConcNode<Integer> implements Node.OfInt {
-
-        public IntConcNode(OfPrimitive<Integer>[] nodes) {
-            super(nodes);
-        }
-
-        @Override
-        public void forEach(IntBlock sink) {
-            for (OfPrimitive<Integer> n : nodes)
-                n.forEach(sink);
-        }
-
-        @Override
-        public Spliterator.OfPrimitive spliterator() {
-            return new InternalNodeSpliterator.OfInt(this);
-        }
-
-        @Override
-        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
-            for (OfPrimitive<Integer> n : nodes) {
-                n.copyInto(array, offset);
-                offset += n.count();
-            }
-        }
-
-        @Override
-        public int[] asIntArray() {
-            int[] array = new int[(int) count()];
-            copyInto(array, 0);
-            return array;
-        }
-    }
-
-    private static class FixedIntNodeBuilder extends IntArrayNode implements Node.OfPrimitive.Builder.OfInt {
-
-        private FixedIntNodeBuilder(long size) {
-            super(size);
-            assert size < Streams.MAX_ARRAY_SIZE;
-        }
-
-        //
-
-        @Override
-        public Node.OfInt build() {
-            if (curSize < array.length) {
-                throw new IllegalStateException(String.format("Current size %d is less than fixed size %d", curSize, array.length));
-            }
-
-            return this;
-        }
-
-        //
-
-        @Override
-        public void begin(long size) {
-            if (size != array.length) {
-                throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d", size, array.length));
-            }
-
-            curSize = 0;
-        }
-
-        @Override
-        public void accept(int i) {
-            if (curSize < array.length) {
-                array[curSize++] = i;
-            } else {
-                throw new IllegalStateException(String.format("Accept exceeded fixed size of %d", array.length));
-            }
-        }
-
-        @Override
-        public void end() {
-            if (curSize < array.length) {
-                throw new IllegalStateException(String.format("End size %d is less than fixed size %d", curSize, array.length));
-            }
-        }
-
-        @Override
-        public String toString() {
-            return String.format("IntFixedNodeBuilder[%d][%s]", array.length - curSize, Arrays.toString(array));
-        }
-    }
-
-    private static class IntSpinedNodeBuilder extends SpinedBuffer.OfInt implements Node.OfInt, Node.OfPrimitive.Builder.OfInt {
-        private boolean building = false;
-
-        @Override
-        public IntStream stream() {
-            assert !building : "during building";
-            return super.stream();
-        }
-
-        @Override
-        public IntStream parallelStream() {
-            assert !building : "during building";
-            return super.parallelStream();
-        }
-
-        @Override
-        public Spliterator.OfInt spliterator() {
-            assert !building : "during building";
-            return super.spliterator();
-        }
-
-        @Override
-        public void forEach(IntBlock block) {
-            assert !building : "during building";
-            super.forEach(block);
-        }
-
-        //
-        @Override
-        public void begin(long size) {
-            assert !building : "was already building";
-            building = true;
-            clear();
-            ensureCapacity(size);
-        }
-
-        @Override
-        public void accept(int i) {
-            assert building : "not building";
-            super.accept(i);
-        }
-
-        @Override
-        public void end() {
-            assert building : "was not building";
-            building = false;
-            // @@@ check begin(size) and size
-        }
-
-        @Override
-        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
-            assert !building : "during building";
-            super.copyInto(array, offset);
-        }
-
-        @Override
-        public int[] asIntArray() {
-            assert !building : "during building";
-            return super.asIntArray();
-        }
-
-        @Override
-        public Node.OfInt build() {
-            assert !building : "during building";
-            return this;
-        }
-    }
-}
--- a/src/share/classes/java/util/stream/op/OpUtils.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,199 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.Spliterator;
-import java.util.concurrent.CountedCompleter;
-import java.util.function.Block;
-import java.util.function.IntBlock;
-import java.util.function.IntSupplier;
-import java.util.function.Supplier;
-import java.util.stream.*;
-
-/**
- * OpUtils
- *
- * @author Brian Goetz
- */
-public class OpUtils {
-    private OpUtils() {
-        throw new IllegalStateException("no instances");
-    }
-
-    /**
-     * Accepts a Sink, wraps it with upstream stages (see {@link java.util.stream.PipelineHelper#wrapSink(Sink)}, and
-     * then push all elements obtained from the Spliterator into that wrapped Sink.
-     * <p>This method performs the equivalent of <code>intoWrapped(sp, helper.wrapSink(sink))</code>.</p>
-     *
-     * @param helper the pipeline helper.
-     * @param sp   the source of elements to push into the wrapped sink.
-     * @param sink the sink in which to wrap.
-     */
-    public static<P_IN, P_OUT, S extends Sink<P_OUT>>
-    S intoUnwrapped(PipelineHelper<P_IN, P_OUT> helper, Spliterator<P_IN> sp, S sink) {
-        intoWrapped(sp, helper.wrapSink(sink));
-        return sink;
-    }
-
-    /**
-     * Push all elements obtained from a spliterator into a sink.
-     *
-     * @param sp   the source of elements to push into the sink
-     * @param sink the sink that accepts elements.
-     */
-    public static<P_IN> void intoWrapped(Spliterator<P_IN> sp, Sink<P_IN> sink) {
-        sink.begin(sp.exactSizeIfKnown());
-        sp.forEach(sink);
-        sink.end();
-    }
-
-    public static<P_IN, P_OUT> void parallelForEach(PipelineHelper<P_IN, P_OUT> helper,
-                                                    Sink<P_IN> sink,
-                                                    boolean shortCircuit) {
-        new ForEachTask<>(helper, sink, shortCircuit).invoke();
-    }
-
-    private static class ForEachTask<S, T> extends AbstractTask<S, T, Void, ForEachTask<S, T>> {
-        // @@@ Extending AbstractTask here is probably inefficient, since we don't really need to
-        // keep track of the structure of the computation tree
-        private final Sink<S> sink;
-        private final boolean shortCircuit;
-
-        private ForEachTask(PipelineHelper<S, T> helper, Sink<S> sink, boolean shortCircuit) {
-            super(helper);
-            this.sink = sink;
-            this.shortCircuit = shortCircuit;
-        }
-
-        private ForEachTask(ForEachTask<S, T> parent, Spliterator<S> spliterator, Sink<S> sink) {
-            super(parent, spliterator);
-            this.sink = sink;
-            this.shortCircuit = parent.shortCircuit;
-        }
-
-        @Override
-        public boolean suggestSplit() {
-            boolean suggest = super.suggestSplit();
-            if (shortCircuit)
-                suggest = suggest && !sink.cancellationRequested();
-            return suggest;
-        }
-
-        @Override
-        protected ForEachTask<S, T> makeChild(Spliterator<S> spliterator) {
-            return new ForEachTask<>(this, spliterator, sink);
-        }
-
-        @Override
-        protected Void doLeaf() {
-            if (shortCircuit)
-                helper.getInputShape().forEachWithCancel(spliterator, sink);
-            else
-                spliterator.forEach(sink);
-            return null;
-        }
-    }
-
-
-    public interface AccumulatingSink<T, R, K extends AccumulatingSink<T, R, K>> extends TerminalSink<T, R> {
-
-        public void combine(K other);
-        public void clearState();
-    }
-
-    public static<P_IN, P_OUT, R, S extends AccumulatingSink<P_OUT, R, S>>
-    R parallelReduce(PipelineHelper<P_IN, P_OUT> helper, Supplier<S> factory) {
-        S sink = new ReduceTask<>(helper, factory).invoke();
-        return sink.getAndClearState();
-    }
-
-    private static class ReduceTask<P_IN, P_OUT, R, S extends AccumulatingSink<P_OUT, R, S>>
-            extends AbstractTask<P_IN, P_OUT, S, ReduceTask<P_IN, P_OUT, R, S>> {
-        private final Supplier<S> sinkFactory;
-
-        private ReduceTask(PipelineHelper<P_IN, P_OUT> helper, Supplier<S> sinkFactory) {
-            super(helper);
-            this.sinkFactory = sinkFactory;
-        }
-
-        private ReduceTask(ReduceTask<P_IN, P_OUT, R, S> parent, Spliterator<P_IN> spliterator) {
-            super(parent, spliterator);
-            this.sinkFactory = parent.sinkFactory;
-        }
-
-        @Override
-        protected ReduceTask<P_IN, P_OUT, R, S> makeChild(Spliterator<P_IN> spliterator) {
-            return new ReduceTask<>(this, spliterator);
-        }
-
-        @Override
-        protected S doLeaf() {
-            return intoUnwrapped(helper, spliterator, sinkFactory.get());
-        }
-
-        @Override
-        public void onCompletion(CountedCompleter caller) {
-            if (!isLeaf()) {
-                ReduceTask<P_IN, P_OUT, R, S> child = children;
-                S result = child.getLocalResult();
-                child = child.nextSibling;
-                for (; child != null; child = child.nextSibling) {
-                    S otherResult = child.getLocalResult();
-                    result.combine(otherResult);
-                    otherResult.clearState();
-                }
-                setLocalResult(result);
-            }
-        }
-    }
-
-    public static class ValueHolder<T> implements Block<T>, Supplier<T> {
-        private T value;
-
-        @Override
-        public void accept(T t) {
-            this.value = t;
-        }
-
-        @Override
-        public T get() {
-            return value;
-        }
-    }
-
-    public static class PrimitiveValueHolder {
-        public static class OfInt implements IntBlock, IntSupplier {
-            private int value;
-
-            public int getAsInt() {
-                return value;
-            }
-
-            public void accept(int value) {
-                this.value = value;
-            }
-        }
-    }
-}
--- a/src/share/classes/java/util/stream/op/Ops.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.stream.Sink;
-import java.util.stream.StreamShape;
-
-/**
- * Ops
- *
- * @author Brian Goetz
- */
-public class Ops {
-    private static class OpBase<T,U> implements IntermediateOp<T,U> {
-        private final int opFlags;
-        private final StreamShape inputShape, outputShape;
-        private final SinkWrapper<T> sinkWrapper;
-
-        protected OpBase(int opFlags, StreamShape inputShape, StreamShape outputShape, SinkWrapper<T> wrapper) {
-            this.opFlags = opFlags;
-            this.inputShape = inputShape;
-            this.outputShape = outputShape;
-            sinkWrapper = wrapper;
-        }
-
-        public StreamShape outputShape() {
-            return outputShape;
-        }
-
-        public StreamShape inputShape() {
-            return inputShape;
-        }
-
-        public int getOpFlags() {
-            return opFlags;
-        }
-
-        @Override
-        public Sink<T> wrapSink(int flags, Sink<U> sink) {
-            return sinkWrapper.wrapSink(flags, sink);
-        }
-    }
-
-    private static class IntOpBase extends OpBase<Integer, Integer> implements IntermediateOp.OfInt {
-        protected IntOpBase(int opFlags, StreamShape inputShape, StreamShape outputShape, SinkWrapper<Integer> wrapper) {
-            super(opFlags, inputShape, outputShape, wrapper);
-        }
-    }
-
-    public interface SinkWrapper<T> {
-        public Sink<T> wrapSink(int flags, Sink sink);
-    }
-
-    public static<T,U> IntermediateOp<T,U> chainedRef(int opFlags,
-                                                      StreamShape outputShape,
-                                                      SinkWrapper<T> sinkWrapper) {
-        return new OpBase<>(opFlags, StreamShape.REFERENCE, outputShape, sinkWrapper);
-    }
-
-    public static<T,U> IntermediateOp<T,U> chainedRef(int opFlags,
-                                                      SinkWrapper<T> sinkWrapper) {
-        return new OpBase<>(opFlags, StreamShape.REFERENCE, StreamShape.REFERENCE, sinkWrapper);
-    }
-
-    public static<T> IntermediateOp<T,T> flagOp(int opFlags) {
-        return new OpBase<T, T>(opFlags, StreamShape.REFERENCE, StreamShape.REFERENCE, (flags, sink) -> sink);
-    }
-
-    public static IntermediateOp.OfInt chainedInt(int opFlags,
-                                                  SinkWrapper<Integer> sinkWrapper) {
-        return new IntOpBase(opFlags, StreamShape.INT_VALUE, StreamShape.INT_VALUE, sinkWrapper);
-    }
-
-    public static<U> IntermediateOp<Integer, U> chainedInt(int opFlags,
-                                                           StreamShape outputShape,
-                                                           SinkWrapper<Integer> sinkWrapper) {
-        return new OpBase<>(opFlags, StreamShape.INT_VALUE, outputShape, sinkWrapper);
-    }
-
-    public static IntermediateOp.OfInt intFlagOp(int opFlags) {
-        return new IntOpBase(opFlags, StreamShape.INT_VALUE, StreamShape.INT_VALUE, (flags, sink) -> sink);
-    }
-}
--- a/src/share/classes/java/util/stream/op/SliceOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,374 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.*;
-import java.util.concurrent.CountedCompleter;
-import java.util.stream.*;
-
-/**
- * SliceOp
- *
- * @author Brian Goetz
- */
-public class SliceOp<T> implements StatefulOp<T> {
-    protected final long skip;
-    protected final long limit; // -1 means infinite
-    protected final StreamShape shape;
-    protected final Ops.SinkWrapper sinkWrapper;
-
-    public SliceOp(long skip, long limit, StreamShape shape) {
-        if (skip < 0)
-            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
-        this.skip = skip;
-        this.limit = limit;
-        this.shape = shape;
-        switch (shape.kind) {
-            case REFERENCE: sinkWrapper = this::wrapSinkRef; break;
-            case INT_VALUE: sinkWrapper = this::wrapSinkInt; break;
-            default:
-                throw new IllegalStateException("Unknown shape: " + shape.kind);
-        }
-    }
-
-    public SliceOp(long skip, StreamShape shape) {
-        this(skip, -1, shape);
-    }
-
-    private<T> Sink<T> wrapSinkRef(int flags, Sink sink) {
-        return new Sink.ChainedReference<T>(sink) {
-            long n = skip;
-            long m = limit >= 0 ? limit : Long.MAX_VALUE;
-
-            @Override
-            public void accept(T t) {
-                if (n == 0) {
-                    if (m > 0) {
-                        m--;
-                        downstream.accept(t);
-                    }
-                }
-                else {
-                    n--;
-                }
-            }
-
-            @Override
-            public boolean cancellationRequested() {
-                return m == 0 || downstream.cancellationRequested();
-            }
-        };
-    }
-
-    private Sink<Integer> wrapSinkInt(int flags, Sink sink) {
-        return new Sink.ChainedInt(sink) {
-            long n = skip;
-            long m = limit >= 0 ? limit : Long.MAX_VALUE;
-
-            @Override
-            public void accept(int t) {
-                if (n == 0) {
-                    if (m > 0) {
-                        m--;
-                        downstream.accept(t);
-                    }
-                }
-                else {
-                    n--;
-                }
-            }
-
-            @Override
-            public boolean cancellationRequested() {
-                return m == 0 || downstream.cancellationRequested();
-            }
-        };
-    }
-
-    @Override
-    public StreamShape outputShape() {
-        return shape;
-    }
-
-    @Override
-    public StreamShape inputShape() {
-        return shape;
-    }
-
-    @Override
-    public int getOpFlags() {
-        return StreamOpFlag.NOT_SIZED | ((limit != -1) ? StreamOpFlag.IS_SHORT_CIRCUIT : 0);
-    }
-
-    @Override
-    public Sink<T> wrapSink(int flags, Sink sink) {
-        return sinkWrapper.wrapSink(flags, sink);
-    }
-
-    private long getFinalSize(PipelineHelper helper) {
-        long size = helper.getOutputSizeIfKnown();
-        if (size >= 0) {
-            size = Math.max(0, size - skip);
-            if (limit >= 0)
-                size = Math.min(size, limit);
-        }
-        return size;
-    }
-
-    @Override
-    public <S> Node<T> evaluateParallel(PipelineHelper<S, T> helper) {
-        // Parallel strategy -- two cases
-        // IF we have full size information
-        // - decompose, keeping track of each leaf's (offset, size)
-        // - calculate leaf only if intersection between (offset, size) and desired slice
-        // - Construct a Node containing the appropriate sections of the appropriate leaves
-        // IF we don't
-        // - decompose, and calculate size of each leaf
-        // - on complete of any node, compute completed initial size from the root, and if big enough, cancel later nodes
-        // - @@@ this can be significantly improved
-
-        // @@@ Currently we don't do the sized version at all
-
-        // @@@ Should take into account ORDERED flag; if not ORDERED, we can limit in temporal order instead
-
-//        Spliterator<S> spliterator = helper.spliterator();
-//        int size = spliterator.getSizeIfKnown();
-//        if (size >= 0 && helper.getOutputSizeIfKnown() == size && spliterator.isPredictableSplits())
-//            return helper.invoke(new SizedSliceTask<>(helper, skip, getFinalSize(helper)));
-//        else
-            return new SliceTask<>(helper, skip, limit).invoke();
-    }
-
-    @Override
-    public String toString() {
-        return String.format("SliceOp[skip=%d,limit=%d]", skip, limit);
-    }
-
-    private static class SliceTask<S, T> extends AbstractShortCircuitTask<S, T, Node<T>, SliceTask<S, T>> {
-        private final long targetOffset, targetSize;
-        private long thisNodeSize;
-
-        private volatile boolean completed;
-
-        private SliceTask(PipelineHelper<S, T> helper, long offset, long size) {
-            super(helper);
-            this.targetOffset = offset;
-            this.targetSize = size;
-        }
-
-        private SliceTask(SliceTask<S, T> parent, Spliterator<S> spliterator) {
-            super(parent, spliterator);
-            this.targetOffset = parent.targetOffset;
-            this.targetSize = parent.targetSize;
-        }
-
-        @Override
-        protected SliceTask<S, T> makeChild(Spliterator<S> spliterator) {
-            return new SliceTask<>(this, spliterator);
-        }
-
-        @Override
-        protected final Node<T> getEmptyResult() {
-            return helper.getOutputNodeFactory().emptyNode();
-        }
-
-        @Override
-        protected final Node<T> doLeaf() {
-            if (isRoot()) {
-                Spliterator<T> wrapped = helper.wrapSequential(spliterator);
-                return helper.getOutputNodeFactory().truncateToNode(-1, wrapped, targetOffset, targetSize, helper.arrayGenerator());
-            }
-            else {
-                Node<T> node = OpUtils.intoUnwrapped(helper, spliterator,
-                                                     helper.getOutputNodeFactory().makeNodeBuilder(-1, helper.arrayGenerator())).build();
-                thisNodeSize = node.count();
-                completed = true;
-                return node;
-            }
-        }
-
-        @Override
-        public final void onCompletion(CountedCompleter<?> caller) {
-            if (!isLeaf()) {
-                thisNodeSize = 0;
-                for (SliceTask<S, T> child = children; child != null; child = child.nextSibling)
-                    thisNodeSize += child.thisNodeSize;
-                completed = true;
-                ArrayList<Node<T>> nodes = new ArrayList<>();
-                visit(nodes, 0);
-                Node<T> result;
-                if (nodes.size() == 0)
-                    result = helper.getOutputNodeFactory().emptyNode();
-                else if (nodes.size() == 1)
-                    result = nodes.get(0);
-                else
-                    result = helper.getOutputNodeFactory().concNodes(nodes);
-                setLocalResult(result);
-            }
-            if (targetSize >= 0) {
-                if (((SliceTask<S,T>) getRoot()).leftSize() >= targetOffset + targetSize)
-                    cancelLaterNodes();
-            }
-        }
-
-        private final long leftSize() {
-            if (completed)
-                return thisNodeSize;
-            else if (isLeaf())
-                return 0;
-            else {
-                long leftSize = 0;
-                for (SliceTask<S, T> child = children; child != null; child = child.nextSibling) {
-                    if (child.completed)
-                        leftSize += child.thisNodeSize;
-                    else {
-                        leftSize += child.leftSize();
-                        break;
-                    }
-                }
-                return leftSize;
-            }
-        }
-
-        private void visit(ArrayList<Node<T>> results, int offset) {
-            if (!isLeaf()) {
-                for (SliceTask<S, T> child = children; child != null; child = child.nextSibling) {
-                    child.visit(results, offset);
-                    offset += child.thisNodeSize;
-                }
-            }
-            else {
-                if (results.size() == 0) {
-                    if (offset+thisNodeSize >= targetOffset)
-                        results.add(truncateNode(getLocalResult(),
-                                                 Math.max(0, targetOffset - offset),
-                                                 targetSize >= 0 ? Math.max(0, offset + thisNodeSize - (targetOffset + targetSize)) : 0));
-                }
-                else {
-                    if (targetSize == -1 || offset < targetOffset+targetSize) {
-                        results.add(truncateNode(getLocalResult(), 0,
-                                                 targetSize >= 0 ? Math.max(0, offset+thisNodeSize - (targetOffset + targetSize)) : 0));
-                    }
-                }
-            }
-        }
-
-        private Node<T> truncateNode(Node<T> input, long skipLeft, long skipRight) {
-            if (skipLeft == 0 && skipRight == 0)
-                return input;
-            else {
-                // @@@ Implement Node.truncate which will be more efficient
-                long truncatedSize = thisNodeSize - skipLeft - skipRight;
-                return helper.getOutputNodeFactory().truncateToNode(truncatedSize, input.spliterator(), skipLeft, truncatedSize, helper.arrayGenerator());
-            }
-        }
-    }
-
-    // @@@ Currently unused -- optimization for when all sizes are known
-//    private static class SizedSliceTask<S, T> extends AbstractShortCircuitTask<S, T, Node<T>, SizedSliceTask<S, T>> {
-//        private final int targetOffset, targetSize;
-//        private final int offset, size;
-//
-//        private SizedSliceTask(ParallelPipelineHelper<S, T> helper, int offset, int size) {
-//            super(helper);
-//            targetOffset = offset;
-//            targetSize = size;
-//            this.offset = 0;
-//            this.size = spliterator.getSizeIfKnown();
-//        }
-//
-//        private SizedSliceTask(SizedSliceTask<S, T> parent, Spliterator<S> spliterator) {
-//            // Makes assumptions about order in which siblings are created and linked into parent!
-//            super(parent, spliterator);
-//            targetOffset = parent.targetOffset;
-//            targetSize = parent.targetSize;
-//            int siblingSizes = 0;
-//            for (SizedSliceTask<S, T> sibling = parent.children; sibling != null; sibling = sibling.nextSibling)
-//                siblingSizes += sibling.size;
-//            size = spliterator.getSizeIfKnown();
-//            offset = parent.offset + siblingSizes;
-//        }
-//
-//        @Override
-//        protected SizedSliceTask<S, T> makeChild(Spliterator<S> spliterator) {
-//            return new SizedSliceTask<>(this, spliterator);
-//        }
-//
-//        @Override
-//        protected Node<T> getEmptyResult() {
-//            return Nodes.emptyNode();
-//        }
-//
-//        @Override
-//        public boolean taskCancelled() {
-//            if (offset > targetOffset+targetSize || offset+size < targetOffset)
-//                return true;
-//            else
-//                return super.taskCancelled();
-//        }
-//
-//        @Override
-//        protected Node<T> doLeaf() {
-//            int skipLeft = Math.max(0, targetOffset - offset);
-//            int skipRight = Math.max(0, offset + size - (targetOffset + targetSize));
-//            if (skipLeft == 0 && skipRight == 0)
-//                return helper.into(Nodes.<T>makeBuilder(spliterator.getSizeIfKnown())).build();
-//            else {
-//                // If we're the first or last node that intersects the target range, peel off irrelevant elements
-//                int truncatedSize = size - skipLeft - skipRight;
-//                NodeBuilder<T> builder = Nodes.<T>makeBuilder(truncatedSize);
-//                Sink<S> wrappedSink = helper.wrapSink(builder);
-//                wrappedSink.begin(truncatedSize);
-//                Iterator<S> iterator = spliterator.iterator();
-//                for (int i=0; i<skipLeft; i++)
-//                    iterator.next();
-//                for (int i=0; i<truncatedSize; i++)
-//                    wrappedSink.apply(iterator.next());
-//                wrappedSink.end();
-//                return builder.build();
-//            }
-//        }
-//
-//        @Override
-//        public void onCompletion(CountedCompleter<?> caller) {
-//            if (!isLeaf()) {
-//                Node<T> result = null;
-//                for (SizedSliceTask<S, T> child = children.nextSibling; child != null; child = child.nextSibling) {
-//                    Node<T> childResult = child.getRawResult();
-//                    if (childResult == null)
-//                        continue;
-//                    else if (result == null)
-//                        result = childResult;
-//                    else
-//                        result = Nodes.node(result, childResult);
-//                }
-//                setRawResult(result);
-//                if (offset <= targetOffset && offset+size >= targetOffset+targetSize)
-//                    shortCircuit(result);
-//            }
-//        }
-//    }
-
-}
--- a/src/share/classes/java/util/stream/op/SortedOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,246 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.*;
-import java.util.stream.*;
-
-
-/**
- * An operation which sorts elements.
- *
- * @param <T> Type of elements to be sorted.
- *
- * @author Brian Goetz
- */
-public abstract class SortedOp<T> implements StatefulOp<T> {
-
-    public static class OfRef<T> extends SortedOp<T> {
-        /** Comparator used for sorting */
-        private final Comparator<? super T> comparator;
-
-        /**
-         * Sort using natural order of {@literal <T>} which must be
-         * {@code Comparable}.
-         */
-        public OfRef() {
-            // Will throw CCE when we try to sort if T is not Comparable
-            this((Comparator<? super T>) Comparators.naturalOrder());
-        }
-
-        /**
-         * Sort using the provided comparator.
-         *
-         * @param comparator The comparator to be used to evaluate ordering.
-         */
-        public OfRef(Comparator<? super T> comparator) {
-            this.comparator = Objects.requireNonNull(comparator);
-        }
-
-        @Override
-        public Sink<T> wrapSink(int flags, Sink sink) {
-            Objects.requireNonNull(sink);
-
-            if (StreamOpFlag.SORTED.isKnown(flags))
-                return sink;
-            else if (StreamOpFlag.SIZED.isKnown(flags))
-                return new SizedRefSortingSink<>(sink, comparator);
-            else
-                return new RefSortingSink<>(sink, comparator);
-        }
-
-        public <P_IN> Node<T> evaluateParallel(PipelineHelper<P_IN, T> helper) {
-            if (StreamOpFlag.SORTED.isKnown(helper.getStreamAndOpFlags())) {
-                return helper.collectOutput(false);
-            }
-            else {
-                // @@@ Weak two-pass parallel implementation; parallel collect, parallel sort
-                T[] flattenedData = helper.collectOutput(true).asArray(helper.arrayGenerator());
-                Arrays.parallelSort(flattenedData, comparator);
-                return Nodes.node(flattenedData);
-            }
-        }
-    }
-
-    public static class OfInt extends SortedOp<Integer> implements StatefulOp.OfInt {
-        @Override
-        public Sink<Integer> wrapSink(int flags, Sink sink) {
-            Objects.requireNonNull(sink);
-
-            if (StreamOpFlag.SORTED.isKnown(flags))
-                return sink;
-            else if (StreamOpFlag.SIZED.isKnown(flags))
-                return new SizedIntSortingSink(sink);
-            else
-                return new IntSortingSink(sink);
-        }
-
-        @Override
-        public <P_IN> Node<Integer> evaluateSequential(PipelineHelper<P_IN, Integer> helper) {
-            Node.OfInt n = (Node.OfPrimitive.OfInt) helper.collectOutput(true);
-
-            int[] content = n.asIntArray();
-            Arrays.sort(content);
-
-            return Nodes.intNode(content);
-        }
-
-        @Override
-        public <P_IN> Node<Integer> evaluateParallel(PipelineHelper<P_IN, Integer> helper) {
-            Node.OfInt n = (Node.OfPrimitive.OfInt) helper.collectOutput(true);
-
-            int[] content = n.asIntArray();
-            Arrays.parallelSort(content);
-
-            return Nodes.intNode(content);
-        }
-
-    }
-
-    @Override
-    public int getOpFlags() {
-        return StreamOpFlag.IS_SORTED | StreamOpFlag.IS_ORDERED;
-    }
-
-
-    private static class SizedRefSortingSink<T> extends Sink.ChainedReference<T> {
-        private final Comparator<? super T> comparator;
-        T[] array;
-        int offset;
-
-        public SizedRefSortingSink(Sink sink, Comparator<? super T> comparator) {
-            super(sink);
-            this.comparator = comparator;
-        }
-
-        @Override
-        public void begin(long size) {
-            if (size >= Streams.MAX_ARRAY_SIZE)
-                throw new IllegalArgumentException("Stream size exceeds max array size");
-            array = (T[]) new Object[(int) size];
-        }
-
-        @Override
-        public void end() {
-            Arrays.sort(array, comparator);
-            downstream.begin(array.length);
-            for (T t : array)
-                downstream.accept(t);
-            downstream.end();
-            array = null;
-        }
-
-        @Override
-        public void accept(T t) {
-            array[offset++] = t;
-        }
-    }
-
-    private static class RefSortingSink<T> extends Sink.ChainedReference<T> {
-        private final Comparator<? super T> comparator;
-        ArrayList<T> list;
-
-        public RefSortingSink(Sink sink, Comparator<? super T> comparator) {
-            super(sink);
-            this.comparator = comparator;
-        }
-
-        @Override
-        public void begin(long size) {
-            list = (size >= 0) ? new ArrayList<T>((int) size) : new ArrayList<T>();
-        }
-
-        @Override
-        public void end() {
-            list.sort(comparator);
-            downstream.begin(list.size());
-            list.forEach(downstream::accept);
-            downstream.end();
-            list = null;
-        }
-
-        @Override
-        public void accept(T t) {
-            list.add(t);
-        }
-    }
-
-    private static class SizedIntSortingSink extends Sink.ChainedInt {
-        int[] array;
-        int offset;
-
-        public SizedIntSortingSink(Sink downstream) {
-            super(downstream);
-        }
-
-        @Override
-        public void begin(long size) {
-            if (size >= Streams.MAX_ARRAY_SIZE)
-                throw new IllegalArgumentException("Stream size exceeds max array size");
-            array = new int[(int) size];
-        }
-
-        @Override
-        public void end() {
-            Arrays.sort(array);
-            downstream.begin(array.length);
-            for (int t : array)
-                downstream.accept(t);
-            downstream.end();
-            array = null;
-        }
-
-        @Override
-        public void accept(int t) {
-            array[offset++] = t;
-        }
-    }
-
-    private static class IntSortingSink extends Sink.ChainedInt {
-        SpinedBuffer.OfInt b;
-
-        public IntSortingSink(Sink sink) {super(sink);}
-
-        @Override
-        public void begin(long size) {
-            b = (size > 0) ? new SpinedBuffer.OfInt((int) size) : new SpinedBuffer.OfInt();
-        }
-
-        @Override
-        public void end() {
-            int[] ints = b.asIntArray();
-            Arrays.sort(ints);
-            downstream.begin(ints.length);
-            for (int anInt : ints)
-                downstream.accept(anInt);
-            downstream.end();
-        }
-
-        @Override
-        public void accept(int t) {
-            b.accept(t);
-        }
-    }
-}
--- a/src/share/classes/java/util/stream/op/SpinedBuffer.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,742 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.*;
-import java.util.function.Block;
-import java.util.function.IntBlock;
-import java.util.function.ObjIntFunction;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.stream.*;
-import java.util.PrimitiveIterator;
-
-/**
- * An ordered collection of elements.
- * Elements can be added, no elements can be removed.
- * <p>
- * One or more arrays are used to store elements.
- * The use of a multiple arrays has better performance characteristics than a single array used by {@link ArrayList}
- * when the capacity of the list needs to be increased. No copying of arrays of elements is required.
- * The trade-off is the elements may be fragmented over two or more arrays. However, for the purposes
- * of adding elements, iterating and splitting this trade-off is acceptable.
- * </p>
- *
- * @param <E> the type of elements in this list
- */
-public class SpinedBuffer<E> extends AbstractSpinedBuffer<E> implements Block<E>, Iterable<E> {
-
-    /*
-     * We optimistically hope that all the data will fit into the first chunk, so we try to avoid
-     * inflating the spine[] and priorElementCount[] arrays prematurely.  So methods must be prepared
-     * to deal with these arrays being null.  If spine is non-null, then spineIndex points to the current
-     * chunk within the spine, otherwise it is zero.  The spine and priorElementCount arrays are always
-     * the same size, and for any i <= spineIndex, priorElementCount[i] is the sum of the sizes of all
-     * the prior chunks.
-     *
-     * The curChunk pointer is always valid.  The elementIndex is the index of the next element to be
-     * written in curChunk; this may be past the end of curChunk so we have to check before writing.
-     * When we inflate the spine array, curChunk becomes the first element in it.  When we clear the
-     * buffer, we discard all chunks except the first one, which we clear, restoring it to the initial
-     * single-chunk state.
-     *
-     */
-
-    // The chunk we're currently writing into
-    protected E[] curChunk;
-
-    // All chunks, or null if there is only one chunk
-    protected E[][] spine;
-
-    /**
-     * Constructs an empty list with the specified initial capacity.
-     *
-     * @param  initialCapacity  the initial capacity of the list
-     * @throws IllegalArgumentException if the specified initial capacity
-     *         is negative
-     */
-    public SpinedBuffer(int initialCapacity) {
-        super(initialCapacity);
-        curChunk = (E[]) new Object[1 << initialChunkPower];
-    }
-
-    /**
-     * Constructs an empty list with an initial capacity of sixteen.
-     */
-    public SpinedBuffer() {
-        this(MIN_CHUNK_SIZE);
-    }
-
-    /**
-     * Constructs a list containing the elements of the specified
-     * iterable, in the order they are returned by the iterables's
-     * iterator.
-     *
-     * @param i the iterable whose elements are to be placed into this list
-     * @throws NullPointerException if the specified iterable is null
-     */
-    public SpinedBuffer(Iterable<E> i) {
-        this();
-
-        // @@@ This can be more efficient if c.toArray() is used
-        i.forEach(this);
-
-        // @@@ Note for testing purposes we need to simulate the contents as if
-        //     elements are added individually, if this method is modified check usage in tests and
-        //     as data source
-    }
-
-    protected long capacity() {
-        return (spineIndex == 0)
-               ? curChunk.length
-               : priorElementCount[spineIndex] + spine[spineIndex].length;
-    }
-
-    private void inflateSpine() {
-        if (spine == null) {
-            spine = (E[][]) new Object[MIN_SPINE_SIZE][];
-            priorElementCount = new long[MIN_SPINE_SIZE];
-            spine[0] = curChunk;
-        }
-    }
-
-    protected final void ensureCapacity(long targetSize) {
-        long capacity = capacity();
-        if (targetSize > capacity) {
-            inflateSpine();
-            for (int i=spineIndex+1; targetSize > capacity; i++) {
-                if (i >= spine.length) {
-                    int newSpineSize = spine.length * 2;
-                    spine = Arrays.copyOf(spine, newSpineSize);
-                    priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize);
-                }
-                int nextChunkSize = chunkSize(i);
-                spine[i] = (E[]) new Object[nextChunkSize];
-                priorElementCount[i] = priorElementCount[i-1] + spine[i-1].length;
-                capacity += nextChunkSize;
-            }
-        }
-    }
-
-    protected void increaseCapacity() {
-        ensureCapacity(capacity() + 1);
-    }
-
-    public E get(long index) {
-        // @@@ can further optimize by caching last seen spineIndex, which is going to be right most of the time
-        if (spineIndex == 0) {
-            if (index < elementIndex)
-                return curChunk[((int) index)];
-            else
-                throw new IndexOutOfBoundsException(Long.toString(index));
-        }
-
-        if (index >= count())
-            throw new IndexOutOfBoundsException(Long.toString(index));
-
-        for (int j=0; j <= spineIndex; j++)
-            if (index < priorElementCount[j] + spine[j].length)
-                return spine[j][((int) (index - priorElementCount[j]))];
-
-        throw new IndexOutOfBoundsException(Long.toString(index));
-    }
-
-    public void copyInto(E[] array, int offset) {
-        long finalOffset = offset + count();
-        if (finalOffset > array.length || finalOffset < offset) {
-            throw new IndexOutOfBoundsException("does not fit");
-        }
-
-        if (spineIndex == 0)
-            System.arraycopy(curChunk, 0, array, offset, elementIndex);
-        else {
-            // full chunks
-            for (int i=0; i < spineIndex; i++) {
-                System.arraycopy(spine[i], 0, array, offset, spine[i].length);
-                offset += spine[i].length;
-            }
-            if (elementIndex > 0)
-                System.arraycopy(curChunk, 0, array, offset, elementIndex);
-        }
-    }
-
-    public E[] asArray(ObjIntFunction<E[]> generator) {
-        // @@@ will fail for size == MAX_VALUE
-        E[] result = generator.apply((int) count());
-
-        copyInto(result, 0);
-
-        return result;
-    }
-
-    @Override
-    public void clear() {
-        if (spine != null) {
-            curChunk = spine[0];
-            for (int i=0; i<curChunk.length; i++)
-                curChunk[i] = null;
-            spine = null;
-            priorElementCount = null;
-        }
-        else {
-            for (int i=0; i<elementIndex; i++)
-                curChunk[i] = null;
-        }
-        elementIndex = 0;
-        spineIndex = 0;
-    }
-
-    // Iterable
-
-    public Iterator<E> iterator() {
-        return spliterator().iterator();
-    }
-
-    public void forEach(Block<? super E> block) {
-        // completed chunks, if any
-        for (int j = 0; j < spineIndex; j++)
-            for (E t : spine[j])
-                block.accept(t);
-
-        // current chunk
-        for (int i=0; i<elementIndex; i++)
-            block.accept(curChunk[i]);
-    }
-
-    // Block
-
-    @Override
-    public void accept(E e) {
-        if (elementIndex == curChunk.length) {
-            inflateSpine();
-            if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null)
-                increaseCapacity();
-            elementIndex = 0;
-            ++spineIndex;
-            curChunk = spine[spineIndex];
-        }
-        curChunk[elementIndex++] = e;
-    }
-
-    // Object
-
-    public String toString() {
-        List<E> list = new ArrayList<>();
-        forEach(list::add);
-        return "SpinedBuffer:" + list.toString();
-    }
-
-    // Streamable
-
-    public Stream<E> stream() {
-        return Streams.stream(this::spliterator,
-                              StreamOpFlag.IS_SIZED | StreamOpFlag.IS_ORDERED);
-    }
-
-    public Stream<E> parallelStream() {
-        return Streams.parallelStream(this::spliterator,
-                                      StreamOpFlag.IS_SIZED | StreamOpFlag.IS_ORDERED);
-    }
-
-    public Spliterator<E> spliterator() {
-        return new AbstractSpliterator<E>() {
-            int splSpineIndex;
-            int splElementIndex;
-            E[] splChunk;
-
-            @Override
-            public long estimateSize() {
-                switch (state) {
-                    case FINISHED:
-                        return 0;
-                    case TRAVERSING:
-                    case SPLITTING:
-                        return (spine == null)
-                               ? (elementIndex - splElementIndex)
-                               : count() - (priorElementCount[splSpineIndex] + splElementIndex);
-                    default:
-                        throw illegalState();
-                }
-            }
-
-            @Override
-            public boolean tryAdvance(Block<? super E> block) {
-                switch (state) {
-                    case SPLITTING: {
-                        // @@@ combine
-                        splChunk = (spine == null) ? curChunk : spine[splSpineIndex];
-                        boolean hasNext = (splSpineIndex < spineIndex) ||
-                                          (splSpineIndex == spineIndex && splElementIndex < elementIndex);
-                        state = hasNext ? State.TRAVERSING : State.FINISHED;
-                        if (hasNext)
-                            block.accept(splChunk[splElementIndex]);
-                        return hasNext;
-                    }
-
-                    case TRAVERSING: {
-                        if (++splElementIndex == splChunk.length) {
-                            splElementIndex = 0;
-                            ++splSpineIndex;
-                            if (spine != null && splSpineIndex < spine.length)
-                                splChunk = spine[splSpineIndex];
-                        }
-                        boolean hasNext = (splSpineIndex < spineIndex) ||
-                                          (splSpineIndex == spineIndex && splElementIndex < elementIndex);
-                        if (!hasNext)
-                            state = State.FINISHED;
-                        else
-                            block.accept(splChunk[splElementIndex]);
-                        return hasNext;
-                    }
-
-                    case FINISHED:
-                        return false;
-
-                    default:
-                        throw illegalState();
-                }
-            }
-
-            @Override
-            public void forEach(Block<? super E> block) {
-                if (state != State.SPLITTING)
-                    throw illegalState();
-                while (tryAdvance(block)) { }
-                state = State.FINISHED;
-            }
-
-            @Override
-            public boolean hasExactSplits() {
-                return true;
-            }
-
-            @Override
-            public Spliterator<E> trySplit() {
-                if (state != State.SPLITTING)
-                    throw illegalState();
-
-                if (splSpineIndex == spineIndex) {
-                    int t = (elementIndex - splElementIndex) / 2;
-                    if (t == 0)
-                        return null;
-                    else {
-                        Spliterator<E> ret = Arrays.spliterator(curChunk, splElementIndex, t);
-                        splElementIndex += t;
-                        return ret;
-                    }
-                }
-                else {
-                    Spliterator<E> ret = Arrays.spliterator(spine[splSpineIndex], 0, spine[splSpineIndex].length);
-                    ++splSpineIndex;
-                    return ret;
-                }
-            }
-        };
-    }
-
-    /**
-     * An ordered collection of primitive values.
-     * Values can be added, no values can be removed.
-     * <p>
-     * One or more arrays are used to store values.
-     * The use of a multiple arrays has better performance characteristics than a single array used by {@link java.util.ArrayList}
-     * when the capacity of the list needs to be increased. No copying of arrays of values is required.
-     * The trade-off is the values may be fragmented over two or more arrays. However, for the purposes
-     * of adding values, iterating and splitting this trade-off is acceptable.
-     * </p>
-     *
-     * @param <E> the type of primitive value.
-     * @param <A> the type primitive array of values.
-     * @param <B> the type of primitive block.
-     */
-    public abstract static class OfPrimitive<E, A, B>
-            extends AbstractSpinedBuffer<E> implements Iterable<E> {
-
-        /*
-         * We optimistically hope that all the data will fit into the first chunk, so we try to avoid
-         * inflating the spine[] and priorElementCount[] arrays prematurely.  So methods must be prepared
-         * to deal with these arrays being null.  If spine is non-null, then spineIndex points to the current
-         * chunk within the spine, otherwise it is zero.  The spine and priorElementCount arrays are always
-         * the same size, and for any i <= spineIndex, priorElementCount[i] is the sum of the sizes of all
-         * the prior chunks.
-         *
-         * The curChunk pointer is always valid.  The elementIndex is the index of the next element to be
-         * written in curChunk; this may be past the end of curChunk so we have to check before writing.
-         * When we inflate the spine array, curChunk becomes the first element in it.  When we clear the
-         * buffer, we discard all chunks except the first one, which we clear, restoring it to the initial
-         * single-chunk state.
-         *
-         */
-
-        // The chunk we're currently writing into
-        protected A curChunk;
-
-        // All chunks, or null if there is only one chunk
-        protected A[] spine;
-
-        /**
-         * Constructs an empty list with the specified initial capacity.
-         *
-         * @param  initialCapacity  the initial capacity of the list
-         * @throws IllegalArgumentException if the specified initial capacity
-         *         is negative
-         */
-        public OfPrimitive(int initialCapacity) {
-            super(initialCapacity);
-            curChunk = newArray(1 << initialChunkPower);
-        }
-
-        /**
-         * Constructs an empty list with an initial capacity of sixteen.
-         */
-        public OfPrimitive() {
-            this(MIN_CHUNK_SIZE);
-        }
-
-        // Iterable
-
-        @Override
-        public abstract PrimitiveIterator<E> iterator();
-
-        @Override
-        public abstract void forEach(Block<? super E> block);
-
-        //
-
-        protected abstract A[] newArrayArray(int size);
-        protected abstract A newArray(int size);
-        protected abstract int length(A array);
-        protected abstract void forEach(A array, int upTo, B block);
-
-        protected long capacity() {
-            return (spineIndex == 0)
-                   ? length(curChunk)
-                   : priorElementCount[spineIndex] + length(spine[spineIndex]);
-        }
-
-        private void inflateSpine() {
-            if (spine == null) {
-                spine = newArrayArray(MIN_SPINE_SIZE);
-                priorElementCount = new long[MIN_SPINE_SIZE];
-                spine[0] = curChunk;
-            }
-        }
-
-        protected final void ensureCapacity(long targetSize) {
-            long capacity = capacity();
-            if (targetSize > capacity) {
-                inflateSpine();
-                for (int i=spineIndex+1; targetSize > capacity; i++) {
-                    if (i >= spine.length) {
-                        int newSpineSize = spine.length * 2;
-                        spine = Arrays.copyOf(spine, newSpineSize);
-                        priorElementCount = Arrays.copyOf(priorElementCount, newSpineSize);
-                    }
-                    int nextChunkSize = chunkSize(i);
-                    spine[i] = newArray(nextChunkSize);
-                    priorElementCount[i] = priorElementCount[i-1] + length(spine[i-1]);
-                    capacity += nextChunkSize;
-                }
-            }
-        }
-
-        protected void increaseCapacity() {
-            ensureCapacity(capacity() + 1);
-        }
-
-        protected int chunkFor(long index) {
-            if (spineIndex == 0) {
-                if (index < elementIndex)
-                    return 0;
-                else
-                    throw new IndexOutOfBoundsException(Long.toString(index));
-            }
-
-            if (index >= count())
-                throw new IndexOutOfBoundsException(Long.toString(index));
-
-            for (int j=0; j <= spineIndex; j++)
-                if (index < priorElementCount[j] + length(spine[j]))
-                    return j;
-
-            throw new IndexOutOfBoundsException(Long.toString(index));
-        }
-
-        public void copyInto(A array, int offset) {
-            long finalOffset = offset + count();
-            if (finalOffset > length(array) || finalOffset < offset) {
-                throw new IndexOutOfBoundsException("does not fit");
-            }
-
-            if (spineIndex == 0)
-                System.arraycopy(curChunk, 0, array, offset, elementIndex);
-            else {
-                // full chunks
-                for (int i=0; i < spineIndex; i++) {
-                    System.arraycopy(spine[i], 0, array, offset, length(spine[i]));
-                    offset += length(spine[i]);
-                }
-                if (elementIndex > 0)
-                    System.arraycopy(curChunk, 0, array, offset, elementIndex);
-            }
-        }
-
-        public A asPrimitiveArray() {
-            // @@@ will fail for size == MAX_VALUE
-            A result = newArray((int) count());
-            copyInto(result, 0);
-            return result;
-        }
-
-        protected void preAccept() {
-            if (elementIndex == length(curChunk)) {
-                inflateSpine();
-                if (spineIndex+1 >= spine.length || spine[spineIndex+1] == null)
-                    increaseCapacity();
-                elementIndex = 0;
-                ++spineIndex;
-                curChunk = spine[spineIndex];
-            }
-        }
-
-        public void clear() {
-            if (spine != null) {
-                curChunk = spine[0];
-                spine = null;
-                priorElementCount = null;
-            }
-            elementIndex = 0;
-            spineIndex = 0;
-        }
-
-        // Iterable
-
-        protected abstract class BaseSpliterator<T_SPLITER extends Spliterator<E>>
-                extends AbstractSpliterator<E> {
-            int splSpineIndex;
-            int splElementIndex;
-            A splChunk;
-
-            abstract T_SPLITER arraySpliterator(A array, int offset, int len);
-
-            @Override
-            public long estimateSize() {
-                switch (state) {
-                    case FINISHED:
-                        return 0;
-                    case TRAVERSING:
-                    case SPLITTING:
-                        return (spine == null)
-                               ? (elementIndex - splElementIndex)
-                               : count() - (priorElementCount[splSpineIndex] + splElementIndex);
-                    default:
-                        throw illegalState();
-                }
-            }
-
-            @Override
-            public boolean hasExactSplits() {
-                return true;
-            }
-
-            protected boolean doAdvance() {
-                switch (state) {
-                    case SPLITTING: {
-                        splChunk = (spine == null) ? curChunk : spine[splSpineIndex];
-                        boolean hasNext = (splSpineIndex < spineIndex) ||
-                                          (splSpineIndex == spineIndex && splElementIndex < elementIndex);
-                        state = hasNext ? State.TRAVERSING : State.FINISHED;
-                        return hasNext;
-                    }
-
-                    case TRAVERSING: {
-                        if (++splElementIndex == length(splChunk)) {
-                            splElementIndex = 0;
-                            ++splSpineIndex;
-                            if (spine != null && splSpineIndex < spine.length)
-                                splChunk = spine[splSpineIndex];
-                        }
-                        boolean hasNext = (splSpineIndex < spineIndex) ||
-                                          (splSpineIndex == spineIndex && splElementIndex < elementIndex);
-                        if (!hasNext)
-                            state = State.FINISHED;
-                        return hasNext;
-                    }
-
-                    case FINISHED:
-                        return false;
-
-                    default:
-                        throw illegalState();
-                }
-            }
-
-            @Override
-            public T_SPLITER trySplit() {
-                if (state != State.SPLITTING)
-                    throw illegalState();
-
-                if (splSpineIndex == spineIndex) {
-                    int t = (elementIndex - splElementIndex) / 2;
-                    if (t == 0)
-                        return null;
-                    else {
-                        T_SPLITER ret = arraySpliterator(curChunk, splElementIndex, t);
-                        splElementIndex += t;
-                        return ret;
-                    }
-                }
-                else {
-                    T_SPLITER ret = arraySpliterator(spine[splSpineIndex], 0, length(spine[splSpineIndex]));
-                    ++splSpineIndex;
-                    return ret;
-                }
-            }
-        }
-
-        public void forEach(B block) {
-            // completed chunks, if any
-            for (int j = 0; j < spineIndex; j++)
-                forEach(spine[j], length(spine[j]), block);
-
-            // current chunk
-            forEach(curChunk, elementIndex, block);
-        }
-
-    }
-
-    /**
-     * An ordered collection of <code>int</code> values.
-     */
-    public static class OfInt extends SpinedBuffer.OfPrimitive<Integer, int[], IntBlock> implements IntBlock {
-        public OfInt() { }
-
-        @Override
-        public void forEach(Block<? super Integer> sink) {
-            if (sink instanceof IntBlock) {
-                forEach((IntBlock) sink);
-            }
-            else {
-                Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using boxed int in forEach", getClass().getName());
-                spliterator().forEach(sink);
-            }
-        }
-
-        @Override
-        protected int[][] newArrayArray(int size) {
-            return new int[size][];
-        }
-
-        public OfInt(int initialCapacity) {
-            super(initialCapacity);
-        }
-
-        @Override
-        protected int[] newArray(int size) {
-            return new int[size];
-        }
-
-        @Override
-        protected void forEach(int[] array, int upTo, IntBlock block) {
-            for (int i=0; i<upTo; i++)
-                block.accept(array[i]);
-        }
-
-        @Override
-        protected int length(int[] array) {
-            return array.length;
-        }
-
-        @Override
-        public void accept(int i) {
-            preAccept();
-            curChunk[elementIndex++] = i;
-        }
-
-        public int get(long index) {
-            int ch = chunkFor(index);
-            if (spineIndex == 0 && ch == 0)
-                return curChunk[(int) index];
-            else
-                return spine[ch][(int) (index-priorElementCount[ch])];
-        }
-
-        public int[] asIntArray() {
-            return asPrimitiveArray();
-        }
-
-        @Override
-        public PrimitiveIterator<Integer> iterator() {
-            return spliterator().iterator();
-        }
-
-        private class Splitr
-                extends BaseSpliterator<Spliterator.OfPrimitive<Integer>>
-                implements Spliterator.OfInt {
-            @Override
-            Spliterator.OfPrimitive<Integer> arraySpliterator(int[] array, int offset, int len) {
-                return Arrays.spliterator(array, offset, len);
-            }
-
-            @Override
-            public boolean tryAdvance(IntBlock block) {
-                boolean hasNext = doAdvance();
-                if (hasNext)
-                    block.accept(splChunk[splElementIndex]);
-                return hasNext;
-            }
-
-        }
-
-        public Spliterator.OfInt spliterator() {
-            return new Splitr();
-        }
-
-        public IntStream stream() {
-            return Streams.intStream(this::spliterator,
-                                     StreamOpFlag.IS_SIZED | StreamOpFlag.IS_ORDERED);
-        }
-
-        public IntStream parallelStream() {
-            return Streams.intParallelStream(this::spliterator,
-                                             StreamOpFlag.IS_SIZED | StreamOpFlag.IS_ORDERED);
-        }
-
-        @Override
-        public String toString() {
-            int[] array = asIntArray();
-            if (array.length < 200) {
-                return String.format("%s[length=%d, chunks=%d]%s", getClass().getSimpleName(), array.length,
-                                     spineIndex, Arrays.toString(array));
-            }
-            else {
-                int[] array2 = Arrays.copyOf(array, 200);
-                return String.format("%s[length=%d, chunks=%d]%s...", getClass().getSimpleName(), array.length,
-                                     spineIndex, Arrays.toString(array2));
-            }
-        }
-    }
-}
-
--- a/src/share/classes/java/util/stream/op/StatefulOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-package java.util.stream.op;
-
-/**
- * A stateful operation. State is accumulated as elements are processed.
- * <p>The parallel evaluation returns a conc-tree of output elements.</p>
- *
- * @param <E> Type of input and output elements.
- *
- */
-public interface StatefulOp<E> extends IntermediateOp<E, E> {
-
-    @Override
-    public default boolean isStateful() {
-        return true;
-    }
-
-    // @@@ re-abstract evaluateParallel?
-
-    interface OfInt extends IntermediateOp.OfInt, StatefulOp<Integer> {
-    }
-}
--- a/src/share/classes/java/util/stream/op/StreamOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package java.util.stream.op;
-
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import java.util.stream.PipelineHelper;
-import java.util.stream.StreamShape;
-
-/**
- * An Op whose results can be evaluated directly.  This includes terminal operations, as well as intermediate
- * stateless and stateful operations.
- *
- * @param <E_IN> Type of input elements.
- * @param <R> Type of result.
- * @author Brian Goetz
- */
-public interface StreamOp<E_IN, R> {
-
-    /**
-     *
-     * @return the input shape of this operation.
-     */
-    default StreamShape inputShape() { return StreamShape.REFERENCE; }
-
-    /**
-     * Get the properties of the operation.
-     * <p>The properties correspond to the properties the output stream is
-     * known to have or is not known to have when this operation is applied, in
-     * encounter order, to elements of an input stream.</p>
-     *
-     * @return the properties of the operation.
-     * @see {@link java.util.stream.StreamOpFlag}
-     */
-    default int getOpFlags() { return 0; }
-
-    /**
-     * Evaluate the result of the operation in parallel.
-     *
-     *
-     * @param helper
-     * @return the result of the operation.
-     */
-    default <P_IN> R evaluateParallel(PipelineHelper<P_IN, E_IN> helper) {
-        Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using computeParallel serial default", getClass().getSimpleName());
-        return evaluateSequential(helper);
-    }
-
-    /**
-     * Evaluate the result of the operation sequentially.
-     *
-     * @param helper
-     * @return the result of the operation.
-     */
-    <P_IN> R evaluateSequential(PipelineHelper<P_IN, E_IN> helper);
-
-}
--- a/src/share/classes/java/util/stream/op/TerminalOp.java	Thu Jan 10 16:54:38 2013 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
-/*<