changeset 6400:507817d66484

Support for int-based streams and testing of. Can serve as a template for long and double-based streams. This commit does not go to any length, and deliberately so, to consolidate functionality. The initial objective is to get int-based streams working such that no boxing is performed, then iterate on that functionality.
author psandoz
date Wed, 14 Nov 2012 18:49:41 +0100
parents abcf56edb55c
children dd7327fe3467
files src/share/classes/java/util/streams/ReferencePipeline.java src/share/classes/java/util/streams/Stream.java src/share/classes/java/util/streams/StreamShapeFactory.java src/share/classes/java/util/streams/ops/Nodes.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/streams/OpTestCase.java test-ng/tests/org/openjdk/tests/java/util/streams/StreamIntermediateOpTestScenario.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/IntNodeTest.java test-ng/tests/org/openjdk/tests/java/util/streams/ops/PrimitiveOpsTests.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
diffstat 39 files changed, 4679 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/streams/ReferencePipeline.java	Wed Nov 14 12:21:20 2012 -0500
+++ b/src/share/classes/java/util/streams/ReferencePipeline.java	Wed Nov 14 18:49:41 2012 +0100
@@ -30,6 +30,8 @@
 import java.util.Optional;
 import java.util.functions.*;
 import java.util.streams.ops.*;
