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