changeset 8463:fad441986ad6

- re-introduce a simpler Spliterator.OfPrimitive based type for primitive specialization of Spliterator that enables more code sharing of primitive spliterator implementations. - Primitive support for slice spliterator. Contributed-By: Brian Goetz <brian.goetz@Oracle.COM>, Paul Sandoz <paul.sandoz@oracle.com>
author psandoz
date Mon, 06 May 2013 18:26:12 +0200
parents 3a44a6038054
children 403a34d53eae
files src/share/classes/java/util/Spliterator.java src/share/classes/java/util/stream/AbstractPipeline.java src/share/classes/java/util/stream/Node.java src/share/classes/java/util/stream/Nodes.java src/share/classes/java/util/stream/PipelineHelper.java src/share/classes/java/util/stream/SliceOps.java src/share/classes/java/util/stream/SpinedBuffer.java src/share/classes/java/util/stream/StreamSpliterators.java
diffstat 8 files changed, 535 insertions(+), 533 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/Spliterator.java	Mon May 06 10:27:01 2013 +0200
+++ b/src/share/classes/java/util/Spliterator.java	Mon May 06 18:26:12 2013 +0200
@@ -567,13 +567,20 @@
     public static final int SUBSIZED = 0x00004000;
 
     /**
-     * A Spliterator specialized for {@code int} values.
+     * A Spliterator specialized for primitive values.
+     *
+     * @param <T> the primitive wrapper type of elements returned by this
+     * Spliterator
+     * @param <T_CONS> the type of consumer associated with the primitive
+     * wrapper type
+     * @param <T_SPL> the type of primitive Spliterator
+     *
      * @since 1.8
      */
