/* * 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 { /** * Return 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(); /** * Traverse 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); /** * Return 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; } /** * Retrieve 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(); } /** * View 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); /** * Copy 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); /** * Get 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; } /** * Return 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 { /** * Build 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); } } /** * Traverse 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(); } /** * View 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(); /** * Copy 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); } } /** * Traverse 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(); } /** * View 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(); /** * Copy 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); } } /** * Traverse 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(); } /** * View 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(); /** * Copy 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; } } }