changeset 6418:c5b238ae25fe

package renames java.util.streams -> java.util.stream java.util.streams.ops -> java.util.op java.util.streams.primitives -> java.util.primitive
author mduigou
date Thu, 15 Nov 2012 19:11:58 -0800
parents dfed78f69c8b
children a4c10f71e673
files make/docs/CORE_PKGS.gmk make/java/java/Makefile makefiles/docs/CORE_PKGS.gmk src/share/classes/com/sun/tools/jdi/EventSetImpl.java src/share/classes/java/io/BufferedReader.java src/share/classes/java/lang/AbstractStringBuilder.java src/share/classes/java/lang/CharSequence.java src/share/classes/java/lang/String.java src/share/classes/java/util/ArrayList.java src/share/classes/java/util/Arrays.java src/share/classes/java/util/Collection.java src/share/classes/java/util/Iterables.java src/share/classes/java/util/LinkedHashMap.java src/share/classes/java/util/LinkedHashSet.java src/share/classes/java/util/List.java src/share/classes/java/util/Map.java src/share/classes/java/util/Queue.java src/share/classes/java/util/Set.java src/share/classes/java/util/SortedMap.java src/share/classes/java/util/SortedSet.java src/share/classes/java/util/StringJoiner.java src/share/classes/java/util/Vector.java src/share/classes/java/util/stream/AbstractPipeline.java src/share/classes/java/util/stream/BaseStream.java src/share/classes/java/util/stream/ParallelPipelineHelper.java src/share/classes/java/util/stream/PipelineHelper.java src/share/classes/java/util/stream/ReferencePipeline.java src/share/classes/java/util/stream/Sink.java src/share/classes/java/util/stream/Spliterator.java src/share/classes/java/util/stream/Stream.java src/share/classes/java/util/stream/StreamOpFlags.java src/share/classes/java/util/stream/StreamShape.java src/share/classes/java/util/stream/StreamShapeFactory.java src/share/classes/java/util/stream/Streamable.java src/share/classes/java/util/stream/Streams.java src/share/classes/java/util/stream/TerminalSink.java src/share/classes/java/util/stream/op/AbstractTask.java src/share/classes/java/util/stream/op/CollectorOps.java src/share/classes/java/util/stream/op/ConcatOp.java src/share/classes/java/util/stream/op/CumulateOp.java src/share/classes/java/util/stream/op/FilterOp.java src/share/classes/java/util/stream/op/FindAnyOp.java src/share/classes/java/util/stream/op/FindFirstOp.java src/share/classes/java/util/stream/op/FlagDeclaringOp.java src/share/classes/java/util/stream/op/FlatMapOp.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/GroupByOp.java src/share/classes/java/util/stream/op/IntermediateOp.java src/share/classes/java/util/stream/op/MapOp.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/NodeBuilder.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/ReduceByOp.java src/share/classes/java/util/stream/op/SeedlessFoldOp.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/StatefulOp.java src/share/classes/java/util/stream/op/StreamOp.java src/share/classes/java/util/stream/op/TeeOp.java src/share/classes/java/util/stream/op/TerminalOp.java src/share/classes/java/util/stream/op/ToArrayOp.java src/share/classes/java/util/stream/op/TreeUtils.java src/share/classes/java/util/stream/op/UniqOp.java src/share/classes/java/util/stream/primitive/IntBlock.java src/share/classes/java/util/stream/primitive/IntCollectorOps.java src/share/classes/java/util/stream/primitive/IntFactory.java src/share/classes/java/util/stream/primitive/IntFilterOp.java src/share/classes/java/util/stream/primitive/IntForEachOp.java src/share/classes/java/util/stream/primitive/IntIterable.java src/share/classes/java/util/stream/primitive/IntIterator.java src/share/classes/java/util/stream/primitive/IntLimitOp.java src/share/classes/java/util/stream/primitive/IntMapOp.java src/share/classes/java/util/stream/primitive/IntNode.java src/share/classes/java/util/stream/primitive/IntNodeBuilder.java src/share/classes/java/util/stream/primitive/IntNodes.java src/share/classes/java/util/stream/primitive/IntPipeline.java src/share/classes/java/util/stream/primitive/IntPredicate.java src/share/classes/java/util/stream/primitive/IntSink.java src/share/classes/java/util/stream/primitive/IntSortedOp.java src/share/classes/java/util/stream/primitive/IntSpliterator.java src/share/classes/java/util/stream/primitive/IntStream.java src/share/classes/java/util/stream/primitive/IntSumOp.java src/share/classes/java/util/stream/primitive/IntTeeOp.java src/share/classes/java/util/stream/primitive/IntTerminalSink.java src/share/classes/java/util/stream/primitive/IntToArrayOp.java src/share/classes/java/util/stream/primitive/IntToIntegerOp.java src/share/classes/java/util/stream/primitive/IntTreeUtils.java src/share/classes/java/util/stream/primitive/IntUnaryOperator.java src/share/classes/java/util/stream/primitive/Primitives.java src/share/classes/java/util/stream/primitive/RefToIntMapOp.java src/share/classes/java/util/streams/AbstractPipeline.java src/share/classes/java/util/streams/BaseStream.java src/share/classes/java/util/streams/ParallelPipelineHelper.java src/share/classes/java/util/streams/PipelineHelper.java src/share/classes/java/util/streams/ReferencePipeline.java src/share/classes/java/util/streams/Sink.java src/share/classes/java/util/streams/Spliterator.java src/share/classes/java/util/streams/Stream.java src/share/classes/java/util/streams/StreamOpFlags.java src/share/classes/java/util/streams/StreamShape.java src/share/classes/java/util/streams/StreamShapeFactory.java src/share/classes/java/util/streams/Streamable.java src/share/classes/java/util/streams/Streams.java src/share/classes/java/util/streams/TerminalSink.java src/share/classes/java/util/streams/ops/AbstractTask.java src/share/classes/java/util/streams/ops/CollectorOps.java src/share/classes/java/util/streams/ops/ConcatOp.java src/share/classes/java/util/streams/ops/CumulateOp.java src/share/classes/java/util/streams/ops/FilterOp.java src/share/classes/java/util/streams/ops/FindAnyOp.java src/share/classes/java/util/streams/ops/FindFirstOp.java src/share/classes/java/util/streams/ops/FlagDeclaringOp.java src/share/classes/java/util/streams/ops/FlatMapOp.java src/share/classes/java/util/streams/ops/FoldOp.java src/share/classes/java/util/streams/ops/ForEachOp.java src/share/classes/java/util/streams/ops/GroupByOp.java src/share/classes/java/util/streams/ops/IntermediateOp.java src/share/classes/java/util/streams/ops/MapOp.java src/share/classes/java/util/streams/ops/MatchOp.java src/share/classes/java/util/streams/ops/Node.java src/share/classes/java/util/streams/ops/NodeBuilder.java src/share/classes/java/util/streams/ops/Nodes.java src/share/classes/java/util/streams/ops/OpUtils.java src/share/classes/java/util/streams/ops/ReduceByOp.java src/share/classes/java/util/streams/ops/SeedlessFoldOp.java src/share/classes/java/util/streams/ops/SliceOp.java src/share/classes/java/util/streams/ops/SortedOp.java src/share/classes/java/util/streams/ops/StatefulOp.java src/share/classes/java/util/streams/ops/StreamOp.java src/share/classes/java/util/streams/ops/TeeOp.java src/share/classes/java/util/streams/ops/TerminalOp.java src/share/classes/java/util/streams/ops/ToArrayOp.java src/share/classes/java/util/streams/ops/TreeUtils.java src/share/classes/java/util/streams/ops/UniqOp.java src/share/classes/java/util/streams/primitives/IntBlock.java src/share/classes/java/util/streams/primitives/IntCollectorOps.java src/share/classes/java/util/streams/primitives/IntFactory.java src/share/classes/java/util/streams/primitives/IntFilterOp.java src/share/classes/java/util/streams/primitives/IntForEachOp.java src/share/classes/java/util/streams/primitives/IntIterable.java src/share/classes/java/util/streams/primitives/IntIterator.java src/share/classes/java/util/streams/primitives/IntLimitOp.java src/share/classes/java/util/streams/primitives/IntMapOp.java src/share/classes/java/util/streams/primitives/IntNode.java src/share/classes/java/util/streams/primitives/IntNodeBuilder.java src/share/classes/java/util/streams/primitives/IntNodes.java src/share/classes/java/util/streams/primitives/IntPipeline.java src/share/classes/java/util/streams/primitives/IntPredicate.java src/share/classes/java/util/streams/primitives/IntSink.java src/share/classes/java/util/streams/primitives/IntSortedOp.java src/share/classes/java/util/streams/primitives/IntSpliterator.java src/share/classes/java/util/streams/primitives/IntStream.java src/share/classes/java/util/streams/primitives/IntSumOp.java src/share/classes/java/util/streams/primitives/IntTeeOp.java src/share/classes/java/util/streams/primitives/IntTerminalSink.java src/share/classes/java/util/streams/primitives/IntToArrayOp.java src/share/classes/java/util/streams/primitives/IntToIntegerOp.java src/share/classes/java/util/streams/primitives/IntTreeUtils.java src/share/classes/java/util/streams/primitives/IntUnaryOperator.java src/share/classes/java/util/streams/primitives/Primitives.java src/share/classes/java/util/streams/primitives/RefToIntMapOp.java test-ng/tests/org/openjdk/tests/java/util/FillableStringTest.java test-ng/tests/org/openjdk/tests/java/util/LambdaTestHelpers.java test-ng/tests/org/openjdk/tests/java/util/streams/CollectionModifyStreamTest.java test-ng/tests/org/openjdk/tests/java/util/streams/OpTestCase.java test-ng/tests/org/openjdk/tests/java/util/streams/StreamIntermediateOpTestScenario.java test-ng/tests/org/openjdk/tests/java/util/streams/StreamOpFlagsTest.java test-ng/tests/org/openjdk/tests/java/util/streams/StreamTestData.java test-ng/tests/org/openjdk/tests/java/util/streams/StreamTestDataProvider.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/ConcatOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/CumulateOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/FilterOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/FindAnyOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/FindFirstOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/FlagOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/FlatMapOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/ForEachOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/GroupByOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/InfiniteStreamWithLimitOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/IntNodeTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/MapOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/MatchOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/NodeBuilderTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/NodeTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/PrimitiveOpsTests.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/ReduceByOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/ReduceTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/SliceOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/SortedOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/TeeOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/TestFlagExpectedOp.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/ToArrayOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/UniqOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/UnorderedStreamTest.java test-ng/tests/org/openjdk/tests/java/util/streams/primitives/IntFilterOpTest.java test-ng/tests/org/openjdk/tests/java/util/streams/primitives/IntStreamIntermediateOpTestScenario.java test-ng/tests/org/openjdk/tests/java/util/streams/primitives/IntStreamTestData.java test-ng/tests/org/openjdk/tests/java/util/streams/primitives/IntStreamTestDataProvider.java test-ng/tests/org/openjdk/tests/javac/MethodReferenceTestInstanceMethod.java
diffstat 202 files changed, 11138 insertions(+), 11134 deletions(-) [+]
line wrap: on
line diff
--- a/make/docs/CORE_PKGS.gmk	Thu Nov 15 18:15:00 2012 -0500
+++ b/make/docs/CORE_PKGS.gmk	Thu Nov 15 19:11:58 2012 -0800
@@ -137,9 +137,9 @@
   java.util.prefs                                \
   java.util.regex                                \
   java.util.spi                                  \
-  java.util.streams                              \
-  java.util.streams.ops                          \
-  java.util.streams.prmitives                    \
+  java.util.stream                               \
+  java.util.stream.primitive                     \
+  java.util.stream.op                            \
   java.util.zip                                  \
   javax.accessibility                            \
   javax.activation                               \
--- a/make/java/java/Makefile	Thu Nov 15 18:15:00 2012 -0500
+++ b/make/java/java/Makefile	Thu Nov 15 19:11:58 2012 -0800
@@ -63,7 +63,7 @@
 include FILES_java.gmk
 include Exportedfiles.gmk
 
-AUTO_FILES_JAVA_DIRS = java/util/concurrent java/util/function java/util/streams
+AUTO_FILES_JAVA_DIRS = java/util/concurrent java/util/function java/util/stream
 
 ifeq ($(PLATFORM),windows)
 FILES_java += 	java/io/Win32FileSystem.java \
--- a/makefiles/docs/CORE_PKGS.gmk	Thu Nov 15 18:15:00 2012 -0500
+++ b/makefiles/docs/CORE_PKGS.gmk	Thu Nov 15 19:11:58 2012 -0800
@@ -137,9 +137,9 @@
   java.util.prefs                                \
   java.util.regex                                \
   java.util.spi                                  \
-  java.util.streams                              \
-  java.util.streams.primitives                   \
-  java.util.streams.ops                          \
+  java.util.stream                               \
+  java.util.stream.primitive                     \
+  java.util.stream.op                            \
   java.util.zip                                  \
   javax.accessibility                            \
   javax.activation                               \
--- a/src/share/classes/com/sun/tools/jdi/EventSetImpl.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/com/sun/tools/jdi/EventSetImpl.java	Thu Nov 15 19:11:58 2012 -0800
@@ -30,7 +30,7 @@
 import com.sun.jdi.request.*;
 
 import java.util.*;
-import java.util.streams.Stream;
+import java.util.stream.Stream;
 
 enum EventDestination {UNKNOWN_EVENT, INTERNAL_EVENT, CLIENT_EVENT};
 
--- a/src/share/classes/java/io/BufferedReader.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/io/BufferedReader.java	Thu Nov 15 19:11:58 2012 -0800
@@ -28,9 +28,9 @@
 
 import java.util.Iterator;
 import java.util.NoSuchElementException;
-import java.util.streams.Stream;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * Reads text from a character-input stream, buffering characters so as to
--- a/src/share/classes/java/lang/AbstractStringBuilder.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/lang/AbstractStringBuilder.java	Thu Nov 15 19:11:58 2012 -0800
@@ -28,7 +28,7 @@
 import java.util.StringJoiner;
 import sun.misc.FloatingDecimal;
 import java.util.Arrays;
-import java.util.streams.Stream;
+import java.util.stream.Stream;
 
 /**
  * A mutable sequence of characters.
--- a/src/share/classes/java/lang/CharSequence.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/lang/CharSequence.java	Thu Nov 15 19:11:58 2012 -0800
@@ -29,9 +29,9 @@
 import java.util.NoSuchElementException;
 import java.util.Sized;
 import java.util.function.Block;
-import java.util.streams.Stream;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * A <tt>CharSequence</tt> is a readable sequence of <code>char</code> values. This
--- a/src/share/classes/java/lang/String.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/lang/String.java	Thu Nov 15 19:11:58 2012 -0800
@@ -32,7 +32,7 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
-import java.util.streams.Stream;
+import java.util.stream.Stream;
 
 /**
  * The {@code String} class represents character strings. All
--- a/src/share/classes/java/util/ArrayList.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/ArrayList.java	Thu Nov 15 19:11:58 2012 -0800
@@ -25,9 +25,9 @@
 
 package java.util;
 
-import java.util.streams.Stream;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * Resizable-array implementation of the <tt>List</tt> interface.  Implements
--- a/src/share/classes/java/util/Arrays.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/Arrays.java	Thu Nov 15 19:11:58 2012 -0800
@@ -27,7 +27,7 @@
 
 import java.lang.reflect.*;
 import java.util.logging.Logger;
-import java.util.streams.*;
+import java.util.stream.*;
 
 /**
  * This class contains various methods for manipulating arrays (such as
--- a/src/share/classes/java/util/Collection.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/Collection.java	Thu Nov 15 19:11:58 2012 -0800
@@ -26,10 +26,10 @@
 package java.util;
 
 import java.util.function.Predicate;
-import java.util.streams.Stream;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streamable;
-import java.util.streams.Streams;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streamable;
+import java.util.stream.Streams;
 
 /**
  * The root interface in the <i>collection hierarchy</i>.  A collection
--- a/src/share/classes/java/util/Iterables.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/Iterables.java	Thu Nov 15 19:11:58 2012 -0800
@@ -24,7 +24,7 @@
  */
 package java.util;
 
-import java.util.streams.ops.FilterOp;
+import java.util.stream.op.FilterOp;
 
 /**
  * Utility methods for {@linkplain Iterable}.
--- a/src/share/classes/java/util/LinkedHashMap.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/LinkedHashMap.java	Thu Nov 15 19:11:58 2012 -0800
@@ -24,8 +24,8 @@
  */
 
 package java.util;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * <p>Hash table and linked list implementation of the <tt>Map</tt> interface,
--- a/src/share/classes/java/util/LinkedHashSet.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/LinkedHashSet.java	Thu Nov 15 19:11:58 2012 -0800
@@ -25,9 +25,9 @@
 
 package java.util;
 
-import java.util.streams.Stream;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * <p>Hash table and linked list implementation of the <tt>Set</tt> interface,
--- a/src/share/classes/java/util/List.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/List.java	Thu Nov 15 19:11:58 2012 -0800
@@ -25,9 +25,9 @@
 
 package java.util;
 
-import java.util.streams.Stream;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * An ordered collection (also known as a <i>sequence</i>).  The user of this
--- a/src/share/classes/java/util/Map.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/Map.java	Thu Nov 15 19:11:58 2012 -0800
@@ -26,8 +26,8 @@
 package java.util;
 
 import java.util.function.BiBlock;
-import java.util.streams.Streamable;
-import java.util.streams.Streams;
+import java.util.stream.Streamable;
+import java.util.stream.Streams;
 
 /**
  * An object that maps keys to values.  A map cannot contain duplicate keys;
--- a/src/share/classes/java/util/Queue.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/Queue.java	Thu Nov 15 19:11:58 2012 -0800
@@ -35,9 +35,9 @@
 
 package java.util;
 
-import java.util.streams.Stream;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * A collection designed for holding elements prior to processing.
--- a/src/share/classes/java/util/Set.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/Set.java	Thu Nov 15 19:11:58 2012 -0800
@@ -25,9 +25,9 @@
 
 package java.util;
 
-import java.util.streams.Stream;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * A collection that contains no duplicate elements.  More formally, sets
--- a/src/share/classes/java/util/SortedMap.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/SortedMap.java	Thu Nov 15 19:11:58 2012 -0800
@@ -25,8 +25,8 @@
 
 package java.util;
 
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * A {@link Map} that further provides a <em>total ordering</em> on its keys.
--- a/src/share/classes/java/util/SortedSet.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/SortedSet.java	Thu Nov 15 19:11:58 2012 -0800
@@ -25,9 +25,9 @@
 
 package java.util;
 
-import java.util.streams.Stream;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * A {@link Set} that further provides a <i>total ordering</i> on its elements.
--- a/src/share/classes/java/util/StringJoiner.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/StringJoiner.java	Thu Nov 15 19:11:58 2012 -0800
@@ -24,7 +24,7 @@
  */
 package java.util;
 