-    public interface OfInt extends Spliterator<Integer> {
-
+    public interface OfPrimitive<T, T_CONS, T_SPL extends Spliterator.OfPrimitive<T, T_CONS, T_SPL>>
+            extends Spliterator<T> {
         @Override
-        OfInt trySplit();
+        T_SPL trySplit();
 
         /**
          * If a remaining element exists, performs the given action on it,
@@ -587,7 +594,7 @@
          * upon entry to this method, else {@code true}.
          * @throws NullPointerException if the specified action is null
          */
-        boolean tryAdvance(IntConsumer action);
+        boolean tryAdvance(T_CONS action);
 
         /**
          * Performs the given action for each remaining element, sequentially in
@@ -604,6 +611,28 @@
          * @param action The action
          * @throws NullPointerException if the specified action is null
          */
+        default void forEachRemaining(T_CONS action) {
+            do { } while (tryAdvance(action));
+        }
+    }
+
+    /**
+     * A Spliterator specialized for {@code int} values.
+     * @since 1.8
+     */
+    public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {
+
+        @Override
+        OfInt trySplit();
+
+        /**
+         * {@inheritDoc}
+         */
+        boolean tryAdvance(IntConsumer action);
+
+        /**
+         * {@inheritDoc}
+         */
         default void forEachRemaining(IntConsumer action) {
             do { } while (tryAdvance(action));
         }
@@ -659,39 +688,18 @@
      * A Spliterator specialized for {@code long} values.
      * @since 1.8
      */
-    public interface OfLong extends Spliterator<Long> {
+    public interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> {
 
         @Override
         OfLong trySplit();
 
         /**
-         * If a remaining element exists, performs the given action on it,
-         * returning {@code true}; else returns {@code false}.  If this
-         * Spliterator is {@link #ORDERED} the action is performed on the
-         * next element in encounter order.  Exceptions thrown by the
-         * action are relayed to the caller.
-         *
-         * @param action The action
-         * @return {@code false} if no remaining elements existed
-         * upon entry to this method, else {@code true}.
-         * @throws NullPointerException if the specified action is null
+         * {@inheritDoc}
          */
         boolean tryAdvance(LongConsumer action);
 
         /**
-         * Performs the given action for each remaining element, sequentially in
-         * the current thread, until all elements have been processed or the
-         * action throws an exception.  If this Spliterator is {@link #ORDERED},
-         * actions are performed in encounter order.  Exceptions thrown by the
-         * action are relayed to the caller.
-         *
-         * @implSpec
-         * The default implementation repeatedly invokes {@link #tryAdvance}
-         * until it returns {@code false}.  It should be overridden whenever
-         * possible.
-         *
-         * @param action The action
-         * @throws NullPointerException if the specified action is null
+         * {@inheritDoc}
          */
         default void forEachRemaining(LongConsumer action) {
             do { } while (tryAdvance(action));
@@ -748,39 +756,18 @@
      * A Spliterator specialized for {@code double} values.
      * @since 1.8
      */
-    public interface OfDouble extends Spliterator<Double> {
+    public interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> {
 
         @Override
         OfDouble trySplit();
 
         /**
-         * If a remaining element exists, performs the given action on it,
-         * returning {@code true}; else returns {@code false}.  If this
-         * Spliterator is {@link #ORDERED} the action is performed on the
-         * next element in encounter order.  Exceptions thrown by the
-         * action are relayed to the caller.
-         *
-         * @param action The action
-         * @return {@code false} if no remaining elements existed
-         * upon entry to this method, else {@code true}.
-         * @throws NullPointerException if the specified action is null
+         * {@inheritDoc}
          */
         boolean tryAdvance(DoubleConsumer action);
 
         /**
-         * Performs the given action for each remaining element, sequentially in
-         * the current thread, until all elements have been processed or the
-         * action throws an exception.  If this Spliterator is {@link #ORDERED},
-         * actions are performed in encounter order.  Exceptions thrown by the
-         * action are relayed to the caller.
-         *
-         * @implSpec
-         * The default implementation repeatedly invokes {@link #tryAdvance}
-         * until it returns {@code false}.  It should be overridden whenever
-         * possible.
-         *
-         * @param action The action
-         * @throws NullPointerException if the specified action is null
+         * {@inheritDoc}
          */
         default void forEachRemaining(DoubleConsumer action) {
             do { } while (tryAdvance(action));
--- a/src/share/classes/java/util/stream/AbstractPipeline.java	Mon May 06 10:27:01 2013 +0200
+++ b/src/share/classes/java/util/stream/AbstractPipeline.java	Mon May 06 18:26:12 2013 +0200
@@ -448,6 +448,15 @@
     // PipelineHelper
 
     @Override
+    final StreamShape getHeadShape() {
+        AbstractPipeline p = AbstractPipeline.this;
+        while (p.depth > 0) {
+            p = p.previousStage;
+        }
+        return p.getOutputShape();
+    }
+
+    @Override
     final <P_IN> long exactOutputSizeIfKnown(Spliterator<P_IN> spliterator) {
         return StreamOpFlag.SIZED.isKnown(getStreamAndOpFlags()) ? spliterator.getExactSizeIfKnown() : -1;
     }
--- a/src/share/classes/java/util/stream/Node.java	Mon May 06 10:27:01 2013 +0200
+++ b/src/share/classes/java/util/stream/Node.java	Mon May 06 18:26:12 2013 +0200
@@ -192,19 +192,55 @@
         }
     }
 
-    /**
-     * Specialized {@code Node} for int elements
-     */
-    interface OfInt extends Node<Integer> {
+    public interface OfPrimitive<T,
+                                 T_CONS,
+                                 T_SPL extends Spliterator.OfPrimitive<T, T_CONS, T_SPL>,
+                                 T_NODE extends OfPrimitive<T, T_CONS, T_SPL, T_NODE>>
+            extends Node<T> {
 
         /**
          * {@inheritDoc}
          *
-         * @return a {@link Spliterator.OfInt} describing the elements of this
-         *         node
+         * @return a {@link Spliterator.OfPrimitive} describing the elements of
+         *         this node
          */
         @Override
-        Spliterator.OfInt spliterator();
+        T_SPL spliterator();
+
+        /**
+         * Traverses the elements of this node, and invoke the provided
+         * {@code action} with each element.
+         *
+         * @param action a consumer that is to be invoked with each
+         *        element in this {@code Node.OfPrimitive}
+         */
+        void forEach(T_CONS action);
+
+        @Override
+        default T_NODE getChild(int i) {
+            throw new IndexOutOfBoundsException();
+        }
+
+        /**
+         * {@inheritDoc}
+         *
+         * @implSpec the default implementation invokes the generator to create
+         * an instance of a boxed primitive array with a length of
+         * {@link #count()} and then invokes {@link #copyInto(T[], int)} with
+         * that array at an offset of 0.
+         */
+        @Override
+        default T[] asArray(IntFunction<T[]> generator) {
+            T[] boxed = generator.apply((int) count());
+            copyInto(boxed, 0);
+            return boxed;
+        }
+    }
+
+    /**
+     * Specialized {@code Node} for int elements
+     */
+    interface OfInt extends OfPrimitive<Integer, IntConsumer, Spliterator.OfInt, OfInt> {
 
         /**
          * {@inheritDoc}
@@ -227,31 +263,6 @@
         }
 
         /**
-         * Traverses the elements of this node, and invoke the provided
-         * {@code IntConsumer} with each element.
-         *
-         * @param consumer a {@code IntConsumer} that is to be invoked with each
-         *        element in this {@code Node}
-         */
-        void forEach(IntConsumer consumer);
-
-        /**
-         * {@inheritDoc}
-         *
-         * @implSpec the default implementation invokes the generator to create
-         * an instance of an Integer[] array with a length of {@link #count()}
-         * and then invokes {@link #copyInto(Integer[], int)} with that
-         * Integer[] array at an offset of 0.  This is not efficient and it is
-         * recommended to invoke {@link #asIntArray()}.
-         */
-        @Override
-        default Integer[] asArray(IntFunction<Integer[]> generator) {
-            Integer[] boxed = generator.apply((int) count());
-            copyInto(boxed, 0);
-            return boxed;
-        }
-
-        /**
          * {@inheritDoc}
          *
          * @implSpec the default implementation invokes {@link #asIntArray()} to
@@ -270,11 +281,6 @@
             }
         }
 
-        @Override
-        default Node.OfInt getChild(int i) {
-            throw new IndexOutOfBoundsException();
-        }
-
         /**
          * Views this node as an int[] array.
          *
@@ -309,22 +315,12 @@
         default StreamShape getShape() {
             return StreamShape.INT_VALUE;
         }
-
     }
 
     /**
      * Specialized {@code Node} for long elements
      */
-    interface OfLong extends Node<Long> {
-
-        /**
-         * {@inheritDoc}
-         *
-         * @return a {@link Spliterator.OfLong} describing the elements of this
-         *         node
-         */
-        @Override
-        Spliterator.OfLong spliterator();
+    interface OfLong extends OfPrimitive<Long, LongConsumer, Spliterator.OfLong, OfLong> {
 
         /**
          * {@inheritDoc}
@@ -347,31 +343,6 @@
         }
 
         /**
-         * Traverses the elements of this node, and invoke the provided
-         * {@code LongConsumer} with each element.
-         *
-         * @param consumer a {@code LongConsumer} that is to be invoked with
-         *        each element in this {@code Node}
-         */
-        void forEach(LongConsumer consumer);
-
-        /**
-         * {@inheritDoc}
-         *
-         * @implSpec the default implementation invokes the generator to create
-         * an instance of a Long[] array with a length of {@link #count()} and
-         * then invokes {@link #copyInto(Long[], int)} with that Long[] array at
-         * an offset of 0.  This is not efficient and it is recommended to
-         * invoke {@link #asLongArray()}.
-         */
-        @Override
-        default Long[] asArray(IntFunction<Long[]> generator) {
-            Long[] boxed = generator.apply((int) count());
-            copyInto(boxed, 0);
-            return boxed;
-        }
-
-        /**
          * {@inheritDoc}
          *
          * @implSpec the default implementation invokes {@link #asLongArray()}
@@ -390,11 +361,6 @@
             }
         }
 
-        @Override
-        default Node.OfLong getChild(int i) {
-            throw new IndexOutOfBoundsException();
-        }
-
         /**
          * Views this node as a long[] array.
          *
@@ -429,23 +395,12 @@
         default StreamShape getShape() {
             return StreamShape.LONG_VALUE;
         }
-
-
     }
 
     /**
      * Specialized {@code Node} for double elements
      */
-    interface OfDouble extends Node<Double> {
-
-        /**
-         * {@inheritDoc}
-         *
-         * @return A {@link Spliterator.OfDouble} describing the elements of
-         *         this node
-         */
-        @Override
-        Spliterator.OfDouble spliterator();
+    interface OfDouble extends OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble, OfDouble> {
 
         /**
          * {@inheritDoc}
@@ -467,36 +422,11 @@
             }
         }
 
-        /**
-         * Traverses the elements of this node, and invoke the provided
-         * {@code DoubleConsumer} with each element.
-         *
-         * @param consumer A {@code DoubleConsumer} that is to be invoked with
-         *        each element in this {@code Node}
-         */
-        void forEach(DoubleConsumer consumer);
-
         //
 
         /**
          * {@inheritDoc}
          *
-         * @implSpec the default implementation invokes the generator to create
-         * an instance of a Double[] array with a length of {@link #count()} and
-         * then invokes {@link #copyInto(Double[], int)} with that Double[]
-         * array at an offset of 0.  This is not efficient and it is recommended
-         * to invoke {@link #asDoubleArray()}.
-         */
-        @Override
-        default Double[] asArray(IntFunction<Double[]> generator) {
-            Double[] boxed = generator.apply((int) count());
-            copyInto(boxed, 0);
-            return boxed;
-        }
-
-        /**
-         * {@inheritDoc}
-         *
          * @implSpec the default implementation invokes {@link #asDoubleArray()}
          * to obtain a double[] array then and copies the elements from that
          * double[] array into the boxed Double[] array.  This is not efficient
@@ -513,11 +443,6 @@
             }
         }
 
-        @Override
-        default Node.OfDouble getChild(int i) {
-            throw new IndexOutOfBoundsException();
-        }
-
         /**
          * Views this node as a double[] array.
          *
--- a/src/share/classes/java/util/stream/Nodes.java	Mon May 06 10:27:01 2013 +0200
+++ b/src/share/classes/java/util/stream/Nodes.java	Mon May 06 18:26:12 2013 +0200
@@ -902,7 +902,7 @@
     /** Abstract class for spliterator for all internal node classes */
     private static abstract class InternalNodeSpliterator<T,
                                                           S extends Spliterator<T>,
-                                                          N extends Node<T>, C>
+                                                          N extends Node<T>>
             implements Spliterator<T> {
         // Node we are pointing to
         // null if full traversal has occurred
@@ -960,7 +960,7 @@
             return null;
         }
 
-        protected final boolean internalTryAdvance(C consumer) {
+        protected final boolean initTryAdvance() {
             if (curNode == null)
                 return false;
 
@@ -981,29 +981,12 @@
                 else
                     tryAdvanceSpliterator = lastNodeSpliterator;
             }
-
-            boolean hasNext = tryAdvance(tryAdvanceSpliterator, consumer);
-            if (!hasNext) {
-                if (lastNodeSpliterator == null) {
-                    // Advance to the spliterator of the next non-empty leaf node
-                    Node<T> leaf = findNextLeafNode(tryAdvanceStack);
-                    if (leaf != null) {
-                        tryAdvanceSpliterator = (S) leaf.spliterator();
-                        // Since the node is not-empty the spliterator can be advanced
-                        return tryAdvance(tryAdvanceSpliterator, consumer);
-                    }
-                }
-                // No more elements to traverse
-                curNode = null;
-            }
-            return hasNext;
+            return true;
         }
 
-        protected abstract boolean tryAdvance(S spliterator, C consumer);
-
         @Override
         @SuppressWarnings("unchecked")
-        public S trySplit() {
+        public final S trySplit() {
             if (curNode == null || tryAdvanceSpliterator != null)
                 return null; // Cannot split if fully or partially traversed
             else if (lastNodeSpliterator != null)
@@ -1024,7 +1007,7 @@
         }
 
         @Override
-        public long estimateSize() {
+        public final long estimateSize() {
             if (curNode == null)
                 return 0;
 
@@ -1041,12 +1024,12 @@
         }
 
         @Override
-        public int characteristics() {
+        public final int characteristics() {
             return Spliterator.SIZED;
         }
 
         private static final class OfRef<T>
-                extends InternalNodeSpliterator<T, Spliterator<T>, Node<T>, Consumer<? super T>> {
+                extends InternalNodeSpliterator<T, Spliterator<T>, Node<T>> {
 
             OfRef(Node<T> curNode) {
                 super(curNode);
@@ -1054,13 +1037,24 @@
 
             @Override
             public boolean tryAdvance(Consumer<? super T> consumer) {
-                return internalTryAdvance(consumer);
-            }
+                if (!initTryAdvance())
+                    return false;
 
-            @Override
-            protected boolean tryAdvance(Spliterator<T> spliterator,
-                                         Consumer<? super T> consumer) {
-                return spliterator.tryAdvance(consumer);
+                boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    if (lastNodeSpliterator == null) {
+                        // Advance to the spliterator of the next non-empty leaf node
+                        Node<T> leaf = findNextLeafNode(tryAdvanceStack);
+                        if (leaf != null) {
+                            tryAdvanceSpliterator = leaf.spliterator();
+                            // Since the node is not-empty the spliterator can be advanced
+                            return tryAdvanceSpliterator.tryAdvance(consumer);
+                        }
+                    }
+                    // No more elements to traverse
+                    curNode = null;
+                }
+                return hasNext;
             }
 
             @Override
@@ -1085,34 +1079,48 @@
             }
         }
 
-        private static final class OfInt
-                extends InternalNodeSpliterator<Integer, Spliterator.OfInt, Node.OfInt, IntConsumer>
-                implements Spliterator.OfInt {
+        private static abstract class OfPrimitive<T,
+                                                  T_SPL extends Spliterator.OfPrimitive<T, T_CONS, T_SPL>,
+                                                  N extends Node.OfPrimitive<T, T_CONS, T_SPL, N>,
+                                                  T_CONS>
+                extends InternalNodeSpliterator<T, T_SPL, N>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPL> {
 
-            OfInt(Node.OfInt cur) {
+            OfPrimitive(N cur) {
                 super(cur);
             }
 
             @Override
-            public boolean tryAdvance(IntConsumer consumer) {
-                return internalTryAdvance(consumer);
+            public boolean tryAdvance(T_CONS consumer) {
+                if (!initTryAdvance())
+                    return false;
+
+                boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
+                if (!hasNext) {
+                    if (lastNodeSpliterator == null) {
+                        // Advance to the spliterator of the next non-empty leaf node
+                        N leaf = findNextLeafNode(tryAdvanceStack);
+                        if (leaf != null) {
+                            tryAdvanceSpliterator = leaf.spliterator();
+                            // Since the node is not-empty the spliterator can be advanced
+                            return tryAdvanceSpliterator.tryAdvance(consumer);
+                        }
+                    }
+                    // No more elements to traverse
+                    curNode = null;
+                }
+                return hasNext;
             }
 
             @Override
-            protected boolean tryAdvance(Spliterator.OfInt spliterator,
-                                         IntConsumer consumer) {
-                return spliterator.tryAdvance(consumer);
-            }
-
-            @Override
-            public void forEachRemaining(IntConsumer consumer) {
+            public void forEachRemaining(T_CONS consumer) {
                 if (curNode == null)
                     return;
 
                 if (tryAdvanceSpliterator == null) {
                     if (lastNodeSpliterator == null) {
-                        Deque<Node.OfInt> stack = initStack();
-                        Node.OfInt leaf;
+                        Deque<N> stack = initStack();
+                        N leaf;
                         while ((leaf = findNextLeafNode(stack)) != null) {
                             leaf.forEach(consumer);
                         }
@@ -1126,86 +1134,31 @@
             }
         }
 
+        private static final class OfInt
+                extends OfPrimitive<Integer, Spliterator.OfInt, Node.OfInt, IntConsumer>
+                implements Spliterator.OfInt {
+
+            OfInt(Node.OfInt cur) {
+                super(cur);
+            }
+        }
+
         private static final class OfLong
-                extends InternalNodeSpliterator<Long, Spliterator.OfLong, Node.OfLong, LongConsumer>
+                extends OfPrimitive<Long, Spliterator.OfLong, Node.OfLong, LongConsumer>
                 implements Spliterator.OfLong {
 
             OfLong(Node.OfLong cur) {
                 super(cur);
             }
-
-            @Override
-            public boolean tryAdvance(LongConsumer consumer) {
-                return internalTryAdvance(consumer);
-            }
-
-            @Override
-            protected boolean tryAdvance(Spliterator.OfLong spliterator,
-                                         LongConsumer consumer) {
-                return spliterator.tryAdvance(consumer);
-            }
-
-            @Override
-            public void forEachRemaining(LongConsumer consumer) {
-                if (curNode == null)
-                    return;
-
-                if (tryAdvanceSpliterator == null) {
-                    if (lastNodeSpliterator == null) {
-                        Deque<Node.OfLong> stack = initStack();
-                        Node.OfLong leaf;
-                        while ((leaf = findNextLeafNode(stack)) != null) {
-                            leaf.forEach(consumer);
-                        }
-                        curNode = null;
-                    }
-                    else
-                        lastNodeSpliterator.forEachRemaining(consumer);
-                }
-                else
-                    while(tryAdvance(consumer)) { }
-            }
         }
 
         private static final class OfDouble
-                extends InternalNodeSpliterator<Double, Spliterator.OfDouble, Node.OfDouble, DoubleConsumer>
+                extends OfPrimitive<Double, Spliterator.OfDouble, Node.OfDouble, DoubleConsumer>
                 implements Spliterator.OfDouble {
 
             OfDouble(Node.OfDouble cur) {
                 super(cur);
             }
-
-            @Override
-            public boolean tryAdvance(DoubleConsumer consumer) {
-                return internalTryAdvance(consumer);
-            }
-
-            @Override
-            protected boolean tryAdvance(Spliterator.OfDouble spliterator,
-                                         DoubleConsumer consumer) {
-                return spliterator.tryAdvance(consumer);
-            }
-
-            @Override
-            public void forEachRemaining(DoubleConsumer consumer) {
-                if (curNode == null)
-                    return;
-
-                if (tryAdvanceSpliterator == null) {
-                    if (lastNodeSpliterator == null) {
-                        Deque<Node.OfDouble> stack = initStack();
-                        Node.OfDouble leaf;
-                        while ((leaf = findNextLeafNode(stack)) != null) {
-                            leaf.forEach(consumer);
-                        }
-                        curNode = null;
-                    }
-                    else
-                        lastNodeSpliterator.forEachRemaining(consumer);
-                }
-                else
-                    while(tryAdvance(consumer)) { }
-            }
         }
     }
 
--- a/src/share/classes/java/util/stream/PipelineHelper.java	Mon May 06 10:27:01 2013 +0200
+++ b/src/share/classes/java/util/stream/PipelineHelper.java	Mon May 06 18:26:12 2013 +0200
@@ -44,7 +44,7 @@
  * and {@link AbstractPipeline#opEvaluateParallel(PipelineHelper, java.util.Spliterator,
  * java.util.function.IntFunction)}, methods, which can use the
  * {@code PipelineHelper} to access information about the pipeline such as
- * input shape, output shape, stream flags, and size, and use the helper methods
+ * head shape, stream flags, and size, and use the helper methods
  * such as {@link #wrapAndCopyInto(Sink, Spliterator)},
  * {@link #copyInto(Sink, Spliterator)}, and {@link #wrapSink(Sink)} to execute
  * pipeline operations.
@@ -55,6 +55,13 @@
 abstract class PipelineHelper<P_OUT> {
 
     /**
+     * Gets the stream shape at the head, or input, of the pipeline segment.
+     *
+     * @return the stream shape at the head of the pipeline segment.
+     */
+    abstract StreamShape getHeadShape();
+
+    /**
      * Gets the combined stream and operation flags for the output of the described
      * pipeline.  This will incorporate stream flags from the stream source, all
      * the intermediate operations and the terminal operation.
--- a/src/share/classes/java/util/stream/SliceOps.java	Mon May 06 10:27:01 2013 +0200
+++ b/src/share/classes/java/util/stream/SliceOps.java	Mon May 06 18:26:12 2013 +0200
@@ -42,7 +42,7 @@
     private SliceOps() { }
 
     /**
-     * Calculate the sliced size given the current size, number of elements
+     * Calculates the sliced size given the current size, number of elements
      * skip, and the number of elements to limit.
      *
      * @param size the current size
@@ -56,6 +56,46 @@
     }
 
     /**
+     * Calculates the slice fence, which is one past the index of the slice
+     * range
+     * @param skip the number of elements to skip, assumed to be >= 0
+     * @param limit the number of elements to limit, assumed to be >= 0, with
+     *        a value of {@code Long.MAX_VALUE} if there is no limit
+     * @return the slice fence.
+     */
+    private static long calcSliceFence(long skip, long limit) {
+        long sliceFence = limit >= 0 ? skip + limit : Long.MAX_VALUE;
+        // Check for overflow
+        return (sliceFence >= 0) ? sliceFence : Long.MAX_VALUE;
+    }
+
+    /**
+     * Creates a slice spliterator given a stream shape governing the
+     * spliterator type.
+     */
+    @SuppressWarnings("unchecked")
+    private static <P_IN> Spliterator<P_IN> sliceSpliterator(StreamShape shape,
+                                                             Spliterator<P_IN> s,
+                                                             long skip, long limit) {
+        long sliceFence = calcSliceFence(skip, limit);
+        switch (shape) {
+            case REFERENCE:
+                return new StreamSpliterators.SliceSpliterator<>(s, skip, sliceFence);
+            case INT_VALUE:
+                return (Spliterator<P_IN>) new StreamSpliterators
+                        .SliceSpliterator.OfInt((Spliterator.OfInt) s, skip, sliceFence);
+            case LONG_VALUE:
+                return (Spliterator<P_IN>) new StreamSpliterators
+                        .SliceSpliterator.OfLong((Spliterator.OfLong) s, skip, sliceFence);
+            case DOUBLE_VALUE:
+                return (Spliterator<P_IN>) new StreamSpliterators
+                        .SliceSpliterator.OfDouble((Spliterator.OfDouble) s, skip, sliceFence);
+            default:
+                throw new IllegalStateException("Unknown shape " + shape);
+        }
+    }
+
+    /**
      * Appends a "slice" operation to the provided stream.  The slice operation
      * may be may be skip-only, limit-only, or skip-and-limit.
      *
@@ -72,23 +112,14 @@
 
         return new ReferencePipeline.StatefulOp<T,T>(upstream, StreamShape.REFERENCE,
                                                      flags(limit)) {
-
-            private <S> Spliterator<S> sliceSpliterator(Spliterator<S> s) {
-                long sliceFence = limit >= 0 ? skip + limit : Long.MAX_VALUE;
-                // Check for overflow
-                if (sliceFence < 0)
-                    sliceFence = Long.MAX_VALUE;
-                return new StreamSpliterators.SliceSpliterator<>(
-                        s,
-                        skip,
-                        sliceFence);
-            }
-
             @Override
             <P_IN> Spliterator<T> opEvaluateParallelLazy(PipelineHelper<T> helper, Spliterator<P_IN> spliterator) {
                 if (helper.exactOutputSizeIfKnown(spliterator) > 0 &&
                     spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
-                    return sliceSpliterator(helper.wrapSpliterator(spliterator));
+                    return new StreamSpliterators.SliceSpliterator<>(
+                            helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
                 }
                 else {
                     return new SliceTask<>(this, helper, spliterator, i -> (T[]) new Object[i], skip, limit).
@@ -100,11 +131,12 @@
             <P_IN> Node<T> opEvaluateParallel(PipelineHelper<T> helper,
                                               Spliterator<P_IN> spliterator,
                                               IntFunction<T[]> generator) {
-
                 if (helper.exactOutputSizeIfKnown(spliterator) > 0 &&
                     spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
-                    // @@@ method on AbstractPipeline and not PipelineHelper
-                    return evaluateToNode(helper, sliceSpliterator(spliterator), true, generator);
+                    // method on AbstractPipeline and not PipelineHelper
+                    return evaluateToNode(helper,
+                                          sliceSpliterator(helper.getHeadShape(), spliterator, skip, limit),
+                                          true, generator);
                 }
                 else {
                     return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
@@ -162,10 +194,37 @@
         return new IntPipeline.StatefulOp<Integer>(upstream, StreamShape.INT_VALUE,
                                                    flags(limit)) {
             @Override
+            <P_IN> Spliterator<Integer> opEvaluateParallelLazy(PipelineHelper<Integer> helper,
+                                                               Spliterator<P_IN> spliterator) {
+                if (helper.exactOutputSizeIfKnown(spliterator) > 0 &&
+                    spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfInt(
+                            (Spliterator.OfInt) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, i -> new Integer[i], skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
             <P_IN> Node<Integer> opEvaluateParallel(PipelineHelper<Integer> helper,
                                                     Spliterator<P_IN> spliterator,
                                                     IntFunction<Integer[]> generator) {
-                return new SliceTask<>(this, helper, spliterator, generator, skip, limit).invoke();
+                if (helper.exactOutputSizeIfKnown(spliterator) > 0 &&
+                    spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // method on AbstractPipeline and not PipelineHelper
+
+                    return evaluateToNode(helper,
+                                          sliceSpliterator(helper.getHeadShape(), spliterator, skip, limit),
+                                          true, generator);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
             }
 
             @Override
@@ -218,10 +277,36 @@
         return new LongPipeline.StatefulOp<Long>(upstream, StreamShape.LONG_VALUE,
                                                  flags(limit)) {
             @Override
+            <P_IN> Spliterator<Long> opEvaluateParallelLazy(PipelineHelper<Long> helper,
+                                                            Spliterator<P_IN> spliterator) {
+                if (helper.exactOutputSizeIfKnown(spliterator) > 0 &&
+                    spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfLong(
+                            (Spliterator.OfLong) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, i -> new Long[i], skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
             <P_IN> Node<Long> opEvaluateParallel(PipelineHelper<Long> helper,
                                                  Spliterator<P_IN> spliterator,
                                                  IntFunction<Long[]> generator) {
-                return new SliceTask<>(this, helper, spliterator, generator, skip, limit).invoke();
+                if (helper.exactOutputSizeIfKnown(spliterator) > 0 &&
+                    spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // method on AbstractPipeline and not PipelineHelper
+                    return evaluateToNode(helper,
+                                          sliceSpliterator(helper.getHeadShape(), spliterator, skip, limit),
+                                          true, generator);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
             }
 
             @Override
@@ -274,10 +359,36 @@
         return new DoublePipeline.StatefulOp<Double>(upstream, StreamShape.DOUBLE_VALUE,
                                                      flags(limit)) {
             @Override
+            <P_IN> Spliterator<Double> opEvaluateParallelLazy(PipelineHelper<Double> helper,
+                                                              Spliterator<P_IN> spliterator) {
+                if (helper.exactOutputSizeIfKnown(spliterator) > 0 &&
+                    spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    return new StreamSpliterators.SliceSpliterator.OfDouble(
+                            (Spliterator.OfDouble) helper.wrapSpliterator(spliterator),
+                            skip,
+                            calcSliceFence(skip, limit));
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, i -> new Double[i], skip, limit).
+                            invoke().spliterator();
+                }
+            }
+
+            @Override
             <P_IN> Node<Double> opEvaluateParallel(PipelineHelper<Double> helper,
                                                    Spliterator<P_IN> spliterator,
                                                    IntFunction<Double[]> generator) {
-                return new SliceTask<>(this, helper, spliterator, generator, skip, limit).invoke();
+                if (helper.exactOutputSizeIfKnown(spliterator) > 0 &&
+                    spliterator.hasCharacteristics(Spliterator.SUBSIZED)) {
+                    // method on AbstractPipeline and not PipelineHelper
+                    return evaluateToNode(helper,
+                                          sliceSpliterator(helper.getHeadShape(), spliterator, skip, limit),
+                                          true, generator);
+                }
+                else {
+                    return new SliceTask<>(this, helper, spliterator, generator, skip, limit).
+                            invoke();
+                }
             }
 
             @Override
@@ -489,90 +600,4 @@
             }
         }
     }
-
-    // @@@ Currently unused -- optimization for when all sizes are known
-//    private static class SizedSliceTask<S, T> extends AbstractShortCircuitTask<S, T, Node<T>, SizedSliceTask<S, T>> {
-//        private final int targetOffset, targetSize;
-//        private final int offset, size;
-//
-//        private SizedSliceTask(ParallelPipelineHelper<S, T> helper, int offset, int size) {
-//            super(helper);
-//            targetOffset = offset;
-//            targetSize = size;
-//            this.offset = 0;
-//            this.size = spliterator.getSizeIfKnown();
-//        }
-//
-//        private SizedSliceTask(SizedSliceTask<S, T> parent, Spliterator<S> spliterator) {
-//            // Makes assumptions about order in which siblings are created and linked into parent!
-//            super(parent, spliterator);
-//            targetOffset = parent.targetOffset;
-//            targetSize = parent.targetSize;
-//            int siblingSizes = 0;
-//            for (SizedSliceTask<S, T> sibling = parent.children; sibling != null; sibling = sibling.nextSibling)
-//                siblingSizes += sibling.size;
-//            size = spliterator.getSizeIfKnown();
-//            offset = parent.offset + siblingSizes;
-//        }
-//
-//        @Override
-//        protected SizedSliceTask<S, T> makeChild(Spliterator<S> spliterator) {
-//            return new SizedSliceTask<>(this, spliterator);
-//        }
-//
-//        @Override
-//        protected Node<T> getEmptyResult() {
-//            return Nodes.emptyNode();
-//        }
-//
-//        @Override
-//        public boolean taskCanceled() {
-//            if (offset > targetOffset+targetSize || offset+size < targetOffset)
-//                return true;
-//            else
-//                return super.taskCanceled();
-//        }
-//
-//        @Override
-//        protected Node<T> doLeaf() {
-//            int skipLeft = Math.max(0, targetOffset - offset);
-//            int skipRight = Math.max(0, offset + size - (targetOffset + targetSize));
-//            if (skipLeft == 0 && skipRight == 0)
-//                return helper.into(Nodes.<T>makeBuilder(spliterator.getSizeIfKnown())).build();
-//            else {
-//                // If we're the first or last node that intersects the target range, peel off irrelevant elements
-//                int truncatedSize = size - skipLeft - skipRight;
-//                NodeBuilder<T> builder = Nodes.<T>makeBuilder(truncatedSize);
-//                Sink<S> wrappedSink = helper.wrapSink(builder);
-//                wrappedSink.begin(truncatedSize);
-//                Iterator<S> iterator = spliterator.iterator();
-//                for (int i=0; i<skipLeft; i++)
-//                    iterator.next();
-//                for (int i=0; i<truncatedSize; i++)
-//                    wrappedSink.apply(iterator.next());
-//                wrappedSink.end();
-//                return builder.build();
-//            }
-//        }
-//
-//        @Override
-//        public void onCompletion(CountedCompleter<?> caller) {
-//            if (!isLeaf()) {
-//                Node<T> result = null;
-//                for (SizedSliceTask<S, T> child = children.nextSibling; child != null; child = child.nextSibling) {
-//                    Node<T> childResult = child.getRawResult();
-//                    if (childResult == null)
-//                        continue;
-//                    else if (result == null)
-//                        result = childResult;
-//                    else
-//                        result = Nodes.node(result, childResult);
-//                }
-//                setRawResult(result);
-//                if (offset <= targetOffset && offset+size >= targetOffset+targetSize)
-//                    shortCircuit(result);
-//            }
-//        }
-//    }
-
 }
--- a/src/share/classes/java/util/stream/SpinedBuffer.java	Mon May 06 10:27:01 2013 +0200
+++ b/src/share/classes/java/util/stream/SpinedBuffer.java	Mon May 06 18:26:12 2013 +0200
@@ -555,8 +555,8 @@
             arrayForEach(curChunk, 0, elementIndex, consumer);
         }
 
-        abstract class BaseSpliterator<T_SPLITER extends Spliterator<E>>
-                implements Spliterator<E> {
+        abstract class BaseSpliterator<T_SPL extends Spliterator.OfPrimitive<E, T_CONS, T_SPL>>
+                implements Spliterator.OfPrimitive<E, T_CONS, T_SPL> {
             // The current spine index
             int splSpineIndex;
 
@@ -572,7 +572,7 @@
 
             abstract void arrayForOne(T_ARR array, int index, T_CONS consumer);
 
-            abstract T_SPLITER arraySpliterator(T_ARR array, int offset, int len);
+            abstract T_SPL arraySpliterator(T_ARR array, int offset, int len);
 
             @Override
             public long estimateSize() {
@@ -621,9 +621,9 @@
             }
 
             @Override
-            public T_SPLITER trySplit() {
+            public T_SPL trySplit() {
                 if (splSpineIndex < spineIndex) {
-                    T_SPLITER ret = arraySpliterator(spine[splSpineIndex], splElementIndex,
+                    T_SPL ret = arraySpliterator(spine[splSpineIndex], splElementIndex,
                                                      arrayLength(spine[splSpineIndex]) - splElementIndex);
                     splChunk = spine[++splSpineIndex];
                     splElementIndex = 0;
@@ -634,7 +634,7 @@
                     if (t == 0)
                         return null;
                     else {
-                        T_SPLITER ret = arraySpliterator(curChunk, splElementIndex, t);
+                        T_SPL ret = arraySpliterator(curChunk, splElementIndex, t);
                         splElementIndex += t;
                         return ret;
                     }
--- a/src/share/classes/java/util/stream/StreamSpliterators.java	Mon May 06 10:27:01 2013 +0200
+++ b/src/share/classes/java/util/stream/StreamSpliterators.java	Mon May 06 18:26:12 2013 +0200
@@ -26,7 +26,6 @@
 
 import java.util.Comparator;
 import java.util.Spliterator;
-import java.util.Spliterators;
 import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
 import java.util.function.DoubleConsumer;
@@ -484,17 +483,17 @@
      * first call to any spliterator method.
      * @param <T>
      */
-    static class DelegatingSpliterator<T> implements Spliterator<T> {
-        private final Supplier<Spliterator<T>> supplier;
+    static class DelegatingSpliterator<T, T_SPL extends Spliterator<T>>
+            implements Spliterator<T> {
+        private final Supplier<? extends T_SPL> supplier;
 
-        private Spliterator<T> s;
+        private T_SPL s;
 
-        @SuppressWarnings("unchecked")
-        DelegatingSpliterator(Supplier<? extends Spliterator<T>> supplier) {
-            this.supplier = (Supplier<Spliterator<T>>) supplier;
+        DelegatingSpliterator(Supplier<? extends T_SPL> supplier) {
+            this.supplier = supplier;
         }
 
-        Spliterator<T> get() {
+        T_SPL get() {
             if (s == null) {
                 s = supplier.get();
             }
@@ -502,8 +501,8 @@
         }
 
         @Override
-        public Spliterator<T> trySplit() {
-            return get().trySplit();
+        public T_SPL trySplit() {
+            return (T_SPL) get().trySplit();
         }
 
         @Override
@@ -541,118 +540,66 @@
             return getClass().getName() + "[" + get() + "]";
         }
 
-        static final class OfInt extends DelegatingSpliterator<Integer> implements Spliterator.OfInt {
-            private Spliterator.OfInt s;
+        static class OfPrimitive<T, T_CONS, T_SPL extends Spliterator.OfPrimitive<T, T_CONS, T_SPL>>
+            extends DelegatingSpliterator<T, T_SPL>
+            implements Spliterator.OfPrimitive<T, T_CONS, T_SPL> {
+            OfPrimitive(Supplier<? extends T_SPL> supplier) {
+                super(supplier);
+            }
+
+            @Override
+            public boolean tryAdvance(T_CONS consumer) {
+                return get().tryAdvance(consumer);
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS consumer) {
+                get().forEachRemaining(consumer);
+            }
+        }
+
+        static final class OfInt
+                extends OfPrimitive<Integer, IntConsumer, Spliterator.OfInt>
+                implements Spliterator.OfInt {
 
             OfInt(Supplier<Spliterator.OfInt> supplier) {
                 super(supplier);
             }
-
-            @Override
-            Spliterator.OfInt get() {
-                if (s == null) {
-                    s = (Spliterator.OfInt) super.get();
-                }
-                return s;
-            }
-
-            @Override
-            public Spliterator.OfInt trySplit() {
-                return get().trySplit();
-            }
-
-            @Override
-            public boolean tryAdvance(IntConsumer consumer) {
-                return get().tryAdvance(consumer);
-            }
-
-            @Override
-            public void forEachRemaining(IntConsumer consumer) {
-                get().forEachRemaining(consumer);
-            }
         }
 
-        static final class OfLong extends DelegatingSpliterator<Long> implements Spliterator.OfLong {
-            private Spliterator.OfLong s;
+        static final class OfLong
+                extends OfPrimitive<Long, LongConsumer, Spliterator.OfLong>
+                implements Spliterator.OfLong {
 
             OfLong(Supplier<Spliterator.OfLong> supplier) {
                 super(supplier);
             }
-
-            @Override
-            Spliterator.OfLong get() {
-                if (s == null) {
-                    s = (Spliterator.OfLong) super.get();
-                }
-                return s;
-            }
-
-            @Override
-            public Spliterator.OfLong trySplit() {
-                return get().trySplit();
-            }
-
-            @Override
-            public boolean tryAdvance(LongConsumer consumer) {
-                return get().tryAdvance(consumer);
-            }
-
-            @Override
-            public void forEachRemaining(LongConsumer consumer) {
-                get().forEachRemaining(consumer);
-            }
         }
 
-        static final class OfDouble extends DelegatingSpliterator<Double> implements Spliterator.OfDouble {
-            private Spliterator.OfDouble s;
+        static final class OfDouble
+                extends OfPrimitive<Double, DoubleConsumer, Spliterator.OfDouble>
+                implements Spliterator.OfDouble {
 
             OfDouble(Supplier<Spliterator.OfDouble> supplier) {
                 super(supplier);
             }
-
-            @Override
-            Spliterator.OfDouble get() {
-                if (s == null) {
-                    s = (Spliterator.OfDouble) super.get();
-                }
-                return s;
-            }
-
-            @Override
-            public Spliterator.OfDouble trySplit() {
-                return get().trySplit();
-            }
-
-            @Override
-            public boolean tryAdvance(DoubleConsumer consumer) {
-                return get().tryAdvance(consumer);
-            }
-
-            @Override
-            public void forEachRemaining(DoubleConsumer consumer) {
-                get().forEachRemaining(consumer);
-            }
         }
     }
 
-    static final class SliceSpliterator<T> implements Spliterator<T> {
+    private abstract static class AbstractSliceSpliterator<T, T_SPL extends Spliterator<T>> {
         // The start index of the slice
         final long sliceOrigin;
         // One past the last index of the slice
         final long sliceFence;
 
         // The spliterator to slice
-        Spliterator<T> s;
+        T_SPL s;
         // current (absolute) index, modified on advance/split
         long index;
         // one past last (absolute) index or sliceFence, which ever is smaller
         long fence;
 
-        SliceSpliterator(Spliterator<T> s, long sliceOrigin, long sliceFence) {
-            this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence));
-        }
-
-        private SliceSpliterator(Spliterator<T> s, long sliceOrigin, long sliceFence, long origin, long fence) {
+        AbstractSliceSpliterator(T_SPL s, long sliceOrigin, long sliceFence, long origin, long fence) {
             assert s.hasCharacteristics(Spliterator.SUBSIZED);
             this.s = s;
             this.sliceOrigin = sliceOrigin;
@@ -661,6 +608,82 @@
             this.fence = fence;
         }
 
+        protected abstract T_SPL makeSpliterator(T_SPL s, long sliceOrigin, long sliceFence, long origin, long fence);
+
+        public T_SPL trySplit() {
+            if (sliceOrigin >= fence)
+                return null;
+
+            if (index >= fence)
+                return null;
+
+            // Keep splitting until the left and right splits intersect with the slice
+            // thereby ensuring the size estimate decreases.
+            // This also avoids creating empty spliterators which can result in
+            // existing and additionally created F/J tasks that perform
+            // redundant work on no elements.
+            while (true) {
+                T_SPL leftSplit = (T_SPL) s.trySplit();
+                if (leftSplit == null)
+                    return null;
+
+                long leftSplitFenceUnbounded = index + leftSplit.estimateSize();
+                long leftSplitFence = Math.min(leftSplitFenceUnbounded, sliceFence);
+                if (sliceOrigin >= leftSplitFence) {
+                    // The left split does not intersect with, and is to the left of, the slice
+                    // The right split does intersect
+                    // Discard the left split and split further with the right split
+                    index = leftSplitFence;
+                }
+                else if (leftSplitFence >= sliceFence) {
+                    // The right split does not intersect with, and is to the right of, the slice
+                    // The left split does intersect
+                    // Discard the right split and split further with the left split
+                    s = leftSplit;
+                    fence = leftSplitFence;
+                }
+                else if (index >= sliceOrigin && leftSplitFenceUnbounded <= sliceFence) {
+                    // The left split is contained within the slice, return the underlying left split
+                    // Right split is contained within or intersects with the slice
+                    index = leftSplitFence;
+                    return leftSplit;
+                } else {
+                    // The left split intersects with the slice
+                    // Right split is contained within or intersects with the slice
+                    return makeSpliterator(leftSplit, sliceOrigin, sliceFence, index, index = leftSplitFence);
+                }
+            }
+        }
+
+        public long estimateSize() {
+            return fence - Math.max(sliceOrigin, index);
+        }
+
+        public int characteristics() {
+            return s.characteristics();
+        }
+    }
+
+    static final class SliceSpliterator<T>
+            extends AbstractSliceSpliterator<T, Spliterator<T>>
+            implements Spliterator<T> {
+
+        SliceSpliterator(Spliterator<T> s, long sliceOrigin, long sliceFence) {
+            this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence));
+        }
+
+        private SliceSpliterator(Spliterator<T> s,
+                                 long sliceOrigin, long sliceFence, long origin, long fence) {
+            super(s, sliceOrigin, sliceFence, origin, fence);
+        }
+
+        @Override
+        protected Spliterator<T> makeSpliterator(Spliterator<T> s,
+                                                 long sliceOrigin, long sliceFence,
+                                                 long origin, long fence) {
+            return new SliceSpliterator<>(s, sliceOrigin, sliceFence, origin, fence);
+        }
+
         @Override
         public boolean tryAdvance(Consumer<? super T> action) {
             if (sliceOrigin >= fence)
@@ -703,60 +726,133 @@
             }
         }
 
-        @Override
-        public Spliterator<T> trySplit() {
-            if (sliceOrigin >= fence)
-                return null;
+        static abstract class OfPrimitive<T,
+                                          T_SPL extends Spliterator.OfPrimitive<T, T_CONS, T_SPL>,
+                                          T_CONS>
+                extends AbstractSliceSpliterator<T, T_SPL>
+                implements Spliterator.OfPrimitive<T, T_CONS, T_SPL> {
 
-            if (index >= fence)
-                return null;
+            OfPrimitive(T_SPL s, long sliceOrigin, long sliceFence) {
+                this(s, sliceOrigin, sliceFence, 0, Math.min(s.estimateSize(), sliceFence));
+            }
 
-            // Keep splitting until the left and right splits intersect with the slice
-            // thereby ensuring the size estimate decreases.
-            // This also avoids creating empty spliterators which can result in
-            // existing and additionally created F/J tasks that perform
-            // redundant work on no elements.
-            while (true) {
-                Spliterator<T> leftSplit = s.trySplit();
-                if (leftSplit == null)
-                    return null;
+            private OfPrimitive(T_SPL s,
+                                long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
 
-                long leftSplitFenceUnbounded = index + leftSplit.estimateSize();
-                long leftSplitFence = Math.min(leftSplitFenceUnbounded, sliceFence);
-                if (sliceOrigin >= leftSplitFence) {
-                    // The left split does not intersect with, and is to the left of, the slice
-                    // The right split does intersect
-                    // Discard the left split and split further with the right split
-                    index = leftSplitFence;
+            @Override
+            public boolean tryAdvance(T_CONS action) {
+                if (sliceOrigin >= fence)
+                    return false;
+
+                if (index >= fence)
+                    return false;
+
+                while (sliceOrigin > index) {
+                    s.tryAdvance(emptyConsumer());
+                    index++;
                 }
-                else if (leftSplitFence >= sliceFence) {
-                    // The right split does not intersect with, and is to the right of, the slice
-                    // The left split does intersect
-                    // Discard the right split and split further with the left split
-                    s = leftSplit;
-                    fence = leftSplitFence;
+
+                index++;
+                return s.tryAdvance(action);
+            }
+
+            @Override
+            public void forEachRemaining(T_CONS action) {
+                if (sliceOrigin >= fence)
+                    return;
+
+                if (index >= fence)
+                    return;
+
+                if (index >= sliceOrigin && (index + s.estimateSize()) <= sliceFence) {
+                    // The spliterator is contained within the slice
+                    s.forEachRemaining(action);
+                    index = fence;
+                } else {
+                    // The spliterator intersects with the slice
+                    while (sliceOrigin > index) {
+                        s.tryAdvance(emptyConsumer());
+                        index++;
+                    }
+                    // Traverse elements up to the fence
+                    for (;index < fence; index++) {
+                        s.tryAdvance(action);
+                    }
                 }
-                else if (index >= sliceOrigin && leftSplitFenceUnbounded <= sliceFence) {
-                    // The left split is contained within the slice, return the underlying left split
-                    // Right split is contained within or intersects with the slice
-                    index = leftSplitFence;
-                    return leftSplit;
-                } else {
-                    // The left split intersects with the slice
-                    // Right split is contained within or intersects with the slice
-                    return new SliceSpliterator<>(leftSplit, sliceOrigin, sliceFence, index, index = leftSplitFence);
-                }
+            }
+
+            protected abstract T_CONS emptyConsumer();
+        }
+
+        static final class OfInt extends OfPrimitive<Integer, Spliterator.OfInt, IntConsumer>
+                implements Spliterator.OfInt {
+            OfInt(Spliterator.OfInt s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfInt(Spliterator.OfInt s,
+                  long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected OfInt makeSpliterator(Spliterator.OfInt s,
+                                            long sliceOrigin, long sliceFence,
+                                            long origin, long fence) {
+                return new SliceSpliterator.OfInt(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            protected IntConsumer emptyConsumer() {
+                return e -> {};
             }
         }
 
-        @Override
-        public long estimateSize() {
-            return fence - Math.max(sliceOrigin, index);
+        static final class OfLong extends OfPrimitive<Long, Spliterator.OfLong, LongConsumer>
+                implements Spliterator.OfLong {
+            OfLong(Spliterator.OfLong s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfLong(Spliterator.OfLong s,
+                   long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected OfLong makeSpliterator(Spliterator.OfLong s,
+                                             long sliceOrigin, long sliceFence,
+                                             long origin, long fence) {
+                return new SliceSpliterator.OfLong(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            protected LongConsumer emptyConsumer() {
+                return e -> {};
+            }
         }
 
-        @Override
-        public int characteristics() {
-            return s.characteristics();
+        static final class OfDouble extends OfPrimitive<Double, Spliterator.OfDouble, DoubleConsumer>
+                implements Spliterator.OfDouble {
+            OfDouble(Spliterator.OfDouble s, long sliceOrigin, long sliceFence) {
+                super(s, sliceOrigin, sliceFence);
+            }
+
+            OfDouble(Spliterator.OfDouble s,
+                     long sliceOrigin, long sliceFence, long origin, long fence) {
+                super(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            @Override
+            protected OfDouble makeSpliterator(Spliterator.OfDouble s,
+                                               long sliceOrigin, long sliceFence,
+                                               long origin, long fence) {
+                return new SliceSpliterator.OfDouble(s, sliceOrigin, sliceFence, origin, fence);
+            }
+
+            protected DoubleConsumer emptyConsumer() {
+                return e -> {};
+            }
         }
     }
 }