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