提交 e25108e4 编写于 作者: P psandoz

8016308: Updates to j.u.stream.Node/Nodes

Reviewed-by: mduigou
Contributed-by: NBrian Goetz &lt;brian.goetz@oracle.com&gt;, Paul Sandoz <paul.sandoz@oracle.com>
上级 131f74ae
...@@ -104,6 +104,32 @@ interface Node<T> { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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> { ...@@ -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}
......
...@@ -33,11 +33,13 @@ import java.util.Objects; ...@@ -33,11 +33,13 @@ import java.util.Objects;
import java.util.Spliterator; import java.util.Spliterator;
import java.util.Spliterators; import java.util.Spliterators;
import java.util.concurrent.CountedCompleter; import java.util.concurrent.CountedCompleter;
import java.util.function.BinaryOperator;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.DoubleConsumer; import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer; import java.util.function.IntConsumer;
import java.util.function.IntFunction; import java.util.function.IntFunction;
import java.util.function.LongConsumer; import java.util.function.LongConsumer;
import java.util.function.LongFunction;
/** /**
* Factory methods for constructing implementations of {@link Node} and * Factory methods for constructing implementations of {@link Node} and
...@@ -97,131 +99,28 @@ final class Nodes { ...@@ -97,131 +99,28 @@ final class Nodes {
* *
* @param <T> the type of elements of the concatenated node * @param <T> the type of elements of the concatenated node
* @param shape the shape of the concatenated node to be created * @param shape the shape of the concatenated node to be created
* @param nodes the input nodes * @param left the left input node
* @param right the right input node
* @return a {@code Node} covering the elements of the input nodes * @return a {@code Node} covering the elements of the input nodes
* @throws IllegalStateException if all {@link Node} elements of the list * @throws IllegalStateException if all {@link Node} elements of the list
* are an not instance of type supported by this factory. * are an not instance of type supported by this factory.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
static <T> Node<T> conc(StreamShape shape, List<? extends Node<T>> nodes) { static <T> Node<T> conc(StreamShape shape, Node<T> left, Node<T> right) {
int size = nodes.size();
if (size == 0)
return emptyNode(shape);
else if (size == 1)
return nodes.get(0);
else {
// Create a right-balanced tree when there are more that 2 nodes
switch (shape) {
case REFERENCE: {
List<Node<T>> refNodes = (List<Node<T>>) nodes;
ConcNode<T> c = new ConcNode<>(refNodes.get(size - 2), refNodes.get(size - 1));
for (int i = size - 3; i >= 0; i--) {
c = new ConcNode<>(refNodes.get(i), c);
}
return c;
}
case INT_VALUE: {
List<? extends Node.OfInt> intNodes = (List<? extends Node.OfInt>) nodes;
IntConcNode c = new IntConcNode(intNodes.get(size - 2), intNodes.get(size - 1));
for (int i = size - 3; i >= 0; i--) {
c = new IntConcNode(intNodes.get(i), c);
}
return (Node<T>) c;
}
case LONG_VALUE: {
List<? extends Node.OfLong> longNodes = (List<? extends Node.OfLong>) nodes;
LongConcNode c = new LongConcNode(longNodes.get(size - 2), longNodes.get(size - 1));
for (int i = size - 3; i >= 0; i--) {
c = new LongConcNode(longNodes.get(i), c);
}
return (Node<T>) c;
}
case DOUBLE_VALUE: {
List<? extends Node.OfDouble> doubleNodes = (List<? extends Node.OfDouble>) nodes;
DoubleConcNode c = new DoubleConcNode(doubleNodes.get(size - 2), doubleNodes.get(size - 1));
for (int i = size - 3; i >= 0; i--) {
c = new DoubleConcNode(doubleNodes.get(i), c);
}
return (Node<T>) c;
}
default:
throw new IllegalStateException("Unknown shape " + shape);
}
}
}
/**
* 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")
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 emptyNode(shape);
else if (from == 0 && to >= input.count())
return input;
switch (shape) { switch (shape) {
case REFERENCE: { case REFERENCE:
Spliterator<T> spliterator = input.spliterator(); return new ConcNode<>(left, right);
Node.Builder<T> nodeBuilder = Nodes.builder(size, generator); case INT_VALUE:
nodeBuilder.begin(size); return (Node<T>) new ConcNode.OfInt((Node.OfInt) left, (Node.OfInt) right);
for (int i = 0; i < from && spliterator.tryAdvance(e -> { }); i++) { } case LONG_VALUE:
for (int i = 0; (i < size) && spliterator.tryAdvance(nodeBuilder); i++) { } return (Node<T>) new ConcNode.OfLong((Node.OfLong) left, (Node.OfLong) right);
nodeBuilder.end(); case DOUBLE_VALUE:
return nodeBuilder.build(); return (Node<T>) new ConcNode.OfDouble((Node.OfDouble) left, (Node.OfDouble) right);
}
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: default:
throw new IllegalStateException("Unknown shape " + shape); 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;
}
// Reference-based node methods // Reference-based node methods
/** /**
...@@ -422,7 +321,7 @@ final class Nodes { ...@@ -422,7 +321,7 @@ final class Nodes {
new SizedCollectorTask.OfRef<>(spliterator, helper, array).invoke(); new SizedCollectorTask.OfRef<>(spliterator, helper, array).invoke();
return node(array); return node(array);
} else { } else {
Node<P_OUT> node = new CollectorTask<>(helper, generator, spliterator).invoke(); Node<P_OUT> node = new CollectorTask.OfRef<>(helper, generator, spliterator).invoke();
return flattenTree ? flatten(node, generator) : node; return flattenTree ? flatten(node, generator) : node;
} }
} }
...@@ -460,7 +359,7 @@ final class Nodes { ...@@ -460,7 +359,7 @@ final class Nodes {
return node(array); return node(array);
} }
else { else {
Node.OfInt node = new IntCollectorTask<>(helper, spliterator).invoke(); Node.OfInt node = new CollectorTask.OfInt<>(helper, spliterator).invoke();
return flattenTree ? flattenInt(node) : node; return flattenTree ? flattenInt(node) : node;
} }
} }
...@@ -498,7 +397,7 @@ final class Nodes { ...@@ -498,7 +397,7 @@ final class Nodes {
return node(array); return node(array);
} }
else { else {
Node.OfLong node = new LongCollectorTask<>(helper, spliterator).invoke(); Node.OfLong node = new CollectorTask.OfLong<>(helper, spliterator).invoke();
return flattenTree ? flattenLong(node) : node; return flattenTree ? flattenLong(node) : node;
} }
} }
...@@ -536,7 +435,7 @@ final class Nodes { ...@@ -536,7 +435,7 @@ final class Nodes {
return node(array); return node(array);
} }
else { else {
Node.OfDouble node = new DoubleCollectorTask<>(helper, spliterator).invoke(); Node.OfDouble node = new CollectorTask.OfDouble<>(helper, spliterator).invoke();
return flattenTree ? flattenDouble(node) : node; return flattenTree ? flattenDouble(node) : node;
} }
} }
...@@ -763,8 +662,6 @@ final class Nodes { ...@@ -763,8 +662,6 @@ final class Nodes {
return curSize; return curSize;
} }
// Traversable
@Override @Override
public void forEach(Consumer<? super T> consumer) { public void forEach(Consumer<? super T> consumer) {
for (int i = 0; i < curSize; i++) { for (int i = 0; i < curSize; i++) {
...@@ -829,13 +726,12 @@ final class Nodes { ...@@ -829,13 +726,12 @@ final class Nodes {
/** /**
* Node class for an internal node with two or more children * Node class for an internal node with two or more children
*/ */
static final class ConcNode<T> implements Node<T> { private static abstract class AbstractConcNode<T, T_NODE extends Node<T>> implements Node<T> {
private final Node<T> left; protected final T_NODE left;
private final Node<T> right; protected final T_NODE right;
private final long size; private final long size;
ConcNode(Node<T> left, Node<T> right) { AbstractConcNode(T_NODE left, T_NODE right) {
this.left = left; this.left = left;
this.right = right; this.right = right;
// The Node count will be required when the Node spliterator is // The Node count will be required when the Node spliterator is
...@@ -845,25 +741,37 @@ final class Nodes { ...@@ -845,25 +741,37 @@ final class Nodes {
this.size = left.count() + right.count(); this.size = left.count() + right.count();
} }
// Node
@Override
public Spliterator<T> spliterator() {
return new Nodes.InternalNodeSpliterator.OfRef<>(this);
}
@Override @Override
public int getChildCount() { public int getChildCount() {
return 2; return 2;
} }
@Override @Override
public Node<T> getChild(int i) { public T_NODE getChild(int i) {
if (i == 0) return left; if (i == 0) return left;
if (i == 1) return right; if (i == 1) return right;
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} }
@Override
public long count() {
return size;
}
}
static final class ConcNode<T>
extends AbstractConcNode<T, Node<T>>
implements Node<T> {
ConcNode(Node<T> left, Node<T> right) {
super(left, right);
}
@Override
public Spliterator<T> spliterator() {
return new Nodes.InternalNodeSpliterator.OfRef<>(this);
}
@Override @Override
public void copyInto(T[] array, int offset) { public void copyInto(T[] array, int offset) {
Objects.requireNonNull(array); Objects.requireNonNull(array);
...@@ -878,17 +786,27 @@ final class Nodes { ...@@ -878,17 +786,27 @@ final class Nodes {
return array; return array;
} }
@Override
public long count() {
return size;
}
@Override @Override
public void forEach(Consumer<? super T> consumer) { public void forEach(Consumer<? super T> consumer) {
left.forEach(consumer); left.forEach(consumer);
right.forEach(consumer); right.forEach(consumer);
} }
@Override
public Node<T> truncate(long from, long to, IntFunction<T[]> generator) {
if (from == 0 && to == count())
return this;
long leftCount = left.count();
if (from >= leftCount)
return right.truncate(from - leftCount, to - leftCount, generator);
else if (to <= leftCount)
return left.truncate(from, to, generator);
else {
return Nodes.conc(getShape(), left.truncate(from, leftCount, generator),
right.truncate(0, to - leftCount, generator));
}
}
@Override @Override
public String toString() { public String toString() {
if (count() < 32) { if (count() < 32) {
...@@ -897,12 +815,92 @@ final class Nodes { ...@@ -897,12 +815,92 @@ final class Nodes {
return String.format("ConcNode[size=%d]", count()); return String.format("ConcNode[size=%d]", count());
} }
} }
private abstract static class OfPrimitive<E, T_CONS, T_ARR,
T_SPLITR extends Spliterator.OfPrimitive<E, T_CONS, T_SPLITR>,
T_NODE extends Node.OfPrimitive<E, T_CONS, T_ARR, T_SPLITR, T_NODE>>
extends AbstractConcNode<E, T_NODE>
implements Node.OfPrimitive<E, T_CONS, T_ARR, T_SPLITR, T_NODE> {
OfPrimitive(T_NODE left, T_NODE right) {
super(left, right);
}
@Override
public void forEach(T_CONS consumer) {
left.forEach(consumer);
right.forEach(consumer);
}
@Override
public void copyInto(T_ARR array, int offset) {
left.copyInto(array, offset);
right.copyInto(array, offset + (int) left.count());
}
@Override
public T_ARR asPrimitiveArray() {
T_ARR array = newArray((int) count());
copyInto(array, 0);
return array;
}
@Override
public String toString() {
if (count() < 32)
return String.format("%s[%s.%s]", this.getClass().getName(), left, right);
else
return String.format("%s[size=%d]", this.getClass().getName(), count());
}
}
static final class OfInt
extends ConcNode.OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt>
implements Node.OfInt {
OfInt(Node.OfInt left, Node.OfInt right) {
super(left, right);
}
@Override
public Spliterator.OfInt spliterator() {
return new InternalNodeSpliterator.OfInt(this);
}
}
static final class OfLong
extends ConcNode.OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong>
implements Node.OfLong {
OfLong(Node.OfLong left, Node.OfLong right) {
super(left, right);
}
@Override
public Spliterator.OfLong spliterator() {
return new InternalNodeSpliterator.OfLong(this);
}
}
static final class OfDouble
extends ConcNode.OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble>
implements Node.OfDouble {
OfDouble(Node.OfDouble left, Node.OfDouble right) {
super(left, right);
}
@Override
public Spliterator.OfDouble spliterator() {
return new InternalNodeSpliterator.OfDouble(this);
}
}
} }
/** Abstract class for spliterator for all internal node classes */ /** Abstract class for spliterator for all internal node classes */
private static abstract class InternalNodeSpliterator<T, private static abstract class InternalNodeSpliterator<T,
S extends Spliterator<T>, S extends Spliterator<T>,
N extends Node<T>, C> N extends Node<T>>
implements Spliterator<T> { implements Spliterator<T> {
// Node we are pointing to // Node we are pointing to
// null if full traversal has occurred // null if full traversal has occurred
...@@ -960,7 +958,7 @@ final class Nodes { ...@@ -960,7 +958,7 @@ final class Nodes {
return null; return null;
} }
protected final boolean internalTryAdvance(C consumer) { protected final boolean initTryAdvance() {
if (curNode == null) if (curNode == null)
return false; return false;
...@@ -981,29 +979,12 @@ final class Nodes { ...@@ -981,29 +979,12 @@ final class Nodes {
else else
tryAdvanceSpliterator = lastNodeSpliterator; tryAdvanceSpliterator = lastNodeSpliterator;
} }
return true;
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;
} }
protected abstract boolean tryAdvance(S spliterator, C consumer);
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public S trySplit() { public final S trySplit() {
if (curNode == null || tryAdvanceSpliterator != null) if (curNode == null || tryAdvanceSpliterator != null)
return null; // Cannot split if fully or partially traversed return null; // Cannot split if fully or partially traversed
else if (lastNodeSpliterator != null) else if (lastNodeSpliterator != null)
...@@ -1024,7 +1005,7 @@ final class Nodes { ...@@ -1024,7 +1005,7 @@ final class Nodes {
} }
@Override @Override
public long estimateSize() { public final long estimateSize() {
if (curNode == null) if (curNode == null)
return 0; return 0;
...@@ -1041,12 +1022,12 @@ final class Nodes { ...@@ -1041,12 +1022,12 @@ final class Nodes {
} }
@Override @Override
public int characteristics() { public final int characteristics() {
return Spliterator.SIZED; return Spliterator.SIZED;
} }
private static final class OfRef<T> 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) { OfRef(Node<T> curNode) {
super(curNode); super(curNode);
...@@ -1054,13 +1035,24 @@ final class Nodes { ...@@ -1054,13 +1035,24 @@ final class Nodes {
@Override @Override
public boolean tryAdvance(Consumer<? super T> consumer) { public boolean tryAdvance(Consumer<? super T> consumer) {
return internalTryAdvance(consumer); if (!initTryAdvance())
} return false;
@Override boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
protected boolean tryAdvance(Spliterator<T> spliterator, if (!hasNext) {
Consumer<? super T> consumer) { if (lastNodeSpliterator == null) {
return spliterator.tryAdvance(consumer); // 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 @Override
...@@ -1085,34 +1077,47 @@ final class Nodes { ...@@ -1085,34 +1077,47 @@ final class Nodes {
} }
} }
private static final class OfInt private static abstract class OfPrimitive<T, T_CONS, T_ARR,
extends InternalNodeSpliterator<Integer, Spliterator.OfInt, Node.OfInt, IntConsumer> T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
implements Spliterator.OfInt { N extends Node.OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, N>>
extends InternalNodeSpliterator<T, T_SPLITR, N>
implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> {
OfInt(Node.OfInt cur) { OfPrimitive(N cur) {
super(cur); super(cur);
} }
@Override @Override
public boolean tryAdvance(IntConsumer consumer) { public boolean tryAdvance(T_CONS consumer) {
return internalTryAdvance(consumer); if (!initTryAdvance())
} return false;
@Override boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
protected boolean tryAdvance(Spliterator.OfInt spliterator, if (!hasNext) {
IntConsumer consumer) { if (lastNodeSpliterator == null) {
return spliterator.tryAdvance(consumer); // 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 @Override
public void forEachRemaining(IntConsumer consumer) { public void forEachRemaining(T_CONS consumer) {
if (curNode == null) if (curNode == null)
return; return;
if (tryAdvanceSpliterator == null) { if (tryAdvanceSpliterator == null) {
if (lastNodeSpliterator == null) { if (lastNodeSpliterator == null) {
Deque<Node.OfInt> stack = initStack(); Deque<N> stack = initStack();
Node.OfInt leaf; N leaf;
while ((leaf = findNextLeafNode(stack)) != null) { while ((leaf = findNextLeafNode(stack)) != null) {
leaf.forEach(consumer); leaf.forEach(consumer);
} }
...@@ -1126,86 +1131,31 @@ final class Nodes { ...@@ -1126,86 +1131,31 @@ final class Nodes {
} }
} }
private static final class OfLong private static final class OfInt
extends InternalNodeSpliterator<Long, Spliterator.OfLong, Node.OfLong, LongConsumer> extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt>
implements Spliterator.OfLong { implements Spliterator.OfInt {
OfLong(Node.OfLong cur) { OfInt(Node.OfInt cur) {
super(cur); super(cur);
} }
}
@Override private static final class OfLong
public boolean tryAdvance(LongConsumer consumer) { extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong>
return internalTryAdvance(consumer); implements Spliterator.OfLong {
}
@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) { OfLong(Node.OfLong cur) {
if (lastNodeSpliterator == null) { super(cur);
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 private static final class OfDouble
extends InternalNodeSpliterator<Double, Spliterator.OfDouble, Node.OfDouble, DoubleConsumer> extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble>
implements Spliterator.OfDouble { implements Spliterator.OfDouble {
OfDouble(Node.OfDouble cur) { OfDouble(Node.OfDouble cur) {
super(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)) { }
}
} }
} }
...@@ -1330,47 +1280,6 @@ final class Nodes { ...@@ -1330,47 +1280,6 @@ final class Nodes {
private static final long[] EMPTY_LONG_ARRAY = new long[0]; private static final long[] EMPTY_LONG_ARRAY = new long[0];
private static final double[] EMPTY_DOUBLE_ARRAY = new double[0]; private static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
private abstract static class AbstractPrimitiveConcNode<E, N extends Node<E>>
implements Node<E> {
final N left;
final N right;
final long size;
AbstractPrimitiveConcNode(N left, N right) {
this.left = left;
this.right = right;
// The Node count will be required when the Node spliterator is
// obtained and it is cheaper to aggressively calculate bottom up as
// the tree is built rather than later on by traversing the tree
this.size = left.count() + right.count();
}
@Override
public int getChildCount() {
return 2;
}
@Override
public N getChild(int i) {
if (i == 0) return left;
if (i == 1) return right;
throw new IndexOutOfBoundsException();
}
@Override
public long count() {
return size;
}
@Override
public String toString() {
if (count() < 32)
return String.format("%s[%s.%s]", this.getClass().getName(), left, right);
else
return String.format("%s[size=%d]", this.getClass().getName(), count());
}
}
private static class IntArrayNode implements Node.OfInt { private static class IntArrayNode implements Node.OfInt {
final int[] array; final int[] array;
int curSize; int curSize;
...@@ -1535,105 +1444,6 @@ final class Nodes { ...@@ -1535,105 +1444,6 @@ final class Nodes {
} }
} }
static final class IntConcNode
extends AbstractPrimitiveConcNode<Integer, Node.OfInt>
implements Node.OfInt {
IntConcNode(Node.OfInt left, Node.OfInt right) {
super(left, right);
}
@Override
public void forEach(IntConsumer consumer) {
left.forEach(consumer);
right.forEach(consumer);
}
@Override
public Spliterator.OfInt spliterator() {
return new InternalNodeSpliterator.OfInt(this);
}
@Override
public void copyInto(int[] array, int offset) {
left.copyInto(array, offset);
right.copyInto(array, offset + (int) left.count());
}
@Override
public int[] asPrimitiveArray() {
int[] array = new int[(int) count()];
copyInto(array, 0);
return array;
}
}
static final class LongConcNode
extends AbstractPrimitiveConcNode<Long, Node.OfLong>
implements Node.OfLong {
LongConcNode(Node.OfLong left, Node.OfLong right) {
super(left, right);
}
@Override
public void forEach(LongConsumer consumer) {
left.forEach(consumer);
right.forEach(consumer);
}
@Override
public Spliterator.OfLong spliterator() {
return new InternalNodeSpliterator.OfLong(this);
}
@Override
public void copyInto(long[] array, int offset) {
left.copyInto(array, offset);
right.copyInto(array, offset + (int) left.count());
}
@Override
public long[] asPrimitiveArray() {
long[] array = new long[(int) count()];
copyInto(array, 0);
return array;
}
}
static final class DoubleConcNode
extends AbstractPrimitiveConcNode<Double, Node.OfDouble>
implements Node.OfDouble {
DoubleConcNode(Node.OfDouble left, Node.OfDouble right) {
super(left, right);
}
@Override
public void forEach(DoubleConsumer consumer) {
left.forEach(consumer);
right.forEach(consumer);
}
@Override
public Spliterator.OfDouble spliterator() {
return new InternalNodeSpliterator.OfDouble(this);
}
@Override
public void copyInto(double[] array, int offset) {
left.copyInto(array, offset);
right.copyInto(array, offset + (int) left.count());
}
@Override
public double[] asPrimitiveArray() {
double[] array = new double[(int) count()];
copyInto(array, 0);
return array;
}
}
private static final class IntFixedNodeBuilder private static final class IntFixedNodeBuilder
extends IntArrayNode extends IntArrayNode
implements Node.Builder.OfInt { implements Node.Builder.OfInt {
...@@ -2245,23 +2055,25 @@ final class Nodes { ...@@ -2245,23 +2055,25 @@ final class Nodes {
} }
} }
private static final class OfInt private static class OfPrimitive<T, T_CONS, T_ARR,
extends ToArrayTask<Integer, Node.OfInt, OfInt> { T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
private final int[] array; T_NODE extends Node.OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>>
extends ToArrayTask<T, T_NODE, OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>> {
private final T_ARR array;
private OfInt(Node.OfInt node, int[] array, int offset) { private OfPrimitive(T_NODE node, T_ARR array, int offset) {
super(node, offset); super(node, offset);
this.array = array; this.array = array;
} }
private OfInt(OfInt parent, Node.OfInt node, int offset) { private OfPrimitive(OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> parent, T_NODE node, int offset) {
super(parent, node, offset); super(parent, node, offset);
this.array = parent.array; this.array = parent.array;
} }
@Override @Override
OfInt makeChild(int childIndex, int offset) { OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> makeChild(int childIndex, int offset) {
return new OfInt(this, node.getChild(childIndex), offset); return new OfPrimitive<>(this, node.getChild(childIndex), offset);
} }
@Override @Override
...@@ -2270,198 +2082,98 @@ final class Nodes { ...@@ -2270,198 +2082,98 @@ final class Nodes {
} }
} }
private static final class OfLong private static final class OfInt
extends ToArrayTask<Long, Node.OfLong, OfLong> { extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt> {
private final long[] array; private OfInt(Node.OfInt node, int[] array, int offset) {
super(node, array, offset);
private OfLong(Node.OfLong node, long[] array, int offset) {
super(node, offset);
this.array = array;
}
private OfLong(OfLong parent, Node.OfLong node, int offset) {
super(parent, node, offset);
this.array = parent.array;
}
@Override
OfLong makeChild(int childIndex, int offset) {
return new OfLong(this, node.getChild(childIndex), offset);
} }
}
@Override private static final class OfLong
void copyNodeToArray() { extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong> {
node.copyInto(array, offset); private OfLong(Node.OfLong node, long[] array, int offset) {
super(node, array, offset);
} }
} }
private static final class OfDouble private static final class OfDouble
extends ToArrayTask<Double, Node.OfDouble, OfDouble> { extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble> {
private final double[] array;
private OfDouble(Node.OfDouble node, double[] array, int offset) { private OfDouble(Node.OfDouble node, double[] array, int offset) {
super(node, offset); super(node, array, offset);
this.array = array;
}
private OfDouble(OfDouble parent, Node.OfDouble node, int offset) {
super(parent, node, offset);
this.array = parent.array;
}
@Override
OfDouble makeChild(int childIndex, int offset) {
return new OfDouble(this, node.getChild(childIndex), offset);
}
@Override
void copyNodeToArray() {
node.copyInto(array, offset);
} }
} }
} }
private static final class CollectorTask<P_IN, P_OUT> private static class CollectorTask<P_IN, P_OUT, T_NODE extends Node<P_OUT>, T_BUILDER extends Node.Builder<P_OUT>>
extends AbstractTask<P_IN, P_OUT, Node<P_OUT>, CollectorTask<P_IN, P_OUT>> { extends AbstractTask<P_IN, P_OUT, T_NODE, CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER>> {
private final PipelineHelper<P_OUT> helper; protected final PipelineHelper<P_OUT> helper;
private final IntFunction<P_OUT[]> generator; protected final LongFunction<T_BUILDER> builderFactory;
protected final BinaryOperator<T_NODE> concFactory;
CollectorTask(PipelineHelper<P_OUT> helper, CollectorTask(PipelineHelper<P_OUT> helper,
IntFunction<P_OUT[]> generator, Spliterator<P_IN> spliterator,
Spliterator<P_IN> spliterator) { LongFunction<T_BUILDER> builderFactory,
BinaryOperator<T_NODE> concFactory) {
super(helper, spliterator); super(helper, spliterator);
this.helper = helper; this.helper = helper;
this.generator = generator; this.builderFactory = builderFactory;
this.concFactory = concFactory;
} }
CollectorTask(CollectorTask<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator) { CollectorTask(CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER> parent,
Spliterator<P_IN> spliterator) {
super(parent, spliterator); super(parent, spliterator);
helper = parent.helper; helper = parent.helper;
generator = parent.generator; builderFactory = parent.builderFactory;
concFactory = parent.concFactory;
} }
@Override @Override
protected CollectorTask<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator) { protected CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER> makeChild(Spliterator<P_IN> spliterator) {
return new CollectorTask<>(this, spliterator); return new CollectorTask<>(this, spliterator);
} }
@Override @Override
protected Node<P_OUT> doLeaf() { protected T_NODE doLeaf() {
Node.Builder<P_OUT> builder T_BUILDER builder = builderFactory.apply(helper.exactOutputSizeIfKnown(spliterator));
= builder(helper.exactOutputSizeIfKnown(spliterator), return (T_NODE) helper.wrapAndCopyInto(builder, spliterator).build();
generator);
return helper.wrapAndCopyInto(builder, spliterator).build();
} }
@Override @Override
public void onCompletion(CountedCompleter caller) { public void onCompletion(CountedCompleter caller) {
if (!isLeaf()) { if (!isLeaf())
setLocalResult(new ConcNode<>(leftChild.getLocalResult(), rightChild.getLocalResult())); setLocalResult(concFactory.apply(leftChild.getLocalResult(), rightChild.getLocalResult()));
}
super.onCompletion(caller); super.onCompletion(caller);
} }
}
private static final class IntCollectorTask<P_IN>
extends AbstractTask<P_IN, Integer, Node.OfInt, IntCollectorTask<P_IN>> {
private final PipelineHelper<Integer> helper;
IntCollectorTask(PipelineHelper<Integer> helper, Spliterator<P_IN> spliterator) {
super(helper, spliterator);
this.helper = helper;
}
IntCollectorTask(IntCollectorTask<P_IN> parent, Spliterator<P_IN> spliterator) { private static final class OfRef<P_IN, P_OUT>
super(parent, spliterator); extends CollectorTask<P_IN, P_OUT, Node<P_OUT>, Node.Builder<P_OUT>> {
helper = parent.helper; OfRef(PipelineHelper<P_OUT> helper,
} IntFunction<P_OUT[]> generator,
Spliterator<P_IN> spliterator) {
@Override super(helper, spliterator, s -> builder(s, generator), ConcNode::new);
protected IntCollectorTask<P_IN> makeChild(Spliterator<P_IN> spliterator) {
return new IntCollectorTask<>(this, spliterator);
}
@Override
protected Node.OfInt doLeaf() {
Node.Builder.OfInt builder = intBuilder(helper.exactOutputSizeIfKnown(spliterator));
return helper.wrapAndCopyInto(builder, spliterator).build();
}
@Override
public void onCompletion(CountedCompleter caller) {
if (!isLeaf()) {
setLocalResult(new IntConcNode(leftChild.getLocalResult(), rightChild.getLocalResult()));
} }
super.onCompletion(caller);
}
}
private static final class LongCollectorTask<P_IN>
extends AbstractTask<P_IN, Long, Node.OfLong, LongCollectorTask<P_IN>> {
private final PipelineHelper<Long> helper;
LongCollectorTask(PipelineHelper<Long> helper, Spliterator<P_IN> spliterator) {
super(helper, spliterator);
this.helper = helper;
}
LongCollectorTask(LongCollectorTask<P_IN> parent, Spliterator<P_IN> spliterator) {
super(parent, spliterator);
helper = parent.helper;
}
@Override
protected LongCollectorTask<P_IN> makeChild(Spliterator<P_IN> spliterator) {
return new LongCollectorTask<>(this, spliterator);
} }
@Override private static final class OfInt<P_IN>
protected Node.OfLong doLeaf() { extends CollectorTask<P_IN, Integer, Node.OfInt, Node.Builder.OfInt> {
Node.Builder.OfLong builder = longBuilder(helper.exactOutputSizeIfKnown(spliterator)); OfInt(PipelineHelper<Integer> helper, Spliterator<P_IN> spliterator) {
return helper.wrapAndCopyInto(builder, spliterator).build(); super(helper, spliterator, Nodes::intBuilder, ConcNode.OfInt::new);
}
@Override
public void onCompletion(CountedCompleter caller) {
if (!isLeaf()) {
setLocalResult(new LongConcNode(leftChild.getLocalResult(), rightChild.getLocalResult()));
} }
super.onCompletion(caller);
}
}
private static final class DoubleCollectorTask<P_IN>
extends AbstractTask<P_IN, Double, Node.OfDouble, DoubleCollectorTask<P_IN>> {
private final PipelineHelper<Double> helper;
DoubleCollectorTask(PipelineHelper<Double> helper, Spliterator<P_IN> spliterator) {
super(helper, spliterator);
this.helper = helper;
} }
DoubleCollectorTask(DoubleCollectorTask<P_IN> parent, Spliterator<P_IN> spliterator) { private static final class OfLong<P_IN>
super(parent, spliterator); extends CollectorTask<P_IN, Long, Node.OfLong, Node.Builder.OfLong> {
helper = parent.helper; OfLong(PipelineHelper<Long> helper, Spliterator<P_IN> spliterator) {
} super(helper, spliterator, Nodes::longBuilder, ConcNode.OfLong::new);
}
@Override
protected DoubleCollectorTask<P_IN> makeChild(Spliterator<P_IN> spliterator) {
return new DoubleCollectorTask<>(this, spliterator);
}
@Override
protected Node.OfDouble doLeaf() {
Node.Builder.OfDouble builder
= doubleBuilder(helper.exactOutputSizeIfKnown(spliterator));
return helper.wrapAndCopyInto(builder, spliterator).build();
} }
@Override private static final class OfDouble<P_IN>
public void onCompletion(CountedCompleter caller) { extends CollectorTask<P_IN, Double, Node.OfDouble, Node.Builder.OfDouble> {
if (!isLeaf()) { OfDouble(PipelineHelper<Double> helper, Spliterator<P_IN> spliterator) {
setLocalResult(new DoubleConcNode(leftChild.getLocalResult(), rightChild.getLocalResult())); super(helper, spliterator, Nodes::doubleBuilder, ConcNode.OfDouble::new);
} }
super.onCompletion(caller);
} }
} }
} }
...@@ -28,7 +28,10 @@ import java.util.ArrayList; ...@@ -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 { ...@@ -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 { ...@@ -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);
} }
} }
}
// @@@ Currently unused -- optimization for when all sizes are known private static long truncatedSize(long size, long from, long to) {
// private static class SizedSliceTask<S, T> extends AbstractShortCircuitTask<S, T, Node<T>, SizedSliceTask<S, T>> { if (from >= 0)
// private final int targetOffset, targetSize; size = Math.max(0, size - from);
// private final int offset, size; long limit = to - from;
// if (limit >= 0)
// private SizedSliceTask(ParallelPipelineHelper<S, T> helper, int offset, int size) { size = Math.min(size, limit);
// super(helper); return size;
// targetOffset = offset; }
// targetSize = size;
// this.offset = 0; /**
// this.size = spliterator.getSizeIfKnown(); * 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
// private SizedSliceTask(SizedSliceTask<S, T> parent, Spliterator<S> spliterator) { * of each child in encounter order of the list of children. Splitting a
// // Makes assumptions about order in which siblings are created and linked into parent! * spliterator obtained from the concatenated node preserves the encounter
// super(parent, spliterator); * order of the list of children.
// targetOffset = parent.targetOffset; *
// targetSize = parent.targetSize; * <p>The result may be a concatenated node, the input sole node if the size
// int siblingSizes = 0; * of the list is 1, or an empty node.
// for (SizedSliceTask<S, T> sibling = parent.children; sibling != null; sibling = sibling.nextSibling) *
// siblingSizes += sibling.size; * @param <T> the type of elements of the concatenated node
// size = spliterator.getSizeIfKnown(); * @param shape the shape of the concatenated node to be created
// offset = parent.offset + siblingSizes; * @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
// @Override * are an not instance of type supported by this factory.
// protected SizedSliceTask<S, T> makeChild(Spliterator<S> spliterator) { */
// return new SizedSliceTask<>(this, spliterator); @SuppressWarnings("unchecked")
// } private static <T> Node<T> conc(StreamShape shape, List<? extends Node<T>> nodes) {
// int size = nodes.size();
// @Override if (size == 0)
// protected Node<T> getEmptyResult() { return Nodes.emptyNode(shape);
// return Nodes.emptyNode(); else if (size == 1)
// } return nodes.get(0);
// else {
// @Override // Create a right-balanced tree when there are more that 2 nodes
// public boolean taskCanceled() { List<Node<T>> refNodes = (List<Node<T>>) nodes;
// if (offset > targetOffset+targetSize || offset+size < targetOffset) Node<T> c = Nodes.conc(shape, refNodes.get(size - 2), refNodes.get(size - 1));
// return true; for (int i = size - 3; i >= 0; i--) {
// else c = Nodes.conc(shape, refNodes.get(i), c);
// return super.taskCanceled(); }
// } return c;
// }
// @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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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));
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册