ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/PAS.java
Revision: 1.18
Committed: Tue Feb 5 17:36:44 2013 UTC (11 years, 3 months ago) by jsr166
Branch: MAIN
Changes since 1.17: +1 -1 lines
Log Message:
javadoc style

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