+import java.util.streams.primitives.RefToIntMapOp;
+import java.util.streams.primitives.IntStream;
 
 /**
  * A pipeline of elements that are references to objects of type <code>T</code>.
@@ -60,6 +62,11 @@
     }
 
     @Override
+    public IntStream mapToInt(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));
     }
--- a/src/share/classes/java/util/streams/Stream.java	Wed Nov 14 12:21:20 2012 -0500
+++ b/src/share/classes/java/util/streams/Stream.java	Wed Nov 14 18:49:41 2012 +0100
@@ -26,6 +26,7 @@
 
 import java.util.*;
 import java.util.functions.*;
+import java.util.streams.primitives.IntStream;
 
 /**
  * A potentially infinite sequence of elements. A stream is a consumable data
@@ -43,8 +44,12 @@
 
     <R> Stream<R> map(Mapper<? extends R, ? super T> mapper);
 
+    IntStream mapToInt(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);
--- a/src/share/classes/java/util/streams/StreamShapeFactory.java	Wed Nov 14 12:21:20 2012 -0500
+++ b/src/share/classes/java/util/streams/StreamShapeFactory.java	Wed Nov 14 18:49:41 2012 +0100
@@ -26,6 +26,7 @@
 
 import java.util.WeakHashMap;
 import java.util.streams.ops.*;
+import java.util.streams.primitives.*;
 
 public final class StreamShapeFactory {
 
@@ -33,6 +34,8 @@
 
     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() {
@@ -72,6 +75,47 @@
         };
 
         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) {
--- a/src/share/classes/java/util/streams/ops/Nodes.java	Wed Nov 14 12:21:20 2012 -0500
+++ b/src/share/classes/java/util/streams/ops/Nodes.java	Wed Nov 14 18:49:41 2012 +0100
@@ -143,6 +143,16 @@
         //
 
         @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));
         }
@@ -213,6 +223,16 @@
         //
 
         @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);
         }
@@ -346,6 +366,16 @@
         //
 
         @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());
@@ -514,16 +544,6 @@
         }
 
         @Override
-        public int hashCode() {
-            return Nodes.hashCode(this);
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            return (obj instanceof NodeBuilder) && Nodes.equals(this, (NodeBuilder) obj);
-        }
-
-        @Override
         public String toString() {
             return String.format("FixedNodeBuilder[%d][%s]", array.length - curSize, Arrays.toString(array));
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntBlock.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.functions.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/streams/primitives/IntCollectorOps.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.streams.StreamOpFlags;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.ops.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/streams/primitives/IntFactory.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.functions.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/streams/primitives/IntFilterOp.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.streams.Sink;
+import java.util.streams.StreamOpFlags;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.ops.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 acceptInt(int t) {
+                if (predicate.testInt(t))
+                    downstream.acceptInt(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/streams/primitives/IntForEachOp.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Objects;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.ops.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 acceptInt(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/streams/primitives/IntIterable.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Iterator;
+import java.util.functions.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/streams/primitives/IntIterator.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Iterator;
+import java.util.functions.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/streams/primitives/IntLimitOp.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+import java.util.streams.*;
+import java.util.streams.ops.Node;
+import java.util.streams.ops.NodeBuilder;
+import java.util.streams.ops.Nodes;
+import java.util.streams.ops.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/streams/primitives/IntMapOp.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.streams.Sink;
+import java.util.streams.StreamOpFlags;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.ops.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 acceptInt(int t) {
+                downstream.acceptInt(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/streams/primitives/IntNode.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.streams.ops.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/streams/primitives/IntNodeBuilder.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.functions.UnaryOperator;
+import java.util.streams.ops.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/streams/primitives/IntNodes.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.*;
+import java.util.functions.Block;
+import java.util.functions.UnaryOperator;
+import java.util.streams.*;
+import java.util.streams.ops.CollectorOps;
+import java.util.streams.ops.Node;
+import java.util.streams.ops.NodeBuilder;
+import java.util.streams.ops.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 acceptInt(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 acceptInt(int i) {
+            super.applyInt(i);
+        }
+
+        @Override
+        public void end() {
+            assert building : "was not building";
+            building = false;
+            // @@@ check begin(size) and size
+        }
+
+        @Override
+        public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException {
+            assert !building : "during building";
+            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++) {
+                int[] 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 int[] asIntArray() {
+            assert !building : "during building";
+            int[] result = new int[size()]; // will fail for size == MAX_VALUE
+
+            copyInto(result, 0);
+
+            return result;
+        }
+
+        @Override
+        public IntNode build() {
+            assert !building : "during building";
+            return this;
+        }
+
+        @Override
+        public IntNode flatten() {
+            return this;
+        }
+
+        //
+
+        @Override
+        public boolean equals(Object obj) {
+            return (obj instanceof IntIterable) && IntNodes.equals(this, (IntIterable) obj);
+        }
+
+        @Override
+        public int hashCode() {
+            return IntNodes.hashCode(this);
+        }
+    }
+
+    private static boolean equals(IntIterable a, IntIterable b) {
+        Objects.requireNonNull(a);
+        Objects.requireNonNull(b);
+
+        if(a instanceof Sized && b instanceof Sized) {
+            if ( ((Sized) a).size() != ((Sized) b).size()) {
+                return false;
+            }
+        }
+
+        IntIterator it1 = a.iterator();
+        IntIterator it2 = b.iterator();
+        while (it1.hasNext() && it2.hasNext()) {
+            if (it1.nextInt() != it2.nextInt()) {
+                return false;
+            }
+        }
+
+        return !(it1.hasNext() || it2.hasNext());
+    }
+
+    private static <T> int hashCode(IntIterable it) {
+        int h = 0;
+
+        IntIterator i = it.iterator();
+        while(i.hasNext()) {
+            h = 31 * h + i.nextInt();
+        }
+        return h;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntPipeline.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Optional;
+import java.util.functions.IntBinaryOperator;
+import java.util.streams.AbstractPipeline;
+import java.util.streams.Stream;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.ops.IntermediateOp;
+
+public class IntPipeline<E_IN> extends AbstractPipeline<E_IN, Integer> implements IntStream {
+
+    private IntIterator iterator;
+
+    public IntPipeline(IntSpliterator source, int flags) {
+        super(source, flags, StreamShapeFactory.INT_VALUE);
+    }
+
+    public IntPipeline(AbstractPipeline<?, E_IN> upstream, IntermediateOp<E_IN, Integer> op) {
+        super(upstream, op);
+    }
+
+    //
+
+    @Override
+    public IntIterator iterator() {
+        if (iterator == null) {
+            iterator = Primitives.adapt(super.iterator());
+        }
+        return iterator;
+    }
+
+    //
+
+    @Override
+    public Stream<Integer> boxed() {
+        return pipeline(new IntToIntegerOp());
+    }
+
+    @Override
+    public IntStream map(IntUnaryOperator mapper) {
+        return pipeline(new IntMapOp(mapper));
+    }
+
+    @Override
+    public IntStream filter(IntPredicate predicate) {
+        return pipeline(new IntFilterOp(predicate));
+    }
+
+    @Override
+    public IntStream tee(IntBlock block) {
+        return pipeline(new IntTeeOp(block));
+    }
+
+    @Override
+    public IntStream sorted() {
+        return pipeline(new IntSortedOp());
+    }
+
+    @Override
+    public void forEach(IntBlock block) {
+        pipeline(IntForEachOp.make(block));
+    }
+
+    @Override
+    public int sum() {
+        return pipeline(new IntSumOp());
+    }
+
+    @Override
+    public int[] toArray() {
+        return pipeline(IntToArrayOp.singleton());
+    }
+
+    //
+
+    @Override
+    public IntStream cumulate(IntBinaryOperator operator) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public IntStream uniqueElements() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public IntStream limit(int n) {
+        return pipeline(new IntLimitOp(n));
+    }
+
+    @Override
+    public IntStream skip(int n) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public IntStream concat(IntStream other) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public IntStream sequential() {
+        return pipeline(IntCollectorOps.sequentialCollector());
+    }
+
+    @Override
+    public IntStream unordered() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int reduce(int base, IntBinaryOperator op) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Optional<Integer> reduce(IntBinaryOperator op) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean anyMatch(IntPredicate predicate) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean allMatch(IntPredicate predicate) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public boolean noneMatch(IntPredicate predicate) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Optional<Integer> findFirst() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Optional<Integer> findAny() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int min() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int max() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public double average() {
+        throw new UnsupportedOperationException();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntPredicate.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,31 @@
+/*
+ * 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.streams.primitives;
+
+public interface IntPredicate {
+
+    boolean testInt(int i);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntSink.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Objects;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.streams.Sink;
+
+public interface IntSink extends Sink<Integer>, IntBlock {
+
+    // Block<Integer>, IntBlock
+
+    @Override
+    default void apply(Integer i) {
+        Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using boxed int", getClass().getName());
+        acceptInt(i.intValue());
+    }
+
+    // IntBlock
+
+    @Override
+    default void applyInt(int i) { acceptInt(i); }
+
+    // Sink<Integer>
+
+    @Override
+    default void accept(Integer i) {
+        Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using boxed int", getClass().getName());
+        acceptInt(i.intValue());
+    }
+
+    //
+
+    void acceptInt(int i);
+
+    public static abstract class ChainedValue implements IntSink {
+        protected final IntSink downstream;
+
+        public ChainedValue(IntSink 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/streams/primitives/IntSortedOp.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,112 @@
+/*
+ * 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.streams.primitives;
+
+import java.util.*;
+import java.util.concurrent.ForkJoinUtils;
+import java.util.streams.*;
+import java.util.streams.ops.*;
+
+public class IntSortedOp implements StatefulOp<Integer, Integer> {
+
+    @Override
+    public StreamShape inputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public StreamShape outputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.IS_SORTED | StreamOpFlags.IS_ORDERED;
+    }
+
+    @Override
+    public IntSink wrapSink(int flags, Sink sink) {
+        IntSink intSink = Primitives.adapt(sink);
+        return new IntSink.ChainedValue(intSink) {
+            IntNodeBuilder nb;
+
+            @Override
+            public void begin(int size) {
+                nb = IntNodes.makeBuilder(size);
+            }
+
+            @Override
+            public void end() {
+                int[] ints = nb.build().asIntArray();
+                Arrays.sort(ints);
+                downstream.begin(ints.length);
+                for (int i = 0; i < ints.length; i++) {
+                    downstream.acceptInt(ints[i]);
+                }
+                downstream.end();
+            }
+
+            @Override
+            public void acceptInt(int t) {
+                nb.acceptInt(t);
+            }
+        };
+    }
+
+    @Override
+    public IntIterator wrapIterator(int flags, Iterator<Integer> iterator) {
+        Objects.requireNonNull(iterator);
+        return iterator(iterator);
+    }
+
+    public static IntIterator iterator(Iterator<Integer> iterator) {
+        Objects.requireNonNull(iterator);
+
+        IntIterator intIterator = Primitives.adapt(iterator);
+        IntNodeBuilder nb = IntNodes.makeVariableSizeBuilder();
+        intIterator.forEach(nb);
+
+        int[] ints = nb.build().asIntArray();
+        Arrays.sort(ints);
+
+        return Primitives.iterator(ints);
+    }
+
+    @Override
+    public <P_IN> Node<Integer> evaluateSequential(PipelineHelper<P_IN, Integer> helper) {
+        IntNode n = (IntNode) helper.collectOutput().flatten();
+
+        int[] content = n.asIntArray();
+        Arrays.sort(content);
+
+        return IntNodes.node(content);
+    }
+
+    @Override
+    public <P_IN> Node<Integer> evaluateParallel(ParallelPipelineHelper<P_IN, Integer> helper) {
+        IntNode n = (IntNode) helper.collectOutput().flatten();
+
+        int[] content = n.asIntArray();
+        Arrays.sort(content);
+
+        return IntNodes.node(content);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntSpliterator.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.util.streams.primitives;
+
+import java.util.Iterator;
+import java.util.functions.Block;
+import java.util.streams.Spliterator;
+import java.util.streams.Streams;
+
+public interface IntSpliterator extends Spliterator<Integer> {
+
+    // Spliterator<Integer>
+
+    @Override
+    IntSpliterator split();
+
+    @Override
+    IntIterator iterator();
+
+    @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());
+            }
+        }
+    }
+
+    //
+
+    default void forEach(IntBlock sink) {
+        IntIterator remaining = iterator();
+        while (remaining.hasNext()) {
+            sink.apply(remaining.nextInt());
+        }
+    }
+
+    /**
+     * An IntSpliterator that can only be used to sequentially traverse a source.
+     */
+    public interface Sequential extends IntSpliterator {
+        @Override
+        default int getNaturalSplits() {
+            return 0;
+        }
+
+        @Override
+        default IntSpliterator split() {
+            return Primitives.emptyIntSpliterator();
+        }
+
+        @Override
+        default boolean isPredictableSplits() {
+            return false;
+        }
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntStream.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,116 @@
+/*
+ * 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.streams.primitives;
+
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Optional;
+import java.util.functions.*;
+import java.util.streams.BaseStream;
+import java.util.streams.Stream;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+
+public interface IntStream extends BaseStream<Integer> {
+
+    // BaseStream
+
+    @Override
+    IntIterator iterator();
+
+    //
+
+    // @@@ Do the following make sense?
+
+//    <R> Stream<R> map(Mapper<? extends R, ? super T> mapper);
+//
+//    <R> Stream<R> flatMap(FlatMapper<? extends R, ? super T> mapper);
+//
+//    <A extends Destination<? super T>> A into(A target);
+//
+//    <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);
+//
+//    <U> U fold(Factory<U> baseFactory,
+//               Combiner<U, U, T> reducer,
+//               BinaryOperator<U> combiner);
+
+    //
+
+    Stream<Integer> boxed();
+
+    IntStream map(IntUnaryOperator mapper);
+
+    IntStream cumulate(IntBinaryOperator operator);
+
+    IntStream filter(IntPredicate predicate);
+
+    IntStream tee(IntBlock block);
+
+    IntStream sorted();
+
+    IntStream uniqueElements();
+
+    IntStream limit(int n);
+
+    IntStream skip(int n);
+
+    IntStream concat(IntStream other);
+
+    IntStream sequential();
+
+    IntStream unordered();
+
+    int reduce(int base, IntBinaryOperator op);
+
+    Optional<Integer> reduce(IntBinaryOperator op);
+
+    boolean anyMatch(IntPredicate predicate);
+
+    boolean allMatch(IntPredicate predicate);
+
+    boolean noneMatch(IntPredicate predicate);
+
+    Optional<Integer> findFirst();
+
+    Optional<Integer> findAny();
+
+    void forEach(IntBlock block);
+
+    int sum();
+
+    int min();
+
+    int max();
+
+    double average();
+
+    int[] toArray();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntSumOp.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,81 @@
+/*
+ * 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.streams.primitives;
+
+import java.util.streams.ParallelPipelineHelper;
+import java.util.streams.PipelineHelper;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.ops.OpUtils;
+import java.util.streams.ops.TerminalOp;
+
+public class IntSumOp implements TerminalOp<Integer, Integer> {
+
+    @Override
+    public StreamShape inputShape() {
+        return StreamShapeFactory.INT_VALUE;
+    }
+
+    @Override
+    public <P_IN> Integer evaluateSequential(PipelineHelper<P_IN, Integer> helper) {
+        return helper.into(new SumIntSink()).getAndClearState();
+    }
+
+    @Override
+    public <P_IN> Integer evaluateParallel(ParallelPipelineHelper<P_IN, Integer> helper) {
+        return OpUtils.parallelReduce(helper, () -> new SumIntSink());
+    }
+
+    private class SumIntSink implements OpUtils.AccumulatingSink<Integer, Integer, SumIntSink>, IntSink {
+        int sum;
+
+        @Override
+        public void begin(int size) {
+            sum = 0;
+        }
+
+        @Override
+        public void clearState() {
+            sum = 0;
+        }
+
+        @Override
+        public Integer getAndClearState() {
+            int r = sum;
+            sum = 0;
+            return r;
+        }
+
+        @Override
+        public void acceptInt(int t) {
+            sum += t;
+        }
+
+        @Override
+        public void combine(SumIntSink other) {
+            sum += other.sum;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntTeeOp.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.streams.Sink;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.ops.IntermediateOp;
+
+public class IntTeeOp implements IntermediateOp<Integer, Integer> {
+    public final IntBlock tee;
+
+    public IntTeeOp(IntBlock tee) {
+        this.tee = Objects.requireNonNull(tee);
+    }
+
+    @Override
+    public StreamShape inputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public StreamShape outputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public IntIterator wrapIterator(int flags, final Iterator<Integer> source) {
+        return iterator(source, tee);
+    }
+
+    @Override
+    public IntSink wrapSink(int flags, Sink sink) {
+        Objects.requireNonNull(sink);
+
+        IntSink intSink = Primitives.adapt(sink);
+        return new IntSink.ChainedValue(intSink) {
+            @Override
+            public void acceptInt(int t) {
+                tee.applyInt(t);
+                downstream.acceptInt(t);
+            }
+        };
+    }
+
+    public static IntIterator iterator(final Iterator<Integer> source, final IntBlock tee) {
+        Objects.requireNonNull(source);
+        Objects.requireNonNull(tee);
+
+        final IntIterator intSource = Primitives.adapt(source);
+        return new IntIterator() {
+            @Override
+            public boolean hasNext() {
+                return intSource.hasNext();
+            }
+
+            @Override
+            public int nextInt() {
+                int next = intSource.next();
+                tee.applyInt(next);
+                return next;
+            }
+        };
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntTerminalSink.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,29 @@
+package java.util.streams.primitives;/*
+ * 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.
+ */
+
+import java.util.streams.TerminalSink;
+
+public interface IntTerminalSink<T> extends TerminalSink<Integer, T>, IntSink {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntToArrayOp.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,59 @@
+/*
+ * 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.streams.primitives;
+
+import java.util.streams.ParallelPipelineHelper;
+import java.util.streams.PipelineHelper;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.ops.Nodes;
+import java.util.streams.ops.TerminalOp;
+import java.util.streams.ops.TreeUtils;
+
+public class IntToArrayOp implements TerminalOp<Integer, int[]> {
+
+    private final static IntToArrayOp INSTANCE = new IntToArrayOp();
+
+    public static IntToArrayOp singleton() {
+        return INSTANCE;
+    }
+
+    @Override
+    public StreamShape inputShape() {
+        return StreamShapeFactory.INT_VALUE;
+    }
+
+    @Override
+    public <P_IN> int[] evaluateSequential(PipelineHelper<P_IN, Integer> helper) {
+        IntNode n = (IntNode) helper.collectOutput().flatten();
+        return n.asIntArray();
+    }
+
+    @Override
+    public <P_IN> int[] evaluateParallel(ParallelPipelineHelper<P_IN, Integer> helper) {
+        IntNode n = (IntNode) helper.collectOutput().flatten();
+        return n.asIntArray();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntToIntegerOp.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,85 @@
+package java.util.streams.primitives;/*
+ * 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.
+ */
+
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.streams.Sink;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.ops.IntermediateOp;
+
+public class IntToIntegerOp implements IntermediateOp<Integer, Integer> {
+
+    @Override
+    public StreamShape inputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public StreamShape outputShape() { return StreamShapeFactory.REFERENCE; }
+
+    @Override
+    public Iterator<Integer> wrapIterator(int flags, final Iterator<Integer> source) {
+        return iterator(source);
+    }
+
+    @Override
+    public IntSink wrapSink(int flags, final Sink sink) {
+        Objects.requireNonNull(sink);
+
+        return new IntSink() {
+            @Override
+            public void begin(int size) {
+                sink.begin(size);
+            }
+
+            @Override
+            public void acceptInt(int t) {
+                sink.accept(t);
+            }
+
+            @Override
+            public void end() {
+                sink.end();
+            }
+        };
+    }
+
+    public static Iterator<Integer> iterator(final Iterator<Integer> source) {
+        Objects.requireNonNull(source);
+
+        final IntIterator intSource = Primitives.adapt(source);
+        return new Iterator<Integer>() {
+            @Override
+            public boolean hasNext() {
+                return intSource.hasNext();
+            }
+
+            @Override
+            public Integer next() {
+                int next = intSource.next();
+                return next;
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntTreeUtils.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.Iterator;
+import java.util.concurrent.CountedCompleter;
+import java.util.streams.ParallelPipelineHelper;
+import java.util.streams.PipelineHelper;
+import java.util.streams.Spliterator;
+import java.util.streams.ops.AbstractTask;
+import java.util.streams.ops.Node;
+import java.util.streams.ops.OpUtils;
+
+/**
+ * Collector
+ *
+ * @author Brian Goetz
+ */
+public class IntTreeUtils {
+
+    private IntTreeUtils() {
+        throw new Error("no instances");
+    }
+
+    // @@@ make public ?
+    private static <P_IN> IntNode collectSequentially(PipelineHelper<P_IN, Integer> helper, Spliterator<P_IN> spliterator) {
+//        NodeBuilder<Integer> builder = OpUtils.makeNodeBuilderFor(helper, spliterator);
+        // @@@ create builder
+        IntNodeBuilder builder = IntNodes.makeBuilder(helper.getOutputSizeIfKnown() >= 0 ? spliterator.getSizeIfKnown() : -1);
+        OpUtils.intoWrapped(spliterator, helper.wrapSink(builder));
+        return builder.build();
+    }
+
+    public static <P_IN> IntNode collect(ParallelPipelineHelper<P_IN, Integer> 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()) {
+                // @@@ create array
+                int[] array = new int[size];
+                helper.invoke(new SizedCollectorTask<>(spliterator, helper, array));
+                // @@@ create node
+                return IntNodes.node(array);
+            }
+            else {
+                CollectorTask<P_IN> task = new CollectorTask<>(helper);
+                helper.invoke(task);
+                IntNode 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 IntNode flatten(IntNode node) {
+        if (node.getChildCount() > 0) {
+            // @@@ create array
+            int[] array = new int[node.size()];
+            new ToArrayTask(node, array, 0).invoke();
+            // @@@ create node
+            return IntNodes.node(array);
+        } else {
+            return node;
+        }
+    }
+
+    public static void copyTo(IntNode node, int[] array, int offset) {
+        // @@@ Currently only used by IntNodes.ConcNode
+        if (node.getChildCount() > 0) {
+            new ToArrayTask(node, array, offset).invoke();
+        } else {
+            node.copyInto(array, offset);
+        }
+    }
+
+    private static class CollectorTask<T> extends AbstractTask<T, Integer, IntNode, CollectorTask<T>> {
+        private final ParallelPipelineHelper<T, Integer> helper;
+
+        private CollectorTask(ParallelPipelineHelper<T, Integer> helper) {
+            super(helper);
+            this.helper = helper;
+        }
+
+        private CollectorTask(CollectorTask<T> parent, Spliterator<T> spliterator) {
+            super(parent, spliterator);
+            helper = parent.helper;
+        }
+
+        @Override
+        protected CollectorTask<T> makeChild(Spliterator<T> spliterator) {
+            return new CollectorTask<>(this, spliterator);
+        }
+
+        @Override
+        protected IntNode doLeaf() {
+            return collectSequentially(helper, spliterator);
+        }
+
+        @Override
+        public void onCompletion(CountedCompleter caller) {
+            if (!isLeaf()) {
+                @SuppressWarnings("unchecked")
+                IntNode[] nodes = new IntNode[numChildren];
+                int idx = 0;
+                for (CollectorTask<T> cur = children; cur != null; cur = cur.nextSibling)
+                    nodes[idx++] = cur.getRawResult();
+
+                // @@@ conc nodes
+                setRawResult(IntNodes.node(nodes));
+            }
+        }
+    }
+
+    private static class SizedCollectorTask<T> extends CountedCompleter<Void> {
+        private final Spliterator<T> spliterator;
+        private final ParallelPipelineHelper<T, Integer> helper;
+        private final int[] array;
+        private int offset;
+        private int length;
+
+        private SizedCollectorTask(Spliterator<T> spliterator, ParallelPipelineHelper<T, Integer> helper, int[] array) {
+            this.spliterator = spliterator;
+            this.helper = helper;
+            this.array = array;
+            this.offset = 0;
+            this.length = array.length;
+        }
+
+        private SizedCollectorTask(SizedCollectorTask<T> 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)) {
+                // @@@ create sink
+                OpUtils.intoUnwrapped(helper, spliterator, Primitives.sink(array, offset, length));
+                helpComplete();
+            }
+            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> task = new SizedCollectorTask<>(this, split, offset + s, thisSplitSize);
+                    task.fork();
+
+                    s += thisSplitSize;
+                }
+
+                SizedCollectorTask<T> task = new SizedCollectorTask<>(this, spliterator, offset + s, length - s);
+                task.compute();
+            }
+        }
+    }
+
+    private static class ToArrayTask extends CountedCompleter<Void> {
+        private final int[] array;
+        private final IntNode node;
+        private final int offset;
+
+        private ToArrayTask(IntNode node, int[] array, int offset) {
+            this.array = array;
+            this.node = node;
+            this.offset = offset;
+        }
+
+        private ToArrayTask(ToArrayTask parent, IntNode 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<IntNode> itNodes = node.children();
+
+                // @@@ cast
+                final ToArrayTask firstTask = new ToArrayTask(this, itNodes.next(), offset);
+                int size = firstTask.node.size();
+
+                while (itNodes.hasNext()) {
+                    // @@@ cast
+                    final ToArrayTask task = new ToArrayTask(this, itNodes.next(), offset + size);
+                    size += task.node.size();
+                    task.fork();
+                }
+                firstTask.compute();
+            }
+            else {
+                // @@@ copy array
+                node.copyInto(array, offset);
+                helpComplete();
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/IntUnaryOperator.java	Wed Nov 14 18:49:41 2012 +0100
@@ -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.streams.primitives;
+
+import java.util.functions.UnaryOperator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public interface IntUnaryOperator extends UnaryOperator<Integer> {
+
+    @Override
+    default Integer operate(Integer operand) {
+        Logger.getLogger(getClass().getName()).log(Level.WARNING, "{0} using boxed int", getClass().getName());
+        return operateInt(operand);
+    }
+
+    int operateInt(int operand);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/Primitives.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,721 @@
+/*
+ * 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.streams.primitives;
+
+import java.util.*;
+import java.util.functions.Block;
+import java.util.functions.Factory;
+import java.util.functions.UnaryOperator;
+import java.util.logging.Logger;
+import java.util.streams.*;
+
+public final class Primitives {
+
+    private Primitives() {}
+
+    // Adapt iterator to int iterator
+
+    public static IntIterator adapt(final Iterator<Integer> i) {
+        if (i instanceof IntIterator) {
+            return (IntIterator) i;
+        }
+        else {
+            // @@@ throw UOE?
+            return new IntIterator() {
+                @Override
+                public boolean hasNext() {
+                    return i.hasNext();
+                }
+
+                @Override
+                public Integer next() {
+                    return i.next();
+                }
+
+                @Override
+                public int nextInt() {
+                    return i.next().intValue();
+                }
+            };
+        }
+    }
+
+    // Adapt sink to int sink
+
+    public static IntSink adapt(final Sink<Integer> s) {
+        if (s instanceof IntSink) {
+            return (IntSink) s;
+        }
+        else {
+            // @@@ throw UOE?
+            return new IntSink() {
+                @Override
+                public void begin(int size) {
+                    s.begin(size);
+                }
+
+                @Override
+                public void acceptInt(int i) {
+                    s.accept(i);
+                }
+
+                @Override
+                public void end() {
+                    s.end();
+                }
+            };
+        }
+    }
+
+    // Adapt block to int block
+
+    public static IntBlock adapt(final Block<Integer> b) {
+        if (b instanceof IntBlock) {
+            return (IntBlock) b;
+        }
+        else {
+            // @@@ throw UOE?
+            return new IntBlock() {
+                @Override
+                public void applyInt(int i) {
+                    b.apply(i);
+                }
+            };
+        }
+    }
+
+    //
+
+    public static IntIterator emptyIntIterator() {
+        return EMPTY_INT_ITERATOR;
+    }
+
+    private static final IntIterator EMPTY_INT_ITERATOR = new IntIterator() {
+        @Override
+        public int nextInt() {
+            throw new NoSuchElementException();
+        }
+
+        @Override
+        public boolean hasNext() {
+            return false;
+        }
+
+        @Override
+        public void forEach(IntBlock sink) {
+        }
+    };
+
+    public static IntSpliterator emptyIntSpliterator() {
+        return EMPTY_INT_SPLITERATOR;
+    }
+
+    private static final IntSpliterator EMPTY_INT_SPLITERATOR = new IntSpliterator() {
+        @Override
+        public int getNaturalSplits() {
+            return 0;
+        }
+
+        @Override
+        public IntSpliterator split() {
+            return EMPTY_INT_SPLITERATOR;
+        }
+
+        @Override
+        public IntIterator iterator() {
+            return EMPTY_INT_ITERATOR;
+        }
+
+        @Override
+        public void forEach(IntBlock sink) {
+        }
+
+        @Override
+        public int getSizeIfKnown() {
+            return 0;
+        }
+
+        @Override
+        public boolean isPredictableSplits() {
+            return true;
+        }
+    };
+
+    public static IntIterator iterator(int[] array) {
+        return iterator(array, 0, array.length);
+    }
+
+    public static IntIterator iterator(int[] array, int offset, int length) {
+        // Validate bounds
+        return new IntArrayIterator(array, offset, length);
+    }
+
+    private static class IntArrayIterator implements IntIterator {
+        final int[] array;
+        int o;
+        final int e;
+
+        private IntArrayIterator(int[] array, int offset, int length) {
+            this.array = array;
+            this.o = offset;
+            this.e = offset + length;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return o < e;
+        }
+
+        @Override
+        public int nextInt() {
+            if (!hasNext()) {
+                throw new NoSuchElementException();
+            }
+
+            return array[o++];
+        }
+
+        @Override
+        public void forEach(IntBlock sink) {
+            if (hasNext()) {
+                for (int i = o; i < e; i++) {
+                    sink.applyInt(array[i]);
+                }
+                o = e;
+            }
+        }
+
+        @Override
+        public void forEach(Block<? super Integer> sink) {
+            IntIterator.super.forEach(sink);
+        }
+    }
+
+    public static IntIterator concat(final IntIterator i1, final IntIterator i2) {
+        Objects.requireNonNull(i1);
+        Objects.requireNonNull(i2);
+
+        return concat(Arrays.asList(i1, i2).iterator());
+    }
+
+    public static IntIterator concat(final Iterator<IntIterator> iterators) {
+        Objects.requireNonNull(iterators);
+
+        if (!iterators.hasNext())
+            return EMPTY_INT_ITERATOR;
+
+        return new IntIterator() {
+            private IntIterator it = Objects.requireNonNull(iterators.next());
+            // Need to retain a reference to the last iterator used with next()
+            // so that remove() can use that reference for deferral and check for two or more calls,
+            // and because hasNext() may update "it" to the next iterator
+            private IntIterator itForRemove = null;
+
+            @Override
+            public boolean hasNext() {
+                while (!it.hasNext()) {
+                    if (!iterators.hasNext()) {
+                        return false;
+                    }
+                    it = Objects.requireNonNull(iterators.next());
+                }
+
+                return true;
+            }
+
+            public int nextInt() {
+                if (!hasNext()) {
+                    throw new NoSuchElementException();
+                }
+
+                itForRemove = it;
+                return it.nextInt();
+            }
+
+            @Override
+            public void remove() {
+                if (itForRemove == null) {
+                    throw new IllegalStateException();
+                }
+
+                itForRemove.remove();
+                itForRemove = null;
+            }
+        };
+    }
+
+    // Infinite int streams
+
+    private static interface IntInfiniteIterator extends IntIterator {
+        @Override
+        default boolean hasNext() {
+            return true;
+        }
+    }
+
+    public static IntStream iterate(final int seed, final IntUnaryOperator f) {
+        Objects.requireNonNull(f);
+        final IntInfiniteIterator iterator = new IntInfiniteIterator() {
+            int t = seed;
+
+            @Override
+            public int nextInt() {
+                int v = t;
+                t = f.operateInt(t);
+                return v;
+            }
+        };
+        return stream(iterator, StreamOpFlags.IS_ORDERED);
+    }
+
+    public static IntStream repeat(int t) {
+        return repeat(-1, t);
+    }
+
+    public static IntStream repeat(final int n, final int t) {
+        return repeatedly(n, () -> t);
+    }
+
+    public static IntStream repeatedly(IntFactory f) {
+        return repeatedly(-1, f);
+    }
+
+    public static IntStream repeatedly(final int n, final IntFactory f) {
+        Objects.requireNonNull(f);
+
+        if (n < 0) {
+            IntInfiniteIterator iterator = () -> f.makeInt();
+            return stream(iterator, StreamOpFlags.IS_ORDERED);
+        }
+        else {
+            final IntIterator repeatedly = new IntIterator() {
+                int c = n;
+
+                @Override
+                public boolean hasNext() {
+                    return c > 0;
+                }
+
+                @Override
+                public int nextInt() {
+                    if (!hasNext()) {
+                        throw new NoSuchElementException();
+                    }
+
+                    c--;
+                    return f.makeInt();
+                }
+            };
+
+            return stream(repeatedly, StreamOpFlags.IS_ORDERED);
+        }
+    }
+
+    public static IntStream cycle(final IntIterable source) {
+        Objects.requireNonNull(source);
+
+        // Check if the source is empty
+        if (!source.iterator().hasNext()) {
+            return emptyIntStream();
+        }
+
+        final IntInfiniteIterator cycle = new IntInfiniteIterator() {
+            IntIterator i = source.iterator();
+
+            @Override
+            public int nextInt() {
+                if (!i.hasNext()) {
+                    i = source.iterator();
+                }
+
+                return i.nextInt();
+            }
+        };
+
+        return stream(cycle, StreamOpFlags.IS_ORDERED);
+    }
+
+
+    //
+
+    private static class IntArraySpliterator extends IntArrayIterator implements IntSpliterator {
+        private boolean traversing = false;
+
+        private IntArraySpliterator(int[] array, int offset, int length) {
+            super(array, offset, length);
+        }
+
+        @Override
+        public void forEach(Block<? super Integer> sink) {
+            traversing = true;
+            super.forEach(sink);
+        }
+
+        @Override
+        public void forEach(IntBlock sink) {
+            traversing = true;
+            super.forEach(sink);
+        }
+
+        @Override
+        public IntSpliterator split() {
+            if (traversing) {
+                throw new IllegalStateException("split after starting traversal");
+            }
+
+            int m = (e - o) / 2;
+            IntSpliterator ret = new IntArraySpliterator(array, o, m);
+            o += m;
+            return ret;
+        }
+
+        @Override
+        public IntIterator iterator() {
+            traversing = true;
+            return this;
+        }
+
+        @Override
+        public int getNaturalSplits() {
+            return (e - o > 1) ? 1 : 0;
+        }
+
+        @Override
+        public int getSizeIfKnown() {
+            return e - o;
+        }
+
+        @Override
+        public boolean isPredictableSplits() {
+            return true;
+        }
+    }
+
+    private static class ArrayIntSink implements IntSink {
+        private final int[] array;
+        private final int offset;
+        private int o;
+        private final int e;
+
+        ArrayIntSink(int[] array) {
+            this(array, 0, array.length);
+        }
+
+        ArrayIntSink(int[] array, int offset, int length) {
+            this.array = Objects.requireNonNull(array);
+            this.offset = offset;
+            this.o = offset;
+            this.e = offset + length;
+        }
+
+        @Override
+        public void begin(int size) {
+            o = offset;
+            if(size > (e - o)) {
+                Logger.getLogger(Primitives.class.getName()).warning(
+                        "Estimate greater than length. There might be blood.");
+            }
+        }
+
+        @Override
+        public void acceptInt(int t) {
+            if (o >= e) {
+                throw new IndexOutOfBoundsException(Integer.toString(o));
+            }
+            array[o++] = t;
+        }
+    }
+
+    static class RangeIntIterator implements IntIterator {
+        int from;
+        int upTo;
+        int step;
+
+        public RangeIntIterator(int from, int upTo, int step) {
+            this.from = from;
+            this.upTo = upTo;
+            this.step = step;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return from < upTo;
+        }
+
+        @Override
+        public Integer next() {
+            // @@@ throw UOE
+            return nextInt();
+        }
+
+        @Override
+        public int nextInt() {
+            int r = from;
+            from += step;
+            return r;
+        }
+    }
+
+    static class RangeIntSpliterator extends RangeIntIterator implements IntSpliterator {
+        boolean traversing = false;
+
+        RangeIntSpliterator(int from, int upTo, int step) {
+            super(from, upTo, step);
+        }
+
+        @Override
+        public int getSizeIfKnown() {
+            return (upTo - from) / step;
+        }
+
+        @Override
+        public int getNaturalSplits() {
+            return (getSizeIfKnown() > 1) && !traversing ? 1 : 0;
+        }
+
+        @Override
+        public boolean isPredictableSplits() {
+            return true;
+        }
+
+        @Override
+        public IntSpliterator split() {
+            if (traversing) {
+                throw new IllegalStateException("split after starting traversal");
+            }
+
+            if (getSizeIfKnown() > 1) {
+                int mid = midPoint();
+                RangeIntSpliterator ret = new RangeIntSpliterator(from, from + mid, step);
+                from += mid;
+
+                return ret;
+            } else {
+                return EMPTY_INT_SPLITERATOR;
+            }
+        }
+
+        private int midPoint() {
+            if (step == 1) {
+                return (upTo - from) / 2;
+            } else {
+                int bisection = (upTo - from) / 2;
+                int remainder = (bisection - from) % step;
+
+                int midPoint = bisection - remainder;
+                if (midPoint <= from) {
+                    midPoint = bisection + (step - remainder);
+                }
+                return midPoint;
+            }
+        }
+
+        @Override
+        public IntIterator iterator() {
+            traversing = true;
+            return this;
+        }
+
+        @Override
+        public void forEach(Block<? super Integer> sink) {
+            traversing = true;
+            if (sink instanceof IntBlock) {
+                forEach((IntBlock) sink);
+            }
+            else {
+                super.forEach(sink);
+            }
+        }
+
+        @Override
+        public void forEach(IntBlock sink) {
+            traversing = true;
+            super.forEach(sink);
+        }
+    }
+
+    // Create IntStream from range
+
+    public static IntStream range(final int from, final int upTo) {
+        return range(from, upTo, 1);
+    }
+
+    public static IntStream range(final int from, final int upTo, final int step) {
+        IntSpliterator s = new RangeIntSpliterator(from, upTo, step);
+        return stream(s, StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED);
+    }
+
+    // Create parallel IntStream from range
+
+    public static IntStream parRange(final int from, final int upTo) {
+        return parRange(from, upTo, 1);
+    }
+
+    public static IntStream parRange(final int from, final int upTo, final int step) {
+        IntSpliterator s = new RangeIntSpliterator(from, upTo, step);
+        return stream(s, StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED | StreamOpFlags.IS_PARALLEL);
+    }
+
+    // Create Spliterator from arrays
+
+    public static IntSpliterator spliterator(int[] array) {
+        return spliterator(array, 0, array.length);
+    }
+
+    public static IntSpliterator spliterator(int[] array, int offset, int length) {
+        return new IntArraySpliterator(array, offset, length);
+    }
+
+    // Create Sink from arrays
+
+    public static IntSink sink(int[] array) {
+        return sink(array, 0, array.length);
+    }
+
+    public static IntSink sink(int[] array, int offset, int length) {
+        return new ArrayIntSink(array, offset, length);
+    }
+
+    // Create IntStream from IntIterable and IntIterator
+
+    public static<T extends Sized & IntIterable> IntStream stream(T entity, int flags) {
+        return toStream(new IntSpliterator.Sequential() {
+            @Override
+            public IntIterator iterator() {
+                return entity.iterator();
+            }
+
+            @Override
+            public void forEach(IntBlock block) {
+                entity.forEach(block);
+            }
+
+            @Override
+            public int getSizeIfKnown() {
+                return entity.size();
+            }
+        }, StreamOpFlags.IS_SIZED | flags);
+    }
+
+    public static IntStream stream(IntIterable entity, Sized sizeProvider, int flags) {
+        return toStream(new IntSpliterator.Sequential() {
+            @Override
+            public IntIterator iterator() {
+                return entity.iterator();
+            }
+
+            @Override
+            public void forEach(IntBlock block) {
+                entity.forEach(block);
+            }
+
+            @Override
+            public int getSizeIfKnown() {
+                return sizeProvider.size();
+            }
+        }, StreamOpFlags.IS_SIZED | flags);
+    }
+
+    public static IntStream stream(IntIterable entity, int flags) {
+        return toStream(new IntSpliterator.Sequential() {
+            @Override
+            public IntIterator iterator() {
+                return entity.iterator();
+            }
+
+            @Override
+            public void forEach(IntBlock block) {
+                entity.forEach(block);
+            }
+            // @@@ Mask off sized if set ?
+        }, flags);
+    }
+
+    public static IntStream stream(IntIterator entity, int flags) {
+        return toStream(new IntSpliterator.Sequential() {
+            @Override
+            public IntIterator iterator() {
+                return entity;
+            }
+
+            @Override
+            public void forEach(IntBlock block) {
+                entity.forEach(block);
+            }
+            // @@@ Mask off sized if set ?
+        }, flags);
+    }
+
+    // Create IntStream from array
+
+    public static IntStream stream(int[] source) {
+        return stream(source, 0, source.length);
+    }
+
+    public static IntStream stream(int[] source, int offset, int length) {
+        // Note use of full-service Spliterator here -- harmless because PARALLEL flag is not set
+        return toStream(spliterator(source, offset, length),
+                        StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED);
+    }
+
+    // Create IntStream from IntSpliterator
+
+    public static IntStream stream(IntSpliterator spliterator, int flags) {
+        if (spliterator.getSizeIfKnown() >= 0)
+            flags |= StreamOpFlags.IS_SIZED;
+        return toStream(spliterator, flags);
+    }
+
+    // Create parallel IntStream from array
+
+    public static IntStream parallel(int[] source) {
+        return parallel(source, 0, source.length);
+    }
+
+    public static IntStream parallel(int[] source, int offset, int length) {
+        return toStream(spliterator(source, offset, length),
+                        StreamOpFlags.IS_SIZED | StreamOpFlags.IS_ORDERED | StreamOpFlags.IS_PARALLEL);
+    }
+
+    // Create parallel IntStream from IntSpliterator
+
+    public static IntStream parallel(IntSpliterator spliterator, int flags) {
+        if (spliterator.getSizeIfKnown() >= 0)
+            flags |= StreamOpFlags.IS_SIZED;
+        return toStream(spliterator, flags | StreamOpFlags.IS_PARALLEL);
+    }
+
+    //
+
+    public static IntStream emptyIntStream() {
+        return stream(emptyIntSpliterator(), 0);
+    }
+
+    //
+
+    private static IntStream toStream(IntSpliterator sp, int flags) {
+        return new IntPipeline<>(sp, flags);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/java/util/streams/primitives/RefToIntMapOp.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,99 @@
+/*
+ * 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.streams.primitives;
+
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.functions.IntMapper;
+import java.util.streams.Sink;
+import java.util.streams.StreamOpFlags;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.ops.IntermediateOp;
+
+public class RefToIntMapOp<T> implements IntermediateOp<T, Integer> {
+
+    private final IntMapper<? super T> mapper;
+
+    public RefToIntMapOp(IntMapper<? super T> mapper) {
+        this.mapper = Objects.requireNonNull(mapper);
+    }
+
+    @Override
+    public int getOpFlags() {
+        return StreamOpFlags.NOT_SORTED | StreamOpFlags.NOT_DISTINCT;
+    }
+
+    @Override
+    public StreamShape inputShape() { return StreamShapeFactory.REFERENCE; }
+
+    @Override
+    public StreamShape outputShape() { return StreamShapeFactory.INT_VALUE; }
+
+    @Override
+    public IntIterator wrapIterator(int flags, final Iterator<T> source) {
+        return iterator(source, mapper);
+    }
+
+    @Override
+    public Sink<T> wrapSink(int flags, Sink sink) {
+        Objects.requireNonNull(sink);
+
+        IntSink intSink = Primitives.adapt(sink);
+        return new Sink<T>() {
+            @Override
+            public void begin(int size) {
+                intSink.begin(size);
+            }
+
+            @Override
+            public void accept(T t) {
+                intSink.acceptInt(mapper.map(t));
+            }
+
+            @Override
+            public void end() {
+                intSink.end();
+            }
+        };
+    }
+
+    public static <T> IntIterator iterator(final Iterator<T> source, IntMapper<? super T> mapper) {
+        Objects.requireNonNull(source);
+
+        return new IntIterator() {
+            @Override
+            public boolean hasNext() {
+                return source.hasNext();
+            }
+
+            @Override
+            public int nextInt() {
+                return mapper.map(source.next());
+            }
+        };
+    }
+
+}
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/OpTestCase.java	Wed Nov 14 12:21:20 2012 -0500
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/OpTestCase.java	Wed Nov 14 18:49:41 2012 +0100
@@ -25,6 +25,7 @@
 package org.openjdk.tests.java.util.streams;
 
 import org.openjdk.tests.java.util.LambdaTestHelpers;
+import org.openjdk.tests.java.util.streams.primitives.IntStreamIntermediateOpTestScenario;
 import org.testng.Assert;
 import org.testng.ITestContext;
 import org.testng.annotations.BeforeClass;
@@ -36,6 +37,7 @@
 import java.util.functions.Factory;
 import java.util.streams.*;
 import java.util.streams.ops.*;
+import java.util.streams.primitives.IntStream;
 
 /**
  * StreamOpTestCase
@@ -52,6 +54,7 @@
         // @@@ This only needs to be done once, consider using injection or an attribute on ITestContext
         testScenarios = new HashMap<>();
         testScenarios.put(Stream.class, Collections.unmodifiableSet(EnumSet.allOf(StreamIntermediateOpTestScenario.class)));
+        testScenarios.put(IntStream.class, Collections.unmodifiableSet(EnumSet.allOf(IntStreamIntermediateOpTestScenario.class)));
     }
 
     // Exercise intermediate operations
@@ -220,7 +223,7 @@
             if (test.isApplicable(ops)) {
                 b.before.apply(b.data);
 
-                NodeBuilder<U> resultBuilder = Nodes.makeVariableSizeBuilder();
+                NodeBuilder<U> resultBuilder = b.shape.makeNodeBuilder(-1);
                 resultBuilder.begin(-1);
                 test.run(b.data, resultBuilder, ops);
                 resultBuilder.end();
@@ -317,24 +320,24 @@
     //
 
     @SuppressWarnings({"rawtypes", "unchecked"})
-    static <T> AbstractPipeline<?, T> chain(AbstractPipeline upstream, IntermediateOp<?, T> op) {
+    public static <T> AbstractPipeline<?, T> chain(AbstractPipeline upstream, IntermediateOp<?, T> op) {
         return upstream.chain(op);
     }
 
     @SuppressWarnings({"rawtypes", "unchecked"})
-    static <U> U chain(AbstractPipeline pipe, TerminalOp<?, U> op) {
+    public static <U> U chain(AbstractPipeline pipe, TerminalOp<?, U> op) {
         return (U) pipe.pipeline(op);
     }
 
     @SuppressWarnings({"rawtypes", "unchecked"})
-    static AbstractPipeline<?, ?> chain(AbstractPipeline pipe, IntermediateOp... ops) {
+    public static AbstractPipeline<?, ?> chain(AbstractPipeline pipe, IntermediateOp... ops) {
         for (IntermediateOp op : ops)
             pipe = chain(pipe, op);
         return pipe;
     }
 
     @SuppressWarnings("rawtypes")
-    static <U> U chain(AbstractPipeline pipe, TerminalOp<?, U> terminal, IntermediateOp... ops) {
+    public static <U> U chain(AbstractPipeline pipe, TerminalOp<?, U> terminal, IntermediateOp... ops) {
         return chain(chain(pipe, ops), terminal);
     }
 
@@ -343,6 +346,7 @@
     @SuppressWarnings({"rawtypes", "unchecked"})
     public static interface TestData<T> extends Iterable<T>, Sized {
 
+        // @@@ This is not used, should it be removed?
         Spliterator<T> spliterator();
 
         //
--- a/test-ng/tests/org/openjdk/tests/java/util/streams/StreamIntermediateOpTestScenario.java	Wed Nov 14 12:21:20 2012 -0500
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/StreamIntermediateOpTestScenario.java	Wed Nov 14 18:49:41 2012 +0100
@@ -34,6 +34,12 @@
 @SuppressWarnings({"rawtypes", "unchecked"})
 public enum StreamIntermediateOpTestScenario implements OpTestCase.IntermediateOpTestScenario {
 
+    STREAM_FOR_EACH(false) {
+        public <T> void run(OpTestCase.TestData<T> data, Block b, IntermediateOp[] ops) {
+            stream(data.seq(ops)).forEach(b);
+        }
+    },
+
     // Wrap as stream and into a list
     STREAM_INTO(false) {
         public <T> void run(OpTestCase.TestData<T> data, Block b, IntermediateOp[] ops) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/IntNodeTest.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.tests.java.util.streams.ops;
+
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.functions.Mapper;
+import java.util.streams.ops.Node;
+import java.util.streams.primitives.*;
+
+import static org.testng.Assert.*;
+
+@Test
+public class IntNodeTest {
+
+    @DataProvider(name = "nodes")
+    public Object[][] createSizes() {
+        List<Object[]> params = new ArrayList<>();
+
+        for (int size : Arrays.asList(0, 1, 4, 15, 16, 17, 127, 128, 129, 1000)) {
+            int[] array = new int[size];
+            for (int i = 0; i < array.length; i++) {
+                array[i] = i;
+            }
+
+            List<Node<Integer>> nodes = new ArrayList<>();
+
+            nodes.add(IntNodes.node(array));
+
+            nodes.add(degenerateTree(Primitives.iterator(array)));
+
+            nodes.add(tree(toList(array), l -> IntNodes.node(toIntArray(l))));
+
+            nodes.add(fill(array, IntNodes.makeBuilder(array.length)));
+
+            nodes.add(fill(array, IntNodes.makeVariableSizeBuilder()));
+
+            for (int i = 0; i < nodes.size(); i++) {
+                params.add(new Object[]{array, nodes.get(i)});
+            }
+
+        }
+
+        return params.toArray(new Object[0][]);
+    }
+
+    List<Integer> toList(int[] a) {
+        List<Integer> l = new ArrayList<>();
+        for (int i : a) {
+            l.add(i);
+        }
+
+        return l;
+    }
+
+    int[] toIntArray(List<Integer> l) {
+        int[] a = new int[l.size()];
+
+        int i = 0;
+        for (Integer e : l) {
+            a[i++] = e;
+        }
+        return a;
+    }
+
+    IntNode fill(int[] array, IntNodeBuilder nb) {
+        nb.begin(array.length);
+        for (Integer i : array) {
+            nb.acceptInt(i);
+        }
+        nb.end();
+        return nb.build();
+    }
+
+    IntNode degenerateTree(IntIterator it) {
+        if (!it.hasNext()) {
+            return IntNodes.node(new int[0]);
+        }
+
+        int i = it.nextInt();
+        if (it.hasNext()) {
+            return IntNodes.node(IntNodes.node(new int[]{i}), degenerateTree(it));
+        }
+        else {
+            return IntNodes.node(new int[]{i});
+        }
+    }
+
+    IntNode tree(List<Integer> l, Mapper<IntNode, List<Integer>> m) {
+        if (l.size() < 3) {
+            return m.map(l);
+        }
+        else {
+            return IntNodes.node(tree(l.subList(0, l.size() / 2), m), tree(l.subList(l.size() / 2, l.size()), m));
+        }
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testAsArray(int[] array, IntNode n) {
+        assertEquals(n.asIntArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testFlattenAsArray(int[] array, IntNode n) {
+        assertEquals(n.flatten().asIntArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testCopyTo(int[] array, IntNode n) {
+        int[] copy = new int[n.size()];
+        n.copyInto(copy, 0);
+
+        assertEquals(copy, array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testForEach(int[] array, IntNode n) {
+        List<Integer> l = new ArrayList<>(n.size());
+        n.forEach(e -> {
+            l.add(e);
+        });
+
+        assertEquals(l.toArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testIterator(int[] array, IntNode n) {
+        List<Integer> l = new ArrayList<>(n.size());
+        IntIterator it = n.iterator();
+        while (it.hasNext()) {
+            l.add(it.nextInt());
+        }
+
+        assertEquals(l.toArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testRootSpliterator(int[] array, IntNode n) {
+        List<Integer> l = new ArrayList<>(n.size());
+        IntIterator it = n.spliterator().iterator();
+        while (it.hasNext()) {
+            l.add(it.nextInt());
+        }
+
+        assertEquals(l.toArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testDepthOneSpliterator(int[] array, IntNode n) {
+        List<Integer> l = new ArrayList<>(n.size());
+
+        IntSpliterator s = n.spliterator();
+        for (int i = 0; i < s.getNaturalSplits(); i++) {
+            IntIterator it = s.split().iterator();
+            while (it.hasNext()) {
+                l.add(it.nextInt());
+            }
+        }
+
+        IntIterator it = s.iterator();
+        while (it.hasNext()) {
+            l.add(it.nextInt());
+        }
+
+        assertEquals(l.toArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testTwoSpliterator(int[] array, IntNode n) {
+        List<Integer> l = new ArrayList<>(n.size());
+
+        IntSpliterator s2 = n.spliterator();
+        IntSpliterator s1 = s2.split();
+
+        IntIterator it = s1.iterator();
+        while (it.hasNext()) {
+            l.add(it.nextInt());
+        }
+
+        it = s2.iterator();
+        while (it.hasNext()) {
+            l.add(it.nextInt());
+        }
+
+        assertEquals(l.toArray(), array);
+    }
+
+    @Test(dataProvider = "nodes")
+    public void testSpliterator(int[] array, IntNode n) {
+        List<Integer> l = new ArrayList<>(n.size());
+        split(l, n.spliterator());
+
+        assertEquals(l.toArray(), array);
+    }
+
+    void split(List<Integer> l, IntSpliterator s) {
+        if (s.getNaturalSplits() == 0) {
+            IntSpliterator _s = s.split();
+            assertEquals(_s.getNaturalSplits(), 0);
+            assertFalse(_s.split().iterator().hasNext());
+
+            s.forEach(e -> {
+                l.add(e);
+            });
+        }
+        else {
+            int size = s.getSizeIfKnown();
+            for (int i = 0; i < s.getNaturalSplits(); i++) {
+                IntSpliterator _s = s.split();
+                split(l, _s);
+            }
+
+            assertTrue(s.getSizeIfKnown() < size);
+
+            split(l, s);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/ops/PrimitiveOpsTests.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,172 @@
+/*
+ * 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 org.openjdk.tests.java.util.streams.ops;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.streams.primitives.*;
+
+@Test
+public class PrimitiveOpsTests {
+
+    public void testSum() {
+        int sum = Primitives.range(1, 10).filter(i -> i % 2 == 0).sum();
+        Assert.assertEquals(sum, 20);
+    }
+
+    public void testMap() {
+        int sum = Primitives.range(1, 10).filter(i -> i % 2 == 0).map(i -> i * 2).sum();
+        Assert.assertEquals(sum, 40);
+    }
+
+    public void testParSum() {
+        int sum = Primitives.parRange(1, 10).filter(i -> i % 2 == 0).sum();
+        Assert.assertEquals(sum, 20);
+    }
+
+    public void testSumPull() {
+        IntStream s = Primitives.range(1, 10).filter(i -> i % 2 == 0);
+
+        IntIterator ii = s.iterator();
+        int i = ii.nextInt();
+
+        Assert.assertEquals(s.sum() + i, 20);
+    }
+
+    public void testTee() {
+        int[] teeSum = new int[1];
+        int sum = Primitives.range(1, 10).filter(i -> i % 2 == 0).tee(i -> { teeSum[0] = teeSum[0] + i; }).sum();
+        Assert.assertEquals(teeSum[0], sum);
+    }
+
+    public void testForEach() {
+        int[] sum = new int[1];
+        Primitives.range(1, 10).filter(i -> i % 2 == 0).forEach(i -> { sum[0] = sum[0] + i; });
+        Assert.assertEquals(sum[0], 20);
+    }
+
+    public void testParForEach() {
+        AtomicInteger ai = new AtomicInteger(0);
+        Primitives.parRange(1, 10).filter(i -> i % 2 == 0).forEach(i -> { ai.addAndGet(i); });
+        Assert.assertEquals(ai.get(), 20);
+    }
+
+    public void testBox() {
+        List<Integer> l = Primitives.parRange(1, 10).boxed().into(new ArrayList<Integer>());
+        int sum = l.stream().reduce(0, (a, b) -> a + b);
+        Assert.assertEquals(sum, 45);
+    }
+
+    public void testUnBox() {
+       int sum = Arrays.asList(1, 2, 3, 4, 5).stream().mapToInt(i -> i).sum();
+        Assert.assertEquals(sum, 15);
+    }
+
+    public void testToArray() {
+        {
+            int[] array =  Primitives.range(1, 10).map(i -> i * 2).toArray();
+            Assert.assertEquals(array, new int[] {2, 4, 6, 8, 10, 12, 14, 16, 18});
+        }
+
+        {
+            int[] array =  Primitives.parRange(1, 10).map(i -> i * 2).toArray();
+            Assert.assertEquals(array, new int[] {2, 4, 6, 8, 10, 12, 14, 16, 18});
+        }
+    }
+
+    public void testSort() {
+        Random r = new Random();
+
+        int[] content = Primitives.repeatedly(10, () -> r.nextInt(100)).toArray();
+        int[] sortedContent = content.clone();
+        Arrays.sort(sortedContent);
+
+        {
+            int[] array =  Primitives.stream(content).sorted().toArray();
+            Assert.assertEquals(array, sortedContent);
+        }
+
+        {
+            int[] array =  Primitives.parallel(content).sorted().toArray();
+            Assert.assertEquals(array, sortedContent);
+        }
+    }
+
+    public void testSortSort() {
+        Random r = new Random();
+
+        int[] content = Primitives.repeatedly(10, () -> r.nextInt(100)).toArray();
+        int[] sortedContent = content.clone();
+        Arrays.sort(sortedContent);
+
+        {
+            int[] array =  Primitives.stream(content).sorted().sorted().toArray();
+            Assert.assertEquals(array, sortedContent);
+        }
+
+        {
+            int[] array =  Primitives.parallel(content).sorted().sorted().toArray();
+            Assert.assertEquals(array, sortedContent);
+        }
+    }
+
+    public void testSequential() {
+
+        int[] expected = Primitives.range(1, 1000).toArray();
+
+        {
+            IntNodeBuilder nb = IntNodes.makeVariableSizeBuilder();
+            Primitives.range(1, 1000).sequential().forEach(nb);
+            Assert.assertTrue(Arrays.equals(expected, nb.build().asIntArray()));
+        }
+
+        {
+            IntNodeBuilder nb = IntNodes.makeVariableSizeBuilder();
+            Primitives.parRange(1, 1000).sequential().forEach(nb);
+            Assert.assertTrue(Arrays.equals(expected, nb.build().asIntArray()));
+        }
+    }
+
+    public void testLimit() {
+        int[] expected = Primitives.range(1, 10).toArray();
+
+        {
+            int[] actual = Primitives.iterate(1, i -> i + 1).limit(9).toArray();
+            Assert.assertTrue(Arrays.equals(expected, actual));
+        }
+
+        {
+            int[] actual = Primitives.parRange(1, 100).limit(9).toArray();
+            Assert.assertTrue(Arrays.equals(expected, actual));
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/primitives/IntFilterOpTest.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,47 @@
+/*
+ * 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 org.openjdk.tests.java.util.streams.primitives;
+
+import org.openjdk.tests.java.util.streams.OpTestCase;
+import org.testng.annotations.Test;
+
+import java.util.streams.ops.Node;
+import java.util.streams.primitives.IntFilterOp;
+
+@Test
+public class IntFilterOpTest extends OpTestCase {
+
+    @Test(dataProvider = "IntStreamTestData", dataProviderClass = IntStreamTestDataProvider.class)
+    public void testOps(String name, IntStreamTestData data) {
+        Node<Integer> result = exerciseOps(data, new IntFilterOp(i -> true));
+        assertEquals(result.size(), data.size());
+
+        result = exerciseOps(data, new IntFilterOp(i -> false));
+        assertEquals(result.size(), 0);
+
+        exerciseOps(data, new IntFilterOp(i -> 0 == i % 2));
+        exerciseOps(data, new IntFilterOp(i -> 1 == i % 2));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/primitives/IntStreamIntermediateOpTestScenario.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,197 @@
+/*
+ * 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 org.openjdk.tests.java.util.streams.primitives;
+
+import org.openjdk.tests.java.util.streams.OpTestCase;
+
+import java.util.Iterator;
+import java.util.functions.Block;
+import java.util.streams.*;
+import java.util.streams.ops.FlagDeclaringOp;
+import java.util.streams.ops.IntermediateOp;
+import java.util.streams.primitives.IntBlock;
+import java.util.streams.primitives.IntIterator;
+import java.util.streams.primitives.IntStream;
+import java.util.streams.primitives.Primitives;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public enum IntStreamIntermediateOpTestScenario implements OpTestCase.IntermediateOpTestScenario {
+
+    STREAM_FOR_EACH(false) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            stream(data.seq(ops)).forEach(b);
+        }
+    },
+
+    STREAM_TO_ARRAY(false) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            for (int t : stream(data.seq(ops)).toArray()) {
+                b.applyInt(t);
+            }
+        }
+    },
+
+    STREAM_ITERATOR(false) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            for (IntIterator seqIter = stream(data.seq(ops)).iterator(); seqIter.hasNext(); )
+                b.applyInt(seqIter.nextInt());
+        }
+    },
+
+    STREAM_MIXED(false) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            IntStream stream = stream(data.seq(ops));
+            IntIterator iter = stream.iterator();
+            if (iter.hasNext())
+                b.applyInt(iter.nextInt());
+            stream.forEach(b);
+        }
+    },
+
+    STREAM_MIXED_ITERATOR_FOR_EACH(false) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            AbstractPipeline<?, ?> pipe1 = data.seq(new NoOp());
+            AbstractPipeline<?, ?> pipe2 = OpTestCase.chain(pipe1, ops);
+
+            pipe1.iterator();
+            stream(pipe2).forEach(b);
+        }
+    },
+
+    PAR_STREAM_SEQUENTIAL_FOR_EACH(true) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            stream(data.par(ops)).sequential().forEach(b);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY(true) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            for (int t : stream(data.par(ops)).toArray())
+                b.applyInt(t);
+        }
+    },
+
+    PAR_STREAM_TO_ARRAY_CLEAR_SIZED(true) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            AbstractPipeline<?, ?> pipe1 = data.seq(new FlagDeclaringOp(StreamOpFlags.NOT_SIZED) {
+                @Override
+                public StreamShape outputShape() {
+                    return StreamShapeFactory.INT_VALUE;
+                }
+
+                @Override
+                public StreamShape inputShape() {
+                    return StreamShapeFactory.INT_VALUE;
+                }
+            });
+            AbstractPipeline<?, ?> pipe2 = OpTestCase.chain(pipe1, ops);
+
+            for (int t : stream(pipe2).toArray())
+                b.applyInt(t);
+        }
+    },
+
+    PAR_STREAM_ITERATOR_TO_ARRAY_MIXED(true) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            IntStream stream = stream(data.par(ops));
+            IntIterator iter = stream.iterator();
+            if (iter.hasNext())
+                b.applyInt(iter.nextInt());
+            for (int t : stream.toArray())
+                b.applyInt(t);
+        }
+    },
+
+    PAR_STREAM_MIXED_ITERATOR_TO_ARRAY(true) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            AbstractPipeline<?, ?> pipe1 = data.par(new NoOp());
+            AbstractPipeline<?, ?> pipe2 = OpTestCase.chain(pipe1, ops);
+
+            pipe1.iterator();
+            for (int t : stream(pipe2).toArray())
+                b.applyInt(t);
+        }
+    },
+
+    // Wrap as parallel stream, and iterate in mixed mode
+    PAR_STREAM_SEQUENTIAL_MIXED(true) {
+        public void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops) {
+            IntStream stream = stream(data.par(ops));
+            IntIterator iter = stream.iterator();
+            if (iter.hasNext())
+                b.applyInt(iter.nextInt());
+            stream.sequential().forEach(b);
+        }
+    },
+
+    ;
+
+    private static class NoOp implements IntermediateOp<Integer, Integer> {
+        @Override
+        public StreamShape inputShape() {
+            return StreamShapeFactory.INT_VALUE;
+        }
+
+        @Override
+        public StreamShape outputShape() {
+            return StreamShapeFactory.INT_VALUE;
+        }
+
+        @Override
+        public Iterator<Integer> wrapIterator(int flags, Iterator<Integer> in) {
+            return in;
+        }
+
+        @Override
+        public Sink<Integer> wrapSink(int flags, Sink<Integer> sink) {
+            return sink;
+        }
+    }
+
+    private boolean isParallel;
+
+    IntStreamIntermediateOpTestScenario(boolean isParallel) {
+        this.isParallel = isParallel;
+    }
+
+    public StreamShape getShape() {
+        return StreamShapeFactory.INT_VALUE;
+    }
+
+    public boolean isParallel() {
+        return isParallel;
+    }
+
+    public <T> void run(OpTestCase.TestData<T> data, Block b, IntermediateOp[] ops) {
+        run((IntStreamTestData) data, Primitives.adapt(b), ops);
+    }
+
+    public abstract <T> void run(IntStreamTestData data, IntBlock b, IntermediateOp[] ops);
+
+    IntStream stream(AbstractPipeline<?, ?> ap) {
+        return (IntStream) ap;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/primitives/IntStreamTestData.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,97 @@
+/*
+ * 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 org.openjdk.tests.java.util.streams.primitives;
+
+import org.openjdk.tests.java.util.streams.OpTestCase;
+
+import java.util.streams.AbstractPipeline;
+import java.util.streams.StreamShape;
+import java.util.streams.StreamShapeFactory;
+import java.util.streams.primitives.IntIterator;
+import java.util.streams.primitives.IntSpliterator;
+import java.util.streams.primitives.IntStream;
+import java.util.streams.primitives.Primitives;
+
+public abstract class IntStreamTestData implements OpTestCase.TestData<Integer> {
+
+    @Override
+    @SuppressWarnings("rawtypes")
+    public StreamShape getShape() {
+        return StreamShapeFactory.INT_VALUE;
+    }
+
+    @SuppressWarnings("unchecked")
+    public IntStream seqStream() {
+        return (IntStream) seq();
+    }
+
+    @SuppressWarnings("unchecked")
+    public IntStream parStream() {
+        return (IntStream) par();
+    }
+
+    public static class ArrayData extends IntStreamTestData {
+        private final String name;
+        private final int[] array;
+
+        public ArrayData(String name, int[] array) {
+            this.name = name;
+            this.array = array;
+        }
+
+        @Override
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        public AbstractPipeline<?, Integer> seq() {
+            return (AbstractPipeline<?, Integer>) Primitives.stream(array);
+        }
+
+        @Override
+        @SuppressWarnings({ "rawtypes", "unchecked" })
+        public AbstractPipeline<?, Integer> par() {
+            return (AbstractPipeline<?, Integer>) Primitives.parallel(array);
+        }
+
+        @Override
+        public IntIterator iterator() {
+            return Primitives.iterator(array);
+        }
+
+        @Override
+        public IntSpliterator spliterator() {
+            return Primitives.spliterator(array);
+        }
+
+        @Override
+        public int size() {
+            return array.length;
+        }
+
+        @Override
+        public String toString() {
+            return name;
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test-ng/tests/org/openjdk/tests/java/util/streams/primitives/IntStreamTestDataProvider.java	Wed Nov 14 18:49:41 2012 +0100
@@ -0,0 +1,99 @@
+/*
+ * 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 org.openjdk.tests.java.util.streams.primitives;
+
+import org.openjdk.tests.java.util.LambdaTestHelpers;
+import org.testng.annotations.DataProvider;
+
+import java.util.*;
+import java.util.functions.Combiner;
+
+public class IntStreamTestDataProvider {
+    private static final int[] to0 = new int[0];
+    private static final int[] to1 = new int[1];
+    private static final int[] to10 = new int[10];
+    private static final int[] to100 = new int[100];
+    private static final int[] to1000 = new int[1000];
+    private static final int[] reversed = new int[100];
+    private static final int[] ones = new int[100];
+    private static final int[] twice = new int[200];
+    private static final int[] pseudoRandom;
+
+    private static final Object[][] testData;
+
+    static {
+        int[][] arrays = {to0, to1, to10, to100, to1000};
+        for (int[] arr : arrays) {
+            for (int i = 0; i < arr.length; i++) {
+                arr[i] = i;
+            }
+        }
+        for (int i = 0; i < reversed.length; i++) {
+            reversed[i] = reversed.length - i;
+        }
+        for (int i = 0; i < ones.length; i++) {
+            ones[i] = 1;
+        }
+        System.arraycopy(to100, 0, twice, 0, to100.length);
+        System.arraycopy(to100, 0, twice, to100.length, to100.length);
+        pseudoRandom = new int[LambdaTestHelpers.LONG_STRING.length()];
+        for (int i = 0; i < LambdaTestHelpers.LONG_STRING.length(); i++) {
+            pseudoRandom[i] = (int) LambdaTestHelpers.LONG_STRING.charAt(i);
+        }
+    }
+
+    static final Object[][] arrays = {
+            {"empty", to0},
+            {"0..1", to1},
+            {"0..10", to10},
+            {"0..100", to100},
+            {"0..1000", to1000},
+            {"100x[1]", ones},
+            {"2x[0..100]", twice},
+            {"reverse 0..100", reversed},
+            {"pseudorandom", pseudoRandom}
+    };
+
+    static {
+        List<Object[]> list = new ArrayList<>();
+        for (Object[] data : arrays) {
+            final Object name = data[0];
+            final int[] ints = (int[])data[1];
+
+            list.add(e("array:" + name, ints, IntStreamTestData.ArrayData::new));
+        }
+        testData = list.toArray(new Object[0][]);
+    }
+
+    static <T> Object[] e(String description, int[] data, Combiner<IntStreamTestData, String, int[]> m) {
+        return new Object[] { description, m.combine(description, data) };
+    }
+
+    // Return an array of ( String name, IntTestData<Integer> )
+    @DataProvider(name = "IntStreamTestData")
+    public static Object[][] makeValueTestData() {
+        return testData;
+    }
+}