ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/PAS.java
Revision: 1.14
Committed: Tue Mar 15 19:47:02 2011 UTC (13 years, 2 months ago) by jsr166
Branch: MAIN
CVS Tags: jdk7-compat, release-1_7_0
Changes since 1.13: +1 -1 lines
Log Message:
Update Creative Commons license URL in legal notices

File Contents

# User Rev Content
1 dl 1.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 jsr166 1.14 * http://creativecommons.org/publicdomain/zero/1.0/
5 dl 1.1 */
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 jsr166 1.10 synchronized (poolLock) {
30 dl 1.1 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 jsr166 1.12 int hc = byIdentity ? System.identityHashCode(x) : x.hashCode();
1495 dl 1.1 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 jsr166 1.5 int hash = hash((int)(bits ^ (bits >>> 32)));
1528 dl 1.1 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 jsr166 1.11 public void compute() {
1661 dl 1.1 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 dl 1.13 Arrays.sort(a, l, l+n, cmp);
1685 dl 1.1 }
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 jsr166 1.11 public void compute() {
1697 dl 1.1 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 dl 1.13 Arrays.sort(a, l, l+n);
1721 dl 1.1 }
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 jsr166 1.11 public void compute() {
1734 dl 1.1 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 dl 1.8 dquickSort(a, cmp, l, l+n-1);
1758 dl 1.1 }
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 jsr166 1.11 public void compute() {
1770 dl 1.1 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 dl 1.7 Arrays.sort(a, l, l+n);
1794 dl 1.1 }
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 jsr166 1.11 public void compute() {
1808 dl 1.1 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 dl 1.8 lquickSort(a, cmp, l, l+n-1);
1832 dl 1.1 }
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 jsr166 1.11 public void compute() {
1844 dl 1.1 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 dl 1.7 Arrays.sort(a, l, l+n);
1869 dl 1.1 }
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 jsr166 1.4 RecursiveAction merger) {
1879 dl 1.1 this.left = left; this.right = right; this.merger = merger;
1880     }
1881     public void compute() {
1882 dl 1.2 right.fork();
1883     left.invoke();
1884     right.join();
1885 dl 1.1 merger.invoke();
1886     }
1887     }
1888    
1889     /**
1890     * Perform 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 dl 1.8 /** 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 jsr166 1.11 while (left < right &&
2346     (c = cmp.compare(pivot, a[left])) >= 0) {
2347 dl 1.8 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 jsr166 1.11 while (left < right &&
2406     (c = cmp.compare(pivot, a[left])) >= 0) {
2407 dl 1.8 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 jsr166 1.9
2418 dl 1.8 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 dl 1.1 /**
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     static abstract 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 jsr166 1.3 if ((b & FINISHED) != 0) // already done
2522 dl 1.1 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 jsr166 1.12 par.lo == op.origin) ? CUMULATE : 0;
2559 dl 1.1 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 jsr166 1.6 * Computational operations for FJScan
2634 dl 1.1 */
2635     static abstract 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     static abstract 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     static abstract 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     static abstract 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     static abstract 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     static abstract 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     }