ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/PAS.java
Revision: 1.11
Committed: Sat Oct 16 16:40:44 2010 UTC (13 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.10: +12 -9 lines
Log Message:
whitespace

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     * http://creativecommons.org/licenses/publicdomain
5     */
6    
7     package extra166y;
8     import jsr166y.*;
9     import static extra166y.Ops.*;
10     import java.util.*;
11     import java.util.concurrent.atomic.*;
12     import java.lang.reflect.Array;
13    
14     /**
15     * Shared internal execution support for ParallelArray and
16     * specializations.
17     */
18     class PAS {
19     private PAS() {} // all-static, non-instantiable
20    
21     /** Global default executor */
22     private static volatile ForkJoinPool defaultExecutor;
23     /** Lock for on-demand initialization of defaultExecutor */
24     private static final Object poolLock = new Object();
25    
26     static ForkJoinPool defaultExecutor() {
27     ForkJoinPool p = defaultExecutor; // double-check
28     if (p == null) {
29 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     int hc = byIdentity? System.identityHashCode(x): x.hashCode();
1495     int hash = hash(hc);
1496     long entry = (((long)hash) << 32) + (k + 1);
1497     int idx = hash & mask;
1498     for (;;) {
1499     long d = get(idx);
1500     if (d != 0) {
1501     if ((int)(d >>> 32) == hash) {
1502     Object y = src[(int)((d-1) & 0x7fffffffL)];
1503     if (x == y || (!byIdentity && x.equals(y)))
1504     break;
1505     }
1506     idx = (idx + 1) & mask;
1507     }
1508     else if (compareAndSet(idx, 0, entry)) {
1509     ++count;
1510     break;
1511     }
1512     }
1513     }
1514     return count;
1515     }
1516    
1517     int addDoubles(int lo, int hi) {
1518     boolean filtered = pap.hasFilter();
1519     double[] src = pap.dgetArray();
1520     final int mask = length() - 1;
1521     int count = 0;
1522     for (int k = lo; k < hi; ++k) {
1523     if (filtered && !pap.isSelected(k))
1524     continue;
1525     double x = src[k];
1526     long bits = Double.doubleToLongBits(x);
1527 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.8 oquickSort(a, cmp, l, l+n-1);
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.8 ocquickSort(a, l, l+n-1);
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     static void oquickSort(Object[] a, Comparator cmp, int lo, int hi) {
2311     for (;;) {
2312     if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2313     for (int i = lo + 1; i <= hi; i++) {
2314     Object t = a[i];
2315     int j = i - 1;
2316     while (j >= lo && cmp.compare(t, a[j]) < 0) {
2317     a[j+1] = a[j];
2318     --j;
2319     }
2320     a[j+1] = t;
2321     }
2322     return;
2323     }
2324    
2325     int mid = (lo + hi) >>> 1;
2326     if (cmp.compare(a[lo], a[mid]) > 0) {
2327     Object t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2328     }
2329     if (cmp.compare(a[mid], a[hi]) > 0) {
2330     Object t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2331     if (cmp.compare(a[lo], a[mid]) > 0) {
2332     Object u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2333     }
2334     }
2335    
2336     Object pivot = a[mid];
2337     int left = lo+1;
2338     int right = hi-1;
2339     boolean sameLefts = true;
2340     for (;;) {
2341     while (cmp.compare(pivot, a[right]) < 0)
2342     --right;
2343     int c;
2344 jsr166 1.11 while (left < right &&
2345     (c = cmp.compare(pivot, a[left])) >= 0) {
2346 dl 1.8 if (c != 0)
2347     sameLefts = false;
2348     ++left;
2349     }
2350     if (left < right) {
2351     Object t = a[left]; a[left] = a[right]; a[right] = t;
2352     --right;
2353     }
2354     else break;
2355     }
2356 jsr166 1.9
2357 dl 1.8 if (sameLefts && right == hi - 1)
2358     return;
2359     if (left - lo <= hi - right) {
2360     oquickSort(a, cmp, lo, left);
2361     lo = left + 1;
2362     }
2363     else {
2364     oquickSort(a, cmp, right, hi);
2365     hi = left;
2366     }
2367     }
2368     }
2369    
2370     static void ocquickSort(Comparable[] a, int lo, int hi) {
2371     for (;;) {
2372     if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2373     for (int i = lo + 1; i <= hi; i++) {
2374     Comparable t = a[i];
2375     int j = i - 1;
2376     while (j >= lo && t.compareTo(a[j]) < 0) {
2377     a[j+1] = a[j];
2378     --j;
2379     }
2380     a[j+1] = t;
2381     }
2382     return;
2383     }
2384    
2385     int mid = (lo + hi) >>> 1;
2386     if (a[lo].compareTo(a[mid]) > 0) {
2387     Comparable t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2388     }
2389     if (a[mid].compareTo(a[hi]) > 0) {
2390     Comparable t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2391     if (a[lo].compareTo(a[mid]) > 0) {
2392     Comparable u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2393     }
2394     }
2395     Comparable pivot = a[mid];
2396     int left = lo+1;
2397     int right = hi-1;
2398     boolean sameLefts = true;
2399     for (;;) {
2400     while (pivot.compareTo(a[right]) < 0)
2401     --right;
2402     int c;
2403     while (left < right && (c = pivot.compareTo(a[left])) >= 0) {
2404     if (c != 0)
2405     sameLefts = false;
2406     ++left;
2407     }
2408     if (left < right) {
2409     Comparable t = a[left]; a[left] = a[right]; a[right] = t;
2410     --right;
2411     }
2412     else break;
2413     }
2414    
2415     if (sameLefts && right == hi - 1)
2416     return;
2417     if (left - lo <= hi - right) {
2418     ocquickSort(a, lo, left);
2419     lo = left + 1;
2420     }
2421     else {
2422     ocquickSort(a, right, hi);
2423     hi = left;
2424     }
2425     }
2426     }
2427    
2428    
2429     static void dquickSort(double[] a, DoubleComparator cmp, int lo, int hi) {
2430     for (;;) {
2431     if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2432     for (int i = lo + 1; i <= hi; i++) {
2433     double t = a[i];
2434     int j = i - 1;
2435     while (j >= lo && cmp.compare(t, a[j]) < 0) {
2436     a[j+1] = a[j];
2437     --j;
2438     }
2439     a[j+1] = t;
2440     }
2441     return;
2442     }
2443    
2444     int mid = (lo + hi) >>> 1;
2445     if (cmp.compare(a[lo], a[mid]) > 0) {
2446     double t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2447     }
2448     if (cmp.compare(a[mid], a[hi]) > 0) {
2449     double t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2450     if (cmp.compare(a[lo], a[mid]) > 0) {
2451     double u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2452     }
2453     }
2454    
2455     double pivot = a[mid];
2456     int left = lo+1;
2457     int right = hi-1;
2458     boolean sameLefts = true;
2459     for (;;) {
2460     while (cmp.compare(pivot, a[right]) < 0)
2461     --right;
2462     int c;
2463 jsr166 1.11 while (left < right &&
2464     (c = cmp.compare(pivot, a[left])) >= 0) {
2465 dl 1.8 if (c != 0)
2466     sameLefts = false;
2467     ++left;
2468     }
2469     if (left < right) {
2470     double t = a[left]; a[left] = a[right]; a[right] = t;
2471     --right;
2472     }
2473     else break;
2474     }
2475    
2476     if (sameLefts && right == hi - 1)
2477     return;
2478     if (left - lo <= hi - right) {
2479     dquickSort(a, cmp, lo, left);
2480     lo = left + 1;
2481     }
2482     else {
2483     dquickSort(a, cmp, right, hi);
2484     hi = left;
2485     }
2486     }
2487     }
2488    
2489     static void lquickSort(long[] a, LongComparator cmp, int lo, int hi) {
2490     for (;;) {
2491     if (hi - lo <= INSERTION_SORT_THRESHOLD) {
2492     for (int i = lo + 1; i <= hi; i++) {
2493     long t = a[i];
2494     int j = i - 1;
2495     while (j >= lo && cmp.compare(t, a[j]) < 0) {
2496     a[j+1] = a[j];
2497     --j;
2498     }
2499     a[j+1] = t;
2500     }
2501     return;
2502     }
2503    
2504     int mid = (lo + hi) >>> 1;
2505     if (cmp.compare(a[lo], a[mid]) > 0) {
2506     long t = a[lo]; a[lo] = a[mid]; a[mid] = t;
2507     }
2508     if (cmp.compare(a[mid], a[hi]) > 0) {
2509     long t = a[mid]; a[mid] = a[hi]; a[hi] = t;
2510     if (cmp.compare(a[lo], a[mid]) > 0) {
2511     long u = a[lo]; a[lo] = a[mid]; a[mid] = u;
2512     }
2513     }
2514    
2515     long pivot = a[mid];
2516     int left = lo+1;
2517     int right = hi-1;
2518     boolean sameLefts = true;
2519     for (;;) {
2520     while (cmp.compare(pivot, a[right]) < 0)
2521     --right;
2522     int c;
2523 jsr166 1.11 while (left < right &&
2524     (c = cmp.compare(pivot, a[left])) >= 0) {
2525 dl 1.8 if (c != 0)
2526     sameLefts = false;
2527     ++left;
2528     }
2529     if (left < right) {
2530     long t = a[left]; a[left] = a[right]; a[right] = t;
2531     --right;
2532     }
2533     else break;
2534     }
2535 jsr166 1.9
2536 dl 1.8 if (sameLefts && right == hi - 1)
2537     return;
2538     if (left - lo <= hi - right) {
2539     lquickSort(a, cmp, lo, left);
2540     lo = left + 1;
2541     }
2542     else {
2543     lquickSort(a, cmp, right, hi);
2544     hi = left;
2545     }
2546     }
2547     }
2548    
2549 dl 1.1 /**
2550     * Cumulative scan
2551     *
2552     * A basic version of scan is straightforward.
2553     * Keep dividing by two to threshold segment size, and then:
2554     * Pass 1: Create tree of partial sums for each segment
2555     * Pass 2: For each segment, cumulate with offset of left sibling
2556     * See G. Blelloch's http://www.cs.cmu.edu/~scandal/alg/scan.html
2557     *
2558     * This version improves performance within FJ framework mainly by
2559     * allowing second pass of ready left-hand sides to proceed even
2560     * if some right-hand side first passes are still executing. It
2561     * also combines first and second pass for leftmost segment, and
2562     * for cumulate (not precumulate) also skips first pass for
2563     * rightmost segment (whose result is not needed for second pass).
2564     *
2565     * To manage this, it relies on "phase" phase/state control field
2566     * maintaining bits CUMULATE, SUMMED, and FINISHED. CUMULATE is
2567     * main phase bit. When false, segments compute only their sum.
2568     * When true, they cumulate array elements. CUMULATE is set at
2569     * root at beginning of second pass and then propagated down. But
2570     * it may also be set earlier for subtrees with lo==origin (the
2571     * left spine of tree). SUMMED is a one bit join count. For leafs,
2572     * set when summed. For internal nodes, becomes true when one
2573     * child is summed. When second child finishes summing, it then
2574     * moves up tree to trigger cumulate phase. FINISHED is also a one
2575     * bit join count. For leafs, it is set when cumulated. For
2576     * internal nodes, it becomes true when one child is cumulated.
2577     * When second child finishes cumulating, it then moves up tree,
2578     * executing complete() at the root.
2579     *
2580     * This class maintains only the basic control logic. Subclasses
2581     * maintain the "in" and "out" fields, and *Ops classes perform
2582     * computations
2583     */
2584     static abstract class FJScan extends ForkJoinTask<Void> {
2585     static final short CUMULATE = (short)1;
2586     static final short SUMMED = (short)2;
2587     static final short FINISHED = (short)4;
2588    
2589     final FJScan parent;
2590     final FJScanOp op;
2591     FJScan left, right;
2592     volatile int phase; // phase/state
2593     final int lo;
2594     final int hi;
2595    
2596     static final AtomicIntegerFieldUpdater<FJScan> phaseUpdater =
2597     AtomicIntegerFieldUpdater.newUpdater(FJScan.class, "phase");
2598    
2599     FJScan(FJScan parent, FJScanOp op, int lo, int hi) {
2600     this.parent = parent;
2601     this.op = op;
2602     this.lo = lo;
2603     this.hi = hi;
2604     }
2605    
2606     public final Void getRawResult() { return null; }
2607     protected final void setRawResult(Void mustBeNull) { }
2608    
2609     /** Returns true if can CAS CUMULATE bit true */
2610     final boolean transitionToCumulate() {
2611     int c;
2612     while (((c = phase) & CUMULATE) == 0)
2613     if (phaseUpdater.compareAndSet(this, c, c | CUMULATE))
2614     return true;
2615     return false;
2616     }
2617    
2618     public final boolean exec() {
2619     if (hi - lo > op.threshold) {
2620     if (left == null) { // first pass
2621     int mid = (lo + hi) >>> 1;
2622     left = op.newSubtask(this, lo, mid);
2623     right = op.newSubtask(this, mid, hi);
2624     }
2625    
2626     boolean cumulate = (phase & CUMULATE) != 0;
2627     if (cumulate)
2628     op.pushDown(this, left, right);
2629    
2630     if (!cumulate || right.transitionToCumulate())
2631     right.fork();
2632     if (!cumulate || left.transitionToCumulate())
2633     left.exec();
2634     }
2635     else {
2636     int cb;
2637     for (;;) { // Establish action: sum, cumulate, or both
2638     int b = phase;
2639 jsr166 1.3 if ((b & FINISHED) != 0) // already done
2640 dl 1.1 return false;
2641     if ((b & CUMULATE) != 0)
2642     cb = FINISHED;
2643     else if (lo == op.origin) // combine leftmost
2644     cb = (SUMMED|FINISHED);
2645     else
2646     cb = SUMMED;
2647     if (phaseUpdater.compareAndSet(this, b, b|cb))
2648     break;
2649     }
2650    
2651     if (cb == SUMMED)
2652     op.sumLeaf(lo, hi, this);
2653     else if (cb == FINISHED)
2654     op.cumulateLeaf(lo, hi, this);
2655     else if (cb == (SUMMED|FINISHED))
2656     op.sumAndCumulateLeaf(lo, hi, this);
2657    
2658     // propagate up
2659     FJScan ch = this;
2660     FJScan par = parent;
2661     for (;;) {
2662     if (par == null) {
2663     if ((cb & FINISHED) != 0)
2664     ch.complete(null);
2665     break;
2666     }
2667     int pb = par.phase;
2668     if ((pb & cb & FINISHED) != 0) { // both finished
2669     ch = par;
2670     par = par.parent;
2671     }
2672     else if ((pb & cb & SUMMED) != 0) { // both summed
2673     op.pushUp(par, par.left, par.right);
2674     int refork =
2675     ((pb & CUMULATE) == 0 &&
2676     par.lo == op.origin)? CUMULATE : 0;
2677     int nextPhase = pb|cb|refork;
2678     if (pb == nextPhase ||
2679     phaseUpdater.compareAndSet(par, pb, nextPhase)) {
2680     if (refork != 0)
2681     par.fork();
2682     cb = SUMMED; // drop finished bit
2683     ch = par;
2684     par = par.parent;
2685     }
2686     }
2687     else if (phaseUpdater.compareAndSet(par, pb, pb|cb))
2688     break;
2689     }
2690     }
2691     return false;
2692     }
2693    
2694     // no-op versions of methods to get/set in/out, overridden as
2695     // appropriate in subclasses
2696     Object ogetIn() { return null; }
2697     Object ogetOut() { return null; }
2698     void rsetIn(Object x) { }
2699     void rsetOut(Object x) { }
2700    
2701     double dgetIn() { return 0; }
2702     double dgetOut() { return 0; }
2703     void dsetIn(double x) { }
2704     void dsetOut(double x) { }
2705    
2706     long lgetIn() { return 0; }
2707     long lgetOut() { return 0; }
2708     void lsetIn(long x) { }
2709     void lsetOut(long x) { }
2710     }
2711    
2712     // Subclasses adding in/out fields of the appropriate type
2713     static final class FJOScan extends FJScan {
2714     Object in;
2715     Object out;
2716     FJOScan(FJScan parent, FJScanOp op, int lo, int hi) {
2717     super(parent, op, lo, hi);
2718     }
2719     Object ogetIn() { return in; }
2720     Object ogetOut() { return out; }
2721     void rsetIn(Object x) { in = x; }
2722     void rsetOut(Object x) { out = x; }
2723     }
2724    
2725     static final class FJDScan extends FJScan {
2726     double in;
2727     double out;
2728     FJDScan(FJScan parent, FJScanOp op, int lo, int hi) {
2729     super(parent, op, lo, hi);
2730     }
2731     double dgetIn() { return in; }
2732     double dgetOut() { return out; }
2733     void dsetIn(double x) { in = x; }
2734     void dsetOut(double x) { out = x; }
2735    
2736     }
2737    
2738     static final class FJLScan extends FJScan {
2739     long in;
2740     long out;
2741     FJLScan(FJScan parent, FJScanOp op, int lo, int hi) {
2742     super(parent, op, lo, hi);
2743     }
2744     long lgetIn() { return in; }
2745     long lgetOut() { return out; }
2746     void lsetIn(long x) { in = x; }
2747     void lsetOut(long x) { out = x; }
2748     }
2749    
2750     /**
2751 jsr166 1.6 * Computational operations for FJScan
2752 dl 1.1 */
2753     static abstract class FJScanOp {
2754     final int threshold;
2755     final int origin;
2756     final int fence;
2757     FJScanOp(AbstractParallelAnyArray pap) {
2758     this.origin = pap.origin;
2759     this.fence = pap.fence;
2760     this.threshold = pap.computeThreshold();
2761     }
2762     abstract void pushDown(FJScan parent, FJScan left, FJScan right);
2763     abstract void pushUp(FJScan parent, FJScan left, FJScan right);
2764     abstract void sumLeaf(int lo, int hi, FJScan f);
2765     abstract void cumulateLeaf(int lo, int hi, FJScan f);
2766     abstract void sumAndCumulateLeaf(int lo, int hi, FJScan f);
2767     abstract FJScan newSubtask(FJScan parent, int lo, int hi);
2768     }
2769    
2770     static abstract class FJOScanOp extends FJScanOp {
2771     final Object[] array;
2772     final Reducer reducer;
2773     final Object base;
2774     FJOScanOp(AbstractParallelAnyArray.OPap pap,
2775     Reducer reducer, Object base) {
2776     super(pap);
2777     this.array = pap.array;
2778     this.reducer = reducer;
2779     this.base = base;
2780     }
2781     final void pushDown(FJScan parent, FJScan left, FJScan right) {
2782     Object pin = parent.ogetIn();
2783     left.rsetIn(pin);
2784     right.rsetIn(reducer.op(pin, left.ogetOut()));
2785     }
2786     final void pushUp(FJScan parent, FJScan left, FJScan right) {
2787     parent.rsetOut(reducer.op(left.ogetOut(),
2788     right.ogetOut()));
2789     }
2790     final FJScan newSubtask(FJScan parent, int lo, int hi) {
2791     FJOScan f = new FJOScan(parent, this, lo, hi);
2792     f.in = base;
2793     f.out = base;
2794     return f;
2795     }
2796     }
2797    
2798     static final class FJOCumulateOp extends FJOScanOp {
2799     FJOCumulateOp(AbstractParallelAnyArray.OPap pap,
2800     Reducer reducer, Object base) {
2801     super(pap, reducer, base);
2802     }
2803     void sumLeaf(int lo, int hi, FJScan f) {
2804     Object sum = base;
2805     if (hi != fence) {
2806     Object[] arr = array;
2807     for (int i = lo; i < hi; ++i)
2808     sum = reducer.op(sum, arr[i]);
2809     }
2810     f.rsetOut(sum);
2811     }
2812     void cumulateLeaf(int lo, int hi, FJScan f) {
2813     Object[] arr = array;
2814     Object sum = f.ogetIn();
2815     for (int i = lo; i < hi; ++i)
2816     arr[i] = sum = reducer.op(sum, arr[i]);
2817     }
2818     void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2819     Object[] arr = array;
2820     Object sum = base;
2821     for (int i = lo; i < hi; ++i)
2822     arr[i] = sum = reducer.op(sum, arr[i]);
2823     f.rsetOut(sum);
2824     }
2825     }
2826    
2827     static final class FJOPrecumulateOp extends FJOScanOp {
2828     FJOPrecumulateOp(AbstractParallelAnyArray.OPap pap,
2829     Reducer reducer, Object base) {
2830     super(pap, reducer, base);
2831     }
2832     void sumLeaf(int lo, int hi, FJScan f) {
2833     Object[] arr = array;
2834     Object sum = base;
2835     for (int i = lo; i < hi; ++i)
2836     sum = reducer.op(sum, arr[i]);
2837     f.rsetOut(sum);
2838     }
2839     void cumulateLeaf(int lo, int hi, FJScan f) {
2840     Object[] arr = array;
2841     Object sum = f.ogetIn();
2842     for (int i = lo; i < hi; ++i) {
2843     Object x = arr[i];
2844     arr[i] = sum;
2845     sum = reducer.op(sum, x);
2846     }
2847     }
2848     void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2849     Object[] arr = array;
2850     Object sum = base;
2851     for (int i = lo; i < hi; ++i) {
2852     Object x = arr[i];
2853     arr[i] = sum;
2854     sum = reducer.op(sum, x);
2855     }
2856     f.rsetOut(sum);
2857     }
2858     }
2859    
2860     static abstract class FJDScanOp extends FJScanOp {
2861     final double[] array;
2862     final DoubleReducer reducer;
2863     final double base;
2864     FJDScanOp(AbstractParallelAnyArray.DPap pap,
2865     DoubleReducer reducer, double base) {
2866     super(pap);
2867     this.array = pap.array;
2868     this.reducer = reducer;
2869     this.base = base;
2870     }
2871     final void pushDown(FJScan parent, FJScan left, FJScan right) {
2872     double pin = parent.dgetIn();
2873     left.dsetIn(pin);
2874     right.dsetIn(reducer.op(pin, left.dgetOut()));
2875     }
2876     final void pushUp(FJScan parent, FJScan left, FJScan right) {
2877     parent.dsetOut(reducer.op(left.dgetOut(),
2878     right.dgetOut()));
2879     }
2880     final FJScan newSubtask(FJScan parent, int lo, int hi) {
2881     FJDScan f = new FJDScan(parent, this, lo, hi);
2882     f.in = base;
2883     f.out = base;
2884     return f;
2885     }
2886     }
2887    
2888     static final class FJDCumulateOp extends FJDScanOp {
2889     FJDCumulateOp(AbstractParallelAnyArray.DPap pap,
2890     DoubleReducer reducer, double base) {
2891     super(pap, reducer, base);
2892     }
2893     void sumLeaf(int lo, int hi, FJScan f) {
2894     double sum = base;
2895     if (hi != fence) {
2896     double[] arr = array;
2897     for (int i = lo; i < hi; ++i)
2898     sum = reducer.op(sum, arr[i]);
2899     }
2900     f.dsetOut(sum);
2901     }
2902     void cumulateLeaf(int lo, int hi, FJScan f) {
2903     double[] arr = array;
2904     double sum = f.dgetIn();
2905     for (int i = lo; i < hi; ++i)
2906     arr[i] = sum = reducer.op(sum, arr[i]);
2907     }
2908     void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2909     double[] arr = array;
2910     double sum = base;
2911     for (int i = lo; i < hi; ++i)
2912     arr[i] = sum = reducer.op(sum, arr[i]);
2913     f.dsetOut(sum);
2914     }
2915     }
2916    
2917     static final class FJDPrecumulateOp extends FJDScanOp {
2918     FJDPrecumulateOp(AbstractParallelAnyArray.DPap pap,
2919     DoubleReducer reducer, double base) {
2920     super(pap, reducer, base);
2921     }
2922     void sumLeaf(int lo, int hi, FJScan f) {
2923     double[] arr = array;
2924     double sum = base;
2925     for (int i = lo; i < hi; ++i)
2926     sum = reducer.op(sum, arr[i]);
2927     f.dsetOut(sum);
2928     }
2929     void cumulateLeaf(int lo, int hi, FJScan f) {
2930     double[] arr = array;
2931     double sum = f.dgetIn();
2932     for (int i = lo; i < hi; ++i) {
2933     double x = arr[i];
2934     arr[i] = sum;
2935     sum = reducer.op(sum, x);
2936     }
2937     }
2938     void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2939     double[] arr = array;
2940     double sum = base;
2941     for (int i = lo; i < hi; ++i) {
2942     double x = arr[i];
2943     arr[i] = sum;
2944     sum = reducer.op(sum, x);
2945     }
2946     f.dsetOut(sum);
2947     }
2948     }
2949    
2950     static abstract class FJLScanOp extends FJScanOp {
2951     final long[] array;
2952     final LongReducer reducer;
2953     final long base;
2954     FJLScanOp(AbstractParallelAnyArray.LPap pap,
2955     LongReducer reducer, long base) {
2956     super(pap);
2957     this.array = pap.array;
2958     this.reducer = reducer;
2959     this.base = base;
2960     }
2961     final void pushDown(FJScan parent, FJScan left, FJScan right) {
2962     long pin = parent.lgetIn();
2963     left.lsetIn(pin);
2964     right.lsetIn(reducer.op(pin, left.lgetOut()));
2965     }
2966     final void pushUp(FJScan parent, FJScan left, FJScan right) {
2967     parent.lsetOut(reducer.op(left.lgetOut(),
2968     right.lgetOut()));
2969     }
2970     final FJScan newSubtask(FJScan parent, int lo, int hi) {
2971     FJLScan f = new FJLScan(parent, this, lo, hi);
2972     f.in = base;
2973     f.out = base;
2974     return f;
2975     }
2976     }
2977    
2978     static final class FJLCumulateOp extends FJLScanOp {
2979     FJLCumulateOp(AbstractParallelAnyArray.LPap pap,
2980     LongReducer reducer, long base) {
2981     super(pap, reducer, base);
2982     }
2983     void sumLeaf(int lo, int hi, FJScan f) {
2984     long sum = base;
2985     if (hi != fence) {
2986     long[] arr = array;
2987     for (int i = lo; i < hi; ++i)
2988     sum = reducer.op(sum, arr[i]);
2989     }
2990     f.lsetOut(sum);
2991     }
2992     void cumulateLeaf(int lo, int hi, FJScan f) {
2993     long[] arr = array;
2994     long sum = f.lgetIn();
2995     for (int i = lo; i < hi; ++i)
2996     arr[i] = sum = reducer.op(sum, arr[i]);
2997     }
2998     void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
2999     long[] arr = array;
3000     long sum = base;
3001     for (int i = lo; i < hi; ++i)
3002     arr[i] = sum = reducer.op(sum, arr[i]);
3003     f.lsetOut(sum);
3004     }
3005     }
3006    
3007     static final class FJLPrecumulateOp extends FJLScanOp {
3008     FJLPrecumulateOp(AbstractParallelAnyArray.LPap pap,
3009     LongReducer reducer, long base) {
3010     super(pap, reducer, base);
3011     }
3012     void sumLeaf(int lo, int hi, FJScan f) {
3013     long[] arr = array;
3014     long sum = base;
3015     for (int i = lo; i < hi; ++i)
3016     sum = reducer.op(sum, arr[i]);
3017     f.lsetOut(sum);
3018     }
3019     void cumulateLeaf(int lo, int hi, FJScan f) {
3020     long[] arr = array;
3021     long sum = f.lgetIn();
3022     for (int i = lo; i < hi; ++i) {
3023     long x = arr[i];
3024     arr[i] = sum;
3025     sum = reducer.op(sum, x);
3026     }
3027     }
3028     void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3029     long[] arr = array;
3030     long sum = base;
3031     for (int i = lo; i < hi; ++i) {
3032     long x = arr[i];
3033     arr[i] = sum;
3034     sum = reducer.op(sum, x);
3035     }
3036     f.lsetOut(sum);
3037     }
3038     }
3039    
3040     // specialized versions for plus
3041    
3042     static abstract class FJDScanPlusOp extends FJScanOp {
3043     final double[] array;
3044     FJDScanPlusOp(AbstractParallelAnyArray.DPap pap) {
3045     super(pap);
3046     this.array = pap.array;
3047     }
3048     final void pushDown(FJScan parent, FJScan left, FJScan right) {
3049     double pin = parent.dgetIn();
3050     left.dsetIn(pin);
3051     right.dsetIn(pin + left.dgetOut());
3052     }
3053     final void pushUp(FJScan parent, FJScan left, FJScan right) {
3054     parent.dsetOut(left.dgetOut() + right.dgetOut());
3055     }
3056     final FJScan newSubtask(FJScan parent, int lo, int hi) {
3057     FJDScan f = new FJDScan(parent, this, lo, hi);
3058     f.in = 0.0;
3059     f.out = 0.0;
3060     return f;
3061     }
3062     }
3063    
3064     static final class FJDCumulatePlusOp extends FJDScanPlusOp {
3065     FJDCumulatePlusOp(AbstractParallelAnyArray.DPap pap) {
3066     super(pap);
3067     }
3068     void sumLeaf(int lo, int hi, FJScan f) {
3069     double sum = 0.0;
3070     if (hi != fence) {
3071     double[] arr = array;
3072     for (int i = lo; i < hi; ++i)
3073     sum += arr[i];
3074     }
3075     f.dsetOut(sum);
3076     }
3077     void cumulateLeaf(int lo, int hi, FJScan f) {
3078     double[] arr = array;
3079     double sum = f.dgetIn();
3080     for (int i = lo; i < hi; ++i)
3081     arr[i] = sum += arr[i];
3082     }
3083     void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3084     double[] arr = array;
3085     double sum = 0.0;
3086     for (int i = lo; i < hi; ++i)
3087     arr[i] = sum += arr[i];
3088     f.dsetOut(sum);
3089     }
3090     }
3091    
3092     static final class FJDPrecumulatePlusOp extends FJDScanPlusOp {
3093     FJDPrecumulatePlusOp(AbstractParallelAnyArray.DPap pap) {
3094     super(pap);
3095     }
3096     void sumLeaf(int lo, int hi, FJScan f) {
3097     double[] arr = array;
3098     double sum = 0.0;
3099     for (int i = lo; i < hi; ++i)
3100     sum += arr[i];
3101     f.dsetOut(sum);
3102     }
3103     void cumulateLeaf(int lo, int hi, FJScan f) {
3104     double[] arr = array;
3105     double sum = f.dgetIn();
3106     for (int i = lo; i < hi; ++i) {
3107     double x = arr[i];
3108     arr[i] = sum;
3109     sum += x;
3110     }
3111     }
3112     void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3113     double[] arr = array;
3114     double sum = 0.0;
3115     for (int i = lo; i < hi; ++i) {
3116     double x = arr[i];
3117     arr[i] = sum;
3118     sum += x;
3119     }
3120     f.dsetOut(sum);
3121     }
3122     }
3123    
3124     static abstract class FJLScanPlusOp extends FJScanOp {
3125     final long[] array;
3126     FJLScanPlusOp(AbstractParallelAnyArray.LPap pap) {
3127     super(pap);
3128     this.array = pap.array;
3129     }
3130     final void pushDown(FJScan parent, FJScan left, FJScan right) {
3131     long pin = parent.lgetIn();
3132     left.lsetIn(pin);
3133     right.lsetIn(pin + left.lgetOut());
3134     }
3135    
3136     final void pushUp(FJScan parent, FJScan left, FJScan right) {
3137     parent.lsetOut(left.lgetOut() + right.lgetOut());
3138     }
3139    
3140     final FJScan newSubtask(FJScan parent, int lo, int hi) {
3141     FJLScan f = new FJLScan(parent, this, lo, hi);
3142     f.in = 0L;
3143     f.out = 0L;
3144     return f;
3145     }
3146     }
3147    
3148     static final class FJLCumulatePlusOp extends FJLScanPlusOp {
3149     FJLCumulatePlusOp(AbstractParallelAnyArray.LPap pap) {
3150     super(pap);
3151     }
3152     void sumLeaf(int lo, int hi, FJScan f) {
3153     long sum = 0L;
3154     if (hi != fence) {
3155     long[] arr = array;
3156     for (int i = lo; i < hi; ++i)
3157     sum += arr[i];
3158     }
3159     f.lsetOut(sum);
3160     }
3161     void cumulateLeaf(int lo, int hi, FJScan f) {
3162     long[] arr = array;
3163     long sum = f.lgetIn();
3164     for (int i = lo; i < hi; ++i)
3165     arr[i] = sum += arr[i];
3166     }
3167     void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3168     long[] arr = array;
3169     long sum = 0L;
3170     for (int i = lo; i < hi; ++i)
3171     arr[i] = sum += arr[i];
3172     f.lsetOut(sum);
3173     }
3174     }
3175    
3176     static final class FJLPrecumulatePlusOp extends FJLScanPlusOp {
3177     FJLPrecumulatePlusOp(AbstractParallelAnyArray.LPap pap) {
3178     super(pap);
3179     }
3180     void sumLeaf(int lo, int hi, FJScan f) {
3181     long[] arr = array;
3182     long sum = 0L;
3183     for (int i = lo; i < hi; ++i)
3184     sum += arr[i];
3185     f.lsetOut(sum);
3186     }
3187     void cumulateLeaf(int lo, int hi, FJScan f) {
3188     long[] arr = array;
3189     long sum = f.lgetIn();
3190     for (int i = lo; i < hi; ++i) {
3191     long x = arr[i];
3192     arr[i] = sum;
3193     sum += x;
3194     }
3195     }
3196     void sumAndCumulateLeaf(int lo, int hi, FJScan f) {
3197     long[] arr = array;
3198     long sum = 0L;
3199     for (int i = lo; i < hi; ++i) {
3200     long x = arr[i];
3201     arr[i] = sum;
3202     sum += x;
3203     }
3204     f.lsetOut(sum);
3205     }
3206     }
3207    
3208     }