-import java.util.streams.Stream;
+import java.util.stream.Stream;
 
 /**
  * StringJoiner is used to construct a sequence of characters separated
--- a/src/share/classes/java/util/Vector.java	Thu Nov 15 18:15:00 2012 -0500
+++ b/src/share/classes/java/util/Vector.java	Thu Nov 15 19:11:58 2012 -0800
@@ -25,9 +25,9 @@
 
 package java.util;
 
-import java.util.streams.Stream;
-import java.util.streams.StreamOpFlags;
-import java.util.streams.Streams;
+import java.util.stream.Stream;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.Streams;
 
 /**
  * The {@code Vector} class implements a growable array of
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/AbstractPipeline.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,590 @@
+/*
+ * 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.concurrent.ForkJoinTask;
+import java.util.concurrent.ForkJoinUtils;
+import java.util.stream.op.*;
+
+/**
+ * AbstractPipeline
+ * <p>
+ * Evaluation works in two modes:
+ * <ol>
+ * <li>Sequential; and</li>
+ * <li>Parallel.</li>
+ * </ol>
+ * </p>
+ * <p>
+ * Sequential evaluation is performed when the {@link StreamOpFlags#PARALLEL} flag is not set on the stream source
+ * flags or when it is not possible to obtain a {@link Spliterator} and split because some part of the pipeline has
+ * already been pulled due to a call to {@link #iterator()}.
+ * </p>
+ * <p>
+ * Parallel evaluation slices up the pipeline into a list of intermediate slices and a terminal slice.
+ * An intermediate slice consists of zero or more stateless intermediate operations and then
+ * one stateful intermediate operation at the end.
+ * The terminal slice consists of zero or more stateless intermediate operations and then
+ * one terminal operation at the end. The terminal operation is responsible for producing a result.
+ * </p>
+ * <p>
+ * Each intermediate slice is evaluated, in order, and in parallel to produce an intermediate list of elements
+ * that is held by a {@link Node}.
+ * That Node is converted to a {@link Spliterator} which becomes the source (or input) into the next intermediate
+ * or terminal slice.
+ * The process repeats until the terminal slice is processed to produce a result.
+ * </p>
+ * <p>
+ * If an intermediate result is produced and the combined stream and operation flags output with that result
+ * clears the {@link StreamOpFlags#PARALLEL} flag then all the remaining operations in the pipeline
+ * (the next operation after the stateful operation in the slice and up to and including the terminal operation)
+ * are evaluated sequentially to produce a result.
+ * </p>
+ * <p>
+ * Combined stream and operation flags are calculated for each slice of the pipeline. When a {@link Spliterator} for
+ * a {@link Node} is created the resultant source and operation flags produced from the intermediate stateful operation
+ * are utilized to create the source flags for that {@link Spliterator}.
+ * This ensures stream properties are preserved and propagated for the next intermediate or terminal evaluation.
+ * In addition the {@link StreamOpFlags#SIZED} flag will be explicitly set, since the {@link Node} knows it's size.
+ * </p>
+ *
+ * @param <E_IN>  Type of input elements.
+ * @param <E_OUT> Type of output elements.
+ * @author Brian Goetz
+ */
+public abstract class AbstractPipeline<E_IN, E_OUT> implements BaseStream<E_OUT> {
+    protected final AbstractPipeline<?, E_IN> upstream;
+    protected final IntermediateOp<E_IN, E_OUT> op;
+    protected final int depth;
+
+    // Head state of pipeline
+    protected final Spliterator<?> spliterator;
+    protected final int sourceFlags;
+    protected final StreamShape shape;
+
+    /**
+     * If non-{@code null} then we are in sequential iteration mode.
+     */
+    protected Iterator<E_OUT> iterator;
+
+    /**
+     * Constructor for the element source of a pipeline.
+     *
+     * @param spliterator a Spliterator describing the input elements
+     * @param sourceFlags the source flags associated with the spliterator
+     * @param shape the shape of the source
+     */
+    protected AbstractPipeline(Spliterator<?> spliterator, int sourceFlags, StreamShape shape) {
+        this.upstream = null;
+        this.op = null;
+        this.depth = 0;
+
+        this.spliterator = Objects.requireNonNull(spliterator);
+        this.sourceFlags = sourceFlags;
+        this.shape = shape;
+    }
+
+    /**
+     * Constructor for a pipeline operation.
+     *
+     * @param upstream the upstream element source.
+     * @param op the operation performed upon elements.
+     */
+    protected AbstractPipeline(AbstractPipeline<?, E_IN> upstream, IntermediateOp<E_IN, E_OUT> op) {
+        this.upstream = Objects.requireNonNull(upstream);
+        this.op = Objects.requireNonNull(op);
+        this.depth = upstream.depth + 1;
+
+        this.spliterator = upstream.spliterator;
+        this.sourceFlags = upstream.sourceFlags;
+        this.shape = upstream.shape;
+
+        assert upstream.getOutputShape().getStreamType() == op.inputShape().getStreamType();
+        assert (upstream.depth == 0) ^ (upstream.op != null);
+    }
+
+    protected<R> R evaluate(TerminalOp<E_OUT, R> terminal) {
+        if (StreamOpFlags.PARALLEL.isKnown(sourceFlags)) {
+            return evaluateParallel(terminal);
+        }
+        else
+            return evaluateSequential(terminal, sourceFlags);
+    }
+
+    protected<R> R evaluateParallel(TerminalOp<E_OUT, R> terminal) {
+        if (isPipelinePulled()) {
+            // If already pulled then cannot split, revert back to sequential evaluation
+            // Ensure the parallel flag is cleared
+            return evaluateSequential(terminal, StreamOpFlags.PARALLEL.clearFromFlags(sourceFlags));
+        }
+
+        final IntermediateOp[] ops = ops();
+        // Ops flags length is one greater than op array to hold initial value
+        // Given an op whose index is i then the flags input to that op are at flags[i]
+        // and the flags output from that op are at flags[i + 1]
+        final int[] opsFlags = new int[ops.length + 1];
+        int fromOp = 0;
+        int upToOp = 0;
+        Node<?> iNode = null;
+        Spliterator<?> iSource = spliterator;
+        int iSourceFlags = sourceFlags;
+        while (true) {
+            while (upToOp < ops.length && !ops[upToOp].isStateful())
+                upToOp++;
+
+            if (upToOp < ops.length) {
+                IntermediateOp<?, ?> statefulOp = ops[upToOp];
+                iNode = evaluateParallel(iNode, iSource, iSourceFlags, opsFlags, ops, fromOp, upToOp, statefulOp);
+
+                // Get the combined stream and ops flags for the stateful op
+                int sourceAndOpsFlags = StreamOpFlags.combineStreamFlags(
+                        iSourceFlags,
+                        StreamOpFlags.combineOpFlags(statefulOp.getOpFlags(), opsFlags[upToOp]));
+                // Get the source flags for the intermediate stream
+                iSourceFlags = StreamOpFlags.flagsToStreamFlags(sourceAndOpsFlags)
+                               | StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED;
+                // Create stream accessor from node using the stream flags
+                iSource = iNode.spliterator();
+
+                fromOp = ++upToOp;
+
+                if (!StreamOpFlags.PARALLEL.isKnown(iSourceFlags)) {
+                    return evaluateSequential(iNode, iSource, iSourceFlags, opsFlags, ops, fromOp, ops.length, terminal);
+                }
+            }
+            else {
+                return evaluateParallel(iNode, iSource, iSourceFlags, opsFlags, ops, fromOp, upToOp, terminal);
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private <R> R evaluateParallel(Node<?> node,
+                                   Spliterator<?> spliterator,
+                                   int sourceFlags,
+                                   int[] opsFlags,
+                                   IntermediateOp[] ops, int from, int upTo,
+                                   StreamOp<?, R> terminal) {
+        return (R) terminal.evaluateParallel(new ParallelImplPipelineHelper(node, spliterator, sourceFlags,
+                                                                            opsFlags, ops, from, upTo,
+                                                                            terminal.inputShape()));
+    }
+
+    @SuppressWarnings("unchecked")
+    private <R> R evaluateSequential(Node<?> node,
+                                     Spliterator<?> spliterator,
+                                     int sourceFlags,
+                                     int[] opsFlags,
+                                     IntermediateOp[] ops, int from, int upTo,
+                                     TerminalOp<E_OUT, R> terminal) {
+        return (R) terminal.evaluateSequential(new SequentialImplPipelineHelper(node, spliterator, sourceFlags,
+                                                                                opsFlags, ops, from, upTo,
+                                                                                terminal.inputShape()));
+    }
+
+    @SuppressWarnings("unchecked")
+    protected <R> R evaluateSequential(TerminalOp<E_OUT, R> terminal, int sourceFlags) {
+        return (R) terminal.evaluateSequential(new SequentialImplPipelineHelperSource(sourceFlags, terminal.inputShape()));
+    }
+
+    static abstract class AbstractPipelineHelper<P_IN, P_OUT> implements PipelineHelper<P_IN, P_OUT> {
+        final Node<P_IN> node;
+        final Spliterator<P_IN> spliterator;
+        final IntermediateOp[] ops;
+        final int[] opsFlags;
+        final int from;
+        final int upTo;
+        final int sourceFlags;
+        final int sourceAndOpsFlags;
+        final StreamShape terminalShape;
+
+        AbstractPipelineHelper(Spliterator<P_IN> spliterator, int sourceFlags,
+                               int[] opsFlags, IntermediateOp[] ops, int from, int upTo,
+                               StreamShape terminalShape) {
+            this(null, spliterator, sourceFlags, opsFlags, ops, from, upTo, terminalShape);
+        }
+
+        AbstractPipelineHelper(Node<P_IN> node, Spliterator<P_IN> spliterator, int sourceFlags,
+                               int[] opsFlags, IntermediateOp[] ops, int from, int upTo,
+                               StreamShape terminalShape) {
+            this.node = node;
+            this.spliterator = spliterator;
+            this.opsFlags = opsFlags;
+            this.ops = ops;
+            this.from = from;
+            this.upTo = upTo;
+            this.sourceFlags = sourceFlags;
+            this.terminalShape = terminalShape;
+
+            int flags = opsFlags[from] = StreamOpFlags.INITIAL_OPS_VALUE;
+            for (int i = from; i < upTo; i++) {
+                flags = opsFlags[i + 1] = StreamOpFlags.combineOpFlags(ops[i].getOpFlags(), flags);
+            }
+
+            this.sourceAndOpsFlags = StreamOpFlags.combineStreamFlags(sourceFlags, flags);
+        }
+
+        protected boolean isOutputSizeKnown() {
+            return StreamOpFlags.SIZED.isKnown(sourceAndOpsFlags);
+        }
+
+        protected boolean isShortCircuit() {
+            return StreamOpFlags.SHORT_CIRCUIT.isKnown(sourceAndOpsFlags);
+        }
+
+        protected boolean hasZeroDepth() {
+            return upTo == from;
+        }
+
+        protected NodeBuilder<P_OUT> makeNodeBuilder() {
+            // @@@ Unchecked
+            return terminalShape.makeNodeBuilder(getOutputSizeIfKnown());
+        }
+
+        @Override
+        public <S extends Sink<P_OUT>> S into(S sink) {
+            Sink<P_IN> wrappedSink = wrapSink(sink);
+            wrappedSink.begin(spliterator.getSizeIfKnown());
+            spliterator.forEach(wrappedSink);
+            wrappedSink.end();
+            return sink;
+        }
+
+        @Override
+        public int getStreamFlags() {
+            return sourceAndOpsFlags;
+        }
+
+        @Override
+        public int getOutputSizeIfKnown() {
+            return isOutputSizeKnown() ? spliterator.getSizeIfKnown() : -1;
+        }
+
+        @Override
+        public Sink<P_IN> wrapSink(Sink sink) {
+            Objects.requireNonNull(sink);
+
+            for (int i = upTo - 1; i >= from; i--) {
+                sink = ops[i].wrapSink(
+                        StreamOpFlags.combineStreamFlags(sourceFlags, opsFlags[i]),
+                        sink);
+            }
+            return sink;
+        }
+
+        @Override
+        public Iterator<P_OUT> wrapIterator(Iterator it) {
+            Objects.requireNonNull(it);
+
+            for (int i = from; i < upTo; i++) {
+                it = ops[i].wrapIterator(
+                        StreamOpFlags.combineStreamFlags(sourceFlags, opsFlags[i]),
+                        it);
+            }
+            return it;
+        }
+    }
+
+    class SequentialImplPipelineHelper<P_IN> extends AbstractPipelineHelper<P_IN, E_OUT> {
+
+        SequentialImplPipelineHelper(Spliterator<P_IN> spliterator, int sourceFlags,
+                                     IntermediateOp[] ops,
+                                     StreamShape terminalShape) {
+            // Start from 2nd element since 1st is the head containing the source
+            super(spliterator, sourceFlags, new int[ops.length + 1], ops, 0, ops.length, terminalShape);
+        }
+
+        SequentialImplPipelineHelper(Node<P_IN> node, Spliterator<P_IN> spliterator, int sourceFlags,
+                                     int[] opsFlags, IntermediateOp[] ops, int from, int to,
+                                     StreamShape terminalShape) {
+            super(node, spliterator, sourceFlags, opsFlags, ops, from, to, terminalShape);
+        }
+
+        boolean requirePull() {
+            return isShortCircuit();
+        }
+
+        @Override
+        public<S extends Sink<E_OUT>> S into(S sink) {
+            Objects.requireNonNull(sink);
+
+            if (requirePull()) {
+                sink.begin(-1);
+                iterator().forEach(sink);
+                sink.end();
+            }  else {
+                super.into(sink);
+            }
+
+            return sink;
+        }
+
+        @Override
+        public Node<E_OUT> collectOutput() {
+            if (hasZeroDepth() && node != null) {
+                // @@@ Unchecked
+                return (Node<E_OUT>) node;
+            }
+            else {
+                return into(makeNodeBuilder()).build();
+            }
+        }
+
+        @Override
+        public Iterator<E_OUT> iterator() {
+            return wrapIterator(spliterator.iterator());
+        }
+    }
+
+    class SequentialImplPipelineHelperSource extends SequentialImplPipelineHelper {
+
+        <R> SequentialImplPipelineHelperSource(int sourceFlags, StreamShape terminalShape) {
+            super(AbstractPipeline.this.spliterator, sourceFlags, ops(), terminalShape);
+        }
+
+        @Override
+        boolean requirePull() {
+            return isPipelinePulled() ? true : super.requirePull();
+        }
+
+        @Override
+        public int getOutputSizeIfKnown() {
+            return isPipelinePulled() ? -1 : super.getOutputSizeIfKnown();
+        }
+
+        @Override
+        public Iterator<E_OUT> iterator() {
+            return AbstractPipeline.this.iterator();
+        }
+    }
+
+    class ParallelImplPipelineHelper<P_IN> extends AbstractPipelineHelper<P_IN, E_OUT>
+            implements ParallelPipelineHelper<P_IN, E_OUT> {
+        final long targetSize;
+
+        ParallelImplPipelineHelper(Node<P_IN> node, Spliterator<P_IN> spliterator, int sourceFlags,
+                                   int[] opsFlags, IntermediateOp[] ops, int from, int to,
+                                   StreamShape terminalShape) {
+            super(node, spliterator, sourceFlags, opsFlags, ops, from, to, terminalShape);
+            this.targetSize = calculateTargetSize();
+        }
+
+        private long calculateTargetSize() {
+            int estimate = spliterator.estimateSize();
+            return estimate >= 0
+                   ? ForkJoinUtils.suggestTargetSize(estimate)
+                   : 2; // @@@ SWAG
+        }
+
+        //
+
+        @Override
+        public long suggestTargetSize() {
+            return targetSize;
+        }
+
+        @Override
+        public boolean suggestSplit(Spliterator<P_IN> spliterator) {
+            int remaining = spliterator.estimateSize();
+            return (remaining > targetSize || remaining < 0) && spliterator.getNaturalSplits() > 0;
+        }
+
+        @Override
+        public <FJ_R> FJ_R invoke(ForkJoinTask<FJ_R> task) {
+            return task.invoke();
+        }
+
+        @Override
+        public Iterator<E_OUT> iterator() {
+            return wrapIterator(spliterator.iterator());
+        }
+
+        @Override
+        public Spliterator<P_IN> spliterator() {
+            return spliterator;
+        }
+
+        @Override
+        public Node<E_OUT> collectOutput() {
+            if (hasZeroDepth() && node != null) {
+                // @@@ Unchecked
+                return (Node<E_OUT>) node;
+            }
+            else {
+                // @@@ Unchecked
+                return terminalShape.collect(this, false);
+            }
+        }
+    }
+
+    private IntermediateOp[] ops() {
+        IntermediateOp[] ops = new IntermediateOp[depth];
+        AbstractPipeline p = this;
+        for (int i = depth - 1; i >= 0; i--) {
+            ops[i] = p.op;
+            p = p.upstream;
+        }
+        return ops;
+    }
+
+    private boolean isPipelinePulled() {
+        if (iterator != null)
+            return true;
+
+        AbstractPipeline p = this.upstream;
+        while (p != null) {
+            if (p.iterator != null) {
+                // @@@ Should iterator() be called to aggressively update this and all upstream non-null iterators?
+                return true;
+            }
+            p = p.upstream;
+        }
+
+        return false;
+    }
+
+    // Chaining and result methods
+
+    /**
+     * Chain an operation to the tail of this pipeline to create a new pipeline.
+     *
+     * @param op the operation to chain.
+     * @param <E_NEXT> the type of elements output from the new pipeline.
+     * @return the new pipeline.
+     */
+    public <E_NEXT> AbstractPipeline<E_OUT, E_NEXT> chain(IntermediateOp<E_OUT, E_NEXT> op) {
+        return op.outputShape().chain(this, op);
+    }
+
+    /**
+     * Chain an operation to the tail of this pipeline to create a new stream.
+     *
+     * @param op the operation to chain.
+     * @param <E_NEXT> the type of elements output from the new stream.
+     * @param <S> the type of stream.
+     * @return the new stream.
+     */
+    @SuppressWarnings("unchecked")
+    public <E_NEXT, S extends BaseStream<E_NEXT>> S pipeline(IntermediateOp<E_OUT, E_NEXT> op) {
+        return (S) chain(op);
+    }
+
+    /**
+     * Evaluate the pipeline with a terminal operation to produce a result.
+     *
+     * @param terminal the terminal operation to be applied to the pipeline.
+     * @param <R> the type of result.
+     * @return the result.
+     */
+    public <R> R pipeline(TerminalOp<E_OUT, R> terminal) {
+        assert getOutputShape().getStreamType() == terminal.inputShape().getStreamType();
+        return evaluate(terminal);
+    }
+
+    /**
+     * Collect the elements output from the pipeline.
+     *
+     * @return a node that holds the collected output elements.
+     */
+    public Node<E_OUT> collectOutput() {
+        // @@@ Generalize CollectorOps for shape when primitive support is in place
+        TerminalOp<E_OUT, Node<E_OUT>> collect = new TerminalOp<E_OUT, Node<E_OUT>>() {
+            @Override
+            public StreamShape inputShape() {
+                return getOutputShape();
+            }
+
+            @Override
+            public <P_IN> Node<E_OUT> evaluateParallel(ParallelPipelineHelper<P_IN, E_OUT> helper) {
+                return helper.collectOutput();
+            }
+
+            @Override
+            public <P_IN> Node<E_OUT> evaluateSequential(PipelineHelper<P_IN, E_OUT> helper) {
+                return helper.collectOutput();
+            }
+        };
+        return evaluate(collect);
+    }
+
+    /**
+     * Get the output shape of the pipeline.
+     *
+     * @return the output shape. If the pipeline is the head then it's output shape corresponds to the shape of the
+     * source. Otherwise, it's output shape corresponds to the output shape of the associated operation.
+     */
+    public StreamShape getOutputShape() {
+        return op == null ? shape : op.outputShape();
+    }
+
+    /**
+     * Get the input shape of the pipeline.
+     *
+     * @return the input shape. If the pipeline is the head then it's input shape corresponds to the shape of the
+     * source. Otherwise, it's input shape corresponds to the input shape of the associated operation.
+     */
+    public StreamShape getInputShape() {
+        return op == null ? shape : op.inputShape();
+    }
+
+    // BaseStream
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Iterator<E_OUT> iterator() {
+        if (iterator == null) {
+            AbstractPipeline[] pipes = new AbstractPipeline[depth + 1];
+            AbstractPipeline p = this;
+            for (int i = depth; i >= 0; i--) {
+                pipes[i] = p;
+                p = p.upstream;
+            }
+
+            // Check if this is the first pull and if so get the source iterator
+            if (pipes[0].iterator == null) {
+                pipes[0].iterator = spliterator.iterator();
+            }
+
+            // Ensure the parallel flag is cleared, if set
+            int sourceFlags = StreamOpFlags.PARALLEL.clearFromFlags(this.sourceFlags);
+            int opsFlags = StreamOpFlags.INITIAL_OPS_VALUE;
+            for (int i = 1; i <= depth; i++) {
+                p = pipes[i];
+                if (p.iterator == null) {
+                    p.iterator = p.op.wrapIterator(StreamOpFlags.combineStreamFlags(sourceFlags, opsFlags),
+                                                   pipes[i - 1].iterator);
+                }
+                opsFlags = StreamOpFlags.combineOpFlags(pipes[i].op.getOpFlags(), opsFlags);
+            }
+        }
+        return iterator;
+    }
+
+    @Override
+    public boolean isParallel() {
+        return StreamOpFlags.PARALLEL.isKnown(sourceFlags);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/BaseStream.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,53 @@
+/*
+ * 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;
+
+/**
+ * BaseStream
+ *
+ * @param <T> Type of stream elements.
+ *
+ * @author Brian Goetz
+ */
+public interface BaseStream<T> {
+    /**
+     * Return the iterator for the elements of this stream. The same iterator
+     * instance is returned for every invocation.  Once the elements of the
+     * stream are consumed it is not possible to "rewind" the stream.
+     *
+     * @return the element iterator for this stream.
+     */
+    Iterator<T> iterator();
+
+    /**
+     * Returns {@code true} if this stream may be split for parallel
+     * processing.
+     *
+     * @return {@code true} if this stream may be split for parallel processing.
+     */
+    boolean isParallel();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/ParallelPipelineHelper.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,73 @@
+/*
+ * 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.concurrent.ForkJoinTask;
+import java.util.stream.op.NodeBuilder;
+import java.util.stream.op.OpUtils;
+
+/**
+ *
+ * @param <P_IN> Type of elements input to the pipeline.
+ * @param <P_OUT> Type of elements output from the pipeline.
+ */
+public interface ParallelPipelineHelper<P_IN, P_OUT> extends PipelineHelper<P_IN, P_OUT> {
+
+    /**
+     * Get the sub-size of the input at which to suggest sequential evaluation rather than parallel evaluation.
+     *
+     * @return the target size.
+     */
+    long suggestTargetSize();
+
+    /**
+     * Suggest if a spliterator should be split further or not.
+     *
+     * <p>Information such as the target size (see {@link #suggestTargetSize()} and size of the
+     * spliterator are factors that are utilized to evaluate whether further splitting is
+     * suggested.</p>
+     *
+     * @param spliterator the spliterator to be split or not.
+     * @return return true if the spliterator should be split further, otherwise false.
+     */
+    boolean suggestSplit(Spliterator<P_IN> spliterator);
+
+    /**
+     * Get the spliterator for the stream accessor that inputs elements to the pipeline.
+     *
+     * @return the spliterator.
+     */
+    Spliterator<P_IN> spliterator();
+
+    /**
+     * Invoke a task in parallel using fork/join.
+     *
+     * @param task the fork/join task.
+     * @param <FJ_R> type of fork/join result
+     * @return the fork/join result
+     */
+    <FJ_R> FJ_R invoke(ForkJoinTask<FJ_R> task);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/PipelineHelper.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,87 @@
+/*
+ * 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.stream.op.Node;
+
+/**
+ * @param <P_IN>  Type of elements input to the pipeline.
+ * @param <P_OUT> Type of elements output from the pipeline.
+ */
+public interface PipelineHelper<P_IN, P_OUT> {
+
+    /**
+     * @return the combined stream and operation flags.
+     * @see {@link StreamOpFlags}
+     */
+    int getStreamFlags();
+
+    /**
+     * Get the size of the stream output from the pipeline if known.
+     *
+     * @return the size of the output stream, otherwise {@code -1} if the size is unknown.
+     */
+    int getOutputSizeIfKnown();
+
+    /**
+     * Wrap a sink (see {@link #wrapSink(Sink)} that corresponds to the sink that
+     * accepts elements output from the pipeline, then push all elements obtained
+     * from the stream accessor into that wrapped sink.
+     *
+     * @param sink the sink in which to wrap.
+     */
+    <S extends Sink<P_OUT>> S into(S sink);
+
+    /**
+     * Create a sink chain.
+     *
+     * @param sink the last sink in the chain that accepts output elements.
+     * @return the first sink in the chain that accepts input elements.
+     */
+    Sink<P_IN> wrapSink(Sink<P_OUT> sink);
+
+    /**
+     * Create an iterator chain.
+     *
+     * @param source the first iterator in the chain that iterates over input elements.
+     * @return the last iterator in the chain that iterates over output elements.
+     */
+    Iterator<P_OUT> wrapIterator(Iterator<P_IN> source);
+
+    /**
+     * Create an iterator chain, starting with the stream source, and wrapping with each stage
+     *
+     * @return the last iterator in the chain.
+     */
+    Iterator<P_OUT> iterator();
+
+    /**
+     * Collect all output elements.
+     *
+     * @return the node containing all output elements.
+     */
+    Node<P_OUT> collectOutput();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/ReferencePipeline.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,199 @@
+/*
+ * 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.function.IntMapper;
+import java.util.function.FlatMapper;
+import java.util.function.Predicate;
+import java.util.function.Factory;
+import java.util.function.Mapper;
+import java.util.function.Block;
+import java.util.function.BinaryOperator;
+import java.util.function.Combiner;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.op.*;
+import java.util.stream.primitive.RefToIntMapOp;
+import java.util.stream.primitive.IntStream;
+
+/**
+ * A pipeline of elements that are references to objects of type <code>T</code>.
+ *
+ * @param <T> Type of elements in the upstream source.
+ * @param <U> Type of elements in produced by this stage.
+ *
+ * @author Brian Goetz
+ */
+public class ReferencePipeline<T, U> extends AbstractPipeline<T, U> implements Stream<U>  {
+
+    public<S> ReferencePipeline(Spliterator<S> spliterator, int sourceFlags) {
+        super(spliterator, sourceFlags, StreamShapeFactory.REFERENCE);
+    }
+
+    public ReferencePipeline(AbstractPipeline<?, T> upstream, IntermediateOp<T, U> op) {
+        super(upstream, op);
+    }
+
+    @Override
+    public Stream<U> filter(Predicate<? super U> predicate) {
+        return pipeline(new FilterOp<>(predicate));
+    }
+
+    @Override
+    public <R> Stream<R> map(Mapper<? extends R, ? super U> mapper) {
+        return pipeline(new MapOp<>(mapper));
+    }
+
+    @Override
+    public IntStream map(IntMapper<? super U> mapper) {
+        return pipeline(new RefToIntMapOp<U>(mapper));
+    }
+
+    @Override
+    public <R> Stream<R> flatMap(FlatMapper<? extends R, ? super U> mapper) {
+        return pipeline(new FlatMapOp<>(mapper));
+    }
+
+    @Override
+    public Stream<U> uniqueElements() {
+        return pipeline(UniqOp.<U>singleton());
+    }
+
+    @Override
+    public Stream<U> sorted(Comparator<? super U> comparator) {
+        return pipeline(new SortedOp<>(comparator));
+    }
+
+    @Override
+    public Stream<U> cumulate(BinaryOperator<U> operator) {
+        return pipeline(new CumulateOp<>(operator));
+    }
+
+    @Override
+    public void forEach(Block<? super U> block) {
+        pipeline(ForEachOp.make(block));
+    }
+
+    @Override
+    public Stream<U> tee(Block<? super U> block) {
+        return pipeline(new TeeOp<>(block));
+    }
+
+    @Override
+    public Stream<U> limit(int limit) {
+        return pipeline(new SliceOp<U>(0, limit));
+    }
+
+    @Override
+    public Stream<U> skip(int toSkip) {
+        return pipeline(new SliceOp<U>(toSkip));
+    }
+
+    @Override
+    public Stream<U> slice(int skip, int limit) {
+        return pipeline(new SliceOp<U>(skip, limit));
+    }
+
+    @Override
+    public Stream<U> concat(Stream<? extends U> other) {
+        return pipeline(new ConcatOp<>(other));
+    }
+
+    @Override
+    public <A extends Destination<? super U>> A into(A target) {
+        target.addAll(this);
+        return target;
+    }
+
+    @Override
+    public <K> Map<K,Collection<U>> groupBy(Mapper<? extends K, ? super U> classifier) {
+        return pipeline(new GroupByOp<>(classifier));
+    }
+
+    @Override
+    public <K, W> Map<K, W> reduceBy(Mapper<? extends K, ? super U> classifier,
+                                     Factory<W> baseFactory,
+                                     Combiner<W, W, U> reducer,
+                                     BinaryOperator<W> combiner) {
+        return pipeline(new ReduceByOp<>(classifier, baseFactory, reducer, combiner));
+    }
+
+    @Override
+    public Object[] toArray() {
+        return pipeline(ToArrayOp.<U>singleton());
+    }
+
+    @Override
+    public boolean anyMatch(Predicate<? super U> predicate) {
+        return pipeline(MatchOp.make(predicate, MatchOp.MatchKind.ANY));
+    }
+
+    @Override
+    public boolean allMatch(Predicate<? super U> predicate) {
+        return pipeline(MatchOp.make(predicate, MatchOp.MatchKind.ALL));
+    }
+
+    @Override
+    public boolean noneMatch(Predicate<? super U> predicate) {
+        return pipeline(MatchOp.make(predicate, MatchOp.MatchKind.NONE));
+    }
+
+    @Override
+    public Optional<U> findFirst() {
+        return pipeline(FindFirstOp.<U>singleton());
+    }
+
+    @Override
+    public Optional<U> findAny() {
+        return pipeline(FindAnyOp.<U>singleton());
+    }
+
+    @Override
+    public Stream<U> sequential() {
+        return pipeline(CollectorOps.<U>sequentialCollector());
+    }
+
+    @Override
+    public Stream<U> unordered() {
+        return pipeline(new FlagDeclaringOp<U>(StreamOpFlags.NOT_ORDERED));
+    }
+
+    @Override
+    public U reduce(final U seed, final BinaryOperator<U> op) {
+        return pipeline(new FoldOp<>(seed, op, op));
+    }
+
+    @Override
+    public Optional<U> reduce(BinaryOperator<U> op) {
+        return pipeline(new SeedlessFoldOp<>(op));
+    }
+
+    @Override
+    public <V> V fold(Factory<V> baseFactory, Combiner<V, V, U> reducer, BinaryOperator<V> combiner) {
+        return pipeline(new FoldOp<>(baseFactory, reducer, combiner));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/Sink.java	Thu Nov 15 19:11:58 2012 -0800
@@ -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;
+
+import java.util.Objects;
+import java.util.function.BiBlock;
+import java.util.function.Block;
+import java.util.logging.Logger;
+
+/**
+ * Sink
+ *
+ * @param <T> Type of elements for value streams.
+ *
+ * @author Brian Goetz
+ */
+public interface Sink<T> extends Block<T> {
+    /**
+     * Reset the sink state to receive a fresh data set. This is used when a
+     * Sink is being reused by multiple calculations.
+     * @param size The exact size of the data to be pushed downstream, if
+     * known or {@code -1} if unknown or infinite.
+     */
+    void begin(int size);
+
+    /**
+     * Indicate that all elements have been pushed. Chained sinks should dump
+     * their contents downstream and clear any stored state.
+     */
+    default void end() {}
+
+    public interface OfValue<T> extends Sink<T> {
+        @Override
+        default void begin(int size) {}
+    }
+
+    public static abstract class ChainedValue<T> implements OfValue<T> {
+        protected final Sink downstream;
+
+        public ChainedValue(Sink downstream) {
+            this.downstream = Objects.requireNonNull(downstream);
+        }
+
+        @Override
+        public void begin(int size) {
+            downstream.begin(size);
+        }
+
+        @Override
+        public void end() {
+            downstream.end();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/Spliterator.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,150 @@
+/*
+ * 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.function.Block;
+
+/**
+ * Provides the ability to decompose an aggregate data structure and to iterate
+ * over the elements the elements of the aggregate.
+ * <p/>
+ * Use of a Spliterator has two phases; splitting and traversal. The splitting
+ * phase divides the elements of the data structures so that they may be
+ * processed concurrently. The split phase is intended to be repeated
+ * recursively until the number of elements per split reaches a threshold where
+ * further splitting would only generate additional cost.
+ * <p/>
+ * The traversal phase applies operations upon the elements of a single split.
+ * <p/>
+ * @author Brian Goetz
+ * @author Doug Lea
+ */
+public interface Spliterator<T> {
+
+    /**
+     * Return the number of calls to {@code split()} that will naturally divide
+     * the data structure. Each of the splits may suggest additional splitting.
+     * <p/>
+     * @return The number of splits available for this Spliterator. May be zero
+     * indicating that no additional splits are recommended or possible.
+     */
+    int getNaturalSplits();
+
+    /**
+     * Returns a Spliterator covering some portion of the elements, guaranteed
+     * not to overlap with those retained by this Spliterator. After invoking
+     * this method, the current Spliterator will <em>not</em> cover the elements
+     * of the returned Spliterator.
+     * <p/>
+     * @return a Spliterator covering the some portion, possibly empty, of the
+     * data structure elements.
+     * <p/>
+     * @throws IllegalStateException if this Spliterator has already commenced
+     * traversing elements.
+     */
+    Spliterator<T> split();
+
+    /**
+     * Return the Iterator covering the remaining elements. The same iterator
+     * instance is returned for every invocation.
+     * <p/>
+     * @return the iterator of the remaining elements.
+     */
+    Iterator<T> iterator();
+
+    /**
+     * Provides any remaining elements into the provided sink.
+     *
+     * @param block The sink to which elements will be provided.
+     */
+    default void forEach(Block<? super T> block) {
+        Iterator<T> remaining = iterator();
+        while (remaining.hasNext()) {
+            block.apply(remaining.next());
+        }
+    }
+
+   /**
+     * Returns the count of elements currently retained by this Stream.
+     * This is the count which would be processed by {@code into()} or via
+     * {@code iterator()}. If the element count cannot be computed exactly and
+     * cheaply then {@code -1} is returned.
+     * <p/>
+     * @return The number of remaining elements or {@code -1} if the remaining
+     * element count is unavailable.
+     */
+    default int getSizeIfKnown() {
+        return -1;
+    }
+
+    /**
+     * Returns an estimate, possibly inexact, of the count of elements currently
+     * retained by this Stream. This is the count which would be processed by
+     * {@code into()} or via {@code iterator()}. If an element count estimate
+     * cannot be computed cheaply then {@code -1} is returned.
+     * <p>
+     * If {@code getSizeIfKnown()} returns a non-negative integer then
+     * {@code estimateSize()} <strong>must</strong> return the same value.
+     *
+     * @return The number of remaining elements or {@code -1} if the remaining
+     * element count is unavailable.
+     */
+    default int estimateSize() {
+        return getSizeIfKnown();
+    }
+
+    /**
+     * Return {@code true} if this Spliterator and all returned Spliterators
+     * provide non-negative size information from {@code getSizeIfKnown} and
+     * {@code estimateSize}.
+     * <p/>
+     * @return {@code true} if size information is available for this
+     * Spliterator and all sub-splits.
+     */
+    boolean isPredictableSplits();
+
+    /**
+     * A Spliterator that can only be used to sequentially traverse a source.
+     * @param <T>
+     */
+    public interface Sequential<T> extends Spliterator<T> {
+        @Override
+        default int getNaturalSplits() {
+            return 0;
+        }
+
+        @Override
+        default Spliterator<T> split() {
+            return Streams.emptySpliterator();
+        }
+
+        @Override
+        default boolean isPredictableSplits() {
+            return false;
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/Stream.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,160 @@
+/*
+ * 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.function.IntMapper;
+import java.util.function.FlatMapper;
+import java.util.function.Predicate;
+import java.util.function.Factory;
+import java.util.function.Mapper;
+import java.util.function.Block;
+import java.util.function.BinaryOperator;
+import java.util.function.Combiner;
+import java.util.*;
+import java.util.stream.primitive.IntStream;
+
+/**
+ * A potentially infinite sequence of elements. A stream is a consumable data
+ * structure. The elements of the stream are available for consumption by either
+ * iteration or an operation. Once consumed the elements are no longer available
+ * from the stream.
+ *
+ * @param <T> Type of elements.
+ *
+ * @author Brian Goetz
+ */
+public interface Stream<T> extends BaseStream<T> {
+
+    Stream<T> filter(Predicate<? super T> predicate);
+
+    <R> Stream<R> map(Mapper<? extends R, ? super T> mapper);
+
+    IntStream map(IntMapper<? super T> mapper);
+
+    <R> Stream<R> flatMap(FlatMapper<? extends R, ? super T> mapper);
+
+    // @@@ flatMapToInt
+
+    Stream<T> uniqueElements();
+
+    Stream<T> sorted(Comparator<? super T> comparator);
+
+    Stream<T> cumulate(BinaryOperator<T> operator);
+
+    /**
+     * Each element of this stream is processed by the provided block.
+     *
+     * @param block the Block via which all elements will be processed.
+     */
+    void forEach(Block<? super T> block);
+
+    Stream<T> tee(Block<? super T> block);
+
+    /**
+     * Limit this stream to at most {@code n} elements. The stream will not be affected
+     * if it contains less than or equal to {@code n} elements.
+     *
+     * @param n the number elements the stream should be limited to.
+     * @return the truncated stream
+     */
+    Stream<T> limit(int n);
+
+    /**
+     * Skip at most {@code n} elements.
+     *
+     * @param n the number of elements to be skipped.
+     * @return the truncated stream
+     */
+    Stream<T> skip(int n);
+
+    /**
+     * Compute a subsequence of this stream
+     *
+     * @param skip the number of elements to be skipped.
+     * @param limit the maximum length of the resulting stream
+     * @return the truncated stream
+     */
+    Stream<T> slice(int skip, int limit);
+
+    /**
+     * Concatenate to the end of this stream.
+     *
+     * @param other the stream to concatenate.
+     * @return the concatenated stream.
+     */
+    Stream<T> concat(Stream<? extends T> other);
+
+    <A extends Destination<? super T>> A into(A target);
+
+    Object[] toArray();
+
+    <U> Map<U, Collection<T>> groupBy(Mapper<? extends U, ? super T> classifier);
+
+    <U, W> Map<U, W> reduceBy(Mapper<? extends U, ? super T> classifier,
+                              Factory<W> baseFactory,
+                              Combiner<W, W, T> reducer,
+                              BinaryOperator<W> combiner);
+
+    T reduce(T base, BinaryOperator<T> op);
+
+    Optional<T> reduce(BinaryOperator<T> op);
+
+    <U> U fold(Factory<U> baseFactory,
+               Combiner<U, U, T> reducer,
+               BinaryOperator<U> combiner);
+
+    boolean anyMatch(Predicate<? super T> predicate);
+
+    boolean allMatch(Predicate<? super T> predicate);
+
+    boolean noneMatch(Predicate<? super T> predicate);
+
+    Optional<T> findFirst();
+
+    Optional<T> findAny();
+
+    /**
+     * Convert this stream, if a parallel stream, to a sequential stream.
+     *
+     * @return a sequential stream.
+     */
+    Stream<T> sequential();
+
+    /**
+     * Convert this stream to a stream that has no encounter order.
+     *
+     * @return a stream whose output elements have no encounter order.
+     */
+    Stream<T> unordered();
+
+    /**
+     * An aggregate that supports an {@code addAll(Stream)} operation.
+     *
+     * @param <T> Type of aggregate elements.
+     */
+    interface Destination<T> {
+        public void addAll(Stream<? extends T> stream);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/StreamOpFlags.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,320 @@
+/*
+ * 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.EnumSet;
+
+/**
+ * Flags for known and not known properties of streams and operations.
+ *
+ * <p>A stream accessor can logically or flags for the set of properties of the stream.</p>
+ * <p>An operation can logically or flags the set of known and and not known properties of the output stream.</p>
+ *
+ */
+// @@@ When a new flag is added what should happen for existing operations?
+//     Need to move to a builder approach used by ops where the masks for the new flag are
+//     taken into account for default behaviour.
+public enum StreamOpFlags {
+
+    DISTINCT(0),
+
+    SORTED(1),
+
+    ORDERED(2),
+
+    SIZED(3),
+
+    SHORT_CIRCUIT(4, false),
+
+    PARALLEL(5)
+    ;
+
+    /**
+     * The bit pattern for setting a flag.
+     */
+    private static final int SET_BITS = 0b01;
+
+    /**
+     * The bit pattern for clearing a flag.
+     */
+    private static final int CLEAR_BITS = 0b10;
+
+    /**
+     * The bit pattern for preserving a flag.
+     */
+    private static final int PRESERVE_BITS = 0b11;
+
+
+    private final boolean isStreamFlag;
+
+    private final int bitPosition;
+
+    private final int set;
+
+    private final int clear;
+
+    private final int preserve;
+
+    private StreamOpFlags(int position) {
+        this(position, true);
+    }
+
+    private StreamOpFlags(int position, boolean isStreamFlag) {
+        // Two bits per flag
+        position *= 2;
+        this.isStreamFlag = isStreamFlag;
+        this.bitPosition = position;
+        this.set = SET_BITS << position;
+        this.clear = CLEAR_BITS << position;
+        this.preserve = PRESERVE_BITS << position;
+    }
+
+    /**
+     *
+     * @return the set flag.
+     */
+    public int set() {
+        return set;
+    }
+
+    /**
+     *
+     * @return the clear flag.
+     */
+    public int clear() {
+        return clear;
+    }
+
+    /**
+     *
+     * @return true if a stream-based flag, otherwise false.
+     */
+    public boolean isStreamFlag() {
+        return isStreamFlag;
+    }
+
+    /**
+     * Check if a property is known on the combined stream and operations flags.
+     *
+     * @param flags the combined stream and operations flags.
+     * @return true if the property is known, otherwise false.
+     */
+    public boolean isKnown(int flags) {
+        return (flags & preserve) == set;
+    }
+
+    /**
+     * Check if a property is preserved on the combined and operation flags.
+     *
+     * @param flags the combined stream and operations flags.
+     * @return true if the property is preserved, otherwise false.
+     */
+    public boolean isPreserve(int flags) {
+        return (flags & preserve) == preserve;
+    }
+
+    /**
+     * Check if a property is known on the combined operations flags.
+     *
+     * @param opFlags the combined operations flags.
+     * @return true if the property is known, otherwise false.
+     */
+    public boolean isKnownOnOpFlags(int opFlags) {
+        return (opFlags & set) > 0;
+    }
+
+    /**
+     * Clear this flag.
+     *
+     * @param flags the flags from which to clear this flag
+     * @return the flags with this flag cleared.
+     */
+    public int clearFromFlags(int flags) {
+        return flags & ~set;
+    }
+
+    /**
+     * The initial value to be combined with the flags of the first operation in the pipeline.
+     */
+    public static final int INITIAL_OPS_VALUE = createMask(0b11, 0b00); // 0b00_11_11_11_11_11;
+
+    // Flag mask for stream and operation flags
+    private static final int        FLAG_MASK = createMask(0b11, 0b11); // 0b11_11_11_11_11_11;
+
+    // Flag mask for stream flags that are set
+    private static final int     FLAG_MASK_IS = createMask(0b01, 0b00); // 0b00_01_01_01_01_01;
+
+    // Flag mask for stream flags that are cleared
+    private static final int    FLAG_MASK_NOT = createMask(0b10, 0b00); // 0b00_10_10_10_10_10;
+
+    private static int createMask(int s, int o) {
+        int mask = 0;
+        for (StreamOpFlags flag : StreamOpFlags.values()) {
+            mask |= (flag.isStreamFlag) ? s << flag.bitPosition : o << flag.bitPosition;
+        }
+        return mask;
+    }
+
+    /**
+     * Stream elements are known to be distinct. No two elements contained in the stream
+     * are equivalent via {@code equals()} or equality ({@code ==}) operator.
+     */
+    public static final int IS_DISTINCT = DISTINCT.set;
+
+    /**
+     * Stream elements are not known to be distinct.
+     */
+    public static final int NOT_DISTINCT = DISTINCT.clear;
+
+    /**
+     * Stream elements are known to be sorted. Elements are {@code Comparable} and each
+     * element is greater or equal to the element which preceed it (if any) and
+     * less than or equal to the element which follows it (if any).
+     */
+    public static final int IS_SORTED = SORTED.set;
+
+    /**
+     * Stream elements are not known to be sorted.
+     */
+    public static final int NOT_SORTED = SORTED.clear;
+
+    /**
+     * Stream elements are known to have an encounter order.
+     * <p>Certain collections have an expected order when encoutering elements in the collection while traversing,
+     * such as an array or {@link java.util.List}. That order is referred to as encounter order.
+     * Other collections may have no such order, such as a {@link java.util.HashSet},
+     * or {@link java.util.HashMap} when traversing the keys.</p>
+     * <p>Encounter order is important when the order at the input to a pipeline should be preserved at the output,
+     * for example when a list of elements is mapped to another list of elements the encouter order of the output
+     * list should correlate with the encouter order of the input list.</p>
+     * <p>Encounter order is also relevant when choosing an algorithm to process elements in parallel.
+     * If encounter order is to be preserved the parallel algorithm will need to apply associative only functions
+     * i.e. a function can be applied to any grouping of elements but the order of elements cannot change.</p>
+     * <p>Stream elements sourced from an array have an encounter order that is also a spatial order.</p>
+     * <p>An infinite stream of elements may have an encounter order.</p>
+     */
+    public static final int IS_ORDERED = ORDERED.set;
+
+    /**
+     * Stream elements are not known to be ordered.
+     */
+    public static final int NOT_ORDERED = ORDERED.clear;
+
+    /**
+     * The size of the stream is known to be calculated in less than {@code O(n)} time and that
+     * size is known to be equal to the size of the stream source.
+     */
+    public static final int IS_SIZED = SIZED.set;
+
+    /**
+     * The size of the stream is not known that it is not known to be equal to the size of the stream source.
+     */
+    public static final int NOT_SIZED = SIZED.clear;
+
+    /**
+     * The stream is known to be short circuited. Evaluation of the pipeline is constrained to be
+     * pull-oriented.  This is true for operations that may truncate or otherwise
+     * manipulate the stream contents.
+     */
+    public static final int IS_SHORT_CIRCUIT = SHORT_CIRCUIT.set;
+
+    /**
+     * The stream can be decomposed for parallel evaluation
+     */
+    public static final int IS_PARALLEL = PARALLEL.set;
+
+    /**
+     * The stream cannot be decomposed for parallel evaluation
+     */
+    public static final int NOT_PARALLEL = PARALLEL.clear;
+
+    private static int getMask(int flags) {
+        return (flags == 0)
+               ? FLAG_MASK
+               : ~(flags | ((FLAG_MASK_IS & flags) << 1) | ((FLAG_MASK_NOT & flags) >> 1));
+    }
+
+    /**
+     * Combine operation flags.
+     *
+     * <p>A flag value of 0b01 means the property is known on the output stream.</p>
+     * <p>A flag value of 0b10 means the property is not known on the output stream.</p>
+     * <p>A flag value of 0b11 means the property is preserved on the output stream.</p>
+     *
+     * @param opFlags the operation flags.
+     * @param opsFlags previously combined operation flags.
+     *                 The value {#link INITIAL_OPS_VALUE} must be used as the seed value.
+     * @return the result of combination.
+     */
+    public static int combineOpFlags(int opFlags, int opsFlags) {
+        // 0x01 or 0x10 nibbles are transformed to 0x11
+        // 0x00 nibbles remain unchanged
+        // Then all the bits are flipped
+        // Then the result is logically or'ed with the operation flags.
+        return (opsFlags & StreamOpFlags.getMask(opFlags)) | opFlags;
+    }
+
+    /**
+     * Combine stream flags with combined operation flags.
+     *
+     * <p>A flag value of 0b01 means the property is known on the output stream.</p>
+     *
+     * @param streamFlags the stream flags.
+     * @param opsFlags the combined operation flags.
+     * @return the result of combination.
+     */
+    public static int combineStreamFlags(int streamFlags, int opsFlags) {
+        // For stream flags all 0x00 nibbles are transformed to 0x11
+        // Then the result is logically and'ed with the combined operation flags
+        // 0x01 nibbles correspond to set flags
+        return (FLAG_MASK ^ ((FLAG_MASK_IS & streamFlags) << 1)) & opsFlags;
+    }
+
+    /**
+     * Obtain flags that can be set on a stream given combined stream and operation flags.
+     *
+     * @param flags the combined stream and operation flags.
+     * @return flags for a stream, all known properties are propagated and all not-known properties are ignored.
+     */
+    public static int flagsToStreamFlags(int flags) {
+        // By flipping the nibbles 0x11 become 0x00 and 0x01 become 0x10
+        // Shift left 1 to restore set flags and mask off anything other than the set flags
+        return ((~flags) >> 1) & FLAG_MASK_IS & flags;
+    }
+
+    /**
+     * Creates an enum set containing all stream-based flags.
+     *
+     */
+    public static EnumSet<StreamOpFlags> allOfStreamFlags() {
+        EnumSet<StreamOpFlags> flags = EnumSet.allOf(StreamOpFlags.class);
+        for (StreamOpFlags f : flags) {
+            if (!f.isStreamFlag()) {
+                flags.remove(f);
+            }
+        }
+        return flags;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/StreamShape.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,106 @@
+/*
+ * 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.stream.op.IntermediateOp;
+import java.util.stream.op.Node;
+import java.util.stream.op.NodeBuilder;
+
+/**
+ * StreamShape
+ *
+ * @author Brian Goetz
+ */
+public interface StreamShape<S extends BaseStream> {
+
+    /**
+     * @return the stream type of this shape.
+     */
+    Class<S> getStreamType();
+
+    /**
+     * Create a new pipeline by chaining an intermediate operation to an upstream pipeline.
+     * <p>
+     * The output shape if the upstream pipeline must be the same as the input shape of
+     * the intermediate operation.
+     * </p>
+     * @param upstream the upstream pipeline.
+     * @param op the intermediate operation.
+     * @param <U> the type of elements output from the upstream pipeline and input to the new stream.
+     * @param <V> the type of elements output from the new pipeline.
+     * @return a the new pipeline.
+     */
+    <U, V> AbstractPipeline<U, V> chain(AbstractPipeline<?, U> upstream, IntermediateOp<U, V> op);
+
+    // @@@ Should this be the place where the base mechanisms to create a stream reside?
+    //     i.e. spliterator plus flags
+
+    // @@@ Should there be Node.getShape() ?
+
+    /**
+     * Create a sequential pipeline from a compatible node.
+     * <p>A compatible node is a node whose contents is compatible with the stream shape.</p>
+     *
+     * @param n the compatible node
+     * @return the pipeline, whose content is sourced from the node.
+     * @throws IllegalArgumentException if the node is not compatible with this stream shape.
+     */
+    <T> AbstractPipeline<?, T> stream(Node<T> n) throws IllegalArgumentException;
+
+    /**
+     * Create a parallel pipeline from a compatible node.
+     * <p>A compatible node is a node whose contents is compatible with the stream shape.</p>
+     *
+     * @param n the compatible node
+     * @return the pipeline, whose content is sourced from the node.
+     * @throws IllegalArgumentException if the node is not compatible with this stream shape.
+     */
+    <T> AbstractPipeline<?, T> parallel(Node<T> n) throws IllegalArgumentException;
+
+    /**
+     * Make a node builder that can hold elements of this shape.
+     *
+     * @param sizeIfKnown if >=0 then a node builder will be created that has a fixed capacity of at most
+     *                    sizeIfKnown elements.
+     *                    If < 0 then the node builder has an unfixed capacity.
+     *                    A fixed capacity node builder will throw exceptions if an element is added and
+     *                    the builder has reached capacity.
+     * @param <T> The type of elements.
+     * @return the node builder.
+     */
+    <T> NodeBuilder<T> makeNodeBuilder(int sizeIfKnown);
+
+    /**
+     * Collect elements output from a pipeline into Node that holds elements of this shape.
+     *
+     * @param helper the parallel pipeline helper from which elements are obtained.
+     * @param flattenTree true of the returned node should be flattened to one node holding an
+     *                    array of elements.
+     * @param <P_IN> the type of elements input into the pipeline.
+     * @param <T> the type of elements output from the pipeline.
+     * @return the node holding elements output from the pipeline.
+     */
+    <P_IN, T> Node<T> collect(ParallelPipelineHelper<P_IN, T> helper, boolean flattenTree);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/StreamShapeFactory.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,149 @@
+/*
+ * 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.stream.primitive.IntTreeUtils;
+import java.util.stream.primitive.IntNodes;
+import java.util.stream.primitive.IntStream;
+import java.util.stream.primitive.IntPipeline;
+import java.util.stream.primitive.IntSpliterator;
+import java.util.WeakHashMap;
+import java.util.stream.op.*;
+
+public final class StreamShapeFactory {
+
+    private static final StreamShapeFactory FACTORY = new StreamShapeFactory();
+
+    public static final StreamShape<Stream> REFERENCE = lookup(Stream.class);
+
+    public static final StreamShape<IntStream> INT_VALUE = lookup(IntStream.class);
+
+    private final WeakHashMap<Class<? extends BaseStream>, StreamShape> streamShapeRegistry = new WeakHashMap<>();
+
+    private StreamShapeFactory() {
+        // Register defaults
+        StreamShape<Stream> referenceStreamShape = new StreamShape<Stream>() {
+            @Override
+            public Class<Stream> getStreamType() {
+                return Stream.class;
+            }
+
+            @Override
+            public <U, V> AbstractPipeline<U, V> chain(AbstractPipeline<?, U> upstream, IntermediateOp<U, V> op) {
+                return new ReferencePipeline<>(upstream, op);
+            }
+
+            @Override
+            public <T> AbstractPipeline<?, T> stream(Node<T> n) throws IllegalArgumentException {
+                return new ReferencePipeline<>(n.spliterator(),
+                                             StreamOpFlags.IS_ORDERED | StreamOpFlags.IS_SIZED);
+            }
+
+            @Override
+            public <T> AbstractPipeline<?, T> parallel(Node<T> n) throws IllegalArgumentException {
+                return new ReferencePipeline<>(n.spliterator(),
+                                             StreamOpFlags.IS_ORDERED | StreamOpFlags.IS_SIZED | StreamOpFlags.IS_PARALLEL);
+            }
+
+            @Override
+            public <T> NodeBuilder<T> makeNodeBuilder(int sizeIfKnown) {
+                return Nodes.makeBuilder(sizeIfKnown);
+            }
+
+            @Override
+            public <P_IN, T> Node<T> collect(ParallelPipelineHelper<P_IN, T> helper, boolean flattenTree) {
+                return TreeUtils.collect(helper, flattenTree);
+            }
+        };
+
+        set(referenceStreamShape);
+
+        StreamShape<IntStream> intStreamShape = new StreamShape<IntStream>() {
+            @Override
+            public Class<IntStream> getStreamType() {
+                return IntStream.class;
+            }
+
+            @Override
+            public <U, V> AbstractPipeline<U, V> chain(AbstractPipeline<?, U> upstream, IntermediateOp<U, V> op) {
+                // @@@ V is constrained to an Integer, but this cannot be expressed statically unless V is pushed up
+                //     to the type
+                return new IntPipeline(upstream, op);
+            }
+
+            @Override
+            public <T> AbstractPipeline<?, T> stream(Node<T> n) throws IllegalArgumentException {
+                return new IntPipeline((IntSpliterator) n.spliterator(),
+                                       StreamOpFlags.IS_ORDERED | StreamOpFlags.IS_SIZED);
+            }
+
+            @Override
+            public <T> AbstractPipeline<?, T> parallel(Node<T> n) throws IllegalArgumentException {
+                return new IntPipeline((IntSpliterator) n.spliterator(),
+                                       StreamOpFlags.IS_ORDERED | StreamOpFlags.IS_SIZED | StreamOpFlags.IS_PARALLEL);
+            }
+
+            @Override
+            public NodeBuilder makeNodeBuilder(int sizeIfKnown) {
+                // @@@ raw types
+                return IntNodes.makeBuilder(sizeIfKnown);
+            }
+
+            @Override
+            public Node collect(ParallelPipelineHelper helper, boolean flattenTree) {
+                // @@@ raw types
+                return IntTreeUtils.collect(helper, flattenTree);
+            }
+
+        };
+
+        set(intStreamShape);
+    }
+
+    private void set(StreamShape<? extends BaseStream> shape) {
+        synchronized (streamShapeRegistry) {
+            if (streamShapeRegistry.containsKey(shape.getStreamType())) {
+                // @@@ Ignore or throw exception?
+                // throw new IllegalStateException(String.format("StreamShape of type %s is already registered", type.getName()));
+            }
+            else {
+                streamShapeRegistry.put(shape.getStreamType(), shape);
+            }
+        }
+    }
+
+    private <S extends BaseStream> StreamShape get(Class<? extends BaseStream> type) {
+        synchronized (streamShapeRegistry) {
+            return streamShapeRegistry.get(type);
+        }
+    }
+
+    //
+
+    @SuppressWarnings("unchecked")
+    public static <S extends BaseStream> StreamShape<S> lookup(Class<? extends BaseStream> type) {
+        return (StreamShape<S>) FACTORY.get(type);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/Streamable.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+/**
+ * Elements are presented as a Stream.
+ *
+ * @param <S> Type of stream.
+ *
+ * @author Brian Goetz
+ */
+public interface Streamable<S extends BaseStream> {
+    S stream();
+    default S parallel() { return stream(); }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/Streams.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,431 @@
+/*
+ * 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.Factory;
+import java.util.function.UnaryOperator;
+
+/**
+ * Streams
+ *
+ * @author Brian Goetz
+ */
+public class Streams {
+    private static final Stream EMPTY_STREAM = stream(Collections.emptyList(), 0);
+
+    private Streams() {
+        throw new Error("no instances");
+    }
+
+    // Stream
+
+    public static<U, T extends Sized & Iterable<U>> Stream<U> stream(T entity, int flags) {
+        return stream(new Spliterator.Sequential<U>() {
+            @Override
+            public Iterator<U> iterator() {
+                return entity.iterator();
+            }
+
+            @Override
+            public void forEach(Block<? super U> block) {
+                entity.forEach(block);
+            }
+
+            @Override
+            public int getSizeIfKnown() {
+                return entity.size();
+            }
+        }, StreamOpFlags.IS_SIZED | flags);
+    }
+
+    public static<U, T extends Iterable<U>> Stream<U> stream(T entity, Sized sizeProvider, int flags) {
+        return stream(new Spliterator.Sequential<U>() {
+            @Override
+            public Iterator<U> iterator() {
+                return entity.iterator();
+            }
+
+            @Override
+            public void forEach(Block<? super U> block) {
+                entity.forEach(block);
+            }
+
+            @Override
+            public int getSizeIfKnown() {
+                return sizeProvider.size();
+            }
+        }, StreamOpFlags.IS_SIZED | flags);
+    }
+
+    public static<U, T extends Iterable<U>> Stream<U> stream(T entity, int flags) {
+        return stream(new Spliterator.Sequential<U>() {
+            @Override
+            public Iterator<U> iterator() {
+                return entity.iterator();
+            }
+
+            @Override
+            public void forEach(Block<? super U> block) {
+                entity.forEach(block);
+            }
+            // @@@ Mask off sized if set ?
+        }, flags);
+    }
+
+    public static<U, T extends Iterator<U>> Stream<U> stream(T iterator, int flags) {
+        return stream(new Spliterator.Sequential<U>() {
+            @Override
+            public Iterator<U> iterator() {
+                return iterator;
+            }
+
+            @Override
+            public void forEach(Block<? super U> block) {
+                iterator.forEach(block);
+            }
+            // @@@ Mask off sized if set ?
+        }, flags);
+    }
+
+    public static<U> Stream<U> stream(Spliterator<U> spliterator, int flags) {
+        return new ReferencePipeline<>(spliterator, flags);
+    }
+
+    public static <T> Stream<T> stream(Factory<Spliterator<T>> proxy, int flags) {
+        return new ReferencePipeline<>(new ProxySpliterator<>(proxy), flags);
+    }
+
+    public static <T> Spliterator<T> spliterator(T[] source) {
+        return spliterator(source, 0, source.length);
+    }
+
+    public static <T> Spliterator<T> spliterator(T[] source, int offset, int length) {
+        return new ArraySpliterator<>(source, offset, length);
+    }
+
+    public static <T> Stream<T> stream(T[] source) {
+        return stream(source, 0, source.length);
+    }
+
+    public static <T> Stream<T> stream(T[] source, int offset, int length) {
+        // Note use of full-service Spliterator here -- harmless because PARALLEL flag is not set
+        return stream((Spliterator) new ArraySpliterator<>(source, offset, length),
+                      StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED);
+    }
+
+    public static <T> Stream<T> parallel(T[] source) {
+        return Streams.parallel(source, 0, source.length);
+    }
+
+    public static <T> Stream<T> parallel(T[] source, int offset, int length) {
+        return parallel(new ArraySpliterator<>(source, offset, length),
+                        StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED);
+    }
+
+    public static<T> Stream<T> parallel(Spliterator<T> spliterator, int flags) {
+        if (spliterator.getSizeIfKnown() >= 0)
+            flags |= StreamOpFlags.IS_SIZED;
+        return new ReferencePipeline<>(spliterator, flags | StreamOpFlags.IS_PARALLEL);
+    }
+
+    public static <T> Stream<T> parallel(Factory<Spliterator<T>> proxy, int flags) {
+        return new ReferencePipeline<>(new ProxySpliterator<>(proxy), flags | StreamOpFlags.IS_PARALLEL);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static<T> Stream<T> emptyStream() {
+        return EMPTY_STREAM;
+    }
+
+    // Infinite streams
+
+    public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) {
+        Objects.requireNonNull(f);
+        final InfiniteIterator<T> iterator = new InfiniteIterator<T>() {
+            T t = null;
+
+            @Override
+            public T next() {
+                return t = (t == null) ? seed : f.operate(t);
+            }
+        };
+        return stream(iterator, StreamOpFlags.IS_ORDERED);
+    }
+
+    public static<T> Stream<T> repeat(T t) {
+        return repeat(-1, t);
+    }
+
+    public static<T> Stream<T> repeat(final int n, final T t) {
+        if (n < 0) {
+            InfiniteIterator<T> iterator = () -> t;
+            return stream(iterator, StreamOpFlags.IS_ORDERED);
+        }
+        else
+            return repeatedly(n, () -> t);
+    }
+
+    public static<T> Stream<T> repeatedly(Factory<T> f) {
+        return repeatedly(-1, f);
+    }
+
+    public static<T> Stream<T> repeatedly(final int n, final Factory<T> f) {
+        Objects.requireNonNull(f);
+
+        if (n < 0) {
+            InfiniteIterator<T> iterator = () -> f.make();
+            return stream(iterator, StreamOpFlags.IS_ORDERED);
+        }
+        else {
+            final Iterator<T> repeatedly = new Iterator<T>() {
+                int c = n;
+
+                @Override
+                public boolean hasNext() {
+                    return c > 0;
+                }
+
+                @Override
+                public T next() {
+                    if (!hasNext()) {
+                        throw new NoSuchElementException();
+                    }
+
+                    c--;
+                    return f.make();
+                }
+            };
+
+            return stream(repeatedly, StreamOpFlags.IS_ORDERED);
+        }
+    }
+
+    public static<T> Stream<T> cycle(final Iterable<T> source) {
+        Objects.requireNonNull(source);
+
+        // Check if the source is empty
+        if (!source.iterator().hasNext()) {
+            return emptyStream();
+        }
+
+        final InfiniteIterator<T> cycle = new InfiniteIterator<T>() {
+            Iterator<T> i = source.iterator();
+
+            @Override
+            public T next() {
+                if (!i.hasNext()) {
+                    i = source.iterator();
+                }
+
+                return i.next();
+            }
+        };
+
+        return stream(cycle, StreamOpFlags.IS_ORDERED);
+    }
+
+    private static final Spliterator<?> EMPTY_SPLITERATOR = new Spliterator<Object>() {
+            @Override
+            public int getNaturalSplits() {
+                return 0;
+            }
+
+            @Override
+            public Spliterator<Object> split() {
+                return emptySpliterator();
+            }
+
+            @Override
+            public Iterator<Object> iterator() {
+                return Collections.emptyIterator();
+            }
+
+            @Override
+            public void forEach(Block<? super Object> block) {
+            }
+
+            @Override
+            public int getSizeIfKnown() {
+                return 0;
+            }
+
+            @Override
+            public boolean isPredictableSplits() {
+                return true;
+            }
+        };
+
+    public static<T> Spliterator<T> emptySpliterator() {
+        return (Spliterator<T>) EMPTY_SPLITERATOR;
+    }
+
+    public interface InfiniteIterator<T> extends Iterator<T> {
+        @Override
+        public default boolean hasNext() {
+            return true;
+        }
+    }
+
+    private static class ArrayIterator<T> implements Iterator<T> {
+        protected final T[] elements;
+        protected final int endOffset;
+        protected int curOffset;
+
+        private ArrayIterator(T[] elements, int startOffset, int len) {
+            this.elements = Objects.requireNonNull(elements);
+            this.endOffset = startOffset + len;
+            this.curOffset = startOffset;
+
+            assert curOffset >= 0 : "offset not positive";
+            assert endOffset >= curOffset : "end lower than start";
+            assert (curOffset < elements.length) || (0 == len && 0 == curOffset) : "offset not in array";
+            assert endOffset <= elements.length : "end not in array";
+        }
+
+        public T next() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+
+            return elements[curOffset++];
+        }
+
+        @Override
+        public final boolean hasNext() {
+            return curOffset < endOffset;
+        }
+    }
+
+    private static class ArraySpliterator<T> extends ArrayIterator<T> implements Spliterator<T> {
+        boolean traversing = false;
+
+        ArraySpliterator(T[] elements) {
+            this(elements, 0, elements.length);
+        }
+
+        ArraySpliterator(T[] elements, int offset, int length) {
+            super(elements, offset, length);
+        }
+
+        @Override
+        public int getSizeIfKnown() {
+            return endOffset - curOffset;
+        }
+
+        @Override
+        public int estimateSize() {
+            return getSizeIfKnown();
+        }
+
+        @Override
+        public boolean isPredictableSplits() {
+            return true;
+        }
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            traversing = true;
+            for (int i= curOffset; i<endOffset; i++) {
+                block.apply(elements[i]);
+            }
+            // update only once; reduce heap write traffic
+            curOffset = endOffset;
+        }
+
+        @Override
+        public int getNaturalSplits() {
+            return (endOffset - curOffset > 1) ? 1 : 0;
+        }
+
+        @Override
+        public Spliterator<T> split() {
+            if (traversing) {
+                throw new IllegalStateException("split after starting traversal");
+            }
+            int t = (endOffset - curOffset) / 2;
+            Spliterator<T> ret = new ArraySpliterator<>(elements, curOffset, t);
+            curOffset += t;
+            return ret;
+        }
+
+        @Override
+        public Iterator<T> iterator() {
+            traversing = true;
+            return this;
+        }
+    }
+
+    private static class ProxySpliterator<T> implements Spliterator<T> {
+        private final Factory<Spliterator<T>> factory;
+        private Spliterator<T> spliterator;
+
+        private ProxySpliterator(Factory<Spliterator<T>> factory) {
+            this.factory = factory;
+        }
+
+        private Spliterator<T> spliterator() {
+            if (spliterator == null)
+                spliterator = factory.make();
+            return spliterator;
+        }
+
+        @Override
+        public int getNaturalSplits() {
+            return spliterator().getNaturalSplits();
+        }
+
+        @Override
+        public Spliterator<T> split() {
+            return spliterator().split();
+        }
+
+        @Override
+        public Iterator<T> iterator() {
+            return spliterator().iterator();
+        }
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            spliterator().forEach(block);
+        }
+
+        @Override
+        public int getSizeIfKnown() {
+            return spliterator().getSizeIfKnown();
+        }
+
+        @Override
+        public int estimateSize() {
+            return spliterator().estimateSize();
+        }
+
+        @Override
+        public boolean isPredictableSplits() {
+            return spliterator().isPredictableSplits();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/TerminalSink.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,52 @@
+/*
+ * 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 Sink which accumulates state as elements are accepted, and allows that
+ * state to be retrieved after the computation is finished
+ *
+ * @param <T> The type of elements to be accepted.
+ * @param <R> The type of the terminal state.
+ *
+ * @author Brian Goetz
+ */
+public interface TerminalSink<T, R> extends Sink<T> {
+
+    /**
+     * @@@ consider removing default
+     * @param size
+     */
+    @Override
+    default void begin(int size) { }
+
+    @Override
+    default void end() { }
+
+    /**
+     * Retrieve, and clear, the current state of the sink.
+     */
+    R getAndClearState();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/AbstractTask.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,281 @@
+/*
+ * 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.atomic.AtomicReference;
+import java.util.stream.ParallelPipelineHelper;
+import java.util.stream.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 ParallelPipelineHelper<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;
+
+    /** 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 rawResult;
+
+    protected AbstractTask(ParallelPipelineHelper<P_IN, P_OUT> helper) {
+        super(null);
+        this.helper = helper;
+        this.spliterator = helper.spliterator();
+    }
+
+    protected AbstractTask(T parent, Spliterator<P_IN> spliterator) {
+        super(parent);
+        this.helper = parent.helper;
+        this.spliterator = spliterator;
+    }
+
+    /** 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();
+
+    /**
+     * Retrieve a result previously stored with <code>setRawResult</code>
+     */
+    @Override
+    public R getRawResult() {
+        return rawResult;
+    }
+
+    /**
+     * Associate the result with the task, can be retrieved with <code>getRawResult</code>
+     */
+    @Override
+    protected void setRawResult(R r) {
+        rawResult = r;
+    }
+
+    /** 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() {
+        if (!helper.suggestSplit(spliterator)) {
+            setRawResult(doLeaf());
+            tryComplete();
+        }
+        else {
+            int naturalSplits = spliterator.getNaturalSplits();
+            if (naturalSplits == 0) {
+                // Shouldn't get here, but if we do, act like a leaf
+                setRawResult(doLeaf());
+                tryComplete();
+            }
+            else if (naturalSplits == 1) {
+                // Common case -- binary splits
+                T leftChild = makeChild(spliterator.split());
+                T rightChild = makeChild(spliterator);
+                setPendingCount(1);
+                numChildren = 2;
+                children = leftChild;
+                leftChild.nextSibling = rightChild;
+                rightChild.fork();
+                leftChild.compute();
+            }
+            else {
+                T firstChild = makeChild(spliterator.split());
+                setPendingCount(naturalSplits);
+                numChildren = naturalSplits + 1;
+                children = firstChild;
+                T curChild = firstChild;
+                for (int i=naturalSplits-1; i >= 0; i--) {
+                    T newChild = makeChild((i > 0) ? spliterator.split() : spliterator);
+                    curChild.nextSibling = newChild;
+                    curChild = newChild;
+                }
+                for (T child=children.nextSibling; child != null; child=child.nextSibling)
+                    child.fork();
+
+                firstChild.compute();
+            }
+        }
+    }
+
+    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;
+    }
+}
+
+abstract class AbstractCancelableTask<P_IN, P_OUT, R, T extends AbstractCancelableTask<P_IN, P_OUT, R, T>>
+        extends AbstractTask<P_IN, P_OUT, R, T> {
+    protected volatile boolean canceled;
+
+    protected AbstractCancelableTask(ParallelPipelineHelper<P_IN, P_OUT> helper) {
+        super(helper);
+    }
+
+    protected AbstractCancelableTask(T parent, Spliterator<P_IN> spliterator) {
+        super(parent, spliterator);
+    }
+
+    protected boolean taskCancelled() {
+        boolean cancel = canceled;
+        if (!cancel)
+            for (T parent = getParent(); !cancel && parent != null; parent = parent.getParent())
+                cancel = parent.canceled;
+        return cancel;
+    }
+
+    protected abstract R getEmptyResult();
+
+    @Override
+    public void compute() {
+        if (taskCancelled()) {
+            setRawResult(getEmptyResult());
+            tryComplete();
+        }
+        else
+            super.compute();
+    }
+
+    protected void cancel() {
+        canceled = true;
+    }
+
+    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();
+    }
+}
+
+abstract class AbstractShortCircuitTask<P_IN, P_OUT, R, T extends AbstractShortCircuitTask<P_IN, P_OUT, R, T>>
+        extends AbstractCancelableTask<P_IN, P_OUT, R, T> {
+    protected final AtomicReference<R> atomicAnswer;
+
+    protected AbstractShortCircuitTask(ParallelPipelineHelper<P_IN, P_OUT> helper) {
+        super(helper);
+        atomicAnswer = new AtomicReference<>(null);
+    }
+
+    protected AbstractShortCircuitTask(T parent, Spliterator<P_IN> spliterator) {
+        super(parent, spliterator);
+        atomicAnswer = parent.atomicAnswer;
+    }
+
+    @Override
+    public void compute() {
+        // Have we already found an answer?
+        if (atomicAnswer.get() != null)
+            tryComplete();
+        else
+            super.compute();
+    }
+
+    protected void shortCircuit(R r) {
+        if (r != null)
+            atomicAnswer.compareAndSet(null, r);
+    }
+
+    @Override
+    protected void setRawResult(R r) {
+        if (isRoot()) {
+            if (r != null)
+                atomicAnswer.compareAndSet(null, r);
+        }
+        else
+            super.setRawResult(r);
+    }
+
+    @Override
+    public R getRawResult() {
+        if (isRoot()) {
+            R answer = atomicAnswer.get();
+            return (answer == null) ? getEmptyResult() : answer;
+        }
+        else
+            return super.getRawResult();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/CollectorOps.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,109 @@
+/*
+ * 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.stream.ParallelPipelineHelper;
+import java.util.stream.PipelineHelper;
+import java.util.stream.Sink;
+import java.util.stream.StreamOpFlags;
+
+public final class CollectorOps {
+    private CollectorOps() { }
+
+    private static Sequential<?> SEQUENTIAL_COLLECTOR_OP = new Sequential<>();
+
+    @SuppressWarnings("unchecked")
+    public static <E_IN> Sequential<E_IN> sequentialCollector() {
+        return (Sequential<E_IN>) SEQUENTIAL_COLLECTOR_OP;
+    }
+
+    private static Parallel<?> PARALLEL_COLLECTOR_OP = new Parallel<>();
+
+    @SuppressWarnings("unchecked")
+    public static <E_IN> Parallel<E_IN> parallelCollector() {
+        return (Parallel<E_IN>) PARALLEL_COLLECTOR_OP;
+    }
+
+    private static Terminal<?> TERMINAL_COLLECTOR_OP = new Terminal<>();
+
+    @SuppressWarnings("unchecked")
+    public static <E_IN> Terminal<E_IN> terminalCollector() {
+        return (Terminal<E_IN>) TERMINAL_COLLECTOR_OP;
+    }
+
+    public static class Parallel<E_IN> implements StatefulOp<E_IN, E_IN> {
+
+        @Override
+        public Iterator<E_IN> wrapIterator(int flags, Iterator<E_IN> in) {
+            return in;
+        }
+
+        @Override
+        public Sink<E_IN> wrapSink(int flags, Sink<E_IN> sink) {
+            return sink;
+        }
+
+        @Override
+        public <P_IN> Node<E_IN> evaluateSequential(PipelineHelper<P_IN, E_IN> helper) {
+            return helper.collectOutput();
+        }
+
+        @Override
+        public <P_IN> Node<E_IN> evaluateParallel(ParallelPipelineHelper<P_IN, E_IN> helper) {
+            return helper.collectOutput();
+        }
+    }
+
+    /**
+     * Collect elements into a Node, if evaluated in parallel, and force sequential evaluation on upstream operations,
+     * otherwise, if evaluated sequentially, this operation is a no-op.
+     */
+    public static class Sequential<E_IN> extends Parallel<E_IN> {
+
+        private Sequential() { }
+
+        @Override
+        public int getOpFlags() {
+            return StreamOpFlags.NOT_PARALLEL;
+        }
+    }
+
+    /**
+     * Collect elements into a Node that is the result of terminal evaluation.
+     */
+    public static class Terminal<E_IN> implements TerminalOp<E_IN, Node<E_IN>> {
+
+        @Override
+        public <P_IN> Node<E_IN> evaluateParallel(ParallelPipelineHelper<P_IN, E_IN> helper) {
+            return helper.collectOutput();
+        }
+
+        @Override
+        public <P_IN> Node<E_IN> evaluateSequential(PipelineHelper<P_IN, E_IN> helper) {
+            return helper.collectOutput();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/ConcatOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,94 @@
+/*
+ * 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.Iterators;
+import java.util.Objects;
+import java.util.stream.*;
+
+public class ConcatOp<T> implements StatefulOp<T, T> {
+
+    private final Stream<? extends T> stream;
+
+    // @@@ Support Streamable
+    //     This will ensure the operation can be used in detached pipelines
+    //     and there is a choice to obtain the serial or parallel stream
+    //     There are still cases where Stream is useful e.g. from I/O sources
+    // @@@ Requires flags are available on Streamable for analysis of the pipeline
+    // @@@ Might be possible for some consolidation if Streamable was generic to Stream/MapStream
+    public ConcatOp(Stream<? extends T> stream) {
+        this.stream = stream;
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT | StreamOpFlags.NOT_SIZED;
+    }
+
+    @Override
+    public Iterator<T> wrapIterator(int flags, Iterator<T> source) {
+        Objects.requireNonNull(source);
+
+        return Iterators.concat(source, stream.iterator());
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, Sink<T> sink) {
+        Objects.requireNonNull(sink);
+
+        return new Sink.ChainedValue<T>(sink) {
+            @Override
+            public void apply(T t) {
+                downstream.apply(t);
+            }
+
+            @Override
+            public void end() {
+                // Pull from the concatenating stream to ensure sequential access
+                // Note that stream.forEach(downstream) will not, in the parallel case,
+                // guarantee an order, and stream.sequential().forEach(downstream) will
+                // result in buffering of the stream contents
+                Iterator<? extends T> i = stream.iterator();
+                while (i.hasNext()) {
+                    downstream.apply(i.next());
+                }
+                downstream.end();
+            }
+        };
+    }
+
+    @Override
+    public <S> Node<T> evaluateParallel(ParallelPipelineHelper<S, T> helper) {
+        // Get all stuff from upstream
+        Node<T> upStreamNode = helper.collectOutput();
+
+        // Get stuff from concatenation
+        Node<T> concatStreamNode = Nodes.node(stream);
+
+        // Combine
+        return Nodes.node(upStreamNode, concatStreamNode);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/CumulateOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,242 @@
+/*
+ * 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.Objects;
+import java.util.concurrent.RecursiveTask;
+import java.util.function.BinaryOperator;
+import java.util.stream.*;
+
+/**
+ * CumulateOp
+ *
+ * @param <T> Type of elements to be cumulated and of result.
+ *
+ * @author Brian Goetz
+ */
+public class CumulateOp<T> implements StatefulOp<T, T> {
+    private final BinaryOperator<T> op;
+
+    public CumulateOp(BinaryOperator<T> op) {
+        this.op = Objects.requireNonNull(op);
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT;
+    }
+
+    @Override
+    public TerminalSink<T, T> wrapSink(int flags, final Sink<T> sink) {
+        return new TerminalSink<T, T>() {
+            private boolean first;
+            private T state;
+
+            @Override
+            public void begin(int size) {
+                first = true;
+                sink.begin(size);
+            }
+
+            @Override
+            public void apply(T t) {
+                if (first) {
+                    first = false;
+                    state = t;
+                }
+                else {
+                    state = op.operate(state, t);
+                }
+                sink.apply(state);
+            }
+
+            @Override
+            public void end() {
+                sink.end();
+            }
+
+            @Override
+            public T getAndClearState() {
+                T ret = state;
+                state = null;
+                return ret;
+            }
+        };
+    }
+
+    @Override
+    public Iterator<T> wrapIterator(int flags, Iterator<T> iterator) {
+        Objects.requireNonNull(iterator);
+        return iterator(iterator, op);
+    }
+
+    public static<T> Iterator<T> iterator(final Iterator<T> in, final BinaryOperator<T> op) {
+        return new Iterator<T>() {
+            boolean first = true;
+            T value;
+
+            @Override
+            public boolean hasNext() {
+                return in.hasNext();
+            }
+
+            @Override
+            public T next() {
+                if (first) {
+                    value = in.next();
+                    first = false;
+                } else {
+                    value = op.operate(value, in.next());
+                }
+                return value;
+            }
+        };
+    }
+
+    @Override
+    public <S> Node<T> evaluateParallel(ParallelPipelineHelper<S, T> helper) {
+        return helper.invoke(new CumulateTask<>(helper.spliterator(), op, helper));
+    }
+
+    private static class Problem<S, T> {
+        final BinaryOperator<T> op;
+        final ParallelPipelineHelper<S, T> helper;
+        int pass = 0;
+
+        private Problem(BinaryOperator<T> op, ParallelPipelineHelper<S, T> helper) {
+            this.op = op;
+            this.helper = helper;
+        }
+
+        T operate(T a, T b) {
+            // If there is a operation before cumulate that removes elements, such as filter
+            // then elements may never get pushed into the sink. In such a case the terminal
+            // sink will return null on a call to "getAndClearState".
+            //
+            // This is more likely to occur if the leaf spliterator size is small
+
+            if (a == null && b == null)
+                return null;
+            if (a == null)
+                return b;
+            if (b == null)
+                return a;
+            return op.operate(a, b);
+        }
+    }
+
+    private class CumulateTask<S> extends RecursiveTask<Node<T>> {
+        private final Problem<S, T> problem;
+        private final Spliterator<S> spliterator;
+        private final boolean isRoot;
+        private CumulateTask<S> left, right;
+        private NodeBuilder<T> leafData;
+        private boolean isLeaf;
+        private T upward;
+        private T downward;
+        private boolean downwardZero = false;
+        private NodeBuilder<T> result;
+
+        private CumulateTask(Spliterator<S> spliterator,
+                             BinaryOperator<T> op,
+                             ParallelPipelineHelper<S, T> helper) {
+            this.spliterator = spliterator;
+            this.problem = new Problem<>(op, helper);
+            this.isRoot = true;
+        }
+
+        private CumulateTask(Spliterator<S> spliterator, Problem<S, T> problem) {
+            this.spliterator = spliterator;
+            this.problem = problem;
+            this.isRoot = false;
+        }
+
+        @Override
+        protected Node<T> compute() {
+            switch (problem.pass) {
+                case 0:
+                    isLeaf = !problem.helper.suggestSplit(spliterator);
+                    if (!isLeaf) {
+                        left = new CumulateTask<>(spliterator.split(), problem);
+                        right = new CumulateTask<>(spliterator, problem);
+                        right.fork();
+                        left.compute();
+                        right.join();
+                        upward = problem.operate(left.upward, right.upward);
+                        if (isRoot) {
+                            downwardZero = true;
+                            problem.pass = 1;
+                            return compute();
+                        }
+                    }
+                    else {
+                        leafData = OpUtils.makeNodeBuilderFor(problem.helper, spliterator);
+                        TerminalSink<T, T> terminalSink = wrapSink(problem.helper.getStreamFlags(), leafData);
+                        OpUtils.intoWrapped(spliterator, problem.helper.wrapSink(terminalSink));
+                        upward = terminalSink.getAndClearState();
+                        // Special case -- if problem.depth == 0, just wrap the result and be done
+                        if (isRoot)
+                            return leafData.build();
+                    }
+                    return null;
+
+                case 1:
+                    if (!isLeaf) {
+                        left.reinitialize();
+                        right.reinitialize();
+                        if (downwardZero) {
+                            left.downwardZero = true;
+                            right.downward = left.upward;
+                        }
+                        else {
+                            left.downward = downward;
+                            right.downward = problem.operate(downward, left.upward);
+                        }
+                        right.fork();
+                        Node<T> leftResult = left.compute();
+                        Node<T> rightResult = right.join();
+                        return Nodes.node(leftResult, rightResult);
+                    }
+                    else {
+                        if (!downwardZero && downward != null) {
+                            if (leafData instanceof NodeBuilder.Fixed) {
+                                T[] content = ((NodeBuilder.Fixed<T>)leafData).getContent();
+                                for (int i = 0; i < leafData.size(); i++) {
+                                    content[i] = problem.op.operate(downward, content[i]);
+                                }
+                            } else {
+                                leafData.forEachUpdate(e -> problem.op.operate(downward, e));
+                            }
+                        }
+                        return leafData.build();
+                    }
+
+                default:
+                    throw new IllegalStateException();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/FilterOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,67 @@
+/*
+ * 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.Iterators;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.stream.Sink;
+import java.util.stream.StreamOpFlags;
+
+/**
+ * FilterOp
+ *
+ * @author Brian Goetz
+ */
+public class FilterOp<T> implements IntermediateOp<T, T> {
+    public final Predicate<? super T> predicate;
+
+    public FilterOp(Predicate<? super T> predicate) {
+        this.predicate = Objects.requireNonNull(predicate);
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED;
+    }
+
+    @Override
+    public Iterator<T> wrapIterator(int flags, Iterator<T> source) {
+        return Iterators.filter(source, predicate);
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, final Sink sink) {
+        Objects.requireNonNull(sink);
+        return new Sink.ChainedValue<T>(sink) {
+            @Override
+            public void apply(T t) {
+                if (predicate.test(t))
+                    downstream.apply(t);
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/FindAnyOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,98 @@
+/*
+ * 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.Optional;
+import java.util.stream.ParallelPipelineHelper;
+import java.util.stream.PipelineHelper;
+import java.util.stream.Spliterator;
+
+/**
+ * FindAnyOp
+ *
+ * @author Brian Goetz
+ */
+public class FindAnyOp<T> implements TerminalOp<T, Optional<T>> {
+    private final static FindAnyOp<?> INSTANCE = new FindAnyOp<>();
+
+    @SuppressWarnings("unchecked")
+    public static <T> FindAnyOp<T> singleton() {
+        return (FindAnyOp<T>) INSTANCE;
+    }
+
+    @Override
+    public boolean isShortCircuit() {
+        return true;
+    }
+
+    @Override
+    public <S> Optional<T> evaluateSequential(PipelineHelper<S, T> helper) {
+        return evaluate(helper.iterator());
+    }
+
+    @Override
+    public <P_IN> Optional<T> evaluateParallel(ParallelPipelineHelper<P_IN, T> helper) {
+        // Approach for parallel implementation:
+        // - Maintain raw result as AtomicReference<Optional<T>>
+        // - Decompose as per usual
+        // - For each chunk, pull first element; if present, complete root
+
+        return helper.invoke(new FindAnyTask<>(helper));
+    }
+
+    // For testing purposes
+    public Optional<T> evaluate(Iterator<T> iterator) {
+        return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.<T>empty();
+    }
+
+    private static class FindAnyTask<S, T> extends AbstractShortCircuitTask<S, T, Optional<T>, FindAnyTask<S, T>> {
+        private FindAnyTask(ParallelPipelineHelper<S, T> helper) {
+            super(helper);
+        }
+
+        private FindAnyTask(FindAnyTask<S, T> parent, Spliterator<S> spliterator) {
+            super(parent, spliterator);
+        }
+
+        @Override
+        protected FindAnyTask<S, T> makeChild(Spliterator<S> spliterator) {
+            return new FindAnyTask<>(this, spliterator);
+        }
+
+        @Override
+        protected Optional<T> getEmptyResult() {
+            return Optional.empty();
+        }
+
+        @Override
+        protected Optional<T> doLeaf() {
+            Iterator<T> iterator = helper.wrapIterator(spliterator.iterator());
+            if (iterator.hasNext())
+                shortCircuit(Optional.of(iterator.next()));
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/FindFirstOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,123 @@
+/*
+ * 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.Optional;
+import java.util.concurrent.CountedCompleter;
+import java.util.stream.ParallelPipelineHelper;
+import java.util.stream.PipelineHelper;
+import java.util.stream.Spliterator;
+
+/**
+ * FindFirstOp
+ *
+ * @author Brian Goetz
+ */
+public class FindFirstOp<T> implements TerminalOp<T, Optional<T>> {
+    private final static FindFirstOp<?> INSTANCE = new FindFirstOp<>();
+
+    @SuppressWarnings("unchecked")
+    public static <T> FindFirstOp<T> singleton() {
+        return (FindFirstOp<T>) INSTANCE;
+    }
+
+    @Override
+    public boolean isShortCircuit() {
+        return true;
+    }
+
+    @Override
+    public <S> Optional<T> evaluateSequential(PipelineHelper<S, T> helper) {
+        return evaluate(helper.iterator());
+    }
+
+    // For testing purposes
+    public Optional<T> evaluate(Iterator<T> iterator) {
+        return iterator.hasNext() ? Optional.of(iterator.next()) : Optional.<T>empty();
+    }
+
+    @Override
+    public <P_IN> Optional<T> evaluateParallel(ParallelPipelineHelper<P_IN, T> helper) {
+        // Parallel strategy
+        // - Each node maintains a result and a cancelation flag
+        // - before compute, check cancelation flag
+        // - after successful leaf, cancel siblings that are later in the order
+
+        return helper.invoke(new FindFirstTask<>(helper));
+    }
+
+    private static class FindFirstTask<S, T> extends AbstractShortCircuitTask<S, T, Optional<T>, FindFirstTask<S, T>> {
+
+        private FindFirstTask(ParallelPipelineHelper<S, T> helper) {
+            super(helper);
+        }
+
+        private FindFirstTask(FindFirstTask<S, T> parent, Spliterator<S> spliterator) {
+            super(parent, spliterator);
+        }
+
+        @Override
+        protected FindFirstTask<S, T> makeChild(Spliterator<S> spliterator) {
+            return new FindFirstTask<>(this, spliterator);
+        }
+
+        @Override
+        protected Optional<T> getEmptyResult() {
+            return Optional.empty();
+        }
+
+        private void foundResult(Optional<T> answer) {
+            if (isLeftSpine())
+                shortCircuit(answer);
+            else
+                cancelLaterNodes();
+        }
+
+        @Override
+        protected Optional<T> doLeaf() {
+            Iterator<T> iterator = helper.wrapIterator(spliterator.iterator());
+            if (iterator.hasNext()) {
+                Optional<T> answer = Optional.of(iterator.next());
+                foundResult(answer);
+                return answer;
+            }
+            else
+                return null;
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            for (FindFirstTask<S, T> child = children; child != null; child = child.nextSibling) {
+                Optional<T> result = child.getRawResult();
+                if (result != null && result.isPresent()) {
+                    setRawResult(result);
+                    foundResult(result);
+                    break;
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/FlagDeclaringOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,56 @@
+/*
+ * 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.stream.Sink;
+
+/**
+ * An operation that injects or clears flags but otherwise performs no operation on elements.
+ *
+ */
+public class FlagDeclaringOp<T> implements IntermediateOp<T, T> {
+    private final int flags;
+
+    public FlagDeclaringOp(int flags) {
+        this.flags = flags;
+    }
+
+    @Override
+    public int getOpFlags() {
+        return flags;
+    }
+
+    @Override
+    public Iterator<T> wrapIterator(int flags, final Iterator<T> source) {
+        return source;
+    }
+
+    @Override
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public Sink<T> wrapSink(int flags, Sink sink) {
+        return sink;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/FlatMapOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,108 @@
+/*
+ * 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.ArrayList;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.function.Block;
+import java.util.function.FlatMapper;
+import java.util.stream.Sink;
+import java.util.stream.StreamOpFlags;
+
+/**
+ * FlatMapOp
+ *
+ * @author Brian Goetz
+ */
+public class FlatMapOp<T,R> implements IntermediateOp<T, R> {
+    public final FlatMapper<? extends R, ? super T> mapper;
+
+    public FlatMapOp(FlatMapper<? extends R, ? super T> mapper) {
+        Objects.requireNonNull(mapper);
+        this.mapper = mapper;
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT | StreamOpFlags.NOT_ORDERED | StreamOpFlags.NOT_SIZED;
+    }
+
+    @Override
+    public Iterator<R> wrapIterator(int flags, final Iterator<T> source) {
+        Objects.requireNonNull(source);
+        return iterator(source, mapper);
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, final Sink sink) {
+        Objects.requireNonNull(sink);
+        return new Sink.ChainedValue<T>(sink) {
+            public void apply(T t) {
+                mapper.flatMapInto(downstream, t);
+            }
+        };
+    }
+
+    public static<T, R> Iterator<R> iterator(final Iterator<T> iterator, final FlatMapper<? extends R, ? super T> mapper) {
+        return new Iterator<R>() {
+            final Iterator<? extends T> source = iterator;
+            // @@@ Replace with spined list implementation
+            final ArrayList<R> buffer = new ArrayList<>();
+            final Block<R> bufferTarget = buffer::add;
+            Iterator<R> currentMapped = null;
+
+            @Override
+            public boolean hasNext() {
+                while (true) {
+                    if (currentMapped == null) {
+                        if (!source.hasNext()) {
+                            return false;
+                        } else {
+                            buffer.clear();
+                            mapper.flatMapInto(bufferTarget, source.next());
+                            currentMapped = buffer.iterator();
+                        }
+                    } else {
+                        if (currentMapped.hasNext()) {
+                            return true;
+                        } else {
+                            currentMapped = null;
+                        }
+                    }
+                }
+            }
+
+            @Override
+            public R next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+                return currentMapped.next();
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/FoldOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,95 @@
+/*
+ * 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.function.BinaryOperator;
+import java.util.function.Combiner;
+import java.util.function.Factory;
+import java.util.stream.ParallelPipelineHelper;
+import java.util.stream.PipelineHelper;
+
+/**
+ * FoldOp
+ *
+ * @author Brian Goetz
+ */
+public class FoldOp<T, U> implements TerminalOp<T, U> {
+    private final Factory<U> seedFactory;
+    private final Combiner<U, U, T> reducer;
+    private final BinaryOperator<U> combiner;
+
+    public FoldOp(Factory<U> factory, Combiner<U, U, T> reducer, BinaryOperator<U> combiner) {
+        this.seedFactory = factory;
+        this.reducer = reducer;
+        this.combiner = combiner;
+    }
+
+    public FoldOp(U seed, Combiner<U, U, T> reducer, BinaryOperator<U> combiner) {
+        this(()->seed, reducer, combiner);
+    }
+
+    public <S> U evaluateSequential(PipelineHelper<S, T> helper) {
+        return helper.into(new FoldingSink()).getAndClearState();
+    }
+
+    @Override
+    public <S> U evaluateParallel(ParallelPipelineHelper<S, T> helper) {
+        return OpUtils.parallelReduce(helper, () -> new FoldingSink());
+    }
+
+    /* private */ class FoldingSink implements OpUtils.AccumulatingSink<T, U, FoldingSink> {
+        U state;
+
+        @Override
+        public void begin(int size) {
+            state = seedFactory.make();
+        }
+
+        @Override
+        public void clearState() {
+            state = null;
+        }
+
+        @Override
+        public U getAndClearState() {
+            try {
+                return state;
+            }
+            finally {
+                state = null;
+            }
+        }
+
+        @Override
+        public void apply(T t) {
+            state = reducer.combine(state, t);
+        }
+
+        @Override
+        public void combine(FoldingSink other) {
+            state = combiner.combine(state, other.state);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/ForEachOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -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.op;
+
+import java.util.Objects;
+import java.util.function.Block;
+import java.util.logging.Logger;
+import java.util.stream.*;
+
+/**
+ * ForEachOp
+ *
+ * @author Brian Goetz
+ */
+public class ForEachOp<T> implements TerminalOp<T, Void> {
+    private static final Logger LOGGER = Logger.getLogger(ForEachOp.class.getName());
+    private final TerminalSink<T, Void> sink;
+    private final StreamShape shape;
+
+    protected ForEachOp(TerminalSink<T, Void> sink, StreamShape shape) {
+        this.shape = Objects.requireNonNull(shape);
+        this.sink = Objects.requireNonNull(sink);
+    }
+
+    public static<T> ForEachOp<T> make(final Block<? super T> block) {
+        Objects.requireNonNull(block);
+        return new ForEachOp<>(new TerminalSink<T, Void>() {
+         @Override
+            public void apply(T t) {
+                block.apply(t);
+            }
+
+            @Override
+            public Void getAndClearState() {
+                return null;
+            }
+        }, StreamShapeFactory.REFERENCE);
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return shape;
+    }
+
+    @Override
+    public <S> Void evaluateSequential(PipelineHelper<S, T> helper) {
+        return helper.into(sink).getAndClearState();
+    }
+
+    @Override
+    public <S> Void evaluateParallel(ParallelPipelineHelper<S, T> helper) {
+        OpUtils.parallelForEach(helper, helper.wrapSink(sink));
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/GroupByOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,137 @@
+/*
+ * 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.ConcurrentHashMap;
+import java.util.function.Factory;
+import java.util.function.Mapper;
+import java.util.stream.*;
+
+/**
+ * GroupByOp
+ * <p>If an element maps to a <code>null</code> key a {@link NullPointerException} will be thrown.</p>
+ *
+ * @param <T> Type of elements to be grouped.
+ * @param <K> Type of elements in the resulting Map.
+ * @author Brian Goetz
+ */
+// @@@ Change from ArrayList to using a SpinedList, to be implemented, which avoids copying
+//     of data when list needs to be re-sized
+public class GroupByOp<T, K> implements TerminalOp<T, Map<K, Collection<T>>> {
+
+    private final Mapper<? extends K, ? super T> mapper;
+
+    private final Factory<Collection<T>> valueFactory;
+
+    public GroupByOp(Mapper<? extends K, ? super T> mapper) {
+        this(mapper, ArrayList::new);
+    }
+
+    public GroupByOp(Mapper<? extends K, ? super T> mapper, Factory<Collection<T>> valueFactory) {
+        this.mapper = mapper;
+        this.valueFactory = valueFactory;
+    }
+
+    // Public for tests
+    public TerminalSink<T, Map<K, Collection<T>>> sink() {
+        return new GroupBySink();
+    }
+
+    @Override
+    public <S> Map<K, Collection<T>> evaluateSequential(PipelineHelper<S, T> helper) {
+        return helper.into(new GroupBySink()).getAndClearState();
+    }
+
+    @Override
+    public <S> Map<K, Collection<T>> evaluateParallel(ParallelPipelineHelper<S, T> helper) {
+        if (StreamOpFlags.ORDERED.isKnown(helper.getStreamFlags())) {
+            // @@@ Should be able to use a ctor ref here, but we get a runtime failure
+            return OpUtils.parallelReduce(helper, () -> new GroupBySink());
+        }
+        else {
+            final ConcurrentHashMap<K, Collection<T>> 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.OfValue<T>() {
+                @Override
+                public void apply(T t) {
+                    final Collection<T> sb = map.computeIfAbsent(mapper.map(t), (k) -> valueFactory.make());
+                    synchronized (sb) {
+                        sb.add(t);
+                    }
+                }
+            });
+
+            OpUtils.parallelForEach(helper, sinkChain);
+
+            return map;
+        }
+    }
+
+    private class GroupBySink implements OpUtils.AccumulatingSink<T, Map<K, Collection<T>>, GroupBySink> {
+        Map<K, Collection<T>> map;
+
+        @Override
+        public void begin(int size) {
+            map = new HashMap<>();
+        }
+
+        @Override
+        public void clearState() {
+            map = null;
+        }
+
+        @Override
+        public Map<K, Collection<T>> getAndClearState() {
+            Map<K, Collection<T>> result = map;
+            map = null;
+            return result;
+        }
+
+        @Override
+        public void apply(T t) {
+            K key = Objects.requireNonNull(mapper.map(t), String.format("The element %s cannot be mapped to a null key", t));
+            Collection<T> c = map.get(key);
+            if (c == null) {
+                c = valueFactory.make();
+                map.put(key, c);
+            }
+            c.add(t);
+        }
+
+        @Override
+        public void combine(GroupBySink other) {
+            for (Map.Entry<K, Collection<T>> e : other.map.entrySet()) {
+                if (map.containsKey(e.getKey())) {
+                    map.get(e.getKey()).addAll(e.getValue());
+                }
+                else {
+                    map.put(e.getKey(), e.getValue());
+                }
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/IntermediateOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,96 @@
+/*
+ * 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.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 StreamShapeFactory.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.StreamOpFlags}
+     */
+    default int getOpFlags() { return 0; }
+
+    /**
+     * 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 an iterator of the elements of the stream. The operation will be
+     * performed upon each element as it is returned by {@code Iterator.next()}.
+     *
+     *
+     * @param flags the combined stream and operation flags up to but not including this operation.
+     * @param in the source stream.
+     * @return an iterator of the elements of the stream.
+     */
+    Iterator<E_OUT> wrapIterator(int flags, Iterator<E_IN> in);
+
+    /**
+     * 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) {
+        // @@@ Can we determine the size from the pipeline and this operation?
+        final NodeBuilder<E_OUT> nb = outputShape().makeNodeBuilder(-1);
+        helper.into(wrapSink(helper.getStreamFlags(), nb));
+        return nb.build();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/MapOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,65 @@
+/*
+ * 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.Iterators;
+import java.util.Objects;
+import java.util.function.Mapper;
+import java.util.stream.Sink;
+import java.util.stream.StreamOpFlags;
+
+/**
+ * MapOp
+ *
+ * @author Brian Goetz
+ */
+public class MapOp<T, R> implements IntermediateOp<T, R> {
+    public final Mapper<? extends R, ? super T> mapper;
+
+    public MapOp(Mapper<? extends R, ? super T> mapper) {
+        this.mapper = Objects.requireNonNull(mapper);
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT;
+    }
+
+    @Override
+    public Iterator<R> wrapIterator(int flags, final Iterator<T> source) {
+        return Iterators.map(source, mapper);
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, Sink sink) {
+        return new Sink.ChainedValue<T>(sink) {
+            @Override
+            public void apply(T t) {
+                downstream.apply(mapper.map(t));
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/MatchOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,139 @@
+/*
+ * 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.concurrent.CountedCompleter;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Mapper;
+import java.util.function.Predicate;
+import java.util.stream.*;
+
+/**
+ * MatchOp
+ *
+ * @author Brian Goetz
+ */
+public class MatchOp<T> implements TerminalOp<T, Boolean> {
+    private final MatchKind matchKind;
+    private final Mapper<Boolean, Iterator<? extends T>> impl;
+    private final StreamShape inputShape;
+
+    private MatchOp(MatchKind matchKind, Mapper<Boolean, Iterator<? extends T>> impl, StreamShape shape) {
+        this.matchKind = matchKind;
+        this.impl = impl;
+        inputShape = shape;
+    }
+
+    public static<T> MatchOp<T> make(Predicate<? super T> predicate, MatchKind matchKind) {
+        return new MatchOp<T>(matchKind, it -> matchKind.match(it, predicate), StreamShapeFactory.REFERENCE);
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return inputShape;
+    }
+
+    @Override
+    public boolean isShortCircuit() {
+        return true;
+    }
+
+    @Override
+    public <S> Boolean evaluateSequential(PipelineHelper<S, T> helper) {
+        return evaluate(helper.iterator());
+    }
+
+    private Boolean evaluate(Iterator<T> iterator) {
+        return impl.map(iterator);
+    }
+
+    @Override
+    public <S> Boolean evaluateParallel(ParallelPipelineHelper<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 helper.invoke(new MatchTask<>(this, helper));
+    }
+
+    private static class MatchTask<S, T> extends AbstractShortCircuitTask<S, T, Boolean, MatchTask<S, T>> {
+        private final MatchOp<T> op;
+
+        private MatchTask(MatchOp<T> op, ParallelPipelineHelper<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.evaluate(helper.wrapIterator(spliterator.iterator()));
+            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;
+
+        MatchKind(boolean stopOnPredicateMatches, boolean shortCircuitResult) {
+            this.stopOnPredicateMatches = stopOnPredicateMatches;
+            this.shortCircuitResult = shortCircuitResult;
+        }
+
+        <T> boolean match(Iterator<? extends T> iterator, Predicate<? super T> predicate) {
+            while (iterator.hasNext()) {
+                if(predicate.test(iterator.next()) == stopOnPredicateMatches) {
+                    return shortCircuitResult;
+                }
+            }
+
+            return !shortCircuitResult;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/Node.java	Thu Nov 15 19:11:58 2012 -0800
@@ -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.op;
+
+import java.util.*;
+import java.util.stream.Spliterator;
+
+public interface Node<T> extends Iterable<T>, Sized {
+
+    /**
+     *
+     * @return the spliterator for this node.
+     */
+    Spliterator<T> spliterator();
+
+    /**
+     *
+     * @return the number of child nodes
+     */
+    default int getChildCount() {
+        return 0;
+    }
+
+    /**
+     *
+     * @return the child nodes.
+     */
+    default Iterator<? extends Node<T>> children() {
+        return Collections.emptyIterator();
+    }
+
+    /**
+     * Flatten this node to a node that has no children.
+     * <p>If this node has no children then this node may be returned.</p>
+     *
+     * @return a flattened node which has no children but holds the equivalent content as this node.
+     */
+    Node<T> flatten();
+
+    /**
+     * 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();
+
+    /**
+     * 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) throws IndexOutOfBoundsException;
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/NodeBuilder.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,66 @@
+/*
+ * 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.Sized;
+import java.util.function.UnaryOperator;
+import java.util.stream.Sink;
+
+/**
+ * A builder of a node.
+ *
+ * @author Brian Goetz
+ */
+// @@@ Implement Stream.Destination for bulk adding with addAll ? (see Nodes.node(Stream ) )
+public interface NodeBuilder<T> extends Iterable<T>, Sized, Sink.OfValue<T> {
+
+    /**
+     * Build the node.
+     *
+     * @return the built node.
+     */
+    Node<T> build();
+
+    /**
+     * Update all elements in place.
+     *
+     * @param operator the function to update elements
+     */
+    void forEachUpdate(UnaryOperator<T> operator);
+
+    /**
+     * A builder of a node that uses a fixed size array for holding content.
+     *
+     */
+    interface Fixed<T> extends NodeBuilder<T> {
+
+        /**
+         * Get the array that holds the node content.
+         *
+         * @return the array that holds the node content.
+         */
+        T[] getContent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/Nodes.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,1039 @@
+/*
+ * 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.UnaryOperator;
+import java.util.stream.*;
+
+public class Nodes {
+
+    private static final Node EMPTY_NODE = new EmptyNode();
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
+    public static<T> Node<T> emptyNode() {
+        return (Node<T>) EMPTY_NODE;
+    }
+
+    private static class EmptyNode<T> implements Node<T> {
+        @Override
+        public Spliterator<T> spliterator() {
+            return Streams. emptySpliterator();
+        }
+
+        @Override
+        public Node flatten() {
+            return this;
+        }
+
+        @Override
+        public T[] asArray() {
+            return (T[]) EMPTY_OBJECT_ARRAY;
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) throws IndexOutOfBoundsException { }
+
+        @Override
+        public Iterator<T> iterator() {
+            return Collections.emptyIterator();
+        }
+
+        @Override
+        public void forEach(Block<? super T> block) { }
+
+        @Override
+        public int size() {
+            return 0;
+        }
+    }
+
+    public static<T> Node<T> node(final T[] array) {
+        return new ArrayNode<>(array);
+    }
+
+    private static class ArrayNode<T> implements Node<T> {
+
+        final T[] array;
+        int curSize;
+
+        @SuppressWarnings("unchecked")
+        ArrayNode(int size) {
+            this.array = (T[]) new Object[size];
+            this.curSize = 0;
+        }
+
+        ArrayNode(T[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        // Node
+
+        @Override
+        public Node flatten() {
+            return this;
+        }
+
+        @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() {
+            if (array.length == curSize) {
+                return array;
+            } else {
+                return Arrays.copyOf(array, curSize);
+            }
+        }
+
+        // Traversable
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            for (int i = 0; i < curSize; i++) {
+                block.apply(array[i]);
+            }
+        }
+
+        // Iterable
+
+        @Override
+        public Iterator<T> iterator() {
+            return Arrays.iterator(array, 0, curSize);
+        }
+
+        // Sized
+
+        @Override
+        public int size() {
+            return curSize;
+        }
+
+        //
+
+        @Override
+        public int hashCode() {
+            return Nodes.hashCode(this);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return (obj instanceof Iterable) && Nodes.equals(this, (Iterable<?>) obj);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("ArrayNode[%d][%s]", array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    public static<T> Node<T> node(Collection<T> c) {
+        return new CollectionNode<>(c);
+    }
+
+    private static class CollectionNode<T> implements Node<T> {
+
+        final Collection<T> c;
+
+        CollectionNode(Collection<T> c) {
+            this.c = c;
+        }
+
+        // Node
+
+        @Override
+        public Node flatten() {
+            return this;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public Spliterator<T> spliterator() {
+            // @@@ Not very efficient
+            //     This requires a general way to obtain a spliterator from a collection
+            return Arrays.spliterator((T[]) c.toArray());
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            // @@@ Not very efficient
+            Objects.requireNonNull(array);
+            for (T t : this)
+                array[offset++] = t;
+        }
+
+        @Override
+        @SuppressWarnings("unchecked")
+        public T[] asArray() {
+            return (T[]) c.toArray();
+        }
+
+        // Traversable
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            c.forEach(block);
+        }
+
+        // Iterable
+
+        @Override
+        public Iterator<T> iterator() {
+            return c.iterator();
+        }
+
+        // Sized
+
+        @Override
+        public int size() {
+            return c.size();
+        }
+
+        //
+
+        @Override
+        public int hashCode() {
+            return Nodes.hashCode(this);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return (obj instanceof Iterable) && Nodes.equals(this, (Iterable<?>) obj);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("CollectionNode[%d][%s]", c.size(), c);
+        }
+    }
+
+    public static<T> Node<T> node(Streamable<Stream<T>> s) {
+        return node(s.parallel());
+    }
+
+    public static<T> Node<T> node(Stream<? extends T> stream) {
+        if (stream instanceof AbstractPipeline) {
+            // @@@ Yuk! the cast sucks, but it avoids uncessary wrapping
+            return ((AbstractPipeline<T, T>) stream).pipeline(CollectorOps.<T>terminalCollector());
+        }
+        else {
+            // @@@ This path can occur if there are other implementations of Stream
+            //     e.g. if the a Stream instance is a proxy
+            final NodeBuilder<T> nb = Nodes.makeVariableSizeBuilder();
+
+            // @@@ stream.into(sb) fails because the NodeBuilder does not implement the full contract
+            // of Collection
+            // @@@ NodeBuilder could implement Stream.Destination
+
+            nb.begin(-1);
+            Iterator<? extends T> i = stream.iterator();
+            while (i.hasNext())
+                nb.apply(i.next());
+            nb.end();
+
+            return nb.build();
+        }
+    }
+
+    @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);
+    }
+
+    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 ConcNodeSpliterator<>(this);
+        }
+
+        @Override
+        public int getChildCount() {
+            return nodes.length;
+        }
+
+        @Override
+        public Iterator<Node<T>> children() {
+            // @@@ This is more effiecient than Arrays.iterator(nodes)
+            //     which should be updated to not create an iteratable then an iterator
+            return new Iterator<Node<T>>() {
+                int i = 0;
+
+                @Override
+                public boolean hasNext() {
+                    return i < nodes.length;
+                }
+
+                @Override
+                public Node<T> next() {
+                    try {
+                        return nodes[i++];
+                    } catch (IndexOutOfBoundsException e) {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+
+        @Override
+        public Node<T> flatten() {
+            return TreeUtils.flatten(this);
+        }
+
+        @Override
+        public void copyInto(T[] array, int offset) {
+            Objects.requireNonNull(array);
+            TreeUtils.copyTo(this, array, offset);
+        }
+
+        @Override
+        public T[] asArray() {
+            return flatten().asArray();
+        }
+
+        // Traversable
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            for (Node<T> n : nodes)
+                n.forEach(block);
+        }
+
+        // Iterable
+
+        @Override
+        public Iterator<T> iterator() {
+            // @@@ Should do a depth first search and accummulate the leaf nodes then concat the iterators
+            return Iterators.concat(Arrays.stream(nodes).map(n -> n.iterator()).iterator());
+        }
+
+        // Sized
+
+        @Override
+        public int size() {
+            if (size == 0) {
+                for (Node<T> n : nodes)
+                    size += n.size();
+            }
+            return size;
+        }
+
+        //
+
+        @Override
+        public int hashCode() {
+            return Nodes.hashCode(this);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return (obj instanceof Iterable) && Nodes.equals(this, (Iterable<?>) obj);
+        }
+
+        @Override
+        public String toString() {
+            if (size() < 32) {
+                return String.format("ConcNode[%s]", Arrays.stream(nodes).map(n -> n.toString()).into(new StringJoiner(",")).toString());
+            } else {
+                return String.format("ConcNode[size=%d]", size());
+            }
+        }
+
+        private static class ConcNodeSpliterator<T> implements Spliterator<T> {
+            private Node<T> cur;
+            private Iterator<? extends Node<T>> children;
+            private int splitsLeft;
+            private Iterator<T> iterator;
+
+            private ConcNodeSpliterator(ConcNode<T> cur) {
+                this.cur = cur;
+                this.children = cur.children();
+                this.splitsLeft = cur.getChildCount() - 1;
+            }
+
+            public Iterator<T> iterator() {
+                if (iterator == null)
+                    iterator = cur.iterator();
+                return iterator;
+            }
+
+            @Override
+            public int getNaturalSplits() {
+                return splitsLeft;
+            }
+
+            @Override
+            public Spliterator<T> split() {
+                if (iterator != null)
+                    throw new IllegalStateException("split after iterate");
+                else if (splitsLeft == 0)
+                    return Streams.emptySpliterator();
+                else {
+                    Spliterator<T> ret = children.next().spliterator();
+                    if (--splitsLeft == 0) {
+                        cur = children.next();
+                        if (cur.getChildCount() > 0) {
+                            children = cur.children();
+                            splitsLeft = cur.getChildCount() - 1;
+                        }
+                        else {
+                            children = Collections.emptyIterator();
+                            splitsLeft = 0;
+                        }
+                    }
+                    return ret;
+                }
+            }
+
+            @Override
+            public void forEach(Block<? super T> block) {
+                if (iterator == null) {
+                    cur.forEach(block);
+                    iterator = Collections.emptyIterator();
+                }
+                else {
+                    while (iterator.hasNext())
+                        block.apply(iterator.next());
+                }
+            }
+
+            @Override
+            public int getSizeIfKnown() {
+                return (iterator == null) ? cur.size() : -1;
+            }
+
+            @Override
+            public boolean isPredictableSplits() {
+                return true;
+            }
+        }
+    }
+
+    // Node builders
+
+    /**
+     * 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> NodeBuilder<T> makeBuilder(int size) {
+        return (size >= 0) ? Nodes.<T>makeFixedSizeBuilder(size)
+                           : Nodes.<T>makeVariableSizeBuilder();
+    }
+
+    /**
+     * Make a fixed size builder.
+     *
+     * @param size the fixed size of the builder.
+     * @return the node builder.
+     */
+    public static <T> NodeBuilder<T> makeFixedSizeBuilder(int size) {
+        return new FixedNodeBuilder<>(size);
+    }
+
+    /**
+     * Make a variable size node builder.
+     *
+     * @return the node builder.
+     */
+    public static <T> NodeBuilder<T> makeVariableSizeBuilder() {
+        return new SpinedNodeBuilder<>();
+    }
+
+    private static class FixedNodeBuilder<T> extends ArrayNode<T> implements NodeBuilder.Fixed<T> {
+
+        private FixedNodeBuilder(int size) {
+            super(size);
+        }
+
+        @Override
+        public T[] getContent() {
+            return array;
+        }
+
+        //
+
+        @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 forEachUpdate(UnaryOperator<T> f) {
+            for (int i = 0; i < curSize; i++) {
+                array[i] = f.operate(array[i]);
+            }
+        }
+
+        //
+
+        @Override
+        public void begin(int 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 apply(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));
+        }
+    }
+
+    static class SpinedList<T> extends AbstractCollection<T> implements Sized {
+
+        protected static final int MIN_CHUNK_SIZE_POWER = 4;
+        protected static final int MIN_CHUNK_SIZE = 1 << MIN_CHUNK_SIZE_POWER;
+        protected static final int MAX_CHUNK_SIZE_POWER = 30; // can't be 2 << 31 because array max is 2 << 31 - 8
+        protected static final int MAX_CHUNK_SIZE = 1 << MAX_CHUNK_SIZE_POWER;
+        protected static final int CHUNKS_PER_SIZE_POWER = 2;
+        protected static final int CHUNKS_PER_SIZE = 1 << CHUNKS_PER_SIZE_POWER;
+        protected static final int ADJUSTED_OFFSET = 1 << (MIN_CHUNK_SIZE_POWER + CHUNKS_PER_SIZE_POWER);
+        protected static final int MIN_SPINE_SIZE = 8; // @@@ something with object allocation overhead.
+        protected static final int MAX_SPINE_SIZE = (MAX_CHUNK_SIZE_POWER - MIN_CHUNK_SIZE_POWER + 1) * CHUNKS_PER_SIZE;
+
+        protected int spineIndex = 0;
+        protected int chunkIndex = 0;
+        @SuppressWarnings("unchecked")
+        protected T[][] spine = (T[][])new Object[MIN_SPINE_SIZE][];
+        @SuppressWarnings("unchecked")
+        protected T[] chunk = spine[spineIndex] = (T[])new Object[MIN_CHUNK_SIZE];
+
+        private SpinedList(int initialSize) {
+            ensureCapacity(initialSize);
+        }
+
+        private SpinedList() {
+            this(MIN_CHUNK_SIZE);
+        }
+
+        protected final void ensureCapacity(long size) {
+            long adjusted = (Math.max(size, MIN_CHUNK_SIZE) - 1) + ADJUSTED_OFFSET;
+            int log2 = Long.SIZE - 1 - Long.numberOfLeadingZeros(adjusted);
+            int offset = (int) (((1L << (log2 - CHUNKS_PER_SIZE_POWER)) - 1) & adjusted);
+            int subchunk = (int) (adjusted - offset) >>> (log2 - CHUNKS_PER_SIZE_POWER) & (CHUNKS_PER_SIZE - 1);
+            int superchunk = (log2 - MIN_CHUNK_SIZE_POWER - CHUNKS_PER_SIZE_POWER) * CHUNKS_PER_SIZE;
+            int inChunk = superchunk + subchunk;
+
+            if(inChunk > spine.length) {
+                spine = Arrays.copyOf(spine, Math.min(inChunk, MAX_SPINE_SIZE));
+            }
+        }
+
+        protected static long totalSizeForSpineIndex(int spineIndex) {
+            assert spineIndex >= 0 && spineIndex < MAX_SPINE_SIZE : "index exceeds limit";
+            long base = 1L << (MIN_CHUNK_SIZE_POWER + CHUNKS_PER_SIZE_POWER + ((spineIndex + 1) / CHUNKS_PER_SIZE));
+            long partial = ((spineIndex + 1) % CHUNKS_PER_SIZE) * (long)sizeForSpineIndex(spineIndex);
+
+            return base + partial - ADJUSTED_OFFSET;
+        }
+
+        protected static int sizeForSpineIndex(int spineIndex) {
+            assert spineIndex >= 0 && spineIndex < MAX_SPINE_SIZE : "index exceeds limit";
+            return 1 << (MIN_CHUNK_SIZE_POWER + (spineIndex / CHUNKS_PER_SIZE));
+        }
+
+        protected void increaseCapacity() {
+            if (spineIndex + 1 == MAX_SPINE_SIZE) {
+                throw new IllegalStateException("Unable to expand capacity");
+            }
+
+            spineIndex += 1;
+            if(spineIndex == spine.length) {
+                spine = Arrays.copyOf(spine, Math.min(spine.length + MIN_SPINE_SIZE, MAX_SPINE_SIZE));
+            }
+
+            if (null == spine[spineIndex]) {
+                @SuppressWarnings("unchecked")
+                T[] newArray = (T[]) new Object[SpinedList.sizeForSpineIndex(spineIndex)];
+                spine[spineIndex] = newArray;
+            }
+
+            chunk = spine[spineIndex];
+            chunkIndex = 0;
+        }
+
+        // <editor-fold desc="Object">
+
+        @Override
+        public boolean equals(Object obj) {
+            return (obj instanceof Iterable) && Nodes.equals(this, (Iterable<?>) obj);
+        }
+
+        @Override
+        public int hashCode() {
+            return Nodes.hashCode(this);
+        }
+
+        // </editor-fold>
+
+        // <editor-fold desc="Iterable">
+
+        @Override
+        public Iterator<T> iterator() {
+            return iterator(0);
+        }
+
+        private Iterator<T> iterator(int startChunk) {
+            return new Iterator<T>() {
+                int currentChunk = startChunk;
+                int currentIndex = 0;
+
+                @Override
+                public boolean hasNext() {
+                    return currentChunk < SpinedList.this.spineIndex ||
+                            (currentChunk == SpinedList.this.spineIndex &&
+                            currentIndex <  SpinedList.this.chunkIndex);
+                }
+
+                @Override
+                public T next() {
+                    if (!hasNext()) {
+                        throw new NoSuchElementException();
+                    }
+
+                    T result = spine[currentChunk][currentIndex++];
+
+                    if (currentIndex == spine[currentChunk].length) {
+                        currentIndex = 0;
+                        currentChunk++;
+                    }
+
+                    return result;
+                }
+            };
+        }
+
+        // </editor-fold>
+
+        // <editor-fold desc="Collection">
+
+        @Override
+        public boolean add(T t) {
+            if (chunkIndex == chunk.length) {
+                increaseCapacity();
+            }
+            chunk[chunkIndex++] = t;
+
+            return true;
+        }
+
+        @Override
+        public void clear() {
+            // clear current values.
+            for(T[] aChunk : spine) {
+                if(null != aChunk) {
+                    Arrays.fill(aChunk, null);
+                } else {
+                    // first null is done.
+                    break;
+                }
+            }
+
+            // reset position.
+            chunk = spine[spineIndex = 0];
+            chunkIndex = 0;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return (spineIndex == 0) && (chunkIndex == 0);
+        }
+
+        @Override
+        public int size() {
+            return (spineIndex > 0)
+                    ? (int)Math.min(Integer.MAX_VALUE, totalSizeForSpineIndex(spineIndex - 1) + chunkIndex)
+                    : chunkIndex;
+        }
+
+        @Override
+        public Stream<T> stream() {
+            return Streams.stream(this, StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED);
+        }
+
+        @Override
+        public Stream<T> parallel() {
+            return Streams.parallel(spliterator(), StreamOpFlags.IS_ORDERED);
+        }
+
+        // </editor-fold>
+
+        // <editor-fold desc="List">
+
+//        @Override
+//        public T get(int index) {
+//            long adjusted = index + ADJUSTED_OFFSET;
+//            int log2 = Long.SIZE - 1 - Long.numberOfLeadingZeros(adjusted);
+//            int offset = (int) (((1L << (log2 - CHUNKS_PER_SIZE_POWER)) - 1) & adjusted);
+//            int subchunk = (int) (adjusted - offset) >>> (log2 - CHUNKS_PER_SIZE_POWER) & (CHUNKS_PER_SIZE - 1);
+//            int superchunk = (log2 - MIN_CHUNK_SIZE_POWER - CHUNKS_PER_SIZE_POWER) * CHUNKS_PER_SIZE;
+//            int inChunk = superchunk + subchunk;
+//
+//            return spine[inChunk][offset];
+//        }
+
+        // </editor-fold>
+
+        protected Spliterator<T> spliterator() {
+            return new SpinedListSpliterator();
+        }
+
+        class SpinedListSpliterator implements Spliterator<T>, Iterator<T>  {
+            Iterator<T> iterator = null;
+
+            boolean traversing = false;
+
+            boolean isSpinedSpliterator = true;
+
+            int spineOffset = 0;
+
+            T[] elements;
+
+            int offset;
+
+            int endOffset;
+
+            SpinedListSpliterator() {
+                if (spineOffset == spineIndex) {
+                    isSpinedSpliterator = false;
+                    elements = chunk;
+                    offset = 0;
+                    endOffset = chunkIndex;
+                }
+            }
+
+            private SpinedListSpliterator(T[] content, int offset, int endOffset) {
+                this.spineOffset = spineIndex;
+                this.elements = content;
+                this.offset = offset;
+                this.endOffset = endOffset;
+            }
+
+            @Override
+            public int getSizeIfKnown() {
+                if (isSpinedSpliterator) {
+                    // @@@ This will not return the correct known size if iterated on
+                    int result = SpinedList.this.size();
+                    if (spineOffset > 0) {
+                        result -= SpinedList.totalSizeForSpineIndex(spineOffset - 1);
+                    }
+
+                    return result;
+                } else {
+                    return endOffset - offset;
+                }
+            }
+
+            @Override
+            public Iterator<T> iterator() {
+                traversing = true;
+
+                if (iterator != null) {
+                    return iterator;
+                }
+
+                if (isSpinedSpliterator) {
+                    return iterator = SpinedList.this.iterator(spineOffset);
+                } else {
+                    return iterator = this;
+                }
+            }
+
+            @Override
+            public void forEach(Block<? super T> block) {
+                traversing = true;
+
+                if (isSpinedSpliterator) {
+                    iterator().forEach(block);
+                } else {
+                    for (int i = offset; i < endOffset; i++) {
+                        block.apply(elements[i]);
+                    }
+                    // update only once; reduce heap write traffic
+                    offset = endOffset;
+                }
+            }
+
+            @Override
+            public T next() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+
+                return elements[offset++];
+            }
+
+            @Override
+            public final boolean hasNext() {
+                return offset < endOffset;
+            }
+
+            @Override
+            public boolean isPredictableSplits() {
+                return true;
+            }
+
+            @Override
+            public int getNaturalSplits() {
+                if (traversing) {
+                    return 0;
+                }
+
+                if (isSpinedSpliterator) {
+                    return spineIndex - spineOffset + (chunkIndex > 1 ? 1 : 0);
+                } else {
+                    return (endOffset - offset > 1) ? 1 : 0;
+                }
+            }
+
+            @Override
+            public Spliterator<T> split() {
+                if (traversing) {
+                    throw new IllegalStateException("split after starting traversal");
+                }
+
+                if (isSpinedSpliterator) {
+                    Spliterator<T> ret = Arrays.spliterator(spine[spineOffset++]);
+
+                    if (spineOffset == spineIndex) {
+                        isSpinedSpliterator = false;
+                        elements = chunk;
+                        offset = 0;
+                        endOffset = chunkIndex;
+                    }
+
+                    return ret;
+                } else {
+                    int mid = (endOffset - offset) / 2;
+                    Spliterator<T> ret = Arrays.spliterator(elements, offset, mid);
+                    offset += mid;
+                    return ret;
+                }
+            }
+        }
+    }
+
+    private static class SpinedNodeBuilder<T> extends SpinedList<T> implements Node<T>, NodeBuilder<T> {
+
+        private boolean building = false;
+
+        @Override
+        public Stream<T> stream() {
+            assert !building : "during building";
+            return super.stream();
+        }
+
+        @Override
+        public Stream<T> parallel() {
+            assert !building : "during building";
+            return super.parallel();
+        }
+
+        public Collection<T> asCollection() {
+            assert !building : "during building";
+            return this;
+        }
+
+        protected Iterator<T> iterator(int startChunk) {
+            assert !building : "during building";
+            return super.iterator(startChunk);
+        }
+
+        @Override
+        public Spliterator<T> spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(Block<? super T> block) {
+            // completed chunks
+            for (int eachChunk = 0; eachChunk < spineIndex; eachChunk++) {
+                for (T t : spine[eachChunk]) {
+                    block.apply(t);
+                }
+            }
+
+            // current chunk
+            for (int index = 0; index < chunkIndex; index++) {
+                block.apply(chunk[index]);
+            }
+        }
+
+        @Override
+        public void forEachUpdate(UnaryOperator<T> f) {
+            for (int eachChunk = 0; eachChunk <= spineIndex; eachChunk++) {
+                T[] aChunk = spine[eachChunk];
+                int bounds = (eachChunk != spineIndex) ? aChunk.length : chunkIndex;
+                for (int element = 0; element < bounds; element++) {
+                    aChunk[element] = f.operate(aChunk[element]);
+                }
+            }
+        }
+
+        //
+        @Override
+        public void begin(int size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void apply(T t) {
+            assert building : "not building";
+            add(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";
+            int finalOffset = offset + size();
+            if (finalOffset > array.length || finalOffset < offset) {
+                throw new IndexOutOfBoundsException("does not fit");
+            }
+
+            // full chunks
+            for (int eachChunk = 0; eachChunk < spineIndex; eachChunk++) {
+                T[] aChunk = spine[eachChunk];
+                System.arraycopy(aChunk, 0, array, offset, aChunk.length);
+                offset += aChunk.length;
+            }
+
+            // final bit.
+            System.arraycopy(spine[spineIndex], 0, array, offset, chunkIndex);
+        }
+
+        @Override
+        public T[] asArray() {
+            assert !building : "during building";
+            @SuppressWarnings("unchecked")
+            T[] result = (T[]) new Object[size()]; // will fail for size == MAX_VALUE
+
+            copyInto(result, 0);
+
+            return result;
+        }
+
+        @Override
+        public Node<T> build() {
+            assert !building : "during building";
+            return this;
+        }
+
+        @Override
+        public Node flatten() {
+            return this;
+        }
+    }
+
+    private static boolean equals(Iterable<?> a, Iterable<?> b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        if(a instanceof Sized && b instanceof Sized) {
+            if ( ((Sized) a).size() != ((Sized) b).size()) {
+                return false;
+            }
+        }
+
+        Iterator it1 = a.iterator();
+        Iterator it2 = b.iterator();
+        while (it1.hasNext() && it2.hasNext()) {
+            Object x1 = it1.next();
+            Object x2 = it2.next();
+
+            if (!Objects.equals(x1, x2)) {
+                return false;
+            }
+        }
+
+        return !(it1.hasNext() || it2.hasNext());
+    }
+
+    private static <T> int hashCode(Iterable<T> it) {
+        int h = 0;
+        for (T t : it) {
+            h = 31 * h + Objects.hashCode(t);
+        }
+        return h;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/OpUtils.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,163 @@
+/*
+ * 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.function.Factory;
+import java.util.stream.*;
+
+/**
+ * OpUtils
+ *
+ * @author Brian Goetz
+ */
+public class OpUtils {
+    private OpUtils() {
+        throw new IllegalStateException("no instances");
+    }
+
+    /**
+     * Make a node builder from which to push output elements, where the input elements are obtained from
+     * a spliterator.
+     *
+     * <p>The builder will be optimized based on known size information of the spliterator and pipeline.</p>
+     *
+     * @param helper the pipeline helper.
+     * @param sp the spliterator containing input elements.
+     * @return a node builder.
+     */
+    public static<P_IN, P_OUT> NodeBuilder<P_OUT> makeNodeBuilderFor(PipelineHelper<P_IN, P_OUT> helper, Spliterator<P_IN> sp) {
+        return Nodes.makeBuilder(helper.getOutputSizeIfKnown() >= 0 ? sp.getSizeIfKnown() : -1);
+    }
+
+    /**
+     * 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.getSizeIfKnown());
+        sp.forEach(sink);
+        sink.end();
+    }
+
+    public static<P_IN, P_OUT> void parallelForEach(ParallelPipelineHelper<P_IN, P_OUT> helper, Sink<P_IN> sink) {
+        helper.invoke(new ForEachTask<>(helper, sink));
+    }
+
+    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 ForEachTask(ParallelPipelineHelper<S, T> helper, Sink<S> sink) {
+            super(helper);
+            this.sink = sink;
+        }
+
+        private ForEachTask(ForEachTask<S, T> parent, Spliterator<S> spliterator, Sink<S> sink) {
+            super(parent, spliterator);
+            this.sink = sink;
+        }
+
+        @Override
+        protected ForEachTask<S, T> makeChild(Spliterator<S> spliterator) {
+            return new ForEachTask<>(this, spliterator, sink);
+        }
+
+        @Override
+        protected Void doLeaf() {
+            intoWrapped(spliterator, 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(ParallelPipelineHelper<P_IN, P_OUT> helper, Factory<S> factory) {
+        S sink = helper.invoke(new ReduceTask<>(helper, factory));
+        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 Factory<S> sinkFactory;
+
+        private ReduceTask(ParallelPipelineHelper<P_IN, P_OUT> helper, Factory<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.make());
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter caller) {
+            if (!isLeaf()) {
+                ReduceTask<P_IN, P_OUT, R, S> child = children;
+                S result = child.getRawResult();
+                child = child.nextSibling;
+                for (; child != null; child = child.nextSibling) {
+                    S otherResult = child.getRawResult();
+                    result.combine(otherResult);
+                    otherResult.clearState();
+                }
+                setRawResult(result);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/ReduceByOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,159 @@
+/*
+ * 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.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BinaryOperator;
+import java.util.function.Combiner;
+import java.util.function.Factory;
+import java.util.function.Mapper;
+import java.util.stream.*;
+
+/**
+ * ReduceByOp
+ *
+ * @author Brian Goetz
+ */
+public class ReduceByOp<T, U, W> implements TerminalOp<T,Map<U,W>> {
+    private final Mapper<? extends U, ? super T> classifier;
+    private final Factory<W> seedFactory;
+    private final Combiner<W, W, T> reducer;
+    private final BinaryOperator<W> combiner;
+
+    public ReduceByOp(Mapper<? extends U, ? super T> classifier,
+                      Factory<W> seedFactory,
+                      Combiner<W, W, T> reducer,
+                      BinaryOperator<W> combiner) {
+        this.classifier = classifier;
+        this.seedFactory = seedFactory;
+        this.reducer = reducer;
+        this.combiner = combiner;
+    }
+
+    private TerminalSink<T, Map<U, W>> sink() {
+        return new TerminalSink<T, Map<U, W>>() {
+            Map<U, W> map;
+
+            @Override
+            public void begin(int size) {
+                map = new HashMap<>();
+            }
+
+            @Override
+            public Map<U, W> getAndClearState() {
+                try {
+                    return map;
+                }
+                finally {
+                    map = null;
+                }
+            }
+
+            @Override
+            public void apply(T t) {
+                U mapped = classifier.map(t);
+                W rVal = map.get(mapped);
+                if (rVal == null)
+                    rVal = seedFactory.make();
+                map.put(mapped, reducer.combine(rVal, t));
+            }
+        };
+    }
+
+    @Override
+    public <S> Map<U, W> evaluateSequential(PipelineHelper<S, T> helper) {
+        return helper.into(sink()).getAndClearState();
+    }
+
+    @Override
+    public <S> Map<U, W> evaluateParallel(ParallelPipelineHelper<S, T> helper) {
+        if (StreamOpFlags.ORDERED.isKnown(helper.getStreamFlags())) {
+            // @@@ Should be able to use a ctor ref here, but we get a runtime failure
+            return OpUtils.parallelReduce(helper, () -> new ReduceBySink());
+        }
+        else {
+            final ConcurrentHashMap<U, W> map = new ConcurrentHashMap<>();
+            final ConcurrentHashMap.Fun<? super U, ? extends W> seedFactoryAsCHMFun = (k) -> seedFactory.make();
+
+            // Cache the sink chain, so it can be reused by all F/J leaf tasks
+            Sink<S> sinkChain = helper.wrapSink(new Sink.OfValue<T>() {
+                @Override
+                public void apply(T t) {
+                    U key = classifier.map(t);
+                    W curValue = map.computeIfAbsent(key, seedFactoryAsCHMFun);
+                    while (!map.replace(key, curValue, reducer.combine(curValue, t)))
+                        curValue = map.get(key);
+                }
+            });
+
+            OpUtils.parallelForEach(helper, sinkChain);
+
+            return map;
+        }
+    }
+
+    private class ReduceBySink implements OpUtils.AccumulatingSink<T, Map<U, W>, ReduceBySink> {
+        Map<U, W> map;
+
+        @Override
+        public void begin(int size) {
+            map = new HashMap<>();
+        }
+
+        @Override
+        public void clearState() {
+            map = null;
+        }
+
+        @Override
+        public Map<U, W> getAndClearState() {
+            Map<U, W> result = map;
+            map = null;
+            return result;
+        }
+
+        @Override
+        public void apply(T t) {
+            U key = Objects.requireNonNull(classifier.map(t), String.format("The element %s cannot be mapped to a null key", t));
+            W r = map.get(key);
+            if (r == null)
+                r = seedFactory.make();
+            map.put(key, reducer.combine(r, t));
+        }
+
+        @Override
+        public void combine(ReduceBySink other) {
+            for (Map.Entry<U, W> e : other.map.entrySet()) {
+                U key = e.getKey();
+                W newValue = map.containsKey(key) ? combiner.operate(map.get(key), e.getValue()) : e.getValue();
+                map.put(key, newValue);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/SeedlessFoldOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,95 @@
+/*
+ * 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.Optional;
+import java.util.function.BinaryOperator;
+import java.util.stream.ParallelPipelineHelper;
+import java.util.stream.PipelineHelper;
+
+/**
+ * SeedlessFoldOp
+ *
+ * @author Brian Goetz
+ */
+public class SeedlessFoldOp<T> implements TerminalOp<T, Optional<T>> {
+    private final BinaryOperator<T> operator;
+
+    public SeedlessFoldOp(BinaryOperator<T> operator) {
+        this.operator = Objects.requireNonNull(operator);
+    }
+
+    public <S> Optional<T> evaluateSequential(PipelineHelper<S, T> helper) {
+        return helper.into(new FoldingSink()).getAndClearState();
+    }
+
+    @Override
+    public <S> Optional<T> evaluateParallel(ParallelPipelineHelper<S, T> helper) {
+        return OpUtils.parallelReduce(helper, () -> new FoldingSink());
+    }
+
+    /* private */ class FoldingSink implements OpUtils.AccumulatingSink<T, Optional<T>, FoldingSink> {
+        private boolean empty;
+        private T state;
+
+        @Override
+        public void begin(int size) {
+            empty = true;
+            state = null;
+        }
+
+        @Override
+        public void clearState() {
+            state = null;
+        }
+
+        @Override
+        public Optional<T> getAndClearState() {
+            try {
+                return empty ? Optional.<T>empty() : Optional.of(state);
+            }
+            finally {
+                state = null;
+            }
+        }
+
+        @Override
+        public void apply(T t) {
+            if (empty) {
+                empty = false;
+                state = t;
+            } else {
+                state = operator.operate(state, t);
+            }
+        }
+
+        @Override
+        public void combine(FoldingSink other) {
+            if (!other.empty)
+                apply(other.state);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/SliceOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -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.op;
+
+import java.util.*;
+import java.util.concurrent.CountedCompleter;
+import java.util.stream.ParallelPipelineHelper;
+import java.util.stream.Sink;
+import java.util.stream.Spliterator;
+import java.util.stream.StreamOpFlags;
+
+/**
+ * SliceOp
+ *
+ * @author Brian Goetz
+ */
+public class SliceOp<T> implements StatefulOp<T, T> {
+
+    private final int skip;
+    private final int limit;
+
+    public SliceOp(int skip, int limit) {
+        if (limit < 0)
+            throw new IllegalArgumentException("Limit must be non-negative: " + limit);
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+        this.skip = skip;
+        this.limit = limit;
+    }
+
+    public SliceOp(int skip) {
+        if (skip < 0)
+            throw new IllegalArgumentException("Skip must be non-negative: " + skip);
+        this.skip = skip;
+        this.limit = -1;
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED | ((limit != -1) ? StreamOpFlags.IS_SHORT_CIRCUIT : 0);
+    }
+
+    private int getFinalSize(ParallelPipelineHelper helper) {
+        int size = helper.getOutputSizeIfKnown();
+        if (size >= 0) {
+            size = Math.max(0, size - skip);
+            if (limit >= 0)
+                size = Math.min(size, limit);
+        }
+        return size;
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, Sink sink) {
+        Objects.requireNonNull(sink);
+        if (limit == -1) {
+            return new Sink.ChainedValue<T>(sink) {
+                int n = skip;
+
+                @Override
+                public void apply(T t) {
+                    if (n == 0) {
+                        downstream.apply(t);
+                    }
+                    else {
+                        n--;
+                    }
+                }
+            };
+        }
+        else
+            // No push for short-circuit operations
+            throw new IllegalStateException("Cannot do push-evaluation of short-circuit stream operation");
+    }
+
+    @Override
+    public Iterator<T> wrapIterator(int flags, Iterator<T> source) {
+        return (limit == 0)
+               ? Collections.emptyIterator()
+               : new SliceIterator<>(source, skip, limit);
+    }
+
+    @Override
+    public <S> Node<T> evaluateParallel(ParallelPipelineHelper<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, if we are a left-spine node, and we have the desired slice covered, cancel rest
+        // - @@@ this can be significantly improved
+
+        // @@@ Currently we don't do the sized version at all
+
+//        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 helper.invoke(new SliceTask<>(helper, skip, limit));
+    }
+
+    @Override
+    public String toString() {
+        return String.format("SliceOp[skip=%d,limit=%d]", skip, limit);
+    }
+
+    private static class SliceIterator<T> implements Iterator<T> {
+
+        private final Iterator<T> source;
+
+        private int toSkip;
+        private int toConsume;
+        private boolean noLimit;
+
+        public SliceIterator(Iterator<T> source, int skip, int limit) {
+            Objects.requireNonNull(source);
+            noLimit = (limit == -1);
+
+            this.source = source;
+            this.toSkip = skip;
+            this.toConsume = limit;
+        }
+
+        @Override
+        public boolean hasNext() {
+            while (toSkip > 0 && source.hasNext()) {
+                source.next();
+                toSkip--;
+            }
+            if (toSkip > 0)
+                return false;
+            else if (noLimit || toConsume > 0)
+                return source.hasNext();
+            else
+                return false;
+        }
+
+        @Override
+        public T next() {
+            if (!hasNext())
+                throw new NoSuchElementException("No Current Element");
+
+            toConsume--;
+            return source.next();
+        }
+    }
+
+    private static class SliceTask<S, T> extends AbstractShortCircuitTask<S, T, Node<T>, SliceTask<S, T>> {
+        private final int targetOffset, targetSize;
+        private int thisNodeSize;
+
+        private SliceTask(ParallelPipelineHelper<S, T> helper, int offset, int size) {
+            super(helper);
+            targetOffset = offset;
+            targetSize = size;
+        }
+
+        private SliceTask(SliceTask<S, T> parent, Spliterator<S> spliterator) {
+            super(parent, spliterator);
+            targetOffset = parent.targetOffset;
+            targetSize = parent.targetSize;
+        }
+
+        @Override
+        protected SliceTask<S, T> makeChild(Spliterator<S> spliterator) {
+            return new SliceTask<>(this, spliterator);
+        }
+
+        @Override
+        protected Node<T> getEmptyResult() {
+            return Nodes.emptyNode();
+        }
+
+        @Override
+        protected Node<T> doLeaf() {
+            if (!isRoot()) {
+                NodeBuilder<T> nodeBuilder = Nodes.<T>makeBuilder(-1);
+                OpUtils.intoUnwrapped(helper, spliterator, nodeBuilder);
+                thisNodeSize = nodeBuilder.size();
+                return nodeBuilder.build();
+            }
+            else {
+                return truncateToNode(-1, helper.wrapIterator(spliterator.iterator()), targetOffset, targetSize);
+            }
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter<?> caller) {
+            if (!isLeaf()) {
+                thisNodeSize = 0;
+                for (SliceTask<S, T> child = children; child != null; child = child.nextSibling)
+                    thisNodeSize += child.thisNodeSize;
+                if (isLeftSpine()
+                    && ((isRoot())
+                        || (targetSize >= 0 && thisNodeSize >= targetOffset + targetSize))) {
+                    ArrayList<Node> nodes = new ArrayList<>();
+                    visit(nodes, 0);
+                    Node<T> result;
+                    if (nodes.size() == 0)
+                        result = Nodes.emptyNode();
+                    else if (nodes.size() == 1)
+                        result = nodes.get(0);
+                    else
+                        result = Nodes.node(nodes.toArray(new Node[nodes.size()]));
+                    setRawResult(result);
+                    shortCircuit(result);
+                }
+            }
+        }
+
+        private void visit(ArrayList<Node> 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(getRawResult(),
+                                                 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(getRawResult(), 0,
+                                                 targetSize >= 0 ? Math.max(0, offset+thisNodeSize - (targetOffset + targetSize)) : 0));
+                    }
+                }
+            }
+        }
+
+        private Node<T> truncateToNode(int size, Iterator<T> iterator, int skip, int targetSize) {
+            NodeBuilder<T> nodeBuilder = Nodes.<T>makeBuilder(size);
+            nodeBuilder.begin(size);
+            for (int i = 0; iterator.hasNext() && i < skip; i++)
+                iterator.next();
+            for (int i = 0; iterator.hasNext() && ((targetSize == -1) || (i < targetSize)); i++)
+                nodeBuilder.apply(iterator.next());
+            nodeBuilder.end();
+            return nodeBuilder.build();
+        }
+
+        private Node<T> truncateNode(Node<T> input, int skipLeft, int skipRight) {
+            if (skipLeft == 0 && skipRight == 0)
+                return input;
+            else {
+                int truncatedSize = thisNodeSize - skipLeft - skipRight;
+                return truncateToNode(truncatedSize, input.iterator(), skipLeft, truncatedSize);
+            }
+        }
+    }
+
+    // @@@ 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/op/SortedOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,184 @@
+/*
+ * 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.ForkJoinUtils;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.ParallelPipelineHelper;
+import java.util.stream.Sink;
+import java.util.stream.StreamOpFlags;
+
+
+/**
+ * An operation which sorts elements.
+ *
+ * @param <T> Type of elements to be sorted.
+ *
+ * @author Brian Goetz
+ */
+public class SortedOp<T> implements StatefulOp<T, T> {
+    private static final int DEFAULT_PRIORITY_QUEUE_SIZE = 16;
+
+    /**
+     * Comparator used for sorting.
+     */
+    private final Comparator<? super T> comparator;
+
+    /**
+     * Sort using natural order of {@literal <T>} which must be
+     * {@code Comparable}.
+     */
+    public SortedOp() {
+        // Will throw CCE when we try to sort if T is not Comparable
+        this((Comparator<? super T>) Comparators.naturalOrder());
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.IS_SORTED | StreamOpFlags.IS_ORDERED;
+    }
+
+    /**
+     * Sort using the provided comparator.
+     *
+     * @param comparator The comparator to be used to evaluate ordering.
+     */
+    public SortedOp(Comparator<? super T> comparator) {
+        this.comparator = Objects.requireNonNull(comparator);
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, Sink sink) {
+        if (StreamOpFlags.SORTED.isKnown(flags)) {
+            return sink;
+        }
+        else if (StreamOpFlags.SIZED.isKnown(flags)) {
+            // Optimized version if we know the size
+            return new Sink.ChainedValue<T>(sink) {
+                T[] array;
+                int offset;
+
+                @Override
+                public void begin(int size) {
+                    array = (T[]) new Object[size];
+                }
+
+                @Override
+                public void end() {
+                    Arrays.sort(array, comparator);
+                    downstream.begin(array.length);
+                    for (T t : array)
+                        downstream.apply(t);
+                    downstream.end();
+                    array = null;
+                }
+
+                @Override
+                public void apply(T t) {
+                    array[offset++] = t;
+                }
+            };
+        }
+        else {
+            return new Sink.ChainedValue<T>(sink) {
+                ArrayList<T> list;
+
+                @Override
+                public void begin(int size) {
+                    list = new ArrayList<>();
+                }
+
+                @Override
+                public void end() {
+                    list.sort(comparator);
+                    downstream.begin(list.size());
+                    list.forEach(e -> downstream.apply(e));
+                    downstream.end();
+                    list = null;
+                }
+
+                @Override
+                public void apply(T t) {
+                    list.add(t);
+                }
+            };
+        }
+    }
+
+    @Override
+    public Iterator<T> wrapIterator(int flags, Iterator<T> iterator) {
+        Objects.requireNonNull(iterator);
+        if (StreamOpFlags.SORTED.isKnown(flags)) {
+            return iterator;
+        }
+        else {
+            return iterator(iterator, comparator);
+        }
+    }
+
+    public static <T> Iterator<T> iterator(Iterator<? extends T> iterator, Comparator<? super T> comparator) {
+        Objects.requireNonNull(iterator);
+        Objects.requireNonNull(comparator);
+
+        return new Iterator<T>() {
+            Iterator<T> sortedIterator = null;
+
+            @Override
+            public boolean hasNext() {
+                if (sortedIterator == null) {
+                    List<T> list = new ArrayList<>();
+                    while (iterator.hasNext())
+                        list.add(iterator.next());
+                    list.sort(comparator);
+                    sortedIterator = list.iterator();
+                }
+                return sortedIterator.hasNext();
+            }
+
+            @Override
+            public T next() {
+                if (hasNext())
+                    return sortedIterator.next();
+                else
+                    throw new NoSuchElementException();
+            }
+        };
+    }
+
+    public <P_IN> Node<T> evaluateParallel(ParallelPipelineHelper<P_IN, T> helper) {
+        if (StreamOpFlags.SORTED.isKnown(helper.getStreamFlags())) {
+            return helper.collectOutput();
+        }
+        else {
+            // @@@ Weak two-pass parallel implementation; parallel collect, parallel sort
+            T[] flattenedData = helper.collectOutput().flatten().asArray();
+            ForkJoinUtils.parallelSort(flattenedData, comparator);
+            return Nodes.node(flattenedData);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/StatefulOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,19 @@
+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_IN> Type of input elements.
+ * @param <E_OUT> Type of output elements.
+ *
+ */
+public interface StatefulOp<E_IN, E_OUT> extends IntermediateOp<E_IN, E_OUT> {
+
+    @Override
+    public default boolean isStateful() {
+        return true;
+    }
+
+    // @@@ re-abstract evaluateParallel?
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/StreamOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,70 @@
+/*
+ * 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.ParallelPipelineHelper;
+import java.util.stream.PipelineHelper;
+import java.util.stream.StreamShape;
+import java.util.stream.StreamShapeFactory;
+
+/**
+ * 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 StreamShapeFactory.REFERENCE; }
+
+    /**
+     * Evaluate the result of the operation in parallel.
+     *
+     * @param helper
+     * @param <P_IN> Type of elements input to the pipeline.
+     * @return the result of the operation.
+     */
+    default <P_IN> R evaluateParallel(ParallelPipelineHelper<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);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/TeeOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,75 @@
+/*
+ * 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.Objects;
+import java.util.function.Block;
+import java.util.stream.Sink;
+
+/**
+ * TeeOp
+ */
+public class TeeOp<T> implements IntermediateOp<T, T> {
+    public final Block<? super T> tee;
+
+    public TeeOp(Block<? super T> tee) {
+        this.tee = Objects.requireNonNull(tee);
+    }
+
+    @Override
+    public Iterator<T> wrapIterator(int flags, final Iterator<T> source) {
+        return iterator(source, tee);
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, Sink sink) {
+        return new Sink.ChainedValue<T>(sink) {
+            @Override
+            public void apply(T t) {
+                tee.apply(t);
+                downstream.apply(t);
+            }
+        };
+    }
+
+    public static<T> Iterator<T> iterator(final Iterator<T> source, final Block<? super T> tee) {
+        Objects.requireNonNull(source);
+        Objects.requireNonNull(tee);
+        return new Iterator<T>() {
+            @Override
+            public boolean hasNext() {
+                return source.hasNext();
+            }
+
+            @Override
+            public T next() {
+                T next = source.next();
+                tee.apply(next);
+                return next;
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/TerminalOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,39 @@
+/*
+ * 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;
+
+/**
+ * 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> {
+
+    default boolean isShortCircuit() { return false; }
+
+    // @@@ re-abstract evaluateParallel?
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/ToArrayOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,53 @@
+/*
+ * 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.ParallelPipelineHelper;
+import java.util.stream.PipelineHelper;
+
+/**
+ * ToArrayOp
+ * <p/>
+ * @author Brian Goetz
+ */
+public class ToArrayOp<T> implements TerminalOp<T, Object[]> {
+
+    private final static ToArrayOp<?> INSTANCE = new ToArrayOp<>();
+
+    @SuppressWarnings("unchecked")
+    public static <T> ToArrayOp<T> singleton() {
+        return (ToArrayOp<T>) INSTANCE;
+    }
+
+    @Override
+    public <S> Object[] evaluateSequential(PipelineHelper<S, T> helper) {
+        return helper.collectOutput().flatten().asArray();
+    }
+
+    @Override
+    public <P_IN> Object[] evaluateParallel(ParallelPipelineHelper<P_IN, T> helper) {
+        return helper.collectOutput().flatten().asArray();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/op/TreeUtils.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,225 @@
+/*
+ * 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.Iterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.concurrent.ForkJoinUtils;
+import java.util.stream.ParallelPipelineHelper;
+import java.util.stream.PipelineHelper;
+import java.util.stream.Spliterator;
+
+/**
+ * Collector
+ *
+ * @author Brian Goetz
+ */
+public class TreeUtils {
+    private TreeUtils() {
+        throw new Error("no instances");
+    }
+
+    // @@@ make public ?
+    private static<P_IN, P_OUT> Node<P_OUT> collectSequentially(PipelineHelper<P_IN, P_OUT> helper, Spliterator<P_IN> spliterator) {
+        NodeBuilder<P_OUT> builder = OpUtils.makeNodeBuilderFor(helper, spliterator);
+        OpUtils.intoWrapped(spliterator, helper.wrapSink(builder));
+        return builder.build();
+    }
+
+    public static <P_IN, P_OUT> Node<P_OUT> collect(ParallelPipelineHelper<P_IN, P_OUT> helper,
+                                                    boolean flattenTree) {
+        Spliterator<P_IN> spliterator = helper.spliterator();
+        if (!helper.suggestSplit(spliterator)) {
+            return collectSequentially(helper, spliterator);
+        } else {
+            int size = spliterator.getSizeIfKnown();
+            if (size >= 0 && helper.getOutputSizeIfKnown() == size && spliterator.isPredictableSplits()) {
+                P_OUT[] array = (P_OUT[]) new Object[size];
+                helper.invoke(new SizedCollectorTask<>(spliterator, helper, array));
+                return Nodes.node(array);
+            } else {
+                CollectorTask<P_IN, P_OUT> task = new CollectorTask<>(helper);
+                helper.invoke(task);
+                Node<P_OUT> node = task.getRawResult();
+
+                // @@@ using default F/J pool, will that be different from that used by helper.invoke?
+                return flattenTree ? flatten(node) : node;
+            }
+        }
+    }
+
+    public static <T> Node<T> flatten(Node<T> node) {
+        if (node.getChildCount() > 0) {
+            T[] array = (T[]) new Object[node.size()];
+            new ToArrayTask<>(node, array, 0).invoke();
+            return Nodes.node(array);
+        } else {
+            return node;
+        }
+    }
+
+    public static <T> void copyTo(Node<T> node, T[] array, int offset) {
+        // @@@ Currently only used by Nodes.ConcNode
+        if (node.getChildCount() > 0) {
+            new ToArrayTask<>(node, array, offset).invoke();
+        } else {
+            node.copyInto(array, offset);
+        }
+    }
+
+    private static class CollectorTask<T, U> extends AbstractTask<T, U, Node<U>, CollectorTask<T, U>> {
+        private final ParallelPipelineHelper<T, U> helper;
+
+        private CollectorTask(ParallelPipelineHelper<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() {
+            return collectSequentially(helper, spliterator);
+        }
+
+        @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.getRawResult();
+                setRawResult(Nodes.node(nodes));
+            }
+        }
+    }
+
+    private static class SizedCollectorTask<T, U> extends CountedCompleter<Void> {
+        private final Spliterator<T> spliterator;
+        private final ParallelPipelineHelper<T, U> helper;
+        private final U[] array;
+        private int offset;
+        private int length;
+
+        private SizedCollectorTask(Spliterator<T> spliterator, ParallelPipelineHelper<T, U> helper, U[] array) {
+            this.spliterator = spliterator;
+            this.helper = helper;
+            this.array = array;
+            this.offset = 0;
+            this.length = array.length;
+        }
+
+        private SizedCollectorTask(SizedCollectorTask<T, U> parent, Spliterator<T> spliterator, int offset, int length) {
+            super(parent);
+            this.spliterator = spliterator;
+            this.helper = parent.helper;
+            this.array = parent.array;
+            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() {
+            if (!helper.suggestSplit(spliterator)) {
+                OpUtils.intoUnwrapped(helper, spliterator, Arrays.sink(array, offset, length));
+                tryComplete();
+            }
+            else {
+                int naturalSplits = spliterator.getNaturalSplits();
+                setPendingCount(naturalSplits);
+                int s = 0;
+                for (int i = 0; i < naturalSplits; i++) {
+                    Spliterator<T> split = spliterator.split();
+                    int thisSplitSize = split.getSizeIfKnown();
+
+                    SizedCollectorTask<T, U> task = new SizedCollectorTask<>(this, split, offset + s, thisSplitSize);
+                    task.fork();
+
+                    s += thisSplitSize;
+                }
+
+                SizedCollectorTask<T, U> task = new SizedCollectorTask<>(this, spliterator, offset + s, length - s);
+                task.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 Iterator<? extends Node<T>> itNodes = node.children();
+
+                final ToArrayTask<T> firstTask = new ToArrayTask<>(this, itNodes.next(), offset);
+                int size = firstTask.node.size();
+
+                while (itNodes.hasNext()) {
+                    final ToArrayTask<T> task = new ToArrayTask<>(this, itNodes.next(), offset + size);
+                    size += task.node.size();
+                    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/op/UniqOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,287 @@
+/*
+ * 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.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.stream.ParallelPipelineHelper;
+import java.util.stream.Sink;
+import java.util.stream.StreamOpFlags;
+
+/**
+ * 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, T> {
+    private static UniqOp<?> INSTANCE = new UniqOp<>();
+
+    public UniqOp() {
+    }
+
+    public static <T> UniqOp<T> singleton() {
+        return (UniqOp<T>) INSTANCE;
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.IS_DISTINCT | StreamOpFlags.NOT_SIZED;
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, Sink sink) {
+        Objects.requireNonNull(sink);
+
+        if (StreamOpFlags.DISTINCT.isKnown(flags)) {
+            return sink;
+        }
+        else if (StreamOpFlags.SORTED.isKnown(flags)) {
+            return new Sink.ChainedValue<T>(sink) {
+                T lastSeen;
+
+                @Override
+                public void begin(int size) {
+                    lastSeen = null;
+                    downstream.begin(-1);
+                }
+
+                @Override
+                public void end() {
+                    lastSeen = null;
+                    downstream.end();
+                }
+
+                @Override
+                public void apply(T t) {
+                    if (lastSeen == null || !t.equals(lastSeen)) {
+                        downstream.apply(lastSeen = t);
+                    }
+                }
+            };
+        }
+        else {
+            return new Sink.ChainedValue<T>(sink) {
+                Set<T> seen;
+
+                @Override
+                public void begin(int size) {
+                    seen = new HashSet<>();
+                    downstream.begin(-1);
+                }
+
+                @Override
+                public void end() {
+                    seen = null;
+                    downstream.end();
+                }
+
+                @Override
+                public void apply(T t) {
+                    if (seen.add(t)) {
+                        downstream.apply(t);
+                    }
+                }
+            };
+        }
+    }
+
+    @Override
+    public Iterator<T> wrapIterator(int flags, final Iterator<T> iterator) {
+        Objects.requireNonNull(iterator);
+
+        if (StreamOpFlags.DISTINCT.isKnown(flags)) {
+            return iterator;
+        }
+        else if (StreamOpFlags.SORTED.isKnown(flags)) {
+            return new CacheElementIterator<T>() {
+                T lastSeen;
+
+                @Override
+                public boolean hasNext() {
+                    if (cache != null)
+                        return true;
+
+                    // cache is empty so attempt to populate it
+                    while (iterator.hasNext()) {
+                        T t = iterator.next();
+                        if (lastSeen == null || !t.equals(lastSeen)) {
+                            lastSeen = cache = t;
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            };
+        }
+        else {
+            return new CacheElementIterator<T>() {
+                final Set<T> seen = new HashSet<>();
+
+                @Override
+                public boolean hasNext() {
+                    if (cache != null)
+                        return true;
+
+                    // cache is empty so attempt to populate it
+                    while (iterator.hasNext()) {
+                        T t = iterator.next();
+                        if (!seen.contains(t)) {
+                            seen.add(t);
+                            cache = t;
+                            return true;
+                        }
+                    }
+                    return false;
+                }
+            };
+        }
+    }
+
+    private static abstract class CacheElementIterator<T> implements Iterator<T> {
+        // Null if empty, non-null if valid. Obviously
+        // does not allow nulls as stream values.
+        T cache = null;
+
+        @Override
+        public T next() {
+            if (hasNext()) {
+                T r = cache;
+                cache = null;
+                return r;
+            }
+            else {
+                throw new NoSuchElementException();
+            }
+        }
+    }
+
+    @Override
+    public <S> Node<T> evaluateParallel(ParallelPipelineHelper<S, T> helper) {
+        if (StreamOpFlags.DISTINCT.isKnown(helper.getStreamFlags())) {
+            // No-op
+            return helper.collectOutput();
+        }
+        else if (StreamOpFlags.SORTED.isKnown(helper.getStreamFlags())) {
+            if (!StreamOpFlags.ORDERED.isKnown(helper.getStreamFlags())) {
+                // @@@ Does this make sense?
+            }
+
+            Set<T> s = OpUtils.parallelReduce(helper, () -> new UniqByPreserveOrderAfterSortedSink<T>());
+            return Nodes.node(s);
+        }
+        else {
+            if (StreamOpFlags.ORDERED.isKnown(helper.getStreamFlags())) {
+                Set<T> s = OpUtils.parallelReduce(helper, () -> new UniqByPreserveOrderSink<T>());
+                return Nodes.node(s);
+            }
+            else {
+                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.OfValue<T>() {
+                    @Override
+                    public void apply(T t) {
+                        map.putIfAbsent(t, Boolean.TRUE);
+                    }
+                });
+
+                OpUtils.parallelForEach(helper, sinkChain);
+
+                return Nodes.node(map.keySet());
+            }
+        }
+    }
+
+    private static abstract class AbstractUniqByPreserveOrderSink<T, S extends AbstractUniqByPreserveOrderSink<T, S>>
+            implements OpUtils.AccumulatingSink<T, Set<T>, S> {
+        Set<T> set;
+
+        @Override
+        public void begin(int 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 apply(T t) {
+            set.add(t);
+        }
+
+        @Override
+        public void combine(S other) {
+            set.addAll(other.set);
+        }
+    }
+
+    // Keep the type system happy
+    private static class UniqByPreserveOrderSink<T>
+            extends AbstractUniqByPreserveOrderSink<T, UniqByPreserveOrderSink<T>> { }
+
+    private static class UniqByPreserveOrderAfterSortedSink<T>
+            extends AbstractUniqByPreserveOrderSink<T, UniqByPreserveOrderAfterSortedSink<T>> {
+        T lastSeen;
+
+        @Override
+        public void begin(int size) {
+            lastSeen = null;
+            super.begin(size);
+        }
+
+        @Override
+        public void clearState() {
+            lastSeen = null;
+            super.clearState();
+        }
+
+        @Override
+        public Set<T> getAndClearState() {
+            lastSeen = null;
+            return super.getAndClearState();
+        }
+
+        @Override
+        public void apply(T t) {
+            if (lastSeen == null || !t.equals(lastSeen)) {
+                super.apply(lastSeen = t);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntBlock.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,40 @@
+/*
+ * 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.primitive;
+
+import java.util.function.Block;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public interface IntBlock extends Block<Integer> {
+
+    @Override
+    default void apply(Integer i) {
+        Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using boxed int", getClass().getName());
+        applyInt(i.intValue());
+    }
+
+    void applyInt(int i);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntCollectorOps.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,88 @@
+/*
+ * 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.primitive;
+
+import java.util.stream.StreamOpFlags;
+import java.util.stream.StreamShape;
+import java.util.stream.StreamShapeFactory;
+import java.util.stream.op.CollectorOps;
+
+public final class IntCollectorOps {
+
+    private IntCollectorOps() {
+    }
+
+    private static Sequential<?> SEQUENTIAL_COLLECTOR_OP = new Sequential<>();
+
+    @SuppressWarnings("unchecked")
+    public static <E_IN> Sequential<E_IN> sequentialCollector() {
+        return (Sequential<E_IN>) SEQUENTIAL_COLLECTOR_OP;
+    }
+
+    private static Parallel<?> PARALLEL_COLLECTOR_OP = new Parallel<>();
+
+    @SuppressWarnings("unchecked")
+    public static <E_IN> Parallel<E_IN> parallelCollector() {
+        return (Parallel<E_IN>) PARALLEL_COLLECTOR_OP;
+    }
+
+    private static Terminal<?> TERMINAL_COLLECTOR_OP = new Terminal<>();
+
+    @SuppressWarnings("unchecked")
+    public static <E_IN> Terminal<E_IN> terminalCollector() {
+        return (Terminal<E_IN>) TERMINAL_COLLECTOR_OP;
+    }
+
+    public static class Parallel<E_IN> extends CollectorOps.Parallel<Integer> {
+        @Override
+        public StreamShape inputShape() { return StreamShapeFactory.INT_VALUE; }
+
+        @Override
+        public StreamShape outputShape() { return StreamShapeFactory.INT_VALUE; }
+    }
+
+    /**
+     * Collect elements into a Node, if evaluated in parallel, and force sequential evaluation on upstream operations,
+     * otherwise, if evaluated sequentially, this operation is a no-op.
+     */
+    public static class Sequential<E_IN> extends Parallel<E_IN> {
+
+        private Sequential() { }
+
+        @Override
+        public int getOpFlags() {
+            return StreamOpFlags.NOT_PARALLEL;
+        }
+    }
+
+    /**
+     * Collect elements into a Node that is the result of terminal evaluation.
+     */
+    public static class Terminal<E_IN> extends CollectorOps.Terminal<Integer> {
+        @Override
+        public StreamShape inputShape() { return StreamShapeFactory.INT_VALUE; }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntFactory.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,40 @@
+/*
+ * 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.primitive;
+
+import java.util.function.Factory;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public interface IntFactory extends Factory<Integer> {
+
+    @Override
+    default Integer make() {
+        Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using boxed int", getClass().getName());
+        return makeInt();
+    }
+
+    int makeInt();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntFilterOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,104 @@
+/*
+ * 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.primitive;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.stream.Sink;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.StreamShape;
+import java.util.stream.StreamShapeFactory;
+import java.util.stream.op.IntermediateOp;
+
+public class IntFilterOp implements IntermediateOp<Integer, Integer> {
+    public final IntPredicate predicate;
+
+    public IntFilterOp(IntPredicate predicate) {
+        this.predicate = Objects.requireNonNull(predicate);
+    }
+
+    @Override
+    public StreamShape inputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public StreamShape outputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED;
+    }
+
+    @Override
+    public IntIterator wrapIterator(int flags, Iterator<Integer> source) {
+        return iterator(source, predicate);
+    }
+
+    @Override
+    public IntSink wrapSink(int flags, Sink sink) {
+        Objects.requireNonNull(sink);
+
+        IntSink intSink = Primitives.adapt(sink);
+        return new IntSink.ChainedValue(intSink) {
+            @Override
+            public void applyInt(int t) {
+                if (predicate.testInt(t))
+                    downstream.applyInt(t);
+            }
+        };
+    }
+
+    public static IntIterator iterator(Iterator<Integer> source, final IntPredicate predicate) {
+        Objects.requireNonNull(source);
+        Objects.requireNonNull(predicate);
+
+        final IntIterator intSource = Primitives.adapt(source);
+        return new IntIterator() {
+            boolean nextReady = false;
+            int nextValue;
+
+            @Override
+            public boolean hasNext() {
+                while (!nextReady && intSource.hasNext()) {
+                    nextValue = intSource.nextInt();
+                    nextReady = predicate.testInt(nextValue);
+                }
+
+                return nextReady;
+            }
+
+            @Override
+            public int nextInt() {
+                if (nextReady || hasNext()) {
+                    nextReady = false;
+                    return nextValue;
+                }
+
+                throw new NoSuchElementException();
+            }
+        };
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntForEachOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,54 @@
+/*
+ * 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.primitive;
+
+import java.util.Objects;
+import java.util.stream.StreamShape;
+import java.util.stream.StreamShapeFactory;
+import java.util.stream.op.ForEachOp;
+
+public class IntForEachOp extends ForEachOp<Integer> {
+
+    protected IntForEachOp(IntTerminalSink<Void> sink, StreamShape shape) {
+        super(sink, shape);
+    }
+
+    public static IntForEachOp make(final IntBlock block) {
+        Objects.requireNonNull(block);
+        return new IntForEachOp(new IntTerminalSink<Void>() {
+
+            @Override
+            public void applyInt(int i) {
+                block.applyInt(i);
+            }
+
+            @Override
+            public Void getAndClearState() {
+                return null;
+            }
+        }, StreamShapeFactory.INT_VALUE);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntIterable.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,56 @@
+/*
+ * 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.primitive;
+
+import java.util.Iterator;
+import java.util.function.Block;
+
+public interface IntIterable extends Iterable<Integer> {
+
+    @Override
+    default void forEach(Block<? super Integer> sink) {
+        if (sink instanceof IntBlock) {
+            forEach((IntBlock) sink);
+        }
+        else {
+            IntIterator remaining = iterator();
+            while (remaining.hasNext()) {
+                sink.apply(remaining.nextInt());
+            }
+        }
+    }
+
+    @Override
+    IntIterator iterator();
+
+    //
+
+    default void forEach(IntBlock sink) {
+        IntIterator remaining = iterator();
+        while (remaining.hasNext()) {
+            sink.applyInt(remaining.nextInt());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntIterator.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,64 @@
+/*
+ * 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.primitive;
+
+import java.util.Iterator;
+import java.util.function.Block;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public interface IntIterator extends Iterator<Integer> {
+
+    // Iterator<Integer>
+
+    @Override
+    default Integer next() {
+        Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using boxed int", getClass().getName());
+        return nextInt();
+    }
+
+
+    @Override
+    default void forEach(Block<? super Integer> sink) {
+        if (sink instanceof IntBlock) {
+            forEach((IntBlock) sink);
+        }
+        else {
+            while (hasNext()) {
+                sink.apply(nextInt());
+            }
+        }
+    }
+
+    //
+
+    int nextInt();
+
+    default void forEach(IntBlock sink) {
+        while (hasNext()) {
+            sink.applyInt(nextInt());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntLimitOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,121 @@
+/*
+ * 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.primitive;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.stream.*;
+import java.util.stream.op.Node;
+import java.util.stream.op.NodeBuilder;
+import java.util.stream.op.Nodes;
+import java.util.stream.op.StatefulOp;
+
+public class IntLimitOp implements StatefulOp<Integer, Integer> {
+
+    private final int limit;
+
+    public IntLimitOp(int limit) {
+        if (limit < 0)
+            throw new IllegalArgumentException("Limit must be non-negative: " + limit);
+
+        this.limit = limit;
+    }
+
+    @Override
+    public StreamShape inputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public StreamShape outputShape() { return StreamShapeFactory.INT_VALUE; }
+
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SIZED | StreamOpFlags.IS_SHORT_CIRCUIT;
+    }
+
+    @Override
+    public IntSink wrapSink(int flags, Sink sink) {
+        // @@@ Cannot short circuit the sink
+        // @@@ This smells somewhat
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public IntIterator wrapIterator(int flags, Iterator<Integer> source) {
+        return iterator(Primitives.adapt(source), limit);
+    }
+
+    @Override
+    public <S> Node<Integer> evaluateParallel(ParallelPipelineHelper<S, Integer> helper) {
+        // Dumb serial implementation defering to iterator
+        final IntIterator i = wrapIterator(helper.getStreamFlags(), helper.iterator());
+
+        final IntNodeBuilder nb = IntNodes.makeBuilder(Math.min(helper.getOutputSizeIfKnown(), limit));
+        i.forEach(nb);
+        return nb.build();
+    }
+
+    public static IntIterator iterator(IntIterator source, int limit) {
+        return (limit > 0)
+               ? new LimitingIntIterator(source, limit)
+               : Primitives.emptyIntIterator();
+    }
+
+    static class LimitingIntIterator implements IntIterator {
+
+        private final IntIterator source;
+
+        private int limit;
+
+        public LimitingIntIterator(IntIterator source, int limit) {
+            Objects.requireNonNull(source);
+            if (limit < 0)
+                throw new IllegalArgumentException("Limit must be non-negative: " + limit);
+
+            this.source = source;
+            this.limit = limit;
+        }
+
+        @Override
+        public boolean hasNext() {
+            if (limit > 0)
+                return source.hasNext();
+
+            return false;
+        }
+
+        @Override
+        public int nextInt() {
+            if (!hasNext())
+                throw new NoSuchElementException("No Current Element");
+
+            limit--;
+            return source.nextInt();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntMapOp.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,86 @@
+/*
+ * 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.primitive;
+
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.stream.Sink;
+import java.util.stream.StreamOpFlags;
+import java.util.stream.StreamShape;
+import java.util.stream.StreamShapeFactory;
+import java.util.stream.op.IntermediateOp;
+
+public class IntMapOp implements IntermediateOp<Integer, Integer> {
+    private final IntUnaryOperator mapper;
+
+    public IntMapOp(IntUnaryOperator mapper) {
+        this.mapper = Objects.requireNonNull(mapper);
+    }
+
+    @Override
+    public StreamShape inputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public StreamShape outputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT;
+    }
+
+    @Override
+    public IntIterator wrapIterator(int flags, final Iterator<Integer> source) {
+        return iterator(source, mapper);
+    }
+
+    @Override
+    public IntSink wrapSink(int flags, Sink<Integer> sink) {
+        IntSink intSink = Primitives.adapt(Objects.requireNonNull(sink));
+
+        return new IntSink.ChainedValue(intSink) {
+            @Override
+            public void applyInt(int t) {
+                downstream.applyInt(mapper.operateInt(t));
+            }
+        };
+    }
+
+    public static IntIterator iterator(final Iterator<Integer> source, final IntUnaryOperator mapper) {
+        Objects.requireNonNull(mapper);
+        IntIterator intSource = Primitives.adapt(Objects.requireNonNull(source));
+
+        return new IntIterator() {
+            @Override
+            public boolean hasNext() {
+                return intSource.hasNext();
+            }
+
+            @Override
+            public int nextInt() {
+                return mapper.operateInt(intSource.nextInt());
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntNode.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,62 @@
+/*
+ * 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.primitive;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.stream.op.Node;
+
+public interface IntNode extends Node<Integer>, IntIterable {
+
+    // Node
+
+
+    @Override
+    default Iterator<IntNode> children() {
+        return Collections.emptyIterator();
+    }
+
+    @Override
+    IntSpliterator spliterator();
+
+    @Override
+    IntNode flatten();
+
+    @Override
+    default Integer[] asArray() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    default void copyInto(Integer[] array, int offset) throws IndexOutOfBoundsException {
+        throw new UnsupportedOperationException();
+    }
+
+    //
+
+    int[] asIntArray();
+
+    void copyInto(int[] array, int offset) throws IndexOutOfBoundsException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntNodeBuilder.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,61 @@
+/*
+ * 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.primitive;
+
+import java.util.function.UnaryOperator;
+import java.util.stream.op.NodeBuilder;
+
+public interface IntNodeBuilder extends NodeBuilder<Integer>, IntIterable, IntSink {
+
+    @Override
+    IntNode build();
+
+    @Override
+    default void forEachUpdate(UnaryOperator<Integer> operator) {
+        if (operator instanceof IntUnaryOperator) {
+            forEachUpdate((IntUnaryOperator) operator);
+        }
+        else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    @Override
+    IntIterator iterator();
+
+    //
+
+    void forEachUpdate(IntUnaryOperator operator);
+
+    interface Fixed extends IntNodeBuilder {
+
+        /**
+         * Get the array that holds the node content.
+         *
+         * @return the array that holds the node content.
+         */
+        int[] getContent();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/stream/primitive/IntNodes.java	Thu Nov 15 19:11:58 2012 -0800
@@ -0,0 +1,899 @@
+/*
+ * 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.primitive;
+
+import java.util.*;
+import java.util.function.Block;
+import java.util.function.UnaryOperator;
+import java.util.stream.*;
+import java.util.stream.op.CollectorOps;
+import java.util.stream.op.Node;
+import java.util.stream.op.NodeBuilder;
+import java.util.stream.op.TreeUtils;
+
+public class IntNodes {
+    public static IntNode node(final int[] array) {
+        return new IntArrayNode(array);
+    }
+
+    private static class IntArrayNode implements IntNode {
+
+        final int[] array;
+        int curSize;
+
+        IntArrayNode(int size) {
+            this.array = new int[size];
+            this.curSize = 0;
+        }
+
+        IntArrayNode(int[] array) {
+            this.array = array;
+            this.curSize = array.length;
+        }
+
+        // Node
+
+        @Override
+        public IntNode flatten() {
+            return this;
+        }
+
+        @Override
+        public IntSpliterator spliterator() {
+            return Primitives.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);
+        }
+
+        // Traversable
+
+        @Override
+        public void forEach(IntBlock sink) {
+            for (int i = 0; i < curSize; i++) {
+                sink.applyInt(array[i]);
+            }
+        }
+
+        // Iterable
+
+        @Override
+        public IntIterator iterator() {
+            return Primitives.iterator(array, 0, curSize);
+        }
+
+        // Sized
+
+        @Override
+        public int size() {
+            return curSize;
+        }
+
+        //
+
+        @Override
+        public boolean equals(Object obj) {
+            return (obj instanceof IntIterable) && IntNodes.equals(this, (IntIterable) obj);
+        }
+
+        @Override
+        public int hashCode() {
+            return IntNodes.hashCode(this);
+        }
+
+        @Override
+        public String toString() {
+            return String.format("IntArrayNode[%d][%s]", array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+    public static IntNode node(Streamable<IntStream> s) {
+        return node(s.parallel());
+    }
+
+    public static IntNode node(IntStream stream) {
+        if (stream instanceof AbstractPipeline) {
+            // @@@ Yuk! the cast sucks, but it avoids unnecessary wrapping
+            return (IntNode) ((AbstractPipeline<Integer, Integer>) stream).pipeline(IntCollectorOps.terminalCollector());
+        }
+        else {
+            // @@@ This path can occur if there are other implementations of Stream
+            //     e.g. if the a Stream instance is a proxy
+            final IntNodeBuilder nb = makeVariableSizeBuilder();
+
+            // @@@ stream.into(sb) fails because the NodeBuilder does not implement the full contract
+            // of Collection
+            // @@@ NodeBuilder could implement Stream.Destination
+
+            nb.begin(-1);
+            stream.iterator().forEach(nb);
+
+            return nb.build();
+        }
+    }
+
+    @SafeVarargs
+    public static IntNode node(IntNode... 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 IntConcNode(nodes);
+    }
+
+    private static class IntConcNode implements IntNode {
+        final IntNode[] nodes;
+        int size = 0;
+
+        private IntConcNode(IntNode[] nodes) {
+            this.nodes = nodes;
+        }
+
+        // Node
+
+        @Override
+        public IntSpliterator spliterator() {
+            return new IntConcNodeSpliterator(this);
+        }
+
+        @Override
+        public int getChildCount() {
+            return nodes.length;
+        }
+
+        @Override
+        public Iterator<IntNode> children() {
+            // @@@ This is more effiecient than Arrays.iterator(nodes)
+            //     which should be updated to not create an iteratable then an iterator
+            return new Iterator<IntNode>() {
+                int i = 0;
+
+                @Override
+                public boolean hasNext() {
+                    return i < nodes.length;
+                }
+
+                @Override
+                public IntNode next() {
+                    try {
+                        return nodes[i++];
+                    } catch (IndexOutOfBoundsException e) {
+                        throw new NoSuchElementException();
+                    }
+                }
+            };
+        }
+
+        @Override
+        public IntNode flatten() {
+            return IntTreeUtils.flatten(this);
+        }
+
+        @Override
+        public int[] asIntArray() {
+            return flatten().asIntArray();
+        }
+
+        @Override
+        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
+            IntTreeUtils.copyTo(this, array, offset);
+        }
+
+        // Traversable
+
+        @Override
+        public void forEach(IntBlock sink) {
+            for (IntNode n : nodes)
+                n.forEach(sink);
+        }
+
+        // Iterable
+
+        @Override
+        public IntIterator iterator() {
+            // @@@ Should do a depth first search and accummulate the leaf nodes then concat the iterators
+            return Primitives.concat(Arrays.stream(nodes).map(n -> n.iterator()).iterator());
+        }
+
+        // Sized
+
+        @Override
+        public int size() {
+            if (size == 0) {
+                for (IntNode n : nodes)
+                    size += n.size();
+            }
+            return size;
+        }
+
+        //
+
+        @Override
+        public boolean equals(Object obj) {
+            return (obj instanceof IntIterable) && IntNodes.equals(this, (IntIterable) obj);
+        }
+
+        @Override
+        public int hashCode() {
+            return IntNodes.hashCode(this);
+        }
+
+        @Override
+        public String toString() {
+            if (size() < 32) {
+                return String.format("IntConcNode[%s]", Arrays.stream(nodes).map(n -> n.toString()).into(new StringJoiner(",")).toString());
+            } else {
+                return String.format("IntConcNode[size=%d]", size());
+            }
+        }
+
+        private static class IntConcNodeSpliterator implements IntSpliterator {
+            private IntNode cur;
+            private Iterator<IntNode> children;
+            private int splitsLeft;
+            private IntIterator iterator;
+
+            private IntConcNodeSpliterator(IntConcNode cur) {
+                this.cur = cur;
+                this.children = cur.children();
+                this.splitsLeft = cur.getChildCount() - 1;
+            }
+
+            public IntIterator iterator() {
+                if (iterator == null)
+                    iterator = cur.iterator();
+                return iterator;
+            }
+
+            @Override
+            public int getNaturalSplits() {
+                return splitsLeft;
+            }
+
+            @Override
+            public IntSpliterator split() {
+                if (iterator != null)
+                    throw new IllegalStateException("split after iterate");
+                else if (splitsLeft == 0)
+                    return Primitives.emptyIntSpliterator();
+                else {
+                    IntSpliterator ret = nextChild().spliterator();
+                    if (--splitsLeft == 0) {
+                        cur = nextChild();
+                        if (cur.getChildCount() > 0) {
+                            children = cur.children();
+                            splitsLeft = cur.getChildCount() - 1;
+                        }
+                        else {
+                            children = Collections.emptyIterator();
+                            splitsLeft = 0;
+                        }
+                    }
+                    return ret;
+                }
+            }
+
+            private IntNode nextChild() {
+                return children.next();
+            }
+
+            @Override
+            public void forEach(Block<? super Integer> block) {
+                if (iterator == null) {
+                    cur.forEach(block);
+                    iterator = Primitives.emptyIntIterator();
+                }
+                else {
+                    while (iterator.hasNext())
+                        block.apply(iterator.nextInt());
+                }
+            }
+
+            @Override
+            public void forEach(IntBlock block) {
+                if (iterator == null) {
+                    cur.forEach(block);
+                    iterator = Primitives.emptyIntIterator();
+                }
+                else {
+                    while (iterator.hasNext())
+                        block.applyInt(iterator.nextInt());
+                }
+            }
+
+            @Override
+            public int getSizeIfKnown() {
+                return (iterator == null) ? cur.size() : -1;
+            }
+
+            @Override
+            public boolean isPredictableSplits() {
+                return true;
+            }
+        }
+    }
+
+    // Node builders
+
+    /**
+     * 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 IntNodeBuilder makeBuilder(int size) {
+        return (size >= 0) ? makeFixedSizeBuilder(size)
+                           : makeVariableSizeBuilder();
+    }
+
+    /**
+     * Make a fixed size builder.
+     *
+     * @param size the fixed size of the builder.
+     * @return the node builder.
+     */
+    public static IntNodeBuilder makeFixedSizeBuilder(int size) {
+        return new FixedIntNodeBuilder(size);
+    }
+
+    /**
+     * Make a variable size node builder.
+     *
+     * @return the node builder.
+     */
+    public static IntNodeBuilder makeVariableSizeBuilder() {
+        return new IntSpinedNodeBuilder();
+    }
+
+    private static class FixedIntNodeBuilder extends IntArrayNode implements IntNodeBuilder.Fixed {
+
+        private FixedIntNodeBuilder(int size) {
+            super(size);
+        }
+
+        @Override
+        public int[] getContent() {
+            return array;
+        }
+
+        //
+
+        @Override
+        public IntNode 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 forEachUpdate(IntUnaryOperator f) {
+            for (int i = 0; i < curSize; i++) {
+                array[i] = f.operateInt(array[i]);
+            }
+        }
+
+        //
+
+        @Override
+        public void begin(int 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 applyInt(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("FixedNodeBuilder[%d][%s]", array.length - curSize, Arrays.toString(array));
+        }
+    }
+
+
+    static class IntSpinedList implements IntIterable, Sized, IntBlock {
+
+        protected static final int MIN_CHUNK_SIZE_POWER = 4;
+        protected static final int MIN_CHUNK_SIZE = 1 << MIN_CHUNK_SIZE_POWER;
+        protected static final int MAX_CHUNK_SIZE_POWER = 30; // can't be 2 << 31 because array max is 2 << 31 - 8
+        protected static final int MAX_CHUNK_SIZE = 1 << MAX_CHUNK_SIZE_POWER;
+        protected static final int CHUNKS_PER_SIZE_POWER = 2;
+        protected static final int CHUNKS_PER_SIZE = 1 << CHUNKS_PER_SIZE_POWER;
+        protected static final int ADJUSTED_OFFSET = 1 << (MIN_CHUNK_SIZE_POWER + CHUNKS_PER_SIZE_POWER);
+        protected static final int MIN_SPINE_SIZE = 8; // @@@ something with object allocation overhead.
+        protected static final int MAX_SPINE_SIZE = (MAX_CHUNK_SIZE_POWER - MIN_CHUNK_SIZE_POWER + 1) * CHUNKS_PER_SIZE;
+
+        protected int spineIndex = 0;
+        protected int chunkIndex = 0;
+        @SuppressWarnings("unchecked")
+        protected int[][] spine = new int[MIN_SPINE_SIZE][];
+        @SuppressWarnings("unchecked")
+        protected int[] chunk = spine[spineIndex] = new int[MIN_CHUNK_SIZE];
+
+        private IntSpinedList(int initialSize) {
+            ensureCapacity(initialSize);
+        }
+
+        private IntSpinedList() {
+            this(MIN_CHUNK_SIZE);
+        }
+
+        protected final void ensureCapacity(long size) {
+            long adjusted = (Math.max(size, MIN_CHUNK_SIZE) - 1) + ADJUSTED_OFFSET;
+            int log2 = Long.SIZE - 1 - Long.numberOfLeadingZeros(adjusted);
+            int offset = (int) (((1L << (log2 - CHUNKS_PER_SIZE_POWER)) - 1) & adjusted);
+            int subchunk = (int) (adjusted - offset) >>> (log2 - CHUNKS_PER_SIZE_POWER) & (CHUNKS_PER_SIZE - 1);
+            int superchunk = (log2 - MIN_CHUNK_SIZE_POWER - CHUNKS_PER_SIZE_POWER) * CHUNKS_PER_SIZE;
+            int inChunk = superchunk + subchunk;
+
+            if(inChunk > spine.length) {
+                spine = Arrays.copyOf(spine, Math.min(inChunk, MAX_SPINE_SIZE));
+            }
+        }
+
+        protected static long totalSizeForSpineIndex(int spineIndex) {
+            assert spineIndex >= 0 && spineIndex < MAX_SPINE_SIZE : "index exceeds limit";
+            long base = 1L << (MIN_CHUNK_SIZE_POWER + CHUNKS_PER_SIZE_POWER + ((spineIndex + 1) / CHUNKS_PER_SIZE));
+            long partial = ((spineIndex + 1) % CHUNKS_PER_SIZE) * (long)sizeForSpineIndex(spineIndex);
+
+            return base + partial - ADJUSTED_OFFSET;
+        }
+
+        protected static int sizeForSpineIndex(int spineIndex) {
+            assert spineIndex >= 0 && spineIndex < MAX_SPINE_SIZE : "index exceeds limit";
+            return 1 << (MIN_CHUNK_SIZE_POWER + (spineIndex / CHUNKS_PER_SIZE));
+        }
+
+        protected void increaseCapacity() {
+            if (spineIndex + 1 == MAX_SPINE_SIZE) {
+                throw new IllegalStateException("Unable to expand capacity");
+            }
+
+            spineIndex += 1;
+            if(spineIndex == spine.length) {
+                spine = Arrays.copyOf(spine, Math.min(spine.length + MIN_SPINE_SIZE, MAX_SPINE_SIZE));
+            }
+
+            if (null == spine[spineIndex]) {
+                @SuppressWarnings("unchecked")
+                int[] newArray = new int[IntSpinedList.sizeForSpineIndex(spineIndex)];
+                spine[spineIndex] = newArray;
+            }
+
+            chunk = spine[spineIndex];
+            chunkIndex = 0;
+        }
+
+        @Override
+        public IntIterator iterator() {
+            return iterator(0);
+        }
+
+        private IntIterator iterator(int startChunk) {
+            return new IntIterator() {
+                int currentChunk = startChunk;
+                int currentIndex = 0;
+
+                @Override
+                public boolean hasNext() {
+                    return currentChunk < IntSpinedList.this.spineIndex ||
+                           (currentChunk == IntSpinedList.this.spineIndex &&
+                            currentIndex <  IntSpinedList.this.chunkIndex);
+                }
+
+                @Override
+                public int nextInt() {
+                    if (!hasNext()) {
+                        throw new NoSuchElementException();
+                    }
+
+                    int result = spine[currentChunk][currentIndex++];
+
+                    if (currentIndex == spine[currentChunk].length) {
+                        currentIndex = 0;
+                        currentChunk++;
+                    }
+
+                    return result;
+                }
+            };
+        }
+
+        @Override
+        public void applyInt(int i) {
+            if (chunkIndex == chunk.length) {
+                increaseCapacity();
+            }
+            chunk[chunkIndex++] = i;
+        }
+
+        public void clear() {
+            // reset position.
+            chunk = spine[spineIndex = 0];
+            chunkIndex = 0;
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return (spineIndex == 0) && (chunkIndex == 0);
+        }
+
+        @Override
+        public int size() {
+            return (spineIndex > 0)
+                   ? (int)Math.min(Integer.MAX_VALUE, totalSizeForSpineIndex(spineIndex - 1) + chunkIndex)
+                   : chunkIndex;
+        }
+
+        public IntStream stream() {
+            return Primitives.stream(this, StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED);
+        }
+
+        public IntStream parallel() {
+            return Primitives.stream(spliterator(), StreamOpFlags.IS_ORDERED);
+        }
+
+        protected IntSpliterator spliterator() {
+            return new SpinedListSpliterator();
+        }
+
+        class SpinedListSpliterator implements IntSpliterator, IntIterator {
+            IntIterator iterator = null;
+
+            boolean traversing = false;
+
+            boolean isSpinedSpliterator = true;
+
+            int spineOffset = 0;
+
+            int[] elements;
+
+            int offset;
+
+            int endOffset;
+
+            SpinedListSpliterator() {
+                if (spineOffset == spineIndex) {
+                    isSpinedSpliterator = false;
+                    elements = chunk;
+                    offset = 0;
+                    endOffset = chunkIndex;
+                }
+            }
+
+            private SpinedListSpliterator(int[] content, int offset, int endOffset) {
+                this.spineOffset = spineIndex;
+                this.elements = content;
+                this.offset = offset;
+                this.endOffset = endOffset;
+            }
+
+            @Override
+            public int getSizeIfKnown() {
+                if (isSpinedSpliterator) {
+                    // @@@ This will not return the correct known size if iterated on
+                    int result = IntSpinedList.this.size();
+                    if (spineOffset > 0) {
+                        result -= IntSpinedList.totalSizeForSpineIndex(spineOffset - 1);
+                    }
+
+                    return result;
+                } else {
+                    return endOffset - offset;
+                }
+            }
+
+            @Override
+            public IntIterator iterator() {
+                traversing = true;
+
+                if (iterator != null) {
+                    return iterator;
+                }
+
+                if (isSpinedSpliterator) {
+                    return iterator = IntSpinedList.this.iterator(spineOffset);
+                } else {
+                    return iterator = this;
+                }
+            }
+
+            @Override
+            public void forEach(Block<? super Integer> block) {
+                traversing = true;
+
+                IntIterator.super.forEach(block);
+            }
+
+            @Override
+            public void forEach(IntBlock block) {
+                traversing = true;
+
+                if (isSpinedSpliterator) {
+                    iterator().forEach(block);
+                } else {
+                    for (int i = offset; i < endOffset; i++) {
+                        block.applyInt(elements[i]);
+                    }
+                    // update only once; reduce heap write traffic
+                    offset = endOffset;
+                }
+            }
+
+            @Override
+            public int nextInt() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+
+                return elements[offset++];
+            }
+
+            @Override
+            public final boolean hasNext() {
+                return offset < endOffset;
+            }
+
+            @Override
+            public boolean isPredictableSplits() {
+                return true;
+            }
+
+            @Override
+            public int getNaturalSplits() {
+                if (traversing) {
+                    return 0;
+                }
+
+                if (isSpinedSpliterator) {
+                    return spineIndex - spineOffset + (chunkIndex > 1 ? 1 : 0);
+                } else {
+                    return (endOffset - offset > 1) ? 1 : 0;
+                }
+            }
+
+            @Override
+            public IntSpliterator split() {
+                if (traversing) {
+                    throw new IllegalStateException("split after starting traversal");
+                }
+
+                if (isSpinedSpliterator) {
+                    IntSpliterator ret = Primitives.spliterator(spine[spineOffset++]);
+
+                    if (spineOffset == spineIndex) {
+                        isSpinedSpliterator = false;
+                        elements = chunk;
+                        offset = 0;
+                        endOffset = chunkIndex;
+                    }
+
+                    return ret;
+                } else {
+                    int mid = (endOffset - offset) / 2;
+                    IntSpliterator ret = Primitives.spliterator(elements, offset, mid);
+                    offset += mid;
+                    return ret;
+                }
+            }
+        }
+    }
+
+    private static class IntSpinedNodeBuilder extends IntSpinedList implements IntNode, IntNodeBuilder {
+
+        private boolean building = false;
+
+        @Override
+        public IntStream stream() {
+            assert !building : "during building";
+            return super.stream();
+        }
+
+        @Override
+        public IntStream parallel() {
+            assert !building : "during building";
+            return super.parallel();
+        }
+
+        public IntIterable asIterable() {
+            assert !building : "during building";
+            return this;
+        }
+
+        protected IntIterator iterator(int startChunk) {
+            assert !building : "during building";
+            return super.iterator(startChunk);
+        }
+
+        @Override
+        public IntSpliterator spliterator() {
+            assert !building : "during building";
+            return super.spliterator();
+        }
+
+        @Override
+        public void forEach(IntBlock block) {
+            // completed chunks
+            for (int ci = 0; ci < spineIndex; ci++) {
+                int[] chunk = spine[ci];
+                for (int i = 0; i < chunk.length; i++) {
+                    block.applyInt(chunk[i]);
+                }
+            }
+
+            // current chunk
+            for (int i = 0; i < chunkIndex; i++) {
+                block.applyInt(chunk[i]);
+            }
+        }
+
+        @Override
+        public void forEachUpdate(IntUnaryOperator f) {
+            for (int eachChunk = 0; eachChunk <= spineIndex; eachChunk++) {
+                int[] aChunk = spine[eachChunk];
+                int bounds = (eachChunk != spineIndex) ? aChunk.length : chunkIndex;
+                for (int element = 0; element < bounds; element++) {
+                    aChunk[element] = f.operateInt(aChunk[element]);
+                }
+            }
+        }
+
+        //
+        @Override
+        public void begin(int size) {
+            assert !building : "was already building";
+            building = true;
+            clear();
+            ensureCapacity(size);
+        }
+
+        @Override
+        public void applyInt(int i) {
+            super.applyInt(i);
+        }
+
+        @Override
+        public void end() {
+