author | psandoz |
Thu, 16 Jan 2014 18:20:31 +0100 | |
changeset 22289 | bb9c71b84919 |
parent 20507 | 8498104f92c3 |
child 22297 | 1c62c67d9dd2 |
permissions | -rw-r--r-- |
17182 | 1 |
/* |
2 |
* Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. |
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
7 |
* published by the Free Software Foundation. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
24 |
*/ |
|
25 |
package java.util.stream; |
|
26 |
||
27 |
import java.util.ArrayDeque; |
|
28 |
import java.util.Arrays; |
|
29 |
import java.util.Collection; |
|
30 |
import java.util.Deque; |
|
31 |
import java.util.List; |
|
32 |
import java.util.Objects; |
|
33 |
import java.util.Spliterator; |
|
34 |
import java.util.Spliterators; |
|
35 |
import java.util.concurrent.CountedCompleter; |
|
18527 | 36 |
import java.util.function.BinaryOperator; |
17182 | 37 |
import java.util.function.Consumer; |
38 |
import java.util.function.DoubleConsumer; |
|
39 |
import java.util.function.IntConsumer; |
|
40 |
import java.util.function.IntFunction; |
|
41 |
import java.util.function.LongConsumer; |
|
18527 | 42 |
import java.util.function.LongFunction; |
17182 | 43 |
|
44 |
/** |
|
45 |
* Factory methods for constructing implementations of {@link Node} and |
|
46 |
* {@link Node.Builder} and their primitive specializations. Fork/Join tasks |
|
47 |
* for collecting output from a {@link PipelineHelper} to a {@link Node} and |
|
48 |
* flattening {@link Node}s. |
|
49 |
* |
|
50 |
* @since 1.8 |
|
51 |
*/ |
|
52 |
final class Nodes { |
|
53 |
||
54 |
private Nodes() { |
|
55 |
throw new Error("no instances"); |
|
56 |
} |
|
57 |
||
58 |
/** |
|
59 |
* The maximum size of an array that can be allocated. |
|
60 |
*/ |
|
61 |
static final long MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; |
|
62 |
||
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
63 |
// IllegalArgumentException messages |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
64 |
static final String BAD_SIZE = "Stream size exceeds max array size"; |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
65 |
|
19220
d3d40ccb544e
8022476: cleanup some raw types and unchecked warnings in java.util.stream
mduigou
parents:
19218
diff
changeset
|
66 |
@SuppressWarnings("raw") |
17182 | 67 |
private static final Node EMPTY_NODE = new EmptyNode.OfRef(); |
68 |
private static final Node.OfInt EMPTY_INT_NODE = new EmptyNode.OfInt(); |
|
69 |
private static final Node.OfLong EMPTY_LONG_NODE = new EmptyNode.OfLong(); |
|
70 |
private static final Node.OfDouble EMPTY_DOUBLE_NODE = new EmptyNode.OfDouble(); |
|
71 |
||
72 |
// General shape-based node creation methods |
|
73 |
||
74 |
/** |
|
75 |
* Produces an empty node whose count is zero, has no children and no content. |
|
76 |
* |
|
77 |
* @param <T> the type of elements of the created node |
|
78 |
* @param shape the shape of the node to be created |
|
79 |
* @return an empty node. |
|
80 |
*/ |
|
81 |
@SuppressWarnings("unchecked") |
|
82 |
static <T> Node<T> emptyNode(StreamShape shape) { |
|
83 |
switch (shape) { |
|
84 |
case REFERENCE: return (Node<T>) EMPTY_NODE; |
|
85 |
case INT_VALUE: return (Node<T>) EMPTY_INT_NODE; |
|
86 |
case LONG_VALUE: return (Node<T>) EMPTY_LONG_NODE; |
|
87 |
case DOUBLE_VALUE: return (Node<T>) EMPTY_DOUBLE_NODE; |
|
88 |
default: |
|
89 |
throw new IllegalStateException("Unknown shape " + shape); |
|
90 |
} |
|
91 |
} |
|
92 |
||
93 |
/** |
|
94 |
* Produces a concatenated {@link Node} that has two or more children. |
|
95 |
* <p>The count of the concatenated node is equal to the sum of the count |
|
96 |
* of each child. Traversal of the concatenated node traverses the content |
|
97 |
* of each child in encounter order of the list of children. Splitting a |
|
98 |
* spliterator obtained from the concatenated node preserves the encounter |
|
99 |
* order of the list of children. |
|
100 |
* |
|
101 |
* <p>The result may be a concatenated node, the input sole node if the size |
|
102 |
* of the list is 1, or an empty node. |
|
103 |
* |
|
104 |
* @param <T> the type of elements of the concatenated node |
|
105 |
* @param shape the shape of the concatenated node to be created |
|
18527 | 106 |
* @param left the left input node |
107 |
* @param right the right input node |
|
17182 | 108 |
* @return a {@code Node} covering the elements of the input nodes |
109 |
* @throws IllegalStateException if all {@link Node} elements of the list |
|
110 |
* are an not instance of type supported by this factory. |
|
111 |
*/ |
|
112 |
@SuppressWarnings("unchecked") |
|
18527 | 113 |
static <T> Node<T> conc(StreamShape shape, Node<T> left, Node<T> right) { |
17182 | 114 |
switch (shape) { |
18527 | 115 |
case REFERENCE: |
116 |
return new ConcNode<>(left, right); |
|
117 |
case INT_VALUE: |
|
118 |
return (Node<T>) new ConcNode.OfInt((Node.OfInt) left, (Node.OfInt) right); |
|
119 |
case LONG_VALUE: |
|
120 |
return (Node<T>) new ConcNode.OfLong((Node.OfLong) left, (Node.OfLong) right); |
|
121 |
case DOUBLE_VALUE: |
|
122 |
return (Node<T>) new ConcNode.OfDouble((Node.OfDouble) left, (Node.OfDouble) right); |
|
17182 | 123 |
default: |
124 |
throw new IllegalStateException("Unknown shape " + shape); |
|
125 |
} |
|
126 |
} |
|
127 |
||
128 |
// Reference-based node methods |
|
129 |
||
130 |
/** |
|
131 |
* Produces a {@link Node} describing an array. |
|
132 |
* |
|
133 |
* <p>The node will hold a reference to the array and will not make a copy. |
|
134 |
* |
|
135 |
* @param <T> the type of elements held by the node |
|
136 |
* @param array the array |
|
137 |
* @return a node holding an array |
|
138 |
*/ |
|
139 |
static <T> Node<T> node(T[] array) { |
|
140 |
return new ArrayNode<>(array); |
|
141 |
} |
|
142 |
||
143 |
/** |
|
144 |
* Produces a {@link Node} describing a {@link Collection}. |
|
145 |
* <p> |
|
146 |
* The node will hold a reference to the collection and will not make a copy. |
|
147 |
* |
|
148 |
* @param <T> the type of elements held by the node |
|
149 |
* @param c the collection |
|
150 |
* @return a node holding a collection |
|
151 |
*/ |
|
152 |
static <T> Node<T> node(Collection<T> c) { |
|
153 |
return new CollectionNode<>(c); |
|
154 |
} |
|
155 |
||
156 |
/** |
|
157 |
* Produces a {@link Node.Builder}. |
|
158 |
* |
|
159 |
* @param exactSizeIfKnown -1 if a variable size builder is requested, |
|
160 |
* otherwise the exact capacity desired. A fixed capacity builder will |
|
161 |
* fail if the wrong number of elements are added to the builder. |
|
162 |
* @param generator the array factory |
|
163 |
* @param <T> the type of elements of the node builder |
|
164 |
* @return a {@code Node.Builder} |
|
165 |
*/ |
|
166 |
static <T> Node.Builder<T> builder(long exactSizeIfKnown, IntFunction<T[]> generator) { |
|
167 |
return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE) |
|
168 |
? new FixedNodeBuilder<>(exactSizeIfKnown, generator) |
|
169 |
: builder(); |
|
170 |
} |
|
171 |
||
172 |
/** |
|
173 |
* Produces a variable size @{link Node.Builder}. |
|
174 |
* |
|
175 |
* @param <T> the type of elements of the node builder |
|
176 |
* @return a {@code Node.Builder} |
|
177 |
*/ |
|
178 |
static <T> Node.Builder<T> builder() { |
|
179 |
return new SpinedNodeBuilder<>(); |
|
180 |
} |
|
181 |
||
182 |
// Int nodes |
|
183 |
||
184 |
/** |
|
185 |
* Produces a {@link Node.OfInt} describing an int[] array. |
|
186 |
* |
|
187 |
* <p>The node will hold a reference to the array and will not make a copy. |
|
188 |
* |
|
189 |
* @param array the array |
|
190 |
* @return a node holding an array |
|
191 |
*/ |
|
192 |
static Node.OfInt node(int[] array) { |
|
193 |
return new IntArrayNode(array); |
|
194 |
} |
|
195 |
||
196 |
/** |
|
197 |
* Produces a {@link Node.Builder.OfInt}. |
|
198 |
* |
|
199 |
* @param exactSizeIfKnown -1 if a variable size builder is requested, |
|
200 |
* otherwise the exact capacity desired. A fixed capacity builder will |
|
201 |
* fail if the wrong number of elements are added to the builder. |
|
202 |
* @return a {@code Node.Builder.OfInt} |
|
203 |
*/ |
|
204 |
static Node.Builder.OfInt intBuilder(long exactSizeIfKnown) { |
|
205 |
return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE) |
|
206 |
? new IntFixedNodeBuilder(exactSizeIfKnown) |
|
207 |
: intBuilder(); |
|
208 |
} |
|
209 |
||
210 |
/** |
|
211 |
* Produces a variable size @{link Node.Builder.OfInt}. |
|
212 |
* |
|
213 |
* @return a {@code Node.Builder.OfInt} |
|
214 |
*/ |
|
215 |
static Node.Builder.OfInt intBuilder() { |
|
216 |
return new IntSpinedNodeBuilder(); |
|
217 |
} |
|
218 |
||
219 |
// Long nodes |
|
220 |
||
221 |
/** |
|
222 |
* Produces a {@link Node.OfLong} describing a long[] array. |
|
223 |
* <p> |
|
224 |
* The node will hold a reference to the array and will not make a copy. |
|
225 |
* |
|
226 |
* @param array the array |
|
227 |
* @return a node holding an array |
|
228 |
*/ |
|
229 |
static Node.OfLong node(final long[] array) { |
|
230 |
return new LongArrayNode(array); |
|
231 |
} |
|
232 |
||
233 |
/** |
|
234 |
* Produces a {@link Node.Builder.OfLong}. |
|
235 |
* |
|
236 |
* @param exactSizeIfKnown -1 if a variable size builder is requested, |
|
237 |
* otherwise the exact capacity desired. A fixed capacity builder will |
|
238 |
* fail if the wrong number of elements are added to the builder. |
|
239 |
* @return a {@code Node.Builder.OfLong} |
|
240 |
*/ |
|
241 |
static Node.Builder.OfLong longBuilder(long exactSizeIfKnown) { |
|
242 |
return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE) |
|
243 |
? new LongFixedNodeBuilder(exactSizeIfKnown) |
|
244 |
: longBuilder(); |
|
245 |
} |
|
246 |
||
247 |
/** |
|
248 |
* Produces a variable size @{link Node.Builder.OfLong}. |
|
249 |
* |
|
250 |
* @return a {@code Node.Builder.OfLong} |
|
251 |
*/ |
|
252 |
static Node.Builder.OfLong longBuilder() { |
|
253 |
return new LongSpinedNodeBuilder(); |
|
254 |
} |
|
255 |
||
256 |
// Double nodes |
|
257 |
||
258 |
/** |
|
259 |
* Produces a {@link Node.OfDouble} describing a double[] array. |
|
260 |
* |
|
261 |
* <p>The node will hold a reference to the array and will not make a copy. |
|
262 |
* |
|
263 |
* @param array the array |
|
264 |
* @return a node holding an array |
|
265 |
*/ |
|
266 |
static Node.OfDouble node(final double[] array) { |
|
267 |
return new DoubleArrayNode(array); |
|
268 |
} |
|
269 |
||
270 |
/** |
|
271 |
* Produces a {@link Node.Builder.OfDouble}. |
|
272 |
* |
|
273 |
* @param exactSizeIfKnown -1 if a variable size builder is requested, |
|
274 |
* otherwise the exact capacity desired. A fixed capacity builder will |
|
275 |
* fail if the wrong number of elements are added to the builder. |
|
276 |
* @return a {@code Node.Builder.OfDouble} |
|
277 |
*/ |
|
278 |
static Node.Builder.OfDouble doubleBuilder(long exactSizeIfKnown) { |
|
279 |
return (exactSizeIfKnown >= 0 && exactSizeIfKnown < MAX_ARRAY_SIZE) |
|
280 |
? new DoubleFixedNodeBuilder(exactSizeIfKnown) |
|
281 |
: doubleBuilder(); |
|
282 |
} |
|
283 |
||
284 |
/** |
|
285 |
* Produces a variable size @{link Node.Builder.OfDouble}. |
|
286 |
* |
|
287 |
* @return a {@code Node.Builder.OfDouble} |
|
288 |
*/ |
|
289 |
static Node.Builder.OfDouble doubleBuilder() { |
|
290 |
return new DoubleSpinedNodeBuilder(); |
|
291 |
} |
|
292 |
||
293 |
// Parallel evaluation of pipelines to nodes |
|
294 |
||
295 |
/** |
|
296 |
* Collect, in parallel, elements output from a pipeline and describe those |
|
297 |
* elements with a {@link Node}. |
|
298 |
* |
|
299 |
* @implSpec |
|
300 |
* If the exact size of the output from the pipeline is known and the source |
|
301 |
* {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic, |
|
302 |
* then a flat {@link Node} will be returned whose content is an array, |
|
303 |
* since the size is known the array can be constructed in advance and |
|
304 |
* output elements can be placed into the array concurrently by leaf |
|
305 |
* tasks at the correct offsets. If the exact size is not known, output |
|
306 |
* elements are collected into a conc-node whose shape mirrors that |
|
307 |
* of the computation. This conc-node can then be flattened in |
|
308 |
* parallel to produce a flat {@code Node} if desired. |
|
309 |
* |
|
310 |
* @param helper the pipeline helper describing the pipeline |
|
311 |
* @param flattenTree whether a conc node should be flattened into a node |
|
312 |
* describing an array before returning |
|
313 |
* @param generator the array generator |
|
314 |
* @return a {@link Node} describing the output elements |
|
315 |
*/ |
|
316 |
public static <P_IN, P_OUT> Node<P_OUT> collect(PipelineHelper<P_OUT> helper, |
|
317 |
Spliterator<P_IN> spliterator, |
|
318 |
boolean flattenTree, |
|
319 |
IntFunction<P_OUT[]> generator) { |
|
320 |
long size = helper.exactOutputSizeIfKnown(spliterator); |
|
321 |
if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) { |
|
322 |
if (size >= MAX_ARRAY_SIZE) |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
323 |
throw new IllegalArgumentException(BAD_SIZE); |
17182 | 324 |
P_OUT[] array = generator.apply((int) size); |
325 |
new SizedCollectorTask.OfRef<>(spliterator, helper, array).invoke(); |
|
326 |
return node(array); |
|
327 |
} else { |
|
18527 | 328 |
Node<P_OUT> node = new CollectorTask.OfRef<>(helper, generator, spliterator).invoke(); |
17182 | 329 |
return flattenTree ? flatten(node, generator) : node; |
330 |
} |
|
331 |
} |
|
332 |
||
333 |
/** |
|
334 |
* Collect, in parallel, elements output from an int-valued pipeline and |
|
335 |
* describe those elements with a {@link Node.OfInt}. |
|
336 |
* |
|
337 |
* @implSpec |
|
338 |
* If the exact size of the output from the pipeline is known and the source |
|
339 |
* {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic, |
|
340 |
* then a flat {@link Node} will be returned whose content is an array, |
|
341 |
* since the size is known the array can be constructed in advance and |
|
342 |
* output elements can be placed into the array concurrently by leaf |
|
343 |
* tasks at the correct offsets. If the exact size is not known, output |
|
344 |
* elements are collected into a conc-node whose shape mirrors that |
|
345 |
* of the computation. This conc-node can then be flattened in |
|
346 |
* parallel to produce a flat {@code Node.OfInt} if desired. |
|
347 |
* |
|
348 |
* @param <P_IN> the type of elements from the source Spliterator |
|
349 |
* @param helper the pipeline helper describing the pipeline |
|
350 |
* @param flattenTree whether a conc node should be flattened into a node |
|
351 |
* describing an array before returning |
|
352 |
* @return a {@link Node.OfInt} describing the output elements |
|
353 |
*/ |
|
354 |
public static <P_IN> Node.OfInt collectInt(PipelineHelper<Integer> helper, |
|
355 |
Spliterator<P_IN> spliterator, |
|
356 |
boolean flattenTree) { |
|
357 |
long size = helper.exactOutputSizeIfKnown(spliterator); |
|
358 |
if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) { |
|
359 |
if (size >= MAX_ARRAY_SIZE) |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
360 |
throw new IllegalArgumentException(BAD_SIZE); |
17182 | 361 |
int[] array = new int[(int) size]; |
362 |
new SizedCollectorTask.OfInt<>(spliterator, helper, array).invoke(); |
|
363 |
return node(array); |
|
364 |
} |
|
365 |
else { |
|
18527 | 366 |
Node.OfInt node = new CollectorTask.OfInt<>(helper, spliterator).invoke(); |
17182 | 367 |
return flattenTree ? flattenInt(node) : node; |
368 |
} |
|
369 |
} |
|
370 |
||
371 |
/** |
|
372 |
* Collect, in parallel, elements output from a long-valued pipeline and |
|
373 |
* describe those elements with a {@link Node.OfLong}. |
|
374 |
* |
|
375 |
* @implSpec |
|
376 |
* If the exact size of the output from the pipeline is known and the source |
|
377 |
* {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic, |
|
378 |
* then a flat {@link Node} will be returned whose content is an array, |
|
379 |
* since the size is known the array can be constructed in advance and |
|
380 |
* output elements can be placed into the array concurrently by leaf |
|
381 |
* tasks at the correct offsets. If the exact size is not known, output |
|
382 |
* elements are collected into a conc-node whose shape mirrors that |
|
383 |
* of the computation. This conc-node can then be flattened in |
|
384 |
* parallel to produce a flat {@code Node.OfLong} if desired. |
|
385 |
* |
|
386 |
* @param <P_IN> the type of elements from the source Spliterator |
|
387 |
* @param helper the pipeline helper describing the pipeline |
|
388 |
* @param flattenTree whether a conc node should be flattened into a node |
|
389 |
* describing an array before returning |
|
390 |
* @return a {@link Node.OfLong} describing the output elements |
|
391 |
*/ |
|
392 |
public static <P_IN> Node.OfLong collectLong(PipelineHelper<Long> helper, |
|
393 |
Spliterator<P_IN> spliterator, |
|
394 |
boolean flattenTree) { |
|
395 |
long size = helper.exactOutputSizeIfKnown(spliterator); |
|
396 |
if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) { |
|
397 |
if (size >= MAX_ARRAY_SIZE) |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
398 |
throw new IllegalArgumentException(BAD_SIZE); |
17182 | 399 |
long[] array = new long[(int) size]; |
400 |
new SizedCollectorTask.OfLong<>(spliterator, helper, array).invoke(); |
|
401 |
return node(array); |
|
402 |
} |
|
403 |
else { |
|
18527 | 404 |
Node.OfLong node = new CollectorTask.OfLong<>(helper, spliterator).invoke(); |
17182 | 405 |
return flattenTree ? flattenLong(node) : node; |
406 |
} |
|
407 |
} |
|
408 |
||
409 |
/** |
|
410 |
* Collect, in parallel, elements output from n double-valued pipeline and |
|
411 |
* describe those elements with a {@link Node.OfDouble}. |
|
412 |
* |
|
413 |
* @implSpec |
|
414 |
* If the exact size of the output from the pipeline is known and the source |
|
415 |
* {@link Spliterator} has the {@link Spliterator#SUBSIZED} characteristic, |
|
416 |
* then a flat {@link Node} will be returned whose content is an array, |
|
417 |
* since the size is known the array can be constructed in advance and |
|
418 |
* output elements can be placed into the array concurrently by leaf |
|
419 |
* tasks at the correct offsets. If the exact size is not known, output |
|
420 |
* elements are collected into a conc-node whose shape mirrors that |
|
421 |
* of the computation. This conc-node can then be flattened in |
|
422 |
* parallel to produce a flat {@code Node.OfDouble} if desired. |
|
423 |
* |
|
424 |
* @param <P_IN> the type of elements from the source Spliterator |
|
425 |
* @param helper the pipeline helper describing the pipeline |
|
426 |
* @param flattenTree whether a conc node should be flattened into a node |
|
427 |
* describing an array before returning |
|
428 |
* @return a {@link Node.OfDouble} describing the output elements |
|
429 |
*/ |
|
430 |
public static <P_IN> Node.OfDouble collectDouble(PipelineHelper<Double> helper, |
|
431 |
Spliterator<P_IN> spliterator, |
|
432 |
boolean flattenTree) { |
|
433 |
long size = helper.exactOutputSizeIfKnown(spliterator); |
|
434 |
if (size >= 0 && spliterator.hasCharacteristics(Spliterator.SUBSIZED)) { |
|
435 |
if (size >= MAX_ARRAY_SIZE) |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
436 |
throw new IllegalArgumentException(BAD_SIZE); |
17182 | 437 |
double[] array = new double[(int) size]; |
438 |
new SizedCollectorTask.OfDouble<>(spliterator, helper, array).invoke(); |
|
439 |
return node(array); |
|
440 |
} |
|
441 |
else { |
|
18527 | 442 |
Node.OfDouble node = new CollectorTask.OfDouble<>(helper, spliterator).invoke(); |
17182 | 443 |
return flattenTree ? flattenDouble(node) : node; |
444 |
} |
|
445 |
} |
|
446 |
||
447 |
// Parallel flattening of nodes |
|
448 |
||
449 |
/** |
|
450 |
* Flatten, in parallel, a {@link Node}. A flattened node is one that has |
|
451 |
* no children. If the node is already flat, it is simply returned. |
|
452 |
* |
|
453 |
* @implSpec |
|
454 |
* If a new node is to be created, the generator is used to create an array |
|
455 |
* whose length is {@link Node#count()}. Then the node tree is traversed |
|
456 |
* and leaf node elements are placed in the array concurrently by leaf tasks |
|
457 |
* at the correct offsets. |
|
458 |
* |
|
459 |
* @param <T> type of elements contained by the node |
|
460 |
* @param node the node to flatten |
|
461 |
* @param generator the array factory used to create array instances |
|
462 |
* @return a flat {@code Node} |
|
463 |
*/ |
|
464 |
public static <T> Node<T> flatten(Node<T> node, IntFunction<T[]> generator) { |
|
465 |
if (node.getChildCount() > 0) { |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
466 |
long size = node.count(); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
467 |
if (size >= MAX_ARRAY_SIZE) |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
468 |
throw new IllegalArgumentException(BAD_SIZE); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
469 |
T[] array = generator.apply((int) size); |
17182 | 470 |
new ToArrayTask.OfRef<>(node, array, 0).invoke(); |
471 |
return node(array); |
|
472 |
} else { |
|
473 |
return node; |
|
474 |
} |
|
475 |
} |
|
476 |
||
477 |
/** |
|
478 |
* Flatten, in parallel, a {@link Node.OfInt}. A flattened node is one that |
|
479 |
* has no children. If the node is already flat, it is simply returned. |
|
480 |
* |
|
481 |
* @implSpec |
|
482 |
* If a new node is to be created, a new int[] array is created whose length |
|
483 |
* is {@link Node#count()}. Then the node tree is traversed and leaf node |
|
484 |
* elements are placed in the array concurrently by leaf tasks at the |
|
485 |
* correct offsets. |
|
486 |
* |
|
487 |
* @param node the node to flatten |
|
488 |
* @return a flat {@code Node.OfInt} |
|
489 |
*/ |
|
490 |
public static Node.OfInt flattenInt(Node.OfInt node) { |
|
491 |
if (node.getChildCount() > 0) { |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
492 |
long size = node.count(); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
493 |
if (size >= MAX_ARRAY_SIZE) |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
494 |
throw new IllegalArgumentException(BAD_SIZE); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
495 |
int[] array = new int[(int) size]; |
17182 | 496 |
new ToArrayTask.OfInt(node, array, 0).invoke(); |
497 |
return node(array); |
|
498 |
} else { |
|
499 |
return node; |
|
500 |
} |
|
501 |
} |
|
502 |
||
503 |
/** |
|
504 |
* Flatten, in parallel, a {@link Node.OfLong}. A flattened node is one that |
|
505 |
* has no children. If the node is already flat, it is simply returned. |
|
506 |
* |
|
507 |
* @implSpec |
|
508 |
* If a new node is to be created, a new long[] array is created whose length |
|
509 |
* is {@link Node#count()}. Then the node tree is traversed and leaf node |
|
510 |
* elements are placed in the array concurrently by leaf tasks at the |
|
511 |
* correct offsets. |
|
512 |
* |
|
513 |
* @param node the node to flatten |
|
514 |
* @return a flat {@code Node.OfLong} |
|
515 |
*/ |
|
516 |
public static Node.OfLong flattenLong(Node.OfLong node) { |
|
517 |
if (node.getChildCount() > 0) { |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
518 |
long size = node.count(); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
519 |
if (size >= MAX_ARRAY_SIZE) |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
520 |
throw new IllegalArgumentException(BAD_SIZE); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
521 |
long[] array = new long[(int) size]; |
17182 | 522 |
new ToArrayTask.OfLong(node, array, 0).invoke(); |
523 |
return node(array); |
|
524 |
} else { |
|
525 |
return node; |
|
526 |
} |
|
527 |
} |
|
528 |
||
529 |
/** |
|
530 |
* Flatten, in parallel, a {@link Node.OfDouble}. A flattened node is one that |
|
531 |
* has no children. If the node is already flat, it is simply returned. |
|
532 |
* |
|
533 |
* @implSpec |
|
534 |
* If a new node is to be created, a new double[] array is created whose length |
|
535 |
* is {@link Node#count()}. Then the node tree is traversed and leaf node |
|
536 |
* elements are placed in the array concurrently by leaf tasks at the |
|
537 |
* correct offsets. |
|
538 |
* |
|
539 |
* @param node the node to flatten |
|
540 |
* @return a flat {@code Node.OfDouble} |
|
541 |
*/ |
|
542 |
public static Node.OfDouble flattenDouble(Node.OfDouble node) { |
|
543 |
if (node.getChildCount() > 0) { |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
544 |
long size = node.count(); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
545 |
if (size >= MAX_ARRAY_SIZE) |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
546 |
throw new IllegalArgumentException(BAD_SIZE); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
547 |
double[] array = new double[(int) size]; |
17182 | 548 |
new ToArrayTask.OfDouble(node, array, 0).invoke(); |
549 |
return node(array); |
|
550 |
} else { |
|
551 |
return node; |
|
552 |
} |
|
553 |
} |
|
554 |
||
555 |
// Implementations |
|
556 |
||
557 |
private static abstract class EmptyNode<T, T_ARR, T_CONS> implements Node<T> { |
|
558 |
EmptyNode() { } |
|
559 |
||
560 |
@Override |
|
561 |
public T[] asArray(IntFunction<T[]> generator) { |
|
562 |
return generator.apply(0); |
|
563 |
} |
|
564 |
||
565 |
public void copyInto(T_ARR array, int offset) { } |
|
566 |
||
567 |
@Override |
|
568 |
public long count() { |
|
569 |
return 0; |
|
570 |
} |
|
571 |
||
572 |
public void forEach(T_CONS consumer) { } |
|
573 |
||
574 |
private static class OfRef<T> extends EmptyNode<T, T[], Consumer<? super T>> { |
|
575 |
private OfRef() { |
|
576 |
super(); |
|
577 |
} |
|
578 |
||
579 |
@Override |
|
580 |
public Spliterator<T> spliterator() { |
|
581 |
return Spliterators.emptySpliterator(); |
|
582 |
} |
|
583 |
} |
|
584 |
||
585 |
private static final class OfInt |
|
586 |
extends EmptyNode<Integer, int[], IntConsumer> |
|
587 |
implements Node.OfInt { |
|
588 |
||
589 |
OfInt() { } // Avoid creation of special accessor |
|
590 |
||
591 |
@Override |
|
592 |
public Spliterator.OfInt spliterator() { |
|
593 |
return Spliterators.emptyIntSpliterator(); |
|
594 |
} |
|
595 |
||
596 |
@Override |
|
18171 | 597 |
public int[] asPrimitiveArray() { |
17182 | 598 |
return EMPTY_INT_ARRAY; |
599 |
} |
|
600 |
} |
|
601 |
||
602 |
private static final class OfLong |
|
603 |
extends EmptyNode<Long, long[], LongConsumer> |
|
604 |
implements Node.OfLong { |
|
605 |
||
606 |
OfLong() { } // Avoid creation of special accessor |
|
607 |
||
608 |
@Override |
|
609 |
public Spliterator.OfLong spliterator() { |
|
610 |
return Spliterators.emptyLongSpliterator(); |
|
611 |
} |
|
612 |
||
613 |
@Override |
|
18171 | 614 |
public long[] asPrimitiveArray() { |
17182 | 615 |
return EMPTY_LONG_ARRAY; |
616 |
} |
|
617 |
} |
|
618 |
||
619 |
private static final class OfDouble |
|
620 |
extends EmptyNode<Double, double[], DoubleConsumer> |
|
621 |
implements Node.OfDouble { |
|
622 |
||
623 |
OfDouble() { } // Avoid creation of special accessor |
|
624 |
||
625 |
@Override |
|
626 |
public Spliterator.OfDouble spliterator() { |
|
627 |
return Spliterators.emptyDoubleSpliterator(); |
|
628 |
} |
|
629 |
||
630 |
@Override |
|
18171 | 631 |
public double[] asPrimitiveArray() { |
17182 | 632 |
return EMPTY_DOUBLE_ARRAY; |
633 |
} |
|
634 |
} |
|
635 |
} |
|
636 |
||
637 |
/** Node class for a reference array */ |
|
638 |
private static class ArrayNode<T> implements Node<T> { |
|
639 |
final T[] array; |
|
640 |
int curSize; |
|
641 |
||
642 |
@SuppressWarnings("unchecked") |
|
643 |
ArrayNode(long size, IntFunction<T[]> generator) { |
|
644 |
if (size >= MAX_ARRAY_SIZE) |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
645 |
throw new IllegalArgumentException(BAD_SIZE); |
17182 | 646 |
this.array = generator.apply((int) size); |
647 |
this.curSize = 0; |
|
648 |
} |
|
649 |
||
650 |
ArrayNode(T[] array) { |
|
651 |
this.array = array; |
|
652 |
this.curSize = array.length; |
|
653 |
} |
|
654 |
||
655 |
// Node |
|
656 |
||
657 |
@Override |
|
658 |
public Spliterator<T> spliterator() { |
|
659 |
return Arrays.spliterator(array, 0, curSize); |
|
660 |
} |
|
661 |
||
662 |
@Override |
|
663 |
public void copyInto(T[] dest, int destOffset) { |
|
664 |
System.arraycopy(array, 0, dest, destOffset, curSize); |
|
665 |
} |
|
666 |
||
667 |
@Override |
|
668 |
public T[] asArray(IntFunction<T[]> generator) { |
|
669 |
if (array.length == curSize) { |
|
670 |
return array; |
|
671 |
} else { |
|
672 |
throw new IllegalStateException(); |
|
673 |
} |
|
674 |
} |
|
675 |
||
676 |
@Override |
|
677 |
public long count() { |
|
678 |
return curSize; |
|
679 |
} |
|
680 |
||
681 |
@Override |
|
682 |
public void forEach(Consumer<? super T> consumer) { |
|
683 |
for (int i = 0; i < curSize; i++) { |
|
684 |
consumer.accept(array[i]); |
|
685 |
} |
|
686 |
} |
|
687 |
||
688 |
// |
|
689 |
||
690 |
@Override |
|
691 |
public String toString() { |
|
692 |
return String.format("ArrayNode[%d][%s]", |
|
693 |
array.length - curSize, Arrays.toString(array)); |
|
694 |
} |
|
695 |
} |
|
696 |
||
697 |
/** Node class for a Collection */ |
|
698 |
private static final class CollectionNode<T> implements Node<T> { |
|
699 |
private final Collection<T> c; |
|
700 |
||
701 |
CollectionNode(Collection<T> c) { |
|
702 |
this.c = c; |
|
703 |
} |
|
704 |
||
705 |
// Node |
|
706 |
||
707 |
@Override |
|
708 |
public Spliterator<T> spliterator() { |
|
709 |
return c.stream().spliterator(); |
|
710 |
} |
|
711 |
||
712 |
@Override |
|
713 |
public void copyInto(T[] array, int offset) { |
|
714 |
for (T t : c) |
|
715 |
array[offset++] = t; |
|
716 |
} |
|
717 |
||
718 |
@Override |
|
719 |
@SuppressWarnings("unchecked") |
|
720 |
public T[] asArray(IntFunction<T[]> generator) { |
|
721 |
return c.toArray(generator.apply(c.size())); |
|
722 |
} |
|
723 |
||
724 |
@Override |
|
725 |
public long count() { |
|
726 |
return c.size(); |
|
727 |
} |
|
728 |
||
729 |
@Override |
|
730 |
public void forEach(Consumer<? super T> consumer) { |
|
731 |
c.forEach(consumer); |
|
732 |
} |
|
733 |
||
734 |
// |
|
735 |
||
736 |
@Override |
|
737 |
public String toString() { |
|
738 |
return String.format("CollectionNode[%d][%s]", c.size(), c); |
|
739 |
} |
|
740 |
} |
|
741 |
||
742 |
/** |
|
743 |
* Node class for an internal node with two or more children |
|
744 |
*/ |
|
18527 | 745 |
private static abstract class AbstractConcNode<T, T_NODE extends Node<T>> implements Node<T> { |
746 |
protected final T_NODE left; |
|
747 |
protected final T_NODE right; |
|
17182 | 748 |
private final long size; |
749 |
||
18527 | 750 |
AbstractConcNode(T_NODE left, T_NODE right) { |
17182 | 751 |
this.left = left; |
752 |
this.right = right; |
|
753 |
// The Node count will be required when the Node spliterator is |
|
754 |
// obtained and it is cheaper to aggressively calculate bottom up |
|
755 |
// as the tree is built rather than later on from the top down |
|
756 |
// traversing the tree |
|
757 |
this.size = left.count() + right.count(); |
|
758 |
} |
|
759 |
||
760 |
@Override |
|
761 |
public int getChildCount() { |
|
762 |
return 2; |
|
763 |
} |
|
764 |
||
765 |
@Override |
|
18527 | 766 |
public T_NODE getChild(int i) { |
17182 | 767 |
if (i == 0) return left; |
768 |
if (i == 1) return right; |
|
769 |
throw new IndexOutOfBoundsException(); |
|
770 |
} |
|
771 |
||
772 |
@Override |
|
18527 | 773 |
public long count() { |
774 |
return size; |
|
775 |
} |
|
776 |
} |
|
777 |
||
778 |
static final class ConcNode<T> |
|
779 |
extends AbstractConcNode<T, Node<T>> |
|
780 |
implements Node<T> { |
|
781 |
||
782 |
ConcNode(Node<T> left, Node<T> right) { |
|
783 |
super(left, right); |
|
784 |
} |
|
785 |
||
786 |
@Override |
|
787 |
public Spliterator<T> spliterator() { |
|
788 |
return new Nodes.InternalNodeSpliterator.OfRef<>(this); |
|
789 |
} |
|
790 |
||
791 |
@Override |
|
17182 | 792 |
public void copyInto(T[] array, int offset) { |
793 |
Objects.requireNonNull(array); |
|
794 |
left.copyInto(array, offset); |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
795 |
// Cast to int is safe since it is the callers responsibility to |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
796 |
// ensure that there is sufficient room in the array |
17182 | 797 |
right.copyInto(array, offset + (int) left.count()); |
798 |
} |
|
799 |
||
800 |
@Override |
|
801 |
public T[] asArray(IntFunction<T[]> generator) { |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
802 |
long size = count(); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
803 |
if (size >= MAX_ARRAY_SIZE) |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
804 |
throw new IllegalArgumentException(BAD_SIZE); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
805 |
T[] array = generator.apply((int) size); |
17182 | 806 |
copyInto(array, 0); |
807 |
return array; |
|
808 |
} |
|
809 |
||
810 |
@Override |
|
18527 | 811 |
public void forEach(Consumer<? super T> consumer) { |
812 |
left.forEach(consumer); |
|
813 |
right.forEach(consumer); |
|
17182 | 814 |
} |
815 |
||
816 |
@Override |
|
18527 | 817 |
public Node<T> truncate(long from, long to, IntFunction<T[]> generator) { |
818 |
if (from == 0 && to == count()) |
|
819 |
return this; |
|
820 |
long leftCount = left.count(); |
|
821 |
if (from >= leftCount) |
|
822 |
return right.truncate(from - leftCount, to - leftCount, generator); |
|
823 |
else if (to <= leftCount) |
|
824 |
return left.truncate(from, to, generator); |
|
825 |
else { |
|
826 |
return Nodes.conc(getShape(), left.truncate(from, leftCount, generator), |
|
827 |
right.truncate(0, to - leftCount, generator)); |
|
828 |
} |
|
17182 | 829 |
} |
830 |
||
831 |
@Override |
|
832 |
public String toString() { |
|
833 |
if (count() < 32) { |
|
834 |
return String.format("ConcNode[%s.%s]", left, right); |
|
835 |
} else { |
|
836 |
return String.format("ConcNode[size=%d]", count()); |
|
837 |
} |
|
838 |
} |
|
18527 | 839 |
|
840 |
private abstract static class OfPrimitive<E, T_CONS, T_ARR, |
|
841 |
T_SPLITR extends Spliterator.OfPrimitive<E, T_CONS, T_SPLITR>, |
|
842 |
T_NODE extends Node.OfPrimitive<E, T_CONS, T_ARR, T_SPLITR, T_NODE>> |
|
843 |
extends AbstractConcNode<E, T_NODE> |
|
844 |
implements Node.OfPrimitive<E, T_CONS, T_ARR, T_SPLITR, T_NODE> { |
|
845 |
||
846 |
OfPrimitive(T_NODE left, T_NODE right) { |
|
847 |
super(left, right); |
|
848 |
} |
|
849 |
||
850 |
@Override |
|
851 |
public void forEach(T_CONS consumer) { |
|
852 |
left.forEach(consumer); |
|
853 |
right.forEach(consumer); |
|
854 |
} |
|
855 |
||
856 |
@Override |
|
857 |
public void copyInto(T_ARR array, int offset) { |
|
858 |
left.copyInto(array, offset); |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
859 |
// Cast to int is safe since it is the callers responsibility to |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
860 |
// ensure that there is sufficient room in the array |
18527 | 861 |
right.copyInto(array, offset + (int) left.count()); |
862 |
} |
|
863 |
||
864 |
@Override |
|
865 |
public T_ARR asPrimitiveArray() { |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
866 |
long size = count(); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
867 |
if (size >= MAX_ARRAY_SIZE) |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
868 |
throw new IllegalArgumentException(BAD_SIZE); |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
869 |
T_ARR array = newArray((int) size); |
18527 | 870 |
copyInto(array, 0); |
871 |
return array; |
|
872 |
} |
|
873 |
||
874 |
@Override |
|
875 |
public String toString() { |
|
876 |
if (count() < 32) |
|
877 |
return String.format("%s[%s.%s]", this.getClass().getName(), left, right); |
|
878 |
else |
|
879 |
return String.format("%s[size=%d]", this.getClass().getName(), count()); |
|
880 |
} |
|
881 |
} |
|
882 |
||
883 |
static final class OfInt |
|
884 |
extends ConcNode.OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt> |
|
885 |
implements Node.OfInt { |
|
886 |
||
887 |
OfInt(Node.OfInt left, Node.OfInt right) { |
|
888 |
super(left, right); |
|
889 |
} |
|
890 |
||
891 |
@Override |
|
892 |
public Spliterator.OfInt spliterator() { |
|
893 |
return new InternalNodeSpliterator.OfInt(this); |
|
894 |
} |
|
895 |
} |
|
896 |
||
897 |
static final class OfLong |
|
898 |
extends ConcNode.OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong> |
|
899 |
implements Node.OfLong { |
|
900 |
||
901 |
OfLong(Node.OfLong left, Node.OfLong right) { |
|
902 |
super(left, right); |
|
903 |
} |
|
904 |
||
905 |
@Override |
|
906 |
public Spliterator.OfLong spliterator() { |
|
907 |
return new InternalNodeSpliterator.OfLong(this); |
|
908 |
} |
|
909 |
} |
|
910 |
||
911 |
static final class OfDouble |
|
912 |
extends ConcNode.OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble> |
|
913 |
implements Node.OfDouble { |
|
914 |
||
915 |
OfDouble(Node.OfDouble left, Node.OfDouble right) { |
|
916 |
super(left, right); |
|
917 |
} |
|
918 |
||
919 |
@Override |
|
920 |
public Spliterator.OfDouble spliterator() { |
|
921 |
return new InternalNodeSpliterator.OfDouble(this); |
|
922 |
} |
|
923 |
} |
|
17182 | 924 |
} |
925 |
||
926 |
/** Abstract class for spliterator for all internal node classes */ |
|
927 |
private static abstract class InternalNodeSpliterator<T, |
|
928 |
S extends Spliterator<T>, |
|
18527 | 929 |
N extends Node<T>> |
17182 | 930 |
implements Spliterator<T> { |
931 |
// Node we are pointing to |
|
932 |
// null if full traversal has occurred |
|
933 |
N curNode; |
|
934 |
||
935 |
// next child of curNode to consume |
|
936 |
int curChildIndex; |
|
937 |
||
938 |
// The spliterator of the curNode if that node is last and has no children. |
|
939 |
// This spliterator will be delegated to for splitting and traversing. |
|
940 |
// null if curNode has children |
|
941 |
S lastNodeSpliterator; |
|
942 |
||
943 |
// spliterator used while traversing with tryAdvance |
|
944 |
// null if no partial traversal has occurred |
|
945 |
S tryAdvanceSpliterator; |
|
946 |
||
947 |
// node stack used when traversing to search and find leaf nodes |
|
948 |
// null if no partial traversal has occurred |
|
949 |
Deque<N> tryAdvanceStack; |
|
950 |
||
951 |
InternalNodeSpliterator(N curNode) { |
|
952 |
this.curNode = curNode; |
|
953 |
} |
|
954 |
||
955 |
/** |
|
956 |
* Initiate a stack containing, in left-to-right order, the child nodes |
|
957 |
* covered by this spliterator |
|
958 |
*/ |
|
959 |
protected final Deque<N> initStack() { |
|
960 |
// Bias size to the case where leaf nodes are close to this node |
|
961 |
// 8 is the minimum initial capacity for the ArrayDeque implementation |
|
962 |
Deque<N> stack = new ArrayDeque<>(8); |
|
963 |
for (int i = curNode.getChildCount() - 1; i >= curChildIndex; i--) |
|
964 |
stack.addFirst((N) curNode.getChild(i)); |
|
965 |
return stack; |
|
966 |
} |
|
967 |
||
968 |
/** |
|
969 |
* Depth first search, in left-to-right order, of the node tree, using |
|
970 |
* an explicit stack, to find the next non-empty leaf node. |
|
971 |
*/ |
|
972 |
protected final N findNextLeafNode(Deque<N> stack) { |
|
973 |
N n = null; |
|
974 |
while ((n = stack.pollFirst()) != null) { |
|
975 |
if (n.getChildCount() == 0) { |
|
976 |
if (n.count() > 0) |
|
977 |
return n; |
|
978 |
} else { |
|
979 |
for (int i = n.getChildCount() - 1; i >= 0; i--) |
|
980 |
stack.addFirst((N) n.getChild(i)); |
|
981 |
} |
|
982 |
} |
|
983 |
||
984 |
return null; |
|
985 |
} |
|
986 |
||
18527 | 987 |
protected final boolean initTryAdvance() { |
17182 | 988 |
if (curNode == null) |
989 |
return false; |
|
990 |
||
991 |
if (tryAdvanceSpliterator == null) { |
|
992 |
if (lastNodeSpliterator == null) { |
|
993 |
// Initiate the node stack |
|
994 |
tryAdvanceStack = initStack(); |
|
995 |
N leaf = findNextLeafNode(tryAdvanceStack); |
|
996 |
if (leaf != null) |
|
997 |
tryAdvanceSpliterator = (S) leaf.spliterator(); |
|
998 |
else { |
|
999 |
// A non-empty leaf node was not found |
|
1000 |
// No elements to traverse |
|
1001 |
curNode = null; |
|
1002 |
return false; |
|
1003 |
} |
|
1004 |
} |
|
1005 |
else |
|
1006 |
tryAdvanceSpliterator = lastNodeSpliterator; |
|
1007 |
} |
|
18527 | 1008 |
return true; |
17182 | 1009 |
} |
1010 |
||
1011 |
@Override |
|
1012 |
@SuppressWarnings("unchecked") |
|
18527 | 1013 |
public final S trySplit() { |
17182 | 1014 |
if (curNode == null || tryAdvanceSpliterator != null) |
1015 |
return null; // Cannot split if fully or partially traversed |
|
1016 |
else if (lastNodeSpliterator != null) |
|
1017 |
return (S) lastNodeSpliterator.trySplit(); |
|
1018 |
else if (curChildIndex < curNode.getChildCount() - 1) |
|
1019 |
return (S) curNode.getChild(curChildIndex++).spliterator(); |
|
1020 |
else { |
|
1021 |
curNode = (N) curNode.getChild(curChildIndex); |
|
1022 |
if (curNode.getChildCount() == 0) { |
|
1023 |
lastNodeSpliterator = (S) curNode.spliterator(); |
|
1024 |
return (S) lastNodeSpliterator.trySplit(); |
|
1025 |
} |
|
1026 |
else { |
|
1027 |
curChildIndex = 0; |
|
1028 |
return (S) curNode.getChild(curChildIndex++).spliterator(); |
|
1029 |
} |
|
1030 |
} |
|
1031 |
} |
|
1032 |
||
1033 |
@Override |
|
18527 | 1034 |
public final long estimateSize() { |
17182 | 1035 |
if (curNode == null) |
1036 |
return 0; |
|
1037 |
||
1038 |
// Will not reflect the effects of partial traversal. |
|
1039 |
// This is compliant with the specification |
|
1040 |
if (lastNodeSpliterator != null) |
|
1041 |
return lastNodeSpliterator.estimateSize(); |
|
1042 |
else { |
|
1043 |
long size = 0; |
|
1044 |
for (int i = curChildIndex; i < curNode.getChildCount(); i++) |
|
1045 |
size += curNode.getChild(i).count(); |
|
1046 |
return size; |
|
1047 |
} |
|
1048 |
} |
|
1049 |
||
1050 |
@Override |
|
18527 | 1051 |
public final int characteristics() { |
17182 | 1052 |
return Spliterator.SIZED; |
1053 |
} |
|
1054 |
||
1055 |
private static final class OfRef<T> |
|
18527 | 1056 |
extends InternalNodeSpliterator<T, Spliterator<T>, Node<T>> { |
17182 | 1057 |
|
1058 |
OfRef(Node<T> curNode) { |
|
1059 |
super(curNode); |
|
1060 |
} |
|
1061 |
||
1062 |
@Override |
|
1063 |
public boolean tryAdvance(Consumer<? super T> consumer) { |
|
18527 | 1064 |
if (!initTryAdvance()) |
1065 |
return false; |
|
17182 | 1066 |
|
18527 | 1067 |
boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer); |
1068 |
if (!hasNext) { |
|
1069 |
if (lastNodeSpliterator == null) { |
|
1070 |
// Advance to the spliterator of the next non-empty leaf node |
|
1071 |
Node<T> leaf = findNextLeafNode(tryAdvanceStack); |
|
1072 |
if (leaf != null) { |
|
1073 |
tryAdvanceSpliterator = leaf.spliterator(); |
|
1074 |
// Since the node is not-empty the spliterator can be advanced |
|
1075 |
return tryAdvanceSpliterator.tryAdvance(consumer); |
|
1076 |
} |
|
1077 |
} |
|
1078 |
// No more elements to traverse |
|
1079 |
curNode = null; |
|
1080 |
} |
|
1081 |
return hasNext; |
|
17182 | 1082 |
} |
1083 |
||
1084 |
@Override |
|
1085 |
public void forEachRemaining(Consumer<? super T> consumer) { |
|
1086 |
if (curNode == null) |
|
1087 |
return; |
|
1088 |
||
1089 |
if (tryAdvanceSpliterator == null) { |
|
1090 |
if (lastNodeSpliterator == null) { |
|
1091 |
Deque<Node<T>> stack = initStack(); |
|
1092 |
Node<T> leaf; |
|
1093 |
while ((leaf = findNextLeafNode(stack)) != null) { |
|
1094 |
leaf.forEach(consumer); |
|
1095 |
} |
|
1096 |
curNode = null; |
|
1097 |
} |
|
1098 |
else |
|
1099 |
lastNodeSpliterator.forEachRemaining(consumer); |
|
1100 |
} |
|
1101 |
else |
|
1102 |
while(tryAdvance(consumer)) { } |
|
1103 |
} |
|
1104 |
} |
|
1105 |
||
18527 | 1106 |
private static abstract class OfPrimitive<T, T_CONS, T_ARR, |
1107 |
T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>, |
|
1108 |
N extends Node.OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, N>> |
|
1109 |
extends InternalNodeSpliterator<T, T_SPLITR, N> |
|
1110 |
implements Spliterator.OfPrimitive<T, T_CONS, T_SPLITR> { |
|
17182 | 1111 |
|
18527 | 1112 |
OfPrimitive(N cur) { |
17182 | 1113 |
super(cur); |
1114 |
} |
|
1115 |
||
1116 |
@Override |
|
18527 | 1117 |
public boolean tryAdvance(T_CONS consumer) { |
1118 |
if (!initTryAdvance()) |
|
1119 |
return false; |
|
1120 |
||
1121 |
boolean hasNext = tryAdvanceSpliterator.tryAdvance(consumer); |
|
1122 |
if (!hasNext) { |
|
1123 |
if (lastNodeSpliterator == null) { |
|
1124 |
// Advance to the spliterator of the next non-empty leaf node |
|
1125 |
N leaf = findNextLeafNode(tryAdvanceStack); |
|
1126 |
if (leaf != null) { |
|
1127 |
tryAdvanceSpliterator = leaf.spliterator(); |
|
1128 |
// Since the node is not-empty the spliterator can be advanced |
|
1129 |
return tryAdvanceSpliterator.tryAdvance(consumer); |
|
1130 |
} |
|
1131 |
} |
|
1132 |
// No more elements to traverse |
|
1133 |
curNode = null; |
|
1134 |
} |
|
1135 |
return hasNext; |
|
17182 | 1136 |
} |
1137 |
||
1138 |
@Override |
|
18527 | 1139 |
public void forEachRemaining(T_CONS consumer) { |
17182 | 1140 |
if (curNode == null) |
1141 |
return; |
|
1142 |
||
1143 |
if (tryAdvanceSpliterator == null) { |
|
1144 |
if (lastNodeSpliterator == null) { |
|
18527 | 1145 |
Deque<N> stack = initStack(); |
1146 |
N leaf; |
|
17182 | 1147 |
while ((leaf = findNextLeafNode(stack)) != null) { |
1148 |
leaf.forEach(consumer); |
|
1149 |
} |
|
1150 |
curNode = null; |
|
1151 |
} |
|
1152 |
else |
|
1153 |
lastNodeSpliterator.forEachRemaining(consumer); |
|
1154 |
} |
|
1155 |
else |
|
1156 |
while(tryAdvance(consumer)) { } |
|
1157 |
} |
|
1158 |
} |
|
1159 |
||
18527 | 1160 |
private static final class OfInt |
1161 |
extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt> |
|
1162 |
implements Spliterator.OfInt { |
|
1163 |
||
1164 |
OfInt(Node.OfInt cur) { |
|
1165 |
super(cur); |
|
1166 |
} |
|
1167 |
} |
|
1168 |
||
17182 | 1169 |
private static final class OfLong |
18527 | 1170 |
extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong> |
17182 | 1171 |
implements Spliterator.OfLong { |
1172 |
||
1173 |
OfLong(Node.OfLong cur) { |
|
1174 |
super(cur); |
|
1175 |
} |
|
1176 |
} |
|
1177 |
||
1178 |
private static final class OfDouble |
|
18527 | 1179 |
extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble> |
17182 | 1180 |
implements Spliterator.OfDouble { |
1181 |
||
1182 |
OfDouble(Node.OfDouble cur) { |
|
1183 |
super(cur); |
|
1184 |
} |
|
1185 |
} |
|
1186 |
} |
|
1187 |
||
1188 |
/** |
|
1189 |
* Fixed-sized builder class for reference nodes |
|
1190 |
*/ |
|
1191 |
private static final class FixedNodeBuilder<T> |
|
1192 |
extends ArrayNode<T> |
|
1193 |
implements Node.Builder<T> { |
|
1194 |
||
1195 |
FixedNodeBuilder(long size, IntFunction<T[]> generator) { |
|
1196 |
super(size, generator); |
|
1197 |
assert size < MAX_ARRAY_SIZE; |
|
1198 |
} |
|
1199 |
||
1200 |
@Override |
|
1201 |
public Node<T> build() { |
|
1202 |
if (curSize < array.length) |
|
1203 |
throw new IllegalStateException(String.format("Current size %d is less than fixed size %d", |
|
1204 |
curSize, array.length)); |
|
1205 |
return this; |
|
1206 |
} |
|
1207 |
||
1208 |
@Override |
|
1209 |
public void begin(long size) { |
|
1210 |
if (size != array.length) |
|
1211 |
throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d", |
|
1212 |
size, array.length)); |
|
1213 |
curSize = 0; |
|
1214 |
} |
|
1215 |
||
1216 |
@Override |
|
1217 |
public void accept(T t) { |
|
1218 |
if (curSize < array.length) { |
|
1219 |
array[curSize++] = t; |
|
1220 |
} else { |
|
1221 |
throw new IllegalStateException(String.format("Accept exceeded fixed size of %d", |
|
1222 |
array.length)); |
|
1223 |
} |
|
1224 |
} |
|
1225 |
||
1226 |
@Override |
|
1227 |
public void end() { |
|
1228 |
if (curSize < array.length) |
|
1229 |
throw new IllegalStateException(String.format("End size %d is less than fixed size %d", |
|
1230 |
curSize, array.length)); |
|
1231 |
} |
|
1232 |
||
1233 |
@Override |
|
1234 |
public String toString() { |
|
1235 |
return String.format("FixedNodeBuilder[%d][%s]", |
|
1236 |
array.length - curSize, Arrays.toString(array)); |
|
1237 |
} |
|
1238 |
} |
|
1239 |
||
1240 |
/** |
|
1241 |
* Variable-sized builder class for reference nodes |
|
1242 |
*/ |
|
1243 |
private static final class SpinedNodeBuilder<T> |
|
1244 |
extends SpinedBuffer<T> |
|
1245 |
implements Node<T>, Node.Builder<T> { |
|
1246 |
private boolean building = false; |
|
1247 |
||
1248 |
SpinedNodeBuilder() {} // Avoid creation of special accessor |
|
1249 |
||
1250 |
@Override |
|
1251 |
public Spliterator<T> spliterator() { |
|
1252 |
assert !building : "during building"; |
|
1253 |
return super.spliterator(); |
|
1254 |
} |
|
1255 |
||
1256 |
@Override |
|
1257 |
public void forEach(Consumer<? super T> consumer) { |
|
1258 |
assert !building : "during building"; |
|
1259 |
super.forEach(consumer); |
|
1260 |
} |
|
1261 |
||
1262 |
// |
|
1263 |
@Override |
|
1264 |
public void begin(long size) { |
|
1265 |
assert !building : "was already building"; |
|
1266 |
building = true; |
|
1267 |
clear(); |
|
1268 |
ensureCapacity(size); |
|
1269 |
} |
|
1270 |
||
1271 |
@Override |
|
1272 |
public void accept(T t) { |
|
1273 |
assert building : "not building"; |
|
1274 |
super.accept(t); |
|
1275 |
} |
|
1276 |
||
1277 |
@Override |
|
1278 |
public void end() { |
|
1279 |
assert building : "was not building"; |
|
1280 |
building = false; |
|
1281 |
// @@@ check begin(size) and size |
|
1282 |
} |
|
1283 |
||
1284 |
@Override |
|
1285 |
public void copyInto(T[] array, int offset) { |
|
1286 |
assert !building : "during building"; |
|
1287 |
super.copyInto(array, offset); |
|
1288 |
} |
|
1289 |
||
1290 |
@Override |
|
1291 |
public T[] asArray(IntFunction<T[]> arrayFactory) { |
|
1292 |
assert !building : "during building"; |
|
1293 |
return super.asArray(arrayFactory); |
|
1294 |
} |
|
1295 |
||
1296 |
@Override |
|
1297 |
public Node<T> build() { |
|
1298 |
assert !building : "during building"; |
|
1299 |
return this; |
|
1300 |
} |
|
1301 |
} |
|
1302 |
||
1303 |
// |
|
1304 |
||
1305 |
private static final int[] EMPTY_INT_ARRAY = new int[0]; |
|
1306 |
private static final long[] EMPTY_LONG_ARRAY = new long[0]; |
|
1307 |
private static final double[] EMPTY_DOUBLE_ARRAY = new double[0]; |
|
1308 |
||
1309 |
private static class IntArrayNode implements Node.OfInt { |
|
1310 |
final int[] array; |
|
1311 |
int curSize; |
|
1312 |
||
1313 |
IntArrayNode(long size) { |
|
1314 |
if (size >= MAX_ARRAY_SIZE) |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
1315 |
throw new IllegalArgumentException(BAD_SIZE); |
17182 | 1316 |
this.array = new int[(int) size]; |
1317 |
this.curSize = 0; |
|
1318 |
} |
|
1319 |
||
1320 |
IntArrayNode(int[] array) { |
|
1321 |
this.array = array; |
|
1322 |
this.curSize = array.length; |
|
1323 |
} |
|
1324 |
||
1325 |
// Node |
|
1326 |
||
1327 |
@Override |
|
1328 |
public Spliterator.OfInt spliterator() { |
|
1329 |
return Arrays.spliterator(array, 0, curSize); |
|
1330 |
} |
|
1331 |
||
1332 |
@Override |
|
18171 | 1333 |
public int[] asPrimitiveArray() { |
17182 | 1334 |
if (array.length == curSize) { |
1335 |
return array; |
|
1336 |
} else { |
|
1337 |
return Arrays.copyOf(array, curSize); |
|
1338 |
} |
|
1339 |
} |
|
1340 |
||
1341 |
@Override |
|
1342 |
public void copyInto(int[] dest, int destOffset) { |
|
1343 |
System.arraycopy(array, 0, dest, destOffset, curSize); |
|
1344 |
} |
|
1345 |
||
1346 |
@Override |
|
1347 |
public long count() { |
|
1348 |
return curSize; |
|
1349 |
} |
|
1350 |
||
1351 |
@Override |
|
1352 |
public void forEach(IntConsumer consumer) { |
|
1353 |
for (int i = 0; i < curSize; i++) { |
|
1354 |
consumer.accept(array[i]); |
|
1355 |
} |
|
1356 |
} |
|
1357 |
||
1358 |
@Override |
|
1359 |
public String toString() { |
|
1360 |
return String.format("IntArrayNode[%d][%s]", |
|
1361 |
array.length - curSize, Arrays.toString(array)); |
|
1362 |
} |
|
1363 |
} |
|
1364 |
||
1365 |
private static class LongArrayNode implements Node.OfLong { |
|
1366 |
final long[] array; |
|
1367 |
int curSize; |
|
1368 |
||
1369 |
LongArrayNode(long size) { |
|
1370 |
if (size >= MAX_ARRAY_SIZE) |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
1371 |
throw new IllegalArgumentException(BAD_SIZE); |
17182 | 1372 |
this.array = new long[(int) size]; |
1373 |
this.curSize = 0; |
|
1374 |
} |
|
1375 |
||
1376 |
LongArrayNode(long[] array) { |
|
1377 |
this.array = array; |
|
1378 |
this.curSize = array.length; |
|
1379 |
} |
|
1380 |
||
1381 |
@Override |
|
1382 |
public Spliterator.OfLong spliterator() { |
|
1383 |
return Arrays.spliterator(array, 0, curSize); |
|
1384 |
} |
|
1385 |
||
1386 |
@Override |
|
18171 | 1387 |
public long[] asPrimitiveArray() { |
17182 | 1388 |
if (array.length == curSize) { |
1389 |
return array; |
|
1390 |
} else { |
|
1391 |
return Arrays.copyOf(array, curSize); |
|
1392 |
} |
|
1393 |
} |
|
1394 |
||
1395 |
@Override |
|
1396 |
public void copyInto(long[] dest, int destOffset) { |
|
1397 |
System.arraycopy(array, 0, dest, destOffset, curSize); |
|
1398 |
} |
|
1399 |
||
1400 |
@Override |
|
1401 |
public long count() { |
|
1402 |
return curSize; |
|
1403 |
} |
|
1404 |
||
1405 |
@Override |
|
1406 |
public void forEach(LongConsumer consumer) { |
|
1407 |
for (int i = 0; i < curSize; i++) { |
|
1408 |
consumer.accept(array[i]); |
|
1409 |
} |
|
1410 |
} |
|
1411 |
||
1412 |
@Override |
|
1413 |
public String toString() { |
|
1414 |
return String.format("LongArrayNode[%d][%s]", |
|
1415 |
array.length - curSize, Arrays.toString(array)); |
|
1416 |
} |
|
1417 |
} |
|
1418 |
||
1419 |
private static class DoubleArrayNode implements Node.OfDouble { |
|
1420 |
final double[] array; |
|
1421 |
int curSize; |
|
1422 |
||
1423 |
DoubleArrayNode(long size) { |
|
1424 |
if (size >= MAX_ARRAY_SIZE) |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
1425 |
throw new IllegalArgumentException(BAD_SIZE); |
17182 | 1426 |
this.array = new double[(int) size]; |
1427 |
this.curSize = 0; |
|
1428 |
} |
|
1429 |
||
1430 |
DoubleArrayNode(double[] array) { |
|
1431 |
this.array = array; |
|
1432 |
this.curSize = array.length; |
|
1433 |
} |
|
1434 |
||
1435 |
@Override |
|
1436 |
public Spliterator.OfDouble spliterator() { |
|
1437 |
return Arrays.spliterator(array, 0, curSize); |
|
1438 |
} |
|
1439 |
||
1440 |
@Override |
|
18171 | 1441 |
public double[] asPrimitiveArray() { |
17182 | 1442 |
if (array.length == curSize) { |
1443 |
return array; |
|
1444 |
} else { |
|
1445 |
return Arrays.copyOf(array, curSize); |
|
1446 |
} |
|
1447 |
} |
|
1448 |
||
1449 |
@Override |
|
1450 |
public void copyInto(double[] dest, int destOffset) { |
|
1451 |
System.arraycopy(array, 0, dest, destOffset, curSize); |
|
1452 |
} |
|
1453 |
||
1454 |
@Override |
|
1455 |
public long count() { |
|
1456 |
return curSize; |
|
1457 |
} |
|
1458 |
||
1459 |
@Override |
|
1460 |
public void forEach(DoubleConsumer consumer) { |
|
1461 |
for (int i = 0; i < curSize; i++) { |
|
1462 |
consumer.accept(array[i]); |
|
1463 |
} |
|
1464 |
} |
|
1465 |
||
1466 |
@Override |
|
1467 |
public String toString() { |
|
1468 |
return String.format("DoubleArrayNode[%d][%s]", |
|
1469 |
array.length - curSize, Arrays.toString(array)); |
|
1470 |
} |
|
1471 |
} |
|
1472 |
||
1473 |
private static final class IntFixedNodeBuilder |
|
1474 |
extends IntArrayNode |
|
1475 |
implements Node.Builder.OfInt { |
|
1476 |
||
1477 |
IntFixedNodeBuilder(long size) { |
|
1478 |
super(size); |
|
1479 |
assert size < MAX_ARRAY_SIZE; |
|
1480 |
} |
|
1481 |
||
1482 |
@Override |
|
1483 |
public Node.OfInt build() { |
|
1484 |
if (curSize < array.length) { |
|
1485 |
throw new IllegalStateException(String.format("Current size %d is less than fixed size %d", |
|
1486 |
curSize, array.length)); |
|
1487 |
} |
|
1488 |
||
1489 |
return this; |
|
1490 |
} |
|
1491 |
||
1492 |
@Override |
|
1493 |
public void begin(long size) { |
|
1494 |
if (size != array.length) { |
|
1495 |
throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d", |
|
1496 |
size, array.length)); |
|
1497 |
} |
|
1498 |
||
1499 |
curSize = 0; |
|
1500 |
} |
|
1501 |
||
1502 |
@Override |
|
1503 |
public void accept(int i) { |
|
1504 |
if (curSize < array.length) { |
|
1505 |
array[curSize++] = i; |
|
1506 |
} else { |
|
1507 |
throw new IllegalStateException(String.format("Accept exceeded fixed size of %d", |
|
1508 |
array.length)); |
|
1509 |
} |
|
1510 |
} |
|
1511 |
||
1512 |
@Override |
|
1513 |
public void end() { |
|
1514 |
if (curSize < array.length) { |
|
1515 |
throw new IllegalStateException(String.format("End size %d is less than fixed size %d", |
|
1516 |
curSize, array.length)); |
|
1517 |
} |
|
1518 |
} |
|
1519 |
||
1520 |
@Override |
|
1521 |
public String toString() { |
|
1522 |
return String.format("IntFixedNodeBuilder[%d][%s]", |
|
1523 |
array.length - curSize, Arrays.toString(array)); |
|
1524 |
} |
|
1525 |
} |
|
1526 |
||
1527 |
private static final class LongFixedNodeBuilder |
|
1528 |
extends LongArrayNode |
|
1529 |
implements Node.Builder.OfLong { |
|
1530 |
||
1531 |
LongFixedNodeBuilder(long size) { |
|
1532 |
super(size); |
|
1533 |
assert size < MAX_ARRAY_SIZE; |
|
1534 |
} |
|
1535 |
||
1536 |
@Override |
|
1537 |
public Node.OfLong build() { |
|
1538 |
if (curSize < array.length) { |
|
1539 |
throw new IllegalStateException(String.format("Current size %d is less than fixed size %d", |
|
1540 |
curSize, array.length)); |
|
1541 |
} |
|
1542 |
||
1543 |
return this; |
|
1544 |
} |
|
1545 |
||
1546 |
@Override |
|
1547 |
public void begin(long size) { |
|
1548 |
if (size != array.length) { |
|
1549 |
throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d", |
|
1550 |
size, array.length)); |
|
1551 |
} |
|
1552 |
||
1553 |
curSize = 0; |
|
1554 |
} |
|
1555 |
||
1556 |
@Override |
|
1557 |
public void accept(long i) { |
|
1558 |
if (curSize < array.length) { |
|
1559 |
array[curSize++] = i; |
|
1560 |
} else { |
|
1561 |
throw new IllegalStateException(String.format("Accept exceeded fixed size of %d", |
|
1562 |
array.length)); |
|
1563 |
} |
|
1564 |
} |
|
1565 |
||
1566 |
@Override |
|
1567 |
public void end() { |
|
1568 |
if (curSize < array.length) { |
|
1569 |
throw new IllegalStateException(String.format("End size %d is less than fixed size %d", |
|
1570 |
curSize, array.length)); |
|
1571 |
} |
|
1572 |
} |
|
1573 |
||
1574 |
@Override |
|
1575 |
public String toString() { |
|
1576 |
return String.format("LongFixedNodeBuilder[%d][%s]", |
|
1577 |
array.length - curSize, Arrays.toString(array)); |
|
1578 |
} |
|
1579 |
} |
|
1580 |
||
1581 |
private static final class DoubleFixedNodeBuilder |
|
1582 |
extends DoubleArrayNode |
|
1583 |
implements Node.Builder.OfDouble { |
|
1584 |
||
1585 |
DoubleFixedNodeBuilder(long size) { |
|
1586 |
super(size); |
|
1587 |
assert size < MAX_ARRAY_SIZE; |
|
1588 |
} |
|
1589 |
||
1590 |
@Override |
|
1591 |
public Node.OfDouble build() { |
|
1592 |
if (curSize < array.length) { |
|
1593 |
throw new IllegalStateException(String.format("Current size %d is less than fixed size %d", |
|
1594 |
curSize, array.length)); |
|
1595 |
} |
|
1596 |
||
1597 |
return this; |
|
1598 |
} |
|
1599 |
||
1600 |
@Override |
|
1601 |
public void begin(long size) { |
|
1602 |
if (size != array.length) { |
|
1603 |
throw new IllegalStateException(String.format("Begin size %d is not equal to fixed size %d", |
|
1604 |
size, array.length)); |
|
1605 |
} |
|
1606 |
||
1607 |
curSize = 0; |
|
1608 |
} |
|
1609 |
||
1610 |
@Override |
|
1611 |
public void accept(double i) { |
|
1612 |
if (curSize < array.length) { |
|
1613 |
array[curSize++] = i; |
|
1614 |
} else { |
|
1615 |
throw new IllegalStateException(String.format("Accept exceeded fixed size of %d", |
|
1616 |
array.length)); |
|
1617 |
} |
|
1618 |
} |
|
1619 |
||
1620 |
@Override |
|
1621 |
public void end() { |
|
1622 |
if (curSize < array.length) { |
|
1623 |
throw new IllegalStateException(String.format("End size %d is less than fixed size %d", |
|
1624 |
curSize, array.length)); |
|
1625 |
} |
|
1626 |
} |
|
1627 |
||
1628 |
@Override |
|
1629 |
public String toString() { |
|
1630 |
return String.format("DoubleFixedNodeBuilder[%d][%s]", |
|
1631 |
array.length - curSize, Arrays.toString(array)); |
|
1632 |
} |
|
1633 |
} |
|
1634 |
||
1635 |
private static final class IntSpinedNodeBuilder |
|
1636 |
extends SpinedBuffer.OfInt |
|
1637 |
implements Node.OfInt, Node.Builder.OfInt { |
|
1638 |
private boolean building = false; |
|
1639 |
||
1640 |
IntSpinedNodeBuilder() {} // Avoid creation of special accessor |
|
1641 |
||
1642 |
@Override |
|
1643 |
public Spliterator.OfInt spliterator() { |
|
1644 |
assert !building : "during building"; |
|
1645 |
return super.spliterator(); |
|
1646 |
} |
|
1647 |
||
1648 |
@Override |
|
1649 |
public void forEach(IntConsumer consumer) { |
|
1650 |
assert !building : "during building"; |
|
1651 |
super.forEach(consumer); |
|
1652 |
} |
|
1653 |
||
1654 |
// |
|
1655 |
@Override |
|
1656 |
public void begin(long size) { |
|
1657 |
assert !building : "was already building"; |
|
1658 |
building = true; |
|
1659 |
clear(); |
|
1660 |
ensureCapacity(size); |
|
1661 |
} |
|
1662 |
||
1663 |
@Override |
|
1664 |
public void accept(int i) { |
|
1665 |
assert building : "not building"; |
|
1666 |
super.accept(i); |
|
1667 |
} |
|
1668 |
||
1669 |
@Override |
|
1670 |
public void end() { |
|
1671 |
assert building : "was not building"; |
|
1672 |
building = false; |
|
1673 |
// @@@ check begin(size) and size |
|
1674 |
} |
|
1675 |
||
1676 |
@Override |
|
1677 |
public void copyInto(int[] array, int offset) throws IndexOutOfBoundsException { |
|
1678 |
assert !building : "during building"; |
|
1679 |
super.copyInto(array, offset); |
|
1680 |
} |
|
1681 |
||
1682 |
@Override |
|
18171 | 1683 |
public int[] asPrimitiveArray() { |
17182 | 1684 |
assert !building : "during building"; |
18171 | 1685 |
return super.asPrimitiveArray(); |
17182 | 1686 |
} |
1687 |
||
1688 |
@Override |
|
1689 |
public Node.OfInt build() { |
|
1690 |
assert !building : "during building"; |
|
1691 |
return this; |
|
1692 |
} |
|
1693 |
} |
|
1694 |
||
1695 |
private static final class LongSpinedNodeBuilder |
|
1696 |
extends SpinedBuffer.OfLong |
|
1697 |
implements Node.OfLong, Node.Builder.OfLong { |
|
1698 |
private boolean building = false; |
|
1699 |
||
1700 |
LongSpinedNodeBuilder() {} // Avoid creation of special accessor |
|
1701 |
||
1702 |
@Override |
|
1703 |
public Spliterator.OfLong spliterator() { |
|
1704 |
assert !building : "during building"; |
|
1705 |
return super.spliterator(); |
|
1706 |
} |
|
1707 |
||
1708 |
@Override |
|
1709 |
public void forEach(LongConsumer consumer) { |
|
1710 |
assert !building : "during building"; |
|
1711 |
super.forEach(consumer); |
|
1712 |
} |
|
1713 |
||
1714 |
// |
|
1715 |
@Override |
|
1716 |
public void begin(long size) { |
|
1717 |
assert !building : "was already building"; |
|
1718 |
building = true; |
|
1719 |
clear(); |
|
1720 |
ensureCapacity(size); |
|
1721 |
} |
|
1722 |
||
1723 |
@Override |
|
1724 |
public void accept(long i) { |
|
1725 |
assert building : "not building"; |
|
1726 |
super.accept(i); |
|
1727 |
} |
|
1728 |
||
1729 |
@Override |
|
1730 |
public void end() { |
|
1731 |
assert building : "was not building"; |
|
1732 |
building = false; |
|
1733 |
// @@@ check begin(size) and size |
|
1734 |
} |
|
1735 |
||
1736 |
@Override |
|
1737 |
public void copyInto(long[] array, int offset) { |
|
1738 |
assert !building : "during building"; |
|
1739 |
super.copyInto(array, offset); |
|
1740 |
} |
|
1741 |
||
1742 |
@Override |
|
18171 | 1743 |
public long[] asPrimitiveArray() { |
17182 | 1744 |
assert !building : "during building"; |
18171 | 1745 |
return super.asPrimitiveArray(); |
17182 | 1746 |
} |
1747 |
||
1748 |
@Override |
|
1749 |
public Node.OfLong build() { |
|
1750 |
assert !building : "during building"; |
|
1751 |
return this; |
|
1752 |
} |
|
1753 |
} |
|
1754 |
||
1755 |
private static final class DoubleSpinedNodeBuilder |
|
1756 |
extends SpinedBuffer.OfDouble |
|
1757 |
implements Node.OfDouble, Node.Builder.OfDouble { |
|
1758 |
private boolean building = false; |
|
1759 |
||
1760 |
DoubleSpinedNodeBuilder() {} // Avoid creation of special accessor |
|
1761 |
||
1762 |
@Override |
|
1763 |
public Spliterator.OfDouble spliterator() { |
|
1764 |
assert !building : "during building"; |
|
1765 |
return super.spliterator(); |
|
1766 |
} |
|
1767 |
||
1768 |
@Override |
|
1769 |
public void forEach(DoubleConsumer consumer) { |
|
1770 |
assert !building : "during building"; |
|
1771 |
super.forEach(consumer); |
|
1772 |
} |
|
1773 |
||
1774 |
// |
|
1775 |
@Override |
|
1776 |
public void begin(long size) { |
|
1777 |
assert !building : "was already building"; |
|
1778 |
building = true; |
|
1779 |
clear(); |
|
1780 |
ensureCapacity(size); |
|
1781 |
} |
|
1782 |
||
1783 |
@Override |
|
1784 |
public void accept(double i) { |
|
1785 |
assert building : "not building"; |
|
1786 |
super.accept(i); |
|
1787 |
} |
|
1788 |
||
1789 |
@Override |
|
1790 |
public void end() { |
|
1791 |
assert building : "was not building"; |
|
1792 |
building = false; |
|
1793 |
// @@@ check begin(size) and size |
|
1794 |
} |
|
1795 |
||
1796 |
@Override |
|
1797 |
public void copyInto(double[] array, int offset) { |
|
1798 |
assert !building : "during building"; |
|
1799 |
super.copyInto(array, offset); |
|
1800 |
} |
|
1801 |
||
1802 |
@Override |
|
18171 | 1803 |
public double[] asPrimitiveArray() { |
17182 | 1804 |
assert !building : "during building"; |
18171 | 1805 |
return super.asPrimitiveArray(); |
17182 | 1806 |
} |
1807 |
||
1808 |
@Override |
|
1809 |
public Node.OfDouble build() { |
|
1810 |
assert !building : "during building"; |
|
1811 |
return this; |
|
1812 |
} |
|
1813 |
} |
|
1814 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
1815 |
/* |
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
1816 |
* This and subclasses are not intended to be serializable |
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
1817 |
*/ |
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
1818 |
@SuppressWarnings("serial") |
17182 | 1819 |
private static abstract class SizedCollectorTask<P_IN, P_OUT, T_SINK extends Sink<P_OUT>, |
1820 |
K extends SizedCollectorTask<P_IN, P_OUT, T_SINK, K>> |
|
1821 |
extends CountedCompleter<Void> |
|
1822 |
implements Sink<P_OUT> { |
|
1823 |
protected final Spliterator<P_IN> spliterator; |
|
1824 |
protected final PipelineHelper<P_OUT> helper; |
|
1825 |
protected final long targetSize; |
|
1826 |
protected long offset; |
|
1827 |
protected long length; |
|
1828 |
// For Sink implementation |
|
1829 |
protected int index, fence; |
|
1830 |
||
1831 |
SizedCollectorTask(Spliterator<P_IN> spliterator, |
|
1832 |
PipelineHelper<P_OUT> helper, |
|
1833 |
int arrayLength) { |
|
1834 |
assert spliterator.hasCharacteristics(Spliterator.SUBSIZED); |
|
1835 |
this.spliterator = spliterator; |
|
1836 |
this.helper = helper; |
|
1837 |
this.targetSize = AbstractTask.suggestTargetSize(spliterator.estimateSize()); |
|
1838 |
this.offset = 0; |
|
1839 |
this.length = arrayLength; |
|
1840 |
} |
|
1841 |
||
1842 |
SizedCollectorTask(K parent, Spliterator<P_IN> spliterator, |
|
1843 |
long offset, long length, int arrayLength) { |
|
1844 |
super(parent); |
|
1845 |
assert spliterator.hasCharacteristics(Spliterator.SUBSIZED); |
|
1846 |
this.spliterator = spliterator; |
|
1847 |
this.helper = parent.helper; |
|
1848 |
this.targetSize = parent.targetSize; |
|
1849 |
this.offset = offset; |
|
1850 |
this.length = length; |
|
1851 |
||
1852 |
if (offset < 0 || length < 0 || (offset + length - 1 >= arrayLength)) { |
|
1853 |
throw new IllegalArgumentException( |
|
1854 |
String.format("offset and length interval [%d, %d + %d) is not within array size interval [0, %d)", |
|
1855 |
offset, offset, length, arrayLength)); |
|
1856 |
} |
|
1857 |
} |
|
1858 |
||
1859 |
@Override |
|
1860 |
public void compute() { |
|
1861 |
SizedCollectorTask<P_IN, P_OUT, T_SINK, K> task = this; |
|
18795
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1862 |
Spliterator<P_IN> rightSplit = spliterator, leftSplit; |
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1863 |
while (rightSplit.estimateSize() > task.targetSize && |
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1864 |
(leftSplit = rightSplit.trySplit()) != null) { |
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1865 |
task.setPendingCount(1); |
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1866 |
long leftSplitSize = leftSplit.estimateSize(); |
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1867 |
task.makeChild(leftSplit, task.offset, leftSplitSize).fork(); |
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1868 |
task = task.makeChild(rightSplit, task.offset + leftSplitSize, |
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1869 |
task.length - leftSplitSize); |
17182 | 1870 |
} |
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
1871 |
|
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
1872 |
assert task.offset + task.length < MAX_ARRAY_SIZE; |
18795
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1873 |
T_SINK sink = (T_SINK) task; |
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1874 |
task.helper.wrapAndCopyInto(sink, rightSplit); |
25d68f4a1b38
8020040: Improve and generalize the F/J tasks to handle right or left-balanced trees
psandoz
parents:
18527
diff
changeset
|
1875 |
task.propagateCompletion(); |
17182 | 1876 |
} |
1877 |
||
1878 |
abstract K makeChild(Spliterator<P_IN> spliterator, long offset, long size); |
|
1879 |
||
1880 |
@Override |
|
1881 |
public void begin(long size) { |
|
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
1882 |
if (size > length) |
17182 | 1883 |
throw new IllegalStateException("size passed to Sink.begin exceeds array length"); |
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
1884 |
// Casts to int are safe since absolute size is verified to be within |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
1885 |
// bounds when the root concrete SizedCollectorTask is constructed |
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
1886 |
// with the shared array |
17182 | 1887 |
index = (int) offset; |
20507
8498104f92c3
8025534: Unsafe typecast in java.util.stream.Streams.Nodes
psandoz
parents:
19220
diff
changeset
|
1888 |
fence = index + (int) length; |
17182 | 1889 |
} |
1890 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
1891 |
@SuppressWarnings("serial") |
17182 | 1892 |
static final class OfRef<P_IN, P_OUT> |
1893 |
extends SizedCollectorTask<P_IN, P_OUT, Sink<P_OUT>, OfRef<P_IN, P_OUT>> |
|
1894 |
implements Sink<P_OUT> { |
|
1895 |
private final P_OUT[] array; |
|
1896 |
||
1897 |
OfRef(Spliterator<P_IN> spliterator, PipelineHelper<P_OUT> helper, P_OUT[] array) { |
|
1898 |
super(spliterator, helper, array.length); |
|
1899 |
this.array = array; |
|
1900 |
} |
|
1901 |
||
1902 |
OfRef(OfRef<P_IN, P_OUT> parent, Spliterator<P_IN> spliterator, |
|
1903 |
long offset, long length) { |
|
1904 |
super(parent, spliterator, offset, length, parent.array.length); |
|
1905 |
this.array = parent.array; |
|
1906 |
} |
|
1907 |
||
1908 |
@Override |
|
1909 |
OfRef<P_IN, P_OUT> makeChild(Spliterator<P_IN> spliterator, |
|
1910 |
long offset, long size) { |
|
1911 |
return new OfRef<>(this, spliterator, offset, size); |
|
1912 |
} |
|
1913 |
||
1914 |
@Override |
|
1915 |
public void accept(P_OUT value) { |
|
1916 |
if (index >= fence) { |
|
1917 |
throw new IndexOutOfBoundsException(Integer.toString(index)); |
|
1918 |
} |
|
1919 |
array[index++] = value; |
|
1920 |
} |
|
1921 |
} |
|
1922 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
1923 |
@SuppressWarnings("serial") |
17182 | 1924 |
static final class OfInt<P_IN> |
1925 |
extends SizedCollectorTask<P_IN, Integer, Sink.OfInt, OfInt<P_IN>> |
|
1926 |
implements Sink.OfInt { |
|
1927 |
private final int[] array; |
|
1928 |
||
1929 |
OfInt(Spliterator<P_IN> spliterator, PipelineHelper<Integer> helper, int[] array) { |
|
1930 |
super(spliterator, helper, array.length); |
|
1931 |
this.array = array; |
|
1932 |
} |
|
1933 |
||
1934 |
OfInt(SizedCollectorTask.OfInt<P_IN> parent, Spliterator<P_IN> spliterator, |
|
1935 |
long offset, long length) { |
|
1936 |
super(parent, spliterator, offset, length, parent.array.length); |
|
1937 |
this.array = parent.array; |
|
1938 |
} |
|
1939 |
||
1940 |
@Override |
|
1941 |
SizedCollectorTask.OfInt<P_IN> makeChild(Spliterator<P_IN> spliterator, |
|
1942 |
long offset, long size) { |
|
1943 |
return new SizedCollectorTask.OfInt<>(this, spliterator, offset, size); |
|
1944 |
} |
|
1945 |
||
1946 |
@Override |
|
1947 |
public void accept(int value) { |
|
1948 |
if (index >= fence) { |
|
1949 |
throw new IndexOutOfBoundsException(Integer.toString(index)); |
|
1950 |
} |
|
1951 |
array[index++] = value; |
|
1952 |
} |
|
1953 |
} |
|
1954 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
1955 |
@SuppressWarnings("serial") |
17182 | 1956 |
static final class OfLong<P_IN> |
1957 |
extends SizedCollectorTask<P_IN, Long, Sink.OfLong, OfLong<P_IN>> |
|
1958 |
implements Sink.OfLong { |
|
1959 |
private final long[] array; |
|
1960 |
||
1961 |
OfLong(Spliterator<P_IN> spliterator, PipelineHelper<Long> helper, long[] array) { |
|
1962 |
super(spliterator, helper, array.length); |
|
1963 |
this.array = array; |
|
1964 |
} |
|
1965 |
||
1966 |
OfLong(SizedCollectorTask.OfLong<P_IN> parent, Spliterator<P_IN> spliterator, |
|
1967 |
long offset, long length) { |
|
1968 |
super(parent, spliterator, offset, length, parent.array.length); |
|
1969 |
this.array = parent.array; |
|
1970 |
} |
|
1971 |
||
1972 |
@Override |
|
1973 |
SizedCollectorTask.OfLong<P_IN> makeChild(Spliterator<P_IN> spliterator, |
|
1974 |
long offset, long size) { |
|
1975 |
return new SizedCollectorTask.OfLong<>(this, spliterator, offset, size); |
|
1976 |
} |
|
1977 |
||
1978 |
@Override |
|
1979 |
public void accept(long value) { |
|
1980 |
if (index >= fence) { |
|
1981 |
throw new IndexOutOfBoundsException(Integer.toString(index)); |
|
1982 |
} |
|
1983 |
array[index++] = value; |
|
1984 |
} |
|
1985 |
} |
|
1986 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
1987 |
@SuppressWarnings("serial") |
17182 | 1988 |
static final class OfDouble<P_IN> |
1989 |
extends SizedCollectorTask<P_IN, Double, Sink.OfDouble, OfDouble<P_IN>> |
|
1990 |
implements Sink.OfDouble { |
|
1991 |
private final double[] array; |
|
1992 |
||
1993 |
OfDouble(Spliterator<P_IN> spliterator, PipelineHelper<Double> helper, double[] array) { |
|
1994 |
super(spliterator, helper, array.length); |
|
1995 |
this.array = array; |
|
1996 |
} |
|
1997 |
||
1998 |
OfDouble(SizedCollectorTask.OfDouble<P_IN> parent, Spliterator<P_IN> spliterator, |
|
1999 |
long offset, long length) { |
|
2000 |
super(parent, spliterator, offset, length, parent.array.length); |
|
2001 |
this.array = parent.array; |
|
2002 |
} |
|
2003 |
||
2004 |
@Override |
|
2005 |
SizedCollectorTask.OfDouble<P_IN> makeChild(Spliterator<P_IN> spliterator, |
|
2006 |
long offset, long size) { |
|
2007 |
return new SizedCollectorTask.OfDouble<>(this, spliterator, offset, size); |
|
2008 |
} |
|
2009 |
||
2010 |
@Override |
|
2011 |
public void accept(double value) { |
|
2012 |
if (index >= fence) { |
|
2013 |
throw new IndexOutOfBoundsException(Integer.toString(index)); |
|
2014 |
} |
|
2015 |
array[index++] = value; |
|
2016 |
} |
|
2017 |
} |
|
2018 |
} |
|
2019 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2020 |
@SuppressWarnings("serial") |
17182 | 2021 |
private static abstract class ToArrayTask<T, T_NODE extends Node<T>, |
2022 |
K extends ToArrayTask<T, T_NODE, K>> |
|
2023 |
extends CountedCompleter<Void> { |
|
2024 |
protected final T_NODE node; |
|
2025 |
protected final int offset; |
|
2026 |
||
2027 |
ToArrayTask(T_NODE node, int offset) { |
|
2028 |
this.node = node; |
|
2029 |
this.offset = offset; |
|
2030 |
} |
|
2031 |
||
2032 |
ToArrayTask(K parent, T_NODE node, int offset) { |
|
2033 |
super(parent); |
|
2034 |
this.node = node; |
|
2035 |
this.offset = offset; |
|
2036 |
} |
|
2037 |
||
2038 |
abstract void copyNodeToArray(); |
|
2039 |
||
2040 |
abstract K makeChild(int childIndex, int offset); |
|
2041 |
||
2042 |
@Override |
|
2043 |
public void compute() { |
|
2044 |
ToArrayTask<T, T_NODE, K> task = this; |
|
2045 |
while (true) { |
|
2046 |
if (task.node.getChildCount() == 0) { |
|
2047 |
task.copyNodeToArray(); |
|
2048 |
task.propagateCompletion(); |
|
2049 |
return; |
|
2050 |
} |
|
2051 |
else { |
|
2052 |
task.setPendingCount(task.node.getChildCount() - 1); |
|
2053 |
||
2054 |
int size = 0; |
|
2055 |
int i = 0; |
|
2056 |
for (;i < task.node.getChildCount() - 1; i++) { |
|
2057 |
K leftTask = task.makeChild(i, task.offset + size); |
|
2058 |
size += leftTask.node.count(); |
|
2059 |
leftTask.fork(); |
|
2060 |
} |
|
2061 |
task = task.makeChild(i, task.offset + size); |
|
2062 |
} |
|
2063 |
} |
|
2064 |
} |
|
2065 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2066 |
@SuppressWarnings("serial") |
17182 | 2067 |
private static final class OfRef<T> |
2068 |
extends ToArrayTask<T, Node<T>, OfRef<T>> { |
|
2069 |
private final T[] array; |
|
2070 |
||
2071 |
private OfRef(Node<T> node, T[] array, int offset) { |
|
2072 |
super(node, offset); |
|
2073 |
this.array = array; |
|
2074 |
} |
|
2075 |
||
2076 |
private OfRef(OfRef<T> parent, Node<T> node, int offset) { |
|
2077 |
super(parent, node, offset); |
|
2078 |
this.array = parent.array; |
|
2079 |
} |
|
2080 |
||
2081 |
@Override |
|
2082 |
OfRef<T> makeChild(int childIndex, int offset) { |
|
2083 |
return new OfRef<>(this, node.getChild(childIndex), offset); |
|
2084 |
} |
|
2085 |
||
2086 |
@Override |
|
2087 |
void copyNodeToArray() { |
|
2088 |
node.copyInto(array, offset); |
|
2089 |
} |
|
2090 |
} |
|
2091 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2092 |
@SuppressWarnings("serial") |
18527 | 2093 |
private static class OfPrimitive<T, T_CONS, T_ARR, |
2094 |
T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>, |
|
2095 |
T_NODE extends Node.OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>> |
|
2096 |
extends ToArrayTask<T, T_NODE, OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE>> { |
|
2097 |
private final T_ARR array; |
|
17182 | 2098 |
|
18527 | 2099 |
private OfPrimitive(T_NODE node, T_ARR array, int offset) { |
17182 | 2100 |
super(node, offset); |
2101 |
this.array = array; |
|
2102 |
} |
|
2103 |
||
18527 | 2104 |
private OfPrimitive(OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> parent, T_NODE node, int offset) { |
17182 | 2105 |
super(parent, node, offset); |
2106 |
this.array = parent.array; |
|
2107 |
} |
|
2108 |
||
2109 |
@Override |
|
18527 | 2110 |
OfPrimitive<T, T_CONS, T_ARR, T_SPLITR, T_NODE> makeChild(int childIndex, int offset) { |
2111 |
return new OfPrimitive<>(this, node.getChild(childIndex), offset); |
|
17182 | 2112 |
} |
2113 |
||
2114 |
@Override |
|
2115 |
void copyNodeToArray() { |
|
2116 |
node.copyInto(array, offset); |
|
2117 |
} |
|
2118 |
} |
|
2119 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2120 |
@SuppressWarnings("serial") |
18527 | 2121 |
private static final class OfInt |
2122 |
extends OfPrimitive<Integer, IntConsumer, int[], Spliterator.OfInt, Node.OfInt> { |
|
2123 |
private OfInt(Node.OfInt node, int[] array, int offset) { |
|
2124 |
super(node, array, offset); |
|
17182 | 2125 |
} |
18527 | 2126 |
} |
17182 | 2127 |
|
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2128 |
@SuppressWarnings("serial") |
18527 | 2129 |
private static final class OfLong |
2130 |
extends OfPrimitive<Long, LongConsumer, long[], Spliterator.OfLong, Node.OfLong> { |
|
2131 |
private OfLong(Node.OfLong node, long[] array, int offset) { |
|
2132 |
super(node, array, offset); |
|
17182 | 2133 |
} |
18527 | 2134 |
} |
17182 | 2135 |
|
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2136 |
@SuppressWarnings("serial") |
18527 | 2137 |
private static final class OfDouble |
2138 |
extends OfPrimitive<Double, DoubleConsumer, double[], Spliterator.OfDouble, Node.OfDouble> { |
|
2139 |
private OfDouble(Node.OfDouble node, double[] array, int offset) { |
|
2140 |
super(node, array, offset); |
|
17182 | 2141 |
} |
2142 |
} |
|
2143 |
} |
|
2144 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2145 |
@SuppressWarnings("serial") |
18527 | 2146 |
private static class CollectorTask<P_IN, P_OUT, T_NODE extends Node<P_OUT>, T_BUILDER extends Node.Builder<P_OUT>> |
2147 |
extends AbstractTask<P_IN, P_OUT, T_NODE, CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER>> { |
|
2148 |
protected final PipelineHelper<P_OUT> helper; |
|
2149 |
protected final LongFunction<T_BUILDER> builderFactory; |
|
2150 |
protected final BinaryOperator<T_NODE> concFactory; |
|
17182 | 2151 |
|
2152 |
CollectorTask(PipelineHelper<P_OUT> helper, |
|
18527 | 2153 |
Spliterator<P_IN> spliterator, |
2154 |
LongFunction<T_BUILDER> builderFactory, |
|
2155 |
BinaryOperator<T_NODE> concFactory) { |
|
17182 | 2156 |
super(helper, spliterator); |
2157 |
this.helper = helper; |
|
18527 | 2158 |
this.builderFactory = builderFactory; |
2159 |
this.concFactory = concFactory; |
|
17182 | 2160 |
} |
2161 |
||
18527 | 2162 |
CollectorTask(CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER> parent, |
2163 |
Spliterator<P_IN> spliterator) { |
|
17182 | 2164 |
super(parent, spliterator); |
2165 |
helper = parent.helper; |
|
18527 | 2166 |
builderFactory = parent.builderFactory; |
2167 |
concFactory = parent.concFactory; |
|
17182 | 2168 |
} |
2169 |
||
2170 |
@Override |
|
18527 | 2171 |
protected CollectorTask<P_IN, P_OUT, T_NODE, T_BUILDER> makeChild(Spliterator<P_IN> spliterator) { |
17182 | 2172 |
return new CollectorTask<>(this, spliterator); |
2173 |
} |
|
2174 |
||
2175 |
@Override |
|
18527 | 2176 |
protected T_NODE doLeaf() { |
2177 |
T_BUILDER builder = builderFactory.apply(helper.exactOutputSizeIfKnown(spliterator)); |
|
2178 |
return (T_NODE) helper.wrapAndCopyInto(builder, spliterator).build(); |
|
17182 | 2179 |
} |
2180 |
||
2181 |
@Override |
|
19220
d3d40ccb544e
8022476: cleanup some raw types and unchecked warnings in java.util.stream
mduigou
parents:
19218
diff
changeset
|
2182 |
public void onCompletion(CountedCompleter<?> caller) { |
18527 | 2183 |
if (!isLeaf()) |
2184 |
setLocalResult(concFactory.apply(leftChild.getLocalResult(), rightChild.getLocalResult())); |
|
17182 | 2185 |
super.onCompletion(caller); |
2186 |
} |
|
2187 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2188 |
@SuppressWarnings("serial") |
18527 | 2189 |
private static final class OfRef<P_IN, P_OUT> |
2190 |
extends CollectorTask<P_IN, P_OUT, Node<P_OUT>, Node.Builder<P_OUT>> { |
|
2191 |
OfRef(PipelineHelper<P_OUT> helper, |
|
2192 |
IntFunction<P_OUT[]> generator, |
|
2193 |
Spliterator<P_IN> spliterator) { |
|
2194 |
super(helper, spliterator, s -> builder(s, generator), ConcNode::new); |
|
17182 | 2195 |
} |
2196 |
} |
|
2197 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2198 |
@SuppressWarnings("serial") |
18527 | 2199 |
private static final class OfInt<P_IN> |
2200 |
extends CollectorTask<P_IN, Integer, Node.OfInt, Node.Builder.OfInt> { |
|
2201 |
OfInt(PipelineHelper<Integer> helper, Spliterator<P_IN> spliterator) { |
|
2202 |
super(helper, spliterator, Nodes::intBuilder, ConcNode.OfInt::new); |
|
2203 |
} |
|
17182 | 2204 |
} |
2205 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2206 |
@SuppressWarnings("serial") |
18527 | 2207 |
private static final class OfLong<P_IN> |
2208 |
extends CollectorTask<P_IN, Long, Node.OfLong, Node.Builder.OfLong> { |
|
2209 |
OfLong(PipelineHelper<Long> helper, Spliterator<P_IN> spliterator) { |
|
2210 |
super(helper, spliterator, Nodes::longBuilder, ConcNode.OfLong::new); |
|
17182 | 2211 |
} |
2212 |
} |
|
2213 |
||
19218
8e7212b90b81
8022446: Fix serial warnings in java.util.stream
henryjen
parents:
18795
diff
changeset
|
2214 |
@SuppressWarnings("serial") |
18527 | 2215 |
private static final class OfDouble<P_IN> |
2216 |
extends CollectorTask<P_IN, Double, Node.OfDouble, Node.Builder.OfDouble> { |
|
2217 |
OfDouble(PipelineHelper<Double> helper, Spliterator<P_IN> spliterator) { |
|
2218 |
super(helper, spliterator, Nodes::doubleBuilder, ConcNode.OfDouble::new); |
|
17182 | 2219 |
} |
2220 |
} |
|
2221 |
} |
|
2222 |
} |