1 /*
   2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.util;
  26 
  27 import java.util.concurrent.RecursiveAction;
  28 import java.util.concurrent.CountedCompleter;
  29 
  30 /**
  31  * Helper utilities for the parallel sort methods in Arrays.parallelSort.
  32  *
  33  * For each primitive type, plus Object, we define a static class to
  34  * contain the Sorter and Merger implementations for that type:
  35  *
  36  * Sorter classes based mainly on CilkSort
  37  * <A href="http://supertech.lcs.mit.edu/cilk/"> Cilk</A>:
  38  * Basic algorithm:
  39  * if array size is small, just use a sequential quicksort (via Arrays.sort)
  40  *         Otherwise:
  41  *         1. Break array in half.
  42  *         2. For each half,
  43  *             a. break the half in half (i.e., quarters),
  44  *             b. sort the quarters
  45  *             c. merge them together
  46  *         3. merge together the two halves.
  47  *
  48  * One reason for splitting in quarters is that this guarantees that
  49  * the final sort is in the main array, not the workspace array.
  50  * (workspace and main swap roles on each subsort step.)  Leaf-level
  51  * sorts use the associated sequential sort.
  52  *
  53  * Merger classes perform merging for Sorter.  They are structured
  54  * such that if the underlying sort is stable (as is true for
  55  * TimSort), then so is the full sort.  If big enough, they split the
  56  * largest of the two partitions in half, find the greatest point in
  57  * smaller partition less than the beginning of the second half of
  58  * larger via binary search; and then merge in parallel the two
  59  * partitions.  In part to ensure tasks are triggered in
  60  * stability-preserving order, the current CountedCompleter design
  61  * requires some little tasks to serve as place holders for triggering
  62  * completion tasks.  These classes (EmptyCompleter and Relay) don't
  63  * need to keep track of the arrays, and are never themselves forked,
  64  * so don't hold any task state.
  65  *
  66  * The primitive class versions (FJByte... FJDouble) are
  67  * identical to each other except for type declarations.
  68  *
  69  * The base sequential sorts rely on non-public versions of TimSort,
  70  * ComparableTimSort, and DualPivotQuicksort sort methods that accept
  71  * temp workspace array slices that we will have already allocated, so
  72  * avoids redundant allocation. (Except for DualPivotQuicksort byte[]
  73  * sort, that does not ever use a workspace array.)
  74  */
  75 /*package*/ class ArraysParallelSortHelpers {
  76 
  77     /*
  78      * Style note: The task classes have a lot of parameters, that are
  79      * stored as task fields and copied to local variables and used in
  80      * compute() methods, We pack these into as few lines as possible,
  81      * and hoist consistency checks among them before main loops, to
  82      * reduce distraction.
  83      */
  84 
  85     /**
  86      * A placeholder task for Sorters, used for the lowest
  87      * quartile task, that does not need to maintain array state.
  88      */
  89     static final class EmptyCompleter extends CountedCompleter<Void> {
  90         @java.io.Serial
  91         static final long serialVersionUID = 2446542900576103244L;
  92         EmptyCompleter(CountedCompleter<?> p) { super(p); }
  93         public final void compute() { }
  94     }
  95 
  96     /**
  97      * A trigger for secondary merge of two merges
  98      */
  99     static final class Relay extends CountedCompleter<Void> {
 100         @java.io.Serial
 101         static final long serialVersionUID = 2446542900576103244L;
 102         final CountedCompleter<?> task;
 103         Relay(CountedCompleter<?> task) {
 104             super(null, 1);
 105             this.task = task;
 106         }
 107         public final void compute() { }
 108         public final void onCompletion(CountedCompleter<?> t) {
 109             task.compute();
 110         }
 111     }
 112 
 113     /** Object + Comparator support class */
 114     static final class FJObject {
 115         static final class Sorter<T> extends CountedCompleter<Void> {
 116             @java.io.Serial
 117             static final long serialVersionUID = 2446542900576103244L;
 118             @SuppressWarnings("serial") // Not statically typed as Serializable
 119             final T[] a;
 120             @SuppressWarnings("serial") // Not statically typed as Serializable
 121             final T[] w;
 122             final int base, size, wbase, gran;
 123             @SuppressWarnings("serial") // Not statically typed as Serializable
 124             Comparator<? super T> comparator;
 125             Sorter(CountedCompleter<?> par, T[] a, T[] w, int base, int size,
 126                    int wbase, int gran,
 127                    Comparator<? super T> comparator) {
 128                 super(par);
 129                 this.a = a; this.w = w; this.base = base; this.size = size;
 130                 this.wbase = wbase; this.gran = gran;
 131                 this.comparator = comparator;
 132             }
 133             public final void compute() {
 134                 CountedCompleter<?> s = this;
 135                 Comparator<? super T> c = this.comparator;
 136                 T[] a = this.a, w = this.w; // localize all params
 137                 int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
 138                 while (n > g) {
 139                     int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
 140                     Relay fc = new Relay(new Merger<>(s, w, a, wb, h,
 141                                                       wb+h, n-h, b, g, c));
 142                     Relay rc = new Relay(new Merger<>(fc, a, w, b+h, q,
 143                                                       b+u, n-u, wb+h, g, c));
 144                     new Sorter<>(rc, a, w, b+u, n-u, wb+u, g, c).fork();
 145                     new Sorter<>(rc, a, w, b+h, q, wb+h, g, c).fork();;
 146                     Relay bc = new Relay(new Merger<>(fc, a, w, b, q,
 147                                                       b+q, h-q, wb, g, c));
 148                     new Sorter<>(bc, a, w, b+q, h-q, wb+q, g, c).fork();
 149                     s = new EmptyCompleter(bc);
 150                     n = q;
 151                 }
 152                 TimSort.sort(a, b, b + n, c, w, wb, n);
 153                 s.tryComplete();
 154             }
 155         }
 156 
 157         static final class Merger<T> extends CountedCompleter<Void> {
 158             @java.io.Serial
 159             static final long serialVersionUID = 2446542900576103244L;
 160              // main and workspace arrays
 161             @SuppressWarnings("serial") // Not statically typed as Serializable
 162             final T[] a;
 163             @SuppressWarnings("serial") // Not statically typed as Serializable
 164             final T[] w;
 165             final int lbase, lsize, rbase, rsize, wbase, gran;
 166             @SuppressWarnings("serial") // Not statically typed as Serializable
 167             Comparator<? super T> comparator;
 168             Merger(CountedCompleter<?> par, T[] a, T[] w,
 169                    int lbase, int lsize, int rbase,
 170                    int rsize, int wbase, int gran,
 171                    Comparator<? super T> comparator) {
 172                 super(par);
 173                 this.a = a; this.w = w;
 174                 this.lbase = lbase; this.lsize = lsize;
 175                 this.rbase = rbase; this.rsize = rsize;
 176                 this.wbase = wbase; this.gran = gran;
 177                 this.comparator = comparator;
 178             }
 179 
 180             public final void compute() {
 181                 Comparator<? super T> c = this.comparator;
 182                 T[] a = this.a, w = this.w; // localize all params
 183                 int lb = this.lbase, ln = this.lsize, rb = this.rbase,
 184                     rn = this.rsize, k = this.wbase, g = this.gran;
 185                 if (a == null || w == null || lb < 0 || rb < 0 || k < 0 ||
 186                     c == null)
 187                     throw new IllegalStateException(); // hoist checks
 188                 for (int lh, rh;;) {  // split larger, find point in smaller
 189                     if (ln >= rn) {
 190                         if (ln <= g)
 191                             break;
 192                         rh = rn;
 193                         T split = a[(lh = ln >>> 1) + lb];
 194                         for (int lo = 0; lo < rh; ) {
 195                             int rm = (lo + rh) >>> 1;
 196                             if (c.compare(split, a[rm + rb]) <= 0)
 197                                 rh = rm;
 198                             else
 199                                 lo = rm + 1;
 200                         }
 201                     }
 202                     else {
 203                         if (rn <= g)
 204                             break;
 205                         lh = ln;
 206                         T split = a[(rh = rn >>> 1) + rb];
 207                         for (int lo = 0; lo < lh; ) {
 208                             int lm = (lo + lh) >>> 1;
 209                             if (c.compare(split, a[lm + lb]) <= 0)
 210                                 lh = lm;
 211                             else
 212                                 lo = lm + 1;
 213                         }
 214                     }
 215                     Merger<T> m = new Merger<>(this, a, w, lb + lh, ln - lh,
 216                                                rb + rh, rn - rh,
 217                                                k + lh + rh, g, c);
 218                     rn = rh;
 219                     ln = lh;
 220                     addToPendingCount(1);
 221                     m.fork();
 222                 }
 223 
 224                 int lf = lb + ln, rf = rb + rn; // index bounds
 225                 while (lb < lf && rb < rf) {
 226                     T t, al, ar;
 227                     if (c.compare((al = a[lb]), (ar = a[rb])) <= 0) {
 228                         lb++; t = al;
 229                     }
 230                     else {
 231                         rb++; t = ar;
 232                     }
 233                     w[k++] = t;
 234                 }
 235                 if (rb < rf)
 236                     System.arraycopy(a, rb, w, k, rf - rb);
 237                 else if (lb < lf)
 238                     System.arraycopy(a, lb, w, k, lf - lb);
 239 
 240                 tryComplete();
 241             }
 242 
 243         }
 244     } // FJObject
 245 
 246     /** byte support class */
 247     static final class FJByte {
 248         static final class Sorter extends CountedCompleter<Void> {
 249             @java.io.Serial
 250             static final long serialVersionUID = 2446542900576103244L;
 251             final byte[] a, w;
 252             final int base, size, wbase, gran;
 253             Sorter(CountedCompleter<?> par, byte[] a, byte[] w, int base,
 254                    int size, int wbase, int gran) {
 255                 super(par);
 256                 this.a = a; this.w = w; this.base = base; this.size = size;
 257                 this.wbase = wbase; this.gran = gran;
 258             }
 259             public final void compute() {
 260                 CountedCompleter<?> s = this;
 261                 byte[] a = this.a, w = this.w; // localize all params
 262                 int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
 263                 while (n > g) {
 264                     int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
 265                     Relay fc = new Relay(new Merger(s, w, a, wb, h,
 266                                                     wb+h, n-h, b, g));
 267                     Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
 268                                                     b+u, n-u, wb+h, g));
 269                     new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
 270                     new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
 271                     Relay bc = new Relay(new Merger(fc, a, w, b, q,
 272                                                     b+q, h-q, wb, g));
 273                     new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
 274                     s = new EmptyCompleter(bc);
 275                     n = q;
 276                 }
 277                 DualPivotQuicksort.sort(a, b, b + n - 1);
 278                 s.tryComplete();
 279             }
 280         }
 281 
 282         static final class Merger extends CountedCompleter<Void> {
 283             @java.io.Serial
 284             static final long serialVersionUID = 2446542900576103244L;
 285             // main and workspace arrays
 286             final byte[] a, w;
 287             final int lbase, lsize, rbase, rsize, wbase, gran;
 288             Merger(CountedCompleter<?> par, byte[] a, byte[] w,
 289                    int lbase, int lsize, int rbase,
 290                    int rsize, int wbase, int gran) {
 291                 super(par);
 292                 this.a = a; this.w = w;
 293                 this.lbase = lbase; this.lsize = lsize;
 294                 this.rbase = rbase; this.rsize = rsize;
 295                 this.wbase = wbase; this.gran = gran;
 296             }
 297 
 298             public final void compute() {
 299                 byte[] a = this.a, w = this.w; // localize all params
 300                 int lb = this.lbase, ln = this.lsize, rb = this.rbase,
 301                     rn = this.rsize, k = this.wbase, g = this.gran;
 302                 if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
 303                     throw new IllegalStateException(); // hoist checks
 304                 for (int lh, rh;;) {  // split larger, find point in smaller
 305                     if (ln >= rn) {
 306                         if (ln <= g)
 307                             break;
 308                         rh = rn;
 309                         byte split = a[(lh = ln >>> 1) + lb];
 310                         for (int lo = 0; lo < rh; ) {
 311                             int rm = (lo + rh) >>> 1;
 312                             if (split <= a[rm + rb])
 313                                 rh = rm;
 314                             else
 315                                 lo = rm + 1;
 316                         }
 317                     }
 318                     else {
 319                         if (rn <= g)
 320                             break;
 321                         lh = ln;
 322                         byte split = a[(rh = rn >>> 1) + rb];
 323                         for (int lo = 0; lo < lh; ) {
 324                             int lm = (lo + lh) >>> 1;
 325                             if (split <= a[lm + lb])
 326                                 lh = lm;
 327                             else
 328                                 lo = lm + 1;
 329                         }
 330                     }
 331                     Merger m = new Merger(this, a, w, lb + lh, ln - lh,
 332                                           rb + rh, rn - rh,
 333                                           k + lh + rh, g);
 334                     rn = rh;
 335                     ln = lh;
 336                     addToPendingCount(1);
 337                     m.fork();
 338                 }
 339 
 340                 int lf = lb + ln, rf = rb + rn; // index bounds
 341                 while (lb < lf && rb < rf) {
 342                     byte t, al, ar;
 343                     if ((al = a[lb]) <= (ar = a[rb])) {
 344                         lb++; t = al;
 345                     }
 346                     else {
 347                         rb++; t = ar;
 348                     }
 349                     w[k++] = t;
 350                 }
 351                 if (rb < rf)
 352                     System.arraycopy(a, rb, w, k, rf - rb);
 353                 else if (lb < lf)
 354                     System.arraycopy(a, lb, w, k, lf - lb);
 355                 tryComplete();
 356             }
 357         }
 358     } // FJByte
 359 
 360     /** char support class */
 361     static final class FJChar {
 362         static final class Sorter extends CountedCompleter<Void> {
 363             @java.io.Serial
 364             static final long serialVersionUID = 2446542900576103244L;
 365             final char[] a, w;
 366             final int base, size, wbase, gran;
 367             Sorter(CountedCompleter<?> par, char[] a, char[] w, int base,
 368                    int size, int wbase, int gran) {
 369                 super(par);
 370                 this.a = a; this.w = w; this.base = base; this.size = size;
 371                 this.wbase = wbase; this.gran = gran;
 372             }
 373             public final void compute() {
 374                 CountedCompleter<?> s = this;
 375                 char[] a = this.a, w = this.w; // localize all params
 376                 int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
 377                 while (n > g) {
 378                     int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
 379                     Relay fc = new Relay(new Merger(s, w, a, wb, h,
 380                                                     wb+h, n-h, b, g));
 381                     Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
 382                                                     b+u, n-u, wb+h, g));
 383                     new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
 384                     new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
 385                     Relay bc = new Relay(new Merger(fc, a, w, b, q,
 386                                                     b+q, h-q, wb, g));
 387                     new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
 388                     s = new EmptyCompleter(bc);
 389                     n = q;
 390                 }
 391                 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
 392                 s.tryComplete();
 393             }
 394         }
 395 
 396         static final class Merger extends CountedCompleter<Void> {
 397             @java.io.Serial
 398             static final long serialVersionUID = 2446542900576103244L;
 399             final char[] a, w; // main and workspace arrays
 400             final int lbase, lsize, rbase, rsize, wbase, gran;
 401             Merger(CountedCompleter<?> par, char[] a, char[] w,
 402                    int lbase, int lsize, int rbase,
 403                    int rsize, int wbase, int gran) {
 404                 super(par);
 405                 this.a = a; this.w = w;
 406                 this.lbase = lbase; this.lsize = lsize;
 407                 this.rbase = rbase; this.rsize = rsize;
 408                 this.wbase = wbase; this.gran = gran;
 409             }
 410 
 411             public final void compute() {
 412                 char[] a = this.a, w = this.w; // localize all params
 413                 int lb = this.lbase, ln = this.lsize, rb = this.rbase,
 414                     rn = this.rsize, k = this.wbase, g = this.gran;
 415                 if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
 416                     throw new IllegalStateException(); // hoist checks
 417                 for (int lh, rh;;) {  // split larger, find point in smaller
 418                     if (ln >= rn) {
 419                         if (ln <= g)
 420                             break;
 421                         rh = rn;
 422                         char split = a[(lh = ln >>> 1) + lb];
 423                         for (int lo = 0; lo < rh; ) {
 424                             int rm = (lo + rh) >>> 1;
 425                             if (split <= a[rm + rb])
 426                                 rh = rm;
 427                             else
 428                                 lo = rm + 1;
 429                         }
 430                     }
 431                     else {
 432                         if (rn <= g)
 433                             break;
 434                         lh = ln;
 435                         char split = a[(rh = rn >>> 1) + rb];
 436                         for (int lo = 0; lo < lh; ) {
 437                             int lm = (lo + lh) >>> 1;
 438                             if (split <= a[lm + lb])
 439                                 lh = lm;
 440                             else
 441                                 lo = lm + 1;
 442                         }
 443                     }
 444                     Merger m = new Merger(this, a, w, lb + lh, ln - lh,
 445                                           rb + rh, rn - rh,
 446                                           k + lh + rh, g);
 447                     rn = rh;
 448                     ln = lh;
 449                     addToPendingCount(1);
 450                     m.fork();
 451                 }
 452 
 453                 int lf = lb + ln, rf = rb + rn; // index bounds
 454                 while (lb < lf && rb < rf) {
 455                     char t, al, ar;
 456                     if ((al = a[lb]) <= (ar = a[rb])) {
 457                         lb++; t = al;
 458                     }
 459                     else {
 460                         rb++; t = ar;
 461                     }
 462                     w[k++] = t;
 463                 }
 464                 if (rb < rf)
 465                     System.arraycopy(a, rb, w, k, rf - rb);
 466                 else if (lb < lf)
 467                     System.arraycopy(a, lb, w, k, lf - lb);
 468                 tryComplete();
 469             }
 470         }
 471     } // FJChar
 472 
 473     /** short support class */
 474     static final class FJShort {
 475         static final class Sorter extends CountedCompleter<Void> {
 476             @java.io.Serial
 477             static final long serialVersionUID = 2446542900576103244L;
 478             final short[] a, w;
 479             final int base, size, wbase, gran;
 480             Sorter(CountedCompleter<?> par, short[] a, short[] w, int base,
 481                    int size, int wbase, int gran) {
 482                 super(par);
 483                 this.a = a; this.w = w; this.base = base; this.size = size;
 484                 this.wbase = wbase; this.gran = gran;
 485             }
 486             public final void compute() {
 487                 CountedCompleter<?> s = this;
 488                 short[] a = this.a, w = this.w; // localize all params
 489                 int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
 490                 while (n > g) {
 491                     int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
 492                     Relay fc = new Relay(new Merger(s, w, a, wb, h,
 493                                                     wb+h, n-h, b, g));
 494                     Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
 495                                                     b+u, n-u, wb+h, g));
 496                     new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
 497                     new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
 498                     Relay bc = new Relay(new Merger(fc, a, w, b, q,
 499                                                     b+q, h-q, wb, g));
 500                     new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
 501                     s = new EmptyCompleter(bc);
 502                     n = q;
 503                 }
 504                 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
 505                 s.tryComplete();
 506             }
 507         }
 508 
 509         static final class Merger extends CountedCompleter<Void> {
 510             @java.io.Serial
 511             static final long serialVersionUID = 2446542900576103244L;
 512             final short[] a, w; // main and workspace arrays
 513             final int lbase, lsize, rbase, rsize, wbase, gran;
 514             Merger(CountedCompleter<?> par, short[] a, short[] w,
 515                    int lbase, int lsize, int rbase,
 516                    int rsize, int wbase, int gran) {
 517                 super(par);
 518                 this.a = a; this.w = w;
 519                 this.lbase = lbase; this.lsize = lsize;
 520                 this.rbase = rbase; this.rsize = rsize;
 521                 this.wbase = wbase; this.gran = gran;
 522             }
 523 
 524             public final void compute() {
 525                 short[] a = this.a, w = this.w; // localize all params
 526                 int lb = this.lbase, ln = this.lsize, rb = this.rbase,
 527                     rn = this.rsize, k = this.wbase, g = this.gran;
 528                 if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
 529                     throw new IllegalStateException(); // hoist checks
 530                 for (int lh, rh;;) {  // split larger, find point in smaller
 531                     if (ln >= rn) {
 532                         if (ln <= g)
 533                             break;
 534                         rh = rn;
 535                         short split = a[(lh = ln >>> 1) + lb];
 536                         for (int lo = 0; lo < rh; ) {
 537                             int rm = (lo + rh) >>> 1;
 538                             if (split <= a[rm + rb])
 539                                 rh = rm;
 540                             else
 541                                 lo = rm + 1;
 542                         }
 543                     }
 544                     else {
 545                         if (rn <= g)
 546                             break;
 547                         lh = ln;
 548                         short split = a[(rh = rn >>> 1) + rb];
 549                         for (int lo = 0; lo < lh; ) {
 550                             int lm = (lo + lh) >>> 1;
 551                             if (split <= a[lm + lb])
 552                                 lh = lm;
 553                             else
 554                                 lo = lm + 1;
 555                         }
 556                     }
 557                     Merger m = new Merger(this, a, w, lb + lh, ln - lh,
 558                                           rb + rh, rn - rh,
 559                                           k + lh + rh, g);
 560                     rn = rh;
 561                     ln = lh;
 562                     addToPendingCount(1);
 563                     m.fork();
 564                 }
 565 
 566                 int lf = lb + ln, rf = rb + rn; // index bounds
 567                 while (lb < lf && rb < rf) {
 568                     short t, al, ar;
 569                     if ((al = a[lb]) <= (ar = a[rb])) {
 570                         lb++; t = al;
 571                     }
 572                     else {
 573                         rb++; t = ar;
 574                     }
 575                     w[k++] = t;
 576                 }
 577                 if (rb < rf)
 578                     System.arraycopy(a, rb, w, k, rf - rb);
 579                 else if (lb < lf)
 580                     System.arraycopy(a, lb, w, k, lf - lb);
 581                 tryComplete();
 582             }
 583         }
 584     } // FJShort
 585 
 586     /** int support class */
 587     static final class FJInt {
 588         static final class Sorter extends CountedCompleter<Void> {
 589             @java.io.Serial
 590             static final long serialVersionUID = 2446542900576103244L;
 591             final int[] a, w;
 592             final int base, size, wbase, gran;
 593             Sorter(CountedCompleter<?> par, int[] a, int[] w, int base,
 594                    int size, int wbase, int gran) {
 595                 super(par);
 596                 this.a = a; this.w = w; this.base = base; this.size = size;
 597                 this.wbase = wbase; this.gran = gran;
 598             }
 599             public final void compute() {
 600                 CountedCompleter<?> s = this;
 601                 int[] a = this.a, w = this.w; // localize all params
 602                 int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
 603                 while (n > g) {
 604                     int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
 605                     Relay fc = new Relay(new Merger(s, w, a, wb, h,
 606                                                     wb+h, n-h, b, g));
 607                     Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
 608                                                     b+u, n-u, wb+h, g));
 609                     new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
 610                     new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
 611                     Relay bc = new Relay(new Merger(fc, a, w, b, q,
 612                                                     b+q, h-q, wb, g));
 613                     new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
 614                     s = new EmptyCompleter(bc);
 615                     n = q;
 616                 }
 617                 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
 618                 s.tryComplete();
 619             }
 620         }
 621 
 622         static final class Merger extends CountedCompleter<Void> {
 623             @java.io.Serial
 624             static final long serialVersionUID = 2446542900576103244L;
 625             final int[] a, w; // main and workspace arrays
 626             final int lbase, lsize, rbase, rsize, wbase, gran;
 627             Merger(CountedCompleter<?> par, int[] a, int[] w,
 628                    int lbase, int lsize, int rbase,
 629                    int rsize, int wbase, int gran) {
 630                 super(par);
 631                 this.a = a; this.w = w;
 632                 this.lbase = lbase; this.lsize = lsize;
 633                 this.rbase = rbase; this.rsize = rsize;
 634                 this.wbase = wbase; this.gran = gran;
 635             }
 636 
 637             public final void compute() {
 638                 int[] a = this.a, w = this.w; // localize all params
 639                 int lb = this.lbase, ln = this.lsize, rb = this.rbase,
 640                     rn = this.rsize, k = this.wbase, g = this.gran;
 641                 if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
 642                     throw new IllegalStateException(); // hoist checks
 643                 for (int lh, rh;;) {  // split larger, find point in smaller
 644                     if (ln >= rn) {
 645                         if (ln <= g)
 646                             break;
 647                         rh = rn;
 648                         int split = a[(lh = ln >>> 1) + lb];
 649                         for (int lo = 0; lo < rh; ) {
 650                             int rm = (lo + rh) >>> 1;
 651                             if (split <= a[rm + rb])
 652                                 rh = rm;
 653                             else
 654                                 lo = rm + 1;
 655                         }
 656                     }
 657                     else {
 658                         if (rn <= g)
 659                             break;
 660                         lh = ln;
 661                         int split = a[(rh = rn >>> 1) + rb];
 662                         for (int lo = 0; lo < lh; ) {
 663                             int lm = (lo + lh) >>> 1;
 664                             if (split <= a[lm + lb])
 665                                 lh = lm;
 666                             else
 667                                 lo = lm + 1;
 668                         }
 669                     }
 670                     Merger m = new Merger(this, a, w, lb + lh, ln - lh,
 671                                           rb + rh, rn - rh,
 672                                           k + lh + rh, g);
 673                     rn = rh;
 674                     ln = lh;
 675                     addToPendingCount(1);
 676                     m.fork();
 677                 }
 678 
 679                 int lf = lb + ln, rf = rb + rn; // index bounds
 680                 while (lb < lf && rb < rf) {
 681                     int t, al, ar;
 682                     if ((al = a[lb]) <= (ar = a[rb])) {
 683                         lb++; t = al;
 684                     }
 685                     else {
 686                         rb++; t = ar;
 687                     }
 688                     w[k++] = t;
 689                 }
 690                 if (rb < rf)
 691                     System.arraycopy(a, rb, w, k, rf - rb);
 692                 else if (lb < lf)
 693                     System.arraycopy(a, lb, w, k, lf - lb);
 694                 tryComplete();
 695             }
 696         }
 697     } // FJInt
 698 
 699     /** long support class */
 700     static final class FJLong {
 701         static final class Sorter extends CountedCompleter<Void> {
 702             @java.io.Serial
 703             static final long serialVersionUID = 2446542900576103244L;
 704             final long[] a, w;
 705             final int base, size, wbase, gran;
 706             Sorter(CountedCompleter<?> par, long[] a, long[] w, int base,
 707                    int size, int wbase, int gran) {
 708                 super(par);
 709                 this.a = a; this.w = w; this.base = base; this.size = size;
 710                 this.wbase = wbase; this.gran = gran;
 711             }
 712             public final void compute() {
 713                 CountedCompleter<?> s = this;
 714                 long[] a = this.a, w = this.w; // localize all params
 715                 int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
 716                 while (n > g) {
 717                     int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
 718                     Relay fc = new Relay(new Merger(s, w, a, wb, h,
 719                                                     wb+h, n-h, b, g));
 720                     Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
 721                                                     b+u, n-u, wb+h, g));
 722                     new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
 723                     new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
 724                     Relay bc = new Relay(new Merger(fc, a, w, b, q,
 725                                                     b+q, h-q, wb, g));
 726                     new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
 727                     s = new EmptyCompleter(bc);
 728                     n = q;
 729                 }
 730                 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
 731                 s.tryComplete();
 732             }
 733         }
 734 
 735         static final class Merger extends CountedCompleter<Void> {
 736             @java.io.Serial
 737             static final long serialVersionUID = 2446542900576103244L;
 738             final long[] a, w; // main and workspace arrays
 739             final int lbase, lsize, rbase, rsize, wbase, gran;
 740             Merger(CountedCompleter<?> par, long[] a, long[] w,
 741                    int lbase, int lsize, int rbase,
 742                    int rsize, int wbase, int gran) {
 743                 super(par);
 744                 this.a = a; this.w = w;
 745                 this.lbase = lbase; this.lsize = lsize;
 746                 this.rbase = rbase; this.rsize = rsize;
 747                 this.wbase = wbase; this.gran = gran;
 748             }
 749 
 750             public final void compute() {
 751                 long[] a = this.a, w = this.w; // localize all params
 752                 int lb = this.lbase, ln = this.lsize, rb = this.rbase,
 753                     rn = this.rsize, k = this.wbase, g = this.gran;
 754                 if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
 755                     throw new IllegalStateException(); // hoist checks
 756                 for (int lh, rh;;) {  // split larger, find point in smaller
 757                     if (ln >= rn) {
 758                         if (ln <= g)
 759                             break;
 760                         rh = rn;
 761                         long split = a[(lh = ln >>> 1) + lb];
 762                         for (int lo = 0; lo < rh; ) {
 763                             int rm = (lo + rh) >>> 1;
 764                             if (split <= a[rm + rb])
 765                                 rh = rm;
 766                             else
 767                                 lo = rm + 1;
 768                         }
 769                     }
 770                     else {
 771                         if (rn <= g)
 772                             break;
 773                         lh = ln;
 774                         long split = a[(rh = rn >>> 1) + rb];
 775                         for (int lo = 0; lo < lh; ) {
 776                             int lm = (lo + lh) >>> 1;
 777                             if (split <= a[lm + lb])
 778                                 lh = lm;
 779                             else
 780                                 lo = lm + 1;
 781                         }
 782                     }
 783                     Merger m = new Merger(this, a, w, lb + lh, ln - lh,
 784                                           rb + rh, rn - rh,
 785                                           k + lh + rh, g);
 786                     rn = rh;
 787                     ln = lh;
 788                     addToPendingCount(1);
 789                     m.fork();
 790                 }
 791 
 792                 int lf = lb + ln, rf = rb + rn; // index bounds
 793                 while (lb < lf && rb < rf) {
 794                     long t, al, ar;
 795                     if ((al = a[lb]) <= (ar = a[rb])) {
 796                         lb++; t = al;
 797                     }
 798                     else {
 799                         rb++; t = ar;
 800                     }
 801                     w[k++] = t;
 802                 }
 803                 if (rb < rf)
 804                     System.arraycopy(a, rb, w, k, rf - rb);
 805                 else if (lb < lf)
 806                     System.arraycopy(a, lb, w, k, lf - lb);
 807                 tryComplete();
 808             }
 809         }
 810     } // FJLong
 811 
 812     /** float support class */
 813     static final class FJFloat {
 814         static final class Sorter extends CountedCompleter<Void> {
 815             @java.io.Serial
 816             static final long serialVersionUID = 2446542900576103244L;
 817             final float[] a, w;
 818             final int base, size, wbase, gran;
 819             Sorter(CountedCompleter<?> par, float[] a, float[] w, int base,
 820                    int size, int wbase, int gran) {
 821                 super(par);
 822                 this.a = a; this.w = w; this.base = base; this.size = size;
 823                 this.wbase = wbase; this.gran = gran;
 824             }
 825             public final void compute() {
 826                 CountedCompleter<?> s = this;
 827                 float[] a = this.a, w = this.w; // localize all params
 828                 int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
 829                 while (n > g) {
 830                     int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
 831                     Relay fc = new Relay(new Merger(s, w, a, wb, h,
 832                                                     wb+h, n-h, b, g));
 833                     Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
 834                                                     b+u, n-u, wb+h, g));
 835                     new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
 836                     new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
 837                     Relay bc = new Relay(new Merger(fc, a, w, b, q,
 838                                                     b+q, h-q, wb, g));
 839                     new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
 840                     s = new EmptyCompleter(bc);
 841                     n = q;
 842                 }
 843                 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
 844                 s.tryComplete();
 845             }
 846         }
 847 
 848         static final class Merger extends CountedCompleter<Void> {
 849             @java.io.Serial
 850             static final long serialVersionUID = 2446542900576103244L;
 851             final float[] a, w; // main and workspace arrays
 852             final int lbase, lsize, rbase, rsize, wbase, gran;
 853             Merger(CountedCompleter<?> par, float[] a, float[] w,
 854                    int lbase, int lsize, int rbase,
 855                    int rsize, int wbase, int gran) {
 856                 super(par);
 857                 this.a = a; this.w = w;
 858                 this.lbase = lbase; this.lsize = lsize;
 859                 this.rbase = rbase; this.rsize = rsize;
 860                 this.wbase = wbase; this.gran = gran;
 861             }
 862 
 863             public final void compute() {
 864                 float[] a = this.a, w = this.w; // localize all params
 865                 int lb = this.lbase, ln = this.lsize, rb = this.rbase,
 866                     rn = this.rsize, k = this.wbase, g = this.gran;
 867                 if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
 868                     throw new IllegalStateException(); // hoist checks
 869                 for (int lh, rh;;) {  // split larger, find point in smaller
 870                     if (ln >= rn) {
 871                         if (ln <= g)
 872                             break;
 873                         rh = rn;
 874                         float split = a[(lh = ln >>> 1) + lb];
 875                         for (int lo = 0; lo < rh; ) {
 876                             int rm = (lo + rh) >>> 1;
 877                             if (split <= a[rm + rb])
 878                                 rh = rm;
 879                             else
 880                                 lo = rm + 1;
 881                         }
 882                     }
 883                     else {
 884                         if (rn <= g)
 885                             break;
 886                         lh = ln;
 887                         float split = a[(rh = rn >>> 1) + rb];
 888                         for (int lo = 0; lo < lh; ) {
 889                             int lm = (lo + lh) >>> 1;
 890                             if (split <= a[lm + lb])
 891                                 lh = lm;
 892                             else
 893                                 lo = lm + 1;
 894                         }
 895                     }
 896                     Merger m = new Merger(this, a, w, lb + lh, ln - lh,
 897                                           rb + rh, rn - rh,
 898                                           k + lh + rh, g);
 899                     rn = rh;
 900                     ln = lh;
 901                     addToPendingCount(1);
 902                     m.fork();
 903                 }
 904 
 905                 int lf = lb + ln, rf = rb + rn; // index bounds
 906                 while (lb < lf && rb < rf) {
 907                     float t, al, ar;
 908                     if ((al = a[lb]) <= (ar = a[rb])) {
 909                         lb++; t = al;
 910                     }
 911                     else {
 912                         rb++; t = ar;
 913                     }
 914                     w[k++] = t;
 915                 }
 916                 if (rb < rf)
 917                     System.arraycopy(a, rb, w, k, rf - rb);
 918                 else if (lb < lf)
 919                     System.arraycopy(a, lb, w, k, lf - lb);
 920                 tryComplete();
 921             }
 922         }
 923     } // FJFloat
 924 
 925     /** double support class */
 926     static final class FJDouble {
 927         static final class Sorter extends CountedCompleter<Void> {
 928             @java.io.Serial
 929             static final long serialVersionUID = 2446542900576103244L;
 930             final double[] a, w;
 931             final int base, size, wbase, gran;
 932             Sorter(CountedCompleter<?> par, double[] a, double[] w, int base,
 933                    int size, int wbase, int gran) {
 934                 super(par);
 935                 this.a = a; this.w = w; this.base = base; this.size = size;
 936                 this.wbase = wbase; this.gran = gran;
 937             }
 938             public final void compute() {
 939                 CountedCompleter<?> s = this;
 940                 double[] a = this.a, w = this.w; // localize all params
 941                 int b = this.base, n = this.size, wb = this.wbase, g = this.gran;
 942                 while (n > g) {
 943                     int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles
 944                     Relay fc = new Relay(new Merger(s, w, a, wb, h,
 945                                                     wb+h, n-h, b, g));
 946                     Relay rc = new Relay(new Merger(fc, a, w, b+h, q,
 947                                                     b+u, n-u, wb+h, g));
 948                     new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork();
 949                     new Sorter(rc, a, w, b+h, q, wb+h, g).fork();;
 950                     Relay bc = new Relay(new Merger(fc, a, w, b, q,
 951                                                     b+q, h-q, wb, g));
 952                     new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork();
 953                     s = new EmptyCompleter(bc);
 954                     n = q;
 955                 }
 956                 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n);
 957                 s.tryComplete();
 958             }
 959         }
 960 
 961         static final class Merger extends CountedCompleter<Void> {
 962             @java.io.Serial
 963             static final long serialVersionUID = 2446542900576103244L;
 964             final double[] a, w; // main and workspace arrays
 965             final int lbase, lsize, rbase, rsize, wbase, gran;
 966             Merger(CountedCompleter<?> par, double[] a, double[] w,
 967                    int lbase, int lsize, int rbase,
 968                    int rsize, int wbase, int gran) {
 969                 super(par);
 970                 this.a = a; this.w = w;
 971                 this.lbase = lbase; this.lsize = lsize;
 972                 this.rbase = rbase; this.rsize = rsize;
 973                 this.wbase = wbase; this.gran = gran;
 974             }
 975 
 976             public final void compute() {
 977                 double[] a = this.a, w = this.w; // localize all params
 978                 int lb = this.lbase, ln = this.lsize, rb = this.rbase,
 979                     rn = this.rsize, k = this.wbase, g = this.gran;
 980                 if (a == null || w == null || lb < 0 || rb < 0 || k < 0)
 981                     throw new IllegalStateException(); // hoist checks
 982                 for (int lh, rh;;) {  // split larger, find point in smaller
 983                     if (ln >= rn) {
 984                         if (ln <= g)
 985                             break;
 986                         rh = rn;
 987                         double split = a[(lh = ln >>> 1) + lb];
 988                         for (int lo = 0; lo < rh; ) {
 989                             int rm = (lo + rh) >>> 1;
 990                             if (split <= a[rm + rb])
 991                                 rh = rm;
 992                             else
 993                                 lo = rm + 1;
 994                         }
 995                     }
 996                     else {
 997                         if (rn <= g)
 998                             break;
 999                         lh = ln;
1000                         double split = a[(rh = rn >>> 1) + rb];
1001                         for (int lo = 0; lo < lh; ) {
1002                             int lm = (lo + lh) >>> 1;
1003                             if (split <= a[lm + lb])
1004                                 lh = lm;
1005                             else
1006                                 lo = lm + 1;
1007                         }
1008                     }
1009                     Merger m = new Merger(this, a, w, lb + lh, ln - lh,
1010                                           rb + rh, rn - rh,
1011                                           k + lh + rh, g);
1012                     rn = rh;
1013                     ln = lh;
1014                     addToPendingCount(1);
1015                     m.fork();
1016                 }
1017 
1018                 int lf = lb + ln, rf = rb + rn; // index bounds
1019                 while (lb < lf && rb < rf) {
1020                     double t, al, ar;
1021                     if ((al = a[lb]) <= (ar = a[rb])) {
1022                         lb++; t = al;
1023                     }
1024                     else {
1025                         rb++; t = ar;
1026                     }
1027                     w[k++] = t;
1028                 }
1029                 if (rb < rf)
1030                     System.arraycopy(a, rb, w, k, rf - rb);
1031                 else if (lb < lf)
1032                     System.arraycopy(a, lb, w, k, lf - lb);
1033                 tryComplete();
1034             }
1035         }
1036     } // FJDouble
1037 
1038 }