--- /dev/null 2013-03-09 17:25:01.184291984 -0500 +++ new/src/share/classes/java/util/stream/Node.java 2013-03-11 17:44:01.000000000 -0400 @@ -0,0 +1,523 @@ +/* + * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package java.util.stream; + +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.DoubleConsumer; +import java.util.function.IntConsumer; +import java.util.function.IntFunction; +import java.util.function.LongConsumer; + +/** + * An immutable container for describing an ordered sequence of elements of some + * type {@code T}. + * + *

A {@code Node} contains a fixed number of elements, which can be accessed + * via the {@link #count}, {@link #spliterator}, {@link #forEach}, + * {@link #asArray}, or {@link #copyInto} methods. A {@code Node} may have zero + * or more child {@code Node}s; if it has no children (accessed via + * {@link #getChildCount} and {@link #getChild(int)}, it is considered flat + * or a leaf; if it has children, it is considered an + * internal node. The size of an internal node is the sum of sizes of + * its children. + * + * @apiNote + *

A {@code Node} typically does not store the elements directly, but instead + * mediates access to one or more existing (effectively immutable) data + * structures such as a {@code Collection}, array, or a set of other + * {@code Node}s. {@code Node}s directly representing existing data structures + * are considered flat (have no children); commonly {@code Node}s are + * formed into a tree whose shape corresponds to the computation tree that + * produced the elements that are contained in the leaf nodes. The use of + * {@code Node} within the stream framework is largely to avoid copying data + * unnecessarily during parallel operations. + * + * @param the type of elements. + * @since 1.8 + */ +interface Node { + + /** + * Returns a {@link Spliterator} describing the elements contained in this + * {@code Node}. + * + * @return a {@code Spliterator describing the elements contained in this + * {@code Node}. + */ + Spliterator spliterator(); + + /** + * Traverses the elements of this node, and invoke the provided + * {@code Consumer} with each element. + * + * @param consumer A {@code Consumer} that is to be invoked with each + * element in this {@code Node} + */ + void forEach(Consumer consumer); + + /** + * Returns the number of child nodes of this node. + * + * @implSpec The default implementation returns zero + * @return the number of child nodes + */ + default int getChildCount() { + return 0; + } + + /** + * Retrieves the child {@code Node} at a given index. + * + * @implSpec The default implementation throws + * {@code IndexOutOfBoundsException} + * @param i the index to the child node + * @return the child node + * @throws IndexOutOfBoundsException if the index is less than 0 or greater + * than or equal to the + * number of child nodes. + */ + default Node getChild(int i) { + throw new IndexOutOfBoundsException(); + } + + /** + * Views this node as an array. + * + *

Depending on the underlying implementation this may return a reference + * to an internal array rather than a copy. It is the callers + * responsibility to decide if either this node or the array is utilized as + * the primary reference for the data.

+ * + * @return an array containing the contents of this {@code Node} + */ + T[] asArray(IntFunction generator); + + /** + * Copies the content of this {@code Node} into an array, starting at a given + * offset into the array. It is the caller's responsibility to ensure there + * is sufficient room in the array. + * + * @param array the array into which to copy the contents of this + * {@code Node} + * @param offset the starting offset within the array + * @throws IndexOutOfBoundsException if copying would cause access of data + * outside array bounds + * @throws NullPointerException if {@code array} is {@code null} + */ + void copyInto(T[] array, int offset); + + /** + * Gets the {@code StreamShape} associated with this {@code Node}. + * + * @implSpec The default in {@code Node} returns + * {@code StreamShape.REFERENCE} + * @return the stream shape associated with this node + */ + default StreamShape getShape() { + return StreamShape.REFERENCE; + } + + /** + * Returns the number of elements contained in this node + * + * @return the number of elements contained in this node + */ + long count(); + + /** + * A mutable builder for a {@code Node} that implements {@link Sink}, which + * builds a flat node containing the elements that have been pushed to it. + * + */ + interface Builder extends Sink { + + /** + * Builds the node. Should be called after all elements have been pushed + * and signalled with an invocation of {@link Sink#end()}. + * + * @return the resulting {@code Node} + */ + Node build(); + + /** Specialized @{code Node.Builder} for int elements */ + interface OfInt extends Node.Builder, Sink.OfInt { + @Override + Node.OfInt build(); + } + + /** Specialized @{code Node.Builder} for long elements */ + interface OfLong extends Node.Builder, Sink.OfLong { + @Override + Node.OfLong build(); + } + + /** Specialized @{code Node.Builder} for double elements */ + interface OfDouble extends Node.Builder, Sink.OfDouble { + @Override + Node.OfDouble build(); + } + } + + /** Specialized {@code Node} for int elements */ + interface OfInt extends Node { + + /** + * {@inheritDoc} + * @return A {@link Spliterator.OfInt} describing the elements of this + * node + */ + @Override + Spliterator.OfInt spliterator(); + + /** + * {@inheritDoc} + * @param consumer A {@code Consumer} that is to be invoked with each + * element in this {@code Node}. If this is an + * {@code IntConsumer}, it is cast to {@code IntConsumer} so the + * elements may be processed without boxing. + */ + @Override + default void forEach(Consumer consumer) { + if (consumer instanceof IntConsumer) { + forEach((IntConsumer) consumer); + } + else { + if (Tripwire.ENABLED) + Tripwire.trip(getClass(), "{0} calling Node.OfInt.forEach(Consumer)"); + spliterator().forEach(consumer); + } + } + + /** + * 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 generator) { + Integer[] boxed = generator.apply((int) count()); + copyInto(boxed, 0); + return boxed; + } + + /** + * {@inheritDoc} + * @implSpec the default implementation invokes {@link #asIntArray()} to + * obtain an int[] array then and copies the elements from that int[] + * array into the boxed Integer[] array. This is not efficient and it + * is recommended to invoke {@link #copyInto(int[], int)}. + */ + @Override + default void copyInto(Integer[] boxed, int offset) { + if (Tripwire.ENABLED) + Tripwire.trip(getClass(), "{0} calling Node.OfInt.copyInto(Integer[], int)"); + + int[] array = asIntArray(); + for (int i = 0; i < array.length; i++) { + boxed[offset + i] = array[i]; + } + } + + @Override + default Node.OfInt getChild(int i) { + throw new IndexOutOfBoundsException(); + } + + /** + * Views this node as an int[] array. + * + *

Depending on the underlying implementation this may return a + * reference to an internal array rather than a copy. It is the callers + * responsibility to decide if either this node or the array is utilized + * as the primary reference for the data.

+ * + * @return an array containing the contents of this {@code Node} + */ + int[] asIntArray(); + + /** + * Copies the content of this {@code Node} into an int[] array, starting + * at a given offset into the array. It is the caller's responsibility + * to ensure there is sufficient room in the array. + * + * @param array the array into which to copy the contents of this {@code Node} + * @param offset the starting offset within the array + * @throws IndexOutOfBoundsException if copying would cause access of + * data outside array bounds + * @throws NullPointerException if {@code array} is {@code null} + */ + void copyInto(int[] array, int offset); + + /** + * {@inheritDoc} + * @implSpec The default in {@code Node.OfInt} returns + * {@code StreamShape.INT_VALUE} + */ + default StreamShape getShape() { + return StreamShape.INT_VALUE; + } + } + + /** Specialized {@code Node} for long elements */ + interface OfLong extends Node { + + /** + * {@inheritDoc} + * @return A {@link Spliterator.OfLong} describing the elements of this + * node + */ + @Override + Spliterator.OfLong spliterator(); + + /** + * {@inheritDoc} + * @param consumer A {@code Consumer} that is to be invoked with each + * element in this {@code Node}. If this is an + * {@code LongConsumer}, it is cast to {@code LongConsumer} so + * the elements may be processed without boxing. + */ + @Override + default void forEach(Consumer consumer) { + if (consumer instanceof LongConsumer) { + forEach((LongConsumer) consumer); + } + else { + if (Tripwire.ENABLED) + Tripwire.trip(getClass(), "{0} calling Node.OfLong.forEach(Consumer)"); + spliterator().forEach(consumer); + } + } + + /** + * 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 generator) { + Long[] boxed = generator.apply((int) count()); + copyInto(boxed, 0); + return boxed; + } + + /** + * {@inheritDoc} + * @implSpec the default implementation invokes {@link #asLongArray()} + * to obtain a long[] array then and copies the elements from that + * long[] array into the boxed Long[] array. This is not efficient and + * it is recommended to invoke {@link #copyInto(long[], int)}. + */ + @Override + default void copyInto(Long[] boxed, int offset) { + if (Tripwire.ENABLED) + Tripwire.trip(getClass(), "{0} calling Node.OfInt.copyInto(Long[], int)"); + + long[] array = asLongArray(); + for (int i = 0; i < array.length; i++) { + boxed[offset + i] = array[i]; + } + } + + @Override + default Node.OfLong getChild(int i) { + throw new IndexOutOfBoundsException(); + } + + /** + * Views this node as a long[] array. + * + *

Depending on the underlying implementation this may return a + * reference to an internal array rather than a copy. It is the callers + * responsibility to decide if either this node or the array is utilized + * as the primary reference for the data.

+ * + * @return an array containing the contents of this {@code Node} + */ + long[] asLongArray(); + + /** + * Copies the content of this {@code Node} into a long[] array, starting + * at a given offset into the array. It is the caller's responsibility + * to ensure there is sufficient room in the array. + * + * @param array the array into which to copy the contents of this + * {@code Node} + * @param offset the starting offset within the array + * @throws IndexOutOfBoundsException if copying would cause access of + * data outside array bounds + * @throws NullPointerException if {@code array} is {@code null} + */ + void copyInto(long[] array, int offset); + + /** + * {@inheritDoc} + * @implSpec The default in {@code Node.OfLong} returns + * {@code StreamShape.LONG_VALUE} + */ + default StreamShape getShape() { + return StreamShape.LONG_VALUE; + } + } + + /** Specialized {@code Node} for double elements */ + interface OfDouble extends Node { + + /** + * {@inheritDoc} + * @return A {@link Spliterator.OfDouble} describing the elements of + * this node + */ + @Override + Spliterator.OfDouble spliterator(); + + /** + * {@inheritDoc} + * @param consumer A {@code Consumer} that is to be invoked with each + * element in this {@code Node}. If this is an + * {@code DoubleConsumer}, it is cast to {@code DoubleConsumer} + * so the elements may be processed without boxing. + */ + @Override + default void forEach(Consumer consumer) { + if (consumer instanceof DoubleConsumer) { + forEach((DoubleConsumer) consumer); + } + else { + if (Tripwire.ENABLED) + Tripwire.trip(getClass(), "{0} calling Node.OfLong.forEach(Consumer)"); + spliterator().forEach(consumer); + } + } + + /** + * 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 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 + * and it is recommended to invoke {@link #copyInto(double[], int)}. + */ + @Override + default void copyInto(Double[] boxed, int offset) { + if (Tripwire.ENABLED) + Tripwire.trip(getClass(), "{0} calling Node.OfDouble.copyInto(Double[], int)"); + + double[] array = asDoubleArray(); + for (int i = 0; i < array.length; i++) { + boxed[offset + i] = array[i]; + } + } + + @Override + default Node.OfDouble getChild(int i) { + throw new IndexOutOfBoundsException(); + } + + /** + * Views this node as a double[] array. + * + *

Depending on the underlying implementation this may return a + * reference to an internal array rather than a copy. It is the callers + * responsibility to decide if either this node or the array is utilized + * as the primary reference for the data.

+ * + * @return an array containing the contents of this {@code Node} + */ + double[] asDoubleArray(); + + /** + * Copies the content of this {@code Node} into a double[] array, starting + * at a given offset into the array. It is the caller's responsibility + * to ensure there is sufficient room in the array. + * + * @param array the array into which to copy the contents of this + * {@code Node} + * @param offset the starting offset within the array + * @throws IndexOutOfBoundsException if copying would cause access of + * data outside array bounds + * @throws NullPointerException if {@code array} is {@code null} + */ + void copyInto(double[] array, int offset); + + /** + * {@inheritDoc} + * @implSpec The default in {@code Node.OfDouble} returns + * {@code StreamShape.DOUBLE_VALUE} + */ + default StreamShape getShape() { + return StreamShape.DOUBLE_VALUE; + } + } +}