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

File Contents

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