ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/PAS.java
Revision: 1.1
Committed: Tue Jan 6 14:30:57 2009 UTC (15 years, 4 months ago) by dl
Branch: MAIN
Log Message:
Repackaged parallel collection classes

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/licenses/publicdomain
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 static abstract 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 static abstract 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 static abstract 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 * Return 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 oquickSort(a, cmp, l, l+n-1);
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 ocquickSort(a, l, l+n-1);
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 dcquickSort(a, l, l+n-1);
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 lcquickSort(a, l, l+n-1);
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 invokeAll(left, right);
1883 merger.invoke();
1884 }
1885 }
1886
1887 /**
1888 * Perform merging for FJSorter. If big enough, splits Left
1889 * partition in half; finds the greatest point in Right partition
1890 * less than the beginning of the second half of Left via binary
1891 * search; and then, in parallel, merges left half of Left with
1892 * elements of Right up to split point, and merges right half of
1893 * Left with elements of R past split point. At leaf, it just
1894 * sequentially merges. This is all messy to code; sadly we need
1895 * six versions.
1896 */
1897 static final class FJOMerger extends RecursiveAction {
1898 final Comparator cmp;
1899 final Object[] a; // partitioned array.
1900 final Object[] w; // Output array.
1901 final int lo; // relative origin of left side of a
1902 final int ln; // number of elements on left of a
1903 final int ro; // relative origin of right side of a
1904 final int rn; // number of elements on right of a
1905 final int wo; // origin for output
1906 final int gran;
1907 final FJOMerger next;
1908
1909 FJOMerger(Comparator cmp, Object[] a, Object[] w,
1910 int lo, int ln, int ro, int rn, int wo,
1911 int gran, FJOMerger next) {
1912 this.cmp = cmp;
1913 this.a = a; this.w = w;
1914 this.lo = lo; this.ln = ln;
1915 this.ro = ro; this.rn = rn;
1916 this.wo = wo;
1917 this.gran = gran;
1918 this.next = next;
1919 }
1920
1921 public void compute() {
1922 // spawn right subtasks
1923 FJOMerger rights = null;
1924 int nleft = ln;
1925 int nright = rn;
1926 while (nleft > gran) {
1927 int lh = nleft >>> 1;
1928 int splitIndex = lo + lh;
1929 Object split = a[splitIndex];
1930 // binary search r for split
1931 int rl = 0;
1932 int rh = nright;
1933 while (rl < rh) {
1934 int mid = (rl + rh) >>> 1;
1935 if (cmp.compare(split, a[ro + mid]) <= 0)
1936 rh = mid;
1937 else
1938 rl = mid + 1;
1939 }
1940 (rights = new FJOMerger
1941 (cmp, a, w, splitIndex, nleft-lh, ro+rh,
1942 nright-rh, wo+lh+rh, gran, rights)).fork();
1943 nleft = lh;
1944 nright = rh;
1945 }
1946
1947 // sequentially merge
1948 int l = lo;
1949 int lFence = lo + nleft;
1950 int r = ro;
1951 int rFence = ro + nright;
1952 int k = wo;
1953 while (l < lFence && r < rFence) {
1954 Object al = a[l];
1955 Object ar = a[r];
1956 Object t;
1957 if (cmp.compare(al, ar) <= 0) {++l; t=al;} else {++r; t=ar;}
1958 w[k++] = t;
1959 }
1960 while (l < lFence)
1961 w[k++] = a[l++];
1962 while (r < rFence)
1963 w[k++] = a[r++];
1964
1965 // join subtasks
1966 while (rights != null) {
1967 if (rights.tryUnfork())
1968 rights.compute();
1969 else
1970 rights.join();
1971 rights = rights.next;
1972 }
1973 }
1974 }
1975
1976 static final class FJOCMerger extends RecursiveAction {
1977 final Comparable[] a; final Comparable[] w;
1978 final int lo; final int ln; final int ro; final int rn; final int wo;
1979 final int gran;
1980 final FJOCMerger next;
1981 FJOCMerger(Comparable[] a, Comparable[] w, int lo,
1982 int ln, int ro, int rn, int wo,
1983 int gran, FJOCMerger next) {
1984 this.a = a; this.w = w;
1985 this.lo = lo; this.ln = ln; this.ro = ro; this.rn = rn;
1986 this.wo = wo;
1987 this.gran = gran;
1988 this.next = next;
1989 }
1990
1991 public void compute() {
1992 FJOCMerger rights = null;
1993 int nleft = ln;
1994 int nright = rn;
1995 while (nleft > gran) {
1996 int lh = nleft >>> 1;
1997 int splitIndex = lo + lh;
1998 Comparable split = a[splitIndex];
1999 int rl = 0;
2000 int rh = nright;
2001 while (rl < rh) {
2002 int mid = (rl + rh) >>> 1;
2003 if (split.compareTo(a[ro + mid]) <= 0)
2004 rh = mid;
2005 else
2006 rl = mid + 1;
2007 }
2008 (rights = new FJOCMerger
2009 (a, w, splitIndex, nleft-lh, ro+rh,
2010 nright-rh, wo+lh+rh, gran, rights)).fork();
2011 nleft = lh;
2012 nright = rh;
2013 }
2014
2015 int l = lo;
2016 int lFence = lo + nleft;
2017 int r = ro;
2018 int rFence = ro + nright;
2019 int k = wo;
2020 while (l < lFence && r < rFence) {
2021 Comparable al = a[l];
2022 Comparable ar = a[r];
2023 Comparable t;
2024 if (al.compareTo(ar) <= 0) {++l; t=al;} else {++r; t=ar; }
2025 w[k++] = t;
2026 }
2027 while (l < lFence)
2028 w[k++] = a[l++];
2029 while (r < rFence)
2030 w[k++] = a[r++];
2031 while (rights != null) {
2032 if (rights.tryUnfork())
2033 rights.compute();
2034 else
2035 rights.join();
2036 rights = rights.next;
2037 }
2038 }
2039 }
2040
2041 static final class FJDMerger extends RecursiveAction {
2042 final DoubleComparator cmp; final double[] a; final double[] w;
2043 final int lo; final int ln; final int ro; final int rn; final int wo;
2044 final int gran;
2045 final FJDMerger next;
2046 FJDMerger(DoubleComparator cmp, double[] a, double[] w,
2047 int lo, int ln, int ro, int rn, int wo,
2048 int gran, FJDMerger next) {
2049 this.cmp = cmp;
2050 this.a = a; this.w = w;
2051 this.lo = lo; this.ln = ln;
2052 this.ro = ro; this.rn = rn;
2053 this.wo = wo;
2054 this.gran = gran;
2055 this.next = next;
2056 }
2057 public void compute() {
2058 FJDMerger rights = null;
2059 int nleft = ln;
2060 int nright = rn;
2061 while (nleft > gran) {
2062 int lh = nleft >>> 1;
2063 int splitIndex = lo + lh;
2064 double split = a[splitIndex];
2065 int rl = 0;
2066 int rh = nright;
2067 while (rl < rh) {
2068 int mid = (rl + rh) >>> 1;
2069 if (cmp.compare(split, a[ro + mid]) <= 0)
2070 rh = mid;
2071 else
2072 rl = mid + 1;
2073 }
2074 (rights = new FJDMerger
2075 (cmp, a, w, splitIndex, nleft-lh, ro+rh,
2076 nright-rh, wo+lh+rh, gran, rights)).fork();
2077 nleft = lh;
2078 nright = rh;
2079 }
2080
2081 int l = lo;
2082 int lFence = lo + nleft;
2083 int r = ro;
2084 int rFence = ro + nright;
2085 int k = wo;
2086 while (l < lFence && r < rFence) {
2087 double al = a[l];
2088 double ar = a[r];
2089 double t;
2090 if (cmp.compare(al, ar) <= 0) {++l; t=al;} else {++r; t=ar; }
2091 w[k++] = t;
2092 }
2093 while (l < lFence)
2094 w[k++] = a[l++];
2095 while (r < rFence)
2096 w[k++] = a[r++];
2097 while (rights != null) {
2098 if (rights.tryUnfork())
2099 rights.compute();
2100 else
2101 rights.join();
2102 rights = rights.next;
2103 }
2104 }
2105 }
2106
2107 static final class FJDCMerger extends RecursiveAction {
2108 final double[] a; final double[] w;
2109 final int lo; final int ln; final int ro; final int rn; final int wo;
2110 final int gran;
2111 final FJDCMerger next;
2112 FJDCMerger(double[] a, double[] w, int lo,
2113 int ln, int ro, int rn, int wo,
2114 int gran, FJDCMerger next) {
2115 this.a = a; this.w = w;
2116 this.lo = lo; this.ln = ln;
2117 this.ro = ro; this.rn = rn;
2118 this.wo = wo;
2119 this.gran = gran;
2120 this.next = next;
2121 }
2122 public void compute() {
2123 FJDCMerger rights = null;
2124 int nleft = ln;
2125 int nright = rn;
2126 while (nleft > gran) {
2127 int lh = nleft >>> 1;
2128 int splitIndex = lo + lh;
2129 double split = a[splitIndex];
2130 int rl = 0;
2131 int rh = nright;
2132 while (rl < rh) {
2133 int mid = (rl + rh) >>> 1;
2134 if (split <= a[ro + mid])
2135 rh = mid;
2136 else
2137 rl = mid + 1;
2138 }
2139 (rights = new FJDCMerger
2140 (a, w, splitIndex, nleft-lh, ro+rh,
2141 nright-rh, wo+lh+rh, gran, rights)).fork();
2142 nleft = lh;
2143 nright = rh;
2144 }
2145
2146 int l = lo;
2147 int lFence = lo + nleft;
2148 int r = ro;
2149 int rFence = ro + nright;
2150 int k = wo;
2151 while (l < lFence && r < rFence) {
2152 double al = a[l];
2153 double ar = a[r];
2154 double t;
2155 if (al <= ar) {++l; t=al;} else {++r; t=ar; }
2156 w[k++] = t;
2157 }
2158 while (l < lFence)
2159 w[k++] = a[l++];
2160 while (r < rFence)
2161 w[k++] = a[r++];
2162 while (rights != null) {
2163 if (rights.tryUnfork())
2164 rights.compute();
2165 else
2166 rights.join();
2167 rights = rights.next;
2168 }
2169 }
2170 }
2171
2172 static final class FJLMerger extends RecursiveAction {
2173 final LongComparator cmp; final long[] a; final long[] w;
2174 final int lo; final int ln; final int ro; final int rn; final int wo;
2175 final int gran;
2176 final FJLMerger next;
2177 FJLMerger(LongComparator cmp, long[] a, long[] w,
2178 int lo, int ln, int ro, int rn, int wo,
2179 int gran, FJLMerger next) {
2180 this.cmp = cmp;
2181 this.a = a; this.w = w;
2182 this.lo = lo; this.ln = ln;
2183 this.ro = ro; this.rn = rn;
2184 this.wo = wo;
2185 this.gran = gran;
2186 this.next = next;
2187 }
2188 public void compute() {
2189 FJLMerger rights = null;
2190 int nleft = ln;
2191 int nright = rn;
2192 while (nleft > gran) {
2193 int lh = nleft >>> 1;
2194 int splitIndex = lo + lh;
2195 long split = a[splitIndex];
2196 int rl = 0;
2197 int rh = nright;
2198 while (rl < rh) {
2199 int mid = (rl + rh) >>> 1;
2200 if (cmp.compare(split, a[ro + mid]) <= 0)
2201 rh = mid;
2202 else
2203 rl = mid + 1;
2204 }
2205 (rights = new FJLMerger
2206 (cmp, a, w, splitIndex, nleft-lh, ro+rh,
2207 nright-rh, wo+lh+rh, gran, rights)).fork();
2208 nleft = lh;
2209 nright = rh;
2210 }
2211
2212 int l = lo;
2213 int lFence = lo + nleft;
2214 int r = ro;
2215 int rFence = ro + nright;
2216 int k = wo;
2217 while (l < lFence && r < rFence) {
2218 long al = a[l];
2219 long ar = a[r];
2220 long t;
2221 if (cmp.compare(al, ar) <= 0) {++l; t=al;} else {++r; t=ar;}
2222 w[k++] = t;
2223 }
2224 while (l < lFence)
2225 w[k++] = a[l++];
2226 while (r < rFence)
2227 w[k++] = a[r++];
2228 while (rights != null) {
2229 if (rights.tryUnfork())
2230 rights.compute();
2231 else
2232 rights.join();
2233 rights = rights.next;
2234 }
2235 }
2236 }
2237
2238 static final class FJLCMerger extends RecursiveAction {
2239 final long[] a; final long[] w;
2240 final int lo; final int ln; final int ro; final int rn; final int wo;
2241 final int gran;
2242 final FJLCMerger next;
2243 FJLCMerger(long[] a, long[] w, int lo,
2244 int ln, int ro, int rn, int wo,
2245 int gran, FJLCMerger next) {
2246 this.a = a; this.w = w;
2247 this.lo = lo; this.ln = ln;
2248 this.ro = ro; this.rn = rn;
2249 this.wo = wo;
2250 this.gran = gran;
2251 this.next = next;
2252 }
2253 public void compute() {
2254 FJLCMerger rights = null;
2255 int nleft = ln;
2256 int nright = rn;
2257 while (nleft > gran) {
2258 int lh = nleft >>> 1;
2259 int splitIndex = lo + lh;
2260 long split = a[splitIndex];
2261 int rl = 0;
2262 int rh = nright;
2263 while (rl < rh) {
2264 int mid = (rl + rh) >>> 1;
2265 if (split <= a[ro + mid])
2266 rh = mid;
2267 else
2268 rl = mid + 1;
2269 }
2270 (rights = new FJLCMerger
2271 (a, w, splitIndex, nleft-lh, ro+rh,
2272 nright-rh, wo+lh+rh, gran, rights)).fork();
2273 nleft = lh;
2274 nright = rh;
2275 }
2276
2277 int l = lo;
2278 int lFence = lo + nleft;
2279 int r = ro;
2280 int rFence = ro + nright;
2281 int k = wo;
2282 while (l < lFence && r < rFence) {
2283 long al = a[l];
2284 long ar = a[r];
2285 long t;
2286 if (al <= ar) {++l; t=al;} else {++r; t = ar;}
2287 w[k++] = t;
2288 }
2289 while (l < lFence)
2290 w[k++] = a[l++];
2291 while (r < rFence)
2292 w[k++] = a[r++];
2293 while (rights != null) {
2294 if (rights.tryUnfork())
2295 rights.compute();
2296 else
2297 rights.join();
2298 rights = rights.next;
2299 }
2300 }
2301 }
2302
2303 /** Cutoff for when to use insertion-sort instead of quicksort */
2304 static final int INSERTION_SORT_THRESHOLD = 8;
2305
2306 // Six nearly identical versions of quicksort
2307
2308 static void oquickSort(Object[] a, Comparator cmp, int lo, int hi) {
2309 for (;;) {
2310 if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2311 for (int i = lo + 1; i <= hi; i++) {
2312 Object t = a[i];
2313 int j = i - 1;
2314 while (j >= lo && cmp.compare(t, a[j]) < 0) {
2315 a[j+1] = a[j];
2316 --j;
2317 }
2318 a[j+1] = t;
2319 }
2320 return;
2321 }
2322
2323 int mid = (lo + hi) >>> 1;
2324 if (cmp.compare(a[lo], a[mid]) > 0) {
2325 Object t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2326 }
2327 if (cmp.compare(a[mid], a[hi]) > 0) {
2328 Object t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2329 if (cmp.compare(a[lo], a[mid]) > 0) {
2330 Object u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2331 }
2332 }
2333
2334 Object pivot = a[mid];
2335 int left = lo+1;
2336 int right = hi-1;
2337 for (;;) {
2338 while (cmp.compare(pivot, a[right]) < 0)
2339 --right;
2340 while (left < right && cmp.compare(pivot, a[left]) >= 0)
2341 ++left;
2342 if (left < right) {
2343 Object t = a[left]; a[left] = a[right]; a[right] = t;
2344 --right;
2345 }
2346 else break;
2347 }
2348
2349 oquickSort(a, cmp, lo, left);
2350 lo = left + 1;
2351 }
2352 }
2353
2354 static void ocquickSort(Comparable[] a, int lo, int hi) {
2355 for (;;) {
2356 if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2357 for (int i = lo + 1; i <= hi; i++) {
2358 Comparable t = a[i];
2359 int j = i - 1;
2360 while (j >= lo && t.compareTo(a[j]) < 0) {
2361 a[j+1] = a[j];
2362 --j;
2363 }
2364 a[j+1] = t;
2365 }
2366 return;
2367 }
2368
2369 int mid = (lo + hi) >>> 1;
2370 if (a[lo].compareTo(a[mid]) > 0) {
2371 Comparable t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2372 }
2373 if (a[mid].compareTo(a[hi]) > 0) {
2374 Comparable t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2375 if (a[lo].compareTo(a[mid]) > 0) {
2376 Comparable u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2377 }
2378 }
2379
2380 Comparable pivot = a[mid];
2381 int left = lo+1;
2382 int right = hi-1;
2383 for (;;) {
2384 while (pivot.compareTo(a[right]) < 0)
2385 --right;
2386 while (left < right && pivot.compareTo(a[left]) >= 0)
2387 ++left;
2388 if (left < right) {
2389 Comparable t = a[left]; a[left] = a[right]; a[right] = t;
2390 --right;
2391 }
2392 else break;
2393 }
2394
2395 ocquickSort(a, lo, left);
2396 lo = left + 1;
2397 }
2398 }
2399
2400 static void dquickSort(double[] a, DoubleComparator cmp, int lo, int hi) {
2401 for (;;) {
2402 if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2403 for (int i = lo + 1; i <= hi; i++) {
2404 double t = a[i];
2405 int j = i - 1;
2406 while (j >= lo && cmp.compare(t, a[j]) < 0) {
2407 a[j+1] = a[j];
2408 --j;
2409 }
2410 a[j+1] = t;
2411 }
2412 return;
2413 }
2414
2415 int mid = (lo + hi) >>> 1;
2416 if (cmp.compare(a[lo], a[mid]) > 0) {
2417 double t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2418 }
2419 if (cmp.compare(a[mid], a[hi]) > 0) {
2420 double t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2421 if (cmp.compare(a[lo], a[mid]) > 0) {
2422 double u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2423 }
2424 }
2425
2426 double pivot = a[mid];
2427 int left = lo+1;
2428 int right = hi-1;
2429 for (;;) {
2430 while (cmp.compare(pivot, a[right]) < 0)
2431 --right;
2432 while (left < right && cmp.compare(pivot, a[left]) >= 0)
2433 ++left;
2434 if (left < right) {
2435 double t = a[left]; a[left] = a[right]; a[right] = t;
2436 --right;
2437 }
2438 else break;
2439 }
2440
2441 dquickSort(a, cmp, lo, left);
2442 lo = left + 1;
2443 }
2444 }
2445
2446 static void dcquickSort(double[] a, int lo, int hi) {
2447 for (;;) {
2448 if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2449 for (int i = lo + 1; i <= hi; i++) {
2450 double t = a[i];
2451 int j = i - 1;
2452 while (j >= lo && t < a[j]) {
2453 a[j+1] = a[j];
2454 --j;
2455 }
2456 a[j+1] = t;
2457 }
2458 return;
2459 }
2460
2461 int mid = (lo + hi) >>> 1;
2462 if (a[lo] > a[mid]) {
2463 double t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2464 }
2465 if (a[mid] > a[hi]) {
2466 double t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2467 if (a[lo] > a[mid]) {
2468 double u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2469 }
2470 }
2471
2472 double pivot = a[mid];
2473 int left = lo+1;
2474 int right = hi-1;
2475 for (;;) {
2476 while (pivot < a[right])
2477 --right;
2478 while (left < right && pivot >= a[left])
2479 ++left;
2480 if (left < right) {
2481 double t = a[left]; a[left] = a[right]; a[right] = t;
2482 --right;
2483 }
2484 else break;
2485 }
2486
2487 dcquickSort(a, lo, left);
2488 lo = left + 1;
2489 }
2490 }
2491
2492 static void lquickSort(long[] a, LongComparator cmp, int lo, int hi) {
2493 for (;;) {
2494 if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2495 for (int i = lo + 1; i <= hi; i++) {
2496 long t = a[i];
2497 int j = i - 1;
2498 while (j >= lo && cmp.compare(t, a[j]) < 0) {
2499 a[j+1] = a[j];
2500 --j;
2501 }
2502 a[j+1] = t;
2503 }
2504 return;
2505 }
2506
2507 int mid = (lo + hi) >>> 1;
2508 if (cmp.compare(a[lo], a[mid]) > 0) {
2509 long t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2510 }
2511 if (cmp.compare(a[mid], a[hi]) > 0) {
2512 long t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2513 if (cmp.compare(a[lo], a[mid]) > 0) {
2514 long u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2515 }
2516 }
2517
2518 long pivot = a[mid];
2519 int left = lo+1;
2520 int right = hi-1;
2521 for (;;) {
2522 while (cmp.compare(pivot, a[right]) < 0)
2523 --right;
2524 while (left < right && cmp.compare(pivot, a[left]) >= 0)
2525 ++left;
2526 if (left < right) {
2527 long t = a[left]; a[left] = a[right]; a[right] = t;
2528 --right;
2529 }
2530 else break;
2531 }
2532
2533 lquickSort(a, cmp, lo, left);
2534 lo = left + 1;
2535 }
2536 }
2537
2538 static void lcquickSort(long[] a, int lo, int hi) {
2539 for (;;) {
2540 if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2541 for (int i = lo + 1; i <= hi; i++) {
2542 long t = a[i];
2543 int j = i - 1;
2544 while (j >= lo && t < a[j]) {
2545 a[j+1] = a[j];
2546 --j;
2547 }
2548 a[j+1] = t;
2549 }
2550 return;
2551 }
2552
2553 int mid = (lo + hi) >>> 1;
2554 if (a[lo] > a[mid]) {
2555 long t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2556 }
2557 if (a[mid] > a[hi]) {
2558 long t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2559 if (a[lo] > a[mid]) {
2560 long u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2561 }
2562 }
2563
2564 long pivot = a[mid];
2565 int left = lo+1;
2566 int right = hi-1;
2567 for (;;) {
2568 while (pivot < a[right])
2569 --right;
2570 while (left < right && pivot >= a[left])
2571 ++left;
2572 if (left < right) {
2573 long t = a[left]; a[left] = a[right]; a[right] = t;
2574 --right;
2575 }
2576 else break;
2577 }
2578
2579 lcquickSort(a, lo, left);
2580 lo = left + 1;
2581 }
2582 }
2583
2584 /**
2585 * Cumulative scan
2586 *
2587 * A basic version of scan is straightforward.
2588 * Keep dividing by two to threshold segment size, and then:
2589 * Pass 1: Create tree of partial sums for each segment
2590 * Pass 2: For each segment, cumulate with offset of left sibling
2591 * See G. Blelloch's http://www.cs.cmu.edu/~scandal/alg/scan.html
2592 *
2593 * This version improves performance within FJ framework mainly by
2594 * allowing second pass of ready left-hand sides to proceed even
2595 * if some right-hand side first passes are still executing. It
2596 * also combines first and second pass for leftmost segment, and
2597 * for cumulate (not precumulate) also skips first pass for
2598 * rightmost segment (whose result is not needed for second pass).
2599 *
2600 * To manage this, it relies on "phase" phase/state control field
2601 * maintaining bits CUMULATE, SUMMED, and FINISHED. CUMULATE is
2602 * main phase bit. When false, segments compute only their sum.
2603 * When true, they cumulate array elements. CUMULATE is set at
2604 * root at beginning of second pass and then propagated down. But
2605 * it may also be set earlier for subtrees with lo==origin (the
2606 * left spine of tree). SUMMED is a one bit join count. For leafs,
2607 * set when summed. For internal nodes, becomes true when one
2608 * child is summed. When second child finishes summing, it then
2609 * moves up tree to trigger cumulate phase. FINISHED is also a one
2610 * bit join count. For leafs, it is set when cumulated. For
2611 * internal nodes, it becomes true when one child is cumulated.
2612 * When second child finishes cumulating, it then moves up tree,
2613 * executing complete() at the root.
2614 *
2615 * This class maintains only the basic control logic. Subclasses
2616 * maintain the "in" and "out" fields, and *Ops classes perform
2617 * computations
2618 */
2619 static abstract class FJScan extends ForkJoinTask<Void> {
2620 static final short CUMULATE = (short)1;
2621 static final short SUMMED = (short)2;
2622 static final short FINISHED = (short)4;
2623
2624 final FJScan parent;
2625 final FJScanOp op;
2626 FJScan left, right;
2627 volatile int phase; // phase/state
2628 final int lo;
2629 final int hi;
2630
2631 static final AtomicIntegerFieldUpdater<FJScan> phaseUpdater =
2632 AtomicIntegerFieldUpdater.newUpdater(FJScan.class, "phase");
2633
2634 FJScan(FJScan parent, FJScanOp op, int lo, int hi) {
2635 this.parent = parent;
2636 this.op = op;
2637 this.lo = lo;
2638 this.hi = hi;
2639 }
2640
2641 public final Void getRawResult() { return null; }
2642 protected final void setRawResult(Void mustBeNull) { }
2643
2644 /** Returns true if can CAS CUMULATE bit true */
2645 final boolean transitionToCumulate() {
2646 int c;
2647 while (((c = phase) & CUMULATE) == 0)
2648 if (phaseUpdater.compareAndSet(this, c, c | CUMULATE))
2649 return true;
2650 return false;
2651 }
2652
2653 public final boolean exec() {
2654 if (hi - lo > op.threshold) {
2655 if (left == null) { // first pass
2656 int mid = (lo + hi) >>> 1;
2657 left = op.newSubtask(this, lo, mid);
2658 right = op.newSubtask(this, mid, hi);
2659 }
2660
2661 boolean cumulate = (phase & CUMULATE) != 0;
2662 if (cumulate)
2663 op.pushDown(this, left, right);
2664
2665 if (!cumulate || right.transitionToCumulate())
2666 right.fork();
2667 if (!cumulate || left.transitionToCumulate())
2668 left.exec();
2669 }
2670 else {
2671 int cb;
2672 for (;;) { // Establish action: sum, cumulate, or both
2673 int b = phase;
2674 if ((b & FINISHED) != 0) // already done
2675 return false;
2676 if ((b & CUMULATE) != 0)
2677 cb = FINISHED;
2678 else if (lo == op.origin) // combine leftmost
2679 cb = (SUMMED|FINISHED);
2680 else
2681 cb = SUMMED;
2682 if (phaseUpdater.compareAndSet(this, b, b|cb))
2683 break;
2684 }
2685
2686 if (cb == SUMMED)
2687 op.sumLeaf(lo, hi, this);
2688 else if (cb == FINISHED)
2689 op.cumulateLeaf(lo, hi, this);
2690 else if (cb == (SUMMED|FINISHED))
2691 op.sumAndCumulateLeaf(lo, hi, this);
2692
2693 // propagate up
2694 FJScan ch = this;
2695 FJScan par = parent;
2696 for (;;) {
2697 if (par == null) {
2698 if ((cb & FINISHED) != 0)
2699 ch.complete(null);
2700 break;
2701 }
2702 int pb = par.phase;
2703 if ((pb & cb & FINISHED) != 0) { // both finished
2704 ch = par;
2705 par = par.parent;
2706 }
2707 else if ((pb & cb & SUMMED) != 0) { // both summed
2708 op.pushUp(par, par.left, par.right);
2709 int refork =
2710 ((pb & CUMULATE) == 0 &&
2711 par.lo == op.origin)? CUMULATE : 0;
2712 int nextPhase = pb|cb|refork;
2713 if (pb == nextPhase ||
2714 phaseUpdater.compareAndSet(par, pb, nextPhase)) {
2715 if (refork != 0)
2716 par.fork();
2717 cb = SUMMED; // drop finished bit
2718 ch = par;
2719 par = par.parent;
2720 }
2721 }
2722 else if (phaseUpdater.compareAndSet(par, pb, pb|cb))
2723 break;
2724 }
2725 }
2726 return false;
2727 }
2728
2729 // no-op versions of methods to get/set in/out, overridden as
2730 // appropriate in subclasses
2731 Object ogetIn() { return null; }
2732 Object ogetOut() { return null; }
2733 void rsetIn(Object x) { }
2734 void rsetOut(Object x) { }
2735
2736 double dgetIn() { return 0; }
2737 double dgetOut() { return 0; }
2738 void dsetIn(double x) { }
2739 void dsetOut(double x) { }
2740
2741 long lgetIn() { return 0; }
2742 long lgetOut() { return 0; }
2743 void lsetIn(long x) { }
2744 void lsetOut(long x) { }
2745 }
2746
2747 // Subclasses adding in/out fields of the appropriate type
2748 static final class FJOScan extends FJScan {
2749 Object in;
2750 Object out;
2751 FJOScan(FJScan parent, FJScanOp op, int lo, int hi) {
2752 super(parent, op, lo, hi);
2753 }
2754 Object ogetIn() { return in; }
2755 Object ogetOut() { return out; }
2756 void rsetIn(Object x) { in = x; }
2757 void rsetOut(Object x) { out = x; }
2758 }
2759
2760 static final class FJDScan extends FJScan {
2761 double in;
2762 double out;
2763 FJDScan(FJScan parent, FJScanOp op, int lo, int hi) {
2764 super(parent, op, lo, hi);
2765 }
2766 double dgetIn() { return in; }
2767 double dgetOut() { return out; }
2768 void dsetIn(double x) { in = x; }
2769 void dsetOut(double x) { out = x; }
2770
2771 }
2772
2773 static final class FJLScan extends FJScan {
2774 long in;
2775 long out;
2776 FJLScan(FJScan parent, FJScanOp op, int lo, int hi) {
2777 super(parent, op, lo, hi);
2778 }
2779 long lgetIn() { return in; }
2780 long lgetOut() { return out; }
2781 void lsetIn(long x) { in = x; }
2782 void lsetOut(long x) { out = x; }
2783 }
2784
2785 /**
2786 * Computational operations for FJSCan
2787 */
2788 static abstract class FJScanOp {
2789 final int threshold;
2790 final int origin;
2791 final int fence;
2792 FJScanOp(AbstractParallelAnyArray pap) {
2793 this.origin = pap.origin;
2794 this.fence = pap.fence;
2795 this.threshold = pap.computeThreshold();
2796 }
2797 abstract void pushDown(FJScan parent, FJScan left, FJScan right);
2798 abstract void pushUp(FJScan parent, FJScan left, FJScan right);
2799 abstract void sumLeaf(int lo, int hi, FJScan f);
2800 abstract void cumulateLeaf(int lo, int hi, FJScan f);
2801 abstract void sumAndCumulateLeaf(int lo, int hi, FJScan f);
2802 abstract FJScan newSubtask(FJScan parent, int lo, int hi);
2803 }
2804
2805 static abstract class FJOScanOp extends FJScanOp {
2806 final Object[] array;
2807 final Reducer reducer;
2808 final Object base;
2809 FJOScanOp(AbstractParallelAnyArray.OPap pap,
2810 Reducer reducer, Object base) {
2811 super(pap);
2812 this.array = pap.array;
2813 this.reducer = reducer;
2814 this.base = base;
2815 }
2816 final void pushDown(FJScan parent, FJScan left, FJScan right) {
2817 Object pin = parent.ogetIn();
2818 left.rsetIn(pin);
2819 right.rsetIn(reducer.op(pin, left.ogetOut()));
2820 }
2821 final void pushUp(FJScan parent, FJScan left, FJScan right) {
2822 parent.rsetOut(reducer.op(left.ogetOut(),
2823 right.ogetOut()));
2824 }
2825 final FJScan newSubtask(FJScan parent, int lo, int hi) {
2826 FJOScan f = new FJOScan(parent, this, lo, hi);
2827 f.in = base;
2828 f.out = base;
2829 return f;
2830 }
2831 }
2832
2833 static final class FJOCumulateOp extends FJOScanOp {
2834 FJOCumulateOp(AbstractParallelAnyArray.OPap pap,
2835 Reducer reducer, Object base) {
2836 super(pap, reducer, base);
2837 }
2838 void sumLeaf(int lo, int hi, FJScan f) {
2839 Object sum = base;
2840 if (hi != fence) {
2841 Object[] arr = array;
2842 for (int i = lo; i < hi; ++i)
2843 sum = reducer.op(sum, arr[i]);
2844 }
2845 f.rsetOut(sum);
2846 }
2847 void cumulateLeaf(int lo, int hi, FJScan f) {
2848 Object[] arr = array;
2849 Object sum = f.ogetIn();
2850 for (int i = lo; i < hi; ++i)
2851 arr[i] = sum = reducer.op(sum, arr[i]);
2852 }
2853 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2854 Object[] arr = array;
2855 Object sum = base;
2856 for (int i = lo; i < hi; ++i)
2857 arr[i] = sum = reducer.op(sum, arr[i]);
2858 f.rsetOut(sum);
2859 }
2860 }
2861
2862 static final class FJOPrecumulateOp extends FJOScanOp {
2863 FJOPrecumulateOp(AbstractParallelAnyArray.OPap pap,
2864 Reducer reducer, Object base) {
2865 super(pap, reducer, base);
2866 }
2867 void sumLeaf(int lo, int hi, FJScan f) {
2868 Object[] arr = array;
2869 Object sum = base;
2870 for (int i = lo; i < hi; ++i)
2871 sum = reducer.op(sum, arr[i]);
2872 f.rsetOut(sum);
2873 }
2874 void cumulateLeaf(int lo, int hi, FJScan f) {
2875 Object[] arr = array;
2876 Object sum = f.ogetIn();
2877 for (int i = lo; i < hi; ++i) {
2878 Object x = arr[i];
2879 arr[i] = sum;
2880 sum = reducer.op(sum, x);
2881 }
2882 }
2883 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2884 Object[] arr = array;
2885 Object sum = base;
2886 for (int i = lo; i < hi; ++i) {
2887 Object x = arr[i];
2888 arr[i] = sum;
2889 sum = reducer.op(sum, x);
2890 }
2891 f.rsetOut(sum);
2892 }
2893 }
2894
2895 static abstract class FJDScanOp extends FJScanOp {
2896 final double[] array;
2897 final DoubleReducer reducer;
2898 final double base;
2899 FJDScanOp(AbstractParallelAnyArray.DPap pap,
2900 DoubleReducer reducer, double base) {
2901 super(pap);
2902 this.array = pap.array;
2903 this.reducer = reducer;
2904 this.base = base;
2905 }
2906 final void pushDown(FJScan parent, FJScan left, FJScan right) {
2907 double pin = parent.dgetIn();
2908 left.dsetIn(pin);
2909 right.dsetIn(reducer.op(pin, left.dgetOut()));
2910 }
2911 final void pushUp(FJScan parent, FJScan left, FJScan right) {
2912 parent.dsetOut(reducer.op(left.dgetOut(),
2913 right.dgetOut()));
2914 }
2915 final FJScan newSubtask(FJScan parent, int lo, int hi) {
2916 FJDScan f = new FJDScan(parent, this, lo, hi);
2917 f.in = base;
2918 f.out = base;
2919 return f;
2920 }
2921 }
2922
2923 static final class FJDCumulateOp extends FJDScanOp {
2924 FJDCumulateOp(AbstractParallelAnyArray.DPap pap,
2925 DoubleReducer reducer, double base) {
2926 super(pap, reducer, base);
2927 }
2928 void sumLeaf(int lo, int hi, FJScan f) {
2929 double sum = base;
2930 if (hi != fence) {
2931 double[] arr = array;
2932 for (int i = lo; i < hi; ++i)
2933 sum = reducer.op(sum, arr[i]);
2934 }
2935 f.dsetOut(sum);
2936 }
2937 void cumulateLeaf(int lo, int hi, FJScan f) {
2938 double[] arr = array;
2939 double sum = f.dgetIn();
2940 for (int i = lo; i < hi; ++i)
2941 arr[i] = sum = reducer.op(sum, arr[i]);
2942 }
2943 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2944 double[] arr = array;
2945 double sum = base;
2946 for (int i = lo; i < hi; ++i)
2947 arr[i] = sum = reducer.op(sum, arr[i]);
2948 f.dsetOut(sum);
2949 }
2950 }
2951
2952 static final class FJDPrecumulateOp extends FJDScanOp {
2953 FJDPrecumulateOp(AbstractParallelAnyArray.DPap pap,
2954 DoubleReducer reducer, double base) {
2955 super(pap, reducer, base);
2956 }
2957 void sumLeaf(int lo, int hi, FJScan f) {
2958 double[] arr = array;
2959 double sum = base;
2960 for (int i = lo; i < hi; ++i)
2961 sum = reducer.op(sum, arr[i]);
2962 f.dsetOut(sum);
2963 }
2964 void cumulateLeaf(int lo, int hi, FJScan f) {
2965 double[] arr = array;
2966 double sum = f.dgetIn();
2967 for (int i = lo; i < hi; ++i) {
2968 double x = arr[i];
2969 arr[i] = sum;
2970 sum = reducer.op(sum, x);
2971 }
2972 }
2973 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2974 double[] arr = array;
2975 double sum = base;
2976 for (int i = lo; i < hi; ++i) {
2977 double x = arr[i];
2978 arr[i] = sum;
2979 sum = reducer.op(sum, x);
2980 }
2981 f.dsetOut(sum);
2982 }
2983 }
2984
2985 static abstract class FJLScanOp extends FJScanOp {
2986 final long[] array;
2987 final LongReducer reducer;
2988 final long base;
2989 FJLScanOp(AbstractParallelAnyArray.LPap pap,
2990 LongReducer reducer, long base) {
2991 super(pap);
2992 this.array = pap.array;
2993 this.reducer = reducer;
2994 this.base = base;
2995 }
2996 final void pushDown(FJScan parent, FJScan left, FJScan right) {
2997 long pin = parent.lgetIn();
2998 left.lsetIn(pin);
2999 right.lsetIn(reducer.op(pin, left.lgetOut()));
3000 }
3001 final void pushUp(FJScan parent, FJScan left, FJScan right) {
3002 parent.lsetOut(reducer.op(left.lgetOut(),
3003 right.lgetOut()));
3004 }
3005 final FJScan newSubtask(FJScan parent, int lo, int hi) {
3006 FJLScan f = new FJLScan(parent, this, lo, hi);
3007 f.in = base;
3008 f.out = base;
3009 return f;
3010 }
3011 }
3012
3013 static final class FJLCumulateOp extends FJLScanOp {
3014 FJLCumulateOp(AbstractParallelAnyArray.LPap pap,
3015 LongReducer reducer, long base) {
3016 super(pap, reducer, base);
3017 }
3018 void sumLeaf(int lo, int hi, FJScan f) {
3019 long sum = base;
3020 if (hi != fence) {
3021 long[] arr = array;
3022 for (int i = lo; i < hi; ++i)
3023 sum = reducer.op(sum, arr[i]);
3024 }
3025 f.lsetOut(sum);
3026 }
3027 void cumulateLeaf(int lo, int hi, FJScan f) {
3028 long[] arr = array;
3029 long sum = f.lgetIn();
3030 for (int i = lo; i < hi; ++i)
3031 arr[i] = sum = reducer.op(sum, arr[i]);
3032 }
3033 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3034 long[] arr = array;
3035 long sum = base;
3036 for (int i = lo; i < hi; ++i)
3037 arr[i] = sum = reducer.op(sum, arr[i]);
3038 f.lsetOut(sum);
3039 }
3040 }
3041
3042 static final class FJLPrecumulateOp extends FJLScanOp {
3043 FJLPrecumulateOp(AbstractParallelAnyArray.LPap pap,
3044 LongReducer reducer, long base) {
3045 super(pap, reducer, base);
3046 }
3047 void sumLeaf(int lo, int hi, FJScan f) {
3048 long[] arr = array;
3049 long sum = base;
3050 for (int i = lo; i < hi; ++i)
3051 sum = reducer.op(sum, arr[i]);
3052 f.lsetOut(sum);
3053 }
3054 void cumulateLeaf(int lo, int hi, FJScan f) {
3055 long[] arr = array;
3056 long sum = f.lgetIn();
3057 for (int i = lo; i < hi; ++i) {
3058 long x = arr[i];
3059 arr[i] = sum;
3060 sum = reducer.op(sum, x);
3061 }
3062 }
3063 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3064 long[] arr = array;
3065 long sum = base;
3066 for (int i = lo; i < hi; ++i) {
3067 long x = arr[i];
3068 arr[i] = sum;
3069 sum = reducer.op(sum, x);
3070 }
3071 f.lsetOut(sum);
3072 }
3073 }
3074
3075 // specialized versions for plus
3076
3077 static abstract class FJDScanPlusOp extends FJScanOp {
3078 final double[] array;
3079 FJDScanPlusOp(AbstractParallelAnyArray.DPap pap) {
3080 super(pap);
3081 this.array = pap.array;
3082 }
3083 final void pushDown(FJScan parent, FJScan left, FJScan right) {
3084 double pin = parent.dgetIn();
3085 left.dsetIn(pin);
3086 right.dsetIn(pin + left.dgetOut());
3087 }
3088 final void pushUp(FJScan parent, FJScan left, FJScan right) {
3089 parent.dsetOut(left.dgetOut() + right.dgetOut());
3090 }
3091 final FJScan newSubtask(FJScan parent, int lo, int hi) {
3092 FJDScan f = new FJDScan(parent, this, lo, hi);
3093 f.in = 0.0;
3094 f.out = 0.0;
3095 return f;
3096 }
3097 }
3098
3099 static final class FJDCumulatePlusOp extends FJDScanPlusOp {
3100 FJDCumulatePlusOp(AbstractParallelAnyArray.DPap pap) {
3101 super(pap);
3102 }
3103 void sumLeaf(int lo, int hi, FJScan f) {
3104 double sum = 0.0;
3105 if (hi != fence) {
3106 double[] arr = array;
3107 for (int i = lo; i < hi; ++i)
3108 sum += arr[i];
3109 }
3110 f.dsetOut(sum);
3111 }
3112 void cumulateLeaf(int lo, int hi, FJScan f) {
3113 double[] arr = array;
3114 double sum = f.dgetIn();
3115 for (int i = lo; i < hi; ++i)
3116 arr[i] = sum += arr[i];
3117 }
3118 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3119 double[] arr = array;
3120 double sum = 0.0;
3121 for (int i = lo; i < hi; ++i)
3122 arr[i] = sum += arr[i];
3123 f.dsetOut(sum);
3124 }
3125 }
3126
3127 static final class FJDPrecumulatePlusOp extends FJDScanPlusOp {
3128 FJDPrecumulatePlusOp(AbstractParallelAnyArray.DPap pap) {
3129 super(pap);
3130 }
3131 void sumLeaf(int lo, int hi, FJScan f) {
3132 double[] arr = array;
3133 double sum = 0.0;
3134 for (int i = lo; i < hi; ++i)
3135 sum += arr[i];
3136 f.dsetOut(sum);
3137 }
3138 void cumulateLeaf(int lo, int hi, FJScan f) {
3139 double[] arr = array;
3140 double sum = f.dgetIn();
3141 for (int i = lo; i < hi; ++i) {
3142 double x = arr[i];
3143 arr[i] = sum;
3144 sum += x;
3145 }
3146 }
3147 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3148 double[] arr = array;
3149 double sum = 0.0;
3150 for (int i = lo; i < hi; ++i) {
3151 double x = arr[i];
3152 arr[i] = sum;
3153 sum += x;
3154 }
3155 f.dsetOut(sum);
3156 }
3157 }
3158
3159 static abstract class FJLScanPlusOp extends FJScanOp {
3160 final long[] array;
3161 FJLScanPlusOp(AbstractParallelAnyArray.LPap pap) {
3162 super(pap);
3163 this.array = pap.array;
3164 }
3165 final void pushDown(FJScan parent, FJScan left, FJScan right) {
3166 long pin = parent.lgetIn();
3167 left.lsetIn(pin);
3168 right.lsetIn(pin + left.lgetOut());
3169 }
3170
3171 final void pushUp(FJScan parent, FJScan left, FJScan right) {
3172 parent.lsetOut(left.lgetOut() + right.lgetOut());
3173 }
3174
3175 final FJScan newSubtask(FJScan parent, int lo, int hi) {
3176 FJLScan f = new FJLScan(parent, this, lo, hi);
3177 f.in = 0L;
3178 f.out = 0L;
3179 return f;
3180 }
3181 }
3182
3183 static final class FJLCumulatePlusOp extends FJLScanPlusOp {
3184 FJLCumulatePlusOp(AbstractParallelAnyArray.LPap pap) {
3185 super(pap);
3186 }
3187 void sumLeaf(int lo, int hi, FJScan f) {
3188 long sum = 0L;
3189 if (hi != fence) {
3190 long[] arr = array;
3191 for (int i = lo; i < hi; ++i)
3192 sum += arr[i];
3193 }
3194 f.lsetOut(sum);
3195 }
3196 void cumulateLeaf(int lo, int hi, FJScan f) {
3197 long[] arr = array;
3198 long sum = f.lgetIn();
3199 for (int i = lo; i < hi; ++i)
3200 arr[i] = sum += arr[i];
3201 }
3202 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3203 long[] arr = array;
3204 long sum = 0L;
3205 for (int i = lo; i < hi; ++i)
3206 arr[i] = sum += arr[i];
3207 f.lsetOut(sum);
3208 }
3209 }
3210
3211 static final class FJLPrecumulatePlusOp extends FJLScanPlusOp {
3212 FJLPrecumulatePlusOp(AbstractParallelAnyArray.LPap pap) {
3213 super(pap);
3214 }
3215 void sumLeaf(int lo, int hi, FJScan f) {
3216 long[] arr = array;
3217 long sum = 0L;
3218 for (int i = lo; i < hi; ++i)
3219 sum += arr[i];
3220 f.lsetOut(sum);
3221 }
3222 void cumulateLeaf(int lo, int hi, FJScan f) {
3223 long[] arr = array;
3224 long sum = f.lgetIn();
3225 for (int i = lo; i < hi; ++i) {
3226 long x = arr[i];
3227 arr[i] = sum;
3228 sum += x;
3229 }
3230 }
3231 void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3232 long[] arr = array;
3233 long sum = 0L;
3234 for (int i = lo; i < hi; ++i) {
3235 long x = arr[i];
3236 arr[i] = sum;
3237 sum += x;
3238 }
3239 f.lsetOut(sum);
3240 }
3241 }
3242
3243 }