提交 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> {
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.
*
......@@ -192,19 +218,90 @@ interface Node<T> {
}
}
public interface OfPrimitive<T, T_CONS, T_ARR,
T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
T_NODE extends OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>>
extends Node<T> {
/**
* Specialized {@code Node} for int elements
* {@inheritDoc}
*
* @return a {@link Spliterator.OfPrimitive} describing the elements of
* this node
*/
@Override
T_SPLITR spliterator();
/**
* Traverses the elements of this node, and invoke the provided
* {@code action} with each element.
*
* @param action a consumer that is to be invoked with each
* element in this {@code Node.OfPrimitive}
*/
interface OfInt extends Node<Integer> {
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}
*
* @return a {@link Spliterator.OfInt} describing the elements of this
* node
* @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
Spliterator.OfInt spliterator();
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}
......@@ -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}
*
* @implSpec the default implementation invokes {@link #asPrimitiveArray()} to
* obtain an int[] array then and copies the elements from that int[]
* array into the boxed Integer[] array. This is not efficient and it
* is recommended to invoke {@link #copyInto(int[], int)}.
* is recommended to invoke {@link #copyInto(Object, int)}.
*/
@Override
default void copyInto(Integer[] boxed, int offset) {
......@@ -271,35 +343,23 @@ interface Node<T> {
}
@Override
default Node.OfInt getChild(int i) {
throw new IndexOutOfBoundsException();
default Node.OfInt truncate(long from, long to, IntFunction<Integer[]> generator) {
if (from == 0 && to == count())
return this;
long size = to - from;
Spliterator.OfInt spliterator = spliterator();
Node.Builder.OfInt nodeBuilder = Nodes.intBuilder(size);
nodeBuilder.begin(size);
for (int i = 0; i < from && spliterator.tryAdvance((IntConsumer) e -> { }); i++) { }
for (int i = 0; (i < size) && spliterator.tryAdvance((IntConsumer) nodeBuilder); i++) { }
nodeBuilder.end();
return nodeBuilder.build();
}
/**
* Views this node as an int[] 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}
*/
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);
@Override
default int[] newArray(int count) {
return new int[count];
}
/**
* {@inheritDoc}
......@@ -309,22 +369,12 @@ interface Node<T> {
default StreamShape getShape() {
return StreamShape.INT_VALUE;
}
}
/**
* Specialized {@code Node} for long elements
*/
interface OfLong extends Node<Long> {
/**
* {@inheritDoc}
*
* @return a {@link Spliterator.OfLong} describing the elements of this
* node
*/
@Override
Spliterator.OfLong spliterator();
interface OfLong extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, OfLong> {
/**
* {@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}
*
* @implSpec the default implementation invokes {@link #asPrimitiveArray()}
* to obtain a long[] array then and copies the elements from that
* long[] array into the boxed Long[] array. This is not efficient and
* it is recommended to invoke {@link #copyInto(long[], int)}.
* it is recommended to invoke {@link #copyInto(Object, int)}.
*/
@Override
default void copyInto(Long[] boxed, int offset) {
......@@ -391,35 +416,23 @@ interface Node<T> {
}
@Override
default Node.OfLong getChild(int i) {
throw new IndexOutOfBoundsException();
default Node.OfLong truncate(long from, long to, IntFunction<Long[]> generator) {
if (from == 0 && to == count())
return this;
long size = to - from;
Spliterator.OfLong spliterator = spliterator();
Node.Builder.OfLong nodeBuilder = Nodes.longBuilder(size);
nodeBuilder.begin(size);
for (int i = 0; i < from && spliterator.tryAdvance((LongConsumer) e -> { }); i++) { }
for (int i = 0; (i < size) && spliterator.tryAdvance((LongConsumer) nodeBuilder); i++) { }
nodeBuilder.end();
return nodeBuilder.build();
}
/**
* Views this node as a long[] 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.
*
* @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);
@Override
default long[] newArray(int count) {
return new long[count];
}
/**
* {@inheritDoc}
......@@ -429,23 +442,12 @@ interface Node<T> {
default StreamShape getShape() {
return StreamShape.LONG_VALUE;
}
}
/**
* Specialized {@code Node} for double elements
*/
interface OfDouble extends Node<Double> {
/**
* {@inheritDoc}
*
* @return A {@link Spliterator.OfDouble} describing the elements of
* this node
*/
@Override
Spliterator.OfDouble spliterator();
interface OfDouble extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, OfDouble> {
/**
* {@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}
*
* @implSpec the default implementation invokes {@link #asPrimitiveArray()}
* to obtain a double[] array then and copies the elements from that
* double[] array into the boxed Double[] array. This is not efficient
* and it is recommended to invoke {@link #copyInto(double[], int)}.
* and it is recommended to invoke {@link #copyInto(Object, int)}.
*/
@Override
default void copyInto(Double[] boxed, int offset) {
......@@ -514,35 +491,23 @@ interface Node<T> {
}
@Override
default Node.OfDouble getChild(int i) {
throw new IndexOutOfBoundsException();
default Node.OfDouble truncate(long from, long to, IntFunction<Double[]> generator) {
if (from == 0 && to == count())
return this;
long size = to - from;
Spliterator.OfDouble spliterator = spliterator();
Node.Builder.OfDouble nodeBuilder = Nodes.doubleBuilder(size);
nodeBuilder.begin(size);
for (int i = 0; i < from && spliterator.tryAdvance((DoubleConsumer) e -> { }); i++) { }
for (int i = 0; (i < size) && spliterator.tryAdvance((DoubleConsumer) nodeBuilder); i++) { }
nodeBuilder.end();
return nodeBuilder.build();
}
/**
* Views this node as a double[] 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.
*
* @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);
@Override
default double[] newArray(int count) {
return new double[count];
}
/**
* {@inheritDoc}
......
......@@ -33,11 +33,13 @@ import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.CountedCompleter;
import java.util.function.BinaryOperator;
import java.util.function.Consumer;
import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.function.LongConsumer;
import java.util.function.LongFunction;
/**
* Factory methods for constructing implementations of {@link Node} and
......@@ -97,131 +99,28 @@ final class Nodes {
*
* @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
* @param left the left input node
* @param right the right input node
* @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")
static <T> Node<T> conc(StreamShape shape, List<? extends Node<T>> nodes) {
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;
static <T> Node<T> conc(StreamShape shape, Node<T> left, Node<T> right) {
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();
}
case REFERENCE:
return new ConcNode<>(left, right);
case INT_VALUE:
return (Node<T>) new ConcNode.OfInt((Node.OfInt) left, (Node.OfInt) right);
case LONG_VALUE:
return (Node<T>) new ConcNode.OfLong((Node.OfLong) left, (Node.OfLong) right);
case DOUBLE_VALUE:
return (Node<T>) new ConcNode.OfDouble((Node.OfDouble) left, (Node.OfDouble) right);
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;
}
// Reference-based node methods
/**
......@@ -422,7 +321,7 @@ final class Nodes {
new SizedCollectorTask.OfRef<>(spliterator, helper, array).invoke();
return node(array);
} 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;
}
}
......@@ -460,7 +359,7 @@ final class Nodes {
return node(array);
}
else {
Node.OfInt node = new IntCollectorTask<>(helper, spliterator).invoke();
Node.OfInt node = new CollectorTask.OfInt<>(helper, spliterator).invoke();
return flattenTree ? flattenInt(node) : node;
}
}
......@@ -498,7 +397,7 @@ final class Nodes {
return node(array);
}
else {
Node.OfLong node = new LongCollectorTask<>(helper, spliterator).invoke();
Node.OfLong node = new CollectorTask.OfLong<>(helper, spliterator).invoke();
return flattenTree ? flattenLong(node) : node;
}
}
......@@ -536,7 +435,7 @@ final class Nodes {
return node(array);
}
else {
Node.OfDouble node = new DoubleCollectorTask<>(helper, spliterator).invoke();
Node.OfDouble node = new CollectorTask.OfDouble<>(helper, spliterator).invoke();
return flattenTree ? flattenDouble(node) : node;
}
}
......@@ -763,8 +662,6 @@ final class Nodes {
return curSize;
}
// Traversable
@Override
public void forEach(Consumer<? super T> consumer) {
for (int i = 0; i < curSize; i++) {
......@@ -829,13 +726,12 @@ final class Nodes {
/**
* Node class for an internal node with two or more children
*/
static final class ConcNode<T> implements Node<T> {
private final Node<T> left;
private final Node<T> right;
private static abstract class AbstractConcNode<T, T_NODE extends Node<T>> implements Node<T> {
protected final T_NODE left;
protected final T_NODE right;
private final long size;
ConcNode(Node<T> left, Node<T> right) {
AbstractConcNode(T_NODE left, T_NODE right) {
this.left = left;
this.right = right;
// The Node count will be required when the Node spliterator is
......@@ -845,25 +741,37 @@ final class Nodes {
this.size = left.count() + right.count();
}
// Node
@Override
public Spliterator<T> spliterator() {
return new Nodes.InternalNodeSpliterator.OfRef<>(this);
}
@Override
public int getChildCount() {
return 2;
}
@Override
public Node<T> getChild(int i) {
public T_NODE getChild(int i) {
if (i == 0) return left;
if (i == 1) return right;
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
public void copyInto(T[] array, int offset) {
Objects.requireNonNull(array);
......@@ -878,17 +786,27 @@ final class Nodes {
return array;
}
@Override
public long count() {
return size;
}
@Override
public void forEach(Consumer<? super T> consumer) {
left.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
public String toString() {
if (count() < 32) {
......@@ -897,12 +815,92 @@ final class Nodes {
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 */
private static abstract class InternalNodeSpliterator<T,
S extends Spliterator<T>,
N extends Node<T>, C>
N extends Node<T>>
implements Spliterator<T> {
// Node we are pointing to
// null if full traversal has occurred
......@@ -960,7 +958,7 @@ final class Nodes {
return null;
}
protected final boolean internalTryAdvance(C consumer) {
protected final boolean initTryAdvance() {
if (curNode == null)
return false;
......@@ -981,29 +979,12 @@ final class Nodes {
else
tryAdvanceSpliterator = lastNodeSpliterator;
}
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 true;
}
return hasNext;
}
protected abstract boolean tryAdvance(S spliterator, C consumer);
@Override
@SuppressWarnings("unchecked")
public S trySplit() {
public final S trySplit() {
if (curNode == null || tryAdvanceSpliterator != null)
return null; // Cannot split if fully or partially traversed
else if (lastNodeSpliterator != null)
......@@ -1024,7 +1005,7 @@ final class Nodes {
}
@Override
public long estimateSize() {
public final long estimateSize() {
if (curNode == null)
return 0;
......@@ -1041,12 +1022,12 @@ final class Nodes {
}
@Override
public int characteristics() {
public final int characteristics() {
return Spliterator.SIZED;
}
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) {
super(curNode);
......@@ -1054,13 +1035,24 @@ final class Nodes {
@Override
public boolean tryAdvance(Consumer<? super T> consumer) {
return internalTryAdvance(consumer);
}
if (!initTryAdvance())
return false;
@Override
protected boolean tryAdvance(Spliterator<T> spliterator,
Consumer<? super T> consumer) {
return spliterator.tryAdvance(consumer);
boolean hasNext = tryAdvanceSpliterator.tryAdvance(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 = 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
......@@ -1085,34 +1077,47 @@ final class Nodes {
}
}
private static final class OfInt
extends InternalNodeSpliterator<Integer, Spliterator.OfInt, Node.OfInt, IntConsumer>
implements Spliterator.OfInt {
private static abstract class OfPrimitive<T, T_CONS, T_ARR,
T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
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);
}
@Override
public boolean tryAdvance(IntConsumer consumer) {
return internalTryAdvance(consumer);
}
public boolean tryAdvance(T_CONS consumer) {
if (!initTryAdvance())
return false;
@Override
protected boolean tryAdvance(Spliterator.OfInt spliterator,
IntConsumer consumer) {
return spliterator.tryAdvance(consumer);
boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer);
if (!hasNext) {
if (lastNodeSpliterator == null) {
// 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
public void forEachRemaining(IntConsumer consumer) {
public void forEachRemaining(T_CONS consumer) {
if (curNode == null)
return;
if (tryAdvanceSpliterator == null) {
if (lastNodeSpliterator == null) {
Deque<Node.OfInt> stack = initStack();
Node.OfInt leaf;
Deque<N> stack = initStack();
N leaf;
while ((leaf = findNextLeafNode(stack)) != null) {
leaf.forEach(consumer);
}
......@@ -1126,86 +1131,31 @@ final class Nodes {
}
}
private static final class OfLong
extends InternalNodeSpliterator<Long, Spliterator.OfLong, Node.OfLong, LongConsumer>
implements Spliterator.OfLong {
private static final class OfInt
extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt>
implements Spliterator.OfInt {
OfLong(Node.OfLong cur) {
OfInt(Node.OfInt cur) {
super(cur);
}
@Override
public boolean tryAdvance(LongConsumer consumer) {
return internalTryAdvance(consumer);
}
@Override
protected boolean tryAdvance(Spliterator.OfLong spliterator,
LongConsumer consumer) {
return spliterator.tryAdvance(consumer);
}
@Override
public void forEachRemaining(LongConsumer consumer) {
if (curNode == null)
return;
private static final class OfLong
extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong>
implements Spliterator.OfLong {
if (tryAdvanceSpliterator == null) {
if (lastNodeSpliterator == null) {
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)) { }
OfLong(Node.OfLong cur) {
super(cur);
}
}
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 {
OfDouble(Node.OfDouble 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 {
private static final long[] EMPTY_LONG_ARRAY = new long[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 {
final int[] array;
int curSize;
......@@ -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
extends IntArrayNode
implements Node.Builder.OfInt {
......@@ -2245,23 +2055,25 @@ final class Nodes {
}
}
private static final class OfInt
extends ToArrayTask<Integer, Node.OfInt, OfInt> {
private final int[] array;
private static class OfPrimitive<T, T_CONS, T_ARR,
T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>,
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);
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);
this.array = parent.array;
}
@Override
OfInt makeChild(int childIndex, int offset) {
return new OfInt(this, node.getChild(childIndex), offset);
OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> makeChild(int childIndex, int offset) {
return new OfPrimitive<>(this, node.getChild(childIndex), offset);
}
@Override
......@@ -2270,198 +2082,98 @@ final class Nodes {
}
}
private static final class OfLong
extends ToArrayTask<Long, Node.OfLong, OfLong> {
private final long[] array;
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;
private static final class OfInt
extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt> {
private OfInt(Node.OfInt node, int[] array, int offset) {
super(node, array, offset);
}
@Override
OfLong makeChild(int childIndex, int offset) {
return new OfLong(this, node.getChild(childIndex), offset);
}
@Override
void copyNodeToArray() {
node.copyInto(array, offset);
private static final class OfLong
extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong> {
private OfLong(Node.OfLong node, long[] array, int offset) {
super(node, array, offset);
}
}
private static final class OfDouble
extends ToArrayTask<Double, Node.OfDouble, OfDouble> {
private final double[] array;
extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble> {
private OfDouble(Node.OfDouble node, double[] array, int offset) {
super(node, 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);
super(node, array, offset);
}
}
}
private static final class CollectorTask<P_IN, P_OUT>
extends AbstractTask<P_IN, P_OUT, Node<P_OUT>, CollectorTask<P_IN, P_OUT>> {
private final PipelineHelper<P_OUT> helper;
private final IntFunction<P_OUT[]> generator;
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, T_NODE, CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER>> {
protected final PipelineHelper<P_OUT> helper;
protected final LongFunction<T_BUILDER> builderFactory;
protected final BinaryOperator<T_NODE> concFactory;
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);
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);
helper = parent.helper;
generator = parent.generator;
builderFactory = parent.builderFactory;
concFactory = parent.concFactory;
}
@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);
}
@Override
protected Node<P_OUT> doLeaf() {
Node.Builder<P_OUT> builder
= builder(helper.exactOutputSizeIfKnown(spliterator),
generator);
return helper.wrapAndCopyInto(builder, spliterator).build();
protected T_NODE doLeaf() {
T_BUILDER builder = builderFactory.apply(helper.exactOutputSizeIfKnown(spliterator));
return (T_NODE) helper.wrapAndCopyInto(builder, spliterator).build();
}
@Override
public void onCompletion(CountedCompleter caller) {
if (!isLeaf()) {
setLocalResult(new ConcNode<>(leftChild.getLocalResult(), rightChild.getLocalResult()));
}
if (!isLeaf())
setLocalResult(concFactory.apply(leftChild.getLocalResult(), rightChild.getLocalResult()));
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) {
super(parent, spliterator);
helper = parent.helper;
}
@Override
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
protected Node.OfLong doLeaf() {
Node.Builder.OfLong builder = longBuilder(helper.exactOutputSizeIfKnown(spliterator));
return helper.wrapAndCopyInto(builder, spliterator).build();
}
@Override
public void onCompletion(CountedCompleter caller) {
if (!isLeaf()) {
setLocalResult(new LongConcNode(leftChild.getLocalResult(), rightChild.getLocalResult()));
}
super.onCompletion(caller);
private static final class OfRef<P_IN, P_OUT>
extends CollectorTask<P_IN, P_OUT, Node<P_OUT>, Node.Builder<P_OUT>> {
OfRef(PipelineHelper<P_OUT> helper,
IntFunction<P_OUT[]> generator,
Spliterator<P_IN> spliterator) {
super(helper, spliterator, s -> builder(s, generator), ConcNode::new);
}
}
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;
private static final class OfInt<P_IN>
extends CollectorTask<P_IN, Integer, Node.OfInt, Node.Builder.OfInt> {
OfInt(PipelineHelper<Integer> helper, Spliterator<P_IN> spliterator) {
super(helper, spliterator, Nodes::intBuilder, ConcNode.OfInt::new);
}
DoubleCollectorTask(DoubleCollectorTask<P_IN> parent, Spliterator<P_IN> spliterator) {
super(parent, spliterator);
helper = parent.helper;
}
@Override
protected DoubleCollectorTask<P_IN> makeChild(Spliterator<P_IN> spliterator) {
return new DoubleCollectorTask<>(this, spliterator);
private static final class OfLong<P_IN>
extends CollectorTask<P_IN, Long, Node.OfLong, Node.Builder.OfLong> {
OfLong(PipelineHelper<Long> helper, Spliterator<P_IN> spliterator) {
super(helper, spliterator, Nodes::longBuilder, ConcNode.OfLong::new);
}
@Override
protected Node.OfDouble doLeaf() {
Node.Builder.OfDouble builder
= doubleBuilder(helper.exactOutputSizeIfKnown(spliterator));
return helper.wrapAndCopyInto(builder, spliterator).build();
}
@Override
public void onCompletion(CountedCompleter caller) {
if (!isLeaf()) {
setLocalResult(new DoubleConcNode(leftChild.getLocalResult(), rightChild.getLocalResult()));
private static final class OfDouble<P_IN>
extends CollectorTask<P_IN, Double, Node.OfDouble, Node.Builder.OfDouble> {
OfDouble(PipelineHelper<Double> helper, Spliterator<P_IN> spliterator) {
super(helper, spliterator, Nodes::doubleBuilder, ConcNode.OfDouble::new);
}
super.onCompletion(caller);
}
}
}
......@@ -28,7 +28,10 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Spliterator;
import java.util.concurrent.CountedCompleter;
import java.util.function.DoubleConsumer;
import java.util.function.IntConsumer;
import java.util.function.IntFunction;
import java.util.function.LongConsumer;
/**
* Factory for instances of a short-circuiting stateful intermediate operations
......@@ -352,7 +355,7 @@ final class SliceOps {
else
// This will create a tree of depth 1 and will not be a sub-tree
// for leaf nodes within the require range
result = Nodes.conc(op.getOutputShape(), nodes);
result = conc(op.getOutputShape(), nodes);
setLocalResult(result);
}
}
......@@ -418,94 +421,116 @@ final class SliceOps {
if (skipLeft == 0 && skipRight == 0)
return input;
else {
return Nodes.truncateNode(input, skipLeft, thisNodeSize - skipRight, generator);
}
}
}
// @@@ 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);
// }
// }
// }
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;
}
}
}
}
......@@ -102,7 +102,7 @@ public class DoubleNodeTest extends OpTestCase {
double i = it.nextDouble();
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 {
return Nodes.node(new double[] {i});
......@@ -114,7 +114,7 @@ public class DoubleNodeTest extends OpTestCase {
return m.apply(l);
}
else {
return new Nodes.DoubleConcNode(
return new Nodes.ConcNode.OfDouble(
tree(l.subList(0, l.size() / 2), m),
tree(l.subList(l.size() / 2, l.size()), m));
}
......
......@@ -102,7 +102,7 @@ public class IntNodeTest extends OpTestCase {
int i = it.nextInt();
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 {
return Nodes.node(new int[] {i});
......@@ -114,7 +114,7 @@ public class IntNodeTest extends OpTestCase {
return m.apply(l);
}
else {
return new Nodes.IntConcNode(
return new Nodes.ConcNode.OfInt(
tree(l.subList(0, l.size() / 2), m),
tree(l.subList(l.size() / 2, l.size()), m));
}
......
......@@ -102,7 +102,7 @@ public class LongNodeTest extends OpTestCase {
long i = it.nextLong();
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 {
return Nodes.node(new long[] {i});
......@@ -114,7 +114,7 @@ public class LongNodeTest extends OpTestCase {
return m.apply(l);
}
else {
return new Nodes.LongConcNode(
return new Nodes.ConcNode.OfLong(
tree(l.subList(0, l.size() / 2), 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.
先完成此消息的编辑!
想要评论请 注册