1 /* 2 * Copyright (c) 2012, 2013, 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 final T[] a, w; 119 final int base, size, wbase, gran; 120 Comparator<? super T> comparator; 121 Sorter(CountedCompleter<?> par, T[] a, T[] w, int base, int size, 122 int wbase, int gran, 123 Comparator<? super T> comparator) { 124 super(par); 125 this.a = a; this.w = w; this.base = base; this.size = size; 126 this.wbase = wbase; this.gran = gran; 127 this.comparator = comparator; 128 } 129 public final void compute() { 130 CountedCompleter<?> s = this; 131 Comparator<? super T> c = this.comparator; 132 T[] a = this.a, w = this.w; // localize all params 133 int b = this.base, n = this.size, wb = this.wbase, g = this.gran; 134 while (n > g) { 135 int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles 136 Relay fc = new Relay(new Merger<>(s, w, a, wb, h, 137 wb+h, n-h, b, g, c)); 138 Relay rc = new Relay(new Merger<>(fc, a, w, b+h, q, 139 b+u, n-u, wb+h, g, c)); 140 new Sorter<>(rc, a, w, b+u, n-u, wb+u, g, c).fork(); 141 new Sorter<>(rc, a, w, b+h, q, wb+h, g, c).fork();; 142 Relay bc = new Relay(new Merger<>(fc, a, w, b, q, 143 b+q, h-q, wb, g, c)); 144 new Sorter<>(bc, a, w, b+q, h-q, wb+q, g, c).fork(); 145 s = new EmptyCompleter(bc); 146 n = q; 147 } 148 TimSort.sort(a, b, b + n, c, w, wb, n); 149 s.tryComplete(); 150 } 151 } 152 153 static final class Merger<T> extends CountedCompleter<Void> { 154 @java.io.Serial 155 static final long serialVersionUID = 2446542900576103244L; 156 final T[] a, w; // main and workspace arrays 157 final int lbase, lsize, rbase, rsize, wbase, gran; 158 Comparator<? super T> comparator; 159 Merger(CountedCompleter<?> par, T[] a, T[] w, 160 int lbase, int lsize, int rbase, 161 int rsize, int wbase, int gran, 162 Comparator<? super T> comparator) { 163 super(par); 164 this.a = a; this.w = w; 165 this.lbase = lbase; this.lsize = lsize; 166 this.rbase = rbase; this.rsize = rsize; 167 this.wbase = wbase; this.gran = gran; 168 this.comparator = comparator; 169 } 170 171 public final void compute() { 172 Comparator<? super T> c = this.comparator; 173 T[] a = this.a, w = this.w; // localize all params 174 int lb = this.lbase, ln = this.lsize, rb = this.rbase, 175 rn = this.rsize, k = this.wbase, g = this.gran; 176 if (a == null || w == null || lb < 0 || rb < 0 || k < 0 || 177 c == null) 178 throw new IllegalStateException(); // hoist checks 179 for (int lh, rh;;) { // split larger, find point in smaller 180 if (ln >= rn) { 181 if (ln <= g) 182 break; 183 rh = rn; 184 T split = a[(lh = ln >>> 1) + lb]; 185 for (int lo = 0; lo < rh; ) { 186 int rm = (lo + rh) >>> 1; 187 if (c.compare(split, a[rm + rb]) <= 0) 188 rh = rm; 189 else 190 lo = rm + 1; 191 } 192 } 193 else { 194 if (rn <= g) 195 break; 196 lh = ln; 197 T split = a[(rh = rn >>> 1) + rb]; 198 for (int lo = 0; lo < lh; ) { 199 int lm = (lo + lh) >>> 1; 200 if (c.compare(split, a[lm + lb]) <= 0) 201 lh = lm; 202 else 203 lo = lm + 1; 204 } 205 } 206 Merger<T> m = new Merger<>(this, a, w, lb + lh, ln - lh, 207 rb + rh, rn - rh, 208 k + lh + rh, g, c); 209 rn = rh; 210 ln = lh; 211 addToPendingCount(1); 212 m.fork(); 213 } 214 215 int lf = lb + ln, rf = rb + rn; // index bounds 216 while (lb < lf && rb < rf) { 217 T t, al, ar; 218 if (c.compare((al = a[lb]), (ar = a[rb])) <= 0) { 219 lb++; t = al; 220 } 221 else { 222 rb++; t = ar; 223 } 224 w[k++] = t; 225 } 226 if (rb < rf) 227 System.arraycopy(a, rb, w, k, rf - rb); 228 else if (lb < lf) 229 System.arraycopy(a, lb, w, k, lf - lb); 230 231 tryComplete(); 232 } 233 234 } 235 } // FJObject 236 237 /** byte support class */ 238 static final class FJByte { 239 static final class Sorter extends CountedCompleter<Void> { 240 @java.io.Serial 241 static final long serialVersionUID = 2446542900576103244L; 242 final byte[] a, w; 243 final int base, size, wbase, gran; 244 Sorter(CountedCompleter<?> par, byte[] a, byte[] w, int base, 245 int size, int wbase, int gran) { 246 super(par); 247 this.a = a; this.w = w; this.base = base; this.size = size; 248 this.wbase = wbase; this.gran = gran; 249 } 250 public final void compute() { 251 CountedCompleter<?> s = this; 252 byte[] a = this.a, w = this.w; // localize all params 253 int b = this.base, n = this.size, wb = this.wbase, g = this.gran; 254 while (n > g) { 255 int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles 256 Relay fc = new Relay(new Merger(s, w, a, wb, h, 257 wb+h, n-h, b, g)); 258 Relay rc = new Relay(new Merger(fc, a, w, b+h, q, 259 b+u, n-u, wb+h, g)); 260 new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); 261 new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; 262 Relay bc = new Relay(new Merger(fc, a, w, b, q, 263 b+q, h-q, wb, g)); 264 new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); 265 s = new EmptyCompleter(bc); 266 n = q; 267 } 268 DualPivotQuicksort.sort(a, b, b + n - 1); 269 s.tryComplete(); 270 } 271 } 272 273 static final class Merger extends CountedCompleter<Void> { 274 @java.io.Serial 275 static final long serialVersionUID = 2446542900576103244L; 276 final byte[] a, w; // main and workspace arrays 277 final int lbase, lsize, rbase, rsize, wbase, gran; 278 Merger(CountedCompleter<?> par, byte[] a, byte[] w, 279 int lbase, int lsize, int rbase, 280 int rsize, int wbase, int gran) { 281 super(par); 282 this.a = a; this.w = w; 283 this.lbase = lbase; this.lsize = lsize; 284 this.rbase = rbase; this.rsize = rsize; 285 this.wbase = wbase; this.gran = gran; 286 } 287 288 public final void compute() { 289 byte[] a = this.a, w = this.w; // localize all params 290 int lb = this.lbase, ln = this.lsize, rb = this.rbase, 291 rn = this.rsize, k = this.wbase, g = this.gran; 292 if (a == null || w == null || lb < 0 || rb < 0 || k < 0) 293 throw new IllegalStateException(); // hoist checks 294 for (int lh, rh;;) { // split larger, find point in smaller 295 if (ln >= rn) { 296 if (ln <= g) 297 break; 298 rh = rn; 299 byte split = a[(lh = ln >>> 1) + lb]; 300 for (int lo = 0; lo < rh; ) { 301 int rm = (lo + rh) >>> 1; 302 if (split <= a[rm + rb]) 303 rh = rm; 304 else 305 lo = rm + 1; 306 } 307 } 308 else { 309 if (rn <= g) 310 break; 311 lh = ln; 312 byte split = a[(rh = rn >>> 1) + rb]; 313 for (int lo = 0; lo < lh; ) { 314 int lm = (lo + lh) >>> 1; 315 if (split <= a[lm + lb]) 316 lh = lm; 317 else 318 lo = lm + 1; 319 } 320 } 321 Merger m = new Merger(this, a, w, lb + lh, ln - lh, 322 rb + rh, rn - rh, 323 k + lh + rh, g); 324 rn = rh; 325 ln = lh; 326 addToPendingCount(1); 327 m.fork(); 328 } 329 330 int lf = lb + ln, rf = rb + rn; // index bounds 331 while (lb < lf && rb < rf) { 332 byte t, al, ar; 333 if ((al = a[lb]) <= (ar = a[rb])) { 334 lb++; t = al; 335 } 336 else { 337 rb++; t = ar; 338 } 339 w[k++] = t; 340 } 341 if (rb < rf) 342 System.arraycopy(a, rb, w, k, rf - rb); 343 else if (lb < lf) 344 System.arraycopy(a, lb, w, k, lf - lb); 345 tryComplete(); 346 } 347 } 348 } // FJByte 349 350 /** char support class */ 351 static final class FJChar { 352 static final class Sorter extends CountedCompleter<Void> { 353 @java.io.Serial 354 static final long serialVersionUID = 2446542900576103244L; 355 final char[] a, w; 356 final int base, size, wbase, gran; 357 Sorter(CountedCompleter<?> par, char[] a, char[] w, int base, 358 int size, int wbase, int gran) { 359 super(par); 360 this.a = a; this.w = w; this.base = base; this.size = size; 361 this.wbase = wbase; this.gran = gran; 362 } 363 public final void compute() { 364 CountedCompleter<?> s = this; 365 char[] a = this.a, w = this.w; // localize all params 366 int b = this.base, n = this.size, wb = this.wbase, g = this.gran; 367 while (n > g) { 368 int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles 369 Relay fc = new Relay(new Merger(s, w, a, wb, h, 370 wb+h, n-h, b, g)); 371 Relay rc = new Relay(new Merger(fc, a, w, b+h, q, 372 b+u, n-u, wb+h, g)); 373 new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); 374 new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; 375 Relay bc = new Relay(new Merger(fc, a, w, b, q, 376 b+q, h-q, wb, g)); 377 new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); 378 s = new EmptyCompleter(bc); 379 n = q; 380 } 381 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); 382 s.tryComplete(); 383 } 384 } 385 386 static final class Merger extends CountedCompleter<Void> { 387 @java.io.Serial 388 static final long serialVersionUID = 2446542900576103244L; 389 final char[] a, w; // main and workspace arrays 390 final int lbase, lsize, rbase, rsize, wbase, gran; 391 Merger(CountedCompleter<?> par, char[] a, char[] w, 392 int lbase, int lsize, int rbase, 393 int rsize, int wbase, int gran) { 394 super(par); 395 this.a = a; this.w = w; 396 this.lbase = lbase; this.lsize = lsize; 397 this.rbase = rbase; this.rsize = rsize; 398 this.wbase = wbase; this.gran = gran; 399 } 400 401 public final void compute() { 402 char[] a = this.a, w = this.w; // localize all params 403 int lb = this.lbase, ln = this.lsize, rb = this.rbase, 404 rn = this.rsize, k = this.wbase, g = this.gran; 405 if (a == null || w == null || lb < 0 || rb < 0 || k < 0) 406 throw new IllegalStateException(); // hoist checks 407 for (int lh, rh;;) { // split larger, find point in smaller 408 if (ln >= rn) { 409 if (ln <= g) 410 break; 411 rh = rn; 412 char split = a[(lh = ln >>> 1) + lb]; 413 for (int lo = 0; lo < rh; ) { 414 int rm = (lo + rh) >>> 1; 415 if (split <= a[rm + rb]) 416 rh = rm; 417 else 418 lo = rm + 1; 419 } 420 } 421 else { 422 if (rn <= g) 423 break; 424 lh = ln; 425 char split = a[(rh = rn >>> 1) + rb]; 426 for (int lo = 0; lo < lh; ) { 427 int lm = (lo + lh) >>> 1; 428 if (split <= a[lm + lb]) 429 lh = lm; 430 else 431 lo = lm + 1; 432 } 433 } 434 Merger m = new Merger(this, a, w, lb + lh, ln - lh, 435 rb + rh, rn - rh, 436 k + lh + rh, g); 437 rn = rh; 438 ln = lh; 439 addToPendingCount(1); 440 m.fork(); 441 } 442 443 int lf = lb + ln, rf = rb + rn; // index bounds 444 while (lb < lf && rb < rf) { 445 char t, al, ar; 446 if ((al = a[lb]) <= (ar = a[rb])) { 447 lb++; t = al; 448 } 449 else { 450 rb++; t = ar; 451 } 452 w[k++] = t; 453 } 454 if (rb < rf) 455 System.arraycopy(a, rb, w, k, rf - rb); 456 else if (lb < lf) 457 System.arraycopy(a, lb, w, k, lf - lb); 458 tryComplete(); 459 } 460 } 461 } // FJChar 462 463 /** short support class */ 464 static final class FJShort { 465 static final class Sorter extends CountedCompleter<Void> { 466 @java.io.Serial 467 static final long serialVersionUID = 2446542900576103244L; 468 final short[] a, w; 469 final int base, size, wbase, gran; 470 Sorter(CountedCompleter<?> par, short[] a, short[] w, int base, 471 int size, int wbase, int gran) { 472 super(par); 473 this.a = a; this.w = w; this.base = base; this.size = size; 474 this.wbase = wbase; this.gran = gran; 475 } 476 public final void compute() { 477 CountedCompleter<?> s = this; 478 short[] a = this.a, w = this.w; // localize all params 479 int b = this.base, n = this.size, wb = this.wbase, g = this.gran; 480 while (n > g) { 481 int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles 482 Relay fc = new Relay(new Merger(s, w, a, wb, h, 483 wb+h, n-h, b, g)); 484 Relay rc = new Relay(new Merger(fc, a, w, b+h, q, 485 b+u, n-u, wb+h, g)); 486 new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); 487 new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; 488 Relay bc = new Relay(new Merger(fc, a, w, b, q, 489 b+q, h-q, wb, g)); 490 new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); 491 s = new EmptyCompleter(bc); 492 n = q; 493 } 494 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); 495 s.tryComplete(); 496 } 497 } 498 499 static final class Merger extends CountedCompleter<Void> { 500 @java.io.Serial 501 static final long serialVersionUID = 2446542900576103244L; 502 final short[] a, w; // main and workspace arrays 503 final int lbase, lsize, rbase, rsize, wbase, gran; 504 Merger(CountedCompleter<?> par, short[] a, short[] w, 505 int lbase, int lsize, int rbase, 506 int rsize, int wbase, int gran) { 507 super(par); 508 this.a = a; this.w = w; 509 this.lbase = lbase; this.lsize = lsize; 510 this.rbase = rbase; this.rsize = rsize; 511 this.wbase = wbase; this.gran = gran; 512 } 513 514 public final void compute() { 515 short[] a = this.a, w = this.w; // localize all params 516 int lb = this.lbase, ln = this.lsize, rb = this.rbase, 517 rn = this.rsize, k = this.wbase, g = this.gran; 518 if (a == null || w == null || lb < 0 || rb < 0 || k < 0) 519 throw new IllegalStateException(); // hoist checks 520 for (int lh, rh;;) { // split larger, find point in smaller 521 if (ln >= rn) { 522 if (ln <= g) 523 break; 524 rh = rn; 525 short split = a[(lh = ln >>> 1) + lb]; 526 for (int lo = 0; lo < rh; ) { 527 int rm = (lo + rh) >>> 1; 528 if (split <= a[rm + rb]) 529 rh = rm; 530 else 531 lo = rm + 1; 532 } 533 } 534 else { 535 if (rn <= g) 536 break; 537 lh = ln; 538 short split = a[(rh = rn >>> 1) + rb]; 539 for (int lo = 0; lo < lh; ) { 540 int lm = (lo + lh) >>> 1; 541 if (split <= a[lm + lb]) 542 lh = lm; 543 else 544 lo = lm + 1; 545 } 546 } 547 Merger m = new Merger(this, a, w, lb + lh, ln - lh, 548 rb + rh, rn - rh, 549 k + lh + rh, g); 550 rn = rh; 551 ln = lh; 552 addToPendingCount(1); 553 m.fork(); 554 } 555 556 int lf = lb + ln, rf = rb + rn; // index bounds 557 while (lb < lf && rb < rf) { 558 short t, al, ar; 559 if ((al = a[lb]) <= (ar = a[rb])) { 560 lb++; t = al; 561 } 562 else { 563 rb++; t = ar; 564 } 565 w[k++] = t; 566 } 567 if (rb < rf) 568 System.arraycopy(a, rb, w, k, rf - rb); 569 else if (lb < lf) 570 System.arraycopy(a, lb, w, k, lf - lb); 571 tryComplete(); 572 } 573 } 574 } // FJShort 575 576 /** int support class */ 577 static final class FJInt { 578 static final class Sorter extends CountedCompleter<Void> { 579 @java.io.Serial 580 static final long serialVersionUID = 2446542900576103244L; 581 final int[] a, w; 582 final int base, size, wbase, gran; 583 Sorter(CountedCompleter<?> par, int[] a, int[] w, int base, 584 int size, int wbase, int gran) { 585 super(par); 586 this.a = a; this.w = w; this.base = base; this.size = size; 587 this.wbase = wbase; this.gran = gran; 588 } 589 public final void compute() { 590 CountedCompleter<?> s = this; 591 int[] a = this.a, w = this.w; // localize all params 592 int b = this.base, n = this.size, wb = this.wbase, g = this.gran; 593 while (n > g) { 594 int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles 595 Relay fc = new Relay(new Merger(s, w, a, wb, h, 596 wb+h, n-h, b, g)); 597 Relay rc = new Relay(new Merger(fc, a, w, b+h, q, 598 b+u, n-u, wb+h, g)); 599 new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); 600 new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; 601 Relay bc = new Relay(new Merger(fc, a, w, b, q, 602 b+q, h-q, wb, g)); 603 new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); 604 s = new EmptyCompleter(bc); 605 n = q; 606 } 607 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); 608 s.tryComplete(); 609 } 610 } 611 612 static final class Merger extends CountedCompleter<Void> { 613 @java.io.Serial 614 static final long serialVersionUID = 2446542900576103244L; 615 final int[] a, w; // main and workspace arrays 616 final int lbase, lsize, rbase, rsize, wbase, gran; 617 Merger(CountedCompleter<?> par, int[] a, int[] w, 618 int lbase, int lsize, int rbase, 619 int rsize, int wbase, int gran) { 620 super(par); 621 this.a = a; this.w = w; 622 this.lbase = lbase; this.lsize = lsize; 623 this.rbase = rbase; this.rsize = rsize; 624 this.wbase = wbase; this.gran = gran; 625 } 626 627 public final void compute() { 628 int[] a = this.a, w = this.w; // localize all params 629 int lb = this.lbase, ln = this.lsize, rb = this.rbase, 630 rn = this.rsize, k = this.wbase, g = this.gran; 631 if (a == null || w == null || lb < 0 || rb < 0 || k < 0) 632 throw new IllegalStateException(); // hoist checks 633 for (int lh, rh;;) { // split larger, find point in smaller 634 if (ln >= rn) { 635 if (ln <= g) 636 break; 637 rh = rn; 638 int split = a[(lh = ln >>> 1) + lb]; 639 for (int lo = 0; lo < rh; ) { 640 int rm = (lo + rh) >>> 1; 641 if (split <= a[rm + rb]) 642 rh = rm; 643 else 644 lo = rm + 1; 645 } 646 } 647 else { 648 if (rn <= g) 649 break; 650 lh = ln; 651 int split = a[(rh = rn >>> 1) + rb]; 652 for (int lo = 0; lo < lh; ) { 653 int lm = (lo + lh) >>> 1; 654 if (split <= a[lm + lb]) 655 lh = lm; 656 else 657 lo = lm + 1; 658 } 659 } 660 Merger m = new Merger(this, a, w, lb + lh, ln - lh, 661 rb + rh, rn - rh, 662 k + lh + rh, g); 663 rn = rh; 664 ln = lh; 665 addToPendingCount(1); 666 m.fork(); 667 } 668 669 int lf = lb + ln, rf = rb + rn; // index bounds 670 while (lb < lf && rb < rf) { 671 int t, al, ar; 672 if ((al = a[lb]) <= (ar = a[rb])) { 673 lb++; t = al; 674 } 675 else { 676 rb++; t = ar; 677 } 678 w[k++] = t; 679 } 680 if (rb < rf) 681 System.arraycopy(a, rb, w, k, rf - rb); 682 else if (lb < lf) 683 System.arraycopy(a, lb, w, k, lf - lb); 684 tryComplete(); 685 } 686 } 687 } // FJInt 688 689 /** long support class */ 690 static final class FJLong { 691 static final class Sorter extends CountedCompleter<Void> { 692 @java.io.Serial 693 static final long serialVersionUID = 2446542900576103244L; 694 final long[] a, w; 695 final int base, size, wbase, gran; 696 Sorter(CountedCompleter<?> par, long[] a, long[] w, int base, 697 int size, int wbase, int gran) { 698 super(par); 699 this.a = a; this.w = w; this.base = base; this.size = size; 700 this.wbase = wbase; this.gran = gran; 701 } 702 public final void compute() { 703 CountedCompleter<?> s = this; 704 long[] a = this.a, w = this.w; // localize all params 705 int b = this.base, n = this.size, wb = this.wbase, g = this.gran; 706 while (n > g) { 707 int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles 708 Relay fc = new Relay(new Merger(s, w, a, wb, h, 709 wb+h, n-h, b, g)); 710 Relay rc = new Relay(new Merger(fc, a, w, b+h, q, 711 b+u, n-u, wb+h, g)); 712 new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); 713 new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; 714 Relay bc = new Relay(new Merger(fc, a, w, b, q, 715 b+q, h-q, wb, g)); 716 new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); 717 s = new EmptyCompleter(bc); 718 n = q; 719 } 720 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); 721 s.tryComplete(); 722 } 723 } 724 725 static final class Merger extends CountedCompleter<Void> { 726 @java.io.Serial 727 static final long serialVersionUID = 2446542900576103244L; 728 final long[] a, w; // main and workspace arrays 729 final int lbase, lsize, rbase, rsize, wbase, gran; 730 Merger(CountedCompleter<?> par, long[] a, long[] w, 731 int lbase, int lsize, int rbase, 732 int rsize, int wbase, int gran) { 733 super(par); 734 this.a = a; this.w = w; 735 this.lbase = lbase; this.lsize = lsize; 736 this.rbase = rbase; this.rsize = rsize; 737 this.wbase = wbase; this.gran = gran; 738 } 739 740 public final void compute() { 741 long[] a = this.a, w = this.w; // localize all params 742 int lb = this.lbase, ln = this.lsize, rb = this.rbase, 743 rn = this.rsize, k = this.wbase, g = this.gran; 744 if (a == null || w == null || lb < 0 || rb < 0 || k < 0) 745 throw new IllegalStateException(); // hoist checks 746 for (int lh, rh;;) { // split larger, find point in smaller 747 if (ln >= rn) { 748 if (ln <= g) 749 break; 750 rh = rn; 751 long split = a[(lh = ln >>> 1) + lb]; 752 for (int lo = 0; lo < rh; ) { 753 int rm = (lo + rh) >>> 1; 754 if (split <= a[rm + rb]) 755 rh = rm; 756 else 757 lo = rm + 1; 758 } 759 } 760 else { 761 if (rn <= g) 762 break; 763 lh = ln; 764 long split = a[(rh = rn >>> 1) + rb]; 765 for (int lo = 0; lo < lh; ) { 766 int lm = (lo + lh) >>> 1; 767 if (split <= a[lm + lb]) 768 lh = lm; 769 else 770 lo = lm + 1; 771 } 772 } 773 Merger m = new Merger(this, a, w, lb + lh, ln - lh, 774 rb + rh, rn - rh, 775 k + lh + rh, g); 776 rn = rh; 777 ln = lh; 778 addToPendingCount(1); 779 m.fork(); 780 } 781 782 int lf = lb + ln, rf = rb + rn; // index bounds 783 while (lb < lf && rb < rf) { 784 long t, al, ar; 785 if ((al = a[lb]) <= (ar = a[rb])) { 786 lb++; t = al; 787 } 788 else { 789 rb++; t = ar; 790 } 791 w[k++] = t; 792 } 793 if (rb < rf) 794 System.arraycopy(a, rb, w, k, rf - rb); 795 else if (lb < lf) 796 System.arraycopy(a, lb, w, k, lf - lb); 797 tryComplete(); 798 } 799 } 800 } // FJLong 801 802 /** float support class */ 803 static final class FJFloat { 804 static final class Sorter extends CountedCompleter<Void> { 805 @java.io.Serial 806 static final long serialVersionUID = 2446542900576103244L; 807 final float[] a, w; 808 final int base, size, wbase, gran; 809 Sorter(CountedCompleter<?> par, float[] a, float[] w, int base, 810 int size, int wbase, int gran) { 811 super(par); 812 this.a = a; this.w = w; this.base = base; this.size = size; 813 this.wbase = wbase; this.gran = gran; 814 } 815 public final void compute() { 816 CountedCompleter<?> s = this; 817 float[] a = this.a, w = this.w; // localize all params 818 int b = this.base, n = this.size, wb = this.wbase, g = this.gran; 819 while (n > g) { 820 int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles 821 Relay fc = new Relay(new Merger(s, w, a, wb, h, 822 wb+h, n-h, b, g)); 823 Relay rc = new Relay(new Merger(fc, a, w, b+h, q, 824 b+u, n-u, wb+h, g)); 825 new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); 826 new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; 827 Relay bc = new Relay(new Merger(fc, a, w, b, q, 828 b+q, h-q, wb, g)); 829 new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); 830 s = new EmptyCompleter(bc); 831 n = q; 832 } 833 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); 834 s.tryComplete(); 835 } 836 } 837 838 static final class Merger extends CountedCompleter<Void> { 839 @java.io.Serial 840 static final long serialVersionUID = 2446542900576103244L; 841 final float[] a, w; // main and workspace arrays 842 final int lbase, lsize, rbase, rsize, wbase, gran; 843 Merger(CountedCompleter<?> par, float[] a, float[] w, 844 int lbase, int lsize, int rbase, 845 int rsize, int wbase, int gran) { 846 super(par); 847 this.a = a; this.w = w; 848 this.lbase = lbase; this.lsize = lsize; 849 this.rbase = rbase; this.rsize = rsize; 850 this.wbase = wbase; this.gran = gran; 851 } 852 853 public final void compute() { 854 float[] a = this.a, w = this.w; // localize all params 855 int lb = this.lbase, ln = this.lsize, rb = this.rbase, 856 rn = this.rsize, k = this.wbase, g = this.gran; 857 if (a == null || w == null || lb < 0 || rb < 0 || k < 0) 858 throw new IllegalStateException(); // hoist checks 859 for (int lh, rh;;) { // split larger, find point in smaller 860 if (ln >= rn) { 861 if (ln <= g) 862 break; 863 rh = rn; 864 float split = a[(lh = ln >>> 1) + lb]; 865 for (int lo = 0; lo < rh; ) { 866 int rm = (lo + rh) >>> 1; 867 if (split <= a[rm + rb]) 868 rh = rm; 869 else 870 lo = rm + 1; 871 } 872 } 873 else { 874 if (rn <= g) 875 break; 876 lh = ln; 877 float split = a[(rh = rn >>> 1) + rb]; 878 for (int lo = 0; lo < lh; ) { 879 int lm = (lo + lh) >>> 1; 880 if (split <= a[lm + lb]) 881 lh = lm; 882 else 883 lo = lm + 1; 884 } 885 } 886 Merger m = new Merger(this, a, w, lb + lh, ln - lh, 887 rb + rh, rn - rh, 888 k + lh + rh, g); 889 rn = rh; 890 ln = lh; 891 addToPendingCount(1); 892 m.fork(); 893 } 894 895 int lf = lb + ln, rf = rb + rn; // index bounds 896 while (lb < lf && rb < rf) { 897 float t, al, ar; 898 if ((al = a[lb]) <= (ar = a[rb])) { 899 lb++; t = al; 900 } 901 else { 902 rb++; t = ar; 903 } 904 w[k++] = t; 905 } 906 if (rb < rf) 907 System.arraycopy(a, rb, w, k, rf - rb); 908 else if (lb < lf) 909 System.arraycopy(a, lb, w, k, lf - lb); 910 tryComplete(); 911 } 912 } 913 } // FJFloat 914 915 /** double support class */ 916 static final class FJDouble { 917 static final class Sorter extends CountedCompleter<Void> { 918 @java.io.Serial 919 static final long serialVersionUID = 2446542900576103244L; 920 final double[] a, w; 921 final int base, size, wbase, gran; 922 Sorter(CountedCompleter<?> par, double[] a, double[] w, int base, 923 int size, int wbase, int gran) { 924 super(par); 925 this.a = a; this.w = w; this.base = base; this.size = size; 926 this.wbase = wbase; this.gran = gran; 927 } 928 public final void compute() { 929 CountedCompleter<?> s = this; 930 double[] a = this.a, w = this.w; // localize all params 931 int b = this.base, n = this.size, wb = this.wbase, g = this.gran; 932 while (n > g) { 933 int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles 934 Relay fc = new Relay(new Merger(s, w, a, wb, h, 935 wb+h, n-h, b, g)); 936 Relay rc = new Relay(new Merger(fc, a, w, b+h, q, 937 b+u, n-u, wb+h, g)); 938 new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); 939 new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; 940 Relay bc = new Relay(new Merger(fc, a, w, b, q, 941 b+q, h-q, wb, g)); 942 new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); 943 s = new EmptyCompleter(bc); 944 n = q; 945 } 946 DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); 947 s.tryComplete(); 948 } 949 } 950 951 static final class Merger extends CountedCompleter<Void> { 952 @java.io.Serial 953 static final long serialVersionUID = 2446542900576103244L; 954 final double[] a, w; // main and workspace arrays 955 final int lbase, lsize, rbase, rsize, wbase, gran; 956 Merger(CountedCompleter<?> par, double[] a, double[] w, 957 int lbase, int lsize, int rbase, 958 int rsize, int wbase, int gran) { 959 super(par); 960 this.a = a; this.w = w; 961 this.lbase = lbase; this.lsize = lsize; 962 this.rbase = rbase; this.rsize = rsize; 963 this.wbase = wbase; this.gran = gran; 964 } 965 966 public final void compute() { 967 double[] a = this.a, w = this.w; // localize all params 968 int lb = this.lbase, ln = this.lsize, rb = this.rbase, 969 rn = this.rsize, k = this.wbase, g = this.gran; 970 if (a == null || w == null || lb < 0 || rb < 0 || k < 0) 971 throw new IllegalStateException(); // hoist checks 972 for (int lh, rh;;) { // split larger, find point in smaller 973 if (ln >= rn) { 974 if (ln <= g) 975 break; 976 rh = rn; 977 double split = a[(lh = ln >>> 1) + lb]; 978 for (int lo = 0; lo < rh; ) { 979 int rm = (lo + rh) >>> 1; 980 if (split <= a[rm + rb]) 981 rh = rm; 982 else 983 lo = rm + 1; 984 } 985 } 986 else { 987 if (rn <= g) 988 break; 989 lh = ln; 990 double split = a[(rh = rn >>> 1) + rb]; 991 for (int lo = 0; lo < lh; ) { 992 int lm = (lo + lh) >>> 1; 993 if (split <= a[lm + lb]) 994 lh = lm; 995 else 996 lo = lm + 1; 997 } 998 } 999 Merger m = new Merger(this, a, w, lb + lh, ln - lh, 1000 rb + rh, rn - rh, 1001 k + lh + rh, g); 1002 rn = rh; 1003 ln = lh; 1004 addToPendingCount(1); 1005 m.fork(); 1006 } 1007 1008 int lf = lb + ln, rf = rb + rn; // index bounds 1009 while (lb < lf && rb < rf) { 1010 double t, al, ar; 1011 if ((al = a[lb]) <= (ar = a[rb])) { 1012 lb++; t = al; 1013 } 1014 else { 1015 rb++; t = ar; 1016 } 1017 w[k++] = t; 1018 } 1019 if (rb < rf) 1020 System.arraycopy(a, rb, w, k, rf - rb); 1021 else if (lb < lf) 1022 System.arraycopy(a, lb, w, k, lf - lb); 1023 tryComplete(); 1024 } 1025 } 1026 } // FJDouble 1027 1028 }