1 /*
   2  * Copyright (c) 2009, 2023, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug 6880672 6896573 6899694 6976036 7013585 7018258 8003981 8226297
  27  * @library /test/lib
  28  * @compile/module=java.base java/util/SortingHelper.java
  29  * @build Sorting
  30  * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_arraySort,_arrayPartition Sorting -shortrun
  31  * @run main/othervm -XX:-TieredCompilation -XX:CompileCommand=CompileThresholdScaling,java.util.DualPivotQuicksort::sort,0.0001 Sorting -shortrun
  32  * @summary Exercise Arrays.sort, Arrays.parallelSort
  33  *
  34  * @author Vladimir Yaroslavskiy
  35  * @author Jon Bentley
  36  * @author Josh Bloch
  37  */
  38 
  39 import java.io.PrintStream;
  40 import java.util.Comparator;
  41 import java.util.Random;
  42 import java.util.SortingHelper;
  43 
  44 import jdk.test.lib.valueclass.AsValueClass;
  45 
  46 public class Sorting {
  47 
  48     private static final PrintStream out = System.out;
  49     private static final PrintStream err = System.err;
  50 
  51     // Array lengths used in a long run (default)
  52     private static final int[] LONG_RUN_LENGTHS = {
  53         1, 3, 8, 21, 55, 100, 1_000, 10_000, 100_000 };
  54 
  55     // Array lengths used in a short run
  56     private static final int[] SHORT_RUN_LENGTHS = {
  57         1, 8, 55, 100, 10_000 };
  58 
  59     // Random initial values used in a long run (default)
  60     private static final TestRandom[] LONG_RUN_RANDOMS = {
  61         TestRandom.BABA, TestRandom.DEDA, TestRandom.C0FFEE };
  62 
  63     // Random initial values used in a short run
  64     private static final TestRandom[] SHORT_RUN_RANDOMS = {
  65         TestRandom.C0FFEE };
  66 
  67     // Constants used in subarray sorting
  68     private static final int A380 = 0xA380;
  69     private static final int B747 = 0xB747;
  70 
  71     private final SortingHelper sortingHelper;
  72     private final TestRandom[] randoms;
  73     private final int[] lengths;
  74     private Object[] gold;
  75     private Object[] test;
  76 
  77     @AsValueClass
  78     record Point(int x, int y) implements Comparable<Point> {
  79         public int compareTo(Point p) {
  80             return Integer.compare(x * x + y * y, p.x * p.x + p.y * p.y);
  81         }
  82     }
  83 
  84     public static void main(String[] args) {
  85         long start = System.currentTimeMillis();
  86         boolean shortRun = args.length > 0 && args[0].equals("-shortrun");
  87 
  88         int[] lengths = shortRun ? SHORT_RUN_LENGTHS : LONG_RUN_LENGTHS;
  89         TestRandom[] randoms = shortRun ? SHORT_RUN_RANDOMS : LONG_RUN_RANDOMS;
  90 
  91         new Sorting(SortingHelper.DUAL_PIVOT_QUICKSORT, randoms, lengths).testCore();
  92         new Sorting(SortingHelper.PARALLEL_SORT, randoms, lengths).testCore();
  93         new Sorting(SortingHelper.HEAP_SORT, randoms, lengths).testBasic();
  94         new Sorting(SortingHelper.ARRAYS_SORT, randoms, lengths).testAll();
  95         new Sorting(SortingHelper.ARRAYS_PARALLEL_SORT, randoms, lengths).testAll();
  96 
  97         long end = System.currentTimeMillis();
  98         out.format("PASSED in %d sec.\n", (end - start) / 1000);
  99     }
 100 
 101     private Sorting(SortingHelper sortingHelper, TestRandom[] randoms, int[] lengths) {
 102         this.sortingHelper = sortingHelper;
 103         this.randoms = randoms;
 104         this.lengths = lengths;
 105     }
 106 
 107     private void testBasic() {
 108         testEmptyArray();
 109 
 110         for (int length : lengths) {
 111             createData(length);
 112             testBasic(length);
 113         }
 114     }
 115 
 116     private void testBasic(int length) {
 117         for (TestRandom random : randoms) {
 118             testWithInsertionSort(length, random);
 119             testWithCheckSum(length, random);
 120             testWithScrambling(length, random);
 121         }
 122     }
 123 
 124     private void testCore() {
 125         for (int length : lengths) {
 126             createData(length);
 127             testCore(length);
 128         }
 129     }
 130 
 131     private void testCore(int length) {
 132         testBasic(length);
 133 
 134         for (TestRandom random : randoms) {
 135             testMergingSort(length, random);
 136             testSubArray(length, random);
 137             testNegativeZero(length, random);
 138             testFloatingPointSorting(length, random);
 139         }
 140     }
 141 
 142     private void testAll() {
 143         for (int length : lengths) {
 144             createData(length);
 145             testAll(length);
 146         }
 147     }
 148 
 149     private void testAll(int length) {
 150         testCore(length);
 151 
 152         for (TestRandom random : randoms) {
 153             testRange(length, random);
 154             testStability(length, random);
 155             testValueClass(length, random);
 156         }
 157     }
 158 
 159     private void testValueClass(int length, TestRandom random) {
 160         printTestName("Test value class (Point[])", random, length);
 161 
 162         Point[] points = new Point[length];
 163         for (int i = 0; i < length; i++) {
 164             points[i] = new Point(random.nextInt(10) - 5, random.nextInt(10) - 5);
 165         }
 166 
 167         sortingHelper.sort(points);
 168         checkSorted(points);
 169 
 170         Comparator<Point> byXThenY = Comparator.comparingInt(Point::x).thenComparingInt(Point::y);
 171         sortingHelper.sort(points, byXThenY);
 172         checkSorted(points, byXThenY);
 173 
 174         out.println();
 175     }
 176 
 177     private void testEmptyArray() {
 178         testEmptyAndNullIntArray();
 179         testEmptyAndNullLongArray();
 180         testEmptyAndNullByteArray();
 181         testEmptyAndNullCharArray();
 182         testEmptyAndNullShortArray();
 183         testEmptyAndNullFloatArray();
 184         testEmptyAndNullDoubleArray();
 185     }
 186 
 187     private void testStability(int length, TestRandom random) {
 188         printTestName("Test stability", random, length);
 189 
 190         Pair[] a = build(length, random);
 191         sortingHelper.sort(a);
 192         checkSorted(a);
 193         checkStable(a);
 194 
 195         a = build(length, random);
 196         sortingHelper.sort(a, pairComparator);
 197         checkSorted(a);
 198         checkStable(a);
 199 
 200         out.println();
 201     }
 202 
 203     private void testEmptyAndNullIntArray() {
 204         sortingHelper.sort(new int[] {});
 205         sortingHelper.sort(new int[] {}, 0, 0);
 206 
 207         try {
 208             sortingHelper.sort(null);
 209         } catch (NullPointerException expected) {
 210             try {
 211                 sortingHelper.sort(null, 0, 0);
 212             } catch (NullPointerException expected2) {
 213                 return;
 214             }
 215             fail(sortingHelper + "(int[],fromIndex,toIndex) shouldn't " +
 216                 "catch null array");
 217         }
 218         fail(sortingHelper + "(int[]) shouldn't catch null array");
 219     }
 220 
 221     private void testEmptyAndNullLongArray() {
 222         sortingHelper.sort(new long[] {});
 223         sortingHelper.sort(new long[] {}, 0, 0);
 224 
 225         try {
 226             sortingHelper.sort(null);
 227         } catch (NullPointerException expected) {
 228             try {
 229                 sortingHelper.sort(null, 0, 0);
 230             } catch (NullPointerException expected2) {
 231                 return;
 232             }
 233             fail(sortingHelper + "(long[],fromIndex,toIndex) shouldn't " +
 234                 "catch null array");
 235         }
 236         fail(sortingHelper + "(long[]) shouldn't catch null array");
 237     }
 238 
 239     private void testEmptyAndNullByteArray() {
 240         sortingHelper.sort(new byte[] {});
 241         sortingHelper.sort(new byte[] {}, 0, 0);
 242 
 243         try {
 244             sortingHelper.sort(null);
 245         } catch (NullPointerException expected) {
 246             try {
 247                 sortingHelper.sort(null, 0, 0);
 248             } catch (NullPointerException expected2) {
 249                 return;
 250             }
 251             fail(sortingHelper + "(byte[],fromIndex,toIndex) shouldn't " +
 252                 "catch null array");
 253         }
 254         fail(sortingHelper + "(byte[]) shouldn't catch null array");
 255     }
 256 
 257     private void testEmptyAndNullCharArray() {
 258         sortingHelper.sort(new char[] {});
 259         sortingHelper.sort(new char[] {}, 0, 0);
 260 
 261         try {
 262             sortingHelper.sort(null);
 263         } catch (NullPointerException expected) {
 264             try {
 265                 sortingHelper.sort(null, 0, 0);
 266             } catch (NullPointerException expected2) {
 267                 return;
 268             }
 269             fail(sortingHelper + "(char[],fromIndex,toIndex) shouldn't " +
 270                 "catch null array");
 271         }
 272         fail(sortingHelper + "(char[]) shouldn't catch null array");
 273     }
 274 
 275     private void testEmptyAndNullShortArray() {
 276         sortingHelper.sort(new short[] {});
 277         sortingHelper.sort(new short[] {}, 0, 0);
 278 
 279         try {
 280             sortingHelper.sort(null);
 281         } catch (NullPointerException expected) {
 282             try {
 283                 sortingHelper.sort(null, 0, 0);
 284             } catch (NullPointerException expected2) {
 285                 return;
 286             }
 287             fail(sortingHelper + "(short[],fromIndex,toIndex) shouldn't " +
 288                 "catch null array");
 289         }
 290         fail(sortingHelper + "(short[]) shouldn't catch null array");
 291     }
 292 
 293     private void testEmptyAndNullFloatArray() {
 294         sortingHelper.sort(new float[] {});
 295         sortingHelper.sort(new float[] {}, 0, 0);
 296 
 297         try {
 298             sortingHelper.sort(null);
 299         } catch (NullPointerException expected) {
 300             try {
 301                 sortingHelper.sort(null, 0, 0);
 302             } catch (NullPointerException expected2) {
 303                 return;
 304             }
 305             fail(sortingHelper + "(float[],fromIndex,toIndex) shouldn't " +
 306                 "catch null array");
 307         }
 308         fail(sortingHelper + "(float[]) shouldn't catch null array");
 309     }
 310 
 311     private void testEmptyAndNullDoubleArray() {
 312         sortingHelper.sort(new double[] {});
 313         sortingHelper.sort(new double[] {}, 0, 0);
 314 
 315         try {
 316             sortingHelper.sort(null);
 317         } catch (NullPointerException expected) {
 318             try {
 319                 sortingHelper.sort(null, 0, 0);
 320             } catch (NullPointerException expected2) {
 321                 return;
 322             }
 323             fail(sortingHelper + "(double[],fromIndex,toIndex) shouldn't " +
 324                 "catch null array");
 325         }
 326         fail(sortingHelper + "(double[]) shouldn't catch null array");
 327     }
 328 
 329     private void testSubArray(int length, TestRandom random) {
 330         if (length < 4) {
 331             return;
 332         }
 333         for (int m = 1; m < length / 2; m <<= 1) {
 334             int fromIndex = m;
 335             int toIndex = length - m;
 336 
 337             prepareSubArray((int[]) gold[0], fromIndex, toIndex);
 338             convertData(length);
 339 
 340             for (int i = 0; i < test.length; i++) {
 341                 printTestName("Test subarray", random, length,
 342                     ", m = " + m + ", " + getType(i));
 343                 sortingHelper.sort(test[i], fromIndex, toIndex);
 344                 checkSubArray(test[i], fromIndex, toIndex);
 345             }
 346         }
 347         out.println();
 348     }
 349 
 350     private void testRange(int length, TestRandom random) {
 351         if (length < 2) {
 352             return;
 353         }
 354         for (int m = 1; m < length; m <<= 1) {
 355             for (int i = 1; i <= length; i++) {
 356                 ((int[]) gold[0]) [i - 1] = i % m + m % i;
 357             }
 358             convertData(length);
 359 
 360             for (int i = 0; i < test.length; i++) {
 361                 printTestName("Test range check", random, length,
 362                     ", m = " + m + ", " + getType(i));
 363                 checkRange(test[i], m);
 364             }
 365         }
 366         out.println();
 367     }
 368 
 369     private void checkSorted(Pair[] a) {
 370         for (int i = 0; i < a.length - 1; i++) {
 371             if (a[i].getKey() > a[i + 1].getKey()) {
 372                 fail("Array is not sorted at " + i + "-th position: " +
 373                     a[i].getKey() + " and " + a[i + 1].getKey());
 374             }
 375         }
 376     }
 377 
 378     private void checkSorted(Point[] a) {
 379         for (int i = 0; i < a.length - 1; i++) {
 380             if (a[i].compareTo(a[i + 1]) > 0) {
 381                 fail("Point array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
 382             }
 383         }
 384     }
 385 
 386     private void checkSorted(Point[] a, Comparator<Point> c) {
 387         for (int i = 0; i < a.length - 1; i++) {
 388             if (c.compare(a[i], a[i + 1]) > 0) {
 389                 fail("Point array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
 390             }
 391         }
 392     }
 393 
 394     private void checkStable(Pair[] a) {
 395         for (int i = 0; i < a.length / 4; ) {
 396             int key1 = a[i].getKey();
 397             int value1 = a[i++].getValue();
 398             int key2 = a[i].getKey();
 399             int value2 = a[i++].getValue();
 400             int key3 = a[i].getKey();
 401             int value3 = a[i++].getValue();
 402             int key4 = a[i].getKey();
 403             int value4 = a[i++].getValue();
 404 
 405             if (!(key1 == key2 && key2 == key3 && key3 == key4)) {
 406                 fail("Keys are different " + key1 + ", " + key2 + ", " +
 407                     key3 + ", " + key4 + " at position " + i);
 408             }
 409             if (!(value1 < value2 && value2 < value3 && value3 < value4)) {
 410                 fail("Sorting is not stable at position " + i +
 411                     ". Second values have been changed: " + value1 + ", " +
 412                     value2 + ", " + value3 + ", " + value4);
 413             }
 414         }
 415     }
 416 
 417     private Pair[] build(int length, Random random) {
 418         Pair[] a = new Pair[length * 4];
 419 
 420         for (int i = 0; i < a.length; ) {
 421             int key = random.nextInt();
 422             a[i++] = new Pair(key, 1);
 423             a[i++] = new Pair(key, 2);
 424             a[i++] = new Pair(key, 3);
 425             a[i++] = new Pair(key, 4);
 426         }
 427         return a;
 428     }
 429 
 430     private void testWithInsertionSort(int length, TestRandom random) {
 431         if (length > 1000) {
 432             return;
 433         }
 434         for (int m = 1; m <= length; m <<= 1) {
 435             for (UnsortedBuilder builder : UnsortedBuilder.values()) {
 436                 builder.build((int[]) gold[0], m, random);
 437                 convertData(length);
 438 
 439                 for (int i = 0; i < test.length; i++) {
 440                     printTestName("Test with insertion sort", random, length,
 441                         ", m = " + m + ", " + getType(i) + " " + builder);
 442                     sortingHelper.sort(test[i]);
 443                     sortByInsertionSort(gold[i]);
 444                     compare(test[i], gold[i]);
 445                 }
 446             }
 447         }
 448         out.println();
 449     }
 450 
 451     private void testMergingSort(int length, TestRandom random) {
 452         if (length < (4 << 10)) { // DualPivotQuicksort.MIN_TRY_MERGE_SIZE
 453             return;
 454         }
 455         final int PERIOD = 50;
 456 
 457         for (int m = PERIOD - 2; m <= PERIOD + 2; m++) {
 458             for (MergingBuilder builder : MergingBuilder.values()) {
 459                 builder.build((int[]) gold[0], m);
 460                 convertData(length);
 461 
 462                 for (int i = 0; i < test.length; i++) {
 463                     printTestName("Test merging sort", random, length,
 464                         ", m = " + m + ", " +  getType(i) + " " + builder);
 465                     sortingHelper.sort(test[i]);
 466                     checkSorted(test[i]);
 467                 }
 468             }
 469         }
 470         out.println();
 471     }
 472 
 473     private void testWithCheckSum(int length, TestRandom random) {
 474         for (int m = 1; m <= length; m <<= 1) {
 475             for (UnsortedBuilder builder : UnsortedBuilder.values()) {
 476                 builder.build((int[]) gold[0], m, random);
 477                 convertData(length);
 478 
 479                 for (int i = 0; i < test.length; i++) {
 480                     printTestName("Test with check sum", random, length,
 481                         ", m = " + m + ", " + getType(i) + " " + builder);
 482                     sortingHelper.sort(test[i]);
 483                     checkWithCheckSum(test[i], gold[i]);
 484                 }
 485             }
 486         }
 487         out.println();
 488     }
 489 
 490     private void testWithScrambling(int length, TestRandom random) {
 491         for (int m = 1; m <= length; m <<= 1) {
 492             for (SortedBuilder builder : SortedBuilder.values()) {
 493                 builder.build((int[]) gold[0], m);
 494                 convertData(length);
 495 
 496                 for (int i = 0; i < test.length; i++) {
 497                     printTestName("Test with scrambling", random, length,
 498                         ", m = " + m + ", " + getType(i) + " " + builder);
 499                     scramble(test[i], random);
 500                     sortingHelper.sort(test[i]);
 501                     compare(test[i], gold[i]);
 502                 }
 503             }
 504         }
 505         out.println();
 506     }
 507 
 508     private void testNegativeZero(int length, TestRandom random) {
 509         for (int i = 5; i < test.length; i++) {
 510             printTestName("Test negative zero -0.0", random, length, " " + getType(i));
 511 
 512             NegativeZeroBuilder builder = NegativeZeroBuilder.values() [i - 5];
 513             builder.build(test[i], random);
 514 
 515             sortingHelper.sort(test[i]);
 516             checkNegativeZero(test[i]);
 517         }
 518         out.println();
 519     }
 520 
 521     private void testFloatingPointSorting(int length, TestRandom random) {
 522         if (length < 2) {
 523             return;
 524         }
 525         final int MAX = 13;
 526 
 527         for (int a = 0; a < MAX; a++) {
 528             for (int g = 0; g < MAX; g++) {
 529                 for (int z = 0; z < MAX; z++) {
 530                     for (int n = 0; n < MAX; n++) {
 531                         for (int p = 0; p < MAX; p++) {
 532                             if (a + g + z + n + p != length) {
 533                                 continue;
 534                             }
 535                             for (int i = 5; i < test.length; i++) {
 536                                 printTestName("Test float-pointing sorting", random, length,
 537                                     ", a = " + a + ", g = " + g + ", z = " + z +
 538                                     ", n = " + n + ", p = " + p + ", " + getType(i));
 539                                 FloatingPointBuilder builder = FloatingPointBuilder.values()[i - 5];
 540                                 builder.build(gold[i], a, g, z, n, p, random);
 541                                 copy(test[i], gold[i]);
 542                                 scramble(test[i], random);
 543                                 sortingHelper.sort(test[i]);
 544                                 compare(test[i], gold[i], a, n, g);
 545                             }
 546                         }
 547                     }
 548                 }
 549             }
 550         }
 551 
 552         for (int m = 13; m > 4; m--) {
 553             int t = length / m;
 554             int g = t, z = t, n = t, p = t;
 555             int a = length - g - z - n - p;
 556 
 557             for (int i = 5; i < test.length; i++) {
 558                 printTestName("Test float-pointing sorting", random, length,
 559                     ", a = " + a + ", g = " + g + ", z = " + z +
 560                     ", n = " + n + ", p = " + p + ", " + getType(i));
 561                 FloatingPointBuilder builder = FloatingPointBuilder.values() [i - 5];
 562                 builder.build(gold[i], a, g, z, n, p, random);
 563                 copy(test[i], gold[i]);
 564                 scramble(test[i], random);
 565                 sortingHelper.sort(test[i]);
 566                 compare(test[i], gold[i], a, n, g);
 567             }
 568         }
 569         out.println();
 570     }
 571 
 572     private void prepareSubArray(int[] a, int fromIndex, int toIndex) {
 573         for (int i = 0; i < fromIndex; i++) {
 574             a[i] = A380;
 575         }
 576         int middle = (fromIndex + toIndex) >>> 1;
 577         int k = 0;
 578 
 579         for (int i = fromIndex; i < middle; i++) {
 580             a[i] = k++;
 581         }
 582 
 583         for (int i = middle; i < toIndex; i++) {
 584             a[i] = k--;
 585         }
 586 
 587         for (int i = toIndex; i < a.length; i++) {
 588             a[i] = B747;
 589         }
 590     }
 591 
 592     private void scramble(Object a, Random random) {
 593         if (a instanceof int[]) {
 594             scramble((int[]) a, random);
 595         } else if (a instanceof long[]) {
 596             scramble((long[]) a, random);
 597         } else if (a instanceof byte[]) {
 598             scramble((byte[]) a, random);
 599         } else if (a instanceof char[]) {
 600             scramble((char[]) a, random);
 601         } else if (a instanceof short[]) {
 602             scramble((short[]) a, random);
 603         } else if (a instanceof float[]) {
 604             scramble((float[]) a, random);
 605         } else if (a instanceof double[]) {
 606             scramble((double[]) a, random);
 607         } else {
 608             fail("Unknown type of array: " + a.getClass().getName());
 609         }
 610     }
 611 
 612     private void scramble(int[] a, Random random) {
 613         for (int i = 0; i < a.length * 7; i++) {
 614             swap(a, random.nextInt(a.length), random.nextInt(a.length));
 615         }
 616     }
 617 
 618     private void scramble(long[] a, Random random) {
 619         for (int i = 0; i < a.length * 7; i++) {
 620             swap(a, random.nextInt(a.length), random.nextInt(a.length));
 621         }
 622     }
 623 
 624     private void scramble(byte[] a, Random random) {
 625         for (int i = 0; i < a.length * 7; i++) {
 626             swap(a, random.nextInt(a.length), random.nextInt(a.length));
 627         }
 628     }
 629 
 630     private void scramble(char[] a, Random random) {
 631         for (int i = 0; i < a.length * 7; i++) {
 632             swap(a, random.nextInt(a.length), random.nextInt(a.length));
 633         }
 634     }
 635 
 636     private void scramble(short[] a, Random random) {
 637         for (int i = 0; i < a.length * 7; i++) {
 638             swap(a, random.nextInt(a.length), random.nextInt(a.length));
 639         }
 640     }
 641 
 642     private void scramble(float[] a, Random random) {
 643         for (int i = 0; i < a.length * 7; i++) {
 644             swap(a, random.nextInt(a.length), random.nextInt(a.length));
 645         }
 646     }
 647 
 648     private void scramble(double[] a, Random random) {
 649         for (int i = 0; i < a.length * 7; i++) {
 650             swap(a, random.nextInt(a.length), random.nextInt(a.length));
 651         }
 652     }
 653 
 654     private void swap(int[] a, int i, int j) {
 655         int t = a[i]; a[i] = a[j]; a[j] = t;
 656     }
 657 
 658     private void swap(long[] a, int i, int j) {
 659         long t = a[i]; a[i] = a[j]; a[j] = t;
 660     }
 661 
 662     private void swap(byte[] a, int i, int j) {
 663         byte t = a[i]; a[i] = a[j]; a[j] = t;
 664     }
 665 
 666     private void swap(char[] a, int i, int j) {
 667         char t = a[i]; a[i] = a[j]; a[j] = t;
 668     }
 669 
 670     private void swap(short[] a, int i, int j) {
 671         short t = a[i]; a[i] = a[j]; a[j] = t;
 672     }
 673 
 674     private void swap(float[] a, int i, int j) {
 675         float t = a[i]; a[i] = a[j]; a[j] = t;
 676     }
 677 
 678     private void swap(double[] a, int i, int j) {
 679         double t = a[i]; a[i] = a[j]; a[j] = t;
 680     }
 681 
 682     private void checkWithCheckSum(Object test, Object gold) {
 683         checkSorted(test);
 684         checkCheckSum(test, gold);
 685     }
 686 
 687     private void fail(String message) {
 688         err.format("\n*** TEST FAILED ***\n\n%s\n\n", message);
 689         throw new RuntimeException("Test failed");
 690     }
 691 
 692     private void checkNegativeZero(Object a) {
 693         if (a instanceof float[]) {
 694             checkNegativeZero((float[]) a);
 695         } else if (a instanceof double[]) {
 696             checkNegativeZero((double[]) a);
 697         } else {
 698             fail("Unknown type of array: " + a.getClass().getName());
 699         }
 700     }
 701 
 702     private void checkNegativeZero(float[] a) {
 703         for (int i = 0; i < a.length - 1; i++) {
 704             if (Float.floatToRawIntBits(a[i]) == 0 && Float.floatToRawIntBits(a[i + 1]) < 0) {
 705                 fail(a[i] + " before " + a[i + 1] + " at position " + i);
 706             }
 707         }
 708     }
 709 
 710     private void checkNegativeZero(double[] a) {
 711         for (int i = 0; i < a.length - 1; i++) {
 712             if (Double.doubleToRawLongBits(a[i]) == 0 && Double.doubleToRawLongBits(a[i + 1]) < 0) {
 713                 fail(a[i] + " before " + a[i + 1] + " at position " + i);
 714             }
 715         }
 716     }
 717 
 718     private void compare(Object a, Object b, int numNaN, int numNeg, int numNegZero) {
 719         if (a instanceof float[]) {
 720             compare((float[]) a, (float[]) b, numNaN, numNeg, numNegZero);
 721         } else if (a instanceof double[]) {
 722             compare((double[]) a, (double[]) b, numNaN, numNeg, numNegZero);
 723         } else {
 724             fail("Unknown type of array: " + a.getClass().getName());
 725         }
 726     }
 727 
 728     private void compare(float[] a, float[] b, int numNaN, int numNeg, int numNegZero) {
 729         for (int i = a.length - numNaN; i < a.length; i++) {
 730             if (a[i] == a[i]) {
 731                 fail("There must be NaN instead of " + a[i] + " at position " + i);
 732             }
 733         }
 734         final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f);
 735 
 736         for (int i = numNeg; i < numNeg + numNegZero; i++) {
 737             if (NEGATIVE_ZERO != Float.floatToIntBits(a[i])) {
 738                 fail("There must be -0.0 instead of " + a[i] + " at position " + i);
 739             }
 740         }
 741 
 742         for (int i = 0; i < a.length - numNaN; i++) {
 743             if (a[i] != b[i]) {
 744                 fail("There must be " + b[i] + " instead of " + a[i] + " at position " + i);
 745             }
 746         }
 747     }
 748 
 749     private void compare(double[] a, double[] b, int numNaN, int numNeg, int numNegZero) {
 750         for (int i = a.length - numNaN; i < a.length; i++) {
 751             if (a[i] == a[i]) {
 752                 fail("There must be NaN instead of " + a[i] + " at position " + i);
 753             }
 754         }
 755         final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d);
 756 
 757         for (int i = numNeg; i < numNeg + numNegZero; i++) {
 758             if (NEGATIVE_ZERO != Double.doubleToLongBits(a[i])) {
 759                 fail("There must be -0.0 instead of " + a[i] + " at position " + i);
 760             }
 761         }
 762 
 763         for (int i = 0; i < a.length - numNaN; i++) {
 764             if (a[i] != b[i]) {
 765                 fail("There must be " + b[i] + " instead of " + a[i] + " at position " + i);
 766             }
 767         }
 768     }
 769 
 770     private void compare(Object a, Object b) {
 771         if (a instanceof int[]) {
 772             compare((int[]) a, (int[]) b);
 773         } else if (a instanceof long[]) {
 774             compare((long[]) a, (long[]) b);
 775         } else if (a instanceof byte[]) {
 776             compare((byte[]) a, (byte[]) b);
 777         } else if (a instanceof char[]) {
 778             compare((char[]) a, (char[]) b);
 779         } else if (a instanceof short[]) {
 780             compare((short[]) a, (short[]) b);
 781         } else if (a instanceof float[]) {
 782             compare((float[]) a, (float[]) b);
 783         } else if (a instanceof double[]) {
 784             compare((double[]) a, (double[]) b);
 785         } else {
 786             fail("Unknown type of array: " + a.getClass().getName());
 787         }
 788     }
 789 
 790     private void compare(int[] a, int[] b) {
 791         for (int i = 0; i < a.length; i++) {
 792             if (a[i] != b[i]) {
 793                 fail("There must be " + b[i] + " instead of " + a[i] + " at position " + i);
 794             }
 795         }
 796     }
 797 
 798     private void compare(long[] a, long[] b) {
 799         for (int i = 0; i < a.length; i++) {
 800             if (a[i] != b[i]) {
 801                 fail("There must be " + b[i] + " instead of " + a[i] + " at position " + i);
 802             }
 803         }
 804     }
 805 
 806     private void compare(byte[] a, byte[] b) {
 807         for (int i = 0; i < a.length; i++) {
 808             if (a[i] != b[i]) {
 809                 fail("There must be " + b[i] + " instead of " + a[i] + " at position " + i);
 810             }
 811         }
 812     }
 813 
 814     private void compare(char[] a, char[] b) {
 815         for (int i = 0; i < a.length; i++) {
 816             if (a[i] != b[i]) {
 817                 fail("There must be " + b[i] + " instead of " + a[i] + " at position " + i);
 818             }
 819         }
 820     }
 821 
 822     private void compare(short[] a, short[] b) {
 823         for (int i = 0; i < a.length; i++) {
 824             if (a[i] != b[i]) {
 825                 fail("There must be " + b[i] + " instead of " + a[i] + " at position " + i);
 826             }
 827         }
 828     }
 829 
 830     private void compare(float[] a, float[] b) {
 831         for (int i = 0; i < a.length; i++) {
 832             if (a[i] != b[i]) {
 833                 fail("There must be " + b[i] + " instead of " + a[i] + " at position " + i);
 834             }
 835         }
 836     }
 837 
 838     private void compare(double[] a, double[] b) {
 839         for (int i = 0; i < a.length; i++) {
 840             if (a[i] != b[i]) {
 841                 fail("There must be " + b[i] + " instead of " + a[i] + " at position " + i);
 842             }
 843         }
 844     }
 845 
 846     private String getType(int i) {
 847         Object a = test[i];
 848 
 849         if (a instanceof int[]) {
 850             return "INT   ";
 851         }
 852         if (a instanceof long[]) {
 853             return "LONG  ";
 854         }
 855         if (a instanceof byte[]) {
 856             return "BYTE  ";
 857         }
 858         if (a instanceof char[]) {
 859             return "CHAR  ";
 860         }
 861         if (a instanceof short[]) {
 862             return "SHORT ";
 863         }
 864         if (a instanceof float[]) {
 865             return "FLOAT ";
 866         }
 867         if (a instanceof double[]) {
 868             return "DOUBLE";
 869         }
 870         fail("Unknown type of array: " + a.getClass().getName());
 871         return null;
 872     }
 873 
 874     private void checkSorted(Object a) {
 875         if (a instanceof int[]) {
 876             checkSorted((int[]) a);
 877         } else if (a instanceof long[]) {
 878             checkSorted((long[]) a);
 879         } else if (a instanceof byte[]) {
 880             checkSorted((byte[]) a);
 881         } else if (a instanceof char[]) {
 882             checkSorted((char[]) a);
 883         } else if (a instanceof short[]) {
 884             checkSorted((short[]) a);
 885         } else if (a instanceof float[]) {
 886             checkSorted((float[]) a);
 887         } else if (a instanceof double[]) {
 888             checkSorted((double[]) a);
 889         } else {
 890             fail("Unknown type of array: " + a.getClass().getName());
 891         }
 892     }
 893 
 894     private void checkSorted(int[] a) {
 895         for (int i = 0; i < a.length - 1; i++) {
 896             if (a[i] > a[i + 1]) {
 897                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
 898             }
 899         }
 900     }
 901 
 902     private void checkSorted(long[] a) {
 903         for (int i = 0; i < a.length - 1; i++) {
 904             if (a[i] > a[i + 1]) {
 905                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
 906             }
 907         }
 908     }
 909 
 910     private void checkSorted(byte[] a) {
 911         for (int i = 0; i < a.length - 1; i++) {
 912             if (a[i] > a[i + 1]) {
 913                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
 914             }
 915         }
 916     }
 917 
 918     private void checkSorted(char[] a) {
 919         for (int i = 0; i < a.length - 1; i++) {
 920             if (a[i] > a[i + 1]) {
 921                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
 922             }
 923         }
 924     }
 925 
 926     private void checkSorted(short[] a) {
 927         for (int i = 0; i < a.length - 1; i++) {
 928             if (a[i] > a[i + 1]) {
 929                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
 930             }
 931         }
 932     }
 933 
 934     private void checkSorted(float[] a) {
 935         for (int i = 0; i < a.length - 1; i++) {
 936             if (a[i] > a[i + 1]) {
 937                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
 938             }
 939         }
 940     }
 941 
 942     private void checkSorted(double[] a) {
 943         for (int i = 0; i < a.length - 1; i++) {
 944             if (a[i] > a[i + 1]) {
 945                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
 946             }
 947         }
 948     }
 949 
 950     private void checkCheckSum(Object test, Object gold) {
 951         if (checkSumXor(test) != checkSumXor(gold)) {
 952             fail("Original and sorted arrays are not identical [^]");
 953         }
 954         if (checkSumPlus(test) != checkSumPlus(gold)) {
 955             fail("Original and sorted arrays are not identical [+]");
 956         }
 957     }
 958 
 959     private int checkSumXor(Object a) {
 960         if (a instanceof int[]) {
 961             return checkSumXor((int[]) a);
 962         }
 963         if (a instanceof long[]) {
 964             return checkSumXor((long[]) a);
 965         }
 966         if (a instanceof byte[]) {
 967             return checkSumXor((byte[]) a);
 968         }
 969         if (a instanceof char[]) {
 970             return checkSumXor((char[]) a);
 971         }
 972         if (a instanceof short[]) {
 973             return checkSumXor((short[]) a);
 974         }
 975         if (a instanceof float[]) {
 976             return checkSumXor((float[]) a);
 977         }
 978         if (a instanceof double[]) {
 979             return checkSumXor((double[]) a);
 980         }
 981         fail("Unknown type of array: " + a.getClass().getName());
 982         return -1;
 983     }
 984 
 985     private int checkSumXor(int[] a) {
 986         int checkSum = 0;
 987 
 988         for (int e : a) {
 989             checkSum ^= e;
 990         }
 991         return checkSum;
 992     }
 993 
 994     private int checkSumXor(long[] a) {
 995         long checkSum = 0;
 996 
 997         for (long e : a) {
 998             checkSum ^= e;
 999         }
1000         return (int) checkSum;
1001     }
1002 
1003     private int checkSumXor(byte[] a) {
1004         byte checkSum = 0;
1005 
1006         for (byte e : a) {
1007             checkSum ^= e;
1008         }
1009         return (int) checkSum;
1010     }
1011 
1012     private int checkSumXor(char[] a) {
1013         char checkSum = 0;
1014 
1015         for (char e : a) {
1016             checkSum ^= e;
1017         }
1018         return (int) checkSum;
1019     }
1020 
1021     private int checkSumXor(short[] a) {
1022         short checkSum = 0;
1023 
1024         for (short e : a) {
1025             checkSum ^= e;
1026         }
1027         return (int) checkSum;
1028     }
1029 
1030     private int checkSumXor(float[] a) {
1031         int checkSum = 0;
1032 
1033         for (float e : a) {
1034             checkSum ^= (int) e;
1035         }
1036         return checkSum;
1037     }
1038 
1039     private int checkSumXor(double[] a) {
1040         int checkSum = 0;
1041 
1042         for (double e : a) {
1043             checkSum ^= (int) e;
1044         }
1045         return checkSum;
1046     }
1047 
1048     private int checkSumPlus(Object a) {
1049         if (a instanceof int[]) {
1050             return checkSumPlus((int[]) a);
1051         }
1052         if (a instanceof long[]) {
1053             return checkSumPlus((long[]) a);
1054         }
1055         if (a instanceof byte[]) {
1056             return checkSumPlus((byte[]) a);
1057         }
1058         if (a instanceof char[]) {
1059             return checkSumPlus((char[]) a);
1060         }
1061         if (a instanceof short[]) {
1062             return checkSumPlus((short[]) a);
1063         }
1064         if (a instanceof float[]) {
1065             return checkSumPlus((float[]) a);
1066         }
1067         if (a instanceof double[]) {
1068             return checkSumPlus((double[]) a);
1069         }
1070         fail("Unknown type of array: " + a.getClass().getName());
1071         return -1;
1072     }
1073 
1074     private int checkSumPlus(int[] a) {
1075         int checkSum = 0;
1076 
1077         for (int e : a) {
1078             checkSum += e;
1079         }
1080         return checkSum;
1081     }
1082 
1083     private int checkSumPlus(long[] a) {
1084         long checkSum = 0;
1085 
1086         for (long e : a) {
1087             checkSum += e;
1088         }
1089         return (int) checkSum;
1090     }
1091 
1092     private int checkSumPlus(byte[] a) {
1093         byte checkSum = 0;
1094 
1095         for (byte e : a) {
1096             checkSum += e;
1097         }
1098         return (int) checkSum;
1099     }
1100 
1101     private int checkSumPlus(char[] a) {
1102         char checkSum = 0;
1103 
1104         for (char e : a) {
1105             checkSum += e;
1106         }
1107         return (int) checkSum;
1108     }
1109 
1110     private int checkSumPlus(short[] a) {
1111         short checkSum = 0;
1112 
1113         for (short e : a) {
1114             checkSum += e;
1115         }
1116         return (int) checkSum;
1117     }
1118 
1119     private int checkSumPlus(float[] a) {
1120         int checkSum = 0;
1121 
1122         for (float e : a) {
1123             checkSum += (int) e;
1124         }
1125         return checkSum;
1126     }
1127 
1128     private int checkSumPlus(double[] a) {
1129         int checkSum = 0;
1130 
1131         for (double e : a) {
1132             checkSum += (int) e;
1133         }
1134         return checkSum;
1135     }
1136 
1137     private void sortByInsertionSort(Object a) {
1138         if (a instanceof int[]) {
1139             sortByInsertionSort((int[]) a);
1140         } else if (a instanceof long[]) {
1141             sortByInsertionSort((long[]) a);
1142         } else if (a instanceof byte[]) {
1143             sortByInsertionSort((byte[]) a);
1144         } else if (a instanceof char[]) {
1145             sortByInsertionSort((char[]) a);
1146         } else if (a instanceof short[]) {
1147             sortByInsertionSort((short[]) a);
1148         } else if (a instanceof float[]) {
1149             sortByInsertionSort((float[]) a);
1150         } else if (a instanceof double[]) {
1151             sortByInsertionSort((double[]) a);
1152         } else {
1153             fail("Unknown type of array: " + a.getClass().getName());
1154         }
1155     }
1156 
1157     private void sortByInsertionSort(int[] a) {
1158         for (int j, i = 1; i < a.length; i++) {
1159             int ai = a[i];
1160 
1161             for (j = i - 1; j >= 0 && ai < a[j]; j--) {
1162                 a[j + 1] = a[j];
1163             }
1164             a[j + 1] = ai;
1165         }
1166     }
1167 
1168     private void sortByInsertionSort(long[] a) {
1169         for (int j, i = 1; i < a.length; i++) {
1170             long ai = a[i];
1171 
1172             for (j = i - 1; j >= 0 && ai < a[j]; j--) {
1173                 a[j + 1] = a[j];
1174             }
1175             a[j + 1] = ai;
1176         }
1177     }
1178 
1179     private void sortByInsertionSort(byte[] a) {
1180         for (int j, i = 1; i < a.length; i++) {
1181             byte ai = a[i];
1182 
1183             for (j = i - 1; j >= 0 && ai < a[j]; j--) {
1184                 a[j + 1] = a[j];
1185             }
1186             a[j + 1] = ai;
1187         }
1188     }
1189 
1190     private void sortByInsertionSort(char[] a) {
1191         for (int j, i = 1; i < a.length; i++) {
1192             char ai = a[i];
1193 
1194             for (j = i - 1; j >= 0 && ai < a[j]; j--) {
1195                 a[j + 1] = a[j];
1196             }
1197             a[j + 1] = ai;
1198         }
1199     }
1200 
1201     private void sortByInsertionSort(short[] a) {
1202         for (int j, i = 1; i < a.length; i++) {
1203             short ai = a[i];
1204 
1205             for (j = i - 1; j >= 0 && ai < a[j]; j--) {
1206                 a[j + 1] = a[j];
1207             }
1208             a[j + 1] = ai;
1209         }
1210     }
1211 
1212     private void sortByInsertionSort(float[] a) {
1213         for (int j, i = 1; i < a.length; i++) {
1214             float ai = a[i];
1215 
1216             for (j = i - 1; j >= 0 && ai < a[j]; j--) {
1217                 a[j + 1] = a[j];
1218             }
1219             a[j + 1] = ai;
1220         }
1221     }
1222 
1223     private void sortByInsertionSort(double[] a) {
1224         for (int j, i = 1; i < a.length; i++) {
1225             double ai = a[i];
1226 
1227             for (j = i - 1; j >= 0 && ai < a[j]; j--) {
1228                 a[j + 1] = a[j];
1229             }
1230             a[j + 1] = ai;
1231         }
1232     }
1233 
1234     private void checkSubArray(Object a, int fromIndex, int toIndex) {
1235         if (a instanceof int[]) {
1236             checkSubArray((int[]) a, fromIndex, toIndex);
1237         } else if (a instanceof long[]) {
1238             checkSubArray((long[]) a, fromIndex, toIndex);
1239         } else if (a instanceof byte[]) {
1240             checkSubArray((byte[]) a, fromIndex, toIndex);
1241         } else if (a instanceof char[]) {
1242             checkSubArray((char[]) a, fromIndex, toIndex);
1243         } else if (a instanceof short[]) {
1244             checkSubArray((short[]) a, fromIndex, toIndex);
1245         } else if (a instanceof float[]) {
1246             checkSubArray((float[]) a, fromIndex, toIndex);
1247         } else if (a instanceof double[]) {
1248             checkSubArray((double[]) a, fromIndex, toIndex);
1249         } else {
1250             fail("Unknown type of array: " + a.getClass().getName());
1251         }
1252     }
1253 
1254     private void checkSubArray(int[] a, int fromIndex, int toIndex) {
1255         for (int i = 0; i < fromIndex; i++) {
1256             if (a[i] != A380) {
1257                 fail("Range sort changes left element at position " + i + hex(a[i], A380));
1258             }
1259         }
1260 
1261         for (int i = fromIndex; i < toIndex - 1; i++) {
1262             if (a[i] > a[i + 1]) {
1263                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
1264             }
1265         }
1266 
1267         for (int i = toIndex; i < a.length; i++) {
1268             if (a[i] != B747) {
1269                 fail("Range sort changes right element at position " + i + hex(a[i], B747));
1270             }
1271         }
1272     }
1273 
1274     private void checkSubArray(long[] a, int fromIndex, int toIndex) {
1275         for (int i = 0; i < fromIndex; i++) {
1276             if (a[i] != (long) A380) {
1277                 fail("Range sort changes left element at position " + i + hex(a[i], A380));
1278             }
1279         }
1280 
1281         for (int i = fromIndex; i < toIndex - 1; i++) {
1282             if (a[i] > a[i + 1]) {
1283                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
1284             }
1285         }
1286 
1287         for (int i = toIndex; i < a.length; i++) {
1288             if (a[i] != (long) B747) {
1289                 fail("Range sort changes right element at position " + i + hex(a[i], B747));
1290             }
1291         }
1292     }
1293 
1294     private void checkSubArray(byte[] a, int fromIndex, int toIndex) {
1295         for (int i = 0; i < fromIndex; i++) {
1296             if (a[i] != (byte) A380) {
1297                 fail("Range sort changes left element at position " + i + hex(a[i], A380));
1298             }
1299         }
1300 
1301         for (int i = fromIndex; i < toIndex - 1; i++) {
1302             if (a[i] > a[i + 1]) {
1303                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
1304             }
1305         }
1306 
1307         for (int i = toIndex; i < a.length; i++) {
1308             if (a[i] != (byte) B747) {
1309                 fail("Range sort changes right element at position " + i + hex(a[i], B747));
1310             }
1311         }
1312     }
1313 
1314     private void checkSubArray(char[] a, int fromIndex, int toIndex) {
1315         for (int i = 0; i < fromIndex; i++) {
1316             if (a[i] != (char) A380) {
1317                 fail("Range sort changes left element at position " + i + hex(a[i], A380));
1318             }
1319         }
1320 
1321         for (int i = fromIndex; i < toIndex - 1; i++) {
1322             if (a[i] > a[i + 1]) {
1323                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
1324             }
1325         }
1326 
1327         for (int i = toIndex; i < a.length; i++) {
1328             if (a[i] != (char) B747) {
1329                 fail("Range sort changes right element at position " + i + hex(a[i], B747));
1330             }
1331         }
1332     }
1333 
1334     private void checkSubArray(short[] a, int fromIndex, int toIndex) {
1335         for (int i = 0; i < fromIndex; i++) {
1336             if (a[i] != (short) A380) {
1337                 fail("Range sort changes left element at position " + i + hex(a[i], A380));
1338             }
1339         }
1340 
1341         for (int i = fromIndex; i < toIndex - 1; i++) {
1342             if (a[i] > a[i + 1]) {
1343                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
1344             }
1345         }
1346 
1347         for (int i = toIndex; i < a.length; i++) {
1348             if (a[i] != (short) B747) {
1349                 fail("Range sort changes right element at position " + i + hex(a[i], B747));
1350             }
1351         }
1352     }
1353 
1354     private void checkSubArray(float[] a, int fromIndex, int toIndex) {
1355         for (int i = 0; i < fromIndex; i++) {
1356             if (a[i] != (float) A380) {
1357                 fail("Range sort changes left element at position " + i + hex((long) a[i], A380));
1358             }
1359         }
1360 
1361         for (int i = fromIndex; i < toIndex - 1; i++) {
1362             if (a[i] > a[i + 1]) {
1363                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
1364             }
1365         }
1366 
1367         for (int i = toIndex; i < a.length; i++) {
1368             if (a[i] != (float) B747) {
1369                 fail("Range sort changes right element at position " + i + hex((long) a[i], B747));
1370             }
1371         }
1372     }
1373 
1374     private void checkSubArray(double[] a, int fromIndex, int toIndex) {
1375         for (int i = 0; i < fromIndex; i++) {
1376             if (a[i] != (double) A380) {
1377                 fail("Range sort changes left element at position " + i + hex((long) a[i], A380));
1378             }
1379         }
1380 
1381         for (int i = fromIndex; i < toIndex - 1; i++) {
1382             if (a[i] > a[i + 1]) {
1383                 fail("Array is not sorted at " + i + "-th position: " + a[i] + " and " + a[i + 1]);
1384             }
1385         }
1386 
1387         for (int i = toIndex; i < a.length; i++) {
1388             if (a[i] != (double) B747) {
1389                 fail("Range sort changes right element at position " + i + hex((long) a[i], B747));
1390             }
1391         }
1392     }
1393 
1394     private void checkRange(Object a, int m) {
1395         if (a instanceof int[]) {
1396             checkRange((int[]) a, m);
1397         } else if (a instanceof long[]) {
1398             checkRange((long[]) a, m);
1399         } else if (a instanceof byte[]) {
1400             checkRange((byte[]) a, m);
1401         } else if (a instanceof char[]) {
1402             checkRange((char[]) a, m);
1403         } else if (a instanceof short[]) {
1404             checkRange((short[]) a, m);
1405         } else if (a instanceof float[]) {
1406             checkRange((float[]) a, m);
1407         } else if (a instanceof double[]) {
1408             checkRange((double[]) a, m);
1409         } else {
1410             fail("Unknown type of array: " + a.getClass().getName());
1411         }
1412     }
1413 
1414     private void checkRange(int[] a, int m) {
1415         try {
1416             sortingHelper.sort(a, m + 1, m);
1417             fail(sortingHelper + " does not throw IllegalArgumentException " +
1418                 "as expected: fromIndex = " + (m + 1) + " toIndex = " + m);
1419         } catch (IllegalArgumentException iae) {
1420             try {
1421                 sortingHelper.sort(a, -m, a.length);
1422                 fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1423                     "as expected: fromIndex = " + (-m));
1424             } catch (ArrayIndexOutOfBoundsException aoe) {
1425                 try {
1426                     sortingHelper.sort(a, 0, a.length + m);
1427                     fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1428                         "as expected: toIndex = " + (a.length + m));
1429                 } catch (ArrayIndexOutOfBoundsException expected) {}
1430             }
1431         }
1432     }
1433 
1434     private void checkRange(long[] a, int m) {
1435         try {
1436             sortingHelper.sort(a, m + 1, m);
1437             fail(sortingHelper + " does not throw IllegalArgumentException " +
1438                 "as expected: fromIndex = " + (m + 1) + " toIndex = " + m);
1439         } catch (IllegalArgumentException iae) {
1440             try {
1441                 sortingHelper.sort(a, -m, a.length);
1442                 fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1443                     "as expected: fromIndex = " + (-m));
1444             } catch (ArrayIndexOutOfBoundsException aoe) {
1445                 try {
1446                     sortingHelper.sort(a, 0, a.length + m);
1447                     fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1448                         "as expected: toIndex = " + (a.length + m));
1449                 } catch (ArrayIndexOutOfBoundsException expected) {}
1450             }
1451         }
1452     }
1453 
1454     private void checkRange(byte[] a, int m) {
1455         try {
1456             sortingHelper.sort(a, m + 1, m);
1457             fail(sortingHelper + " does not throw IllegalArgumentException " +
1458                 "as expected: fromIndex = " + (m + 1) + " toIndex = " + m);
1459         } catch (IllegalArgumentException iae) {
1460             try {
1461                 sortingHelper.sort(a, -m, a.length);
1462                 fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1463                     "as expected: fromIndex = " + (-m));
1464             } catch (ArrayIndexOutOfBoundsException aoe) {
1465                 try {
1466                     sortingHelper.sort(a, 0, a.length + m);
1467                     fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1468                         "as expected: toIndex = " + (a.length + m));
1469                 } catch (ArrayIndexOutOfBoundsException expected) {}
1470             }
1471         }
1472     }
1473 
1474     private void checkRange(char[] a, int m) {
1475         try {
1476             sortingHelper.sort(a, m + 1, m);
1477             fail(sortingHelper + " does not throw IllegalArgumentException " +
1478                 "as expected: fromIndex = " + (m + 1) + " toIndex = " + m);
1479         } catch (IllegalArgumentException iae) {
1480             try {
1481                 sortingHelper.sort(a, -m, a.length);
1482                 fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1483                     "as expected: fromIndex = " + (-m));
1484             } catch (ArrayIndexOutOfBoundsException aoe) {
1485                 try {
1486                     sortingHelper.sort(a, 0, a.length + m);
1487                     fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1488                         "as expected: toIndex = " + (a.length + m));
1489                 } catch (ArrayIndexOutOfBoundsException expected) {}
1490             }
1491         }
1492     }
1493 
1494     private void checkRange(short[] a, int m) {
1495         try {
1496             sortingHelper.sort(a, m + 1, m);
1497             fail(sortingHelper + " does not throw IllegalArgumentException " +
1498                 "as expected: fromIndex = " + (m + 1) + " toIndex = " + m);
1499         } catch (IllegalArgumentException iae) {
1500             try {
1501                 sortingHelper.sort(a, -m, a.length);
1502                 fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1503                     "as expected: fromIndex = " + (-m));
1504             } catch (ArrayIndexOutOfBoundsException aoe) {
1505                 try {
1506                     sortingHelper.sort(a, 0, a.length + m);
1507                     fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1508                         "as expected: toIndex = " + (a.length + m));
1509                 } catch (ArrayIndexOutOfBoundsException expected) {}
1510             }
1511         }
1512     }
1513 
1514     private void checkRange(float[] a, int m) {
1515         try {
1516             sortingHelper.sort(a, m + 1, m);
1517             fail(sortingHelper + " does not throw IllegalArgumentException " +
1518                 "as expected: fromIndex = " + (m + 1) + " toIndex = " + m);
1519         } catch (IllegalArgumentException iae) {
1520             try {
1521                 sortingHelper.sort(a, -m, a.length);
1522                 fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1523                     "as expected: fromIndex = " + (-m));
1524             } catch (ArrayIndexOutOfBoundsException aoe) {
1525                 try {
1526                     sortingHelper.sort(a, 0, a.length + m);
1527                     fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1528                         "as expected: toIndex = " + (a.length + m));
1529                 } catch (ArrayIndexOutOfBoundsException expected) {}
1530             }
1531         }
1532     }
1533 
1534     private void checkRange(double[] a, int m) {
1535         try {
1536             sortingHelper.sort(a, m + 1, m);
1537             fail(sortingHelper + " does not throw IllegalArgumentException " +
1538                 "as expected: fromIndex = " + (m + 1) + " toIndex = " + m);
1539         } catch (IllegalArgumentException iae) {
1540             try {
1541                 sortingHelper.sort(a, -m, a.length);
1542                 fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1543                     "as expected: fromIndex = " + (-m));
1544             } catch (ArrayIndexOutOfBoundsException aoe) {
1545                 try {
1546                     sortingHelper.sort(a, 0, a.length + m);
1547                     fail(sortingHelper + " does not throw ArrayIndexOutOfBoundsException " +
1548                         "as expected: toIndex = " + (a.length + m));
1549                 } catch (ArrayIndexOutOfBoundsException expected) {}
1550             }
1551         }
1552     }
1553 
1554     private void copy(Object dst, Object src) {
1555         if (src instanceof float[]) {
1556             copy((float[]) dst, (float[]) src);
1557         } else if (src instanceof double[]) {
1558             copy((double[]) dst, (double[]) src);
1559         } else {
1560             fail("Unknown type of array: " + src.getClass().getName());
1561         }
1562     }
1563 
1564     private void copy(float[] dst, float[] src) {
1565         System.arraycopy(src, 0, dst, 0, src.length);
1566     }
1567 
1568     private void copy(double[] dst, double[] src) {
1569         System.arraycopy(src, 0, dst, 0, src.length);
1570     }
1571 
1572     private void printTestName(String test, TestRandom random, int length) {
1573         printTestName(test, random, length, "");
1574     }
1575 
1576     private void createData(int length) {
1577         gold = new Object[] {
1578             new int[length], new long[length],
1579             new byte[length], new char[length], new short[length],
1580             new float[length], new double[length]
1581         };
1582 
1583         test = new Object[] {
1584             new int[length], new long[length],
1585             new byte[length], new char[length], new short[length],
1586             new float[length], new double[length]
1587         };
1588     }
1589 
1590     private void convertData(int length) {
1591         for (int i = 1; i < gold.length; i++) {
1592             TypeConverter converter = TypeConverter.values()[i - 1];
1593             converter.convert((int[])gold[0], gold[i]);
1594         }
1595 
1596         for (int i = 0; i < gold.length; i++) {
1597             System.arraycopy(gold[i], 0, test[i], 0, length);
1598         }
1599     }
1600 
1601     private String hex(long a, int b) {
1602         return ": " + Long.toHexString(a) + ", must be " + Integer.toHexString(b);
1603     }
1604 
1605     private void printTestName(String test, TestRandom random, int length, String message) {
1606         out.println( "[" + sortingHelper + "] '" + test +
1607             "' length = " + length + ", random = " + random + message);
1608     }
1609 
1610     private static enum TypeConverter {
1611         LONG {
1612             void convert(int[] src, Object dst) {
1613                 long[] b = (long[]) dst;
1614 
1615                 for (int i = 0; i < src.length; i++) {
1616                     b[i] = (long) src[i];
1617                 }
1618             }
1619         },
1620 
1621         BYTE {
1622             void convert(int[] src, Object dst) {
1623                 byte[] b = (byte[]) dst;
1624 
1625                 for (int i = 0; i < src.length; i++) {
1626                     b[i] = (byte) src[i];
1627                 }
1628             }
1629         },
1630 
1631         CHAR {
1632             void convert(int[] src, Object dst) {
1633                 char[] b = (char[]) dst;
1634 
1635                 for (int i = 0; i < src.length; i++) {
1636                     b[i] = (char) src[i];
1637                 }
1638             }
1639         },
1640 
1641         SHORT {
1642             void convert(int[] src, Object dst) {
1643                 short[] b = (short[]) dst;
1644 
1645                 for (int i = 0; i < src.length; i++) {
1646                     b[i] = (short) src[i];
1647                 }
1648             }
1649         },
1650 
1651         FLOAT {
1652             void convert(int[] src, Object dst) {
1653                 float[] b = (float[]) dst;
1654 
1655                 for (int i = 0; i < src.length; i++) {
1656                     b[i] = (float) src[i];
1657                 }
1658             }
1659         },
1660 
1661         DOUBLE {
1662             void convert(int[] src, Object dst) {
1663                 double[] b = (double[]) dst;
1664 
1665                 for (int i = 0; i < src.length; i++) {
1666                     b[i] = (double) src[i];
1667                 }
1668             }
1669         };
1670 
1671         abstract void convert(int[] src, Object dst);
1672     }
1673 
1674     private static enum SortedBuilder {
1675         STEPS {
1676             void build(int[] a, int m) {
1677                 for (int i = 0; i < m; i++) {
1678                     a[i] = 0;
1679                 }
1680 
1681                 for (int i = m; i < a.length; i++) {
1682                     a[i] = 1;
1683                 }
1684             }
1685         };
1686 
1687         abstract void build(int[] a, int m);
1688     }
1689 
1690     private static enum UnsortedBuilder {
1691         RANDOM {
1692             void build(int[] a, int m, Random random) {
1693                 for (int i = 0; i < a.length; i++) {
1694                     a[i] = random.nextInt();
1695                 }
1696             }
1697         },
1698 
1699         ASCENDING {
1700             void build(int[] a, int m, Random random) {
1701                 for (int i = 0; i < a.length; i++) {
1702                     a[i] = m + i;
1703                 }
1704             }
1705         },
1706 
1707         DESCENDING {
1708             void build(int[] a, int m, Random random) {
1709                 for (int i = 0; i < a.length; i++) {
1710                     a[i] = a.length - m - i;
1711                 }
1712             }
1713         },
1714 
1715         EQUAL {
1716             void build(int[] a, int m, Random random) {
1717                 for (int i = 0; i < a.length; i++) {
1718                     a[i] = m;
1719                 }
1720             }
1721         },
1722 
1723         SAW {
1724             void build(int[] a, int m, Random random) {
1725                 int incCount = 1;
1726                 int decCount = a.length;
1727                 int i = 0;
1728                 int period = m--;
1729 
1730                 while (true) {
1731                     for (int k = 1; k <= period; k++) {
1732                         if (i >= a.length) {
1733                             return;
1734                         }
1735                         a[i++] = incCount++;
1736                     }
1737                     period += m;
1738 
1739                     for (int k = 1; k <= period; k++) {
1740                         if (i >= a.length) {
1741                             return;
1742                         }
1743                         a[i++] = decCount--;
1744                     }
1745                     period += m;
1746                 }
1747             }
1748         },
1749 
1750         REPEATED {
1751             void build(int[] a, int m, Random random) {
1752                 for (int i = 0; i < a.length; i++) {
1753                     a[i] = i % m;
1754                 }
1755             }
1756         },
1757 
1758         DUPLICATED {
1759             void build(int[] a, int m, Random random) {
1760                 for (int i = 0; i < a.length; i++) {
1761                     a[i] = random.nextInt(m);
1762                 }
1763             }
1764         },
1765 
1766         ORGAN_PIPES {
1767             void build(int[] a, int m, Random random) {
1768                 int middle = a.length / (m + 1);
1769 
1770                 for (int i = 0; i < middle; i++) {
1771                     a[i] = i;
1772                 }
1773 
1774                 for (int i = middle; i < a.length; i++) {
1775                     a[i] = a.length - i - 1;
1776                 }
1777             }
1778         },
1779 
1780         STAGGER {
1781             void build(int[] a, int m, Random random) {
1782                 for (int i = 0; i < a.length; i++) {
1783                     a[i] = (i * m + i) % a.length;
1784                 }
1785             }
1786         },
1787 
1788         PLATEAU {
1789             void build(int[] a, int m, Random random) {
1790                 for (int i = 0; i < a.length; i++) {
1791                     a[i] = Math.min(i, m);
1792                 }
1793             }
1794         },
1795 
1796         SHUFFLE {
1797             void build(int[] a, int m, Random random) {
1798                 int x = 0, y = 0;
1799 
1800                 for (int i = 0; i < a.length; i++) {
1801                     a[i] = random.nextBoolean() ? (x += 2) : (y += 2);
1802                 }
1803             }
1804         },
1805 
1806         LATCH {
1807             void build(int[] a, int m, Random random) {
1808                 int max = a.length / m;
1809                 max = max < 2 ? 2 : max;
1810 
1811                 for (int i = 0; i < a.length; i++) {
1812                     a[i] = i % max;
1813                 }
1814             }
1815         };
1816 
1817         abstract void build(int[] a, int m, Random random);
1818     }
1819 
1820     private static enum MergingBuilder {
1821         ASCENDING {
1822             void build(int[] a, int m) {
1823                 int period = a.length / m;
1824                 int v = 1, i = 0;
1825 
1826                 for (int k = 0; k < m; k++) {
1827                     v = 1;
1828 
1829                     for (int p = 0; p < period; p++) {
1830                         a[i++] = v++;
1831                     }
1832                 }
1833 
1834                 for (int j = i; j < a.length - 1; j++) {
1835                     a[j] = v++;
1836                 }
1837 
1838                 a[a.length - 1] = 0;
1839             }
1840         },
1841 
1842         DESCENDING {
1843             void build(int[] a, int m) {
1844                 int period = a.length / m;
1845                 int v = -1, i = 0;
1846 
1847                 for (int k = 0; k < m; k++) {
1848                     v = -1;
1849 
1850                     for (int p = 0; p < period; p++) {
1851                         a[i++] = v--;
1852                     }
1853                 }
1854 
1855                 for (int j = i; j < a.length - 1; j++) {
1856                     a[j] = v--;
1857                 }
1858 
1859                 a[a.length - 1] = 0;
1860             }
1861         },
1862 
1863         POINT {
1864             void build(int[] a, int m) {
1865                 for (int i = 0; i < a.length; i++) {
1866                     a[i] = 0;
1867                 }
1868                 a[a.length / 2] = m;
1869             }
1870         },
1871 
1872         LINE {
1873             void build(int[] a, int m) {
1874                 for (int i = 0; i < a.length; i++) {
1875                     a[i] = i;
1876                 }
1877                 reverse(a, 0, a.length - 1);
1878             }
1879         },
1880 
1881         PEARL {
1882             void build(int[] a, int m) {
1883                 for (int i = 0; i < a.length; i++) {
1884                     a[i] = i;
1885                 }
1886                 reverse(a, 0, 2);
1887             }
1888         },
1889 
1890         RING {
1891             void build(int[] a, int m) {
1892                 int k1 = a.length / 3;
1893                 int k2 = a.length / 3 * 2;
1894                 int level = a.length / 3;
1895 
1896                 for (int i = 0, k = level; i < k1; i++) {
1897                     a[i] = k--;
1898                 }
1899 
1900                 for (int i = k1; i < k2; i++) {
1901                     a[i] = 0;
1902                 }
1903 
1904                 for (int i = k2, k = level; i < a.length; i++) {
1905                     a[i] = k--;
1906                 }
1907             }
1908         };
1909 
1910         abstract void build(int[] a, int m);
1911 
1912         private static void reverse(int[] a, int lo, int hi) {
1913             for (--hi; lo < hi; ) {
1914                 int tmp = a[lo];
1915                 a[lo++] = a[hi];
1916                 a[hi--] = tmp;
1917             }
1918         }
1919     }
1920 
1921     private static enum NegativeZeroBuilder {
1922         FLOAT {
1923             void build(Object o, Random random) {
1924                 float[] a = (float[]) o;
1925 
1926                 for (int i = 0; i < a.length; i++) {
1927                     a[i] = random.nextBoolean() ? -0.0f : 0.0f;
1928                 }
1929             }
1930         },
1931 
1932         DOUBLE {
1933             void build(Object o, Random random) {
1934                 double[] a = (double[]) o;
1935 
1936                 for (int i = 0; i < a.length; i++) {
1937                     a[i] = random.nextBoolean() ? -0.0d : 0.0d;
1938                 }
1939             }
1940         };
1941 
1942         abstract void build(Object o, Random random);
1943     }
1944 
1945     private static enum FloatingPointBuilder {
1946         FLOAT {
1947             void build(Object o, int a, int g, int z, int n, int p, Random random) {
1948                 float negativeValue = -random.nextFloat();
1949                 float positiveValue =  random.nextFloat();
1950                 float[] x = (float[]) o;
1951                 int fromIndex = 0;
1952 
1953                 writeValue(x, negativeValue, fromIndex, n);
1954                 fromIndex += n;
1955 
1956                 writeValue(x, -0.0f, fromIndex, g);
1957                 fromIndex += g;
1958 
1959                 writeValue(x, 0.0f, fromIndex, z);
1960                 fromIndex += z;
1961 
1962                 writeValue(x, positiveValue, fromIndex, p);
1963                 fromIndex += p;
1964 
1965                 writeValue(x, Float.NaN, fromIndex, a);
1966             }
1967         },
1968 
1969         DOUBLE {
1970             void build(Object o, int a, int g, int z, int n, int p, Random random) {
1971                 double negativeValue = -random.nextFloat();
1972                 double positiveValue =  random.nextFloat();
1973                 double[] x = (double[]) o;
1974                 int fromIndex = 0;
1975 
1976                 writeValue(x, negativeValue, fromIndex, n);
1977                 fromIndex += n;
1978 
1979                 writeValue(x, -0.0d, fromIndex, g);
1980                 fromIndex += g;
1981 
1982                 writeValue(x, 0.0d, fromIndex, z);
1983                 fromIndex += z;
1984 
1985                 writeValue(x, positiveValue, fromIndex, p);
1986                 fromIndex += p;
1987 
1988                 writeValue(x, Double.NaN, fromIndex, a);
1989             }
1990         };
1991 
1992         abstract void build(Object o, int a, int g, int z, int n, int p, Random random);
1993 
1994         private static void writeValue(float[] a, float value, int fromIndex, int count) {
1995             for (int i = fromIndex; i < fromIndex + count; i++) {
1996                 a[i] = value;
1997             }
1998         }
1999 
2000         private static void writeValue(double[] a, double value, int fromIndex, int count) {
2001             for (int i = fromIndex; i < fromIndex + count; i++) {
2002                 a[i] = value;
2003             }
2004         }
2005     }
2006 
2007     private static Comparator<Pair> pairComparator = new Comparator<Pair>() {
2008 
2009         @Override
2010         public int compare(Pair p1, Pair p2) {
2011             return p1.compareTo(p2);
2012         }
2013     };
2014 
2015     private static class Pair implements Comparable<Pair> {
2016 
2017         private Pair(int key, int value) {
2018             this.key = key;
2019             this.value = value;
2020         }
2021 
2022         int getKey() {
2023             return key;
2024         }
2025 
2026         int getValue() {
2027             return value;
2028         }
2029 
2030         @Override
2031         public int compareTo(Pair pair) {
2032             return Integer.compare(key, pair.key);
2033         }
2034 
2035         @Override
2036         public String toString() {
2037             return "(" + key + ", " + value + ")";
2038         }
2039 
2040         private int key;
2041         private int value;
2042     }
2043 
2044     private static class TestRandom extends Random {
2045 
2046         private static final TestRandom BABA = new TestRandom(0xBABA);
2047         private static final TestRandom DEDA = new TestRandom(0xDEDA);
2048         private static final TestRandom C0FFEE = new TestRandom(0xC0FFEE);
2049 
2050         private TestRandom(long seed) {
2051             super(seed);
2052             this.seed = Long.toHexString(seed).toUpperCase();
2053         }
2054 
2055         @Override
2056         public String toString() {
2057             return seed;
2058         }
2059 
2060         private String seed;
2061     }
2062 }