8016308: Updates to j.u.stream.Node/Nodes
Co-authored-by: Brian Goetz <brian.goetz@oracle.com> Reviewed-by: mduigou
This commit is contained in:
parent
1f4dfcf422
commit
434bea45ac
@ -104,6 +104,32 @@ interface Node<T> {
|
|||||||
throw new IndexOutOfBoundsException();
|
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++) { }
|
||||||
|
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.
|
* Provides an array view of the contents of this node.
|
||||||
*
|
*
|
||||||
@ -192,19 +218,90 @@ interface Node<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public interface OfPrimitive<T, T_CONS, T_ARR,
|
||||||
* Specialized {@code Node} for int elements
|
T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
|
||||||
*/
|
T_NODE extends OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>>
|
||||||
interface OfInt extends Node<Integer> {
|
extends Node<T> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* @return a {@link Spliterator.OfInt} describing the elements of this
|
* @return a {@link Spliterator.OfPrimitive} describing the elements of
|
||||||
* node
|
* this node
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
Spliterator.OfInt spliterator();
|
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}
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
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}
|
* {@inheritDoc}
|
||||||
@ -226,38 +323,13 @@ interface Node<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 #asPrimitiveArray()}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
default Integer[] asArray(IntFunction<Integer[]> generator) {
|
|
||||||
Integer[] boxed = generator.apply((int) count());
|
|
||||||
copyInto(boxed, 0);
|
|
||||||
return boxed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* @implSpec the default implementation invokes {@link #asPrimitiveArray()} to
|
* @implSpec the default implementation invokes {@link #asPrimitiveArray()} to
|
||||||
* obtain an int[] array then and copies the elements from that int[]
|
* obtain an int[] array then and copies the elements from that int[]
|
||||||
* array into the boxed Integer[] array. This is not efficient and it
|
* array into the boxed Integer[] array. This is not efficient and it
|
||||||
* is recommended to invoke {@link #copyInto(int[], int)}.
|
* is recommended to invoke {@link #copyInto(Object, int)}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void copyInto(Integer[] boxed, int offset) {
|
default void copyInto(Integer[] boxed, int offset) {
|
||||||
@ -271,35 +343,23 @@ interface Node<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default Node.OfInt getChild(int i) {
|
default Node.OfInt truncate(long from, long to, IntFunction<Integer[]> generator) {
|
||||||
throw new IndexOutOfBoundsException();
|
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++) { }
|
||||||
|
for (int i = 0; (i < size) && spliterator.tryAdvance((IntConsumer) nodeBuilder); i++) { }
|
||||||
|
nodeBuilder.end();
|
||||||
|
return nodeBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Views this node as an int[] array.
|
default int[] newArray(int count) {
|
||||||
*
|
return new int[count];
|
||||||
* <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}
|
|
||||||
*/
|
|
||||||
int[] asPrimitiveArray();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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}
|
* {@inheritDoc}
|
||||||
@ -309,22 +369,12 @@ interface Node<T> {
|
|||||||
default StreamShape getShape() {
|
default StreamShape getShape() {
|
||||||
return StreamShape.INT_VALUE;
|
return StreamShape.INT_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specialized {@code Node} for long elements
|
* Specialized {@code Node} for long elements
|
||||||
*/
|
*/
|
||||||
interface OfLong extends Node<Long> {
|
interface OfLong extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, OfLong> {
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* @return a {@link Spliterator.OfLong} describing the elements of this
|
|
||||||
* node
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
Spliterator.OfLong spliterator();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
@ -346,38 +396,13 @@ interface Node<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 #asPrimitiveArray()}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
default Long[] asArray(IntFunction<Long[]> generator) {
|
|
||||||
Long[] boxed = generator.apply((int) count());
|
|
||||||
copyInto(boxed, 0);
|
|
||||||
return boxed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* @implSpec the default implementation invokes {@link #asPrimitiveArray()}
|
* @implSpec the default implementation invokes {@link #asPrimitiveArray()}
|
||||||
* to obtain a long[] array then and copies the elements from that
|
* to obtain a long[] array then and copies the elements from that
|
||||||
* long[] array into the boxed Long[] array. This is not efficient and
|
* long[] array into the boxed Long[] array. This is not efficient and
|
||||||
* it is recommended to invoke {@link #copyInto(long[], int)}.
|
* it is recommended to invoke {@link #copyInto(Object, int)}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void copyInto(Long[] boxed, int offset) {
|
default void copyInto(Long[] boxed, int offset) {
|
||||||
@ -391,35 +416,23 @@ interface Node<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default Node.OfLong getChild(int i) {
|
default Node.OfLong truncate(long from, long to, IntFunction<Long[]> generator) {
|
||||||
throw new IndexOutOfBoundsException();
|
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++) { }
|
||||||
|
for (int i = 0; (i < size) && spliterator.tryAdvance((LongConsumer) nodeBuilder); i++) { }
|
||||||
|
nodeBuilder.end();
|
||||||
|
return nodeBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Views this node as a long[] array.
|
default long[] newArray(int count) {
|
||||||
*
|
return new long[count];
|
||||||
* <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.
|
|
||||||
*
|
|
||||||
* @return an array containing the contents of this {@code Node}
|
|
||||||
*/
|
|
||||||
long[] asPrimitiveArray();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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}
|
* {@inheritDoc}
|
||||||
@ -429,23 +442,12 @@ interface Node<T> {
|
|||||||
default StreamShape getShape() {
|
default StreamShape getShape() {
|
||||||
return StreamShape.LONG_VALUE;
|
return StreamShape.LONG_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specialized {@code Node} for double elements
|
* Specialized {@code Node} for double elements
|
||||||
*/
|
*/
|
||||||
interface OfDouble extends Node<Double> {
|
interface OfDouble extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, OfDouble> {
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* @return A {@link Spliterator.OfDouble} describing the elements of
|
|
||||||
* this node
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
Spliterator.OfDouble spliterator();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
@ -467,40 +469,15 @@ interface Node<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 #asPrimitiveArray()}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
default Double[] asArray(IntFunction<Double[]> generator) {
|
|
||||||
Double[] boxed = generator.apply((int) count());
|
|
||||||
copyInto(boxed, 0);
|
|
||||||
return boxed;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc}
|
* {@inheritDoc}
|
||||||
*
|
*
|
||||||
* @implSpec the default implementation invokes {@link #asPrimitiveArray()}
|
* @implSpec the default implementation invokes {@link #asPrimitiveArray()}
|
||||||
* to obtain a double[] array then and copies the elements from that
|
* to obtain a double[] array then and copies the elements from that
|
||||||
* double[] array into the boxed Double[] array. This is not efficient
|
* double[] array into the boxed Double[] array. This is not efficient
|
||||||
* and it is recommended to invoke {@link #copyInto(double[], int)}.
|
* and it is recommended to invoke {@link #copyInto(Object, int)}.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
default void copyInto(Double[] boxed, int offset) {
|
default void copyInto(Double[] boxed, int offset) {
|
||||||
@ -514,35 +491,23 @@ interface Node<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
default Node.OfDouble getChild(int i) {
|
default Node.OfDouble truncate(long from, long to, IntFunction<Double[]> generator) {
|
||||||
throw new IndexOutOfBoundsException();
|
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++) { }
|
||||||
|
for (int i = 0; (i < size) && spliterator.tryAdvance((DoubleConsumer) nodeBuilder); i++) { }
|
||||||
|
nodeBuilder.end();
|
||||||
|
return nodeBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Views this node as a double[] array.
|
default double[] newArray(int count) {
|
||||||
*
|
return new double[count];
|
||||||
* <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.
|
|
||||||
*
|
|
||||||
* @return an array containing the contents of this {@code Node}
|
|
||||||
*/
|
|
||||||
double[] asPrimitiveArray();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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}
|
* {@inheritDoc}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -28,7 +28,10 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
import java.util.concurrent.CountedCompleter;
|
import java.util.concurrent.CountedCompleter;
|
||||||
|
import java.util.function.DoubleConsumer;
|
||||||
|
import java.util.function.IntConsumer;
|
||||||
import java.util.function.IntFunction;
|
import java.util.function.IntFunction;
|
||||||
|
import java.util.function.LongConsumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory for instances of a short-circuiting stateful intermediate operations
|
* Factory for instances of a short-circuiting stateful intermediate operations
|
||||||
@ -352,7 +355,7 @@ final class SliceOps {
|
|||||||
else
|
else
|
||||||
// This will create a tree of depth 1 and will not be a sub-tree
|
// This will create a tree of depth 1 and will not be a sub-tree
|
||||||
// for leaf nodes within the require range
|
// for leaf nodes within the require range
|
||||||
result = Nodes.conc(op.getOutputShape(), nodes);
|
result = conc(op.getOutputShape(), nodes);
|
||||||
setLocalResult(result);
|
setLocalResult(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -418,94 +421,116 @@ final class SliceOps {
|
|||||||
if (skipLeft == 0 && skipRight == 0)
|
if (skipLeft == 0 && skipRight == 0)
|
||||||
return input;
|
return input;
|
||||||
else {
|
else {
|
||||||
return Nodes.truncateNode(input, skipLeft, thisNodeSize - skipRight, generator);
|
return truncateNode(input, skipLeft, thisNodeSize - skipRight, generator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Truncate a {@link Node}, returning a node describing a subsequence of
|
||||||
|
* the contents of the input node.
|
||||||
|
*
|
||||||
|
* @param <T> the type of elements of the input node and truncated node
|
||||||
|
* @param input the input node
|
||||||
|
* @param from the starting offset to include in the truncated node (inclusive)
|
||||||
|
* @param to the ending offset ot include in the truncated node (exclusive)
|
||||||
|
* @param generator the array factory (only used for reference nodes)
|
||||||
|
* @return the truncated node
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T> Node<T> truncateNode(Node<T> input, long from, long to, IntFunction<T[]> generator) {
|
||||||
|
StreamShape shape = input.getShape();
|
||||||
|
long size = truncatedSize(input.count(), from, to);
|
||||||
|
if (size == 0)
|
||||||
|
return Nodes.emptyNode(shape);
|
||||||
|
else if (from == 0 && to >= input.count())
|
||||||
|
return input;
|
||||||
|
|
||||||
|
switch (shape) {
|
||||||
|
case REFERENCE: {
|
||||||
|
Spliterator<T> spliterator = input.spliterator();
|
||||||
|
Node.Builder<T> nodeBuilder = Nodes.builder(size, generator);
|
||||||
|
nodeBuilder.begin(size);
|
||||||
|
for (int i = 0; i < from && spliterator.tryAdvance(e -> { }); i++) { }
|
||||||
|
for (int i = 0; (i < size) && spliterator.tryAdvance(nodeBuilder); i++) { }
|
||||||
|
nodeBuilder.end();
|
||||||
|
return nodeBuilder.build();
|
||||||
|
}
|
||||||
|
case INT_VALUE: {
|
||||||
|
Spliterator.OfInt spliterator = ((Node.OfInt) input).spliterator();
|
||||||
|
Node.Builder.OfInt nodeBuilder = Nodes.intBuilder(size);
|
||||||
|
nodeBuilder.begin(size);
|
||||||
|
for (int i = 0; i < from && spliterator.tryAdvance((IntConsumer) e -> { }); i++) { }
|
||||||
|
for (int i = 0; (i < size) && spliterator.tryAdvance((IntConsumer) nodeBuilder); i++) { }
|
||||||
|
nodeBuilder.end();
|
||||||
|
return (Node<T>) nodeBuilder.build();
|
||||||
|
}
|
||||||
|
case LONG_VALUE: {
|
||||||
|
Spliterator.OfLong spliterator = ((Node.OfLong) input).spliterator();
|
||||||
|
Node.Builder.OfLong nodeBuilder = Nodes.longBuilder(size);
|
||||||
|
nodeBuilder.begin(size);
|
||||||
|
for (int i = 0; i < from && spliterator.tryAdvance((LongConsumer) e -> { }); i++) { }
|
||||||
|
for (int i = 0; (i < size) && spliterator.tryAdvance((LongConsumer) nodeBuilder); i++) { }
|
||||||
|
nodeBuilder.end();
|
||||||
|
return (Node<T>) nodeBuilder.build();
|
||||||
|
}
|
||||||
|
case DOUBLE_VALUE: {
|
||||||
|
Spliterator.OfDouble spliterator = ((Node.OfDouble) input).spliterator();
|
||||||
|
Node.Builder.OfDouble nodeBuilder = Nodes.doubleBuilder(size);
|
||||||
|
nodeBuilder.begin(size);
|
||||||
|
for (int i = 0; i < from && spliterator.tryAdvance((DoubleConsumer) e -> { }); i++) { }
|
||||||
|
for (int i = 0; (i < size) && spliterator.tryAdvance((DoubleConsumer) nodeBuilder); i++) { }
|
||||||
|
nodeBuilder.end();
|
||||||
|
return (Node<T>) nodeBuilder.build();
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw new IllegalStateException("Unknown shape " + shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long truncatedSize(long size, long from, long to) {
|
||||||
|
if (from >= 0)
|
||||||
|
size = Math.max(0, size - from);
|
||||||
|
long limit = to - from;
|
||||||
|
if (limit >= 0)
|
||||||
|
size = Math.min(size, limit);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces a concatenated {@link Node} that has two or more children.
|
||||||
|
* <p>The count of the concatenated node is equal to the sum of the count
|
||||||
|
* of each child. Traversal of the concatenated node traverses the content
|
||||||
|
* of each child in encounter order of the list of children. Splitting a
|
||||||
|
* spliterator obtained from the concatenated node preserves the encounter
|
||||||
|
* order of the list of children.
|
||||||
|
*
|
||||||
|
* <p>The result may be a concatenated node, the input sole node if the size
|
||||||
|
* of the list is 1, or an empty node.
|
||||||
|
*
|
||||||
|
* @param <T> the type of elements of the concatenated node
|
||||||
|
* @param shape the shape of the concatenated node to be created
|
||||||
|
* @param nodes the input nodes
|
||||||
|
* @return a {@code Node} covering the elements of the input nodes
|
||||||
|
* @throws IllegalStateException if all {@link Node} elements of the list
|
||||||
|
* are an not instance of type supported by this factory.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T> Node<T> conc(StreamShape shape, List<? extends Node<T>> nodes) {
|
||||||
|
int size = nodes.size();
|
||||||
|
if (size == 0)
|
||||||
|
return Nodes.emptyNode(shape);
|
||||||
|
else if (size == 1)
|
||||||
|
return nodes.get(0);
|
||||||
|
else {
|
||||||
|
// Create a right-balanced tree when there are more that 2 nodes
|
||||||
|
List<Node<T>> refNodes = (List<Node<T>>) nodes;
|
||||||
|
Node<T> c = Nodes.conc(shape, refNodes.get(size - 2), refNodes.get(size - 1));
|
||||||
|
for (int i = size - 3; i >= 0; i--) {
|
||||||
|
c = Nodes.conc(shape, refNodes.get(i), c);
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// @@@ 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);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ public class DoubleNodeTest extends OpTestCase {
|
|||||||
|
|
||||||
double i = it.nextDouble();
|
double i = it.nextDouble();
|
||||||
if (it.hasNext()) {
|
if (it.hasNext()) {
|
||||||
return new Nodes.DoubleConcNode(Nodes.node(new double[] {i}), degenerateTree(it));
|
return new Nodes.ConcNode.OfDouble(Nodes.node(new double[] {i}), degenerateTree(it));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Nodes.node(new double[] {i});
|
return Nodes.node(new double[] {i});
|
||||||
@ -114,7 +114,7 @@ public class DoubleNodeTest extends OpTestCase {
|
|||||||
return m.apply(l);
|
return m.apply(l);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new Nodes.DoubleConcNode(
|
return new Nodes.ConcNode.OfDouble(
|
||||||
tree(l.subList(0, l.size() / 2), m),
|
tree(l.subList(0, l.size() / 2), m),
|
||||||
tree(l.subList(l.size() / 2, l.size()), m));
|
tree(l.subList(l.size() / 2, l.size()), m));
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ public class IntNodeTest extends OpTestCase {
|
|||||||
|
|
||||||
int i = it.nextInt();
|
int i = it.nextInt();
|
||||||
if (it.hasNext()) {
|
if (it.hasNext()) {
|
||||||
return new Nodes.IntConcNode(Nodes.node(new int[] {i}), degenerateTree(it));
|
return new Nodes.ConcNode.OfInt(Nodes.node(new int[] {i}), degenerateTree(it));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Nodes.node(new int[] {i});
|
return Nodes.node(new int[] {i});
|
||||||
@ -114,7 +114,7 @@ public class IntNodeTest extends OpTestCase {
|
|||||||
return m.apply(l);
|
return m.apply(l);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new Nodes.IntConcNode(
|
return new Nodes.ConcNode.OfInt(
|
||||||
tree(l.subList(0, l.size() / 2), m),
|
tree(l.subList(0, l.size() / 2), m),
|
||||||
tree(l.subList(l.size() / 2, l.size()), m));
|
tree(l.subList(l.size() / 2, l.size()), m));
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ public class LongNodeTest extends OpTestCase {
|
|||||||
|
|
||||||
long i = it.nextLong();
|
long i = it.nextLong();
|
||||||
if (it.hasNext()) {
|
if (it.hasNext()) {
|
||||||
return new Nodes.LongConcNode(Nodes.node(new long[] {i}), degenerateTree(it));
|
return new Nodes.ConcNode.OfLong(Nodes.node(new long[] {i}), degenerateTree(it));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return Nodes.node(new long[] {i});
|
return Nodes.node(new long[] {i});
|
||||||
@ -114,7 +114,7 @@ public class LongNodeTest extends OpTestCase {
|
|||||||
return m.apply(l);
|
return m.apply(l);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return new Nodes.LongConcNode(
|
return new Nodes.ConcNode.OfLong(
|
||||||
tree(l.subList(0, l.size() / 2), m),
|
tree(l.subList(0, l.size() / 2), m),
|
||||||
tree(l.subList(l.size() / 2, l.size()), m));
|
tree(l.subList(l.size() / 2, l.size()), m));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user