/* |
|
* Copyright (c) 2012, 2015, 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}. |
|
* |
|
* <p>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 <em>flat |
|
* </em> or a <em>leaf</em>; if it has children, it is considered an |
|
* <em>internal</em> node. The size of an internal node is the sum of sizes of |
|
* its children. |
|
* |
|
* @apiNote |
|
* <p>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. 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 <T> the type of elements. |
|
* @since 1.8 |
|
*/ |
|
interface Node<T> { |
|
/** |
|
* 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<T> spliterator(); |
|
/** |
|
* Traverses the elements of this node, and invoke the provided |
|
* {@code Consumer} with each element. Elements are provided in encounter |
|
* order if the source for the {@code Node} has a defined encounter order. |
|
* |
|
* @param consumer a {@code Consumer} that is to be invoked with each |
|
* element in this {@code Node} |
|
*/ |
|
void forEach(Consumer<? super T> 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 always 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<T> getChild(int i) { |
|
throw new IndexOutOfBoundsException(); |
|
} |
|
/** |
|
* Return a node describing a subsequence of the elements of this node, |
|
* starting at the given inclusive start offset and ending at the given |
|
* exclusive end offset. |
|
* |
|
* @param from The (inclusive) starting offset of elements to include, must |
|
* be in range 0..count(). |
|
* @param to The (exclusive) end offset of elements to include, must be |
|
* in range 0..count(). |
|
* @param generator A function to be used to create a new array, if needed, |
|
* for reference nodes. |
|
* @return the truncated node |
|
*/ |
|
default Node<T> truncate(long from, long to, IntFunction<T[]> generator) { |
|
if (from == 0 && to == count()) |
|
return this; |
|
Spliterator<T> spliterator = spliterator(); |
|
long size = to - from; |
|
Node.Builder<T> nodeBuilder = Nodes.builder(size, generator); |
|
nodeBuilder.begin(size); |
|
for (int i = 0; i < from && spliterator.tryAdvance(e -> { }); i++) { } |
|
if (to == count()) { |
|
spliterator.forEachRemaining(nodeBuilder); |
|
} else { |
|
for (int i = 0; i < size && spliterator.tryAdvance(nodeBuilder); i++) { } |
|
} |
|
nodeBuilder.end(); |
|
return nodeBuilder.build(); |
|
} |
|
/** |
|
* Provides an array view of the contents of this node. |
|
* |
|
* <p>Depending on the underlying implementation, this may return a |
|
* reference to an internal array rather than a copy. Since the returned |
|
* array may be shared, the returned array should not be modified. The |
|
* {@code generator} function may be consulted to create the array if a new |
|
* array needs to be created. |
|
* |
|
* @param generator a factory function which takes an integer parameter and |
|
* returns a new, empty array of that size and of the appropriate |
|
* array type |
|
* @return an array containing the contents of this {@code Node} |
|
*/ |
|
T[] asArray(IntFunction<T[]> 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, otherwise unspecified behaviour |
|
* will occur if the array length is less than the number of elements |
|
* contained in this node. |
|
* |
|
* @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<T> extends Sink<T> { |
|
/** |
|
* 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<T> build(); |
|
/** |
|
* Specialized @{code Node.Builder} for int elements |
|
*/ |
|
interface OfInt extends Node.Builder<Integer>, Sink.OfInt { |
|
@Override |
|
Node.OfInt build(); |
|
} |
|
/** |
|
* Specialized @{code Node.Builder} for long elements |
|
*/ |
|
interface OfLong extends Node.Builder<Long>, Sink.OfLong { |
|
@Override |
|
Node.OfLong build(); |
|
} |
|
/** |
|
* Specialized @{code Node.Builder} for double elements |
|
*/ |
|
interface OfDouble extends Node.Builder<Double>, Sink.OfDouble { |
|
@Override |
|
Node.OfDouble build(); |
|
} |
|
} |
|
public interface OfPrimitive<T, T_CONS, T_ARR, |
|
T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>, |
|
T_NODE extends OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>> |
|
extends Node<T> { |
|
/** |
|
* {@inheritDoc} |
|
* |
|
* @return a {@link Spliterator.OfPrimitive} describing the elements of |
|
* this node |
|
*/ |
|
@Override |
|
T_SPLITR 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} |
|
*/ |
|
@SuppressWarnings("overloads") |
|
void forEach(T_CONS action); |
|
@Override |
|
default T_NODE getChild(int i) { |
|
throw new IndexOutOfBoundsException(); |
|
} |
|
T_NODE truncate(long from, long to, IntFunction<T[]> generator); |
|
/** |
|
* {@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) { |
|
if (java.util.stream.Tripwire.ENABLED) |
|
java.util.stream.Tripwire.trip(getClass(), "{0} calling Node.OfPrimitive.asArray"); |
|
long size = count(); |
|
if (size >= Nodes.MAX_ARRAY_SIZE) |
|
throw new IllegalArgumentException(Nodes.BAD_SIZE); |
|
T[] boxed = generator.apply((int) count()); |
|
copyInto(boxed, 0); |
|
return boxed; |
|
} |
|
/** |
|
* Views this node as a primitive array. |
|
* |
|
* <p>Depending on the underlying implementation this may return a |
|
* reference to an internal array rather than a copy. It is the callers |
|
* responsibility to decide if either this node or the array is utilized |
|
* as the primary reference for the data.</p> |
|
* |
|
* @return an array containing the contents of this {@code Node} |
|
*/ |
|
T_ARR asPrimitiveArray(); |
|
/** |
|
* Creates a new primitive array. |
|
* |
|
* @param count the length of the primitive array. |
|
* @return the new primitive array. |
|
*/ |
|
T_ARR newArray(int count); |
|
/** |
|
* Copies the content of this {@code Node} into a primitive 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_ARR array, int offset); |
|
} |
|
/** |
|
* Specialized {@code Node} for int elements |
|
*/ |
|
interface OfInt extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, OfInt> { |
|
/** |
|
* {@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<? super Integer> consumer) { |
|
if (consumer instanceof IntConsumer) { |
|
forEach((IntConsumer) consumer); |
|
} |
|
else { |
|
if (Tripwire.ENABLED) |
|
Tripwire.trip(getClass(), "{0} calling Node.OfInt.forEachRemaining(Consumer)"); |
|
spliterator().forEachRemaining(consumer); |
|
} |
|
} |
|
/** |
|
* {@inheritDoc} |
|
* |
|
* @implSpec the default implementation invokes {@link #asPrimitiveArray()} 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(Object, int)}. |
|
*/ |
|
@Override |
|
default void copyInto(Integer[] boxed, int offset) { |
|
if (Tripwire.ENABLED) |
|
Tripwire.trip(getClass(), "{0} calling Node.OfInt.copyInto(Integer[], int)"); |
|
int[] array = asPrimitiveArray(); |
|
for (int i = 0; i < array.length; i++) { |
|
boxed[offset + i] = array[i]; |
|
} |
|
} |
|
@Override |
|
default Node.OfInt truncate(long from, long to, IntFunction<Integer[]> generator) { |
|
if (from == 0 && to == count()) |
|
return this; |
|
long size = to - from; |
|
Spliterator.OfInt spliterator = spliterator(); |
|
Node.Builder.OfInt nodeBuilder = Nodes.intBuilder(size); |
|
nodeBuilder.begin(size); |
|
for (int i = 0; i < from && spliterator.tryAdvance((IntConsumer) e -> { }); i++) { } |
|
if (to == count()) { |
|
spliterator.forEachRemaining((IntConsumer) nodeBuilder); |
|
} else { |
|
for (int i = 0; i < size && spliterator.tryAdvance((IntConsumer) nodeBuilder); i++) { } |
|
} |
|
nodeBuilder.end(); |
|
return nodeBuilder.build(); |
|
} |
|
@Override |
|
default int[] newArray(int count) { |
|
return new int[count]; |
|
} |
|
/** |
|
* {@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 OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, OfLong> { |
|
/** |
|
* {@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<? super Long> consumer) { |
|
if (consumer instanceof LongConsumer) { |
|
forEach((LongConsumer) consumer); |
|
} |
|
else { |
|
if (Tripwire.ENABLED) |
|
Tripwire.trip(getClass(), "{0} calling Node.OfLong.forEachRemaining(Consumer)"); |
|
spliterator().forEachRemaining(consumer); |
|
} |
|
} |
|
/** |
|
* {@inheritDoc} |
|
* |
|
* @implSpec the default implementation invokes {@link #asPrimitiveArray()} |
|
* 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(Object, int)}. |
|
*/ |
|
@Override |
|
default void copyInto(Long[] boxed, int offset) { |
|
if (Tripwire.ENABLED) |
|
Tripwire.trip(getClass(), "{0} calling Node.OfInt.copyInto(Long[], int)"); |
|
long[] array = asPrimitiveArray(); |
|
for (int i = 0; i < array.length; i++) { |
|
boxed[offset + i] = array[i]; |
|
} |
|
} |
|
@Override |
|
default Node.OfLong truncate(long from, long to, IntFunction<Long[]> generator) { |
|
if (from == 0 && to == count()) |
|
return this; |
|
long size = to - from; |
|
Spliterator.OfLong spliterator = spliterator(); |
|
Node.Builder.OfLong nodeBuilder = Nodes.longBuilder(size); |
|
nodeBuilder.begin(size); |
|
for (int i = 0; i < from && spliterator.tryAdvance((LongConsumer) e -> { }); i++) { } |
|
if (to == count()) { |
|
spliterator.forEachRemaining((LongConsumer) nodeBuilder); |
|
} else { |
|
for (int i = 0; i < size && spliterator.tryAdvance((LongConsumer) nodeBuilder); i++) { } |
|
} |
|
nodeBuilder.end(); |
|
return nodeBuilder.build(); |
|
} |
|
@Override |
|
default long[] newArray(int count) { |
|
return new long[count]; |
|
} |
|
/** |
|
* {@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 OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, OfDouble> { |
|
/** |
|
* {@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<? super Double> consumer) { |
|
if (consumer instanceof DoubleConsumer) { |
|
forEach((DoubleConsumer) consumer); |
|
} |
|
else { |
|
if (Tripwire.ENABLED) |
|
Tripwire.trip(getClass(), "{0} calling Node.OfLong.forEachRemaining(Consumer)"); |
|
spliterator().forEachRemaining(consumer); |
|
} |
|
} |
|
// |
|
/** |
|
* {@inheritDoc} |
|
* |
|
* @implSpec the default implementation invokes {@link #asPrimitiveArray()} |
|
* 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(Object, int)}. |
|
*/ |
|
@Override |
|
default void copyInto(Double[] boxed, int offset) { |
|
if (Tripwire.ENABLED) |
|
Tripwire.trip(getClass(), "{0} calling Node.OfDouble.copyInto(Double[], int)"); |
|
double[] array = asPrimitiveArray(); |
|
for (int i = 0; i < array.length; i++) { |
|
boxed[offset + i] = array[i]; |
|
} |
|
} |
|
@Override |
|
default Node.OfDouble truncate(long from, long to, IntFunction<Double[]> generator) { |
|
if (from == 0 && to == count()) |
|
return this; |
|
long size = to - from; |
|
Spliterator.OfDouble spliterator = spliterator(); |
|
Node.Builder.OfDouble nodeBuilder = Nodes.doubleBuilder(size); |
|
nodeBuilder.begin(size); |
|
for (int i = 0; i < from && spliterator.tryAdvance((DoubleConsumer) e -> { }); i++) { } |
|
if (to == count()) { |
|
spliterator.forEachRemaining((DoubleConsumer) nodeBuilder); |
|
} else { |
|
for (int i = 0; i < size && spliterator.tryAdvance((DoubleConsumer) nodeBuilder); i++) { } |
|
} |
|
nodeBuilder.end(); |
|
return nodeBuilder.build(); |
|
} |
|
@Override |
|
default double[] newArray(int count) { |
|
return new double[count]; |
|
} |
|
/** |
|
* {@inheritDoc} |
|
* |
|
* @implSpec The default in {@code Node.OfDouble} returns |
|
* {@code StreamShape.DOUBLE_VALUE} |
|
*/ |
|
default StreamShape getShape() { |
|
return StreamShape.DOUBLE_VALUE; |
|
} |
|
} |
|
} |