| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
package java.util;  | 
 | 
 | 
 | 
import java.util.concurrent.RecursiveAction;  | 
 | 
import java.util.concurrent.CountedCompleter;  | 
 | 
 | 
 | 
/**  | 
 | 
 * Helper utilities for the parallel sort methods in Arrays.parallelSort.  | 
 | 
 *  | 
 | 
 * For each primitive type, plus Object, we define a static class to  | 
 | 
 * contain the Sorter and Merger implementations for that type:  | 
 | 
 *  | 
 | 
 * Sorter classes based mainly on CilkSort  | 
 | 
 * <A href="http://supertech.lcs.mit.edu/cilk/"> Cilk</A>:  | 
 | 
 * Basic algorithm:  | 
 | 
 * if array size is small, just use a sequential quicksort (via Arrays.sort)  | 
 | 
 *         Otherwise:  | 
 | 
 *         1. Break array in half.  | 
 | 
 *         2. For each half,  | 
 | 
 *             a. break the half in half (i.e., quarters),  | 
 | 
 *             b. sort the quarters  | 
 | 
 *             c. merge them together  | 
 | 
 *         3. merge together the two halves.  | 
 | 
 *  | 
 | 
 * One reason for splitting in quarters is that this guarantees that  | 
 | 
 * the final sort is in the main array, not the workspace array.  | 
 | 
 * (workspace and main swap roles on each subsort step.)  Leaf-level  | 
 | 
 * sorts use the associated sequential sort.  | 
 | 
 *  | 
 | 
 * Merger classes perform merging for Sorter.  They are structured  | 
 | 
 * such that if the underlying sort is stable (as is true for  | 
 | 
 * TimSort), then so is the full sort.  If big enough, they split the  | 
 | 
 * largest of the two partitions in half, find the greatest point in  | 
 | 
 * smaller partition less than the beginning of the second half of  | 
 | 
 * larger via binary search; and then merge in parallel the two  | 
 | 
 * partitions.  In part to ensure tasks are triggered in  | 
 | 
 * stability-preserving order, the current CountedCompleter design  | 
 | 
 * requires some little tasks to serve as place holders for triggering  | 
 | 
 * completion tasks.  These classes (EmptyCompleter and Relay) don't  | 
 | 
 * need to keep track of the arrays, and are never themselves forked,  | 
 | 
 * so don't hold any task state.  | 
 | 
 *  | 
 | 
 * The primitive class versions (FJByte... FJDouble) are  | 
 | 
 * identical to each other except for type declarations.  | 
 | 
 *  | 
 | 
 * The base sequential sorts rely on non-public versions of TimSort,  | 
 | 
 * ComparableTimSort, and DualPivotQuicksort sort methods that accept  | 
 | 
 * temp workspace array slices that we will have already allocated, so  | 
 | 
 * avoids redundant allocation. (Except for DualPivotQuicksort byte[]  | 
 | 
 * sort, that does not ever use a workspace array.)  | 
 | 
 */  | 
 | 
 class ArraysParallelSortHelpers { | 
 | 
 | 
 | 
    /*  | 
 | 
     * Style note: The task classes have a lot of parameters, that are  | 
 | 
     * stored as task fields and copied to local variables and used in  | 
 | 
     * compute() methods, We pack these into as few lines as possible,  | 
 | 
     * and hoist consistency checks among them before main loops, to  | 
 | 
     * reduce distraction.  | 
 | 
     */  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    static final class EmptyCompleter extends CountedCompleter<Void> { | 
 | 
        static final long serialVersionUID = 2446542900576103244L;  | 
 | 
        EmptyCompleter(CountedCompleter<?> p) { super(p); } | 
 | 
        public final void compute() { } | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    static final class Relay extends CountedCompleter<Void> { | 
 | 
        static final long serialVersionUID = 2446542900576103244L;  | 
 | 
        final CountedCompleter<?> task;  | 
 | 
        Relay(CountedCompleter<?> task) { | 
 | 
            super(null, 1);  | 
 | 
            this.task = task;  | 
 | 
        }  | 
 | 
        public final void compute() { } | 
 | 
        public final void onCompletion(CountedCompleter<?> t) { | 
 | 
            task.compute();  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
    static final class FJObject { | 
 | 
        static final class Sorter<T> extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final T[] a, w;  | 
 | 
            final int base, size, wbase, gran;  | 
 | 
            Comparator<? super T> comparator;  | 
 | 
            Sorter(CountedCompleter<?> par, T[] a, T[] w, int base, int size,  | 
 | 
                   int wbase, int gran,  | 
 | 
                   Comparator<? super T> comparator) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w; this.base = base; this.size = size;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
                this.comparator = comparator;  | 
 | 
            }  | 
 | 
            public final void compute() { | 
 | 
                CountedCompleter<?> s = this;  | 
 | 
                Comparator<? super T> c = this.comparator;  | 
 | 
                T[] a = this.a, w = this.w;   | 
 | 
                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;  | 
 | 
                while (n > g) { | 
 | 
                    int h = n >>> 1, q = h >>> 1, u = h + q;   | 
 | 
                    Relay fc = new Relay(new Merger<T>(s, w, a, wb, h,  | 
 | 
                                                       wb+h, n-h, b, g, c));  | 
 | 
                    Relay rc = new Relay(new Merger<T>(fc, a, w, b+h, q,  | 
 | 
                                                       b+u, n-u, wb+h, g, c));  | 
 | 
                    new Sorter<T>(rc, a, w, b+u, n-u, wb+u, g, c).fork();  | 
 | 
                    new Sorter<T>(rc, a, w, b+h, q, wb+h, g, c).fork();;  | 
 | 
                    Relay bc = new Relay(new Merger<T>(fc, a, w, b, q,  | 
 | 
                                                       b+q, h-q, wb, g, c));  | 
 | 
                    new Sorter<T>(bc, a, w, b+q, h-q, wb+q, g, c).fork();  | 
 | 
                    s = new EmptyCompleter(bc);  | 
 | 
                    n = q;  | 
 | 
                }  | 
 | 
                TimSort.sort(a, b, b + n, c, w, wb, n);  | 
 | 
                s.tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        static final class Merger<T> extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final T[] a, w;   | 
 | 
            final int lbase, lsize, rbase, rsize, wbase, gran;  | 
 | 
            Comparator<? super T> comparator;  | 
 | 
            Merger(CountedCompleter<?> par, T[] a, T[] w,  | 
 | 
                   int lbase, int lsize, int rbase,  | 
 | 
                   int rsize, int wbase, int gran,  | 
 | 
                   Comparator<? super T> comparator) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w;  | 
 | 
                this.lbase = lbase; this.lsize = lsize;  | 
 | 
                this.rbase = rbase; this.rsize = rsize;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
                this.comparator = comparator;  | 
 | 
            }  | 
 | 
 | 
 | 
            public final void compute() { | 
 | 
                Comparator<? super T> c = this.comparator;  | 
 | 
                T[] a = this.a, w = this.w;   | 
 | 
                int lb = this.lbase, ln = this.lsize, rb = this.rbase,  | 
 | 
                    rn = this.rsize, k = this.wbase, g = this.gran;  | 
 | 
                if (a == null || w == null || lb < 0 || rb < 0 || k < 0 ||  | 
 | 
                    c == null)  | 
 | 
                    throw new IllegalStateException();   | 
 | 
                for (int lh, rh;;) {   | 
 | 
                    if (ln >= rn) { | 
 | 
                        if (ln <= g)  | 
 | 
                            break;  | 
 | 
                        rh = rn;  | 
 | 
                        T split = a[(lh = ln >>> 1) + lb];  | 
 | 
                        for (int lo = 0; lo < rh; ) { | 
 | 
                            int rm = (lo + rh) >>> 1;  | 
 | 
                            if (c.compare(split, a[rm + rb]) <= 0)  | 
 | 
                                rh = rm;  | 
 | 
                            else  | 
 | 
                                lo = rm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        if (rn <= g)  | 
 | 
                            break;  | 
 | 
                        lh = ln;  | 
 | 
                        T split = a[(rh = rn >>> 1) + rb];  | 
 | 
                        for (int lo = 0; lo < lh; ) { | 
 | 
                            int lm = (lo + lh) >>> 1;  | 
 | 
                            if (c.compare(split, a[lm + lb]) <= 0)  | 
 | 
                                lh = lm;  | 
 | 
                            else  | 
 | 
                                lo = lm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    Merger<T> m = new Merger<T>(this, a, w, lb + lh, ln - lh,  | 
 | 
                                                rb + rh, rn - rh,  | 
 | 
                                                k + lh + rh, g, c);  | 
 | 
                    rn = rh;  | 
 | 
                    ln = lh;  | 
 | 
                    addToPendingCount(1);  | 
 | 
                    m.fork();  | 
 | 
                }  | 
 | 
 | 
 | 
                int lf = lb + ln, rf = rb + rn;   | 
 | 
                while (lb < lf && rb < rf) { | 
 | 
                    T t, al, ar;  | 
 | 
                    if (c.compare((al = a[lb]), (ar = a[rb])) <= 0) { | 
 | 
                        lb++; t = al;  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        rb++; t = ar;  | 
 | 
                    }  | 
 | 
                    w[k++] = t;  | 
 | 
                }  | 
 | 
                if (rb < rf)  | 
 | 
                    System.arraycopy(a, rb, w, k, rf - rb);  | 
 | 
                else if (lb < lf)  | 
 | 
                    System.arraycopy(a, lb, w, k, lf - lb);  | 
 | 
 | 
 | 
                tryComplete();  | 
 | 
            }  | 
 | 
 | 
 | 
        }  | 
 | 
    } // FJObject  | 
 | 
 | 
 | 
      | 
 | 
    static final class FJByte { | 
 | 
        static final class Sorter extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final byte[] a, w;  | 
 | 
            final int base, size, wbase, gran;  | 
 | 
            Sorter(CountedCompleter<?> par, byte[] a, byte[] w, int base,  | 
 | 
                   int size, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w; this.base = base; this.size = size;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
            public final void compute() { | 
 | 
                CountedCompleter<?> s = this;  | 
 | 
                byte[] a = this.a, w = this.w;   | 
 | 
                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;  | 
 | 
                while (n > g) { | 
 | 
                    int h = n >>> 1, q = h >>> 1, u = h + q;   | 
 | 
                    Relay fc = new Relay(new Merger(s, w, a, wb, h,  | 
 | 
                                                    wb+h, n-h, b, g));  | 
 | 
                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,  | 
 | 
                                                    b+u, n-u, wb+h, g));  | 
 | 
                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();  | 
 | 
                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;  | 
 | 
                    Relay bc = new Relay(new Merger(fc, a, w, b, q,  | 
 | 
                                                    b+q, h-q, wb, g));  | 
 | 
                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();  | 
 | 
                    s = new EmptyCompleter(bc);  | 
 | 
                    n = q;  | 
 | 
                }  | 
 | 
                DualPivotQuicksort.sort(a, b, b + n - 1);  | 
 | 
                s.tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        static final class Merger extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final byte[] a, w;   | 
 | 
            final int lbase, lsize, rbase, rsize, wbase, gran;  | 
 | 
            Merger(CountedCompleter<?> par, byte[] a, byte[] w,  | 
 | 
                   int lbase, int lsize, int rbase,  | 
 | 
                   int rsize, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w;  | 
 | 
                this.lbase = lbase; this.lsize = lsize;  | 
 | 
                this.rbase = rbase; this.rsize = rsize;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
 | 
 | 
            public final void compute() { | 
 | 
                byte[] a = this.a, w = this.w;   | 
 | 
                int lb = this.lbase, ln = this.lsize, rb = this.rbase,  | 
 | 
                    rn = this.rsize, k = this.wbase, g = this.gran;  | 
 | 
                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)  | 
 | 
                    throw new IllegalStateException();   | 
 | 
                for (int lh, rh;;) {   | 
 | 
                    if (ln >= rn) { | 
 | 
                        if (ln <= g)  | 
 | 
                            break;  | 
 | 
                        rh = rn;  | 
 | 
                        byte split = a[(lh = ln >>> 1) + lb];  | 
 | 
                        for (int lo = 0; lo < rh; ) { | 
 | 
                            int rm = (lo + rh) >>> 1;  | 
 | 
                            if (split <= a[rm + rb])  | 
 | 
                                rh = rm;  | 
 | 
                            else  | 
 | 
                                lo = rm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        if (rn <= g)  | 
 | 
                            break;  | 
 | 
                        lh = ln;  | 
 | 
                        byte split = a[(rh = rn >>> 1) + rb];  | 
 | 
                        for (int lo = 0; lo < lh; ) { | 
 | 
                            int lm = (lo + lh) >>> 1;  | 
 | 
                            if (split <= a[lm + lb])  | 
 | 
                                lh = lm;  | 
 | 
                            else  | 
 | 
                                lo = lm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,  | 
 | 
                                          rb + rh, rn - rh,  | 
 | 
                                          k + lh + rh, g);  | 
 | 
                    rn = rh;  | 
 | 
                    ln = lh;  | 
 | 
                    addToPendingCount(1);  | 
 | 
                    m.fork();  | 
 | 
                }  | 
 | 
 | 
 | 
                int lf = lb + ln, rf = rb + rn;   | 
 | 
                while (lb < lf && rb < rf) { | 
 | 
                    byte t, al, ar;  | 
 | 
                    if ((al = a[lb]) <= (ar = a[rb])) { | 
 | 
                        lb++; t = al;  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        rb++; t = ar;  | 
 | 
                    }  | 
 | 
                    w[k++] = t;  | 
 | 
                }  | 
 | 
                if (rb < rf)  | 
 | 
                    System.arraycopy(a, rb, w, k, rf - rb);  | 
 | 
                else if (lb < lf)  | 
 | 
                    System.arraycopy(a, lb, w, k, lf - lb);  | 
 | 
                tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    } // FJByte  | 
 | 
 | 
 | 
      | 
 | 
    static final class FJChar { | 
 | 
        static final class Sorter extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final char[] a, w;  | 
 | 
            final int base, size, wbase, gran;  | 
 | 
            Sorter(CountedCompleter<?> par, char[] a, char[] w, int base,  | 
 | 
                   int size, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w; this.base = base; this.size = size;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
            public final void compute() { | 
 | 
                CountedCompleter<?> s = this;  | 
 | 
                char[] a = this.a, w = this.w;   | 
 | 
                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;  | 
 | 
                while (n > g) { | 
 | 
                    int h = n >>> 1, q = h >>> 1, u = h + q;   | 
 | 
                    Relay fc = new Relay(new Merger(s, w, a, wb, h,  | 
 | 
                                                    wb+h, n-h, b, g));  | 
 | 
                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,  | 
 | 
                                                    b+u, n-u, wb+h, g));  | 
 | 
                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();  | 
 | 
                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;  | 
 | 
                    Relay bc = new Relay(new Merger(fc, a, w, b, q,  | 
 | 
                                                    b+q, h-q, wb, g));  | 
 | 
                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();  | 
 | 
                    s = new EmptyCompleter(bc);  | 
 | 
                    n = q;  | 
 | 
                }  | 
 | 
                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);  | 
 | 
                s.tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        static final class Merger extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final char[] a, w;   | 
 | 
            final int lbase, lsize, rbase, rsize, wbase, gran;  | 
 | 
            Merger(CountedCompleter<?> par, char[] a, char[] w,  | 
 | 
                   int lbase, int lsize, int rbase,  | 
 | 
                   int rsize, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w;  | 
 | 
                this.lbase = lbase; this.lsize = lsize;  | 
 | 
                this.rbase = rbase; this.rsize = rsize;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
 | 
 | 
            public final void compute() { | 
 | 
                char[] a = this.a, w = this.w;   | 
 | 
                int lb = this.lbase, ln = this.lsize, rb = this.rbase,  | 
 | 
                    rn = this.rsize, k = this.wbase, g = this.gran;  | 
 | 
                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)  | 
 | 
                    throw new IllegalStateException();   | 
 | 
                for (int lh, rh;;) {   | 
 | 
                    if (ln >= rn) { | 
 | 
                        if (ln <= g)  | 
 | 
                            break;  | 
 | 
                        rh = rn;  | 
 | 
                        char split = a[(lh = ln >>> 1) + lb];  | 
 | 
                        for (int lo = 0; lo < rh; ) { | 
 | 
                            int rm = (lo + rh) >>> 1;  | 
 | 
                            if (split <= a[rm + rb])  | 
 | 
                                rh = rm;  | 
 | 
                            else  | 
 | 
                                lo = rm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        if (rn <= g)  | 
 | 
                            break;  | 
 | 
                        lh = ln;  | 
 | 
                        char split = a[(rh = rn >>> 1) + rb];  | 
 | 
                        for (int lo = 0; lo < lh; ) { | 
 | 
                            int lm = (lo + lh) >>> 1;  | 
 | 
                            if (split <= a[lm + lb])  | 
 | 
                                lh = lm;  | 
 | 
                            else  | 
 | 
                                lo = lm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,  | 
 | 
                                          rb + rh, rn - rh,  | 
 | 
                                          k + lh + rh, g);  | 
 | 
                    rn = rh;  | 
 | 
                    ln = lh;  | 
 | 
                    addToPendingCount(1);  | 
 | 
                    m.fork();  | 
 | 
                }  | 
 | 
 | 
 | 
                int lf = lb + ln, rf = rb + rn;   | 
 | 
                while (lb < lf && rb < rf) { | 
 | 
                    char t, al, ar;  | 
 | 
                    if ((al = a[lb]) <= (ar = a[rb])) { | 
 | 
                        lb++; t = al;  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        rb++; t = ar;  | 
 | 
                    }  | 
 | 
                    w[k++] = t;  | 
 | 
                }  | 
 | 
                if (rb < rf)  | 
 | 
                    System.arraycopy(a, rb, w, k, rf - rb);  | 
 | 
                else if (lb < lf)  | 
 | 
                    System.arraycopy(a, lb, w, k, lf - lb);  | 
 | 
                tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    } // FJChar  | 
 | 
 | 
 | 
      | 
 | 
    static final class FJShort { | 
 | 
        static final class Sorter extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final short[] a, w;  | 
 | 
            final int base, size, wbase, gran;  | 
 | 
            Sorter(CountedCompleter<?> par, short[] a, short[] w, int base,  | 
 | 
                   int size, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w; this.base = base; this.size = size;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
            public final void compute() { | 
 | 
                CountedCompleter<?> s = this;  | 
 | 
                short[] a = this.a, w = this.w;   | 
 | 
                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;  | 
 | 
                while (n > g) { | 
 | 
                    int h = n >>> 1, q = h >>> 1, u = h + q;   | 
 | 
                    Relay fc = new Relay(new Merger(s, w, a, wb, h,  | 
 | 
                                                    wb+h, n-h, b, g));  | 
 | 
                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,  | 
 | 
                                                    b+u, n-u, wb+h, g));  | 
 | 
                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();  | 
 | 
                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;  | 
 | 
                    Relay bc = new Relay(new Merger(fc, a, w, b, q,  | 
 | 
                                                    b+q, h-q, wb, g));  | 
 | 
                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();  | 
 | 
                    s = new EmptyCompleter(bc);  | 
 | 
                    n = q;  | 
 | 
                }  | 
 | 
                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);  | 
 | 
                s.tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        static final class Merger extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final short[] a, w;   | 
 | 
            final int lbase, lsize, rbase, rsize, wbase, gran;  | 
 | 
            Merger(CountedCompleter<?> par, short[] a, short[] w,  | 
 | 
                   int lbase, int lsize, int rbase,  | 
 | 
                   int rsize, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w;  | 
 | 
                this.lbase = lbase; this.lsize = lsize;  | 
 | 
                this.rbase = rbase; this.rsize = rsize;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
 | 
 | 
            public final void compute() { | 
 | 
                short[] a = this.a, w = this.w;   | 
 | 
                int lb = this.lbase, ln = this.lsize, rb = this.rbase,  | 
 | 
                    rn = this.rsize, k = this.wbase, g = this.gran;  | 
 | 
                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)  | 
 | 
                    throw new IllegalStateException();   | 
 | 
                for (int lh, rh;;) {   | 
 | 
                    if (ln >= rn) { | 
 | 
                        if (ln <= g)  | 
 | 
                            break;  | 
 | 
                        rh = rn;  | 
 | 
                        short split = a[(lh = ln >>> 1) + lb];  | 
 | 
                        for (int lo = 0; lo < rh; ) { | 
 | 
                            int rm = (lo + rh) >>> 1;  | 
 | 
                            if (split <= a[rm + rb])  | 
 | 
                                rh = rm;  | 
 | 
                            else  | 
 | 
                                lo = rm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        if (rn <= g)  | 
 | 
                            break;  | 
 | 
                        lh = ln;  | 
 | 
                        short split = a[(rh = rn >>> 1) + rb];  | 
 | 
                        for (int lo = 0; lo < lh; ) { | 
 | 
                            int lm = (lo + lh) >>> 1;  | 
 | 
                            if (split <= a[lm + lb])  | 
 | 
                                lh = lm;  | 
 | 
                            else  | 
 | 
                                lo = lm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,  | 
 | 
                                          rb + rh, rn - rh,  | 
 | 
                                          k + lh + rh, g);  | 
 | 
                    rn = rh;  | 
 | 
                    ln = lh;  | 
 | 
                    addToPendingCount(1);  | 
 | 
                    m.fork();  | 
 | 
                }  | 
 | 
 | 
 | 
                int lf = lb + ln, rf = rb + rn;   | 
 | 
                while (lb < lf && rb < rf) { | 
 | 
                    short t, al, ar;  | 
 | 
                    if ((al = a[lb]) <= (ar = a[rb])) { | 
 | 
                        lb++; t = al;  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        rb++; t = ar;  | 
 | 
                    }  | 
 | 
                    w[k++] = t;  | 
 | 
                }  | 
 | 
                if (rb < rf)  | 
 | 
                    System.arraycopy(a, rb, w, k, rf - rb);  | 
 | 
                else if (lb < lf)  | 
 | 
                    System.arraycopy(a, lb, w, k, lf - lb);  | 
 | 
                tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    } // FJShort  | 
 | 
 | 
 | 
      | 
 | 
    static final class FJInt { | 
 | 
        static final class Sorter extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final int[] a, w;  | 
 | 
            final int base, size, wbase, gran;  | 
 | 
            Sorter(CountedCompleter<?> par, int[] a, int[] w, int base,  | 
 | 
                   int size, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w; this.base = base; this.size = size;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
            public final void compute() { | 
 | 
                CountedCompleter<?> s = this;  | 
 | 
                int[] a = this.a, w = this.w;   | 
 | 
                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;  | 
 | 
                while (n > g) { | 
 | 
                    int h = n >>> 1, q = h >>> 1, u = h + q;   | 
 | 
                    Relay fc = new Relay(new Merger(s, w, a, wb, h,  | 
 | 
                                                    wb+h, n-h, b, g));  | 
 | 
                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,  | 
 | 
                                                    b+u, n-u, wb+h, g));  | 
 | 
                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();  | 
 | 
                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;  | 
 | 
                    Relay bc = new Relay(new Merger(fc, a, w, b, q,  | 
 | 
                                                    b+q, h-q, wb, g));  | 
 | 
                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();  | 
 | 
                    s = new EmptyCompleter(bc);  | 
 | 
                    n = q;  | 
 | 
                }  | 
 | 
                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);  | 
 | 
                s.tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        static final class Merger extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final int[] a, w;   | 
 | 
            final int lbase, lsize, rbase, rsize, wbase, gran;  | 
 | 
            Merger(CountedCompleter<?> par, int[] a, int[] w,  | 
 | 
                   int lbase, int lsize, int rbase,  | 
 | 
                   int rsize, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w;  | 
 | 
                this.lbase = lbase; this.lsize = lsize;  | 
 | 
                this.rbase = rbase; this.rsize = rsize;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
 | 
 | 
            public final void compute() { | 
 | 
                int[] a = this.a, w = this.w;   | 
 | 
                int lb = this.lbase, ln = this.lsize, rb = this.rbase,  | 
 | 
                    rn = this.rsize, k = this.wbase, g = this.gran;  | 
 | 
                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)  | 
 | 
                    throw new IllegalStateException();   | 
 | 
                for (int lh, rh;;) {   | 
 | 
                    if (ln >= rn) { | 
 | 
                        if (ln <= g)  | 
 | 
                            break;  | 
 | 
                        rh = rn;  | 
 | 
                        int split = a[(lh = ln >>> 1) + lb];  | 
 | 
                        for (int lo = 0; lo < rh; ) { | 
 | 
                            int rm = (lo + rh) >>> 1;  | 
 | 
                            if (split <= a[rm + rb])  | 
 | 
                                rh = rm;  | 
 | 
                            else  | 
 | 
                                lo = rm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        if (rn <= g)  | 
 | 
                            break;  | 
 | 
                        lh = ln;  | 
 | 
                        int split = a[(rh = rn >>> 1) + rb];  | 
 | 
                        for (int lo = 0; lo < lh; ) { | 
 | 
                            int lm = (lo + lh) >>> 1;  | 
 | 
                            if (split <= a[lm + lb])  | 
 | 
                                lh = lm;  | 
 | 
                            else  | 
 | 
                                lo = lm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,  | 
 | 
                                          rb + rh, rn - rh,  | 
 | 
                                          k + lh + rh, g);  | 
 | 
                    rn = rh;  | 
 | 
                    ln = lh;  | 
 | 
                    addToPendingCount(1);  | 
 | 
                    m.fork();  | 
 | 
                }  | 
 | 
 | 
 | 
                int lf = lb + ln, rf = rb + rn;   | 
 | 
                while (lb < lf && rb < rf) { | 
 | 
                    int t, al, ar;  | 
 | 
                    if ((al = a[lb]) <= (ar = a[rb])) { | 
 | 
                        lb++; t = al;  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        rb++; t = ar;  | 
 | 
                    }  | 
 | 
                    w[k++] = t;  | 
 | 
                }  | 
 | 
                if (rb < rf)  | 
 | 
                    System.arraycopy(a, rb, w, k, rf - rb);  | 
 | 
                else if (lb < lf)  | 
 | 
                    System.arraycopy(a, lb, w, k, lf - lb);  | 
 | 
                tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    } // FJInt  | 
 | 
 | 
 | 
      | 
 | 
    static final class FJLong { | 
 | 
        static final class Sorter extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final long[] a, w;  | 
 | 
            final int base, size, wbase, gran;  | 
 | 
            Sorter(CountedCompleter<?> par, long[] a, long[] w, int base,  | 
 | 
                   int size, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w; this.base = base; this.size = size;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
            public final void compute() { | 
 | 
                CountedCompleter<?> s = this;  | 
 | 
                long[] a = this.a, w = this.w;   | 
 | 
                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;  | 
 | 
                while (n > g) { | 
 | 
                    int h = n >>> 1, q = h >>> 1, u = h + q;   | 
 | 
                    Relay fc = new Relay(new Merger(s, w, a, wb, h,  | 
 | 
                                                    wb+h, n-h, b, g));  | 
 | 
                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,  | 
 | 
                                                    b+u, n-u, wb+h, g));  | 
 | 
                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();  | 
 | 
                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;  | 
 | 
                    Relay bc = new Relay(new Merger(fc, a, w, b, q,  | 
 | 
                                                    b+q, h-q, wb, g));  | 
 | 
                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();  | 
 | 
                    s = new EmptyCompleter(bc);  | 
 | 
                    n = q;  | 
 | 
                }  | 
 | 
                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);  | 
 | 
                s.tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        static final class Merger extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final long[] a, w;   | 
 | 
            final int lbase, lsize, rbase, rsize, wbase, gran;  | 
 | 
            Merger(CountedCompleter<?> par, long[] a, long[] w,  | 
 | 
                   int lbase, int lsize, int rbase,  | 
 | 
                   int rsize, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w;  | 
 | 
                this.lbase = lbase; this.lsize = lsize;  | 
 | 
                this.rbase = rbase; this.rsize = rsize;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
 | 
 | 
            public final void compute() { | 
 | 
                long[] a = this.a, w = this.w;   | 
 | 
                int lb = this.lbase, ln = this.lsize, rb = this.rbase,  | 
 | 
                    rn = this.rsize, k = this.wbase, g = this.gran;  | 
 | 
                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)  | 
 | 
                    throw new IllegalStateException();   | 
 | 
                for (int lh, rh;;) {   | 
 | 
                    if (ln >= rn) { | 
 | 
                        if (ln <= g)  | 
 | 
                            break;  | 
 | 
                        rh = rn;  | 
 | 
                        long split = a[(lh = ln >>> 1) + lb];  | 
 | 
                        for (int lo = 0; lo < rh; ) { | 
 | 
                            int rm = (lo + rh) >>> 1;  | 
 | 
                            if (split <= a[rm + rb])  | 
 | 
                                rh = rm;  | 
 | 
                            else  | 
 | 
                                lo = rm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        if (rn <= g)  | 
 | 
                            break;  | 
 | 
                        lh = ln;  | 
 | 
                        long split = a[(rh = rn >>> 1) + rb];  | 
 | 
                        for (int lo = 0; lo < lh; ) { | 
 | 
                            int lm = (lo + lh) >>> 1;  | 
 | 
                            if (split <= a[lm + lb])  | 
 | 
                                lh = lm;  | 
 | 
                            else  | 
 | 
                                lo = lm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,  | 
 | 
                                          rb + rh, rn - rh,  | 
 | 
                                          k + lh + rh, g);  | 
 | 
                    rn = rh;  | 
 | 
                    ln = lh;  | 
 | 
                    addToPendingCount(1);  | 
 | 
                    m.fork();  | 
 | 
                }  | 
 | 
 | 
 | 
                int lf = lb + ln, rf = rb + rn;   | 
 | 
                while (lb < lf && rb < rf) { | 
 | 
                    long t, al, ar;  | 
 | 
                    if ((al = a[lb]) <= (ar = a[rb])) { | 
 | 
                        lb++; t = al;  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        rb++; t = ar;  | 
 | 
                    }  | 
 | 
                    w[k++] = t;  | 
 | 
                }  | 
 | 
                if (rb < rf)  | 
 | 
                    System.arraycopy(a, rb, w, k, rf - rb);  | 
 | 
                else if (lb < lf)  | 
 | 
                    System.arraycopy(a, lb, w, k, lf - lb);  | 
 | 
                tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    } // FJLong  | 
 | 
 | 
 | 
      | 
 | 
    static final class FJFloat { | 
 | 
        static final class Sorter extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final float[] a, w;  | 
 | 
            final int base, size, wbase, gran;  | 
 | 
            Sorter(CountedCompleter<?> par, float[] a, float[] w, int base,  | 
 | 
                   int size, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w; this.base = base; this.size = size;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
            public final void compute() { | 
 | 
                CountedCompleter<?> s = this;  | 
 | 
                float[] a = this.a, w = this.w;   | 
 | 
                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;  | 
 | 
                while (n > g) { | 
 | 
                    int h = n >>> 1, q = h >>> 1, u = h + q;   | 
 | 
                    Relay fc = new Relay(new Merger(s, w, a, wb, h,  | 
 | 
                                                    wb+h, n-h, b, g));  | 
 | 
                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,  | 
 | 
                                                    b+u, n-u, wb+h, g));  | 
 | 
                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();  | 
 | 
                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;  | 
 | 
                    Relay bc = new Relay(new Merger(fc, a, w, b, q,  | 
 | 
                                                    b+q, h-q, wb, g));  | 
 | 
                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();  | 
 | 
                    s = new EmptyCompleter(bc);  | 
 | 
                    n = q;  | 
 | 
                }  | 
 | 
                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);  | 
 | 
                s.tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        static final class Merger extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final float[] a, w;   | 
 | 
            final int lbase, lsize, rbase, rsize, wbase, gran;  | 
 | 
            Merger(CountedCompleter<?> par, float[] a, float[] w,  | 
 | 
                   int lbase, int lsize, int rbase,  | 
 | 
                   int rsize, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w;  | 
 | 
                this.lbase = lbase; this.lsize = lsize;  | 
 | 
                this.rbase = rbase; this.rsize = rsize;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
 | 
 | 
            public final void compute() { | 
 | 
                float[] a = this.a, w = this.w;   | 
 | 
                int lb = this.lbase, ln = this.lsize, rb = this.rbase,  | 
 | 
                    rn = this.rsize, k = this.wbase, g = this.gran;  | 
 | 
                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)  | 
 | 
                    throw new IllegalStateException();   | 
 | 
                for (int lh, rh;;) {   | 
 | 
                    if (ln >= rn) { | 
 | 
                        if (ln <= g)  | 
 | 
                            break;  | 
 | 
                        rh = rn;  | 
 | 
                        float split = a[(lh = ln >>> 1) + lb];  | 
 | 
                        for (int lo = 0; lo < rh; ) { | 
 | 
                            int rm = (lo + rh) >>> 1;  | 
 | 
                            if (split <= a[rm + rb])  | 
 | 
                                rh = rm;  | 
 | 
                            else  | 
 | 
                                lo = rm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        if (rn <= g)  | 
 | 
                            break;  | 
 | 
                        lh = ln;  | 
 | 
                        float split = a[(rh = rn >>> 1) + rb];  | 
 | 
                        for (int lo = 0; lo < lh; ) { | 
 | 
                            int lm = (lo + lh) >>> 1;  | 
 | 
                            if (split <= a[lm + lb])  | 
 | 
                                lh = lm;  | 
 | 
                            else  | 
 | 
                                lo = lm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,  | 
 | 
                                          rb + rh, rn - rh,  | 
 | 
                                          k + lh + rh, g);  | 
 | 
                    rn = rh;  | 
 | 
                    ln = lh;  | 
 | 
                    addToPendingCount(1);  | 
 | 
                    m.fork();  | 
 | 
                }  | 
 | 
 | 
 | 
                int lf = lb + ln, rf = rb + rn;   | 
 | 
                while (lb < lf && rb < rf) { | 
 | 
                    float t, al, ar;  | 
 | 
                    if ((al = a[lb]) <= (ar = a[rb])) { | 
 | 
                        lb++; t = al;  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        rb++; t = ar;  | 
 | 
                    }  | 
 | 
                    w[k++] = t;  | 
 | 
                }  | 
 | 
                if (rb < rf)  | 
 | 
                    System.arraycopy(a, rb, w, k, rf - rb);  | 
 | 
                else if (lb < lf)  | 
 | 
                    System.arraycopy(a, lb, w, k, lf - lb);  | 
 | 
                tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    } // FJFloat  | 
 | 
 | 
 | 
      | 
 | 
    static final class FJDouble { | 
 | 
        static final class Sorter extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final double[] a, w;  | 
 | 
            final int base, size, wbase, gran;  | 
 | 
            Sorter(CountedCompleter<?> par, double[] a, double[] w, int base,  | 
 | 
                   int size, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w; this.base = base; this.size = size;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
            public final void compute() { | 
 | 
                CountedCompleter<?> s = this;  | 
 | 
                double[] a = this.a, w = this.w;   | 
 | 
                int b = this.base, n = this.size, wb = this.wbase, g = this.gran;  | 
 | 
                while (n > g) { | 
 | 
                    int h = n >>> 1, q = h >>> 1, u = h + q;   | 
 | 
                    Relay fc = new Relay(new Merger(s, w, a, wb, h,  | 
 | 
                                                    wb+h, n-h, b, g));  | 
 | 
                    Relay rc = new Relay(new Merger(fc, a, w, b+h, q,  | 
 | 
                                                    b+u, n-u, wb+h, g));  | 
 | 
                    new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();  | 
 | 
                    new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;  | 
 | 
                    Relay bc = new Relay(new Merger(fc, a, w, b, q,  | 
 | 
                                                    b+q, h-q, wb, g));  | 
 | 
                    new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();  | 
 | 
                    s = new EmptyCompleter(bc);  | 
 | 
                    n = q;  | 
 | 
                }  | 
 | 
                DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);  | 
 | 
                s.tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        static final class Merger extends CountedCompleter<Void> { | 
 | 
            static final long serialVersionUID = 2446542900576103244L;  | 
 | 
            final double[] a, w;   | 
 | 
            final int lbase, lsize, rbase, rsize, wbase, gran;  | 
 | 
            Merger(CountedCompleter<?> par, double[] a, double[] w,  | 
 | 
                   int lbase, int lsize, int rbase,  | 
 | 
                   int rsize, int wbase, int gran) { | 
 | 
                super(par);  | 
 | 
                this.a = a; this.w = w;  | 
 | 
                this.lbase = lbase; this.lsize = lsize;  | 
 | 
                this.rbase = rbase; this.rsize = rsize;  | 
 | 
                this.wbase = wbase; this.gran = gran;  | 
 | 
            }  | 
 | 
 | 
 | 
            public final void compute() { | 
 | 
                double[] a = this.a, w = this.w;   | 
 | 
                int lb = this.lbase, ln = this.lsize, rb = this.rbase,  | 
 | 
                    rn = this.rsize, k = this.wbase, g = this.gran;  | 
 | 
                if (a == null || w == null || lb < 0 || rb < 0 || k < 0)  | 
 | 
                    throw new IllegalStateException();   | 
 | 
                for (int lh, rh;;) {   | 
 | 
                    if (ln >= rn) { | 
 | 
                        if (ln <= g)  | 
 | 
                            break;  | 
 | 
                        rh = rn;  | 
 | 
                        double split = a[(lh = ln >>> 1) + lb];  | 
 | 
                        for (int lo = 0; lo < rh; ) { | 
 | 
                            int rm = (lo + rh) >>> 1;  | 
 | 
                            if (split <= a[rm + rb])  | 
 | 
                                rh = rm;  | 
 | 
                            else  | 
 | 
                                lo = rm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        if (rn <= g)  | 
 | 
                            break;  | 
 | 
                        lh = ln;  | 
 | 
                        double split = a[(rh = rn >>> 1) + rb];  | 
 | 
                        for (int lo = 0; lo < lh; ) { | 
 | 
                            int lm = (lo + lh) >>> 1;  | 
 | 
                            if (split <= a[lm + lb])  | 
 | 
                                lh = lm;  | 
 | 
                            else  | 
 | 
                                lo = lm + 1;  | 
 | 
                        }  | 
 | 
                    }  | 
 | 
                    Merger m = new Merger(this, a, w, lb + lh, ln - lh,  | 
 | 
                                          rb + rh, rn - rh,  | 
 | 
                                          k + lh + rh, g);  | 
 | 
                    rn = rh;  | 
 | 
                    ln = lh;  | 
 | 
                    addToPendingCount(1);  | 
 | 
                    m.fork();  | 
 | 
                }  | 
 | 
 | 
 | 
                int lf = lb + ln, rf = rb + rn;   | 
 | 
                while (lb < lf && rb < rf) { | 
 | 
                    double t, al, ar;  | 
 | 
                    if ((al = a[lb]) <= (ar = a[rb])) { | 
 | 
                        lb++; t = al;  | 
 | 
                    }  | 
 | 
                    else { | 
 | 
                        rb++; t = ar;  | 
 | 
                    }  | 
 | 
                    w[k++] = t;  | 
 | 
                }  | 
 | 
                if (rb < rf)  | 
 | 
                    System.arraycopy(a, rb, w, k, rf - rb);  | 
 | 
                else if (lb < lf)  | 
 | 
                    System.arraycopy(a, lb, w, k, lf - lb);  | 
 | 
                tryComplete();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    } // FJDouble  | 
 | 
 | 
 | 
}  |