ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/PAS.java
Revision: 1.19
Committed: Sun Jan 18 20:17:32 2015 UTC (9 years, 3 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.18: +1 -0 lines
Log Message:
exactly one blank line before and after package statements

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 package extra166y;
8
9 import jsr166y.*;
10 import static extra166y.Ops.*;
11 import java.util.*;
12 import java.util.concurrent.atomic.*;
13 import java.lang.reflect.Array;
14
15 /**
16 * Shared internal execution support for ParallelArray and
17 * specializations.
18 */
19 class PAS {
20 private PAS() {} // all-static, non-instantiable
21
22 /** Global default executor */
23 private static volatile ForkJoinPool defaultExecutor;
24 /** Lock for on-demand initialization of defaultExecutor */
25 private static final Object poolLock = new Object();
26
27 static ForkJoinPool defaultExecutor() {
28 ForkJoinPool p = defaultExecutor; // double-check
29 if (p == null) {
30 synchronized (poolLock) {
31 p = defaultExecutor;
32 if (p == null) {
33 // use ceil(7/8 * ncpus)
34 int nprocs = Runtime.getRuntime().availableProcessors();
35 int nthreads = nprocs - (nprocs >>> 3);
36 defaultExecutor = p = new ForkJoinPool(nthreads);
37 }
38 }
39 }
40 return p;
41 }
42
43 /**
44 * Base for most divide-and-conquer tasks used for computing
45 * ParallelArray operations. Rather than pure recursion, it links
46 * right-hand-sides and then joins up the tree, exploiting cases
47 * where tasks aren't stolen. This generates and joins tasks with
48 * a bit less overhead than pure recursive style -- there are only
49 * as many tasks as leaves (no strictly internal nodes).
50 *
51 * Split control relies on pap.getThreshold(), which is
52 * expected to err on the side of generating too many tasks. To
53 * counterbalance, if a task pops off its own smallest subtask, it
54 * directly runs its leaf action rather than possibly resplitting.
55 *
56 * There are, with a few exceptions, three flavors of each FJBase
57 * subclass, prefixed FJO (object reference), FJD (double) and FJL
58 * (long).
59 */
60 abstract static class FJBase extends RecursiveAction {
61 final AbstractParallelAnyArray pap;
62 final int lo;
63 final int hi;
64 final FJBase next; // the next task that creator should join
65 FJBase(AbstractParallelAnyArray pap, int lo, int hi, FJBase next) {
66 this.pap = pap;
67 this.lo = lo;
68 this.hi = hi;
69 this.next = next;
70 }
71
72 public final void compute() {
73 int g = pap.getThreshold();
74 int l = lo;
75 int h = hi;
76 if (h - l > g)
77 internalCompute(l, h, g);
78 else
79 atLeaf(l, h);
80 }
81
82 final void internalCompute(int l, int h, int g) {
83 FJBase r = null;
84 do {
85 int rh = h;
86 h = (l + h) >>> 1;
87 (r = newSubtask(h, rh, r)).fork();
88 } while (h - l > g);
89 atLeaf(l, h);
90 do {
91 if (r.tryUnfork()) r.atLeaf(r.lo, r.hi); else r.join();
92 onReduce(r);
93 r = r.next;
94 } while (r != null);
95 }
96
97 /** Leaf computation */
98 abstract void atLeaf(int l, int h);
99 /** Operation performed after joining right subtask -- default noop */
100 void onReduce(FJBase right) {}
101 /** Factory method to create new subtask, normally of current type */
102 abstract FJBase newSubtask(int l, int h, FJBase r);
103 }
104
105 // apply
106
107 static final class FJOApply extends FJBase {
108 final Procedure procedure;
109 FJOApply(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
110 Procedure procedure) {
111 super(pap, lo, hi, next);
112 this.procedure = procedure;
113 }
114 FJBase newSubtask(int l, int h, FJBase r) {
115 return new FJOApply(pap, l, h, r, procedure);
116 }
117 void atLeaf(int l, int h) {
118 pap.leafApply(l, h, procedure);
119 }
120 }
121
122 static final class FJDApply extends FJBase {
123 final DoubleProcedure procedure;
124 FJDApply(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
125 DoubleProcedure procedure) {
126 super(pap, lo, hi, next);
127 this.procedure = procedure;
128 }
129 FJBase newSubtask(int l, int h, FJBase r) {
130 return new FJDApply(pap, l, h, r, procedure);
131 }
132 void atLeaf(int l, int h) {
133 pap.leafApply(l, h, procedure);
134 }
135 }
136
137 static final class FJLApply extends FJBase {
138 final LongProcedure procedure;
139 FJLApply(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
140 LongProcedure procedure) {
141 super(pap, lo, hi, next);
142 this.procedure = procedure;
143 }
144 FJBase newSubtask(int l, int h, FJBase r) {
145 return new FJLApply(pap, l, h, r, procedure);
146 }
147 void atLeaf(int l, int h) {
148 pap.leafApply(l, h, procedure);
149 }
150 }
151
152 // reduce
153
154 static final class FJOReduce extends FJBase {
155 final Reducer reducer;
156 Object result;
157 FJOReduce(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
158 Reducer reducer, Object base) {
159 super(pap, lo, hi, next);
160 this.reducer = reducer;
161 this.result = base;
162 }
163 FJBase newSubtask(int l, int h, FJBase r) {
164 return new FJOReduce(pap, l, h, r, reducer, result);
165 }
166 void atLeaf(int l, int h) {
167 result = pap.leafReduce(l, h, reducer, result);
168 }
169 void onReduce(FJBase right) {
170 result = reducer.op(result, ((FJOReduce)right).result);
171 }
172 }
173
174 static final class FJDReduce extends FJBase {
175 final DoubleReducer reducer;
176 double result;
177 FJDReduce(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
178 DoubleReducer reducer, double base) {
179 super(pap, lo, hi, next);
180 this.reducer = reducer;
181 this.result = base;
182 }
183 FJBase newSubtask(int l, int h, FJBase r) {
184 return new FJDReduce(pap, l, h, r, reducer, result);
185 }
186 void atLeaf(int l, int h) {
187 result = pap.leafReduce(l, h, reducer, result);
188 }
189 void onReduce(FJBase right) {
190 result = reducer.op(result, ((FJDReduce)right).result);
191 }
192 }
193
194 static final class FJLReduce extends FJBase {
195 final LongReducer reducer;
196 long result;
197 FJLReduce(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
198 LongReducer reducer, long base) {
199 super(pap, lo, hi, next);
200 this.reducer = reducer;
201 this.result = base;
202 }
203 FJBase newSubtask(int l, int h, FJBase r) {
204 return new FJLReduce(pap, l, h, r, reducer, result);
205 }
206 void atLeaf(int l, int h) {
207 result = pap.leafReduce(l, h, reducer, result);
208 }
209 void onReduce(FJBase right) {
210 result = reducer.op(result, ((FJLReduce)right).result);
211 }
212 }
213
214 // map
215
216 static final class FJOMap extends FJBase {
217 final Object[] dest;
218 final int offset;
219 FJOMap(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
220 Object[] dest, int offset) {
221 super(pap, lo, hi, next);
222 this.dest = dest;
223 this.offset = offset;
224 }
225 FJBase newSubtask(int l, int h, FJBase r) {
226 return new FJOMap(pap, l, h, r, dest, offset);
227 }
228 void atLeaf(int l, int h) {
229 pap.leafTransfer(l, h, dest, l + offset);
230 }
231 }
232
233 static final class FJDMap extends FJBase {
234 final double[] dest;
235 final int offset;
236 FJDMap(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
237 double[] dest, int offset) {
238 super(pap, lo, hi, next);
239 this.dest = dest;
240 this.offset = offset;
241 }
242 FJBase newSubtask(int l, int h, FJBase r) {
243 return new FJDMap(pap, l, h, r, dest, offset);
244 }
245 void atLeaf(int l, int h) {
246 pap.leafTransfer(l, h, dest, l + offset);
247 }
248 }
249
250 static final class FJLMap extends FJBase {
251 final long[] dest;
252 final int offset;
253 FJLMap(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
254 long[] dest, int offset) {
255 super(pap, lo, hi, next);
256 this.dest = dest;
257 this.offset = offset;
258 }
259 FJBase newSubtask(int l, int h, FJBase r) {
260 return new FJLMap(pap, l, h, r, dest, offset);
261 }
262 void atLeaf(int l, int h) {
263 pap.leafTransfer(l, h, dest, l + offset);
264 }
265 }
266
267 // transform
268
269 static final class FJOTransform extends FJBase {
270 final Op op;
271 FJOTransform(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
272 Op op) {
273 super(pap, lo, hi, next);
274 this.op = op;
275 }
276 FJBase newSubtask(int l, int h, FJBase r) {
277 return new FJOTransform(pap, l, h, r, op);
278 }
279 void atLeaf(int l, int h) {
280 pap.leafTransform(l, h, op);
281 }
282 }
283
284 static final class FJDTransform extends FJBase {
285 final DoubleOp op;
286 FJDTransform(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
287 DoubleOp op) {
288 super(pap, lo, hi, next);
289 this.op = op;
290 }
291 FJBase newSubtask(int l, int h, FJBase r) {
292 return new FJDTransform(pap, l, h, r, op);
293 }
294 void atLeaf(int l, int h) {
295 pap.leafTransform(l, h, op);
296 }
297 }
298
299 static final class FJLTransform extends FJBase {
300 final LongOp op;
301 FJLTransform(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
302 LongOp op) {
303 super(pap, lo, hi, next);
304 this.op = op;
305 }
306 FJBase newSubtask(int l, int h, FJBase r) {
307 return new FJLTransform(pap, l, h, r, op);
308 }
309 void atLeaf(int l, int h) {
310 pap.leafTransform(l, h, op);
311 }
312 }
313
314 // index map
315
316 static final class FJOIndexMap extends FJBase {
317 final IntToObject op;
318 FJOIndexMap(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
319 IntToObject op) {
320 super(pap, lo, hi, next);
321 this.op = op;
322 }
323 FJBase newSubtask(int l, int h, FJBase r) {
324 return new FJOIndexMap(pap, l, h, r, op);
325 }
326 void atLeaf(int l, int h) {
327 pap.leafIndexMap(l, h, op);
328 }
329 }
330
331 static final class FJDIndexMap extends FJBase {
332 final IntToDouble op;
333 FJDIndexMap(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
334 IntToDouble op) {
335 super(pap, lo, hi, next);
336 this.op = op;
337 }
338 FJBase newSubtask(int l, int h, FJBase r) {
339 return new FJDIndexMap(pap, l, h, r, op);
340 }
341 void atLeaf(int l, int h) {
342 pap.leafIndexMap(l, h, op);
343 }
344 }
345
346 static final class FJLIndexMap extends FJBase {
347 final IntToLong op;
348 FJLIndexMap(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
349 IntToLong op) {
350 super(pap, lo, hi, next);
351 this.op = op;
352 }
353 FJBase newSubtask(int l, int h, FJBase r) {
354 return new FJLIndexMap(pap, l, h, r, op);
355 }
356 void atLeaf(int l, int h) {
357 pap.leafIndexMap(l, h, op);
358 }
359 }
360
361 // binary index map
362
363 static final class FJOBinaryIndexMap extends FJBase {
364 final IntAndObjectToObject op;
365 FJOBinaryIndexMap(AbstractParallelAnyArray pap, int lo, int hi,
366 FJBase next, IntAndObjectToObject op) {
367 super(pap, lo, hi, next);
368 this.op = op;
369 }
370 FJBase newSubtask(int l, int h, FJBase r) {
371 return new FJOBinaryIndexMap(pap, l, h, r, op);
372 }
373 void atLeaf(int l, int h) {
374 pap.leafBinaryIndexMap(l, h, op);
375 }
376 }
377
378 static final class FJDBinaryIndexMap extends FJBase {
379 final IntAndDoubleToDouble op;
380 FJDBinaryIndexMap(AbstractParallelAnyArray pap, int lo, int hi,
381 FJBase next, IntAndDoubleToDouble op) {
382 super(pap, lo, hi, next);
383 this.op = op;
384 }
385 FJBase newSubtask(int l, int h, FJBase r) {
386 return new FJDBinaryIndexMap(pap, l, h, r, op);
387 }
388 void atLeaf(int l, int h) {
389 pap.leafBinaryIndexMap(l, h, op);
390 }
391 }
392
393 static final class FJLBinaryIndexMap extends FJBase {
394 final IntAndLongToLong op;
395 FJLBinaryIndexMap(AbstractParallelAnyArray pap, int lo, int hi,
396 FJBase next, IntAndLongToLong op) {
397 super(pap, lo, hi, next);
398 this.op = op;
399 }
400 FJBase newSubtask(int l, int h, FJBase r) {
401 return new FJLBinaryIndexMap(pap, l, h, r, op);
402 }
403 void atLeaf(int l, int h) {
404 pap.leafBinaryIndexMap(l, h, op);
405 }
406 }
407
408
409 // generate
410
411 static final class FJOGenerate extends FJBase {
412 final Generator generator;
413 FJOGenerate(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
414 Generator generator) {
415 super(pap, lo, hi, next);
416 this.generator = generator;
417 }
418 FJBase newSubtask(int l, int h, FJBase r) {
419 return new FJOGenerate(pap, l, h, r, generator);
420 }
421 void atLeaf(int l, int h) {
422 pap.leafGenerate(l, h, generator);
423 }
424 }
425
426 static final class FJDGenerate extends FJBase {
427 final DoubleGenerator generator;
428 FJDGenerate(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
429 DoubleGenerator generator) {
430 super(pap, lo, hi, next);
431 this.generator = generator;
432 }
433 FJBase newSubtask(int l, int h, FJBase r) {
434 return new FJDGenerate(pap, l, h, r, generator);
435 }
436 void atLeaf(int l, int h) {
437 pap.leafGenerate(l, h, generator);
438 }
439 }
440
441 static final class FJLGenerate extends FJBase {
442 final LongGenerator generator;
443 FJLGenerate(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
444 LongGenerator generator) {
445 super(pap, lo, hi, next);
446 this.generator = generator;
447 }
448 FJBase newSubtask(int l, int h, FJBase r) {
449 return new FJLGenerate(pap, l, h, r, generator);
450 }
451 void atLeaf(int l, int h) {
452 pap.leafGenerate(l, h, generator);
453 }
454 }
455
456 // fill
457
458 static final class FJOFill extends FJBase {
459 final Object value;
460 FJOFill(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
461 Object value) {
462 super(pap, lo, hi, next);
463 this.value = value;
464 }
465 FJBase newSubtask(int l, int h, FJBase r) {
466 return new FJOFill(pap, l, h, r, value);
467 }
468 void atLeaf(int l, int h) {
469 pap.leafFill(l, h, value);
470 }
471 }
472
473 static final class FJDFill extends FJBase {
474 final double value;
475 FJDFill(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
476 double value) {
477 super(pap, lo, hi, next);
478 this.value = value;
479 }
480 FJBase newSubtask(int l, int h, FJBase r) {
481 return new FJDFill(pap, l, h, r, value);
482 }
483 void atLeaf(int l, int h) {
484 pap.leafFill(l, h, value);
485 }
486 }
487
488 static final class FJLFill extends FJBase {
489 final long value;
490 FJLFill(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
491 long value) {
492 super(pap, lo, hi, next);
493 this.value = value;
494 }
495 FJBase newSubtask(int l, int h, FJBase r) {
496 return new FJLFill(pap, l, h, r, value);
497 }
498 void atLeaf(int l, int h) {
499 pap.leafFill(l, h, value);
500 }
501 }
502
503 // combine in place
504
505 static final class FJOCombineInPlace extends FJBase {
506 final Object[] other;
507 final int otherOffset;
508 final BinaryOp combiner;
509 FJOCombineInPlace(AbstractParallelAnyArray pap, int lo, int hi,
510 FJBase next, Object[] other, int otherOffset,
511 BinaryOp combiner) {
512 super(pap, lo, hi, next);
513 this.other = other;
514 this.otherOffset = otherOffset;
515 this.combiner = combiner;
516 }
517 FJBase newSubtask(int l, int h, FJBase r) {
518 return new FJOCombineInPlace
519 (pap, l, h, r, other, otherOffset, combiner);
520 }
521 void atLeaf(int l, int h) {
522 pap.leafCombineInPlace(l, h, other, otherOffset, combiner);
523 }
524 }
525
526 static final class FJDCombineInPlace extends FJBase {
527 final double[] other;
528 final int otherOffset;
529 final BinaryDoubleOp combiner;
530 FJDCombineInPlace(AbstractParallelAnyArray pap, int lo, int hi,
531 FJBase next, double[] other, int otherOffset,
532 BinaryDoubleOp combiner) {
533 super(pap, lo, hi, next);
534 this.other = other;
535 this.otherOffset = otherOffset;
536 this.combiner = combiner;
537 }
538 FJBase newSubtask(int l, int h, FJBase r) {
539 return new FJDCombineInPlace
540 (pap, l, h, r, other, otherOffset, combiner);
541 }
542 void atLeaf(int l, int h) {
543 pap.leafCombineInPlace(l, h, other, otherOffset, combiner);
544 }
545 }
546
547 static final class FJLCombineInPlace extends FJBase {
548 final long[] other;
549 final int otherOffset;
550 final BinaryLongOp combiner;
551 FJLCombineInPlace(AbstractParallelAnyArray pap, int lo, int hi,
552 FJBase next, long[] other, int otherOffset,
553 BinaryLongOp combiner) {
554 super(pap, lo, hi, next);
555 this.other = other;
556 this.otherOffset = otherOffset;
557 this.combiner = combiner;
558 }
559 FJBase newSubtask(int l, int h, FJBase r) {
560 return new FJLCombineInPlace
561 (pap, l, h, r, other, otherOffset, combiner);
562 }
563 void atLeaf(int l, int h) {
564 pap.leafCombineInPlace(l, h, other, otherOffset, combiner);
565 }
566 }
567
568 static final class FJOPACombineInPlace extends FJBase {
569 final ParallelArrayWithMapping other;
570 final int otherOffset;
571 final BinaryOp combiner;
572 FJOPACombineInPlace(AbstractParallelAnyArray pap, int lo, int hi,
573 FJBase next,
574 ParallelArrayWithMapping other, int otherOffset,
575 BinaryOp combiner) {
576 super(pap, lo, hi, next);
577 this.other = other;
578 this.otherOffset = otherOffset;
579 this.combiner = combiner;
580 }
581 FJBase newSubtask(int l, int h, FJBase r) {
582 return new FJOPACombineInPlace
583 (pap, l, h, r, other, otherOffset, combiner);
584 }
585 void atLeaf(int l, int h) {
586 pap.leafCombineInPlace(l, h, other, otherOffset, combiner);
587 }
588 }
589
590 static final class FJDPACombineInPlace extends FJBase {
591 final ParallelDoubleArrayWithDoubleMapping other;
592 final int otherOffset;
593 final BinaryDoubleOp combiner;
594 FJDPACombineInPlace(AbstractParallelAnyArray pap, int lo, int hi,
595 FJBase next,
596 ParallelDoubleArrayWithDoubleMapping other,
597 int otherOffset, BinaryDoubleOp combiner) {
598 super(pap, lo, hi, next);
599 this.other = other;
600 this.otherOffset = otherOffset;
601 this.combiner = combiner;
602 }
603 FJBase newSubtask(int l, int h, FJBase r) {
604 return new FJDPACombineInPlace
605 (pap, l, h, r, other, otherOffset, combiner);
606 }
607 void atLeaf(int l, int h) {
608 pap.leafCombineInPlace(l, h, other, otherOffset, combiner);
609 }
610 }
611
612 static final class FJLPACombineInPlace extends FJBase {
613 final ParallelLongArrayWithLongMapping other;
614 final int otherOffset;
615 final BinaryLongOp combiner;
616 FJLPACombineInPlace(AbstractParallelAnyArray pap, int lo, int hi,
617 FJBase next,
618 ParallelLongArrayWithLongMapping other,
619 int otherOffset, BinaryLongOp combiner) {
620 super(pap, lo, hi, next);
621 this.other = other;
622 this.otherOffset = otherOffset;
623 this.combiner = combiner;
624 }
625 FJBase newSubtask(int l, int h, FJBase r) {
626 return new FJLPACombineInPlace
627 (pap, l, h, r, other, otherOffset, combiner);
628 }
629 void atLeaf(int l, int h) {
630 pap.leafCombineInPlace(l, h, other, otherOffset, combiner);
631 }
632 }
633
634 // stats
635
636 static final class FJOStats extends FJBase
637 implements ParallelArray.SummaryStatistics {
638 final Comparator comparator;
639 public int size() { return size; }
640 public Object min() { return min; }
641 public Object max() { return max; }
642 public int indexOfMin() { return indexOfMin; }
643 public int indexOfMax() { return indexOfMax; }
644 int size;
645 Object min;
646 Object max;
647 int indexOfMin;
648 int indexOfMax;
649 FJOStats(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
650 Comparator comparator) {
651 super(pap, lo, hi, next);
652 this.comparator = comparator;
653 this.indexOfMin = -1;
654 this.indexOfMax = -1;
655 }
656 FJBase newSubtask(int l, int h, FJBase r) {
657 return new FJOStats(pap, l, h, r, comparator);
658 }
659 void onReduce(FJBase right) {
660 FJOStats r = (FJOStats)right;
661 size += r.size;
662 updateMin(r.indexOfMin, r.min);
663 updateMax(r.indexOfMax, r.max);
664 }
665 void updateMin(int i, Object x) {
666 if (i >= 0 &&
667 (indexOfMin < 0 || comparator.compare(min, x) > 0)) {
668 min = x;
669 indexOfMin = i;
670 }
671 }
672 void updateMax(int i, Object x) {
673 if (i >= 0 &&
674 (indexOfMax < 0 || comparator.compare(max, x) < 0)) {
675 max = x;
676 indexOfMax = i;
677 }
678 }
679
680 void atLeaf(int l, int h) {
681 if (pap.hasFilter())
682 filteredAtLeaf(l, h);
683 else {
684 size = h - l;
685 for (int i = l; i < h; ++i) {
686 Object x = pap.oget(i);
687 updateMin(i, x);
688 updateMax(i, x);
689 }
690 }
691 }
692
693 void filteredAtLeaf(int l, int h) {
694 for (int i = l; i < h; ++i) {
695 if (pap.isSelected(i)) {
696 Object x = pap.oget(i);
697 ++size;
698 updateMin(i, x);
699 updateMax(i, x);
700 }
701 }
702 }
703
704 public String toString() {
705 return
706 "size: " + size +
707 " min: " + min + " (index " + indexOfMin +
708 ") max: " + max + " (index " + indexOfMax + ")";
709 }
710
711 }
712
713 static final class FJDStats extends FJBase
714 implements ParallelDoubleArray.SummaryStatistics {
715 final DoubleComparator comparator;
716 public int size() { return size; }
717 public double min() { return min; }
718 public double max() { return max; }
719 public double sum() { return sum; }
720 public double average() { return sum / size; }
721 public int indexOfMin() { return indexOfMin; }
722 public int indexOfMax() { return indexOfMax; }
723 int size;
724 double min;
725 double max;
726 double sum;
727 int indexOfMin;
728 int indexOfMax;
729 FJDStats(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
730 DoubleComparator comparator) {
731 super(pap, lo, hi, next);
732 this.comparator = comparator;
733 this.indexOfMin = -1;
734 this.indexOfMax = -1;
735 this.min = Double.MAX_VALUE;
736 this.max = -Double.MAX_VALUE;
737 }
738 FJBase newSubtask(int l, int h, FJBase r) {
739 return new FJDStats(pap, l, h, r, comparator);
740 }
741 void onReduce(FJBase right) {
742 FJDStats r = (FJDStats)right;
743 size += r.size;
744 sum += r.sum;
745 updateMin(r.indexOfMin, r.min);
746 updateMax(r.indexOfMax, r.max);
747 }
748 void updateMin(int i, double x) {
749 if (i >= 0 &&
750 (indexOfMin < 0 || comparator.compare(min, x) > 0)) {
751 min = x;
752 indexOfMin = i;
753 }
754 }
755 void updateMax(int i, double x) {
756 if (i >= 0 &&
757 (indexOfMax < 0 || comparator.compare(max, x) < 0)) {
758 max = x;
759 indexOfMax = i;
760 }
761 }
762 void atLeaf(int l, int h) {
763 if (pap.hasFilter())
764 filteredAtLeaf(l, h);
765 else {
766 size = h - l;
767 for (int i = l; i < h; ++i) {
768 double x = pap.dget(i);
769 sum += x;
770 updateMin(i, x);
771 updateMax(i, x);
772 }
773 }
774 }
775
776 void filteredAtLeaf(int l, int h) {
777 for (int i = l; i < h; ++i) {
778 if (pap.isSelected(i)) {
779 double x = pap.dget(i);
780 ++size;
781 sum += x;
782 updateMin(i, x);
783 updateMax(i, x);
784 }
785 }
786 }
787
788 public String toString() {
789 return
790 "size: " + size +
791 " min: " + min + " (index " + indexOfMin +
792 ") max: " + max + " (index " + indexOfMax +
793 ") sum: " + sum;
794 }
795 }
796
797 static final class FJLStats extends FJBase
798 implements ParallelLongArray.SummaryStatistics {
799 final LongComparator comparator;
800 public int size() { return size; }
801 public long min() { return min; }
802 public long max() { return max; }
803 public long sum() { return sum; }
804 public double average() { return (double)sum / size; }
805 public int indexOfMin() { return indexOfMin; }
806 public int indexOfMax() { return indexOfMax; }
807 int size;
808 long min;
809 long max;
810 long sum;
811 int indexOfMin;
812 int indexOfMax;
813 FJLStats(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
814 LongComparator comparator) {
815 super(pap, lo, hi, next);
816 this.comparator = comparator;
817 this.indexOfMin = -1;
818 this.indexOfMax = -1;
819 this.min = Long.MAX_VALUE;
820 this.max = Long.MIN_VALUE;
821 }
822 FJBase newSubtask(int l, int h, FJBase r) {
823 return new FJLStats(pap, l, h, r, comparator);
824 }
825 void onReduce(FJBase right) {
826 FJLStats r = (FJLStats)right;
827 size += r.size;
828 sum += r.sum;
829 updateMin(r.indexOfMin, r.min);
830 updateMax(r.indexOfMax, r.max);
831 }
832 void updateMin(int i, long x) {
833 if (i >= 0 &&
834 (indexOfMin < 0 || comparator.compare(min, x) > 0)) {
835 min = x;
836 indexOfMin = i;
837 }
838 }
839 void updateMax(int i, long x) {
840 if (i >= 0 &&
841 (indexOfMax < 0 || comparator.compare(max, x) < 0)) {
842 max = x;
843 indexOfMax = i;
844 }
845 }
846
847 void atLeaf(int l, int h) {
848 if (pap.hasFilter())
849 filteredAtLeaf(l, h);
850 else {
851 size = h - l;
852 for (int i = l; i < h; ++i) {
853 long x = pap.lget(i);
854 sum += x;
855 updateMin(i, x);
856 updateMax(i, x);
857 }
858 }
859 }
860
861 void filteredAtLeaf(int l, int h) {
862 for (int i = l; i < h; ++i) {
863 if (pap.isSelected(i)) {
864 long x = pap.lget(i);
865 ++size;
866 sum += x;
867 updateMin(i, x);
868 updateMax(i, x);
869 }
870 }
871 }
872
873 public String toString() {
874 return
875 "size: " + size +
876 " min: " + min + " (index " + indexOfMin +
877 ") max: " + max + " (index " + indexOfMax +
878 ") sum: " + sum;
879 }
880 }
881
882 // count
883
884 static final class FJCountSelected extends FJBase {
885 int count;
886 FJCountSelected(AbstractParallelAnyArray pap, int lo, int hi,
887 FJBase next) {
888 super(pap, lo, hi, next);
889 }
890 FJBase newSubtask(int l, int h, FJBase r) {
891 return new FJCountSelected(pap, l, h, r);
892 }
893 void onReduce(FJBase right) {
894 count += ((FJCountSelected)right).count;
895 }
896 void atLeaf(int l, int h) {
897 int n = 0;
898 for (int i = l; i < h; ++i) {
899 if (pap.isSelected(i))
900 ++n;
901 }
902 count = n;
903 }
904 }
905
906 /**
907 * Base for cancellable search tasks. Same idea as FJBase
908 * but cancels tasks when result nonnegative.
909 */
910 abstract static class FJSearchBase extends RecursiveAction {
911 final AbstractParallelAnyArray pap;
912 final int lo;
913 final int hi;
914 final FJSearchBase next;
915 final AtomicInteger result;
916
917 FJSearchBase(AbstractParallelAnyArray pap, int lo, int hi,
918 FJSearchBase next,
919 AtomicInteger result) {
920 this.pap = pap;
921 this.lo = lo;
922 this.hi = hi;
923 this.next = next;
924 this.result = result;
925 }
926
927 public void compute() {
928 if (result.get() >= 0)
929 return;
930 FJSearchBase r = null;
931 int l = lo;
932 int h = hi;
933 int g = pap.getThreshold();
934 while (h - l > g) {
935 int rh = h;
936 h = (l + h) >>> 1;
937 (r = newSubtask(h, rh, r)).fork();
938 }
939 atLeaf(l, h);
940 boolean stopping = false;
941 while (r != null) {
942 stopping |= result.get() >= 0;
943 if (r.tryUnfork()) {
944 if (!stopping)
945 r.atLeaf(r.lo, r.hi);
946 }
947 else if (stopping)
948 r.cancel(false);
949 else
950 r.join();
951 r = r.next;
952 }
953 }
954 abstract FJSearchBase newSubtask(int l, int h, FJSearchBase r);
955 abstract void atLeaf(int l, int h);
956 }
957
958 // select any
959
960 static final class FJSelectAny extends FJSearchBase {
961 FJSelectAny(AbstractParallelAnyArray pap, int lo, int hi,
962 FJSearchBase next, AtomicInteger result) {
963 super(pap, lo, hi, next, result);
964 }
965 FJSearchBase newSubtask(int l, int h, FJSearchBase r) {
966 return new FJSelectAny(pap, l, h, r, result);
967 }
968 void atLeaf(int l, int h) {
969 for (int i = l; i < h; ++i) {
970 if (pap.isSelected(i)) {
971 result.compareAndSet(-1, i);
972 break;
973 }
974 else if (result.get() >= 0)
975 break;
976 }
977 }
978 }
979
980 // index of
981
982 static final class FJOIndexOf extends FJSearchBase {
983 final Object target;
984 FJOIndexOf(AbstractParallelAnyArray pap, int lo, int hi,
985 FJSearchBase next, AtomicInteger result, Object target) {
986 super(pap, lo, hi, next, result);
987 this.target = target;
988 }
989 FJSearchBase newSubtask(int l, int h, FJSearchBase r) {
990 return new FJOIndexOf(pap, l, h, r, result, target);
991 }
992 void atLeaf(int l, int h) {
993 final Object[] array = pap.ogetArray();
994 if (array == null) return;
995 for (int i = l; i < h; ++i) {
996 if (target.equals(array[i])) {
997 result.compareAndSet(-1, i);
998 break;
999 }
1000 else if (result.get() >= 0)
1001 break;
1002 }
1003 }
1004 }
1005
1006 static final class FJDIndexOf extends FJSearchBase {
1007 final double target;
1008 FJDIndexOf(AbstractParallelAnyArray pap, int lo, int hi,
1009 FJSearchBase next, AtomicInteger result, double target) {
1010 super(pap, lo, hi, next, result);
1011 this.target = target;
1012 }
1013 FJSearchBase newSubtask(int l, int h, FJSearchBase r) {
1014 return new FJDIndexOf(pap, l, h, r, result, target);
1015 }
1016 void atLeaf(int l, int h) {
1017 final double[] array = pap.dgetArray();
1018 if (array == null) return;
1019 for (int i = l; i < h; ++i) {
1020 if (target == (array[i])) {
1021 result.compareAndSet(-1, i);
1022 break;
1023 }
1024 else if (result.get() >= 0)
1025 break;
1026 }
1027 }
1028 }
1029
1030 static final class FJLIndexOf extends FJSearchBase {
1031 final long target;
1032 FJLIndexOf(AbstractParallelAnyArray pap, int lo, int hi,
1033 FJSearchBase next, AtomicInteger result, long target) {
1034 super(pap, lo, hi, next, result);
1035 this.target = target;
1036 }
1037 FJSearchBase newSubtask(int l, int h, FJSearchBase r) {
1038 return new FJLIndexOf(pap, l, h, r, result, target);
1039 }
1040 void atLeaf(int l, int h) {
1041 final long[] array = pap.lgetArray();
1042 if (array == null) return;
1043 for (int i = l; i < h; ++i) {
1044 if (target == (array[i])) {
1045 result.compareAndSet(-1, i);
1046 break;
1047 }
1048 else if (result.get() >= 0)
1049 break;
1050 }
1051 }
1052 }
1053
1054 // select all
1055
1056 /**
1057 * SelectAll proceeds in two passes. In the first phase, indices
1058 * of matching elements are recorded in indices array. In second
1059 * pass, once the size of results is known and result array is
1060 * constructed in driver, the matching elements are placed into
1061 * corresponding result positions.
1062 */
1063 static final class FJSelectAll extends RecursiveAction {
1064 final FJSelectAllDriver driver;
1065 FJSelectAll left, right;
1066 final int lo;
1067 final int hi;
1068 int count; // number of matching elements
1069 int offset;
1070 boolean isInternal; // true if this is a non-leaf node
1071 final int threshold;
1072
1073 FJSelectAll(FJSelectAllDriver driver, int lo, int hi) {
1074 this.driver = driver;
1075 this.lo = lo;
1076 this.hi = hi;
1077 this.threshold = driver.pap.getThreshold();
1078 }
1079
1080 public void compute() {
1081 int l = lo;
1082 int h = hi;
1083 FJSelectAllDriver d = driver;
1084 if (d.phase == 0) {
1085 AbstractParallelAnyArray p = d.pap;
1086 if (isInternal = (h - l > threshold))
1087 internalPhase0();
1088 else
1089 count = p.leafIndexSelected(l, h, true, d.indices);
1090 }
1091 else if (count != 0) {
1092 if (isInternal)
1093 internalPhase1();
1094 else
1095 d.leafPhase1(l, l+count, offset);
1096 }
1097 }
1098
1099 void internalPhase0() {
1100 int mid = (lo + hi) >>> 1;
1101 FJSelectAll l = new FJSelectAll(driver, lo, mid);
1102 FJSelectAll r = new FJSelectAll(driver, mid, hi);
1103 r.fork();
1104 l.compute();
1105 if (r.tryUnfork()) r.compute(); else r.join();
1106 int ln = l.count;
1107 if (ln != 0)
1108 left = l;
1109 int rn = r.count;
1110 if (rn != 0)
1111 right = r;
1112 count = ln + rn;
1113 }
1114
1115 void internalPhase1() {
1116 int k = offset;
1117 if (left != null) {
1118 int ln = left.count;
1119 left.offset = k;
1120 left.reinitialize();
1121 if (right != null) {
1122 right.offset = k + ln;
1123 right.reinitialize();
1124 right.fork();
1125 left.compute();
1126 if (right.tryUnfork()) right.compute(); else right.join();
1127 }
1128 else
1129 left.compute();
1130 }
1131 else if (right != null) {
1132 right.offset = k;
1133 right.compute();
1134 }
1135 }
1136 }
1137
1138 abstract static class FJSelectAllDriver extends RecursiveAction {
1139 final int[] indices;
1140 final AbstractParallelAnyArray pap;
1141 final int initialOffset;
1142 int phase;
1143 int resultSize;
1144 FJSelectAllDriver(AbstractParallelAnyArray pap, int initialOffset) {
1145 this.pap = pap;
1146 this.initialOffset = initialOffset;
1147 int n = pap.fence - pap.origin;
1148 indices = new int[n];
1149 }
1150 public final void compute() {
1151 FJSelectAll r = new FJSelectAll(this, pap.origin, pap.fence);
1152 r.offset = initialOffset;
1153 r.compute();
1154 createResults(resultSize = r.count);
1155 phase = 1;
1156 r.compute();
1157 }
1158 abstract void createResults(int size);
1159 abstract void leafPhase1(int loIdx, int hiIdx, int offset);
1160 }
1161
1162 static final class FJOSelectAllDriver extends FJSelectAllDriver {
1163 final Class elementType;
1164 Object[] results;
1165 FJOSelectAllDriver(AbstractParallelAnyArray pap, Class elementType) {
1166 super(pap, 0);
1167 this.elementType = elementType;
1168 }
1169 void createResults(int size) {
1170 results = (Object[])Array.newInstance(elementType, size);
1171 }
1172 void leafPhase1(int loIdx, int hiIdx, int offset) {
1173 pap.leafTransferByIndex(indices, loIdx, hiIdx, results, offset);
1174 }
1175 }
1176
1177 static final class FJDSelectAllDriver extends FJSelectAllDriver {
1178 double[] results;
1179 FJDSelectAllDriver(AbstractParallelAnyArray pap) {
1180 super(pap, 0);
1181 }
1182 void createResults(int size) {
1183 results = new double[size];
1184 }
1185 void leafPhase1(int loIdx, int hiIdx, int offset) {
1186 pap.leafTransferByIndex(indices, loIdx, hiIdx, results, offset);
1187 }
1188 }
1189
1190 static final class FJLSelectAllDriver extends FJSelectAllDriver {
1191 long[] results;
1192 FJLSelectAllDriver(AbstractParallelAnyArray pap) {
1193 super(pap, 0);
1194 }
1195 void createResults(int size) {
1196 results = new long[size];
1197 }
1198 void leafPhase1(int loIdx, int hiIdx, int offset) {
1199 pap.leafTransferByIndex(indices, loIdx, hiIdx, results, offset);
1200 }
1201 }
1202
1203 static final class FJOAppendAllDriver extends FJSelectAllDriver {
1204 Object[] results;
1205 FJOAppendAllDriver(AbstractParallelAnyArray pap, int initialOffset,
1206 Object[] results) {
1207 super(pap, 0);
1208 this.results = results;
1209 }
1210 void createResults(int size) {
1211 int newSize = initialOffset + size;
1212 int oldLength = results.length;
1213 if (newSize > oldLength) {
1214 Class elementType = results.getClass().getComponentType();
1215 Object[] r = (Object[])Array.newInstance(elementType, newSize);
1216 System.arraycopy(results, 0, r, 0, oldLength);
1217 results = r;
1218 }
1219 }
1220 void leafPhase1(int loIdx, int hiIdx, int offset) {
1221 pap.leafTransferByIndex(indices, loIdx, hiIdx, results, offset);
1222 }
1223 }
1224
1225 static final class FJDAppendAllDriver extends FJSelectAllDriver {
1226 double[] results;
1227 FJDAppendAllDriver(AbstractParallelAnyArray pap, int initialOffset,
1228 double[] results) {
1229 super(pap, initialOffset);
1230 this.results = results;
1231 }
1232 void createResults(int size) {
1233 int newSize = initialOffset + size;
1234 int oldLength = results.length;
1235 if (newSize > oldLength) {
1236 double[] r = new double[newSize];
1237 System.arraycopy(results, 0, r, 0, oldLength);
1238 results = r;
1239 }
1240 }
1241 void leafPhase1(int loIdx, int hiIdx, int offset) {
1242 pap.leafTransferByIndex(indices, loIdx, hiIdx, results, offset);
1243 }
1244 }
1245
1246 static final class FJLAppendAllDriver extends FJSelectAllDriver {
1247 long[] results;
1248 FJLAppendAllDriver(AbstractParallelAnyArray pap, int initialOffset,
1249 long[] results) {
1250 super(pap, initialOffset);
1251 this.results = results;
1252 }
1253 void createResults(int size) {
1254 int newSize = initialOffset + size;
1255 int oldLength = results.length;
1256 if (newSize > oldLength) {
1257 long[] r = new long[newSize];
1258 System.arraycopy(results, 0, r, 0, oldLength);
1259 results = r;
1260 }
1261 }
1262 void leafPhase1(int loIdx, int hiIdx, int offset) {
1263 pap.leafTransferByIndex(indices, loIdx, hiIdx, results, offset);
1264 }
1265 }
1266
1267
1268 /**
1269 * Root node for FJRemoveAll. Spawns subtasks and shifts elements
1270 * as indices become available, bypassing index array creation
1271 * when offsets are known. This differs from SelectAll mainly in
1272 * that data movement is all done by the driver rather than in a
1273 * second parallel pass.
1274 */
1275 static final class FJRemoveAllDriver extends RecursiveAction {
1276 final AbstractParallelAnyArray pap;
1277 final int lo;
1278 final int hi;
1279 final int[] indices;
1280 int offset;
1281 final int threshold;
1282 FJRemoveAllDriver(AbstractParallelAnyArray pap, int lo, int hi) {
1283 this.pap = pap;
1284 this.lo = lo;
1285 this.hi = hi;
1286 this.indices = new int[hi - lo];
1287 this.threshold = pap.getThreshold();
1288 }
1289
1290 public void compute() {
1291 FJRemoveAll r = null;
1292 int l = lo;
1293 int h = hi;
1294 int g = threshold;
1295 while (h - l > g) {
1296 int rh = h;
1297 h = (l + h) >>> 1;
1298 (r = new FJRemoveAll(pap, h, rh, r, indices)).fork();
1299 }
1300 int k = pap.leafMoveSelected(l, h, l, false);
1301 while (r != null) {
1302 if (r.tryUnfork())
1303 k = pap.leafMoveSelected(r.lo, r.hi, k, false);
1304 else {
1305 r.join();
1306 int n = r.count;
1307 if (n != 0)
1308 pap.leafMoveByIndex(indices, r.lo, r.lo+n, k);
1309 k += n;
1310 FJRemoveAll rr = r.right;
1311 if (rr != null)
1312 k = inorderMove(rr, k);
1313 }
1314 r = r.next;
1315 }
1316 offset = k;
1317 }
1318
1319 /**
1320 * Inorder traversal to move indexed elements across reachable
1321 * nodes. This guarantees that element shifts don't overwrite
1322 * those still being used by active subtasks.
1323 */
1324 static int inorderMove(FJRemoveAll t, int index) {
1325 while (t != null) {
1326 int n = t.count;
1327 if (n != 0)
1328 t.pap.leafMoveByIndex(t.indices, t.lo, t.lo+n, index);
1329 index += n;
1330 FJRemoveAll p = t.next;
1331 if (p != null)
1332 index = inorderMove(p, index);
1333 t = t.right;
1334 }
1335 return index;
1336 }
1337 }
1338
1339 /**
1340 * Basic FJ task for non-root FJRemoveAll nodes. Differs from
1341 * FJBase because it requires maintaining explicit right pointers so
1342 * FJRemoveAllDriver can traverse them
1343 */
1344 static final class FJRemoveAll extends RecursiveAction {
1345 final AbstractParallelAnyArray pap;
1346 final int lo;
1347 final int hi;
1348 final FJRemoveAll next;
1349 final int[] indices;
1350 int count;
1351 FJRemoveAll right;
1352 final int threshold;
1353 FJRemoveAll(AbstractParallelAnyArray pap, int lo, int hi,
1354 FJRemoveAll next, int[] indices) {
1355 this.pap = pap;
1356 this.lo = lo;
1357 this.hi = hi;
1358 this.next = next;
1359 this.indices = indices;
1360 this.threshold = pap.getThreshold();
1361 }
1362
1363 public void compute() {
1364 FJRemoveAll r = null;
1365 int l = lo;
1366 int h = hi;
1367 int g = threshold;
1368 while (h - l > g) {
1369 int rh = h;
1370 h = (l + h) >>> 1;
1371 (r = new FJRemoveAll(pap, h, rh, r, indices)).fork();
1372 }
1373 right = r;
1374 count = pap.leafIndexSelected(l, h, false, indices);
1375 while (r != null) {
1376 if (r.tryUnfork())
1377 r.count = pap.leafIndexSelected
1378 (r.lo, r.hi, false, indices);
1379 else
1380 r.join();
1381 r = r.next;
1382 }
1383 }
1384 }
1385
1386 // unique elements
1387
1388 static final class FJOUniquifier extends FJBase {
1389 final UniquifierTable table;
1390 int count;
1391 FJOUniquifier(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
1392 UniquifierTable table) {
1393 super(pap, lo, hi, next);
1394 this.table = table;
1395 }
1396 FJBase newSubtask(int l, int h, FJBase r) {
1397 return new FJOUniquifier(pap, l, h, r, table);
1398 }
1399 void atLeaf(int l, int h) {
1400 count = table.addObjects(l, h);
1401 }
1402 void onReduce(FJBase right) {
1403 count += ((FJOUniquifier)right).count;
1404 }
1405 }
1406
1407 static final class FJDUniquifier extends FJBase {
1408 final UniquifierTable table;
1409 int count;
1410 FJDUniquifier(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
1411 UniquifierTable table) {
1412 super(pap, lo, hi, next);
1413 this.table = table;
1414 }
1415 FJBase newSubtask(int l, int h, FJBase r) {
1416 return new FJDUniquifier(pap, l, h, r, table);
1417 }
1418 void atLeaf(int l, int h) {
1419 count = table.addDoubles(l, h);
1420 }
1421 void onReduce(FJBase right) {
1422 count += ((FJDUniquifier)right).count;
1423 }
1424 }
1425
1426 static final class FJLUniquifier extends FJBase {
1427 final UniquifierTable table;
1428 int count;
1429 FJLUniquifier(AbstractParallelAnyArray pap, int lo, int hi, FJBase next,
1430 UniquifierTable table) {
1431 super(pap, lo, hi, next);
1432 this.table = table;
1433 }
1434 FJBase newSubtask(int l, int h, FJBase r) {
1435 return new FJLUniquifier(pap, l, h, r, table);
1436 }
1437 void atLeaf(int l, int h) {
1438 count = table.addLongs(l, h);
1439 }
1440 void onReduce(FJBase right) {
1441 count += ((FJLUniquifier)right).count;
1442 }
1443 }
1444
1445 /**
1446 * Base class of fixed-size hash tables for
1447 * uniquification. Opportunistically subclasses
1448 * AtomicLongArray. The high word of each slot is the cached
1449 * massaged hash of an element, and the low word contains its
1450 * index, plus one, to ensure that a zero tab entry means
1451 * empty. The mechanics for this are just folded into the
1452 * main addElements method.
1453 * Each leaf step places source array elements into table,
1454 * Even though this table undergoes a lot of contention when
1455 * elements are concurrently inserted by parallel threads, it is
1456 * generally faster to do this than to have separate tables and
1457 * then merge them.
1458 */
1459 static final class UniquifierTable extends AtomicLongArray {
1460 final AbstractParallelAnyArray pap;
1461 final boolean byIdentity;
1462 UniquifierTable(int size, AbstractParallelAnyArray pap,
1463 boolean byIdentity) {
1464 super(tableSizeFor(size));
1465 this.pap = pap;
1466 this.byIdentity = byIdentity;
1467 }
1468
1469 /** Returns a good size for table */
1470 static int tableSizeFor(int n) {
1471 int padded = n + (n >>> 1) + 1;
1472 if (padded < n) // int overflow
1473 throw new OutOfMemoryError();
1474 int s = 8;
1475 while (s < padded) s <<= 1;
1476 return s;
1477 }
1478
1479 // Same hashcode conditioning as HashMap
1480 static int hash(int h) {
1481 h ^= (h >>> 20) ^ (h >>> 12);
1482 return h ^ (h >>> 7) ^ (h >>> 4);
1483 }
1484
1485 int addObjects(int lo, int hi) {
1486 boolean filtered = pap.hasFilter();
1487 Object[] src = pap.ogetArray();
1488 final int mask = length() - 1;
1489 int count = 0;
1490 for (int k = lo; k < hi; ++k) {
1491 Object x;
1492 if ((filtered && !pap.isSelected(k)) ||
1493 (x = src[k]) == null)
1494 continue;
1495 int hc = byIdentity ? System.identityHashCode(x) : x.hashCode();
1496 int hash = hash(hc);
1497 long entry = (((long)hash) << 32) + (k + 1);
1498 int idx = hash & mask;
1499 for (;;) {
1500 long d = get(idx);
1501 if (d != 0) {
1502 if ((int)(d >>> 32) == hash) {
1503 Object y = src[(int)((d-1) & 0x7fffffffL)];
1504 if (x == y || (!byIdentity && x.equals(y)))
1505 break;
1506 }
1507 idx = (idx + 1) & mask;
1508 }
1509 else if (compareAndSet(idx, 0, entry)) {
1510 ++count;
1511 break;
1512 }
1513 }
1514 }
1515 return count;
1516 }
1517
1518 int addDoubles(int lo, int hi) {
1519 boolean filtered = pap.hasFilter();
1520 double[] src = pap.dgetArray();
1521 final int mask = length() - 1;
1522 int count = 0;
1523 for (int k = lo; k < hi; ++k) {
1524 if (filtered && !pap.isSelected(k))
1525 continue;
1526 double x = src[k];
1527 long bits = Double.doubleToLongBits(x);
1528 int hash = hash((int)(bits ^ (bits >>> 32)));
1529 long entry = (((long)hash) << 32) + (k + 1);
1530 int idx = hash & mask;
1531 for (;;) {
1532 long d = get(idx);
1533 if (d != 0) {
1534 if ((int)(d >>> 32) == hash &&
1535 x == src[(int)((d - 1) & 0x7fffffffL)])
1536 break;
1537 idx = (idx + 1) & mask;
1538 }
1539 else if (compareAndSet(idx, 0, entry)) {
1540 ++count;
1541 break;
1542 }
1543 }
1544 }
1545 return count;
1546 }
1547
1548 int addLongs(int lo, int hi) {
1549 boolean filtered = pap.hasFilter();
1550 long[] src = pap.lgetArray();
1551 final int mask = length() - 1;
1552 int count = 0;
1553 for (int k = lo; k < hi; ++k) {
1554 if (filtered && !pap.isSelected(k))
1555 continue;
1556 long x = src[k];
1557 int hash = hash((int)(x ^ (x >>> 32)));
1558 long entry = (((long)hash) << 32) + (k + 1);
1559 int idx = hash & mask;
1560 for (;;) {
1561 long d = get(idx);
1562 if (d != 0) {
1563 if ((int)(d >>> 32) == hash &&
1564 x == src[(int)((d - 1) & 0x7fffffffL)])
1565 break;
1566 idx = (idx + 1) & mask;
1567 }
1568 else if (compareAndSet(idx, 0, entry)) {
1569 ++count;
1570 break;
1571 }
1572 }
1573 }
1574 return count;
1575 }
1576
1577 /**
1578 * Returns new array holding all elements.
1579 */
1580 Object[] uniqueObjects(int size) {
1581 Object[] src = pap.ogetArray();
1582 Class sclass = src.getClass().getComponentType();
1583 Object[] res = (Object[])Array.newInstance(sclass, size);
1584 int k = 0;
1585 int n = length();
1586 for (int i = 0; i < n && k < size; ++i) {
1587 long d = get(i);
1588 if (d != 0)
1589 res[k++] = src[((int)((d - 1) & 0x7fffffffL))];
1590 }
1591 return res;
1592 }
1593
1594 double[] uniqueDoubles(int size) {
1595 double[] src = pap.dgetArray();
1596 double[] res = new double[size];
1597 int k = 0;
1598 int n = length();
1599 for (int i = 0; i < n && k < size; ++i) {
1600 long d = get(i);
1601 if (d != 0)
1602 res[k++] = src[((int)((d - 1) & 0x7fffffffL))];
1603 }
1604 return res;
1605 }
1606
1607 long[] uniqueLongs(int size) {
1608 long[] src = pap.lgetArray();
1609 long[] res = new long[size];
1610 int k = 0;
1611 int n = length();
1612 for (int i = 0; i < n && k < size; ++i) {
1613 long d = get(i);
1614 if (d != 0)
1615 res[k++] = src[((int)((d - 1) & 0x7fffffffL))];
1616 }
1617 return res;
1618 }
1619 }
1620
1621 /**
1622 * Sorter classes based mainly on CilkSort
1623 * <A href="http://supertech.lcs.mit.edu/cilk/"> Cilk</A>:
1624 * Basic algorithm:
1625 * if array size is small, just use a sequential quicksort
1626 * Otherwise:
1627 * 1. Break array in half.
1628 * 2. For each half,
1629 * a. break the half in half (i.e., quarters),
1630 * b. sort the quarters
1631 * c. merge them together
1632 * 3. merge together the two halves.
1633 *
1634 * One reason for splitting in quarters is that this guarantees
1635 * that the final sort is in the main array, not the workspace
1636 * array. (workspace and main swap roles on each subsort step.)
1637 * Leaf-level sorts use a Sequential quicksort, that in turn uses
1638 * insertion sort if under threshold. Otherwise it uses median of
1639 * three to pick pivot, and loops rather than recurses along left
1640 * path.
1641 *
1642 * It is sad but true that sort and merge performance are
1643 * sensitive enough to inner comparison overhead to warrant
1644 * creating 6 versions (not just 3) -- one each for natural
1645 * comparisons vs supplied comparators.
1646 */
1647 static final class FJOSorter extends RecursiveAction {
1648 final Comparator cmp;
1649 final Object[] a; // array to be sorted.
1650 final Object[] w; // workspace for merge
1651 final int origin; // origin of the part of array we deal with
1652 final int n; // Number of elements in (sub)arrays.
1653 final int gran; // split control
1654 FJOSorter(Comparator cmp,
1655 Object[] a, Object[] w, int origin, int n, int gran) {
1656 this.cmp = cmp;
1657 this.a = a; this.w = w; this.origin = origin; this.n = n;
1658 this.gran = gran;
1659 }
1660
1661 public void compute() {
1662 int l = origin;
1663 int g = gran;
1664 if (n > g) {
1665 int h = n >>> 1; // half
1666 int q = n >>> 2; // lower quarter index
1667 int u = h + q; // upper quarter
1668 FJSubSorter ls = new FJSubSorter
1669 (new FJOSorter(cmp, a, w, l, q, g),
1670 new FJOSorter(cmp, a, w, l+q, h-q, g),
1671 new FJOMerger(cmp, a, w, l, q,
1672 l+q, h-q, l, g, null));
1673 FJSubSorter rs = new FJSubSorter
1674 (new FJOSorter(cmp, a, w, l+h, q, g),
1675 new FJOSorter(cmp, a, w, l+u, n-u, g),
1676 new FJOMerger(cmp, a, w, l+h, q,
1677 l+u, n-u, l+h, g, null));
1678 rs.fork();
1679 ls.compute();
1680 if (rs.tryUnfork()) rs.compute(); else rs.join();
1681 new FJOMerger(cmp, w, a, l, h,
1682 l+h, n-h, l, g, null).compute();
1683 }
1684 else
1685 Arrays.sort(a, l, l+n, cmp);
1686 }
1687 }
1688
1689 static final class FJOCSorter extends RecursiveAction {
1690 final Comparable[] a; final Comparable[] w;
1691 final int origin; final int n; final int gran;
1692 FJOCSorter(Comparable[] a, Comparable[] w,
1693 int origin, int n, int gran) {
1694 this.a = a; this.w = w; this.origin = origin; this.n = n;
1695 this.gran = gran;
1696 }
1697 public void compute() {
1698 int l = origin;
1699 int g = gran;
1700 if (n > g) {
1701 int h = n >>> 1;
1702 int q = n >>> 2;
1703 int u = h + q;
1704 FJSubSorter ls = new FJSubSorter
1705 (new FJOCSorter(a, w, l, q, g),
1706 new FJOCSorter(a, w, l+q, h-q, g),
1707 new FJOCMerger(a, w, l, q,
1708 l+q, h-q, l, g, null));
1709 FJSubSorter rs = new FJSubSorter
1710 (new FJOCSorter(a, w, l+h, q, g),
1711 new FJOCSorter(a, w, l+u, n-u, g),
1712 new FJOCMerger(a, w, l+h, q,
1713 l+u, n-u, l+h, g, null));
1714 rs.fork();
1715 ls.compute();
1716 if (rs.tryUnfork()) rs.compute(); else rs.join();
1717 new FJOCMerger(w, a, l, h,
1718 l+h, n-h, l, g, null).compute();
1719 }
1720 else
1721 Arrays.sort(a, l, l+n);
1722 }
1723 }
1724
1725 static final class FJDSorter extends RecursiveAction {
1726 final DoubleComparator cmp; final double[] a; final double[] w;
1727 final int origin; final int n; final int gran;
1728 FJDSorter(DoubleComparator cmp,
1729 double[] a, double[] w, int origin, int n, int gran) {
1730 this.cmp = cmp;
1731 this.a = a; this.w = w; this.origin = origin; this.n = n;
1732 this.gran = gran;
1733 }
1734 public void compute() {
1735 int l = origin;
1736 int g = gran;
1737 if (n > g) {
1738 int h = n >>> 1;
1739 int q = n >>> 2;
1740 int u = h + q;
1741 FJSubSorter ls = new FJSubSorter
1742 (new FJDSorter(cmp, a, w, l, q, g),
1743 new FJDSorter(cmp, a, w, l+q, h-q, g),
1744 new FJDMerger(cmp, a, w, l, q,
1745 l+q, h-q, l, g, null));
1746 FJSubSorter rs = new FJSubSorter
1747 (new FJDSorter(cmp, a, w, l+h, q, g),
1748 new FJDSorter(cmp, a, w, l+u, n-u, g),
1749 new FJDMerger(cmp, a, w, l+h, q,
1750 l+u, n-u, l+h, g, null));
1751 rs.fork();
1752 ls.compute();
1753 if (rs.tryUnfork()) rs.compute(); else rs.join();
1754 new FJDMerger(cmp, w, a, l, h,
1755 l+h, n-h, l, g, null).compute();
1756 }
1757 else
1758 dquickSort(a, cmp, l, l+n-1);
1759 }
1760 }
1761
1762 static final class FJDCSorter extends RecursiveAction {
1763 final double[] a; final double[] w;
1764 final int origin; final int n; final int gran;
1765 FJDCSorter(double[] a, double[] w, int origin,
1766 int n, int gran) {
1767 this.a = a; this.w = w; this.origin = origin; this.n = n;
1768 this.gran = gran;
1769 }
1770 public void compute() {
1771 int l = origin;
1772 int g = gran;
1773 if (n > g) {
1774 int h = n >>> 1;
1775 int q = n >>> 2;
1776 int u = h + q;
1777 FJSubSorter ls = new FJSubSorter
1778 (new FJDCSorter(a, w, l, q, g),
1779 new FJDCSorter(a, w, l+q, h-q, g),
1780 new FJDCMerger(a, w, l, q,
1781 l+q, h-q, l, g, null));
1782 FJSubSorter rs = new FJSubSorter
1783 (new FJDCSorter(a, w, l+h, q, g),
1784 new FJDCSorter(a, w, l+u, n-u, g),
1785 new FJDCMerger(a, w, l+h, q,
1786 l+u, n-u, l+h, g, null));
1787 rs.fork();
1788 ls.compute();
1789 if (rs.tryUnfork()) rs.compute(); else rs.join();
1790 new FJDCMerger(w, a, l, h,
1791 l+h, n-h, l, g, null).compute();
1792 }
1793 else
1794 Arrays.sort(a, l, l+n);
1795 }
1796 }
1797
1798 static final class FJLSorter extends RecursiveAction {
1799 final LongComparator cmp; final long[] a; final long[] w;
1800 final int origin; final int n; final int gran;
1801 FJLSorter(LongComparator cmp,
1802 long[] a, long[] w, int origin, int n, int gran) {
1803 this.cmp = cmp;
1804 this.a = a; this.w = w; this.origin = origin; this.n = n;
1805 this.gran = gran;
1806 }
1807
1808 public void compute() {
1809 int l = origin;
1810 int g = gran;
1811 if (n > g) {
1812 int h = n >>> 1;
1813 int q = n >>> 2;
1814 int u = h + q;
1815 FJSubSorter ls = new FJSubSorter
1816 (new FJLSorter(cmp, a, w, l, q, g),
1817 new FJLSorter(cmp, a, w, l+q, h-q, g),
1818 new FJLMerger(cmp, a, w, l, q,
1819 l+q, h-q, l, g, null));
1820 FJSubSorter rs = new FJSubSorter
1821 (new FJLSorter(cmp, a, w, l+h, q, g),
1822 new FJLSorter(cmp, a, w, l+u, n-u, g),
1823 new FJLMerger(cmp, a, w, l+h, q,
1824 l+u, n-u, l+h, g, null));
1825 rs.fork();
1826 ls.compute();
1827 if (rs.tryUnfork()) rs.compute(); else rs.join();
1828 new FJLMerger(cmp, w, a, l, h,
1829 l+h, n-h, l, g, null).compute();
1830 }
1831 else
1832 lquickSort(a, cmp, l, l+n-1);
1833 }
1834 }
1835
1836 static final class FJLCSorter extends RecursiveAction {
1837 final long[] a; final long[] w;
1838 final int origin; final int n; final int gran;
1839 FJLCSorter(long[] a, long[] w, int origin,
1840 int n, int gran) {
1841 this.a = a; this.w = w; this.origin = origin; this.n = n;
1842 this.gran = gran;
1843 }
1844 public void compute() {
1845 int l = origin;
1846 int g = gran;
1847 if (n > g) {
1848 int h = n >>> 1;
1849 int q = n >>> 2;
1850 int u = h + q;
1851 FJSubSorter ls = new FJSubSorter
1852 (new FJLCSorter(a, w, l, q, g),
1853 new FJLCSorter(a, w, l+q, h-q, g),
1854 new FJLCMerger(a, w, l, q,
1855 l+q, h-q, l, g, null));
1856
1857 FJSubSorter rs = new FJSubSorter
1858 (new FJLCSorter(a, w, l+h, q, g),
1859 new FJLCSorter(a, w, l+u, n-u, g),
1860 new FJLCMerger(a, w, l+h, q,
1861 l+u, n-u, l+h, g, null));
1862 rs.fork();
1863 ls.compute();
1864 if (rs.tryUnfork()) rs.compute(); else rs.join();
1865 new FJLCMerger(w, a, l, h,
1866 l+h, n-h, l, g, null).compute();
1867 }
1868 else
1869 Arrays.sort(a, l, l+n);
1870 }
1871 }
1872
1873 /** Utility class to sort half a partitioned array */
1874 static final class FJSubSorter extends RecursiveAction {
1875 final RecursiveAction left;
1876 final RecursiveAction right;
1877 final RecursiveAction merger;
1878 FJSubSorter(RecursiveAction left, RecursiveAction right,
1879 RecursiveAction merger) {
1880 this.left = left; this.right = right; this.merger = merger;
1881 }
1882 public void compute() {
1883 right.fork();
1884 left.invoke();
1885 right.join();
1886 merger.invoke();
1887 }
1888 }
1889
1890 /**
1891 * Performs merging for FJSorter. If big enough, splits Left
1892 * partition in half; finds the greatest point in Right partition
1893 * less than the beginning of the second half of Left via binary
1894 * search; and then, in parallel, merges left half of Left with
1895 * elements of Right up to split point, and merges right half of
1896 * Left with elements of R past split point. At leaf, it just
1897 * sequentially merges. This is all messy to code; sadly we need
1898 * six versions.
1899 */
1900 static final class FJOMerger extends RecursiveAction {
1901 final Comparator cmp;
1902 final Object[] a; // partitioned array.
1903 final Object[] w; // Output array.
1904 final int lo; // relative origin of left side of a
1905 final int ln; // number of elements on left of a
1906 final int ro; // relative origin of right side of a
1907 final int rn; // number of elements on right of a
1908 final int wo; // origin for output
1909 final int gran;
1910 final FJOMerger next;
1911
1912 FJOMerger(Comparator cmp, Object[] a, Object[] w,
1913 int lo, int ln, int ro, int rn, int wo,
1914 int gran, FJOMerger next) {
1915 this.cmp = cmp;
1916 this.a = a; this.w = w;
1917 this.lo = lo; this.ln = ln;
1918 this.ro = ro; this.rn = rn;
1919 this.wo = wo;
1920 this.gran = gran;
1921 this.next = next;
1922 }
1923
1924 public void compute() {
1925 // spawn right subtasks
1926 FJOMerger rights = null;
1927 int nleft = ln;
1928 int nright = rn;
1929 while (nleft > gran) {
1930 int lh = nleft >>> 1;
1931 int splitIndex = lo + lh;
1932 Object split = a[splitIndex];
1933 // binary search r for split
1934 int rl = 0;
1935 int rh = nright;
1936 while (rl < rh) {
1937 int mid = (rl + rh) >>> 1;
1938 if (cmp.compare(split, a[ro + mid]) <= 0)
1939 rh = mid;
1940 else
1941 rl = mid + 1;
1942 }
1943 (rights = new FJOMerger
1944 (cmp, a, w, splitIndex, nleft-lh, ro+rh,
1945 nright-rh, wo+lh+rh, gran, rights)).fork();
1946 nleft = lh;
1947 nright = rh;
1948 }
1949
1950 // sequentially merge
1951 int l = lo;
1952 int lFence = lo + nleft;
1953 int r = ro;
1954 int rFence = ro + nright;
1955 int k = wo;
1956 while (l < lFence && r < rFence) {
1957 Object al = a[l];
1958 Object ar = a[r];
1959 Object t;
1960 if (cmp.compare(al, ar) <= 0) {++l; t=al;} else {++r; t=ar;}
1961 w[k++] = t;
1962 }
1963 while (l < lFence)
1964 w[k++] = a[l++];
1965 while (r < rFence)
1966 w[k++] = a[r++];
1967
1968 // join subtasks
1969 while (rights != null) {
1970 if (rights.tryUnfork())
1971 rights.compute();
1972 else
1973 rights.join();
1974 rights = rights.next;
1975 }
1976 }
1977 }
1978
1979 static final class FJOCMerger extends RecursiveAction {
1980 final Comparable[] a; final Comparable[] w;
1981 final int lo; final int ln; final int ro; final int rn; final int wo;
1982 final int gran;
1983 final FJOCMerger next;
1984 FJOCMerger(Comparable[] a, Comparable[] w, int lo,
1985 int ln, int ro, int rn, int wo,
1986 int gran, FJOCMerger next) {
1987 this.a = a; this.w = w;
1988 this.lo = lo; this.ln = ln; this.ro = ro; this.rn = rn;
1989 this.wo = wo;
1990 this.gran = gran;
1991 this.next = next;
1992 }
1993
1994 public void compute() {
1995 FJOCMerger rights = null;
1996 int nleft = ln;
1997 int nright = rn;
1998 while (nleft > gran) {
1999 int lh = nleft >>> 1;
2000 int splitIndex = lo + lh;
2001 Comparable split = a[splitIndex];
2002 int rl = 0;
2003 int rh = nright;
2004 while (rl < rh) {
2005 int mid = (rl + rh) >>> 1;
2006 if (split.compareTo(a[ro + mid]) <= 0)
2007 rh = mid;
2008 else
2009 rl = mid + 1;
2010 }
2011 (rights = new FJOCMerger
2012 (a, w, splitIndex, nleft-lh, ro+rh,
2013 nright-rh, wo+lh+rh, gran, rights)).fork();
2014 nleft = lh;
2015 nright = rh;
2016 }
2017
2018 int l = lo;
2019 int lFence = lo + nleft;
2020 int r = ro;
2021 int rFence = ro + nright;
2022 int k = wo;
2023 while (l < lFence && r < rFence) {
2024 Comparable al = a[l];
2025 Comparable ar = a[r];
2026 Comparable t;
2027 if (al.compareTo(ar) <= 0) {++l; t=al;} else {++r; t=ar; }
2028 w[k++] = t;
2029 }
2030 while (l < lFence)
2031 w[k++] = a[l++];
2032 while (r < rFence)
2033 w[k++] = a[r++];
2034 while (rights != null) {
2035 if (rights.tryUnfork())
2036 rights.compute();
2037 else
2038 rights.join();
2039 rights = rights.next;
2040 }
2041 }
2042 }
2043
2044 static final class FJDMerger extends RecursiveAction {
2045 final DoubleComparator cmp; final double[] a; final double[] w;
2046 final int lo; final int ln; final int ro; final int rn; final int wo;
2047 final int gran;
2048 final FJDMerger next;
2049 FJDMerger(DoubleComparator cmp, double[] a, double[] w,
2050 int lo, int ln, int ro, int rn, int wo,
2051 int gran, FJDMerger next) {
2052 this.cmp = cmp;
2053 this.a = a; this.w = w;
2054 this.lo = lo; this.ln = ln;
2055 this.ro = ro; this.rn = rn;
2056 this.wo = wo;
2057 this.gran = gran;
2058 this.next = next;
2059 }
2060 public void compute() {
2061 FJDMerger rights = null;
2062 int nleft = ln;
2063 int nright = rn;
2064 while (nleft > gran) {
2065 int lh = nleft >>> 1;
2066 int splitIndex = lo + lh;
2067 double split = a[splitIndex];
2068 int rl = 0;
2069 int rh = nright;
2070 while (rl < rh) {
2071 int mid = (rl + rh) >>> 1;
2072 if (cmp.compare(split, a[ro + mid]) <= 0)
2073 rh = mid;
2074 else
2075 rl = mid + 1;
2076 }
2077 (rights = new FJDMerger
2078 (cmp, a, w, splitIndex, nleft-lh, ro+rh,
2079 nright-rh, wo+lh+rh, gran, rights)).fork();
2080 nleft = lh;
2081 nright = rh;
2082 }
2083
2084 int l = lo;
2085 int lFence = lo + nleft;
2086 int r = ro;
2087 int rFence = ro + nright;
2088 int k = wo;
2089 while (l < lFence && r < rFence) {
2090 double al = a[l];
2091 double ar = a[r];
2092 double t;
2093 if (cmp.compare(al, ar) <= 0) {++l; t=al;} else {++r; t=ar; }
2094 w[k++] = t;
2095 }
2096 while (l < lFence)
2097 w[k++] = a[l++];
2098 while (r < rFence)
2099 w[k++] = a[r++];
2100 while (rights != null) {
2101 if (rights.tryUnfork())
2102 rights.compute();
2103 else
2104 rights.join();
2105 rights = rights.next;
2106 }
2107 }
2108 }
2109
2110 static final class FJDCMerger extends RecursiveAction {
2111 final double[] a; final double[] w;
2112 final int lo; final int ln; final int ro; final int rn; final int wo;
2113 final int gran;
2114 final FJDCMerger next;
2115 FJDCMerger(double[] a, double[] w, int lo,
2116 int ln, int ro, int rn, int wo,
2117 int gran, FJDCMerger next) {
2118 this.a = a; this.w = w;
2119 this.lo = lo; this.ln = ln;
2120 this.ro = ro; this.rn = rn;
2121 this.wo = wo;
2122 this.gran = gran;
2123 this.next = next;
2124 }
2125 public void compute() {
2126 FJDCMerger rights = null;
2127 int nleft = ln;
2128 int nright = rn;
2129 while (nleft > gran) {
2130 int lh = nleft >>> 1;
2131 int splitIndex = lo + lh;
2132 double split = a[splitIndex];
2133 int rl = 0;
2134 int rh = nright;
2135 while (rl < rh) {
2136 int mid = (rl + rh) >>> 1;
2137 if (split <= a[ro + mid])
2138 rh = mid;
2139 else
2140 rl = mid + 1;
2141 }
2142 (rights = new FJDCMerger
2143 (a, w, splitIndex, nleft-lh, ro+rh,
2144 nright-rh, wo+lh+rh, gran, rights)).fork();
2145 nleft = lh;
2146 nright = rh;
2147 }
2148
2149 int l = lo;
2150 int lFence = lo + nleft;
2151 int r = ro;
2152 int rFence = ro + nright;
2153 int k = wo;
2154 while (l < lFence && r < rFence) {
2155 double al = a[l];
2156 double ar = a[r];
2157 double t;
2158 if (al <= ar) {++l; t=al;} else {++r; t=ar; }
2159 w[k++] = t;
2160 }
2161 while (l < lFence)
2162 w[k++] = a[l++];
2163 while (r < rFence)
2164 w[k++] = a[r++];
2165 while (rights != null) {
2166 if (rights.tryUnfork())
2167 rights.compute();
2168 else
2169 rights.join();
2170 rights = rights.next;
2171 }
2172 }
2173 }
2174
2175 static final class FJLMerger extends RecursiveAction {
2176 final LongComparator cmp; final long[] a; final long[] w;
2177 final int lo; final int ln; final int ro; final int rn; final int wo;
2178 final int gran;
2179 final FJLMerger next;
2180 FJLMerger(LongComparator cmp, long[] a, long[] w,
2181 int lo, int ln, int ro, int rn, int wo,
2182 int gran, FJLMerger next) {
2183 this.cmp = cmp;
2184 this.a = a; this.w = w;
2185 this.lo = lo; this.ln = ln;
2186 this.ro = ro; this.rn = rn;
2187 this.wo = wo;
2188 this.gran = gran;
2189 this.next = next;
2190 }
2191 public void compute() {
2192 FJLMerger rights = null;
2193 int nleft = ln;
2194 int nright = rn;
2195 while (nleft > gran) {
2196 int lh = nleft >>> 1;
2197 int splitIndex = lo + lh;
2198 long split = a[splitIndex];
2199 int rl = 0;
2200 int rh = nright;
2201 while (rl < rh) {
2202 int mid = (rl + rh) >>> 1;
2203 if (cmp.compare(split, a[ro + mid]) <= 0)
2204 rh = mid;
2205 else
2206 rl = mid + 1;
2207 }
2208 (rights = new FJLMerger
2209 (cmp, a, w, splitIndex, nleft-lh, ro+rh,
2210 nright-rh, wo+lh+rh, gran, rights)).fork();
2211 nleft = lh;
2212 nright = rh;
2213 }
2214
2215 int l = lo;
2216 int lFence = lo + nleft;
2217 int r = ro;
2218 int rFence = ro + nright;
2219 int k = wo;
2220 while (l < lFence && r < rFence) {
2221 long al = a[l];
2222 long ar = a[r];
2223 long t;
2224 if (cmp.compare(al, ar) <= 0) {++l; t=al;} else {++r; t=ar;}
2225 w[k++] = t;
2226 }
2227 while (l < lFence)
2228 w[k++] = a[l++];
2229 while (r < rFence)
2230 w[k++] = a[r++];
2231 while (rights != null) {
2232 if (rights.tryUnfork())
2233 rights.compute();
2234 else
2235 rights.join();
2236 rights = rights.next;
2237 }
2238 }
2239 }
2240
2241 static final class FJLCMerger extends RecursiveAction {
2242 final long[] a; final long[] w;
2243 final int lo; final int ln; final int ro; final int rn; final int wo;
2244 final int gran;
2245 final FJLCMerger next;
2246 FJLCMerger(long[] a, long[] w, int lo,
2247 int ln, int ro, int rn, int wo,
2248 int gran, FJLCMerger next) {
2249 this.a = a; this.w = w;
2250 this.lo = lo; this.ln = ln;
2251 this.ro = ro; this.rn = rn;
2252 this.wo = wo;
2253 this.gran = gran;
2254 this.next = next;
2255 }
2256 public void compute() {
2257 FJLCMerger rights = null;
2258 int nleft = ln;
2259 int nright = rn;
2260 while (nleft > gran) {
2261 int lh = nleft >>> 1;
2262 int splitIndex = lo + lh;
2263 long split = a[splitIndex];
2264 int rl = 0;
2265 int rh = nright;
2266 while (rl < rh) {
2267 int mid = (rl + rh) >>> 1;
2268 if (split <= a[ro + mid])
2269 rh = mid;
2270 else
2271 rl = mid + 1;
2272 }
2273 (rights = new FJLCMerger
2274 (a, w, splitIndex, nleft-lh, ro+rh,
2275 nright-rh, wo+lh+rh, gran, rights)).fork();
2276 nleft = lh;
2277 nright = rh;
2278 }
2279
2280 int l = lo;
2281 int lFence = lo + nleft;
2282 int r = ro;
2283 int rFence = ro + nright;
2284 int k = wo;
2285 while (l < lFence && r < rFence) {
2286 long al = a[l];
2287 long ar = a[r];
2288 long t;
2289 if (al <= ar) {++l; t=al;} else {++r; t = ar;}
2290 w[k++] = t;
2291 }
2292 while (l < lFence)
2293 w[k++] = a[l++];
2294 while (r < rFence)
2295 w[k++] = a[r++];
2296 while (rights != null) {
2297 if (rights.tryUnfork())
2298 rights.compute();
2299 else
2300 rights.join();
2301 rights = rights.next;
2302 }
2303 }
2304 }
2305
2306 /** Cutoff for when to use insertion-sort instead of quicksort */
2307 static final int INSERTION_SORT_THRESHOLD = 8;
2308
2309 // versions of quicksort with comparators
2310
2311
2312 static void dquickSort(double[] a, DoubleComparator cmp, int lo, int hi) {
2313 for (;;) {
2314 if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2315 for (int i = lo + 1; i <= hi; i++) {
2316 double t = a[i];
2317 int j = i - 1;
2318 while (j >= lo && cmp.compare(t, a[j]) < 0) {
2319 a[j+1] = a[j];
2320 --j;
2321 }
2322 a[j+1] = t;
2323 }
2324 return;
2325 }
2326
2327 int mid = (lo + hi) >>> 1;
2328 if (cmp.compare(a[lo], a[mid]) > 0) {
2329 double t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2330 }
2331 if (cmp.compare(a[mid], a[hi]) > 0) {
2332 double t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2333 if (cmp.compare(a[lo], a[mid]) > 0) {
2334 double u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2335 }
2336 }
2337
2338 double pivot = a[mid];
2339 int left = lo+1;
2340 int right = hi-1;
2341 boolean sameLefts = true;
2342 for (;;) {
2343 while (cmp.compare(pivot, a[right]) < 0)
2344 --right;
2345 int c;
2346 while (left < right &&
2347 (c = cmp.compare(pivot, a[left])) >= 0) {
2348 if (c != 0)
2349 sameLefts = false;
2350 ++left;
2351 }
2352 if (left < right) {
2353 double t = a[left]; a[left] = a[right]; a[right] = t;
2354 --right;
2355 }
2356 else break;
2357 }
2358
2359 if (sameLefts && right == hi - 1)
2360 return;
2361 if (left - lo <= hi - right) {
2362 dquickSort(a, cmp, lo, left);
2363 lo = left + 1;
2364 }
2365 else {
2366 dquickSort(a, cmp, right, hi);
2367 hi = left;
2368 }
2369 }
2370 }
2371
2372 static void lquickSort(long[] a, LongComparator cmp, int lo, int hi) {
2373 for (;;) {
2374 if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2375 for (int i = lo + 1; i <= hi; i++) {
2376 long t = a[i];
2377 int j = i - 1;
2378 while (j >= lo && cmp.compare(t, a[j]) < 0) {
2379 a[j+1] = a[j];
2380 --j;
2381 }
2382 a[j+1] = t;
2383 }
2384 return;
2385 }
2386
2387 int mid = (lo + hi) >>> 1;
2388 if (cmp.compare(a[lo], a[mid]) > 0) {
2389 long t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2390 }
2391 if (cmp.compare(a[mid], a[hi]) > 0) {
2392 long t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2393 if (cmp.compare(a[lo], a[mid]) > 0) {
2394 long u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2395 }
2396 }
2397
2398 long pivot = a[mid];
2399 int left = lo+1;
2400 int right = hi-1;
2401 boolean sameLefts = true;
2402 for (;;) {
2403 while (cmp.compare(pivot, a[right]) < 0)
2404 --right;
2405 int c;
2406 while (left < right &&
2407 (c = cmp.compare(pivot, a[left])) >= 0) {
2408 if (c != 0)
2409 sameLefts = false;
2410 ++left;
2411 }
2412 if (left < right) {
2413 long t = a[left]; a[left] = a[right]; a[right] = t;
2414 --right;
2415 }
2416 else break;
2417 }
2418
2419 if (sameLefts && right == hi - 1)
2420 return;
2421 if (left - lo <= hi - right) {
2422 lquickSort(a, cmp, lo, left);
2423 lo = left + 1;
2424 }
2425 else {
2426 lquickSort(a, cmp, right, hi);
2427 hi = left;
2428 }
2429 }
2430 }
2431
2432 /**
2433 * Cumulative scan
2434 *
2435 * A basic version of scan is straightforward.
2436 * Keep dividing by two to threshold segment size, and then:
2437 * Pass 1: Create tree of partial sums for each segment
2438 * Pass 2: For each segment, cumulate with offset of left sibling
2439 * See G. Blelloch's http://www.cs.cmu.edu/~scandal/alg/scan.html
2440 *
2441 * This version improves performance within FJ framework mainly by
2442 * allowing second pass of ready left-hand sides to proceed even
2443 * if some right-hand side first passes are still executing. It
2444 * also combines first and second pass for leftmost segment, and
2445 * for cumulate (not precumulate) also skips first pass for
2446 * rightmost segment (whose result is not needed for second pass).
2447 *
2448 * To manage this, it relies on "phase" phase/state control field
2449 * maintaining bits CUMULATE, SUMMED, and FINISHED. CUMULATE is
2450 * main phase bit. When false, segments compute only their sum.
2451 * When true, they cumulate array elements. CUMULATE is set at
2452 * root at beginning of second pass and then propagated down. But
2453 * it may also be set earlier for subtrees with lo==origin (the
2454 * left spine of tree). SUMMED is a one bit join count. For leafs,
2455 * set when summed. For internal nodes, becomes true when one
2456 * child is summed. When second child finishes summing, it then
2457 * moves up tree to trigger cumulate phase. FINISHED is also a one
2458 * bit join count. For leafs, it is set when cumulated. For
2459 * internal nodes, it becomes true when one child is cumulated.
2460 * When second child finishes cumulating, it then moves up tree,
2461 * executing complete() at the root.
2462 *
2463 * This class maintains only the basic control logic. Subclasses
2464 * maintain the "in" and "out" fields, and *Ops classes perform
2465 * computations.
2466 */
2467 abstract static class FJScan extends ForkJoinTask<Void> {
2468 static final short CUMULATE = (short)1;
2469 static final short SUMMED = (short)2;
2470 static final short FINISHED = (short)4;
2471
2472 final FJScan parent;
2473 final FJScanOp op;
2474 FJScan left, right;
2475 volatile int phase; // phase/state
2476 final int lo;
2477 final int hi;
2478
2479 static final AtomicIntegerFieldUpdater<FJScan> phaseUpdater =
2480 AtomicIntegerFieldUpdater.newUpdater(FJScan.class, "phase");
2481
2482 FJScan(FJScan parent, FJScanOp op, int lo, int hi) {
2483 this.parent = parent;
2484 this.op = op;
2485 this.lo = lo;
2486 this.hi = hi;
2487 }
2488
2489 public final Void getRawResult() { return null; }
2490 protected final void setRawResult(Void mustBeNull) { }
2491
2492 /** Returns true if can CAS CUMULATE bit true */
2493 final boolean transitionToCumulate() {
2494 int c;
2495 while (((c = phase) & CUMULATE) == 0)
2496 if (phaseUpdater.compareAndSet(this, c, c | CUMULATE))
2497 return true;
2498 return false;
2499 }
2500
2501 public final boolean exec() {
2502 if (hi - lo > op.threshold) {
2503 if (left == null) { // first pass
2504 int mid = (lo + hi) >>> 1;
2505 left = op.newSubtask(this, lo, mid);
2506 right = op.newSubtask(this, mid, hi);
2507 }
2508
2509 boolean cumulate = (phase & CUMULATE) != 0;
2510 if (cumulate)
2511 op.pushDown(this, left, right);
2512
2513 if (!cumulate || right.transitionToCumulate())
2514 right.fork();
2515 if (!cumulate || left.transitionToCumulate())
2516 left.exec();
2517 }
2518 else {
2519 int cb;
2520 for (;;) { // Establish action: sum, cumulate, or both
2521 int b = phase;
2522 if ((b & FINISHED) != 0) // already done
2523 return false;
2524 if ((b & CUMULATE) != 0)
2525 cb = FINISHED;
2526 else if (lo == op.origin) // combine leftmost
2527 cb = (SUMMED|FINISHED);
2528 else
2529 cb = SUMMED;
2530 if (phaseUpdater.compareAndSet(this, b, b|cb))
2531 break;
2532 }
2533
2534 if (cb == SUMMED)
2535 op.sumLeaf(lo, hi, this);
2536 else if (cb == FINISHED)
2537 op.cumulateLeaf(lo, hi, this);
2538 else if (cb == (SUMMED|FINISHED))
2539 op.sumAndCumulateLeaf(lo, hi, this);
2540
2541 // propagate up
2542 FJScan ch = this;
2543 FJScan par = parent;
2544 for (;;) {
2545 if (par == null) {
2546 if ((cb & FINISHED) != 0)
2547 ch.complete(null);
2548 break;
2549 }
2550 int pb = par.phase;
2551 if ((pb & cb & FINISHED) != 0) { // both finished
2552 ch = par;
2553 par = par.parent;
2554 }
2555 else if ((pb & cb & SUMMED) != 0) { // both summed
2556 op.pushUp(par, par.left, par.right);
2557 int refork =
2558 ((pb & CUMULATE) == 0 &&
2559 par.lo == op.origin) ? CUMULATE : 0;
2560 int nextPhase = pb|cb|refork;
2561 if (pb == nextPhase ||
2562 phaseUpdater.compareAndSet(par, pb, nextPhase)) {
2563 if (refork != 0)
2564 par.fork();
2565 cb = SUMMED; // drop finished bit
2566 ch = par;
2567 par = par.parent;
2568 }
2569 }
2570 else if (phaseUpdater.compareAndSet(par, pb, pb|cb))
2571 break;
2572 }
2573 }
2574 return false;
2575 }
2576
2577 // no-op versions of methods to get/set in/out, overridden as
2578 // appropriate in subclasses
2579 Object ogetIn() { return null; }
2580 Object ogetOut() { return null; }
2581 void rsetIn(Object x) { }
2582 void rsetOut(Object x) { }
2583
2584 double dgetIn() { return 0; }
2585 double dgetOut() { return 0; }
2586 void dsetIn(double x) { }
2587 void dsetOut(double x) { }
2588
2589 long lgetIn() { return 0; }
2590 long lgetOut() { return 0; }
2591 void lsetIn(long x) { }
2592 void lsetOut(long x) { }
2593 }
2594
2595 // Subclasses adding in/out fields of the appropriate type
2596 static final class FJOScan extends FJScan {
2597 Object in;
2598 Object out;
2599 FJOScan(FJScan parent, FJScanOp op, int lo, int hi) {
2600 super(parent, op, lo, hi);
2601 }
2602 Object ogetIn() { return in; }
2603 Object ogetOut() { return out; }
2604 void rsetIn(Object x) { in = x; }
2605 void rsetOut(Object x) { out = x; }
2606 }
2607
2608 static final class FJDScan extends FJScan {
2609 double in;
2610 double out;
2611 FJDScan(FJScan parent, FJScanOp op, int lo, int hi) {
2612 super(parent, op, lo, hi);
2613 }
2614 double dgetIn() { return in; }
2615 double dgetOut() { return out; }
2616 void dsetIn(double x) { in = x; }
2617 void dsetOut(double x) { out = x; }
2618
2619 }
2620
2621 static final class FJLScan extends FJScan {
2622 long in;
2623 long out;
2624 FJLScan(FJScan parent, FJScanOp op, int lo, int hi) {
2625 super(parent, op, lo, hi);
2626 }
2627 long lgetIn() { return in; }
2628 long lgetOut() { return out; }
2629 void lsetIn(long x) { in = x; }
2630 void lsetOut(long x) { out = x; }
2631 }
2632
2633 /**
2634 * Computational operations for FJScan
2635 */
2636 abstract static class FJScanOp {
2637 final int threshold;
2638 final int origin;
2639 final int fence;
2640 FJScanOp(AbstractParallelAnyArray pap) {
2641 this.origin = pap.origin;
2642 this.fence = pap.fence;
2643 this.threshold = pap.computeThreshold();
2644 }
2645 abstract void pushDown(FJScan parent, FJScan left, FJScan right);
2646 abstract void pushUp(FJScan parent, FJScan left, FJScan right);
2647 abstract void sumLeaf(int lo, int hi, FJScan f);
2648 abstract void cumulateLeaf(int lo, int hi, FJScan f);
2649 abstract void sumAndCumulateLeaf(int lo, int hi, FJScan f);
2650 abstract FJScan newSubtask(FJScan parent, int lo, int hi);
2651 }
2652
2653 abstract static class FJOScanOp extends FJScanOp {
2654 final Object[] array;
2655 final Reducer reducer;
2656 final Object base;
2657 FJOScanOp(AbstractParallelAnyArray.OPap pap,
2658 Reducer reducer, Object base) {
2659 super(pap);
2660 this.array = pap.array;
2661 this.reducer = reducer;
2662 this.base = base;
2663 }
2664 final void pushDown(FJScan parent, FJScan left, FJScan right) {
2665 Object pin = parent.ogetIn();
2666 left.rsetIn(pin);
2667 right.rsetIn(reducer.op(pin, left.ogetOut()));
2668 }
2669 final void pushUp(FJScan parent, FJScan left, FJScan right) {
2670 parent.rsetOut(reducer.op(left.ogetOut(),
2671 right.ogetOut()));
2672 }
2673 final FJScan newSubtask(FJScan parent, int lo, int hi) {
2674 FJOScan f = new FJOScan(parent, this, lo, hi);
2675 f.in = base;
2676 f.out = base;
2677 return f;
2678 }
2679 }
2680
2681 static final class FJOCumulateOp extends FJOScanOp {
2682 FJOCumulateOp(AbstractParallelAnyArray.OPap pap,
2683 Reducer reducer, Object base) {
2684 super(pap, reducer, base);
2685 }
2686 void sumLeaf(int lo, int hi, FJScan f) {
2687 Object sum = base;
2688 if (hi != fence) {
2689 Object[] arr = array;
2690 for (int i = lo; i < hi; ++i)
2691 sum = reducer.op(sum, arr[i]);
2692 }
2693 f.rsetOut(sum);
2694 }
2695 void cumulateLeaf(int lo, int hi, FJScan f) {
2696 Object[] arr = array;
2697 Object sum = f.ogetIn();
2698 for (int i = lo; i < hi; ++i)
2699 arr[i] = sum = reducer.op(sum, arr[i]);
2700 }
2701 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2702 Object[] arr = array;
2703 Object sum = base;
2704 for (int i = lo; i < hi; ++i)
2705 arr[i] = sum = reducer.op(sum, arr[i]);
2706 f.rsetOut(sum);
2707 }
2708 }
2709
2710 static final class FJOPrecumulateOp extends FJOScanOp {
2711 FJOPrecumulateOp(AbstractParallelAnyArray.OPap pap,
2712 Reducer reducer, Object base) {
2713 super(pap, reducer, base);
2714 }
2715 void sumLeaf(int lo, int hi, FJScan f) {
2716 Object[] arr = array;
2717 Object sum = base;
2718 for (int i = lo; i < hi; ++i)
2719 sum = reducer.op(sum, arr[i]);
2720 f.rsetOut(sum);
2721 }
2722 void cumulateLeaf(int lo, int hi, FJScan f) {
2723 Object[] arr = array;
2724 Object sum = f.ogetIn();
2725 for (int i = lo; i < hi; ++i) {
2726 Object x = arr[i];
2727 arr[i] = sum;
2728 sum = reducer.op(sum, x);
2729 }
2730 }
2731 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2732 Object[] arr = array;
2733 Object sum = base;
2734 for (int i = lo; i < hi; ++i) {
2735 Object x = arr[i];
2736 arr[i] = sum;
2737 sum = reducer.op(sum, x);
2738 }
2739 f.rsetOut(sum);
2740 }
2741 }
2742
2743 abstract static class FJDScanOp extends FJScanOp {
2744 final double[] array;
2745 final DoubleReducer reducer;
2746 final double base;
2747 FJDScanOp(AbstractParallelAnyArray.DPap pap,
2748 DoubleReducer reducer, double base) {
2749 super(pap);
2750 this.array = pap.array;
2751 this.reducer = reducer;
2752 this.base = base;
2753 }
2754 final void pushDown(FJScan parent, FJScan left, FJScan right) {
2755 double pin = parent.dgetIn();
2756 left.dsetIn(pin);
2757 right.dsetIn(reducer.op(pin, left.dgetOut()));
2758 }
2759 final void pushUp(FJScan parent, FJScan left, FJScan right) {
2760 parent.dsetOut(reducer.op(left.dgetOut(),
2761 right.dgetOut()));
2762 }
2763 final FJScan newSubtask(FJScan parent, int lo, int hi) {
2764 FJDScan f = new FJDScan(parent, this, lo, hi);
2765 f.in = base;
2766 f.out = base;
2767 return f;
2768 }
2769 }
2770
2771 static final class FJDCumulateOp extends FJDScanOp {
2772 FJDCumulateOp(AbstractParallelAnyArray.DPap pap,
2773 DoubleReducer reducer, double base) {
2774 super(pap, reducer, base);
2775 }
2776 void sumLeaf(int lo, int hi, FJScan f) {
2777 double sum = base;
2778 if (hi != fence) {
2779 double[] arr = array;
2780 for (int i = lo; i < hi; ++i)
2781 sum = reducer.op(sum, arr[i]);
2782 }
2783 f.dsetOut(sum);
2784 }
2785 void cumulateLeaf(int lo, int hi, FJScan f) {
2786 double[] arr = array;
2787 double sum = f.dgetIn();
2788 for (int i = lo; i < hi; ++i)
2789 arr[i] = sum = reducer.op(sum, arr[i]);
2790 }
2791 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2792 double[] arr = array;
2793 double sum = base;
2794 for (int i = lo; i < hi; ++i)
2795 arr[i] = sum = reducer.op(sum, arr[i]);
2796 f.dsetOut(sum);
2797 }
2798 }
2799
2800 static final class FJDPrecumulateOp extends FJDScanOp {
2801 FJDPrecumulateOp(AbstractParallelAnyArray.DPap pap,
2802 DoubleReducer reducer, double base) {
2803 super(pap, reducer, base);
2804 }
2805 void sumLeaf(int lo, int hi, FJScan f) {
2806 double[] arr = array;
2807 double sum = base;
2808 for (int i = lo; i < hi; ++i)
2809 sum = reducer.op(sum, arr[i]);
2810 f.dsetOut(sum);
2811 }
2812 void cumulateLeaf(int lo, int hi, FJScan f) {
2813 double[] arr = array;
2814 double sum = f.dgetIn();
2815 for (int i = lo; i < hi; ++i) {
2816 double x = arr[i];
2817 arr[i] = sum;
2818 sum = reducer.op(sum, x);
2819 }
2820 }
2821 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2822 double[] arr = array;
2823 double sum = base;
2824 for (int i = lo; i < hi; ++i) {
2825 double x = arr[i];
2826 arr[i] = sum;
2827 sum = reducer.op(sum, x);
2828 }
2829 f.dsetOut(sum);
2830 }
2831 }
2832
2833 abstract static class FJLScanOp extends FJScanOp {
2834 final long[] array;
2835 final LongReducer reducer;
2836 final long base;
2837 FJLScanOp(AbstractParallelAnyArray.LPap pap,
2838 LongReducer reducer, long base) {
2839 super(pap);
2840 this.array = pap.array;
2841 this.reducer = reducer;
2842 this.base = base;
2843 }
2844 final void pushDown(FJScan parent, FJScan left, FJScan right) {
2845 long pin = parent.lgetIn();
2846 left.lsetIn(pin);
2847 right.lsetIn(reducer.op(pin, left.lgetOut()));
2848 }
2849 final void pushUp(FJScan parent, FJScan left, FJScan right) {
2850 parent.lsetOut(reducer.op(left.lgetOut(),
2851 right.lgetOut()));
2852 }
2853 final FJScan newSubtask(FJScan parent, int lo, int hi) {
2854 FJLScan f = new FJLScan(parent, this, lo, hi);
2855 f.in = base;
2856 f.out = base;
2857 return f;
2858 }
2859 }
2860
2861 static final class FJLCumulateOp extends FJLScanOp {
2862 FJLCumulateOp(AbstractParallelAnyArray.LPap pap,
2863 LongReducer reducer, long base) {
2864 super(pap, reducer, base);
2865 }
2866 void sumLeaf(int lo, int hi, FJScan f) {
2867 long sum = base;
2868 if (hi != fence) {
2869 long[] arr = array;
2870 for (int i = lo; i < hi; ++i)
2871 sum = reducer.op(sum, arr[i]);
2872 }
2873 f.lsetOut(sum);
2874 }
2875 void cumulateLeaf(int lo, int hi, FJScan f) {
2876 long[] arr = array;
2877 long sum = f.lgetIn();
2878 for (int i = lo; i < hi; ++i)
2879 arr[i] = sum = reducer.op(sum, arr[i]);
2880 }
2881 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2882 long[] arr = array;
2883 long sum = base;
2884 for (int i = lo; i < hi; ++i)
2885 arr[i] = sum = reducer.op(sum, arr[i]);
2886 f.lsetOut(sum);
2887 }
2888 }
2889
2890 static final class FJLPrecumulateOp extends FJLScanOp {
2891 FJLPrecumulateOp(AbstractParallelAnyArray.LPap pap,
2892 LongReducer reducer, long base) {
2893 super(pap, reducer, base);
2894 }
2895 void sumLeaf(int lo, int hi, FJScan f) {
2896 long[] arr = array;
2897 long sum = base;
2898 for (int i = lo; i < hi; ++i)
2899 sum = reducer.op(sum, arr[i]);
2900 f.lsetOut(sum);
2901 }
2902 void cumulateLeaf(int lo, int hi, FJScan f) {
2903 long[] arr = array;
2904 long sum = f.lgetIn();
2905 for (int i = lo; i < hi; ++i) {
2906 long x = arr[i];
2907 arr[i] = sum;
2908 sum = reducer.op(sum, x);
2909 }
2910 }
2911 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2912 long[] arr = array;
2913 long sum = base;
2914 for (int i = lo; i < hi; ++i) {
2915 long x = arr[i];
2916 arr[i] = sum;
2917 sum = reducer.op(sum, x);
2918 }
2919 f.lsetOut(sum);
2920 }
2921 }
2922
2923 // specialized versions for plus
2924
2925 abstract static class FJDScanPlusOp extends FJScanOp {
2926 final double[] array;
2927 FJDScanPlusOp(AbstractParallelAnyArray.DPap pap) {
2928 super(pap);
2929 this.array = pap.array;
2930 }
2931 final void pushDown(FJScan parent, FJScan left, FJScan right) {
2932 double pin = parent.dgetIn();
2933 left.dsetIn(pin);
2934 right.dsetIn(pin + left.dgetOut());
2935 }
2936 final void pushUp(FJScan parent, FJScan left, FJScan right) {
2937 parent.dsetOut(left.dgetOut() + right.dgetOut());
2938 }
2939 final FJScan newSubtask(FJScan parent, int lo, int hi) {
2940 FJDScan f = new FJDScan(parent, this, lo, hi);
2941 f.in = 0.0;
2942 f.out = 0.0;
2943 return f;
2944 }
2945 }
2946
2947 static final class FJDCumulatePlusOp extends FJDScanPlusOp {
2948 FJDCumulatePlusOp(AbstractParallelAnyArray.DPap pap) {
2949 super(pap);
2950 }
2951 void sumLeaf(int lo, int hi, FJScan f) {
2952 double sum = 0.0;
2953 if (hi != fence) {
2954 double[] arr = array;
2955 for (int i = lo; i < hi; ++i)
2956 sum += arr[i];
2957 }
2958 f.dsetOut(sum);
2959 }
2960 void cumulateLeaf(int lo, int hi, FJScan f) {
2961 double[] arr = array;
2962 double sum = f.dgetIn();
2963 for (int i = lo; i < hi; ++i)
2964 arr[i] = sum += arr[i];
2965 }
2966 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2967 double[] arr = array;
2968 double sum = 0.0;
2969 for (int i = lo; i < hi; ++i)
2970 arr[i] = sum += arr[i];
2971 f.dsetOut(sum);
2972 }
2973 }
2974
2975 static final class FJDPrecumulatePlusOp extends FJDScanPlusOp {
2976 FJDPrecumulatePlusOp(AbstractParallelAnyArray.DPap pap) {
2977 super(pap);
2978 }
2979 void sumLeaf(int lo, int hi, FJScan f) {
2980 double[] arr = array;
2981 double sum = 0.0;
2982 for (int i = lo; i < hi; ++i)
2983 sum += arr[i];
2984 f.dsetOut(sum);
2985 }
2986 void cumulateLeaf(int lo, int hi, FJScan f) {
2987 double[] arr = array;
2988 double sum = f.dgetIn();
2989 for (int i = lo; i < hi; ++i) {
2990 double x = arr[i];
2991 arr[i] = sum;
2992 sum += x;
2993 }
2994 }
2995 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2996 double[] arr = array;
2997 double sum = 0.0;
2998 for (int i = lo; i < hi; ++i) {
2999 double x = arr[i];
3000 arr[i] = sum;
3001 sum += x;
3002 }
3003 f.dsetOut(sum);
3004 }
3005 }
3006
3007 abstract static class FJLScanPlusOp extends FJScanOp {
3008 final long[] array;
3009 FJLScanPlusOp(AbstractParallelAnyArray.LPap pap) {
3010 super(pap);
3011 this.array = pap.array;
3012 }
3013 final void pushDown(FJScan parent, FJScan left, FJScan right) {
3014 long pin = parent.lgetIn();
3015 left.lsetIn(pin);
3016 right.lsetIn(pin + left.lgetOut());
3017 }
3018
3019 final void pushUp(FJScan parent, FJScan left, FJScan right) {
3020 parent.lsetOut(left.lgetOut() + right.lgetOut());
3021 }
3022
3023 final FJScan newSubtask(FJScan parent, int lo, int hi) {
3024 FJLScan f = new FJLScan(parent, this, lo, hi);
3025 f.in = 0L;
3026 f.out = 0L;
3027 return f;
3028 }
3029 }
3030
3031 static final class FJLCumulatePlusOp extends FJLScanPlusOp {
3032 FJLCumulatePlusOp(AbstractParallelAnyArray.LPap pap) {
3033 super(pap);
3034 }
3035 void sumLeaf(int lo, int hi, FJScan f) {
3036 long sum = 0L;
3037 if (hi != fence) {
3038 long[] arr = array;
3039 for (int i = lo; i < hi; ++i)
3040 sum += arr[i];
3041 }
3042 f.lsetOut(sum);
3043 }
3044 void cumulateLeaf(int lo, int hi, FJScan f) {
3045 long[] arr = array;
3046 long sum = f.lgetIn();
3047 for (int i = lo; i < hi; ++i)
3048 arr[i] = sum += arr[i];
3049 }
3050 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3051 long[] arr = array;
3052 long sum = 0L;
3053 for (int i = lo; i < hi; ++i)
3054 arr[i] = sum += arr[i];
3055 f.lsetOut(sum);
3056 }
3057 }
3058
3059 static final class FJLPrecumulatePlusOp extends FJLScanPlusOp {
3060 FJLPrecumulatePlusOp(AbstractParallelAnyArray.LPap pap) {
3061 super(pap);
3062 }
3063 void sumLeaf(int lo, int hi, FJScan f) {
3064 long[] arr = array;
3065 long sum = 0L;
3066 for (int i = lo; i < hi; ++i)
3067 sum += arr[i];
3068 f.lsetOut(sum);
3069 }
3070 void cumulateLeaf(int lo, int hi, FJScan f) {
3071 long[] arr = array;
3072 long sum = f.lgetIn();
3073 for (int i = lo; i < hi; ++i) {
3074 long x = arr[i];
3075 arr[i] = sum;
3076 sum += x;
3077 }
3078 }
3079 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3080 long[] arr = array;
3081 long sum = 0L;
3082 for (int i = lo; i < hi; ++i) {
3083 long x = arr[i];
3084 arr[i] = sum;
3085 sum += x;
3086 }
3087 f.lsetOut(sum);
3088 }
3089 }
3090
3091 }