--- old/src/java.base/share/classes/java/util/Arrays.java 2019-07-17 17:04:35.860314325 +0200 +++ new/src/java.base/share/classes/java/util/Arrays.java 2019-07-17 17:04:35.556314329 +0200 @@ -1,8927 +1,8716 @@ -/* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.util; - -import jdk.internal.HotSpotIntrinsicCandidate; -import jdk.internal.util.ArraysSupport; - -import java.io.Serializable; -import java.lang.reflect.Array; -import java.util.concurrent.ForkJoinPool; -import java.util.function.BinaryOperator; -import java.util.function.Consumer; -import java.util.function.DoubleBinaryOperator; -import java.util.function.IntBinaryOperator; -import java.util.function.IntFunction; -import java.util.function.IntToDoubleFunction; -import java.util.function.IntToLongFunction; -import java.util.function.IntUnaryOperator; -import java.util.function.LongBinaryOperator; -import java.util.function.UnaryOperator; -import java.util.stream.DoubleStream; -import java.util.stream.IntStream; -import java.util.stream.LongStream; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; - -/** - * This class contains various methods for manipulating arrays (such as - * sorting and searching). This class also contains a static factory - * that allows arrays to be viewed as lists. - * - *

The methods in this class all throw a {@code NullPointerException}, - * if the specified array reference is null, except where noted. - * - *

The documentation for the methods contained in this class includes - * brief descriptions of the implementations. Such descriptions should - * be regarded as implementation notes, rather than parts of the - * specification. Implementors should feel free to substitute other - * algorithms, so long as the specification itself is adhered to. (For - * example, the algorithm used by {@code sort(Object[])} does not have to be - * a MergeSort, but it does have to be stable.) - * - *

This class is a member of the - * - * Java Collections Framework. - * - * @author Josh Bloch - * @author Neal Gafter - * @author John Rose - * @since 1.2 - */ -public class Arrays { - - /** - * The minimum array length below which a parallel sorting - * algorithm will not further partition the sorting task. Using - * smaller sizes typically results in memory contention across - * tasks that makes parallel speedups unlikely. - */ - private static final int MIN_ARRAY_SORT_GRAN = 1 << 13; - - // Suppresses default constructor, ensuring non-instantiability. - private Arrays() {} - - /** - * A comparator that implements the natural ordering of a group of - * mutually comparable elements. May be used when a supplied - * comparator is null. To simplify code-sharing within underlying - * implementations, the compare method only declares type Object - * for its second argument. - * - * Arrays class implementor's note: It is an empirical matter - * whether ComparableTimSort offers any performance benefit over - * TimSort used with this comparator. If not, you are better off - * deleting or bypassing ComparableTimSort. There is currently no - * empirical case for separating them for parallel sorting, so all - * public Object parallelSort methods use the same comparator - * based implementation. - */ - static final class NaturalOrder implements Comparator { - @SuppressWarnings("unchecked") - public int compare(Object first, Object second) { - return ((Comparable)first).compareTo(second); - } - static final NaturalOrder INSTANCE = new NaturalOrder(); - } - - /** - * Checks that {@code fromIndex} and {@code toIndex} are in - * the range and throws an exception if they aren't. - */ - static void rangeCheck(int arrayLength, int fromIndex, int toIndex) { - if (fromIndex > toIndex) { - throw new IllegalArgumentException( - "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); - } - if (fromIndex < 0) { - throw new ArrayIndexOutOfBoundsException(fromIndex); - } - if (toIndex > arrayLength) { - throw new ArrayIndexOutOfBoundsException(toIndex); - } - } - - /* - * Sorting methods. Note that all public "sort" methods take the - * same form: Performing argument checks if necessary, and then - * expanding arguments into those required for the internal - * implementation methods residing in other package-private - * classes (except for legacyMergeSort, included in this class). - */ - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - */ - public static void sort(int[] a) { - DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - */ - public static void sort(int[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - */ - public static void sort(long[] a) { - DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - */ - public static void sort(long[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - */ - public static void sort(short[] a) { - DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - */ - public static void sort(short[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - */ - public static void sort(char[] a) { - DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - */ - public static void sort(char[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - */ - public static void sort(byte[] a) { - DualPivotQuicksort.sort(a, 0, a.length - 1); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - */ - public static void sort(byte[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

The {@code <} relation does not provide a total order on all float - * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Float#compareTo}: {@code -0.0f} is treated as less than value - * {@code 0.0f} and {@code Float.NaN} is considered greater than any - * other value and all {@code Float.NaN} values are considered equal. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - */ - public static void sort(float[] a) { - DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

The {@code <} relation does not provide a total order on all float - * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Float#compareTo}: {@code -0.0f} is treated as less than value - * {@code 0.0f} and {@code Float.NaN} is considered greater than any - * other value and all {@code Float.NaN} values are considered equal. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - */ - public static void sort(float[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

The {@code <} relation does not provide a total order on all double - * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Double#compareTo}: {@code -0.0d} is treated as less than value - * {@code 0.0d} and {@code Double.NaN} is considered greater than any - * other value and all {@code Double.NaN} values are considered equal. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - */ - public static void sort(double[] a) { - DualPivotQuicksort.sort(a, 0, a.length - 1, null, 0, 0); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty. - * - *

The {@code <} relation does not provide a total order on all double - * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Double#compareTo}: {@code -0.0d} is treated as less than value - * {@code 0.0d} and {@code Double.NaN} is considered greater than any - * other value and all {@code Double.NaN} values are considered equal. - * - *

Implementation note: The sorting algorithm is a Dual-Pivot Quicksort - * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically - * faster than traditional (one-pivot) Quicksort implementations. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - */ - public static void sort(double[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - } - - /** - * Sorts the specified array into ascending numerical order. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(byte[] a) { - int n = a.length, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, 0, n - 1); - else - new ArraysParallelSortHelpers.FJByte.Sorter - (null, a, new byte[n], 0, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified range of the array into ascending numerical order. - * The range to be sorted extends from the index {@code fromIndex}, - * inclusive, to the index {@code toIndex}, exclusive. If - * {@code fromIndex == toIndex}, the range to be sorted is empty. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(byte[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(byte[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(byte[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int n = toIndex - fromIndex, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1); - else - new ArraysParallelSortHelpers.FJByte.Sorter - (null, a, new byte[n], fromIndex, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(char[] a) { - int n = a.length, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJChar.Sorter - (null, a, new char[n], 0, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified range of the array into ascending numerical order. - * The range to be sorted extends from the index {@code fromIndex}, - * inclusive, to the index {@code toIndex}, exclusive. If - * {@code fromIndex == toIndex}, the range to be sorted is empty. - * - @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(char[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(char[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(char[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int n = toIndex - fromIndex, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJChar.Sorter - (null, a, new char[n], fromIndex, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(short[] a) { - int n = a.length, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJShort.Sorter - (null, a, new short[n], 0, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified range of the array into ascending numerical order. - * The range to be sorted extends from the index {@code fromIndex}, - * inclusive, to the index {@code toIndex}, exclusive. If - * {@code fromIndex == toIndex}, the range to be sorted is empty. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(short[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(short[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(short[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int n = toIndex - fromIndex, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJShort.Sorter - (null, a, new short[n], fromIndex, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(int[] a) { - int n = a.length, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJInt.Sorter - (null, a, new int[n], 0, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified range of the array into ascending numerical order. - * The range to be sorted extends from the index {@code fromIndex}, - * inclusive, to the index {@code toIndex}, exclusive. If - * {@code fromIndex == toIndex}, the range to be sorted is empty. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(int[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(int[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(int[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int n = toIndex - fromIndex, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJInt.Sorter - (null, a, new int[n], fromIndex, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(long[] a) { - int n = a.length, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJLong.Sorter - (null, a, new long[n], 0, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified range of the array into ascending numerical order. - * The range to be sorted extends from the index {@code fromIndex}, - * inclusive, to the index {@code toIndex}, exclusive. If - * {@code fromIndex == toIndex}, the range to be sorted is empty. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(long[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(long[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(long[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int n = toIndex - fromIndex, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJLong.Sorter - (null, a, new long[n], fromIndex, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

The {@code <} relation does not provide a total order on all float - * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Float#compareTo}: {@code -0.0f} is treated as less than value - * {@code 0.0f} and {@code Float.NaN} is considered greater than any - * other value and all {@code Float.NaN} values are considered equal. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(float[] a) { - int n = a.length, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJFloat.Sorter - (null, a, new float[n], 0, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified range of the array into ascending numerical order. - * The range to be sorted extends from the index {@code fromIndex}, - * inclusive, to the index {@code toIndex}, exclusive. If - * {@code fromIndex == toIndex}, the range to be sorted is empty. - * - *

The {@code <} relation does not provide a total order on all float - * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Float#compareTo}: {@code -0.0f} is treated as less than value - * {@code 0.0f} and {@code Float.NaN} is considered greater than any - * other value and all {@code Float.NaN} values are considered equal. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(float[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(float[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(float[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int n = toIndex - fromIndex, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJFloat.Sorter - (null, a, new float[n], fromIndex, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified array into ascending numerical order. - * - *

The {@code <} relation does not provide a total order on all double - * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Double#compareTo}: {@code -0.0d} is treated as less than value - * {@code 0.0d} and {@code Double.NaN} is considered greater than any - * other value and all {@code Double.NaN} values are considered equal. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. - * - * @param a the array to be sorted - * - * @since 1.8 - */ - public static void parallelSort(double[] a) { - int n = a.length, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, 0, n - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJDouble.Sorter - (null, a, new double[n], 0, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified range of the array into ascending numerical order. - * The range to be sorted extends from the index {@code fromIndex}, - * inclusive, to the index {@code toIndex}, exclusive. If - * {@code fromIndex == toIndex}, the range to be sorted is empty. - * - *

The {@code <} relation does not provide a total order on all double - * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Double#compareTo}: {@code -0.0d} is treated as less than value - * {@code 0.0d} and {@code Double.NaN} is considered greater than any - * other value and all {@code Double.NaN} values are considered equal. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(double[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(double[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - * - * @since 1.8 - */ - public static void parallelSort(double[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int n = toIndex - fromIndex, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - DualPivotQuicksort.sort(a, fromIndex, toIndex - 1, null, 0, 0); - else - new ArraysParallelSortHelpers.FJDouble.Sorter - (null, a, new double[n], fromIndex, n, 0, - ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g).invoke(); - } - - /** - * Sorts the specified array of objects into ascending order, according - * to the {@linkplain Comparable natural ordering} of its elements. - * All elements in the array must implement the {@link Comparable} - * interface. Furthermore, all elements in the array must be - * mutually comparable (that is, {@code e1.compareTo(e2)} must - * not throw a {@code ClassCastException} for any elements {@code e1} - * and {@code e2} in the array). - * - *

This sort is guaranteed to be stable: equal elements will - * not be reordered as a result of the sort. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. - * - * @param the class of the objects to be sorted - * @param a the array to be sorted - * - * @throws ClassCastException if the array contains elements that are not - * mutually comparable (for example, strings and integers) - * @throws IllegalArgumentException (optional) if the natural - * ordering of the array elements is found to violate the - * {@link Comparable} contract - * - * @since 1.8 - */ - @SuppressWarnings("unchecked") - public static > void parallelSort(T[] a) { - int n = a.length, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - TimSort.sort(a, 0, n, NaturalOrder.INSTANCE, null, 0, 0); - else - new ArraysParallelSortHelpers.FJObject.Sorter<> - (null, a, - (T[])Array.newInstance(a.getClass().getComponentType(), n), - 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke(); - } - - /** - * Sorts the specified range of the specified array of objects into - * ascending order, according to the - * {@linkplain Comparable natural ordering} of its - * elements. The range to be sorted extends from index - * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive. - * (If {@code fromIndex==toIndex}, the range to be sorted is empty.) All - * elements in this range must implement the {@link Comparable} - * interface. Furthermore, all elements in this range must be mutually - * comparable (that is, {@code e1.compareTo(e2)} must not throw a - * {@code ClassCastException} for any elements {@code e1} and - * {@code e2} in the array). - * - *

This sort is guaranteed to be stable: equal elements will - * not be reordered as a result of the sort. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param the class of the objects to be sorted - * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @throws IllegalArgumentException if {@code fromIndex > toIndex} or - * (optional) if the natural ordering of the array elements is - * found to violate the {@link Comparable} contract - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - * @throws ClassCastException if the array contains elements that are - * not mutually comparable (for example, strings and - * integers). - * - * @since 1.8 - */ - @SuppressWarnings("unchecked") - public static > - void parallelSort(T[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - int n = toIndex - fromIndex, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - TimSort.sort(a, fromIndex, toIndex, NaturalOrder.INSTANCE, null, 0, 0); - else - new ArraysParallelSortHelpers.FJObject.Sorter<> - (null, a, - (T[])Array.newInstance(a.getClass().getComponentType(), n), - fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke(); - } - - /** - * Sorts the specified array of objects according to the order induced by - * the specified comparator. All elements in the array must be - * mutually comparable by the specified comparator (that is, - * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} - * for any elements {@code e1} and {@code e2} in the array). - * - *

This sort is guaranteed to be stable: equal elements will - * not be reordered as a result of the sort. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a - * working space no greater than the size of the original array. The - * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to - * execute any parallel tasks. - * - * @param the class of the objects to be sorted - * @param a the array to be sorted - * @param cmp the comparator to determine the order of the array. A - * {@code null} value indicates that the elements' - * {@linkplain Comparable natural ordering} should be used. - * @throws ClassCastException if the array contains elements that are - * not mutually comparable using the specified comparator - * @throws IllegalArgumentException (optional) if the comparator is - * found to violate the {@link java.util.Comparator} contract - * - * @since 1.8 - */ - @SuppressWarnings("unchecked") - public static void parallelSort(T[] a, Comparator cmp) { - if (cmp == null) - cmp = NaturalOrder.INSTANCE; - int n = a.length, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - TimSort.sort(a, 0, n, cmp, null, 0, 0); - else - new ArraysParallelSortHelpers.FJObject.Sorter<> - (null, a, - (T[])Array.newInstance(a.getClass().getComponentType(), n), - 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g, cmp).invoke(); - } - - /** - * Sorts the specified range of the specified array of objects according - * to the order induced by the specified comparator. The range to be - * sorted extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be sorted is empty.) All elements in the range must be - * mutually comparable by the specified comparator (that is, - * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} - * for any elements {@code e1} and {@code e2} in the range). - * - *

This sort is guaranteed to be stable: equal elements will - * not be reordered as a result of the sort. - * - * @implNote The sorting algorithm is a parallel sort-merge that breaks the - * array into sub-arrays that are themselves sorted and then merged. When - * the sub-array length reaches a minimum granularity, the sub-array is - * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} - * method. If the length of the specified array is less than the minimum - * granularity, then it is sorted using the appropriate {@link - * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working - * space no greater than the size of the specified range of the original - * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is - * used to execute any parallel tasks. - * - * @param the class of the objects to be sorted - * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @param cmp the comparator to determine the order of the array. A - * {@code null} value indicates that the elements' - * {@linkplain Comparable natural ordering} should be used. - * @throws IllegalArgumentException if {@code fromIndex > toIndex} or - * (optional) if the natural ordering of the array elements is - * found to violate the {@link Comparable} contract - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - * @throws ClassCastException if the array contains elements that are - * not mutually comparable (for example, strings and - * integers). - * - * @since 1.8 - */ - @SuppressWarnings("unchecked") - public static void parallelSort(T[] a, int fromIndex, int toIndex, - Comparator cmp) { - rangeCheck(a.length, fromIndex, toIndex); - if (cmp == null) - cmp = NaturalOrder.INSTANCE; - int n = toIndex - fromIndex, p, g; - if (n <= MIN_ARRAY_SORT_GRAN || - (p = ForkJoinPool.getCommonPoolParallelism()) == 1) - TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0); - else - new ArraysParallelSortHelpers.FJObject.Sorter<> - (null, a, - (T[])Array.newInstance(a.getClass().getComponentType(), n), - fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? - MIN_ARRAY_SORT_GRAN : g, cmp).invoke(); - } - - /* - * Sorting of complex type arrays. - */ - - /** - * Old merge sort implementation can be selected (for - * compatibility with broken comparators) using a system property. - * Cannot be a static boolean in the enclosing class due to - * circular dependencies. To be removed in a future release. - */ - static final class LegacyMergeSort { - private static final boolean userRequested = - java.security.AccessController.doPrivileged( - new sun.security.action.GetBooleanAction( - "java.util.Arrays.useLegacyMergeSort")).booleanValue(); - } - - /** - * Sorts the specified array of objects into ascending order, according - * to the {@linkplain Comparable natural ordering} of its elements. - * All elements in the array must implement the {@link Comparable} - * interface. Furthermore, all elements in the array must be - * mutually comparable (that is, {@code e1.compareTo(e2)} must - * not throw a {@code ClassCastException} for any elements {@code e1} - * and {@code e2} in the array). - * - *

This sort is guaranteed to be stable: equal elements will - * not be reordered as a result of the sort. - * - *

Implementation note: This implementation is a stable, adaptive, - * iterative mergesort that requires far fewer than n lg(n) comparisons - * when the input array is partially sorted, while offering the - * performance of a traditional mergesort when the input array is - * randomly ordered. If the input array is nearly sorted, the - * implementation requires approximately n comparisons. Temporary - * storage requirements vary from a small constant for nearly sorted - * input arrays to n/2 object references for randomly ordered input - * arrays. - * - *

The implementation takes equal advantage of ascending and - * descending order in its input array, and can take advantage of - * ascending and descending order in different parts of the same - * input array. It is well-suited to merging two or more sorted arrays: - * simply concatenate the arrays and sort the resulting array. - * - *

The implementation was adapted from Tim Peters's list sort for Python - * ( - * TimSort). It uses techniques from Peter McIlroy's "Optimistic - * Sorting and Information Theoretic Complexity", in Proceedings of the - * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, - * January 1993. - * - * @param a the array to be sorted - * @throws ClassCastException if the array contains elements that are not - * mutually comparable (for example, strings and integers) - * @throws IllegalArgumentException (optional) if the natural - * ordering of the array elements is found to violate the - * {@link Comparable} contract - */ - public static void sort(Object[] a) { - if (LegacyMergeSort.userRequested) - legacyMergeSort(a); - else - ComparableTimSort.sort(a, 0, a.length, null, 0, 0); - } - - /** To be removed in a future release. */ - private static void legacyMergeSort(Object[] a) { - Object[] aux = a.clone(); - mergeSort(aux, a, 0, a.length, 0); - } - - /** - * Sorts the specified range of the specified array of objects into - * ascending order, according to the - * {@linkplain Comparable natural ordering} of its - * elements. The range to be sorted extends from index - * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive. - * (If {@code fromIndex==toIndex}, the range to be sorted is empty.) All - * elements in this range must implement the {@link Comparable} - * interface. Furthermore, all elements in this range must be mutually - * comparable (that is, {@code e1.compareTo(e2)} must not throw a - * {@code ClassCastException} for any elements {@code e1} and - * {@code e2} in the array). - * - *

This sort is guaranteed to be stable: equal elements will - * not be reordered as a result of the sort. - * - *

Implementation note: This implementation is a stable, adaptive, - * iterative mergesort that requires far fewer than n lg(n) comparisons - * when the input array is partially sorted, while offering the - * performance of a traditional mergesort when the input array is - * randomly ordered. If the input array is nearly sorted, the - * implementation requires approximately n comparisons. Temporary - * storage requirements vary from a small constant for nearly sorted - * input arrays to n/2 object references for randomly ordered input - * arrays. - * - *

The implementation takes equal advantage of ascending and - * descending order in its input array, and can take advantage of - * ascending and descending order in different parts of the same - * input array. It is well-suited to merging two or more sorted arrays: - * simply concatenate the arrays and sort the resulting array. - * - *

The implementation was adapted from Tim Peters's list sort for Python - * ( - * TimSort). It uses techniques from Peter McIlroy's "Optimistic - * Sorting and Information Theoretic Complexity", in Proceedings of the - * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, - * January 1993. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @throws IllegalArgumentException if {@code fromIndex > toIndex} or - * (optional) if the natural ordering of the array elements is - * found to violate the {@link Comparable} contract - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - * @throws ClassCastException if the array contains elements that are - * not mutually comparable (for example, strings and - * integers). - */ - public static void sort(Object[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - if (LegacyMergeSort.userRequested) - legacyMergeSort(a, fromIndex, toIndex); - else - ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0); - } - - /** To be removed in a future release. */ - private static void legacyMergeSort(Object[] a, - int fromIndex, int toIndex) { - Object[] aux = copyOfRange(a, fromIndex, toIndex); - mergeSort(aux, a, fromIndex, toIndex, -fromIndex); - } - - /** - * Tuning parameter: list size at or below which insertion sort will be - * used in preference to mergesort. - * To be removed in a future release. - */ - private static final int INSERTIONSORT_THRESHOLD = 7; - - /** - * Src is the source array that starts at index 0 - * Dest is the (possibly larger) array destination with a possible offset - * low is the index in dest to start sorting - * high is the end index in dest to end sorting - * off is the offset to generate corresponding low, high in src - * To be removed in a future release. - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - private static void mergeSort(Object[] src, - Object[] dest, - int low, - int high, - int off) { - int length = high - low; - - // Insertion sort on smallest arrays - if (length < INSERTIONSORT_THRESHOLD) { - for (int i=low; ilow && - ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--) - swap(dest, j, j-1); - return; - } - - // Recursively sort halves of dest into src - int destLow = low; - int destHigh = high; - low += off; - high += off; - int mid = (low + high) >>> 1; - mergeSort(dest, src, low, mid, -off); - mergeSort(dest, src, mid, high, -off); - - // If list is already sorted, just copy from src to dest. This is an - // optimization that results in faster sorts for nearly ordered lists. - if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) { - System.arraycopy(src, low, dest, destLow, length); - return; - } - - // Merge sorted halves (now in src) into dest - for(int i = destLow, p = low, q = mid; i < destHigh; i++) { - if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0) - dest[i] = src[p++]; - else - dest[i] = src[q++]; - } - } - - /** - * Swaps x[a] with x[b]. - */ - private static void swap(Object[] x, int a, int b) { - Object t = x[a]; - x[a] = x[b]; - x[b] = t; - } - - /** - * Sorts the specified array of objects according to the order induced by - * the specified comparator. All elements in the array must be - * mutually comparable by the specified comparator (that is, - * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} - * for any elements {@code e1} and {@code e2} in the array). - * - *

This sort is guaranteed to be stable: equal elements will - * not be reordered as a result of the sort. - * - *

Implementation note: This implementation is a stable, adaptive, - * iterative mergesort that requires far fewer than n lg(n) comparisons - * when the input array is partially sorted, while offering the - * performance of a traditional mergesort when the input array is - * randomly ordered. If the input array is nearly sorted, the - * implementation requires approximately n comparisons. Temporary - * storage requirements vary from a small constant for nearly sorted - * input arrays to n/2 object references for randomly ordered input - * arrays. - * - *

The implementation takes equal advantage of ascending and - * descending order in its input array, and can take advantage of - * ascending and descending order in different parts of the same - * input array. It is well-suited to merging two or more sorted arrays: - * simply concatenate the arrays and sort the resulting array. - * - *

The implementation was adapted from Tim Peters's list sort for Python - * ( - * TimSort). It uses techniques from Peter McIlroy's "Optimistic - * Sorting and Information Theoretic Complexity", in Proceedings of the - * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, - * January 1993. - * - * @param the class of the objects to be sorted - * @param a the array to be sorted - * @param c the comparator to determine the order of the array. A - * {@code null} value indicates that the elements' - * {@linkplain Comparable natural ordering} should be used. - * @throws ClassCastException if the array contains elements that are - * not mutually comparable using the specified comparator - * @throws IllegalArgumentException (optional) if the comparator is - * found to violate the {@link Comparator} contract - */ - public static void sort(T[] a, Comparator c) { - if (c == null) { - sort(a); - } else { - if (LegacyMergeSort.userRequested) - legacyMergeSort(a, c); - else - TimSort.sort(a, 0, a.length, c, null, 0, 0); - } - } - - /** To be removed in a future release. */ - private static void legacyMergeSort(T[] a, Comparator c) { - T[] aux = a.clone(); - if (c==null) - mergeSort(aux, a, 0, a.length, 0); - else - mergeSort(aux, a, 0, a.length, 0, c); - } - - /** - * Sorts the specified range of the specified array of objects according - * to the order induced by the specified comparator. The range to be - * sorted extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be sorted is empty.) All elements in the range must be - * mutually comparable by the specified comparator (that is, - * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} - * for any elements {@code e1} and {@code e2} in the range). - * - *

This sort is guaranteed to be stable: equal elements will - * not be reordered as a result of the sort. - * - *

Implementation note: This implementation is a stable, adaptive, - * iterative mergesort that requires far fewer than n lg(n) comparisons - * when the input array is partially sorted, while offering the - * performance of a traditional mergesort when the input array is - * randomly ordered. If the input array is nearly sorted, the - * implementation requires approximately n comparisons. Temporary - * storage requirements vary from a small constant for nearly sorted - * input arrays to n/2 object references for randomly ordered input - * arrays. - * - *

The implementation takes equal advantage of ascending and - * descending order in its input array, and can take advantage of - * ascending and descending order in different parts of the same - * input array. It is well-suited to merging two or more sorted arrays: - * simply concatenate the arrays and sort the resulting array. - * - *

The implementation was adapted from Tim Peters's list sort for Python - * ( - * TimSort). It uses techniques from Peter McIlroy's "Optimistic - * Sorting and Information Theoretic Complexity", in Proceedings of the - * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, - * January 1993. - * - * @param the class of the objects to be sorted - * @param a the array to be sorted - * @param fromIndex the index of the first element (inclusive) to be - * sorted - * @param toIndex the index of the last element (exclusive) to be sorted - * @param c the comparator to determine the order of the array. A - * {@code null} value indicates that the elements' - * {@linkplain Comparable natural ordering} should be used. - * @throws ClassCastException if the array contains elements that are not - * mutually comparable using the specified comparator. - * @throws IllegalArgumentException if {@code fromIndex > toIndex} or - * (optional) if the comparator is found to violate the - * {@link Comparator} contract - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - */ - public static void sort(T[] a, int fromIndex, int toIndex, - Comparator c) { - if (c == null) { - sort(a, fromIndex, toIndex); - } else { - rangeCheck(a.length, fromIndex, toIndex); - if (LegacyMergeSort.userRequested) - legacyMergeSort(a, fromIndex, toIndex, c); - else - TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0); - } - } - - /** To be removed in a future release. */ - private static void legacyMergeSort(T[] a, int fromIndex, int toIndex, - Comparator c) { - T[] aux = copyOfRange(a, fromIndex, toIndex); - if (c==null) - mergeSort(aux, a, fromIndex, toIndex, -fromIndex); - else - mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c); - } - - /** - * Src is the source array that starts at index 0 - * Dest is the (possibly larger) array destination with a possible offset - * low is the index in dest to start sorting - * high is the end index in dest to end sorting - * off is the offset into src corresponding to low in dest - * To be removed in a future release. - */ - @SuppressWarnings({"rawtypes", "unchecked"}) - private static void mergeSort(Object[] src, - Object[] dest, - int low, int high, int off, - Comparator c) { - int length = high - low; - - // Insertion sort on smallest arrays - if (length < INSERTIONSORT_THRESHOLD) { - for (int i=low; ilow && c.compare(dest[j-1], dest[j])>0; j--) - swap(dest, j, j-1); - return; - } - - // Recursively sort halves of dest into src - int destLow = low; - int destHigh = high; - low += off; - high += off; - int mid = (low + high) >>> 1; - mergeSort(dest, src, low, mid, -off, c); - mergeSort(dest, src, mid, high, -off, c); - - // If list is already sorted, just copy from src to dest. This is an - // optimization that results in faster sorts for nearly ordered lists. - if (c.compare(src[mid-1], src[mid]) <= 0) { - System.arraycopy(src, low, dest, destLow, length); - return; - } - - // Merge sorted halves (now in src) into dest - for(int i = destLow, p = low, q = mid; i < destHigh; i++) { - if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0) - dest[i] = src[p++]; - else - dest[i] = src[q++]; - } - } - - // Parallel prefix - - /** - * Cumulates, in parallel, each element of the given array in place, - * using the supplied function. For example if the array initially - * holds {@code [2, 1, 0, 3]} and the operation performs addition, - * then upon return the array holds {@code [2, 3, 3, 6]}. - * Parallel prefix computation is usually more efficient than - * sequential loops for large arrays. - * - * @param the class of the objects in the array - * @param array the array, which is modified in-place by this method - * @param op a side-effect-free, associative function to perform the - * cumulation - * @throws NullPointerException if the specified array or function is null - * @since 1.8 - */ - public static void parallelPrefix(T[] array, BinaryOperator op) { - Objects.requireNonNull(op); - if (array.length > 0) - new ArrayPrefixHelpers.CumulateTask<> - (null, op, array, 0, array.length).invoke(); - } - - /** - * Performs {@link #parallelPrefix(Object[], BinaryOperator)} - * for the given subrange of the array. - * - * @param the class of the objects in the array - * @param array the array - * @param fromIndex the index of the first element, inclusive - * @param toIndex the index of the last element, exclusive - * @param op a side-effect-free, associative function to perform the - * cumulation - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > array.length} - * @throws NullPointerException if the specified array or function is null - * @since 1.8 - */ - public static void parallelPrefix(T[] array, int fromIndex, - int toIndex, BinaryOperator op) { - Objects.requireNonNull(op); - rangeCheck(array.length, fromIndex, toIndex); - if (fromIndex < toIndex) - new ArrayPrefixHelpers.CumulateTask<> - (null, op, array, fromIndex, toIndex).invoke(); - } - - /** - * Cumulates, in parallel, each element of the given array in place, - * using the supplied function. For example if the array initially - * holds {@code [2, 1, 0, 3]} and the operation performs addition, - * then upon return the array holds {@code [2, 3, 3, 6]}. - * Parallel prefix computation is usually more efficient than - * sequential loops for large arrays. - * - * @param array the array, which is modified in-place by this method - * @param op a side-effect-free, associative function to perform the - * cumulation - * @throws NullPointerException if the specified array or function is null - * @since 1.8 - */ - public static void parallelPrefix(long[] array, LongBinaryOperator op) { - Objects.requireNonNull(op); - if (array.length > 0) - new ArrayPrefixHelpers.LongCumulateTask - (null, op, array, 0, array.length).invoke(); - } - - /** - * Performs {@link #parallelPrefix(long[], LongBinaryOperator)} - * for the given subrange of the array. - * - * @param array the array - * @param fromIndex the index of the first element, inclusive - * @param toIndex the index of the last element, exclusive - * @param op a side-effect-free, associative function to perform the - * cumulation - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > array.length} - * @throws NullPointerException if the specified array or function is null - * @since 1.8 - */ - public static void parallelPrefix(long[] array, int fromIndex, - int toIndex, LongBinaryOperator op) { - Objects.requireNonNull(op); - rangeCheck(array.length, fromIndex, toIndex); - if (fromIndex < toIndex) - new ArrayPrefixHelpers.LongCumulateTask - (null, op, array, fromIndex, toIndex).invoke(); - } - - /** - * Cumulates, in parallel, each element of the given array in place, - * using the supplied function. For example if the array initially - * holds {@code [2.0, 1.0, 0.0, 3.0]} and the operation performs addition, - * then upon return the array holds {@code [2.0, 3.0, 3.0, 6.0]}. - * Parallel prefix computation is usually more efficient than - * sequential loops for large arrays. - * - *

Because floating-point operations may not be strictly associative, - * the returned result may not be identical to the value that would be - * obtained if the operation was performed sequentially. - * - * @param array the array, which is modified in-place by this method - * @param op a side-effect-free function to perform the cumulation - * @throws NullPointerException if the specified array or function is null - * @since 1.8 - */ - public static void parallelPrefix(double[] array, DoubleBinaryOperator op) { - Objects.requireNonNull(op); - if (array.length > 0) - new ArrayPrefixHelpers.DoubleCumulateTask - (null, op, array, 0, array.length).invoke(); - } - - /** - * Performs {@link #parallelPrefix(double[], DoubleBinaryOperator)} - * for the given subrange of the array. - * - * @param array the array - * @param fromIndex the index of the first element, inclusive - * @param toIndex the index of the last element, exclusive - * @param op a side-effect-free, associative function to perform the - * cumulation - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > array.length} - * @throws NullPointerException if the specified array or function is null - * @since 1.8 - */ - public static void parallelPrefix(double[] array, int fromIndex, - int toIndex, DoubleBinaryOperator op) { - Objects.requireNonNull(op); - rangeCheck(array.length, fromIndex, toIndex); - if (fromIndex < toIndex) - new ArrayPrefixHelpers.DoubleCumulateTask - (null, op, array, fromIndex, toIndex).invoke(); - } - - /** - * Cumulates, in parallel, each element of the given array in place, - * using the supplied function. For example if the array initially - * holds {@code [2, 1, 0, 3]} and the operation performs addition, - * then upon return the array holds {@code [2, 3, 3, 6]}. - * Parallel prefix computation is usually more efficient than - * sequential loops for large arrays. - * - * @param array the array, which is modified in-place by this method - * @param op a side-effect-free, associative function to perform the - * cumulation - * @throws NullPointerException if the specified array or function is null - * @since 1.8 - */ - public static void parallelPrefix(int[] array, IntBinaryOperator op) { - Objects.requireNonNull(op); - if (array.length > 0) - new ArrayPrefixHelpers.IntCumulateTask - (null, op, array, 0, array.length).invoke(); - } - - /** - * Performs {@link #parallelPrefix(int[], IntBinaryOperator)} - * for the given subrange of the array. - * - * @param array the array - * @param fromIndex the index of the first element, inclusive - * @param toIndex the index of the last element, exclusive - * @param op a side-effect-free, associative function to perform the - * cumulation - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > array.length} - * @throws NullPointerException if the specified array or function is null - * @since 1.8 - */ - public static void parallelPrefix(int[] array, int fromIndex, - int toIndex, IntBinaryOperator op) { - Objects.requireNonNull(op); - rangeCheck(array.length, fromIndex, toIndex); - if (fromIndex < toIndex) - new ArrayPrefixHelpers.IntCumulateTask - (null, op, array, fromIndex, toIndex).invoke(); - } - - // Searching - - /** - * Searches the specified array of longs for the specified value using the - * binary search algorithm. The array must be sorted (as - * by the {@link #sort(long[])} method) prior to making this call. If it - * is not sorted, the results are undefined. If the array contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element greater than the key, or {@code a.length} if all - * elements in the array are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - */ - public static int binarySearch(long[] a, long key) { - return binarySearch0(a, 0, a.length, key); - } - - /** - * Searches a range of - * the specified array of longs for the specified value using the - * binary search algorithm. - * The range must be sorted (as - * by the {@link #sort(long[], int, int)} method) - * prior to making this call. If it - * is not sorted, the results are undefined. If the range contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param fromIndex the index of the first element (inclusive) to be - * searched - * @param toIndex the index of the last element (exclusive) to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array - * within the specified range; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element in the range greater than the key, - * or {@code toIndex} if all - * elements in the range are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws IllegalArgumentException - * if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0 or toIndex > a.length} - * @since 1.6 - */ - public static int binarySearch(long[] a, int fromIndex, int toIndex, - long key) { - rangeCheck(a.length, fromIndex, toIndex); - return binarySearch0(a, fromIndex, toIndex, key); - } - - // Like public version, but without range checks. - private static int binarySearch0(long[] a, int fromIndex, int toIndex, - long key) { - int low = fromIndex; - int high = toIndex - 1; - - while (low <= high) { - int mid = (low + high) >>> 1; - long midVal = a[mid]; - - if (midVal < key) - low = mid + 1; - else if (midVal > key) - high = mid - 1; - else - return mid; // key found - } - return -(low + 1); // key not found. - } - - /** - * Searches the specified array of ints for the specified value using the - * binary search algorithm. The array must be sorted (as - * by the {@link #sort(int[])} method) prior to making this call. If it - * is not sorted, the results are undefined. If the array contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element greater than the key, or {@code a.length} if all - * elements in the array are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - */ - public static int binarySearch(int[] a, int key) { - return binarySearch0(a, 0, a.length, key); - } - - /** - * Searches a range of - * the specified array of ints for the specified value using the - * binary search algorithm. - * The range must be sorted (as - * by the {@link #sort(int[], int, int)} method) - * prior to making this call. If it - * is not sorted, the results are undefined. If the range contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param fromIndex the index of the first element (inclusive) to be - * searched - * @param toIndex the index of the last element (exclusive) to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array - * within the specified range; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element in the range greater than the key, - * or {@code toIndex} if all - * elements in the range are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws IllegalArgumentException - * if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0 or toIndex > a.length} - * @since 1.6 - */ - public static int binarySearch(int[] a, int fromIndex, int toIndex, - int key) { - rangeCheck(a.length, fromIndex, toIndex); - return binarySearch0(a, fromIndex, toIndex, key); - } - - // Like public version, but without range checks. - private static int binarySearch0(int[] a, int fromIndex, int toIndex, - int key) { - int low = fromIndex; - int high = toIndex - 1; - - while (low <= high) { - int mid = (low + high) >>> 1; - int midVal = a[mid]; - - if (midVal < key) - low = mid + 1; - else if (midVal > key) - high = mid - 1; - else - return mid; // key found - } - return -(low + 1); // key not found. - } - - /** - * Searches the specified array of shorts for the specified value using - * the binary search algorithm. The array must be sorted - * (as by the {@link #sort(short[])} method) prior to making this call. If - * it is not sorted, the results are undefined. If the array contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element greater than the key, or {@code a.length} if all - * elements in the array are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - */ - public static int binarySearch(short[] a, short key) { - return binarySearch0(a, 0, a.length, key); - } - - /** - * Searches a range of - * the specified array of shorts for the specified value using - * the binary search algorithm. - * The range must be sorted - * (as by the {@link #sort(short[], int, int)} method) - * prior to making this call. If - * it is not sorted, the results are undefined. If the range contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param fromIndex the index of the first element (inclusive) to be - * searched - * @param toIndex the index of the last element (exclusive) to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array - * within the specified range; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element in the range greater than the key, - * or {@code toIndex} if all - * elements in the range are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws IllegalArgumentException - * if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0 or toIndex > a.length} - * @since 1.6 - */ - public static int binarySearch(short[] a, int fromIndex, int toIndex, - short key) { - rangeCheck(a.length, fromIndex, toIndex); - return binarySearch0(a, fromIndex, toIndex, key); - } - - // Like public version, but without range checks. - private static int binarySearch0(short[] a, int fromIndex, int toIndex, - short key) { - int low = fromIndex; - int high = toIndex - 1; - - while (low <= high) { - int mid = (low + high) >>> 1; - short midVal = a[mid]; - - if (midVal < key) - low = mid + 1; - else if (midVal > key) - high = mid - 1; - else - return mid; // key found - } - return -(low + 1); // key not found. - } - - /** - * Searches the specified array of chars for the specified value using the - * binary search algorithm. The array must be sorted (as - * by the {@link #sort(char[])} method) prior to making this call. If it - * is not sorted, the results are undefined. If the array contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element greater than the key, or {@code a.length} if all - * elements in the array are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - */ - public static int binarySearch(char[] a, char key) { - return binarySearch0(a, 0, a.length, key); - } - - /** - * Searches a range of - * the specified array of chars for the specified value using the - * binary search algorithm. - * The range must be sorted (as - * by the {@link #sort(char[], int, int)} method) - * prior to making this call. If it - * is not sorted, the results are undefined. If the range contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param fromIndex the index of the first element (inclusive) to be - * searched - * @param toIndex the index of the last element (exclusive) to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array - * within the specified range; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element in the range greater than the key, - * or {@code toIndex} if all - * elements in the range are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws IllegalArgumentException - * if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0 or toIndex > a.length} - * @since 1.6 - */ - public static int binarySearch(char[] a, int fromIndex, int toIndex, - char key) { - rangeCheck(a.length, fromIndex, toIndex); - return binarySearch0(a, fromIndex, toIndex, key); - } - - // Like public version, but without range checks. - private static int binarySearch0(char[] a, int fromIndex, int toIndex, - char key) { - int low = fromIndex; - int high = toIndex - 1; - - while (low <= high) { - int mid = (low + high) >>> 1; - char midVal = a[mid]; - - if (midVal < key) - low = mid + 1; - else if (midVal > key) - high = mid - 1; - else - return mid; // key found - } - return -(low + 1); // key not found. - } - - /** - * Searches the specified array of bytes for the specified value using the - * binary search algorithm. The array must be sorted (as - * by the {@link #sort(byte[])} method) prior to making this call. If it - * is not sorted, the results are undefined. If the array contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element greater than the key, or {@code a.length} if all - * elements in the array are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - */ - public static int binarySearch(byte[] a, byte key) { - return binarySearch0(a, 0, a.length, key); - } - - /** - * Searches a range of - * the specified array of bytes for the specified value using the - * binary search algorithm. - * The range must be sorted (as - * by the {@link #sort(byte[], int, int)} method) - * prior to making this call. If it - * is not sorted, the results are undefined. If the range contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param fromIndex the index of the first element (inclusive) to be - * searched - * @param toIndex the index of the last element (exclusive) to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array - * within the specified range; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element in the range greater than the key, - * or {@code toIndex} if all - * elements in the range are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws IllegalArgumentException - * if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0 or toIndex > a.length} - * @since 1.6 - */ - public static int binarySearch(byte[] a, int fromIndex, int toIndex, - byte key) { - rangeCheck(a.length, fromIndex, toIndex); - return binarySearch0(a, fromIndex, toIndex, key); - } - - // Like public version, but without range checks. - private static int binarySearch0(byte[] a, int fromIndex, int toIndex, - byte key) { - int low = fromIndex; - int high = toIndex - 1; - - while (low <= high) { - int mid = (low + high) >>> 1; - byte midVal = a[mid]; - - if (midVal < key) - low = mid + 1; - else if (midVal > key) - high = mid - 1; - else - return mid; // key found - } - return -(low + 1); // key not found. - } - - /** - * Searches the specified array of doubles for the specified value using - * the binary search algorithm. The array must be sorted - * (as by the {@link #sort(double[])} method) prior to making this call. - * If it is not sorted, the results are undefined. If the array contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. This method considers all NaN values to be - * equivalent and equal. - * - * @param a the array to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element greater than the key, or {@code a.length} if all - * elements in the array are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - */ - public static int binarySearch(double[] a, double key) { - return binarySearch0(a, 0, a.length, key); - } - - /** - * Searches a range of - * the specified array of doubles for the specified value using - * the binary search algorithm. - * The range must be sorted - * (as by the {@link #sort(double[], int, int)} method) - * prior to making this call. - * If it is not sorted, the results are undefined. If the range contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. This method considers all NaN values to be - * equivalent and equal. - * - * @param a the array to be searched - * @param fromIndex the index of the first element (inclusive) to be - * searched - * @param toIndex the index of the last element (exclusive) to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array - * within the specified range; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element in the range greater than the key, - * or {@code toIndex} if all - * elements in the range are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws IllegalArgumentException - * if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0 or toIndex > a.length} - * @since 1.6 - */ - public static int binarySearch(double[] a, int fromIndex, int toIndex, - double key) { - rangeCheck(a.length, fromIndex, toIndex); - return binarySearch0(a, fromIndex, toIndex, key); - } - - // Like public version, but without range checks. - private static int binarySearch0(double[] a, int fromIndex, int toIndex, - double key) { - int low = fromIndex; - int high = toIndex - 1; - - while (low <= high) { - int mid = (low + high) >>> 1; - double midVal = a[mid]; - - if (midVal < key) - low = mid + 1; // Neither val is NaN, thisVal is smaller - else if (midVal > key) - high = mid - 1; // Neither val is NaN, thisVal is larger - else { - long midBits = Double.doubleToLongBits(midVal); - long keyBits = Double.doubleToLongBits(key); - if (midBits == keyBits) // Values are equal - return mid; // Key found - else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN) - low = mid + 1; - else // (0.0, -0.0) or (NaN, !NaN) - high = mid - 1; - } - } - return -(low + 1); // key not found. - } - - /** - * Searches the specified array of floats for the specified value using - * the binary search algorithm. The array must be sorted - * (as by the {@link #sort(float[])} method) prior to making this call. If - * it is not sorted, the results are undefined. If the array contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. This method considers all NaN values to be - * equivalent and equal. - * - * @param a the array to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element greater than the key, or {@code a.length} if all - * elements in the array are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - */ - public static int binarySearch(float[] a, float key) { - return binarySearch0(a, 0, a.length, key); - } - - /** - * Searches a range of - * the specified array of floats for the specified value using - * the binary search algorithm. - * The range must be sorted - * (as by the {@link #sort(float[], int, int)} method) - * prior to making this call. If - * it is not sorted, the results are undefined. If the range contains - * multiple elements with the specified value, there is no guarantee which - * one will be found. This method considers all NaN values to be - * equivalent and equal. - * - * @param a the array to be searched - * @param fromIndex the index of the first element (inclusive) to be - * searched - * @param toIndex the index of the last element (exclusive) to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array - * within the specified range; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element in the range greater than the key, - * or {@code toIndex} if all - * elements in the range are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws IllegalArgumentException - * if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0 or toIndex > a.length} - * @since 1.6 - */ - public static int binarySearch(float[] a, int fromIndex, int toIndex, - float key) { - rangeCheck(a.length, fromIndex, toIndex); - return binarySearch0(a, fromIndex, toIndex, key); - } - - // Like public version, but without range checks. - private static int binarySearch0(float[] a, int fromIndex, int toIndex, - float key) { - int low = fromIndex; - int high = toIndex - 1; - - while (low <= high) { - int mid = (low + high) >>> 1; - float midVal = a[mid]; - - if (midVal < key) - low = mid + 1; // Neither val is NaN, thisVal is smaller - else if (midVal > key) - high = mid - 1; // Neither val is NaN, thisVal is larger - else { - int midBits = Float.floatToIntBits(midVal); - int keyBits = Float.floatToIntBits(key); - if (midBits == keyBits) // Values are equal - return mid; // Key found - else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN) - low = mid + 1; - else // (0.0, -0.0) or (NaN, !NaN) - high = mid - 1; - } - } - return -(low + 1); // key not found. - } - - /** - * Searches the specified array for the specified object using the binary - * search algorithm. The array must be sorted into ascending order - * according to the - * {@linkplain Comparable natural ordering} - * of its elements (as by the - * {@link #sort(Object[])} method) prior to making this call. - * If it is not sorted, the results are undefined. - * (If the array contains elements that are not mutually comparable (for - * example, strings and integers), it cannot be sorted according - * to the natural ordering of its elements, hence results are undefined.) - * If the array contains multiple - * elements equal to the specified object, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element greater than the key, or {@code a.length} if all - * elements in the array are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws ClassCastException if the search key is not comparable to the - * elements of the array. - */ - public static int binarySearch(Object[] a, Object key) { - return binarySearch0(a, 0, a.length, key); - } - - /** - * Searches a range of - * the specified array for the specified object using the binary - * search algorithm. - * The range must be sorted into ascending order - * according to the - * {@linkplain Comparable natural ordering} - * of its elements (as by the - * {@link #sort(Object[], int, int)} method) prior to making this - * call. If it is not sorted, the results are undefined. - * (If the range contains elements that are not mutually comparable (for - * example, strings and integers), it cannot be sorted according - * to the natural ordering of its elements, hence results are undefined.) - * If the range contains multiple - * elements equal to the specified object, there is no guarantee which - * one will be found. - * - * @param a the array to be searched - * @param fromIndex the index of the first element (inclusive) to be - * searched - * @param toIndex the index of the last element (exclusive) to be searched - * @param key the value to be searched for - * @return index of the search key, if it is contained in the array - * within the specified range; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element in the range greater than the key, - * or {@code toIndex} if all - * elements in the range are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws ClassCastException if the search key is not comparable to the - * elements of the array within the specified range. - * @throws IllegalArgumentException - * if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0 or toIndex > a.length} - * @since 1.6 - */ - public static int binarySearch(Object[] a, int fromIndex, int toIndex, - Object key) { - rangeCheck(a.length, fromIndex, toIndex); - return binarySearch0(a, fromIndex, toIndex, key); - } - - // Like public version, but without range checks. - private static int binarySearch0(Object[] a, int fromIndex, int toIndex, - Object key) { - int low = fromIndex; - int high = toIndex - 1; - - while (low <= high) { - int mid = (low + high) >>> 1; - @SuppressWarnings("rawtypes") - Comparable midVal = (Comparable)a[mid]; - @SuppressWarnings("unchecked") - int cmp = midVal.compareTo(key); - - if (cmp < 0) - low = mid + 1; - else if (cmp > 0) - high = mid - 1; - else - return mid; // key found - } - return -(low + 1); // key not found. - } - - /** - * Searches the specified array for the specified object using the binary - * search algorithm. The array must be sorted into ascending order - * according to the specified comparator (as by the - * {@link #sort(Object[], Comparator) sort(T[], Comparator)} - * method) prior to making this call. If it is - * not sorted, the results are undefined. - * If the array contains multiple - * elements equal to the specified object, there is no guarantee which one - * will be found. - * - * @param the class of the objects in the array - * @param a the array to be searched - * @param key the value to be searched for - * @param c the comparator by which the array is ordered. A - * {@code null} value indicates that the elements' - * {@linkplain Comparable natural ordering} should be used. - * @return index of the search key, if it is contained in the array; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element greater than the key, or {@code a.length} if all - * elements in the array are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws ClassCastException if the array contains elements that are not - * mutually comparable using the specified comparator, - * or the search key is not comparable to the - * elements of the array using this comparator. - */ - public static int binarySearch(T[] a, T key, Comparator c) { - return binarySearch0(a, 0, a.length, key, c); - } - - /** - * Searches a range of - * the specified array for the specified object using the binary - * search algorithm. - * The range must be sorted into ascending order - * according to the specified comparator (as by the - * {@link #sort(Object[], int, int, Comparator) - * sort(T[], int, int, Comparator)} - * method) prior to making this call. - * If it is not sorted, the results are undefined. - * If the range contains multiple elements equal to the specified object, - * there is no guarantee which one will be found. - * - * @param the class of the objects in the array - * @param a the array to be searched - * @param fromIndex the index of the first element (inclusive) to be - * searched - * @param toIndex the index of the last element (exclusive) to be searched - * @param key the value to be searched for - * @param c the comparator by which the array is ordered. A - * {@code null} value indicates that the elements' - * {@linkplain Comparable natural ordering} should be used. - * @return index of the search key, if it is contained in the array - * within the specified range; - * otherwise, (-(insertion point) - 1). The - * insertion point is defined as the point at which the - * key would be inserted into the array: the index of the first - * element in the range greater than the key, - * or {@code toIndex} if all - * elements in the range are less than the specified key. Note - * that this guarantees that the return value will be >= 0 if - * and only if the key is found. - * @throws ClassCastException if the range contains elements that are not - * mutually comparable using the specified comparator, - * or the search key is not comparable to the - * elements in the range using this comparator. - * @throws IllegalArgumentException - * if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0 or toIndex > a.length} - * @since 1.6 - */ - public static int binarySearch(T[] a, int fromIndex, int toIndex, - T key, Comparator c) { - rangeCheck(a.length, fromIndex, toIndex); - return binarySearch0(a, fromIndex, toIndex, key, c); - } - - // Like public version, but without range checks. - private static int binarySearch0(T[] a, int fromIndex, int toIndex, - T key, Comparator c) { - if (c == null) { - return binarySearch0(a, fromIndex, toIndex, key); - } - int low = fromIndex; - int high = toIndex - 1; - - while (low <= high) { - int mid = (low + high) >>> 1; - T midVal = a[mid]; - int cmp = c.compare(midVal, key); - if (cmp < 0) - low = mid + 1; - else if (cmp > 0) - high = mid - 1; - else - return mid; // key found - } - return -(low + 1); // key not found. - } - - // Equality Testing - - /** - * Returns {@code true} if the two specified arrays of longs are - * equal to one another. Two arrays are considered equal if both - * arrays contain the same number of elements, and all corresponding pairs - * of elements in the two arrays are equal. In other words, two arrays - * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are {@code null}. - * - * @param a one array to be tested for equality - * @param a2 the other array to be tested for equality - * @return {@code true} if the two arrays are equal - */ - public static boolean equals(long[] a, long[] a2) { - if (a==a2) - return true; - if (a==null || a2==null) - return false; - - int length = a.length; - if (a2.length != length) - return false; - - return ArraysSupport.mismatch(a, a2, length) < 0; - } - - /** - * Returns true if the two specified arrays of longs, over the specified - * ranges, are equal to one another. - * - *

Two arrays are considered equal if the number of elements covered by - * each range is the same, and all corresponding pairs of elements over the - * specified ranges in the two arrays are equal. In other words, two arrays - * are equal if they contain, over the specified ranges, the same elements - * in the same order. - * - * @param a the first array to be tested for equality - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested fro equality - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return {@code true} if the two arrays, over the specified ranges, are - * equal - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static boolean equals(long[] a, int aFromIndex, int aToIndex, - long[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - if (aLength != bLength) - return false; - - return ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - aLength) < 0; - } - - /** - * Returns {@code true} if the two specified arrays of ints are - * equal to one another. Two arrays are considered equal if both - * arrays contain the same number of elements, and all corresponding pairs - * of elements in the two arrays are equal. In other words, two arrays - * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are {@code null}. - * - * @param a one array to be tested for equality - * @param a2 the other array to be tested for equality - * @return {@code true} if the two arrays are equal - */ - public static boolean equals(int[] a, int[] a2) { - if (a==a2) - return true; - if (a==null || a2==null) - return false; - - int length = a.length; - if (a2.length != length) - return false; - - return ArraysSupport.mismatch(a, a2, length) < 0; - } - - /** - * Returns true if the two specified arrays of ints, over the specified - * ranges, are equal to one another. - * - *

Two arrays are considered equal if the number of elements covered by - * each range is the same, and all corresponding pairs of elements over the - * specified ranges in the two arrays are equal. In other words, two arrays - * are equal if they contain, over the specified ranges, the same elements - * in the same order. - * - * @param a the first array to be tested for equality - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested fro equality - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return {@code true} if the two arrays, over the specified ranges, are - * equal - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static boolean equals(int[] a, int aFromIndex, int aToIndex, - int[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - if (aLength != bLength) - return false; - - return ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - aLength) < 0; - } - - /** - * Returns {@code true} if the two specified arrays of shorts are - * equal to one another. Two arrays are considered equal if both - * arrays contain the same number of elements, and all corresponding pairs - * of elements in the two arrays are equal. In other words, two arrays - * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are {@code null}. - * - * @param a one array to be tested for equality - * @param a2 the other array to be tested for equality - * @return {@code true} if the two arrays are equal - */ - public static boolean equals(short[] a, short a2[]) { - if (a==a2) - return true; - if (a==null || a2==null) - return false; - - int length = a.length; - if (a2.length != length) - return false; - - return ArraysSupport.mismatch(a, a2, length) < 0; - } - - /** - * Returns true if the two specified arrays of shorts, over the specified - * ranges, are equal to one another. - * - *

Two arrays are considered equal if the number of elements covered by - * each range is the same, and all corresponding pairs of elements over the - * specified ranges in the two arrays are equal. In other words, two arrays - * are equal if they contain, over the specified ranges, the same elements - * in the same order. - * - * @param a the first array to be tested for equality - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested fro equality - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return {@code true} if the two arrays, over the specified ranges, are - * equal - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static boolean equals(short[] a, int aFromIndex, int aToIndex, - short[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - if (aLength != bLength) - return false; - - return ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - aLength) < 0; - } - - /** - * Returns {@code true} if the two specified arrays of chars are - * equal to one another. Two arrays are considered equal if both - * arrays contain the same number of elements, and all corresponding pairs - * of elements in the two arrays are equal. In other words, two arrays - * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are {@code null}. - * - * @param a one array to be tested for equality - * @param a2 the other array to be tested for equality - * @return {@code true} if the two arrays are equal - */ - @HotSpotIntrinsicCandidate - public static boolean equals(char[] a, char[] a2) { - if (a==a2) - return true; - if (a==null || a2==null) - return false; - - int length = a.length; - if (a2.length != length) - return false; - - return ArraysSupport.mismatch(a, a2, length) < 0; - } - - /** - * Returns true if the two specified arrays of chars, over the specified - * ranges, are equal to one another. - * - *

Two arrays are considered equal if the number of elements covered by - * each range is the same, and all corresponding pairs of elements over the - * specified ranges in the two arrays are equal. In other words, two arrays - * are equal if they contain, over the specified ranges, the same elements - * in the same order. - * - * @param a the first array to be tested for equality - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested fro equality - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return {@code true} if the two arrays, over the specified ranges, are - * equal - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static boolean equals(char[] a, int aFromIndex, int aToIndex, - char[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - if (aLength != bLength) - return false; - - return ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - aLength) < 0; - } - - /** - * Returns {@code true} if the two specified arrays of bytes are - * equal to one another. Two arrays are considered equal if both - * arrays contain the same number of elements, and all corresponding pairs - * of elements in the two arrays are equal. In other words, two arrays - * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are {@code null}. - * - * @param a one array to be tested for equality - * @param a2 the other array to be tested for equality - * @return {@code true} if the two arrays are equal - */ - @HotSpotIntrinsicCandidate - public static boolean equals(byte[] a, byte[] a2) { - if (a==a2) - return true; - if (a==null || a2==null) - return false; - - int length = a.length; - if (a2.length != length) - return false; - - return ArraysSupport.mismatch(a, a2, length) < 0; - } - - /** - * Returns true if the two specified arrays of bytes, over the specified - * ranges, are equal to one another. - * - *

Two arrays are considered equal if the number of elements covered by - * each range is the same, and all corresponding pairs of elements over the - * specified ranges in the two arrays are equal. In other words, two arrays - * are equal if they contain, over the specified ranges, the same elements - * in the same order. - * - * @param a the first array to be tested for equality - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested fro equality - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return {@code true} if the two arrays, over the specified ranges, are - * equal - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static boolean equals(byte[] a, int aFromIndex, int aToIndex, - byte[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - if (aLength != bLength) - return false; - - return ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - aLength) < 0; - } - - /** - * Returns {@code true} if the two specified arrays of booleans are - * equal to one another. Two arrays are considered equal if both - * arrays contain the same number of elements, and all corresponding pairs - * of elements in the two arrays are equal. In other words, two arrays - * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are {@code null}. - * - * @param a one array to be tested for equality - * @param a2 the other array to be tested for equality - * @return {@code true} if the two arrays are equal - */ - public static boolean equals(boolean[] a, boolean[] a2) { - if (a==a2) - return true; - if (a==null || a2==null) - return false; - - int length = a.length; - if (a2.length != length) - return false; - - return ArraysSupport.mismatch(a, a2, length) < 0; - } - - /** - * Returns true if the two specified arrays of booleans, over the specified - * ranges, are equal to one another. - * - *

Two arrays are considered equal if the number of elements covered by - * each range is the same, and all corresponding pairs of elements over the - * specified ranges in the two arrays are equal. In other words, two arrays - * are equal if they contain, over the specified ranges, the same elements - * in the same order. - * - * @param a the first array to be tested for equality - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested fro equality - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return {@code true} if the two arrays, over the specified ranges, are - * equal - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static boolean equals(boolean[] a, int aFromIndex, int aToIndex, - boolean[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - if (aLength != bLength) - return false; - - return ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - aLength) < 0; - } - - /** - * Returns {@code true} if the two specified arrays of doubles are - * equal to one another. Two arrays are considered equal if both - * arrays contain the same number of elements, and all corresponding pairs - * of elements in the two arrays are equal. In other words, two arrays - * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are {@code null}. - * - * Two doubles {@code d1} and {@code d2} are considered equal if: - *

    {@code new Double(d1).equals(new Double(d2))}
- * (Unlike the {@code ==} operator, this method considers - * {@code NaN} equals to itself, and 0.0d unequal to -0.0d.) - * - * @param a one array to be tested for equality - * @param a2 the other array to be tested for equality - * @return {@code true} if the two arrays are equal - * @see Double#equals(Object) - */ - public static boolean equals(double[] a, double[] a2) { - if (a==a2) - return true; - if (a==null || a2==null) - return false; - - int length = a.length; - if (a2.length != length) - return false; - - return ArraysSupport.mismatch(a, a2, length) < 0; - } - - /** - * Returns true if the two specified arrays of doubles, over the specified - * ranges, are equal to one another. - * - *

Two arrays are considered equal if the number of elements covered by - * each range is the same, and all corresponding pairs of elements over the - * specified ranges in the two arrays are equal. In other words, two arrays - * are equal if they contain, over the specified ranges, the same elements - * in the same order. - * - *

Two doubles {@code d1} and {@code d2} are considered equal if: - *

    {@code new Double(d1).equals(new Double(d2))}
- * (Unlike the {@code ==} operator, this method considers - * {@code NaN} equals to itself, and 0.0d unequal to -0.0d.) - * - * @param a the first array to be tested for equality - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested fro equality - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return {@code true} if the two arrays, over the specified ranges, are - * equal - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @see Double#equals(Object) - * @since 9 - */ - public static boolean equals(double[] a, int aFromIndex, int aToIndex, - double[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - if (aLength != bLength) - return false; - - return ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, aLength) < 0; - } - - /** - * Returns {@code true} if the two specified arrays of floats are - * equal to one another. Two arrays are considered equal if both - * arrays contain the same number of elements, and all corresponding pairs - * of elements in the two arrays are equal. In other words, two arrays - * are equal if they contain the same elements in the same order. Also, - * two array references are considered equal if both are {@code null}. - * - * Two floats {@code f1} and {@code f2} are considered equal if: - *
    {@code new Float(f1).equals(new Float(f2))}
- * (Unlike the {@code ==} operator, this method considers - * {@code NaN} equals to itself, and 0.0f unequal to -0.0f.) - * - * @param a one array to be tested for equality - * @param a2 the other array to be tested for equality - * @return {@code true} if the two arrays are equal - * @see Float#equals(Object) - */ - public static boolean equals(float[] a, float[] a2) { - if (a==a2) - return true; - if (a==null || a2==null) - return false; - - int length = a.length; - if (a2.length != length) - return false; - - return ArraysSupport.mismatch(a, a2, length) < 0; - } - - /** - * Returns true if the two specified arrays of floats, over the specified - * ranges, are equal to one another. - * - *

Two arrays are considered equal if the number of elements covered by - * each range is the same, and all corresponding pairs of elements over the - * specified ranges in the two arrays are equal. In other words, two arrays - * are equal if they contain, over the specified ranges, the same elements - * in the same order. - * - *

Two floats {@code f1} and {@code f2} are considered equal if: - *

    {@code new Float(f1).equals(new Float(f2))}
- * (Unlike the {@code ==} operator, this method considers - * {@code NaN} equals to itself, and 0.0f unequal to -0.0f.) - * - * @param a the first array to be tested for equality - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested fro equality - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return {@code true} if the two arrays, over the specified ranges, are - * equal - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @see Float#equals(Object) - * @since 9 - */ - public static boolean equals(float[] a, int aFromIndex, int aToIndex, - float[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - if (aLength != bLength) - return false; - - return ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, aLength) < 0; - } - - /** - * Returns {@code true} if the two specified arrays of Objects are - * equal to one another. The two arrays are considered equal if - * both arrays contain the same number of elements, and all corresponding - * pairs of elements in the two arrays are equal. Two objects {@code e1} - * and {@code e2} are considered equal if - * {@code Objects.equals(e1, e2)}. - * In other words, the two arrays are equal if - * they contain the same elements in the same order. Also, two array - * references are considered equal if both are {@code null}. - * - * @param a one array to be tested for equality - * @param a2 the other array to be tested for equality - * @return {@code true} if the two arrays are equal - */ - public static boolean equals(Object[] a, Object[] a2) { - if (a==a2) - return true; - if (a==null || a2==null) - return false; - - int length = a.length; - if (a2.length != length) - return false; - - for (int i=0; iequal to one another. - * - *

Two arrays are considered equal if the number of elements covered by - * each range is the same, and all corresponding pairs of elements over the - * specified ranges in the two arrays are equal. In other words, two arrays - * are equal if they contain, over the specified ranges, the same elements - * in the same order. - * - *

Two objects {@code e1} and {@code e2} are considered equal if - * {@code Objects.equals(e1, e2)}. - * - * @param a the first array to be tested for equality - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested fro equality - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return {@code true} if the two arrays, over the specified ranges, are - * equal - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static boolean equals(Object[] a, int aFromIndex, int aToIndex, - Object[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - if (aLength != bLength) - return false; - - for (int i = 0; i < aLength; i++) { - if (!Objects.equals(a[aFromIndex++], b[bFromIndex++])) - return false; - } - - return true; - } - - /** - * Returns {@code true} if the two specified arrays of Objects are - * equal to one another. - * - *

Two arrays are considered equal if both arrays contain the same number - * of elements, and all corresponding pairs of elements in the two arrays - * are equal. In other words, the two arrays are equal if they contain the - * same elements in the same order. Also, two array references are - * considered equal if both are {@code null}. - * - *

Two objects {@code e1} and {@code e2} are considered equal if, - * given the specified comparator, {@code cmp.compare(e1, e2) == 0}. - * - * @param a one array to be tested for equality - * @param a2 the other array to be tested for equality - * @param cmp the comparator to compare array elements - * @param the type of array elements - * @return {@code true} if the two arrays are equal - * @throws NullPointerException if the comparator is {@code null} - * @since 9 - */ - public static boolean equals(T[] a, T[] a2, Comparator cmp) { - Objects.requireNonNull(cmp); - if (a==a2) - return true; - if (a==null || a2==null) - return false; - - int length = a.length; - if (a2.length != length) - return false; - - for (int i=0; iequal to one another. - * - *

Two arrays are considered equal if the number of elements covered by - * each range is the same, and all corresponding pairs of elements over the - * specified ranges in the two arrays are equal. In other words, two arrays - * are equal if they contain, over the specified ranges, the same elements - * in the same order. - * - *

Two objects {@code e1} and {@code e2} are considered equal if, - * given the specified comparator, {@code cmp.compare(e1, e2) == 0}. - * - * @param a the first array to be tested for equality - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested fro equality - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @param cmp the comparator to compare array elements - * @param the type of array elements - * @return {@code true} if the two arrays, over the specified ranges, are - * equal - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array or the comparator is {@code null} - * @since 9 - */ - public static boolean equals(T[] a, int aFromIndex, int aToIndex, - T[] b, int bFromIndex, int bToIndex, - Comparator cmp) { - Objects.requireNonNull(cmp); - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - if (aLength != bLength) - return false; - - for (int i = 0; i < aLength; i++) { - if (cmp.compare(a[aFromIndex++], b[bFromIndex++]) != 0) - return false; - } - - return true; - } - - // Filling - - /** - * Assigns the specified long value to each element of the specified array - * of longs. - * - * @param a the array to be filled - * @param val the value to be stored in all elements of the array - */ - public static void fill(long[] a, long val) { - for (int i = 0, len = a.length; i < len; i++) - a[i] = val; - } - - /** - * Assigns the specified long value to each element of the specified - * range of the specified array of longs. The range to be filled - * extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be filled is empty.) - * - * @param a the array to be filled - * @param fromIndex the index of the first element (inclusive) to be - * filled with the specified value - * @param toIndex the index of the last element (exclusive) to be - * filled with the specified value - * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - */ - public static void fill(long[] a, int fromIndex, int toIndex, long val) { - rangeCheck(a.length, fromIndex, toIndex); - for (int i = fromIndex; i < toIndex; i++) - a[i] = val; - } - - /** - * Assigns the specified int value to each element of the specified array - * of ints. - * - * @param a the array to be filled - * @param val the value to be stored in all elements of the array - */ - public static void fill(int[] a, int val) { - for (int i = 0, len = a.length; i < len; i++) - a[i] = val; - } - - /** - * Assigns the specified int value to each element of the specified - * range of the specified array of ints. The range to be filled - * extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be filled is empty.) - * - * @param a the array to be filled - * @param fromIndex the index of the first element (inclusive) to be - * filled with the specified value - * @param toIndex the index of the last element (exclusive) to be - * filled with the specified value - * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - */ - public static void fill(int[] a, int fromIndex, int toIndex, int val) { - rangeCheck(a.length, fromIndex, toIndex); - for (int i = fromIndex; i < toIndex; i++) - a[i] = val; - } - - /** - * Assigns the specified short value to each element of the specified array - * of shorts. - * - * @param a the array to be filled - * @param val the value to be stored in all elements of the array - */ - public static void fill(short[] a, short val) { - for (int i = 0, len = a.length; i < len; i++) - a[i] = val; - } - - /** - * Assigns the specified short value to each element of the specified - * range of the specified array of shorts. The range to be filled - * extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be filled is empty.) - * - * @param a the array to be filled - * @param fromIndex the index of the first element (inclusive) to be - * filled with the specified value - * @param toIndex the index of the last element (exclusive) to be - * filled with the specified value - * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - */ - public static void fill(short[] a, int fromIndex, int toIndex, short val) { - rangeCheck(a.length, fromIndex, toIndex); - for (int i = fromIndex; i < toIndex; i++) - a[i] = val; - } - - /** - * Assigns the specified char value to each element of the specified array - * of chars. - * - * @param a the array to be filled - * @param val the value to be stored in all elements of the array - */ - public static void fill(char[] a, char val) { - for (int i = 0, len = a.length; i < len; i++) - a[i] = val; - } - - /** - * Assigns the specified char value to each element of the specified - * range of the specified array of chars. The range to be filled - * extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be filled is empty.) - * - * @param a the array to be filled - * @param fromIndex the index of the first element (inclusive) to be - * filled with the specified value - * @param toIndex the index of the last element (exclusive) to be - * filled with the specified value - * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - */ - public static void fill(char[] a, int fromIndex, int toIndex, char val) { - rangeCheck(a.length, fromIndex, toIndex); - for (int i = fromIndex; i < toIndex; i++) - a[i] = val; - } - - /** - * Assigns the specified byte value to each element of the specified array - * of bytes. - * - * @param a the array to be filled - * @param val the value to be stored in all elements of the array - */ - public static void fill(byte[] a, byte val) { - for (int i = 0, len = a.length; i < len; i++) - a[i] = val; - } - - /** - * Assigns the specified byte value to each element of the specified - * range of the specified array of bytes. The range to be filled - * extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be filled is empty.) - * - * @param a the array to be filled - * @param fromIndex the index of the first element (inclusive) to be - * filled with the specified value - * @param toIndex the index of the last element (exclusive) to be - * filled with the specified value - * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - */ - public static void fill(byte[] a, int fromIndex, int toIndex, byte val) { - rangeCheck(a.length, fromIndex, toIndex); - for (int i = fromIndex; i < toIndex; i++) - a[i] = val; - } - - /** - * Assigns the specified boolean value to each element of the specified - * array of booleans. - * - * @param a the array to be filled - * @param val the value to be stored in all elements of the array - */ - public static void fill(boolean[] a, boolean val) { - for (int i = 0, len = a.length; i < len; i++) - a[i] = val; - } - - /** - * Assigns the specified boolean value to each element of the specified - * range of the specified array of booleans. The range to be filled - * extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be filled is empty.) - * - * @param a the array to be filled - * @param fromIndex the index of the first element (inclusive) to be - * filled with the specified value - * @param toIndex the index of the last element (exclusive) to be - * filled with the specified value - * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - */ - public static void fill(boolean[] a, int fromIndex, int toIndex, - boolean val) { - rangeCheck(a.length, fromIndex, toIndex); - for (int i = fromIndex; i < toIndex; i++) - a[i] = val; - } - - /** - * Assigns the specified double value to each element of the specified - * array of doubles. - * - * @param a the array to be filled - * @param val the value to be stored in all elements of the array - */ - public static void fill(double[] a, double val) { - for (int i = 0, len = a.length; i < len; i++) - a[i] = val; - } - - /** - * Assigns the specified double value to each element of the specified - * range of the specified array of doubles. The range to be filled - * extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be filled is empty.) - * - * @param a the array to be filled - * @param fromIndex the index of the first element (inclusive) to be - * filled with the specified value - * @param toIndex the index of the last element (exclusive) to be - * filled with the specified value - * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - */ - public static void fill(double[] a, int fromIndex, int toIndex,double val){ - rangeCheck(a.length, fromIndex, toIndex); - for (int i = fromIndex; i < toIndex; i++) - a[i] = val; - } - - /** - * Assigns the specified float value to each element of the specified array - * of floats. - * - * @param a the array to be filled - * @param val the value to be stored in all elements of the array - */ - public static void fill(float[] a, float val) { - for (int i = 0, len = a.length; i < len; i++) - a[i] = val; - } - - /** - * Assigns the specified float value to each element of the specified - * range of the specified array of floats. The range to be filled - * extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be filled is empty.) - * - * @param a the array to be filled - * @param fromIndex the index of the first element (inclusive) to be - * filled with the specified value - * @param toIndex the index of the last element (exclusive) to be - * filled with the specified value - * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - */ - public static void fill(float[] a, int fromIndex, int toIndex, float val) { - rangeCheck(a.length, fromIndex, toIndex); - for (int i = fromIndex; i < toIndex; i++) - a[i] = val; - } - - /** - * Assigns the specified Object reference to each element of the specified - * array of Objects. - * - * @param a the array to be filled - * @param val the value to be stored in all elements of the array - * @throws ArrayStoreException if the specified value is not of a - * runtime type that can be stored in the specified array - */ - public static void fill(Object[] a, Object val) { - for (int i = 0, len = a.length; i < len; i++) - a[i] = val; - } - - /** - * Assigns the specified Object reference to each element of the specified - * range of the specified array of Objects. The range to be filled - * extends from index {@code fromIndex}, inclusive, to index - * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the - * range to be filled is empty.) - * - * @param a the array to be filled - * @param fromIndex the index of the first element (inclusive) to be - * filled with the specified value - * @param toIndex the index of the last element (exclusive) to be - * filled with the specified value - * @param val the value to be stored in all elements of the array - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or - * {@code toIndex > a.length} - * @throws ArrayStoreException if the specified value is not of a - * runtime type that can be stored in the specified array - */ - public static void fill(Object[] a, int fromIndex, int toIndex, Object val) { - rangeCheck(a.length, fromIndex, toIndex); - for (int i = fromIndex; i < toIndex; i++) - a[i] = val; - } - - // Cloning - - /** - * Copies the specified array, truncating or padding with nulls (if necessary) - * so the copy has the specified length. For all indices that are - * valid in both the original array and the copy, the two arrays will - * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain {@code null}. - * Such indices will exist if and only if the specified length - * is greater than that of the original array. - * The resulting array is of exactly the same class as the original array. - * - * @param the class of the objects in the array - * @param original the array to be copied - * @param newLength the length of the copy to be returned - * @return a copy of the original array, truncated or padded with nulls - * to obtain the specified length - * @throws NegativeArraySizeException if {@code newLength} is negative - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - @SuppressWarnings("unchecked") - public static T[] copyOf(T[] original, int newLength) { - return (T[]) copyOf(original, newLength, original.getClass()); - } - - /** - * Copies the specified array, truncating or padding with nulls (if necessary) - * so the copy has the specified length. For all indices that are - * valid in both the original array and the copy, the two arrays will - * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain {@code null}. - * Such indices will exist if and only if the specified length - * is greater than that of the original array. - * The resulting array is of the class {@code newType}. - * - * @param the class of the objects in the original array - * @param the class of the objects in the returned array - * @param original the array to be copied - * @param newLength the length of the copy to be returned - * @param newType the class of the copy to be returned - * @return a copy of the original array, truncated or padded with nulls - * to obtain the specified length - * @throws NegativeArraySizeException if {@code newLength} is negative - * @throws NullPointerException if {@code original} is null - * @throws ArrayStoreException if an element copied from - * {@code original} is not of a runtime type that can be stored in - * an array of class {@code newType} - * @since 1.6 - */ - @HotSpotIntrinsicCandidate - public static T[] copyOf(U[] original, int newLength, Class newType) { - @SuppressWarnings("unchecked") - T[] copy = ((Object)newType == (Object)Object[].class) - ? (T[]) new Object[newLength] - : (T[]) Array.newInstance(newType.getComponentType(), newLength); - System.arraycopy(original, 0, copy, 0, - Math.min(original.length, newLength)); - return copy; - } - - /** - * Copies the specified array, truncating or padding with zeros (if necessary) - * so the copy has the specified length. For all indices that are - * valid in both the original array and the copy, the two arrays will - * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain {@code (byte)0}. - * Such indices will exist if and only if the specified length - * is greater than that of the original array. - * - * @param original the array to be copied - * @param newLength the length of the copy to be returned - * @return a copy of the original array, truncated or padded with zeros - * to obtain the specified length - * @throws NegativeArraySizeException if {@code newLength} is negative - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static byte[] copyOf(byte[] original, int newLength) { - byte[] copy = new byte[newLength]; - System.arraycopy(original, 0, copy, 0, - Math.min(original.length, newLength)); - return copy; - } - - /** - * Copies the specified array, truncating or padding with zeros (if necessary) - * so the copy has the specified length. For all indices that are - * valid in both the original array and the copy, the two arrays will - * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain {@code (short)0}. - * Such indices will exist if and only if the specified length - * is greater than that of the original array. - * - * @param original the array to be copied - * @param newLength the length of the copy to be returned - * @return a copy of the original array, truncated or padded with zeros - * to obtain the specified length - * @throws NegativeArraySizeException if {@code newLength} is negative - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static short[] copyOf(short[] original, int newLength) { - short[] copy = new short[newLength]; - System.arraycopy(original, 0, copy, 0, - Math.min(original.length, newLength)); - return copy; - } - - /** - * Copies the specified array, truncating or padding with zeros (if necessary) - * so the copy has the specified length. For all indices that are - * valid in both the original array and the copy, the two arrays will - * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain {@code 0}. - * Such indices will exist if and only if the specified length - * is greater than that of the original array. - * - * @param original the array to be copied - * @param newLength the length of the copy to be returned - * @return a copy of the original array, truncated or padded with zeros - * to obtain the specified length - * @throws NegativeArraySizeException if {@code newLength} is negative - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static int[] copyOf(int[] original, int newLength) { - int[] copy = new int[newLength]; - System.arraycopy(original, 0, copy, 0, - Math.min(original.length, newLength)); - return copy; - } - - /** - * Copies the specified array, truncating or padding with zeros (if necessary) - * so the copy has the specified length. For all indices that are - * valid in both the original array and the copy, the two arrays will - * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain {@code 0L}. - * Such indices will exist if and only if the specified length - * is greater than that of the original array. - * - * @param original the array to be copied - * @param newLength the length of the copy to be returned - * @return a copy of the original array, truncated or padded with zeros - * to obtain the specified length - * @throws NegativeArraySizeException if {@code newLength} is negative - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static long[] copyOf(long[] original, int newLength) { - long[] copy = new long[newLength]; - System.arraycopy(original, 0, copy, 0, - Math.min(original.length, newLength)); - return copy; - } - - /** - * Copies the specified array, truncating or padding with null characters (if necessary) - * so the copy has the specified length. For all indices that are valid - * in both the original array and the copy, the two arrays will contain - * identical values. For any indices that are valid in the copy but not - * the original, the copy will contain {@code '\\u000'}. Such indices - * will exist if and only if the specified length is greater than that of - * the original array. - * - * @param original the array to be copied - * @param newLength the length of the copy to be returned - * @return a copy of the original array, truncated or padded with null characters - * to obtain the specified length - * @throws NegativeArraySizeException if {@code newLength} is negative - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static char[] copyOf(char[] original, int newLength) { - char[] copy = new char[newLength]; - System.arraycopy(original, 0, copy, 0, - Math.min(original.length, newLength)); - return copy; - } - - /** - * Copies the specified array, truncating or padding with zeros (if necessary) - * so the copy has the specified length. For all indices that are - * valid in both the original array and the copy, the two arrays will - * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain {@code 0f}. - * Such indices will exist if and only if the specified length - * is greater than that of the original array. - * - * @param original the array to be copied - * @param newLength the length of the copy to be returned - * @return a copy of the original array, truncated or padded with zeros - * to obtain the specified length - * @throws NegativeArraySizeException if {@code newLength} is negative - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static float[] copyOf(float[] original, int newLength) { - float[] copy = new float[newLength]; - System.arraycopy(original, 0, copy, 0, - Math.min(original.length, newLength)); - return copy; - } - - /** - * Copies the specified array, truncating or padding with zeros (if necessary) - * so the copy has the specified length. For all indices that are - * valid in both the original array and the copy, the two arrays will - * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain {@code 0d}. - * Such indices will exist if and only if the specified length - * is greater than that of the original array. - * - * @param original the array to be copied - * @param newLength the length of the copy to be returned - * @return a copy of the original array, truncated or padded with zeros - * to obtain the specified length - * @throws NegativeArraySizeException if {@code newLength} is negative - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static double[] copyOf(double[] original, int newLength) { - double[] copy = new double[newLength]; - System.arraycopy(original, 0, copy, 0, - Math.min(original.length, newLength)); - return copy; - } - - /** - * Copies the specified array, truncating or padding with {@code false} (if necessary) - * so the copy has the specified length. For all indices that are - * valid in both the original array and the copy, the two arrays will - * contain identical values. For any indices that are valid in the - * copy but not the original, the copy will contain {@code false}. - * Such indices will exist if and only if the specified length - * is greater than that of the original array. - * - * @param original the array to be copied - * @param newLength the length of the copy to be returned - * @return a copy of the original array, truncated or padded with false elements - * to obtain the specified length - * @throws NegativeArraySizeException if {@code newLength} is negative - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static boolean[] copyOf(boolean[] original, int newLength) { - boolean[] copy = new boolean[newLength]; - System.arraycopy(original, 0, copy, 0, - Math.min(original.length, newLength)); - return copy; - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code null} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - *

- * The resulting array is of exactly the same class as the original array. - * - * @param the class of the objects in the array - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with nulls to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - @SuppressWarnings("unchecked") - public static T[] copyOfRange(T[] original, int from, int to) { - return copyOfRange(original, from, to, (Class) original.getClass()); - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code null} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - * The resulting array is of the class {@code newType}. - * - * @param the class of the objects in the original array - * @param the class of the objects in the returned array - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @param newType the class of the copy to be returned - * @return a new array containing the specified range from the original array, - * truncated or padded with nulls to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @throws ArrayStoreException if an element copied from - * {@code original} is not of a runtime type that can be stored in - * an array of class {@code newType}. - * @since 1.6 - */ - @HotSpotIntrinsicCandidate - public static T[] copyOfRange(U[] original, int from, int to, Class newType) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - @SuppressWarnings("unchecked") - T[] copy = ((Object)newType == (Object)Object[].class) - ? (T[]) new Object[newLength] - : (T[]) Array.newInstance(newType.getComponentType(), newLength); - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code (byte)0} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - * - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with zeros to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static byte[] copyOfRange(byte[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - byte[] copy = new byte[newLength]; - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code (short)0} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - * - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with zeros to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static short[] copyOfRange(short[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - short[] copy = new short[newLength]; - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code 0} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - * - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with zeros to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static int[] copyOfRange(int[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - int[] copy = new int[newLength]; - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code 0L} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - * - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with zeros to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static long[] copyOfRange(long[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - long[] copy = new long[newLength]; - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code '\\u000'} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - * - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with null characters to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static char[] copyOfRange(char[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - char[] copy = new char[newLength]; - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code 0f} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - * - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with zeros to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static float[] copyOfRange(float[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - float[] copy = new float[newLength]; - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code 0d} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - * - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with zeros to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static double[] copyOfRange(double[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - double[] copy = new double[newLength]; - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - - /** - * Copies the specified range of the specified array into a new array. - * The initial index of the range ({@code from}) must lie between zero - * and {@code original.length}, inclusive. The value at - * {@code original[from]} is placed into the initial element of the copy - * (unless {@code from == original.length} or {@code from == to}). - * Values from subsequent elements in the original array are placed into - * subsequent elements in the copy. The final index of the range - * ({@code to}), which must be greater than or equal to {@code from}, - * may be greater than {@code original.length}, in which case - * {@code false} is placed in all elements of the copy whose index is - * greater than or equal to {@code original.length - from}. The length - * of the returned array will be {@code to - from}. - * - * @param original the array from which a range is to be copied - * @param from the initial index of the range to be copied, inclusive - * @param to the final index of the range to be copied, exclusive. - * (This index may lie outside the array.) - * @return a new array containing the specified range from the original array, - * truncated or padded with false elements to obtain the required length - * @throws ArrayIndexOutOfBoundsException if {@code from < 0} - * or {@code from > original.length} - * @throws IllegalArgumentException if {@code from > to} - * @throws NullPointerException if {@code original} is null - * @since 1.6 - */ - public static boolean[] copyOfRange(boolean[] original, int from, int to) { - int newLength = to - from; - if (newLength < 0) - throw new IllegalArgumentException(from + " > " + to); - boolean[] copy = new boolean[newLength]; - System.arraycopy(original, from, copy, 0, - Math.min(original.length - from, newLength)); - return copy; - } - - // Misc - - /** - * Returns a fixed-size list backed by the specified array. Changes made to - * the array will be visible in the returned list, and changes made to the - * list will be visible in the array. The returned list is - * {@link Serializable} and implements {@link RandomAccess}. - * - *

The returned list implements the optional {@code Collection} methods, except - * those that would change the size of the returned list. Those methods leave - * the list unchanged and throw {@link UnsupportedOperationException}. - * - * @apiNote - * This method acts as bridge between array-based and collection-based - * APIs, in combination with {@link Collection#toArray}. - * - *

This method provides a way to wrap an existing array: - *

{@code
-     *     Integer[] numbers = ...
-     *     ...
-     *     List values = Arrays.asList(numbers);
-     * }
- * - *

This method also provides a convenient way to create a fixed-size - * list initialized to contain several elements: - *

{@code
-     *     List stooges = Arrays.asList("Larry", "Moe", "Curly");
-     * }
- * - *

The list returned by this method is modifiable. - * To create an unmodifiable list, use - * {@link Collections#unmodifiableList Collections.unmodifiableList} - * or Unmodifiable Lists. - * - * @param the class of the objects in the array - * @param a the array by which the list will be backed - * @return a list view of the specified array - * @throws NullPointerException if the specified array is {@code null} - */ - @SafeVarargs - @SuppressWarnings("varargs") - public static List asList(T... a) { - return new ArrayList<>(a); - } - - /** - * @serial include - */ - private static class ArrayList extends AbstractList - implements RandomAccess, java.io.Serializable - { - private static final long serialVersionUID = -2764017481108945198L; - private final E[] a; - - ArrayList(E[] array) { - a = Objects.requireNonNull(array); - } - - @Override - public int size() { - return a.length; - } - - @Override - public Object[] toArray() { - return Arrays.copyOf(a, a.length, Object[].class); - } - - @Override - @SuppressWarnings("unchecked") - public T[] toArray(T[] a) { - int size = size(); - if (a.length < size) - return Arrays.copyOf(this.a, size, - (Class) a.getClass()); - System.arraycopy(this.a, 0, a, 0, size); - if (a.length > size) - a[size] = null; - return a; - } - - @Override - public E get(int index) { - return a[index]; - } - - @Override - public E set(int index, E element) { - E oldValue = a[index]; - a[index] = element; - return oldValue; - } - - @Override - public int indexOf(Object o) { - E[] a = this.a; - if (o == null) { - for (int i = 0; i < a.length; i++) - if (a[i] == null) - return i; - } else { - for (int i = 0; i < a.length; i++) - if (o.equals(a[i])) - return i; - } - return -1; - } - - @Override - public boolean contains(Object o) { - return indexOf(o) >= 0; - } - - @Override - public Spliterator spliterator() { - return Spliterators.spliterator(a, Spliterator.ORDERED); - } - - @Override - public void forEach(Consumer action) { - Objects.requireNonNull(action); - for (E e : a) { - action.accept(e); - } - } - - @Override - public void replaceAll(UnaryOperator operator) { - Objects.requireNonNull(operator); - E[] a = this.a; - for (int i = 0; i < a.length; i++) { - a[i] = operator.apply(a[i]); - } - } - - @Override - public void sort(Comparator c) { - Arrays.sort(a, c); - } - - @Override - public Iterator iterator() { - return new ArrayItr<>(a); - } - } - - private static class ArrayItr implements Iterator { - private int cursor; - private final E[] a; - - ArrayItr(E[] a) { - this.a = a; - } - - @Override - public boolean hasNext() { - return cursor < a.length; - } - - @Override - public E next() { - int i = cursor; - if (i >= a.length) { - throw new NoSuchElementException(); - } - cursor = i + 1; - return a[i]; - } - } - - /** - * Returns a hash code based on the contents of the specified array. - * For any two {@code long} arrays {@code a} and {@code b} - * such that {@code Arrays.equals(a, b)}, it is also the case that - * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. - * - *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} - * method on a {@link List} containing a sequence of {@link Long} - * instances representing the elements of {@code a} in the same order. - * If {@code a} is {@code null}, this method returns 0. - * - * @param a the array whose hash value to compute - * @return a content-based hash code for {@code a} - * @since 1.5 - */ - public static int hashCode(long a[]) { - if (a == null) - return 0; - - int result = 1; - for (long element : a) { - int elementHash = (int)(element ^ (element >>> 32)); - result = 31 * result + elementHash; - } - - return result; - } - - /** - * Returns a hash code based on the contents of the specified array. - * For any two non-null {@code int} arrays {@code a} and {@code b} - * such that {@code Arrays.equals(a, b)}, it is also the case that - * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. - * - *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} - * method on a {@link List} containing a sequence of {@link Integer} - * instances representing the elements of {@code a} in the same order. - * If {@code a} is {@code null}, this method returns 0. - * - * @param a the array whose hash value to compute - * @return a content-based hash code for {@code a} - * @since 1.5 - */ - public static int hashCode(int a[]) { - if (a == null) - return 0; - - int result = 1; - for (int element : a) - result = 31 * result + element; - - return result; - } - - /** - * Returns a hash code based on the contents of the specified array. - * For any two {@code short} arrays {@code a} and {@code b} - * such that {@code Arrays.equals(a, b)}, it is also the case that - * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. - * - *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} - * method on a {@link List} containing a sequence of {@link Short} - * instances representing the elements of {@code a} in the same order. - * If {@code a} is {@code null}, this method returns 0. - * - * @param a the array whose hash value to compute - * @return a content-based hash code for {@code a} - * @since 1.5 - */ - public static int hashCode(short a[]) { - if (a == null) - return 0; - - int result = 1; - for (short element : a) - result = 31 * result + element; - - return result; - } - - /** - * Returns a hash code based on the contents of the specified array. - * For any two {@code char} arrays {@code a} and {@code b} - * such that {@code Arrays.equals(a, b)}, it is also the case that - * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. - * - *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} - * method on a {@link List} containing a sequence of {@link Character} - * instances representing the elements of {@code a} in the same order. - * If {@code a} is {@code null}, this method returns 0. - * - * @param a the array whose hash value to compute - * @return a content-based hash code for {@code a} - * @since 1.5 - */ - public static int hashCode(char a[]) { - if (a == null) - return 0; - - int result = 1; - for (char element : a) - result = 31 * result + element; - - return result; - } - - /** - * Returns a hash code based on the contents of the specified array. - * For any two {@code byte} arrays {@code a} and {@code b} - * such that {@code Arrays.equals(a, b)}, it is also the case that - * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. - * - *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} - * method on a {@link List} containing a sequence of {@link Byte} - * instances representing the elements of {@code a} in the same order. - * If {@code a} is {@code null}, this method returns 0. - * - * @param a the array whose hash value to compute - * @return a content-based hash code for {@code a} - * @since 1.5 - */ - public static int hashCode(byte a[]) { - if (a == null) - return 0; - - int result = 1; - for (byte element : a) - result = 31 * result + element; - - return result; - } - - /** - * Returns a hash code based on the contents of the specified array. - * For any two {@code boolean} arrays {@code a} and {@code b} - * such that {@code Arrays.equals(a, b)}, it is also the case that - * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. - * - *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} - * method on a {@link List} containing a sequence of {@link Boolean} - * instances representing the elements of {@code a} in the same order. - * If {@code a} is {@code null}, this method returns 0. - * - * @param a the array whose hash value to compute - * @return a content-based hash code for {@code a} - * @since 1.5 - */ - public static int hashCode(boolean a[]) { - if (a == null) - return 0; - - int result = 1; - for (boolean element : a) - result = 31 * result + (element ? 1231 : 1237); - - return result; - } - - /** - * Returns a hash code based on the contents of the specified array. - * For any two {@code float} arrays {@code a} and {@code b} - * such that {@code Arrays.equals(a, b)}, it is also the case that - * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. - * - *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} - * method on a {@link List} containing a sequence of {@link Float} - * instances representing the elements of {@code a} in the same order. - * If {@code a} is {@code null}, this method returns 0. - * - * @param a the array whose hash value to compute - * @return a content-based hash code for {@code a} - * @since 1.5 - */ - public static int hashCode(float a[]) { - if (a == null) - return 0; - - int result = 1; - for (float element : a) - result = 31 * result + Float.floatToIntBits(element); - - return result; - } - - /** - * Returns a hash code based on the contents of the specified array. - * For any two {@code double} arrays {@code a} and {@code b} - * such that {@code Arrays.equals(a, b)}, it is also the case that - * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. - * - *

The value returned by this method is the same value that would be - * obtained by invoking the {@link List#hashCode() hashCode} - * method on a {@link List} containing a sequence of {@link Double} - * instances representing the elements of {@code a} in the same order. - * If {@code a} is {@code null}, this method returns 0. - * - * @param a the array whose hash value to compute - * @return a content-based hash code for {@code a} - * @since 1.5 - */ - public static int hashCode(double a[]) { - if (a == null) - return 0; - - int result = 1; - for (double element : a) { - long bits = Double.doubleToLongBits(element); - result = 31 * result + (int)(bits ^ (bits >>> 32)); - } - return result; - } - - /** - * Returns a hash code based on the contents of the specified array. If - * the array contains other arrays as elements, the hash code is based on - * their identities rather than their contents. It is therefore - * acceptable to invoke this method on an array that contains itself as an - * element, either directly or indirectly through one or more levels of - * arrays. - * - *

For any two arrays {@code a} and {@code b} such that - * {@code Arrays.equals(a, b)}, it is also the case that - * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. - * - *

The value returned by this method is equal to the value that would - * be returned by {@code Arrays.asList(a).hashCode()}, unless {@code a} - * is {@code null}, in which case {@code 0} is returned. - * - * @param a the array whose content-based hash code to compute - * @return a content-based hash code for {@code a} - * @see #deepHashCode(Object[]) - * @since 1.5 - */ - public static int hashCode(Object a[]) { - if (a == null) - return 0; - - int result = 1; - - for (Object element : a) - result = 31 * result + (element == null ? 0 : element.hashCode()); - - return result; - } - - /** - * Returns a hash code based on the "deep contents" of the specified - * array. If the array contains other arrays as elements, the - * hash code is based on their contents and so on, ad infinitum. - * It is therefore unacceptable to invoke this method on an array that - * contains itself as an element, either directly or indirectly through - * one or more levels of arrays. The behavior of such an invocation is - * undefined. - * - *

For any two arrays {@code a} and {@code b} such that - * {@code Arrays.deepEquals(a, b)}, it is also the case that - * {@code Arrays.deepHashCode(a) == Arrays.deepHashCode(b)}. - * - *

The computation of the value returned by this method is similar to - * that of the value returned by {@link List#hashCode()} on a list - * containing the same elements as {@code a} in the same order, with one - * difference: If an element {@code e} of {@code a} is itself an array, - * its hash code is computed not by calling {@code e.hashCode()}, but as - * by calling the appropriate overloading of {@code Arrays.hashCode(e)} - * if {@code e} is an array of a primitive type, or as by calling - * {@code Arrays.deepHashCode(e)} recursively if {@code e} is an array - * of a reference type. If {@code a} is {@code null}, this method - * returns 0. - * - * @param a the array whose deep-content-based hash code to compute - * @return a deep-content-based hash code for {@code a} - * @see #hashCode(Object[]) - * @since 1.5 - */ - public static int deepHashCode(Object a[]) { - if (a == null) - return 0; - - int result = 1; - - for (Object element : a) { - final int elementHash; - final Class cl; - if (element == null) - elementHash = 0; - else if ((cl = element.getClass().getComponentType()) == null) - elementHash = element.hashCode(); - else if (element instanceof Object[]) - elementHash = deepHashCode((Object[]) element); - else - elementHash = primitiveArrayHashCode(element, cl); - - result = 31 * result + elementHash; - } - - return result; - } - - private static int primitiveArrayHashCode(Object a, Class cl) { - return - (cl == byte.class) ? hashCode((byte[]) a) : - (cl == int.class) ? hashCode((int[]) a) : - (cl == long.class) ? hashCode((long[]) a) : - (cl == char.class) ? hashCode((char[]) a) : - (cl == short.class) ? hashCode((short[]) a) : - (cl == boolean.class) ? hashCode((boolean[]) a) : - (cl == double.class) ? hashCode((double[]) a) : - // If new primitive types are ever added, this method must be - // expanded or we will fail here with ClassCastException. - hashCode((float[]) a); - } - - /** - * Returns {@code true} if the two specified arrays are deeply - * equal to one another. Unlike the {@link #equals(Object[],Object[])} - * method, this method is appropriate for use with nested arrays of - * arbitrary depth. - * - *

Two array references are considered deeply equal if both - * are {@code null}, or if they refer to arrays that contain the same - * number of elements and all corresponding pairs of elements in the two - * arrays are deeply equal. - * - *

Two possibly {@code null} elements {@code e1} and {@code e2} are - * deeply equal if any of the following conditions hold: - *

    - *
  • {@code e1} and {@code e2} are both arrays of object reference - * types, and {@code Arrays.deepEquals(e1, e2) would return true} - *
  • {@code e1} and {@code e2} are arrays of the same primitive - * type, and the appropriate overloading of - * {@code Arrays.equals(e1, e2)} would return true. - *
  • {@code e1 == e2} - *
  • {@code e1.equals(e2)} would return true. - *
- * Note that this definition permits {@code null} elements at any depth. - * - *

If either of the specified arrays contain themselves as elements - * either directly or indirectly through one or more levels of arrays, - * the behavior of this method is undefined. - * - * @param a1 one array to be tested for equality - * @param a2 the other array to be tested for equality - * @return {@code true} if the two arrays are equal - * @see #equals(Object[],Object[]) - * @see Objects#deepEquals(Object, Object) - * @since 1.5 - */ - public static boolean deepEquals(Object[] a1, Object[] a2) { - if (a1 == a2) - return true; - if (a1 == null || a2==null) - return false; - int length = a1.length; - if (a2.length != length) - return false; - - for (int i = 0; i < length; i++) { - Object e1 = a1[i]; - Object e2 = a2[i]; - - if (e1 == e2) - continue; - if (e1 == null) - return false; - - // Figure out whether the two elements are equal - boolean eq = deepEquals0(e1, e2); - - if (!eq) - return false; - } - return true; - } - - static boolean deepEquals0(Object e1, Object e2) { - assert e1 != null; - boolean eq; - if (e1 instanceof Object[] && e2 instanceof Object[]) - eq = deepEquals ((Object[]) e1, (Object[]) e2); - else if (e1 instanceof byte[] && e2 instanceof byte[]) - eq = equals((byte[]) e1, (byte[]) e2); - else if (e1 instanceof short[] && e2 instanceof short[]) - eq = equals((short[]) e1, (short[]) e2); - else if (e1 instanceof int[] && e2 instanceof int[]) - eq = equals((int[]) e1, (int[]) e2); - else if (e1 instanceof long[] && e2 instanceof long[]) - eq = equals((long[]) e1, (long[]) e2); - else if (e1 instanceof char[] && e2 instanceof char[]) - eq = equals((char[]) e1, (char[]) e2); - else if (e1 instanceof float[] && e2 instanceof float[]) - eq = equals((float[]) e1, (float[]) e2); - else if (e1 instanceof double[] && e2 instanceof double[]) - eq = equals((double[]) e1, (double[]) e2); - else if (e1 instanceof boolean[] && e2 instanceof boolean[]) - eq = equals((boolean[]) e1, (boolean[]) e2); - else - eq = e1.equals(e2); - return eq; - } - - /** - * Returns a string representation of the contents of the specified array. - * The string representation consists of a list of the array's elements, - * enclosed in square brackets ({@code "[]"}). Adjacent elements are - * separated by the characters {@code ", "} (a comma followed by a - * space). Elements are converted to strings as by - * {@code String.valueOf(long)}. Returns {@code "null"} if {@code a} - * is {@code null}. - * - * @param a the array whose string representation to return - * @return a string representation of {@code a} - * @since 1.5 - */ - public static String toString(long[] a) { - if (a == null) - return "null"; - int iMax = a.length - 1; - if (iMax == -1) - return "[]"; - - StringBuilder b = new StringBuilder(); - b.append('['); - for (int i = 0; ; i++) { - b.append(a[i]); - if (i == iMax) - return b.append(']').toString(); - b.append(", "); - } - } - - /** - * Returns a string representation of the contents of the specified array. - * The string representation consists of a list of the array's elements, - * enclosed in square brackets ({@code "[]"}). Adjacent elements are - * separated by the characters {@code ", "} (a comma followed by a - * space). Elements are converted to strings as by - * {@code String.valueOf(int)}. Returns {@code "null"} if {@code a} is - * {@code null}. - * - * @param a the array whose string representation to return - * @return a string representation of {@code a} - * @since 1.5 - */ - public static String toString(int[] a) { - if (a == null) - return "null"; - int iMax = a.length - 1; - if (iMax == -1) - return "[]"; - - StringBuilder b = new StringBuilder(); - b.append('['); - for (int i = 0; ; i++) { - b.append(a[i]); - if (i == iMax) - return b.append(']').toString(); - b.append(", "); - } - } - - /** - * Returns a string representation of the contents of the specified array. - * The string representation consists of a list of the array's elements, - * enclosed in square brackets ({@code "[]"}). Adjacent elements are - * separated by the characters {@code ", "} (a comma followed by a - * space). Elements are converted to strings as by - * {@code String.valueOf(short)}. Returns {@code "null"} if {@code a} - * is {@code null}. - * - * @param a the array whose string representation to return - * @return a string representation of {@code a} - * @since 1.5 - */ - public static String toString(short[] a) { - if (a == null) - return "null"; - int iMax = a.length - 1; - if (iMax == -1) - return "[]"; - - StringBuilder b = new StringBuilder(); - b.append('['); - for (int i = 0; ; i++) { - b.append(a[i]); - if (i == iMax) - return b.append(']').toString(); - b.append(", "); - } - } - - /** - * Returns a string representation of the contents of the specified array. - * The string representation consists of a list of the array's elements, - * enclosed in square brackets ({@code "[]"}). Adjacent elements are - * separated by the characters {@code ", "} (a comma followed by a - * space). Elements are converted to strings as by - * {@code String.valueOf(char)}. Returns {@code "null"} if {@code a} - * is {@code null}. - * - * @param a the array whose string representation to return - * @return a string representation of {@code a} - * @since 1.5 - */ - public static String toString(char[] a) { - if (a == null) - return "null"; - int iMax = a.length - 1; - if (iMax == -1) - return "[]"; - - StringBuilder b = new StringBuilder(); - b.append('['); - for (int i = 0; ; i++) { - b.append(a[i]); - if (i == iMax) - return b.append(']').toString(); - b.append(", "); - } - } - - /** - * Returns a string representation of the contents of the specified array. - * The string representation consists of a list of the array's elements, - * enclosed in square brackets ({@code "[]"}). Adjacent elements - * are separated by the characters {@code ", "} (a comma followed - * by a space). Elements are converted to strings as by - * {@code String.valueOf(byte)}. Returns {@code "null"} if - * {@code a} is {@code null}. - * - * @param a the array whose string representation to return - * @return a string representation of {@code a} - * @since 1.5 - */ - public static String toString(byte[] a) { - if (a == null) - return "null"; - int iMax = a.length - 1; - if (iMax == -1) - return "[]"; - - StringBuilder b = new StringBuilder(); - b.append('['); - for (int i = 0; ; i++) { - b.append(a[i]); - if (i == iMax) - return b.append(']').toString(); - b.append(", "); - } - } - - /** - * Returns a string representation of the contents of the specified array. - * The string representation consists of a list of the array's elements, - * enclosed in square brackets ({@code "[]"}). Adjacent elements are - * separated by the characters {@code ", "} (a comma followed by a - * space). Elements are converted to strings as by - * {@code String.valueOf(boolean)}. Returns {@code "null"} if - * {@code a} is {@code null}. - * - * @param a the array whose string representation to return - * @return a string representation of {@code a} - * @since 1.5 - */ - public static String toString(boolean[] a) { - if (a == null) - return "null"; - int iMax = a.length - 1; - if (iMax == -1) - return "[]"; - - StringBuilder b = new StringBuilder(); - b.append('['); - for (int i = 0; ; i++) { - b.append(a[i]); - if (i == iMax) - return b.append(']').toString(); - b.append(", "); - } - } - - /** - * Returns a string representation of the contents of the specified array. - * The string representation consists of a list of the array's elements, - * enclosed in square brackets ({@code "[]"}). Adjacent elements are - * separated by the characters {@code ", "} (a comma followed by a - * space). Elements are converted to strings as by - * {@code String.valueOf(float)}. Returns {@code "null"} if {@code a} - * is {@code null}. - * - * @param a the array whose string representation to return - * @return a string representation of {@code a} - * @since 1.5 - */ - public static String toString(float[] a) { - if (a == null) - return "null"; - - int iMax = a.length - 1; - if (iMax == -1) - return "[]"; - - StringBuilder b = new StringBuilder(); - b.append('['); - for (int i = 0; ; i++) { - b.append(a[i]); - if (i == iMax) - return b.append(']').toString(); - b.append(", "); - } - } - - /** - * Returns a string representation of the contents of the specified array. - * The string representation consists of a list of the array's elements, - * enclosed in square brackets ({@code "[]"}). Adjacent elements are - * separated by the characters {@code ", "} (a comma followed by a - * space). Elements are converted to strings as by - * {@code String.valueOf(double)}. Returns {@code "null"} if {@code a} - * is {@code null}. - * - * @param a the array whose string representation to return - * @return a string representation of {@code a} - * @since 1.5 - */ - public static String toString(double[] a) { - if (a == null) - return "null"; - int iMax = a.length - 1; - if (iMax == -1) - return "[]"; - - StringBuilder b = new StringBuilder(); - b.append('['); - for (int i = 0; ; i++) { - b.append(a[i]); - if (i == iMax) - return b.append(']').toString(); - b.append(", "); - } - } - - /** - * Returns a string representation of the contents of the specified array. - * If the array contains other arrays as elements, they are converted to - * strings by the {@link Object#toString} method inherited from - * {@code Object}, which describes their identities rather than - * their contents. - * - *

The value returned by this method is equal to the value that would - * be returned by {@code Arrays.asList(a).toString()}, unless {@code a} - * is {@code null}, in which case {@code "null"} is returned. - * - * @param a the array whose string representation to return - * @return a string representation of {@code a} - * @see #deepToString(Object[]) - * @since 1.5 - */ - public static String toString(Object[] a) { - if (a == null) - return "null"; - - int iMax = a.length - 1; - if (iMax == -1) - return "[]"; - - StringBuilder b = new StringBuilder(); - b.append('['); - for (int i = 0; ; i++) { - b.append(String.valueOf(a[i])); - if (i == iMax) - return b.append(']').toString(); - b.append(", "); - } - } - - /** - * Returns a string representation of the "deep contents" of the specified - * array. If the array contains other arrays as elements, the string - * representation contains their contents and so on. This method is - * designed for converting multidimensional arrays to strings. - * - *

The string representation consists of a list of the array's - * elements, enclosed in square brackets ({@code "[]"}). Adjacent - * elements are separated by the characters {@code ", "} (a comma - * followed by a space). Elements are converted to strings as by - * {@code String.valueOf(Object)}, unless they are themselves - * arrays. - * - *

If an element {@code e} is an array of a primitive type, it is - * converted to a string as by invoking the appropriate overloading of - * {@code Arrays.toString(e)}. If an element {@code e} is an array of a - * reference type, it is converted to a string as by invoking - * this method recursively. - * - *

To avoid infinite recursion, if the specified array contains itself - * as an element, or contains an indirect reference to itself through one - * or more levels of arrays, the self-reference is converted to the string - * {@code "[...]"}. For example, an array containing only a reference - * to itself would be rendered as {@code "[[...]]"}. - * - *

This method returns {@code "null"} if the specified array - * is {@code null}. - * - * @param a the array whose string representation to return - * @return a string representation of {@code a} - * @see #toString(Object[]) - * @since 1.5 - */ - public static String deepToString(Object[] a) { - if (a == null) - return "null"; - - int bufLen = 20 * a.length; - if (a.length != 0 && bufLen <= 0) - bufLen = Integer.MAX_VALUE; - StringBuilder buf = new StringBuilder(bufLen); - deepToString(a, buf, new HashSet<>()); - return buf.toString(); - } - - private static void deepToString(Object[] a, StringBuilder buf, - Set dejaVu) { - if (a == null) { - buf.append("null"); - return; - } - int iMax = a.length - 1; - if (iMax == -1) { - buf.append("[]"); - return; - } - - dejaVu.add(a); - buf.append('['); - for (int i = 0; ; i++) { - - Object element = a[i]; - if (element == null) { - buf.append("null"); - } else { - Class eClass = element.getClass(); - - if (eClass.isArray()) { - if (eClass == byte[].class) - buf.append(toString((byte[]) element)); - else if (eClass == short[].class) - buf.append(toString((short[]) element)); - else if (eClass == int[].class) - buf.append(toString((int[]) element)); - else if (eClass == long[].class) - buf.append(toString((long[]) element)); - else if (eClass == char[].class) - buf.append(toString((char[]) element)); - else if (eClass == float[].class) - buf.append(toString((float[]) element)); - else if (eClass == double[].class) - buf.append(toString((double[]) element)); - else if (eClass == boolean[].class) - buf.append(toString((boolean[]) element)); - else { // element is an array of object references - if (dejaVu.contains(element)) - buf.append("[...]"); - else - deepToString((Object[])element, buf, dejaVu); - } - } else { // element is non-null and not an array - buf.append(element.toString()); - } - } - if (i == iMax) - break; - buf.append(", "); - } - buf.append(']'); - dejaVu.remove(a); - } - - - /** - * Set all elements of the specified array, using the provided - * generator function to compute each element. - * - *

If the generator function throws an exception, it is relayed to - * the caller and the array is left in an indeterminate state. - * - * @apiNote - * Setting a subrange of an array, using a generator function to compute - * each element, can be written as follows: - *

{@code
-     * IntStream.range(startInclusive, endExclusive)
-     *          .forEach(i -> array[i] = generator.apply(i));
-     * }
- * - * @param type of elements of the array - * @param array array to be initialized - * @param generator a function accepting an index and producing the desired - * value for that position - * @throws NullPointerException if the generator is null - * @since 1.8 - */ - public static void setAll(T[] array, IntFunction generator) { - Objects.requireNonNull(generator); - for (int i = 0; i < array.length; i++) - array[i] = generator.apply(i); - } - - /** - * Set all elements of the specified array, in parallel, using the - * provided generator function to compute each element. - * - *

If the generator function throws an exception, an unchecked exception - * is thrown from {@code parallelSetAll} and the array is left in an - * indeterminate state. - * - * @apiNote - * Setting a subrange of an array, in parallel, using a generator function - * to compute each element, can be written as follows: - *

{@code
-     * IntStream.range(startInclusive, endExclusive)
-     *          .parallel()
-     *          .forEach(i -> array[i] = generator.apply(i));
-     * }
- * - * @param type of elements of the array - * @param array array to be initialized - * @param generator a function accepting an index and producing the desired - * value for that position - * @throws NullPointerException if the generator is null - * @since 1.8 - */ - public static void parallelSetAll(T[] array, IntFunction generator) { - Objects.requireNonNull(generator); - IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.apply(i); }); - } - - /** - * Set all elements of the specified array, using the provided - * generator function to compute each element. - * - *

If the generator function throws an exception, it is relayed to - * the caller and the array is left in an indeterminate state. - * - * @apiNote - * Setting a subrange of an array, using a generator function to compute - * each element, can be written as follows: - *

{@code
-     * IntStream.range(startInclusive, endExclusive)
-     *          .forEach(i -> array[i] = generator.applyAsInt(i));
-     * }
- * - * @param array array to be initialized - * @param generator a function accepting an index and producing the desired - * value for that position - * @throws NullPointerException if the generator is null - * @since 1.8 - */ - public static void setAll(int[] array, IntUnaryOperator generator) { - Objects.requireNonNull(generator); - for (int i = 0; i < array.length; i++) - array[i] = generator.applyAsInt(i); - } - - /** - * Set all elements of the specified array, in parallel, using the - * provided generator function to compute each element. - * - *

If the generator function throws an exception, an unchecked exception - * is thrown from {@code parallelSetAll} and the array is left in an - * indeterminate state. - * - * @apiNote - * Setting a subrange of an array, in parallel, using a generator function - * to compute each element, can be written as follows: - *

{@code
-     * IntStream.range(startInclusive, endExclusive)
-     *          .parallel()
-     *          .forEach(i -> array[i] = generator.applyAsInt(i));
-     * }
- * - * @param array array to be initialized - * @param generator a function accepting an index and producing the desired - * value for that position - * @throws NullPointerException if the generator is null - * @since 1.8 - */ - public static void parallelSetAll(int[] array, IntUnaryOperator generator) { - Objects.requireNonNull(generator); - IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsInt(i); }); - } - - /** - * Set all elements of the specified array, using the provided - * generator function to compute each element. - * - *

If the generator function throws an exception, it is relayed to - * the caller and the array is left in an indeterminate state. - * - * @apiNote - * Setting a subrange of an array, using a generator function to compute - * each element, can be written as follows: - *

{@code
-     * IntStream.range(startInclusive, endExclusive)
-     *          .forEach(i -> array[i] = generator.applyAsLong(i));
-     * }
- * - * @param array array to be initialized - * @param generator a function accepting an index and producing the desired - * value for that position - * @throws NullPointerException if the generator is null - * @since 1.8 - */ - public static void setAll(long[] array, IntToLongFunction generator) { - Objects.requireNonNull(generator); - for (int i = 0; i < array.length; i++) - array[i] = generator.applyAsLong(i); - } - - /** - * Set all elements of the specified array, in parallel, using the - * provided generator function to compute each element. - * - *

If the generator function throws an exception, an unchecked exception - * is thrown from {@code parallelSetAll} and the array is left in an - * indeterminate state. - * - * @apiNote - * Setting a subrange of an array, in parallel, using a generator function - * to compute each element, can be written as follows: - *

{@code
-     * IntStream.range(startInclusive, endExclusive)
-     *          .parallel()
-     *          .forEach(i -> array[i] = generator.applyAsLong(i));
-     * }
- * - * @param array array to be initialized - * @param generator a function accepting an index and producing the desired - * value for that position - * @throws NullPointerException if the generator is null - * @since 1.8 - */ - public static void parallelSetAll(long[] array, IntToLongFunction generator) { - Objects.requireNonNull(generator); - IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsLong(i); }); - } - - /** - * Set all elements of the specified array, using the provided - * generator function to compute each element. - * - *

If the generator function throws an exception, it is relayed to - * the caller and the array is left in an indeterminate state. - * - * @apiNote - * Setting a subrange of an array, using a generator function to compute - * each element, can be written as follows: - *

{@code
-     * IntStream.range(startInclusive, endExclusive)
-     *          .forEach(i -> array[i] = generator.applyAsDouble(i));
-     * }
- * - * @param array array to be initialized - * @param generator a function accepting an index and producing the desired - * value for that position - * @throws NullPointerException if the generator is null - * @since 1.8 - */ - public static void setAll(double[] array, IntToDoubleFunction generator) { - Objects.requireNonNull(generator); - for (int i = 0; i < array.length; i++) - array[i] = generator.applyAsDouble(i); - } - - /** - * Set all elements of the specified array, in parallel, using the - * provided generator function to compute each element. - * - *

If the generator function throws an exception, an unchecked exception - * is thrown from {@code parallelSetAll} and the array is left in an - * indeterminate state. - * - * @apiNote - * Setting a subrange of an array, in parallel, using a generator function - * to compute each element, can be written as follows: - *

{@code
-     * IntStream.range(startInclusive, endExclusive)
-     *          .parallel()
-     *          .forEach(i -> array[i] = generator.applyAsDouble(i));
-     * }
- * - * @param array array to be initialized - * @param generator a function accepting an index and producing the desired - * value for that position - * @throws NullPointerException if the generator is null - * @since 1.8 - */ - public static void parallelSetAll(double[] array, IntToDoubleFunction generator) { - Objects.requireNonNull(generator); - IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsDouble(i); }); - } - - /** - * Returns a {@link Spliterator} covering all of the specified array. - * - *

The spliterator reports {@link Spliterator#SIZED}, - * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and - * {@link Spliterator#IMMUTABLE}. - * - * @param type of elements - * @param array the array, assumed to be unmodified during use - * @return a spliterator for the array elements - * @since 1.8 - */ - public static Spliterator spliterator(T[] array) { - return Spliterators.spliterator(array, - Spliterator.ORDERED | Spliterator.IMMUTABLE); - } - - /** - * Returns a {@link Spliterator} covering the specified range of the - * specified array. - * - *

The spliterator reports {@link Spliterator#SIZED}, - * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and - * {@link Spliterator#IMMUTABLE}. - * - * @param type of elements - * @param array the array, assumed to be unmodified during use - * @param startInclusive the first index to cover, inclusive - * @param endExclusive index immediately past the last index to cover - * @return a spliterator for the array elements - * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is - * negative, {@code endExclusive} is less than - * {@code startInclusive}, or {@code endExclusive} is greater than - * the array size - * @since 1.8 - */ - public static Spliterator spliterator(T[] array, int startInclusive, int endExclusive) { - return Spliterators.spliterator(array, startInclusive, endExclusive, - Spliterator.ORDERED | Spliterator.IMMUTABLE); - } - - /** - * Returns a {@link Spliterator.OfInt} covering all of the specified array. - * - *

The spliterator reports {@link Spliterator#SIZED}, - * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and - * {@link Spliterator#IMMUTABLE}. - * - * @param array the array, assumed to be unmodified during use - * @return a spliterator for the array elements - * @since 1.8 - */ - public static Spliterator.OfInt spliterator(int[] array) { - return Spliterators.spliterator(array, - Spliterator.ORDERED | Spliterator.IMMUTABLE); - } - - /** - * Returns a {@link Spliterator.OfInt} covering the specified range of the - * specified array. - * - *

The spliterator reports {@link Spliterator#SIZED}, - * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and - * {@link Spliterator#IMMUTABLE}. - * - * @param array the array, assumed to be unmodified during use - * @param startInclusive the first index to cover, inclusive - * @param endExclusive index immediately past the last index to cover - * @return a spliterator for the array elements - * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is - * negative, {@code endExclusive} is less than - * {@code startInclusive}, or {@code endExclusive} is greater than - * the array size - * @since 1.8 - */ - public static Spliterator.OfInt spliterator(int[] array, int startInclusive, int endExclusive) { - return Spliterators.spliterator(array, startInclusive, endExclusive, - Spliterator.ORDERED | Spliterator.IMMUTABLE); - } - - /** - * Returns a {@link Spliterator.OfLong} covering all of the specified array. - * - *

The spliterator reports {@link Spliterator#SIZED}, - * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and - * {@link Spliterator#IMMUTABLE}. - * - * @param array the array, assumed to be unmodified during use - * @return the spliterator for the array elements - * @since 1.8 - */ - public static Spliterator.OfLong spliterator(long[] array) { - return Spliterators.spliterator(array, - Spliterator.ORDERED | Spliterator.IMMUTABLE); - } - - /** - * Returns a {@link Spliterator.OfLong} covering the specified range of the - * specified array. - * - *

The spliterator reports {@link Spliterator#SIZED}, - * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and - * {@link Spliterator#IMMUTABLE}. - * - * @param array the array, assumed to be unmodified during use - * @param startInclusive the first index to cover, inclusive - * @param endExclusive index immediately past the last index to cover - * @return a spliterator for the array elements - * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is - * negative, {@code endExclusive} is less than - * {@code startInclusive}, or {@code endExclusive} is greater than - * the array size - * @since 1.8 - */ - public static Spliterator.OfLong spliterator(long[] array, int startInclusive, int endExclusive) { - return Spliterators.spliterator(array, startInclusive, endExclusive, - Spliterator.ORDERED | Spliterator.IMMUTABLE); - } - - /** - * Returns a {@link Spliterator.OfDouble} covering all of the specified - * array. - * - *

The spliterator reports {@link Spliterator#SIZED}, - * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and - * {@link Spliterator#IMMUTABLE}. - * - * @param array the array, assumed to be unmodified during use - * @return a spliterator for the array elements - * @since 1.8 - */ - public static Spliterator.OfDouble spliterator(double[] array) { - return Spliterators.spliterator(array, - Spliterator.ORDERED | Spliterator.IMMUTABLE); - } - - /** - * Returns a {@link Spliterator.OfDouble} covering the specified range of - * the specified array. - * - *

The spliterator reports {@link Spliterator#SIZED}, - * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and - * {@link Spliterator#IMMUTABLE}. - * - * @param array the array, assumed to be unmodified during use - * @param startInclusive the first index to cover, inclusive - * @param endExclusive index immediately past the last index to cover - * @return a spliterator for the array elements - * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is - * negative, {@code endExclusive} is less than - * {@code startInclusive}, or {@code endExclusive} is greater than - * the array size - * @since 1.8 - */ - public static Spliterator.OfDouble spliterator(double[] array, int startInclusive, int endExclusive) { - return Spliterators.spliterator(array, startInclusive, endExclusive, - Spliterator.ORDERED | Spliterator.IMMUTABLE); - } - - /** - * Returns a sequential {@link Stream} with the specified array as its - * source. - * - * @param The type of the array elements - * @param array The array, assumed to be unmodified during use - * @return a {@code Stream} for the array - * @since 1.8 - */ - public static Stream stream(T[] array) { - return stream(array, 0, array.length); - } - - /** - * Returns a sequential {@link Stream} with the specified range of the - * specified array as its source. - * - * @param the type of the array elements - * @param array the array, assumed to be unmodified during use - * @param startInclusive the first index to cover, inclusive - * @param endExclusive index immediately past the last index to cover - * @return a {@code Stream} for the array range - * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is - * negative, {@code endExclusive} is less than - * {@code startInclusive}, or {@code endExclusive} is greater than - * the array size - * @since 1.8 - */ - public static Stream stream(T[] array, int startInclusive, int endExclusive) { - return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false); - } - - /** - * Returns a sequential {@link IntStream} with the specified array as its - * source. - * - * @param array the array, assumed to be unmodified during use - * @return an {@code IntStream} for the array - * @since 1.8 - */ - public static IntStream stream(int[] array) { - return stream(array, 0, array.length); - } - - /** - * Returns a sequential {@link IntStream} with the specified range of the - * specified array as its source. - * - * @param array the array, assumed to be unmodified during use - * @param startInclusive the first index to cover, inclusive - * @param endExclusive index immediately past the last index to cover - * @return an {@code IntStream} for the array range - * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is - * negative, {@code endExclusive} is less than - * {@code startInclusive}, or {@code endExclusive} is greater than - * the array size - * @since 1.8 - */ - public static IntStream stream(int[] array, int startInclusive, int endExclusive) { - return StreamSupport.intStream(spliterator(array, startInclusive, endExclusive), false); - } - - /** - * Returns a sequential {@link LongStream} with the specified array as its - * source. - * - * @param array the array, assumed to be unmodified during use - * @return a {@code LongStream} for the array - * @since 1.8 - */ - public static LongStream stream(long[] array) { - return stream(array, 0, array.length); - } - - /** - * Returns a sequential {@link LongStream} with the specified range of the - * specified array as its source. - * - * @param array the array, assumed to be unmodified during use - * @param startInclusive the first index to cover, inclusive - * @param endExclusive index immediately past the last index to cover - * @return a {@code LongStream} for the array range - * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is - * negative, {@code endExclusive} is less than - * {@code startInclusive}, or {@code endExclusive} is greater than - * the array size - * @since 1.8 - */ - public static LongStream stream(long[] array, int startInclusive, int endExclusive) { - return StreamSupport.longStream(spliterator(array, startInclusive, endExclusive), false); - } - - /** - * Returns a sequential {@link DoubleStream} with the specified array as its - * source. - * - * @param array the array, assumed to be unmodified during use - * @return a {@code DoubleStream} for the array - * @since 1.8 - */ - public static DoubleStream stream(double[] array) { - return stream(array, 0, array.length); - } - - /** - * Returns a sequential {@link DoubleStream} with the specified range of the - * specified array as its source. - * - * @param array the array, assumed to be unmodified during use - * @param startInclusive the first index to cover, inclusive - * @param endExclusive index immediately past the last index to cover - * @return a {@code DoubleStream} for the array range - * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is - * negative, {@code endExclusive} is less than - * {@code startInclusive}, or {@code endExclusive} is greater than - * the array size - * @since 1.8 - */ - public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) { - return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false); - } - - - // Comparison methods - - // Compare boolean - - /** - * Compares two {@code boolean} arrays lexicographically. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Boolean#compare(boolean, boolean)}, at an index within the - * respective arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(boolean[], boolean[])} for the definition of a - * common and proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - *

The comparison is consistent with {@link #equals(boolean[], boolean[]) equals}, - * more specifically the following holds for arrays {@code a} and {@code b}: - *

{@code
-     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Boolean.compare(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are equal and - * contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compare(boolean[] a, boolean[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Boolean.compare(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code boolean} arrays lexicographically over the specified - * ranges. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Boolean#compare(boolean, boolean)}, at a - * relative index within the respective arrays that is the length of the - * prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(boolean[], int, int, boolean[], int, int)} for the - * definition of a common and proper prefix.) - * - *

The comparison is consistent with - * {@link #equals(boolean[], int, int, boolean[], int, int) equals}, more - * specifically the following holds for arrays {@code a} and {@code b} with - * specified ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively: - *

{@code
-     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
-     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Boolean.compare(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int compare(boolean[] a, int aFromIndex, int aToIndex, - boolean[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Boolean.compare(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - // Compare byte - - /** - * Compares two {@code byte} arrays lexicographically. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Byte#compare(byte, byte)}, at an index within the respective - * arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(byte[], byte[])} for the definition of a common and - * proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - *

The comparison is consistent with {@link #equals(byte[], byte[]) equals}, - * more specifically the following holds for arrays {@code a} and {@code b}: - *

{@code
-     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Byte.compare(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are equal and - * contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compare(byte[] a, byte[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Byte.compare(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code byte} arrays lexicographically over the specified - * ranges. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Byte#compare(byte, byte)}, at a relative index - * within the respective arrays that is the length of the prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(byte[], int, int, byte[], int, int)} for the - * definition of a common and proper prefix.) - * - *

The comparison is consistent with - * {@link #equals(byte[], int, int, byte[], int, int) equals}, more - * specifically the following holds for arrays {@code a} and {@code b} with - * specified ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively: - *

{@code
-     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
-     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Byte.compare(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int compare(byte[] a, int aFromIndex, int aToIndex, - byte[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Byte.compare(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - /** - * Compares two {@code byte} arrays lexicographically, numerically treating - * elements as unsigned. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Byte#compareUnsigned(byte, byte)}, at an index within the - * respective arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(byte[], byte[])} for the definition of a common - * and proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Byte.compareUnsigned(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are - * equal and contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compareUnsigned(byte[] a, byte[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Byte.compareUnsigned(a[i], b[i]); - } - - return a.length - b.length; - } - - - /** - * Compares two {@code byte} arrays lexicographically over the specified - * ranges, numerically treating elements as unsigned. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Byte#compareUnsigned(byte, byte)}, at a - * relative index within the respective arrays that is the length of the - * prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(byte[], int, int, byte[], int, int)} for the - * definition of a common and proper prefix.) - * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Byte.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is null - * @since 9 - */ - public static int compareUnsigned(byte[] a, int aFromIndex, int aToIndex, - byte[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Byte.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - // Compare short - - /** - * Compares two {@code short} arrays lexicographically. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Short#compare(short, short)}, at an index within the respective - * arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(short[], short[])} for the definition of a common - * and proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - *

The comparison is consistent with {@link #equals(short[], short[]) equals}, - * more specifically the following holds for arrays {@code a} and {@code b}: - *

{@code
-     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Short.compare(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are equal and - * contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compare(short[] a, short[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Short.compare(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code short} arrays lexicographically over the specified - * ranges. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Short#compare(short, short)}, at a relative - * index within the respective arrays that is the length of the prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(short[], int, int, short[], int, int)} for the - * definition of a common and proper prefix.) - * - *

The comparison is consistent with - * {@link #equals(short[], int, int, short[], int, int) equals}, more - * specifically the following holds for arrays {@code a} and {@code b} with - * specified ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively: - *

{@code
-     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
-     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Short.compare(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int compare(short[] a, int aFromIndex, int aToIndex, - short[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Short.compare(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - /** - * Compares two {@code short} arrays lexicographically, numerically treating - * elements as unsigned. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Short#compareUnsigned(short, short)}, at an index within the - * respective arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(short[], short[])} for the definition of a common - * and proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Short.compareUnsigned(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are - * equal and contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compareUnsigned(short[] a, short[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Short.compareUnsigned(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code short} arrays lexicographically over the specified - * ranges, numerically treating elements as unsigned. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Short#compareUnsigned(short, short)}, at a - * relative index within the respective arrays that is the length of the - * prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(short[], int, int, short[], int, int)} for the - * definition of a common and proper prefix.) - * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Short.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is null - * @since 9 - */ - public static int compareUnsigned(short[] a, int aFromIndex, int aToIndex, - short[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Short.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - // Compare char - - /** - * Compares two {@code char} arrays lexicographically. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Character#compare(char, char)}, at an index within the respective - * arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(char[], char[])} for the definition of a common and - * proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - *

The comparison is consistent with {@link #equals(char[], char[]) equals}, - * more specifically the following holds for arrays {@code a} and {@code b}: - *

{@code
-     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Character.compare(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are equal and - * contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compare(char[] a, char[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Character.compare(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code char} arrays lexicographically over the specified - * ranges. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Character#compare(char, char)}, at a relative - * index within the respective arrays that is the length of the prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(char[], int, int, char[], int, int)} for the - * definition of a common and proper prefix.) - * - *

The comparison is consistent with - * {@link #equals(char[], int, int, char[], int, int) equals}, more - * specifically the following holds for arrays {@code a} and {@code b} with - * specified ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively: - *

{@code
-     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
-     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Character.compare(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int compare(char[] a, int aFromIndex, int aToIndex, - char[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Character.compare(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - // Compare int - - /** - * Compares two {@code int} arrays lexicographically. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Integer#compare(int, int)}, at an index within the respective - * arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(int[], int[])} for the definition of a common and - * proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - *

The comparison is consistent with {@link #equals(int[], int[]) equals}, - * more specifically the following holds for arrays {@code a} and {@code b}: - *

{@code
-     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Integer.compare(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are equal and - * contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compare(int[] a, int[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Integer.compare(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code int} arrays lexicographically over the specified - * ranges. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Integer#compare(int, int)}, at a relative index - * within the respective arrays that is the length of the prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(int[], int, int, int[], int, int)} for the - * definition of a common and proper prefix.) - * - *

The comparison is consistent with - * {@link #equals(int[], int, int, int[], int, int) equals}, more - * specifically the following holds for arrays {@code a} and {@code b} with - * specified ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively: - *

{@code
-     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
-     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Integer.compare(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int compare(int[] a, int aFromIndex, int aToIndex, - int[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Integer.compare(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - /** - * Compares two {@code int} arrays lexicographically, numerically treating - * elements as unsigned. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Integer#compareUnsigned(int, int)}, at an index within the - * respective arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(int[], int[])} for the definition of a common - * and proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Integer.compareUnsigned(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are - * equal and contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compareUnsigned(int[] a, int[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Integer.compareUnsigned(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code int} arrays lexicographically over the specified - * ranges, numerically treating elements as unsigned. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Integer#compareUnsigned(int, int)}, at a - * relative index within the respective arrays that is the length of the - * prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(int[], int, int, int[], int, int)} for the - * definition of a common and proper prefix.) - * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Integer.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is null - * @since 9 - */ - public static int compareUnsigned(int[] a, int aFromIndex, int aToIndex, - int[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Integer.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - // Compare long - - /** - * Compares two {@code long} arrays lexicographically. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Long#compare(long, long)}, at an index within the respective - * arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(long[], long[])} for the definition of a common and - * proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - *

The comparison is consistent with {@link #equals(long[], long[]) equals}, - * more specifically the following holds for arrays {@code a} and {@code b}: - *

{@code
-     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Long.compare(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are equal and - * contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compare(long[] a, long[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Long.compare(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code long} arrays lexicographically over the specified - * ranges. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Long#compare(long, long)}, at a relative index - * within the respective arrays that is the length of the prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(long[], int, int, long[], int, int)} for the - * definition of a common and proper prefix.) - * - *

The comparison is consistent with - * {@link #equals(long[], int, int, long[], int, int) equals}, more - * specifically the following holds for arrays {@code a} and {@code b} with - * specified ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively: - *

{@code
-     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
-     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Long.compare(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int compare(long[] a, int aFromIndex, int aToIndex, - long[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Long.compare(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - /** - * Compares two {@code long} arrays lexicographically, numerically treating - * elements as unsigned. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Long#compareUnsigned(long, long)}, at an index within the - * respective arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(long[], long[])} for the definition of a common - * and proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Long.compareUnsigned(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are - * equal and contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compareUnsigned(long[] a, long[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Long.compareUnsigned(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code long} arrays lexicographically over the specified - * ranges, numerically treating elements as unsigned. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Long#compareUnsigned(long, long)}, at a - * relative index within the respective arrays that is the length of the - * prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(long[], int, int, long[], int, int)} for the - * definition of a common and proper prefix.) - * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Long.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is null - * @since 9 - */ - public static int compareUnsigned(long[] a, int aFromIndex, int aToIndex, - long[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Long.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - // Compare float - - /** - * Compares two {@code float} arrays lexicographically. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Float#compare(float, float)}, at an index within the respective - * arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(float[], float[])} for the definition of a common - * and proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - *

The comparison is consistent with {@link #equals(float[], float[]) equals}, - * more specifically the following holds for arrays {@code a} and {@code b}: - *

{@code
-     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Float.compare(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are equal and - * contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compare(float[] a, float[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Float.compare(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code float} arrays lexicographically over the specified - * ranges. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Float#compare(float, float)}, at a relative - * index within the respective arrays that is the length of the prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(float[], int, int, float[], int, int)} for the - * definition of a common and proper prefix.) - * - *

The comparison is consistent with - * {@link #equals(float[], int, int, float[], int, int) equals}, more - * specifically the following holds for arrays {@code a} and {@code b} with - * specified ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively: - *

{@code
-     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
-     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Float.compare(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int compare(float[] a, int aFromIndex, int aToIndex, - float[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Float.compare(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - // Compare double - - /** - * Compares two {@code double} arrays lexicographically. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements, as if by - * {@link Double#compare(double, double)}, at an index within the respective - * arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(double[], double[])} for the definition of a common - * and proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - *

The comparison is consistent with {@link #equals(double[], double[]) equals}, - * more specifically the following holds for arrays {@code a} and {@code b}: - *

{@code
-     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return Double.compare(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @return the value {@code 0} if the first and second array are equal and - * contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static int compare(double[] a, double[] b) { - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int i = ArraysSupport.mismatch(a, b, - Math.min(a.length, b.length)); - if (i >= 0) { - return Double.compare(a[i], b[i]); - } - - return a.length - b.length; - } - - /** - * Compares two {@code double} arrays lexicographically over the specified - * ranges. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements, as if by {@link Double#compare(double, double)}, at a relative - * index within the respective arrays that is the length of the prefix. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(double[], int, int, double[], int, int)} for the - * definition of a common and proper prefix.) - * - *

The comparison is consistent with - * {@link #equals(double[], int, int, double[], int, int) equals}, more - * specifically the following holds for arrays {@code a} and {@code b} with - * specified ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively: - *

{@code
-     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
-     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if: - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return Double.compare(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int compare(double[] a, int aFromIndex, int aToIndex, - double[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - Math.min(aLength, bLength)); - if (i >= 0) { - return Double.compare(a[aFromIndex + i], b[bFromIndex + i]); - } - - return aLength - bLength; - } - - // Compare objects - - /** - * Compares two {@code Object} arrays, within comparable elements, - * lexicographically. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing two elements of type {@code T} at - * an index {@code i} within the respective arrays that is the prefix - * length, as if by: - *

{@code
-     *     Comparator.nullsFirst(Comparator.naturalOrder()).
-     *         compare(a[i], b[i])
-     * }
- * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(Object[], Object[])} for the definition of a common - * and proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * A {@code null} array element is considered lexicographically than a - * non-{@code null} array element. Two {@code null} array elements are - * considered equal. - * - *

The comparison is consistent with {@link #equals(Object[], Object[]) equals}, - * more specifically the following holds for arrays {@code a} and {@code b}: - *

{@code
-     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if (for non-{@code null} array references - * and elements): - *

{@code
-     *     int i = Arrays.mismatch(a, b);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return a[i].compareTo(b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @param the type of comparable array elements - * @return the value {@code 0} if the first and second array are equal and - * contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @since 9 - */ - public static > int compare(T[] a, T[] b) { - if (a == b) - return 0; - // A null array is less than a non-null array - if (a == null || b == null) - return a == null ? -1 : 1; - - int length = Math.min(a.length, b.length); - for (int i = 0; i < length; i++) { - T oa = a[i]; - T ob = b[i]; - if (oa != ob) { - // A null element is less than a non-null element - if (oa == null || ob == null) - return oa == null ? -1 : 1; - int v = oa.compareTo(ob); - if (v != 0) { - return v; - } - } - } - - return a.length - b.length; - } - - /** - * Compares two {@code Object} arrays lexicographically over the specified - * ranges. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing two - * elements of type {@code T} at a relative index {@code i} within the - * respective arrays that is the prefix length, as if by: - *

{@code
-     *     Comparator.nullsFirst(Comparator.naturalOrder()).
-     *         compare(a[aFromIndex + i, b[bFromIndex + i])
-     * }
- * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(Object[], int, int, Object[], int, int)} for the - * definition of a common and proper prefix.) - * - *

The comparison is consistent with - * {@link #equals(Object[], int, int, Object[], int, int) equals}, more - * specifically the following holds for arrays {@code a} and {@code b} with - * specified ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively: - *

{@code
-     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
-     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
-     * }
- * - * @apiNote - *

This method behaves as if (for non-{@code null} array elements): - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return a[aFromIndex + i].compareTo(b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @param the type of comparable array elements - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static > int compare( - T[] a, int aFromIndex, int aToIndex, - T[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - for (int i = 0; i < length; i++) { - T oa = a[aFromIndex++]; - T ob = b[bFromIndex++]; - if (oa != ob) { - if (oa == null || ob == null) - return oa == null ? -1 : 1; - int v = oa.compareTo(ob); - if (v != 0) { - return v; - } - } - } - - return aLength - bLength; - } - - /** - * Compares two {@code Object} arrays lexicographically using a specified - * comparator. - * - *

If the two arrays share a common prefix then the lexicographic - * comparison is the result of comparing with the specified comparator two - * elements at an index within the respective arrays that is the prefix - * length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two array lengths. - * (See {@link #mismatch(Object[], Object[])} for the definition of a common - * and proper prefix.) - * - *

A {@code null} array reference is considered lexicographically less - * than a non-{@code null} array reference. Two {@code null} array - * references are considered equal. - * - * @apiNote - *

This method behaves as if (for non-{@code null} array references): - *

{@code
-     *     int i = Arrays.mismatch(a, b, cmp);
-     *     if (i >= 0 && i < Math.min(a.length, b.length))
-     *         return cmp.compare(a[i], b[i]);
-     *     return a.length - b.length;
-     * }
- * - * @param a the first array to compare - * @param b the second array to compare - * @param cmp the comparator to compare array elements - * @param the type of array elements - * @return the value {@code 0} if the first and second array are equal and - * contain the same elements in the same order; - * a value less than {@code 0} if the first array is - * lexicographically less than the second array; and - * a value greater than {@code 0} if the first array is - * lexicographically greater than the second array - * @throws NullPointerException if the comparator is {@code null} - * @since 9 - */ - public static int compare(T[] a, T[] b, - Comparator cmp) { - Objects.requireNonNull(cmp); - if (a == b) - return 0; - if (a == null || b == null) - return a == null ? -1 : 1; - - int length = Math.min(a.length, b.length); - for (int i = 0; i < length; i++) { - T oa = a[i]; - T ob = b[i]; - if (oa != ob) { - // Null-value comparison is deferred to the comparator - int v = cmp.compare(oa, ob); - if (v != 0) { - return v; - } - } - } - - return a.length - b.length; - } - - /** - * Compares two {@code Object} arrays lexicographically over the specified - * ranges. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the lexicographic comparison is the result of comparing with the - * specified comparator two elements at a relative index within the - * respective arrays that is the prefix length. - * Otherwise, one array is a proper prefix of the other and, lexicographic - * comparison is the result of comparing the two range lengths. - * (See {@link #mismatch(Object[], int, int, Object[], int, int)} for the - * definition of a common and proper prefix.) - * - * @apiNote - *

This method behaves as if (for non-{@code null} array elements): - *

{@code
-     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
-     *                             b, bFromIndex, bToIndex, cmp);
-     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     *         return cmp.compare(a[aFromIndex + i], b[bFromIndex + i]);
-     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
-     * }
- * - * @param a the first array to compare - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be compared - * @param aToIndex the index (exclusive) of the last element in the - * first array to be compared - * @param b the second array to compare - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be compared - * @param bToIndex the index (exclusive) of the last element in the - * second array to be compared - * @param cmp the comparator to compare array elements - * @param the type of array elements - * @return the value {@code 0} if, over the specified ranges, the first and - * second array are equal and contain the same elements in the same - * order; - * a value less than {@code 0} if, over the specified ranges, the - * first array is lexicographically less than the second array; and - * a value greater than {@code 0} if, over the specified ranges, the - * first array is lexicographically greater than the second array - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array or the comparator is {@code null} - * @since 9 - */ - public static int compare( - T[] a, int aFromIndex, int aToIndex, - T[] b, int bFromIndex, int bToIndex, - Comparator cmp) { - Objects.requireNonNull(cmp); - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - for (int i = 0; i < length; i++) { - T oa = a[aFromIndex++]; - T ob = b[bFromIndex++]; - if (oa != ob) { - // Null-value comparison is deferred to the comparator - int v = cmp.compare(oa, ob); - if (v != 0) { - return v; - } - } - } - - return aLength - bLength; - } - - - // Mismatch methods - - // Mismatch boolean - - /** - * Finds and returns the index of the first mismatch between two - * {@code boolean} arrays, otherwise return -1 if no mismatch is found. The - * index will be in the range of 0 (inclusive) up to the length (inclusive) - * of the smaller array. - * - *

If the two arrays share a common prefix then the returned index is the - * length of the common prefix and it follows that there is a mismatch - * between the two elements at that index within the respective arrays. - * If one array is a proper prefix of the other then the returned index is - * the length of the smaller array and it follows that the index is only - * valid for the larger array. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(a.length, b.length) &&
-     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
-     *     a[pl] != b[pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper - * prefix if the following expression is true: - *

{@code
-     *     a.length != b.length &&
-     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
-     *                   b, 0, Math.min(a.length, b.length))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param b the second array to be tested for a mismatch - * @return the index of the first mismatch between the two arrays, - * otherwise {@code -1}. - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(boolean[] a, boolean[] b) { - int length = Math.min(a.length, b.length); // Check null array refs - if (a == b) - return -1; - - int i = ArraysSupport.mismatch(a, b, length); - return (i < 0 && a.length != b.length) ? length : i; - } - - /** - * Finds and returns the relative index of the first mismatch between two - * {@code boolean} arrays over the specified ranges, otherwise return -1 if - * no mismatch is found. The index will be in the range of 0 (inclusive) up - * to the length (inclusive) of the smaller range. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the returned relative index is the length of the common prefix and - * it follows that there is a mismatch between the two elements at that - * relative index within the respective arrays. - * If one array is a proper prefix of the other, over the specified ranges, - * then the returned relative index is the length of the smaller range and - * it follows that the relative index is only valid for the array with the - * larger range. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
-     *     a[aFromIndex + pl] != b[bFromIndex + pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper - * if the following expression is true: - *

{@code
-     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested for a mismatch - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return the relative index of the first mismatch between the two arrays - * over the specified ranges, otherwise {@code -1}. - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(boolean[] a, int aFromIndex, int aToIndex, - boolean[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - length); - return (i < 0 && aLength != bLength) ? length : i; - } - - // Mismatch byte - - /** - * Finds and returns the index of the first mismatch between two {@code byte} - * arrays, otherwise return -1 if no mismatch is found. The index will be - * in the range of 0 (inclusive) up to the length (inclusive) of the smaller - * array. - * - *

If the two arrays share a common prefix then the returned index is the - * length of the common prefix and it follows that there is a mismatch - * between the two elements at that index within the respective arrays. - * If one array is a proper prefix of the other then the returned index is - * the length of the smaller array and it follows that the index is only - * valid for the larger array. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(a.length, b.length) &&
-     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
-     *     a[pl] != b[pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper - * prefix if the following expression is true: - *

{@code
-     *     a.length != b.length &&
-     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
-     *                   b, 0, Math.min(a.length, b.length))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param b the second array to be tested for a mismatch - * @return the index of the first mismatch between the two arrays, - * otherwise {@code -1}. - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(byte[] a, byte[] b) { - int length = Math.min(a.length, b.length); // Check null array refs - if (a == b) - return -1; - - int i = ArraysSupport.mismatch(a, b, length); - return (i < 0 && a.length != b.length) ? length : i; - } - - /** - * Finds and returns the relative index of the first mismatch between two - * {@code byte} arrays over the specified ranges, otherwise return -1 if no - * mismatch is found. The index will be in the range of 0 (inclusive) up to - * the length (inclusive) of the smaller range. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the returned relative index is the length of the common prefix and - * it follows that there is a mismatch between the two elements at that - * relative index within the respective arrays. - * If one array is a proper prefix of the other, over the specified ranges, - * then the returned relative index is the length of the smaller range and - * it follows that the relative index is only valid for the array with the - * larger range. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
-     *     a[aFromIndex + pl] != b[bFromIndex + pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper - * if the following expression is true: - *

{@code
-     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested for a mismatch - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return the relative index of the first mismatch between the two arrays - * over the specified ranges, otherwise {@code -1}. - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(byte[] a, int aFromIndex, int aToIndex, - byte[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - length); - return (i < 0 && aLength != bLength) ? length : i; - } - - // Mismatch char - - /** - * Finds and returns the index of the first mismatch between two {@code char} - * arrays, otherwise return -1 if no mismatch is found. The index will be - * in the range of 0 (inclusive) up to the length (inclusive) of the smaller - * array. - * - *

If the two arrays share a common prefix then the returned index is the - * length of the common prefix and it follows that there is a mismatch - * between the two elements at that index within the respective arrays. - * If one array is a proper prefix of the other then the returned index is - * the length of the smaller array and it follows that the index is only - * valid for the larger array. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(a.length, b.length) &&
-     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
-     *     a[pl] != b[pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper - * prefix if the following expression is true: - *

{@code
-     *     a.length != b.length &&
-     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
-     *                   b, 0, Math.min(a.length, b.length))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param b the second array to be tested for a mismatch - * @return the index of the first mismatch between the two arrays, - * otherwise {@code -1}. - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(char[] a, char[] b) { - int length = Math.min(a.length, b.length); // Check null array refs - if (a == b) - return -1; - - int i = ArraysSupport.mismatch(a, b, length); - return (i < 0 && a.length != b.length) ? length : i; - } - - /** - * Finds and returns the relative index of the first mismatch between two - * {@code char} arrays over the specified ranges, otherwise return -1 if no - * mismatch is found. The index will be in the range of 0 (inclusive) up to - * the length (inclusive) of the smaller range. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the returned relative index is the length of the common prefix and - * it follows that there is a mismatch between the two elements at that - * relative index within the respective arrays. - * If one array is a proper prefix of the other, over the specified ranges, - * then the returned relative index is the length of the smaller range and - * it follows that the relative index is only valid for the array with the - * larger range. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
-     *     a[aFromIndex + pl] != b[bFromIndex + pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper - * if the following expression is true: - *

{@code
-     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested for a mismatch - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return the relative index of the first mismatch between the two arrays - * over the specified ranges, otherwise {@code -1}. - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(char[] a, int aFromIndex, int aToIndex, - char[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - length); - return (i < 0 && aLength != bLength) ? length : i; - } - - // Mismatch short - - /** - * Finds and returns the index of the first mismatch between two {@code short} - * arrays, otherwise return -1 if no mismatch is found. The index will be - * in the range of 0 (inclusive) up to the length (inclusive) of the smaller - * array. - * - *

If the two arrays share a common prefix then the returned index is the - * length of the common prefix and it follows that there is a mismatch - * between the two elements at that index within the respective arrays. - * If one array is a proper prefix of the other then the returned index is - * the length of the smaller array and it follows that the index is only - * valid for the larger array. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(a.length, b.length) &&
-     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
-     *     a[pl] != b[pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper - * prefix if the following expression is true: - *

{@code
-     *     a.length != b.length &&
-     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
-     *                   b, 0, Math.min(a.length, b.length))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param b the second array to be tested for a mismatch - * @return the index of the first mismatch between the two arrays, - * otherwise {@code -1}. - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(short[] a, short[] b) { - int length = Math.min(a.length, b.length); // Check null array refs - if (a == b) - return -1; - - int i = ArraysSupport.mismatch(a, b, length); - return (i < 0 && a.length != b.length) ? length : i; - } - - /** - * Finds and returns the relative index of the first mismatch between two - * {@code short} arrays over the specified ranges, otherwise return -1 if no - * mismatch is found. The index will be in the range of 0 (inclusive) up to - * the length (inclusive) of the smaller range. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the returned relative index is the length of the common prefix and - * it follows that there is a mismatch between the two elements at that - * relative index within the respective arrays. - * If one array is a proper prefix of the other, over the specified ranges, - * then the returned relative index is the length of the smaller range and - * it follows that the relative index is only valid for the array with the - * larger range. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
-     *     a[aFromIndex + pl] != b[bFromIndex + pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper - * if the following expression is true: - *

{@code
-     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested for a mismatch - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return the relative index of the first mismatch between the two arrays - * over the specified ranges, otherwise {@code -1}. - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(short[] a, int aFromIndex, int aToIndex, - short[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - length); - return (i < 0 && aLength != bLength) ? length : i; - } - - // Mismatch int - - /** - * Finds and returns the index of the first mismatch between two {@code int} - * arrays, otherwise return -1 if no mismatch is found. The index will be - * in the range of 0 (inclusive) up to the length (inclusive) of the smaller - * array. - * - *

If the two arrays share a common prefix then the returned index is the - * length of the common prefix and it follows that there is a mismatch - * between the two elements at that index within the respective arrays. - * If one array is a proper prefix of the other then the returned index is - * the length of the smaller array and it follows that the index is only - * valid for the larger array. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(a.length, b.length) &&
-     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
-     *     a[pl] != b[pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper - * prefix if the following expression is true: - *

{@code
-     *     a.length != b.length &&
-     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
-     *                   b, 0, Math.min(a.length, b.length))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param b the second array to be tested for a mismatch - * @return the index of the first mismatch between the two arrays, - * otherwise {@code -1}. - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(int[] a, int[] b) { - int length = Math.min(a.length, b.length); // Check null array refs - if (a == b) - return -1; - - int i = ArraysSupport.mismatch(a, b, length); - return (i < 0 && a.length != b.length) ? length : i; - } - - /** - * Finds and returns the relative index of the first mismatch between two - * {@code int} arrays over the specified ranges, otherwise return -1 if no - * mismatch is found. The index will be in the range of 0 (inclusive) up to - * the length (inclusive) of the smaller range. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the returned relative index is the length of the common prefix and - * it follows that there is a mismatch between the two elements at that - * relative index within the respective arrays. - * If one array is a proper prefix of the other, over the specified ranges, - * then the returned relative index is the length of the smaller range and - * it follows that the relative index is only valid for the array with the - * larger range. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
-     *     a[aFromIndex + pl] != b[bFromIndex + pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper - * if the following expression is true: - *

{@code
-     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested for a mismatch - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return the relative index of the first mismatch between the two arrays - * over the specified ranges, otherwise {@code -1}. - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(int[] a, int aFromIndex, int aToIndex, - int[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - length); - return (i < 0 && aLength != bLength) ? length : i; - } - - // Mismatch long - - /** - * Finds and returns the index of the first mismatch between two {@code long} - * arrays, otherwise return -1 if no mismatch is found. The index will be - * in the range of 0 (inclusive) up to the length (inclusive) of the smaller - * array. - * - *

If the two arrays share a common prefix then the returned index is the - * length of the common prefix and it follows that there is a mismatch - * between the two elements at that index within the respective arrays. - * If one array is a proper prefix of the other then the returned index is - * the length of the smaller array and it follows that the index is only - * valid for the larger array. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(a.length, b.length) &&
-     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
-     *     a[pl] != b[pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper - * prefix if the following expression is true: - *

{@code
-     *     a.length != b.length &&
-     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
-     *                   b, 0, Math.min(a.length, b.length))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param b the second array to be tested for a mismatch - * @return the index of the first mismatch between the two arrays, - * otherwise {@code -1}. - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(long[] a, long[] b) { - int length = Math.min(a.length, b.length); // Check null array refs - if (a == b) - return -1; - - int i = ArraysSupport.mismatch(a, b, length); - return (i < 0 && a.length != b.length) ? length : i; - } - - /** - * Finds and returns the relative index of the first mismatch between two - * {@code long} arrays over the specified ranges, otherwise return -1 if no - * mismatch is found. The index will be in the range of 0 (inclusive) up to - * the length (inclusive) of the smaller range. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the returned relative index is the length of the common prefix and - * it follows that there is a mismatch between the two elements at that - * relative index within the respective arrays. - * If one array is a proper prefix of the other, over the specified ranges, - * then the returned relative index is the length of the smaller range and - * it follows that the relative index is only valid for the array with the - * larger range. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
-     *     a[aFromIndex + pl] != b[bFromIndex + pl]
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper - * if the following expression is true: - *

{@code
-     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested for a mismatch - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return the relative index of the first mismatch between the two arrays - * over the specified ranges, otherwise {@code -1}. - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(long[] a, int aFromIndex, int aToIndex, - long[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - length); - return (i < 0 && aLength != bLength) ? length : i; - } - - // Mismatch float - - /** - * Finds and returns the index of the first mismatch between two {@code float} - * arrays, otherwise return -1 if no mismatch is found. The index will be - * in the range of 0 (inclusive) up to the length (inclusive) of the smaller - * array. - * - *

If the two arrays share a common prefix then the returned index is the - * length of the common prefix and it follows that there is a mismatch - * between the two elements at that index within the respective arrays. - * If one array is a proper prefix of the other then the returned index is - * the length of the smaller array and it follows that the index is only - * valid for the larger array. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(a.length, b.length) &&
-     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
-     *     Float.compare(a[pl], b[pl]) != 0
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper - * prefix if the following expression is true: - *

{@code
-     *     a.length != b.length &&
-     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
-     *                   b, 0, Math.min(a.length, b.length))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param b the second array to be tested for a mismatch - * @return the index of the first mismatch between the two arrays, - * otherwise {@code -1}. - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(float[] a, float[] b) { - int length = Math.min(a.length, b.length); // Check null array refs - if (a == b) - return -1; - - int i = ArraysSupport.mismatch(a, b, length); - return (i < 0 && a.length != b.length) ? length : i; - } - - /** - * Finds and returns the relative index of the first mismatch between two - * {@code float} arrays over the specified ranges, otherwise return -1 if no - * mismatch is found. The index will be in the range of 0 (inclusive) up to - * the length (inclusive) of the smaller range. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the returned relative index is the length of the common prefix and - * it follows that there is a mismatch between the two elements at that - * relative index within the respective arrays. - * If one array is a proper prefix of the other, over the specified ranges, - * then the returned relative index is the length of the smaller range and - * it follows that the relative index is only valid for the array with the - * larger range. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
-     *     Float.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper - * if the following expression is true: - *

{@code
-     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested for a mismatch - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return the relative index of the first mismatch between the two arrays - * over the specified ranges, otherwise {@code -1}. - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(float[] a, int aFromIndex, int aToIndex, - float[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - length); - return (i < 0 && aLength != bLength) ? length : i; - } - - // Mismatch double - - /** - * Finds and returns the index of the first mismatch between two - * {@code double} arrays, otherwise return -1 if no mismatch is found. The - * index will be in the range of 0 (inclusive) up to the length (inclusive) - * of the smaller array. - * - *

If the two arrays share a common prefix then the returned index is the - * length of the common prefix and it follows that there is a mismatch - * between the two elements at that index within the respective arrays. - * If one array is a proper prefix of the other then the returned index is - * the length of the smaller array and it follows that the index is only - * valid for the larger array. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(a.length, b.length) &&
-     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
-     *     Double.compare(a[pl], b[pl]) != 0
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper - * prefix if the following expression is true: - *

{@code
-     *     a.length != b.length &&
-     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
-     *                   b, 0, Math.min(a.length, b.length))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param b the second array to be tested for a mismatch - * @return the index of the first mismatch between the two arrays, - * otherwise {@code -1}. - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(double[] a, double[] b) { - int length = Math.min(a.length, b.length); // Check null array refs - if (a == b) - return -1; - - int i = ArraysSupport.mismatch(a, b, length); - return (i < 0 && a.length != b.length) ? length : i; - } - - /** - * Finds and returns the relative index of the first mismatch between two - * {@code double} arrays over the specified ranges, otherwise return -1 if - * no mismatch is found. The index will be in the range of 0 (inclusive) up - * to the length (inclusive) of the smaller range. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the returned relative index is the length of the common prefix and - * it follows that there is a mismatch between the two elements at that - * relative index within the respective arrays. - * If one array is a proper prefix of the other, over the specified ranges, - * then the returned relative index is the length of the smaller range and - * it follows that the relative index is only valid for the array with the - * larger range. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
-     *     Double.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper - * if the following expression is true: - *

{@code
-     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested for a mismatch - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return the relative index of the first mismatch between the two arrays - * over the specified ranges, otherwise {@code -1}. - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(double[] a, int aFromIndex, int aToIndex, - double[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - int i = ArraysSupport.mismatch(a, aFromIndex, - b, bFromIndex, - length); - return (i < 0 && aLength != bLength) ? length : i; - } - - // Mismatch objects - - /** - * Finds and returns the index of the first mismatch between two - * {@code Object} arrays, otherwise return -1 if no mismatch is found. The - * index will be in the range of 0 (inclusive) up to the length (inclusive) - * of the smaller array. - * - *

If the two arrays share a common prefix then the returned index is the - * length of the common prefix and it follows that there is a mismatch - * between the two elements at that index within the respective arrays. - * If one array is a proper prefix of the other then the returned index is - * the length of the smaller array and it follows that the index is only - * valid for the larger array. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(a.length, b.length) &&
-     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
-     *     !Objects.equals(a[pl], b[pl])
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper - * prefix if the following expression is true: - *

{@code
-     *     a.length != b.length &&
-     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
-     *                   b, 0, Math.min(a.length, b.length))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param b the second array to be tested for a mismatch - * @return the index of the first mismatch between the two arrays, - * otherwise {@code -1}. - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch(Object[] a, Object[] b) { - int length = Math.min(a.length, b.length); // Check null array refs - if (a == b) - return -1; - - for (int i = 0; i < length; i++) { - if (!Objects.equals(a[i], b[i])) - return i; - } - - return a.length != b.length ? length : -1; - } - - /** - * Finds and returns the relative index of the first mismatch between two - * {@code Object} arrays over the specified ranges, otherwise return -1 if - * no mismatch is found. The index will be in the range of 0 (inclusive) up - * to the length (inclusive) of the smaller range. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the returned relative index is the length of the common prefix and - * it follows that there is a mismatch between the two elements at that - * relative index within the respective arrays. - * If one array is a proper prefix of the other, over the specified ranges, - * then the returned relative index is the length of the smaller range and - * it follows that the relative index is only valid for the array with the - * larger range. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
-     *     !Objects.equals(a[aFromIndex + pl], b[bFromIndex + pl])
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper - * if the following expression is true: - *

{@code
-     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested for a mismatch - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @return the relative index of the first mismatch between the two arrays - * over the specified ranges, otherwise {@code -1}. - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array is {@code null} - * @since 9 - */ - public static int mismatch( - Object[] a, int aFromIndex, int aToIndex, - Object[] b, int bFromIndex, int bToIndex) { - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - for (int i = 0; i < length; i++) { - if (!Objects.equals(a[aFromIndex++], b[bFromIndex++])) - return i; - } - - return aLength != bLength ? length : -1; - } - - /** - * Finds and returns the index of the first mismatch between two - * {@code Object} arrays, otherwise return -1 if no mismatch is found. - * The index will be in the range of 0 (inclusive) up to the length - * (inclusive) of the smaller array. - * - *

The specified comparator is used to determine if two array elements - * from the each array are not equal. - * - *

If the two arrays share a common prefix then the returned index is the - * length of the common prefix and it follows that there is a mismatch - * between the two elements at that index within the respective arrays. - * If one array is a proper prefix of the other then the returned index is - * the length of the smaller array and it follows that the index is only - * valid for the larger array. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(a.length, b.length) &&
-     *     Arrays.equals(a, 0, pl, b, 0, pl, cmp)
-     *     cmp.compare(a[pl], b[pl]) != 0
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper - * prefix if the following expression is true: - *

{@code
-     *     a.length != b.length &&
-     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
-     *                   b, 0, Math.min(a.length, b.length),
-     *                   cmp)
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param b the second array to be tested for a mismatch - * @param cmp the comparator to compare array elements - * @param the type of array elements - * @return the index of the first mismatch between the two arrays, - * otherwise {@code -1}. - * @throws NullPointerException - * if either array or the comparator is {@code null} - * @since 9 - */ - public static int mismatch(T[] a, T[] b, Comparator cmp) { - Objects.requireNonNull(cmp); - int length = Math.min(a.length, b.length); // Check null array refs - if (a == b) - return -1; - - for (int i = 0; i < length; i++) { - T oa = a[i]; - T ob = b[i]; - if (oa != ob) { - // Null-value comparison is deferred to the comparator - int v = cmp.compare(oa, ob); - if (v != 0) { - return i; - } - } - } - - return a.length != b.length ? length : -1; - } - - /** - * Finds and returns the relative index of the first mismatch between two - * {@code Object} arrays over the specified ranges, otherwise return -1 if - * no mismatch is found. The index will be in the range of 0 (inclusive) up - * to the length (inclusive) of the smaller range. - * - *

If the two arrays, over the specified ranges, share a common prefix - * then the returned relative index is the length of the common prefix and - * it follows that there is a mismatch between the two elements at that - * relative index within the respective arrays. - * If one array is a proper prefix of the other, over the specified ranges, - * then the returned relative index is the length of the smaller range and - * it follows that the relative index is only valid for the array with the - * larger range. - * Otherwise, there is no mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common - * prefix of length {@code pl} if the following expression is true: - *

{@code
-     *     pl >= 0 &&
-     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl, cmp) &&
-     *     cmp.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
-     * }
- * Note that a common prefix length of {@code 0} indicates that the first - * elements from each array mismatch. - * - *

Two non-{@code null} arrays, {@code a} and {@code b} with specified - * ranges [{@code aFromIndex}, {@code atoIndex}) and - * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper - * if the following expression is true: - *

{@code
-     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
-     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
-     *                   cmp)
-     * }
- * - * @param a the first array to be tested for a mismatch - * @param aFromIndex the index (inclusive) of the first element in the - * first array to be tested - * @param aToIndex the index (exclusive) of the last element in the - * first array to be tested - * @param b the second array to be tested for a mismatch - * @param bFromIndex the index (inclusive) of the first element in the - * second array to be tested - * @param bToIndex the index (exclusive) of the last element in the - * second array to be tested - * @param cmp the comparator to compare array elements - * @param the type of array elements - * @return the relative index of the first mismatch between the two arrays - * over the specified ranges, otherwise {@code -1}. - * @throws IllegalArgumentException - * if {@code aFromIndex > aToIndex} or - * if {@code bFromIndex > bToIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code aFromIndex < 0 or aToIndex > a.length} or - * if {@code bFromIndex < 0 or bToIndex > b.length} - * @throws NullPointerException - * if either array or the comparator is {@code null} - * @since 9 - */ - public static int mismatch( - T[] a, int aFromIndex, int aToIndex, - T[] b, int bFromIndex, int bToIndex, - Comparator cmp) { - Objects.requireNonNull(cmp); - rangeCheck(a.length, aFromIndex, aToIndex); - rangeCheck(b.length, bFromIndex, bToIndex); - - int aLength = aToIndex - aFromIndex; - int bLength = bToIndex - bFromIndex; - int length = Math.min(aLength, bLength); - for (int i = 0; i < length; i++) { - T oa = a[aFromIndex++]; - T ob = b[bFromIndex++]; - if (oa != ob) { - // Null-value comparison is deferred to the comparator - int v = cmp.compare(oa, ob); - if (v != 0) { - return i; - } - } - } - - return aLength != bLength ? length : -1; - } -} +/* + * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import jdk.internal.HotSpotIntrinsicCandidate; +import jdk.internal.util.ArraysSupport; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.util.concurrent.ForkJoinPool; +import java.util.function.BinaryOperator; +import java.util.function.Consumer; +import java.util.function.DoubleBinaryOperator; +import java.util.function.IntBinaryOperator; +import java.util.function.IntFunction; +import java.util.function.IntToDoubleFunction; +import java.util.function.IntToLongFunction; +import java.util.function.IntUnaryOperator; +import java.util.function.LongBinaryOperator; +import java.util.function.UnaryOperator; +import java.util.stream.DoubleStream; +import java.util.stream.IntStream; +import java.util.stream.LongStream; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * This class contains various methods for manipulating arrays (such as + * sorting and searching). This class also contains a static factory + * that allows arrays to be viewed as lists. + * + *

The methods in this class all throw a {@code NullPointerException}, + * if the specified array reference is null, except where noted. + * + *

The documentation for the methods contained in this class includes + * brief descriptions of the implementations. Such descriptions should + * be regarded as implementation notes, rather than parts of the + * specification. Implementors should feel free to substitute other + * algorithms, so long as the specification itself is adhered to. (For + * example, the algorithm used by {@code sort(Object[])} does not have to be + * a MergeSort, but it does have to be stable.) + * + *

This class is a member of the + * + * Java Collections Framework. + * + * @author Josh Bloch + * @author Neal Gafter + * @author John Rose + * @since 1.2 + */ +public class Arrays { + + // Suppresses default constructor, ensuring non-instantiability. + private Arrays() {} + + /* + * Sorting methods. Note that all public "sort" methods take the + * same form: performing argument checks if necessary, and then + * expanding arguments into those required for the internal + * implementation methods residing in other package-private + * classes (except for legacyMergeSort, included in this class). + */ + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(int[] a) { + DualPivotQuicksort.sort(a, 0, 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(int[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, 0, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(long[] a) { + DualPivotQuicksort.sort(a, 0, 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(long[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, 0, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(byte[] a) { + DualPivotQuicksort.sort(a, 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(byte[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(char[] a) { + DualPivotQuicksort.sort(a, 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(char[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(short[] a) { + DualPivotQuicksort.sort(a, 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(short[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(float[] a) { + DualPivotQuicksort.sort(a, 0, 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(float[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, 0, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + */ + public static void sort(double[] a) { + DualPivotQuicksort.sort(a, 0, 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending order. The range + * to be sorted extends from the index {@code fromIndex}, inclusive, to + * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, + * the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + */ + public static void sort(double[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, 0, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(int[] a) { + DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(int[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(long[] a) { + DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(long[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(byte[] a) { + DualPivotQuicksort.sort(a, 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(byte[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(char[] a) { + DualPivotQuicksort.sort(a, 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(char[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(short[] a) { + DualPivotQuicksort.sort(a, 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(short[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(float[] a) { + DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all float + * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Float#compareTo}: {@code -0.0f} is treated as less than value + * {@code 0.0f} and {@code Float.NaN} is considered greater than any + * other value and all {@code Float.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(float[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), fromIndex, toIndex); + } + + /** + * Sorts the specified array into ascending numerical order. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * + * @since 1.8 + */ + public static void parallelSort(double[] a) { + DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), 0, a.length); + } + + /** + * Sorts the specified range of the array into ascending numerical order. + * The range to be sorted extends from the index {@code fromIndex}, + * inclusive, to the index {@code toIndex}, exclusive. If + * {@code fromIndex == toIndex}, the range to be sorted is empty. + * + *

The {@code <} relation does not provide a total order on all double + * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} + * value compares neither less than, greater than, nor equal to any value, + * even itself. This method uses the total order imposed by the method + * {@link Double#compareTo}: {@code -0.0d} is treated as less than value + * {@code 0.0d} and {@code Double.NaN} is considered greater than any + * other value and all {@code Double.NaN} values are considered equal. + * + * @implNote The sorting algorithm is a Dual-Pivot Quicksort by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically + * faster than traditional (one-pivot) Quicksort implementations. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element, inclusive, to be sorted + * @param toIndex the index of the last element, exclusive, to be sorted + * + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > a.length} + * + * @since 1.8 + */ + public static void parallelSort(double[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + DualPivotQuicksort.sort(a, ForkJoinPool.getCommonPoolParallelism(), fromIndex, toIndex); + } + + /** + * Checks that {@code fromIndex} and {@code toIndex} are + * in the range and throws an exception if they aren't. + */ + static void rangeCheck(int arrayLength, int fromIndex, int toIndex) { + if (fromIndex > toIndex) { + throw new IllegalArgumentException( + "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); + } + if (fromIndex < 0) { + throw new ArrayIndexOutOfBoundsException(fromIndex); + } + if (toIndex > arrayLength) { + throw new ArrayIndexOutOfBoundsException(toIndex); + } + } + + /** + * A comparator that implements the natural ordering of a group of + * mutually comparable elements. May be used when a supplied + * comparator is null. To simplify code-sharing within underlying + * implementations, the compare method only declares type Object + * for its second argument. + * + * Arrays class implementor's note: It is an empirical matter + * whether ComparableTimSort offers any performance benefit over + * TimSort used with this comparator. If not, you are better off + * deleting or bypassing ComparableTimSort. There is currently no + * empirical case for separating them for parallel sorting, so all + * public Object parallelSort methods use the same comparator + * based implementation. + */ + static final class NaturalOrder implements Comparator { + @SuppressWarnings("unchecked") + public int compare(Object first, Object second) { + return ((Comparable)first).compareTo(second); + } + static final NaturalOrder INSTANCE = new NaturalOrder(); + } + + /** + * The minimum array length below which a parallel sorting + * algorithm will not further partition the sorting task. Using + * smaller sizes typically results in memory contention across + * tasks that makes parallel speedups unlikely. + */ + private static final int MIN_ARRAY_SORT_GRAN = 1 << 13; + + /** + * Sorts the specified array of objects into ascending order, according + * to the {@linkplain Comparable natural ordering} of its elements. + * All elements in the array must implement the {@link Comparable} + * interface. Furthermore, all elements in the array must be + * mutually comparable (that is, {@code e1.compareTo(e2)} must + * not throw a {@code ClassCastException} for any elements {@code e1} + * and {@code e2} in the array). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param the class of the objects to be sorted + * @param a the array to be sorted + * + * @throws ClassCastException if the array contains elements that are not + * mutually comparable (for example, strings and integers) + * @throws IllegalArgumentException (optional) if the natural + * ordering of the array elements is found to violate the + * {@link Comparable} contract + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static > void parallelSort(T[] a) { + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + TimSort.sort(a, 0, n, NaturalOrder.INSTANCE, null, 0, 0); + else + new ArraysParallelSortHelpers.FJObject.Sorter<> + (null, a, + (T[])Array.newInstance(a.getClass().getComponentType(), n), + 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke(); + } + + /** + * Sorts the specified range of the specified array of objects into + * ascending order, according to the + * {@linkplain Comparable natural ordering} of its + * elements. The range to be sorted extends from index + * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive. + * (If {@code fromIndex==toIndex}, the range to be sorted is empty.) All + * elements in this range must implement the {@link Comparable} + * interface. Furthermore, all elements in this range must be mutually + * comparable (that is, {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the array). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param the class of the objects to be sorted + * @param a the array to be sorted + * @param fromIndex the index of the first element (inclusive) to be + * sorted + * @param toIndex the index of the last element (exclusive) to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} or + * (optional) if the natural ordering of the array elements is + * found to violate the {@link Comparable} contract + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + * @throws ClassCastException if the array contains elements that are + * not mutually comparable (for example, strings and + * integers). + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static > + void parallelSort(T[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + TimSort.sort(a, fromIndex, toIndex, NaturalOrder.INSTANCE, null, 0, 0); + else + new ArraysParallelSortHelpers.FJObject.Sorter<> + (null, a, + (T[])Array.newInstance(a.getClass().getComponentType(), n), + fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g, NaturalOrder.INSTANCE).invoke(); + } + + /** + * Sorts the specified array of objects according to the order induced by + * the specified comparator. All elements in the array must be + * mutually comparable by the specified comparator (that is, + * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} + * for any elements {@code e1} and {@code e2} in the array). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a + * working space no greater than the size of the original array. The + * {@link ForkJoinPool#commonPool() ForkJoin common pool} is used to + * execute any parallel tasks. + * + * @param the class of the objects to be sorted + * @param a the array to be sorted + * @param cmp the comparator to determine the order of the array. A + * {@code null} value indicates that the elements' + * {@linkplain Comparable natural ordering} should be used. + * @throws ClassCastException if the array contains elements that are + * not mutually comparable using the specified comparator + * @throws IllegalArgumentException (optional) if the comparator is + * found to violate the {@link java.util.Comparator} contract + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static void parallelSort(T[] a, Comparator cmp) { + if (cmp == null) + cmp = NaturalOrder.INSTANCE; + int n = a.length, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + TimSort.sort(a, 0, n, cmp, null, 0, 0); + else + new ArraysParallelSortHelpers.FJObject.Sorter<> + (null, a, + (T[])Array.newInstance(a.getClass().getComponentType(), n), + 0, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g, cmp).invoke(); + } + + /** + * Sorts the specified range of the specified array of objects according + * to the order induced by the specified comparator. The range to be + * sorted extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be sorted is empty.) All elements in the range must be + * mutually comparable by the specified comparator (that is, + * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} + * for any elements {@code e1} and {@code e2} in the range). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + * @implNote The sorting algorithm is a parallel sort-merge that breaks the + * array into sub-arrays that are themselves sorted and then merged. When + * the sub-array length reaches a minimum granularity, the sub-array is + * sorted using the appropriate {@link Arrays#sort(Object[]) Arrays.sort} + * method. If the length of the specified array is less than the minimum + * granularity, then it is sorted using the appropriate {@link + * Arrays#sort(Object[]) Arrays.sort} method. The algorithm requires a working + * space no greater than the size of the specified range of the original + * array. The {@link ForkJoinPool#commonPool() ForkJoin common pool} is + * used to execute any parallel tasks. + * + * @param the class of the objects to be sorted + * @param a the array to be sorted + * @param fromIndex the index of the first element (inclusive) to be + * sorted + * @param toIndex the index of the last element (exclusive) to be sorted + * @param cmp the comparator to determine the order of the array. A + * {@code null} value indicates that the elements' + * {@linkplain Comparable natural ordering} should be used. + * @throws IllegalArgumentException if {@code fromIndex > toIndex} or + * (optional) if the natural ordering of the array elements is + * found to violate the {@link Comparable} contract + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + * @throws ClassCastException if the array contains elements that are + * not mutually comparable (for example, strings and + * integers). + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static void parallelSort(T[] a, int fromIndex, int toIndex, + Comparator cmp) { + rangeCheck(a.length, fromIndex, toIndex); + if (cmp == null) + cmp = NaturalOrder.INSTANCE; + int n = toIndex - fromIndex, p, g; + if (n <= MIN_ARRAY_SORT_GRAN || + (p = ForkJoinPool.getCommonPoolParallelism()) == 1) + TimSort.sort(a, fromIndex, toIndex, cmp, null, 0, 0); + else + new ArraysParallelSortHelpers.FJObject.Sorter<> + (null, a, + (T[])Array.newInstance(a.getClass().getComponentType(), n), + fromIndex, n, 0, ((g = n / (p << 2)) <= MIN_ARRAY_SORT_GRAN) ? + MIN_ARRAY_SORT_GRAN : g, cmp).invoke(); + } + + /* + * Sorting of complex type arrays. + */ + + /** + * Old merge sort implementation can be selected (for + * compatibility with broken comparators) using a system property. + * Cannot be a static boolean in the enclosing class due to + * circular dependencies. To be removed in a future release. + */ + static final class LegacyMergeSort { + private static final boolean userRequested = + java.security.AccessController.doPrivileged( + new sun.security.action.GetBooleanAction( + "java.util.Arrays.useLegacyMergeSort")).booleanValue(); + } + + /** + * Sorts the specified array of objects into ascending order, according + * to the {@linkplain Comparable natural ordering} of its elements. + * All elements in the array must implement the {@link Comparable} + * interface. Furthermore, all elements in the array must be + * mutually comparable (that is, {@code e1.compareTo(e2)} must + * not throw a {@code ClassCastException} for any elements {@code e1} + * and {@code e2} in the array). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + *

Implementation note: This implementation is a stable, adaptive, + * iterative mergesort that requires far fewer than n lg(n) comparisons + * when the input array is partially sorted, while offering the + * performance of a traditional mergesort when the input array is + * randomly ordered. If the input array is nearly sorted, the + * implementation requires approximately n comparisons. Temporary + * storage requirements vary from a small constant for nearly sorted + * input arrays to n/2 object references for randomly ordered input + * arrays. + * + *

The implementation takes equal advantage of ascending and + * descending order in its input array, and can take advantage of + * ascending and descending order in different parts of the same + * input array. It is well-suited to merging two or more sorted arrays: + * simply concatenate the arrays and sort the resulting array. + * + *

The implementation was adapted from Tim Peters's list sort for Python + * ( + * TimSort). It uses techniques from Peter McIlroy's "Optimistic + * Sorting and Information Theoretic Complexity", in Proceedings of the + * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, + * January 1993. + * + * @param a the array to be sorted + * @throws ClassCastException if the array contains elements that are not + * mutually comparable (for example, strings and integers) + * @throws IllegalArgumentException (optional) if the natural + * ordering of the array elements is found to violate the + * {@link Comparable} contract + */ + public static void sort(Object[] a) { + if (LegacyMergeSort.userRequested) + legacyMergeSort(a); + else + ComparableTimSort.sort(a, 0, a.length, null, 0, 0); + } + + /** To be removed in a future release. */ + private static void legacyMergeSort(Object[] a) { + Object[] aux = a.clone(); + mergeSort(aux, a, 0, a.length, 0); + } + + /** + * Sorts the specified range of the specified array of objects into + * ascending order, according to the + * {@linkplain Comparable natural ordering} of its + * elements. The range to be sorted extends from index + * {@code fromIndex}, inclusive, to index {@code toIndex}, exclusive. + * (If {@code fromIndex==toIndex}, the range to be sorted is empty.) All + * elements in this range must implement the {@link Comparable} + * interface. Furthermore, all elements in this range must be mutually + * comparable (that is, {@code e1.compareTo(e2)} must not throw a + * {@code ClassCastException} for any elements {@code e1} and + * {@code e2} in the array). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + *

Implementation note: This implementation is a stable, adaptive, + * iterative mergesort that requires far fewer than n lg(n) comparisons + * when the input array is partially sorted, while offering the + * performance of a traditional mergesort when the input array is + * randomly ordered. If the input array is nearly sorted, the + * implementation requires approximately n comparisons. Temporary + * storage requirements vary from a small constant for nearly sorted + * input arrays to n/2 object references for randomly ordered input + * arrays. + * + *

The implementation takes equal advantage of ascending and + * descending order in its input array, and can take advantage of + * ascending and descending order in different parts of the same + * input array. It is well-suited to merging two or more sorted arrays: + * simply concatenate the arrays and sort the resulting array. + * + *

The implementation was adapted from Tim Peters's list sort for Python + * ( + * TimSort). It uses techniques from Peter McIlroy's "Optimistic + * Sorting and Information Theoretic Complexity", in Proceedings of the + * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, + * January 1993. + * + * @param a the array to be sorted + * @param fromIndex the index of the first element (inclusive) to be + * sorted + * @param toIndex the index of the last element (exclusive) to be sorted + * @throws IllegalArgumentException if {@code fromIndex > toIndex} or + * (optional) if the natural ordering of the array elements is + * found to violate the {@link Comparable} contract + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + * @throws ClassCastException if the array contains elements that are + * not mutually comparable (for example, strings and + * integers). + */ + public static void sort(Object[] a, int fromIndex, int toIndex) { + rangeCheck(a.length, fromIndex, toIndex); + if (LegacyMergeSort.userRequested) + legacyMergeSort(a, fromIndex, toIndex); + else + ComparableTimSort.sort(a, fromIndex, toIndex, null, 0, 0); + } + + /** To be removed in a future release. */ + private static void legacyMergeSort(Object[] a, + int fromIndex, int toIndex) { + Object[] aux = copyOfRange(a, fromIndex, toIndex); + mergeSort(aux, a, fromIndex, toIndex, -fromIndex); + } + + /** + * Tuning parameter: list size at or below which insertion sort will be + * used in preference to mergesort. + * To be removed in a future release. + */ + private static final int INSERTIONSORT_THRESHOLD = 7; + + /** + * Src is the source array that starts at index 0 + * Dest is the (possibly larger) array destination with a possible offset + * low is the index in dest to start sorting + * high is the end index in dest to end sorting + * off is the offset to generate corresponding low, high in src + * To be removed in a future release. + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + private static void mergeSort(Object[] src, + Object[] dest, + int low, + int high, + int off) { + int length = high - low; + + // Insertion sort on smallest arrays + if (length < INSERTIONSORT_THRESHOLD) { + for (int i=low; ilow && + ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--) + swap(dest, j, j-1); + return; + } + + // Recursively sort halves of dest into src + int destLow = low; + int destHigh = high; + low += off; + high += off; + int mid = (low + high) >>> 1; + mergeSort(dest, src, low, mid, -off); + mergeSort(dest, src, mid, high, -off); + + // If list is already sorted, just copy from src to dest. This is an + // optimization that results in faster sorts for nearly ordered lists. + if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) { + System.arraycopy(src, low, dest, destLow, length); + return; + } + + // Merge sorted halves (now in src) into dest + for(int i = destLow, p = low, q = mid; i < destHigh; i++) { + if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0) + dest[i] = src[p++]; + else + dest[i] = src[q++]; + } + } + + /** + * Swaps x[a] with x[b]. + */ + private static void swap(Object[] x, int a, int b) { + Object t = x[a]; + x[a] = x[b]; + x[b] = t; + } + + /** + * Sorts the specified array of objects according to the order induced by + * the specified comparator. All elements in the array must be + * mutually comparable by the specified comparator (that is, + * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} + * for any elements {@code e1} and {@code e2} in the array). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + *

Implementation note: This implementation is a stable, adaptive, + * iterative mergesort that requires far fewer than n lg(n) comparisons + * when the input array is partially sorted, while offering the + * performance of a traditional mergesort when the input array is + * randomly ordered. If the input array is nearly sorted, the + * implementation requires approximately n comparisons. Temporary + * storage requirements vary from a small constant for nearly sorted + * input arrays to n/2 object references for randomly ordered input + * arrays. + * + *

The implementation takes equal advantage of ascending and + * descending order in its input array, and can take advantage of + * ascending and descending order in different parts of the same + * input array. It is well-suited to merging two or more sorted arrays: + * simply concatenate the arrays and sort the resulting array. + * + *

The implementation was adapted from Tim Peters's list sort for Python + * ( + * TimSort). It uses techniques from Peter McIlroy's "Optimistic + * Sorting and Information Theoretic Complexity", in Proceedings of the + * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, + * January 1993. + * + * @param the class of the objects to be sorted + * @param a the array to be sorted + * @param c the comparator to determine the order of the array. A + * {@code null} value indicates that the elements' + * {@linkplain Comparable natural ordering} should be used. + * @throws ClassCastException if the array contains elements that are + * not mutually comparable using the specified comparator + * @throws IllegalArgumentException (optional) if the comparator is + * found to violate the {@link Comparator} contract + */ + public static void sort(T[] a, Comparator c) { + if (c == null) { + sort(a); + } else { + if (LegacyMergeSort.userRequested) + legacyMergeSort(a, c); + else + TimSort.sort(a, 0, a.length, c, null, 0, 0); + } + } + + /** To be removed in a future release. */ + private static void legacyMergeSort(T[] a, Comparator c) { + T[] aux = a.clone(); + if (c==null) + mergeSort(aux, a, 0, a.length, 0); + else + mergeSort(aux, a, 0, a.length, 0, c); + } + + /** + * Sorts the specified range of the specified array of objects according + * to the order induced by the specified comparator. The range to be + * sorted extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be sorted is empty.) All elements in the range must be + * mutually comparable by the specified comparator (that is, + * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException} + * for any elements {@code e1} and {@code e2} in the range). + * + *

This sort is guaranteed to be stable: equal elements will + * not be reordered as a result of the sort. + * + *

Implementation note: This implementation is a stable, adaptive, + * iterative mergesort that requires far fewer than n lg(n) comparisons + * when the input array is partially sorted, while offering the + * performance of a traditional mergesort when the input array is + * randomly ordered. If the input array is nearly sorted, the + * implementation requires approximately n comparisons. Temporary + * storage requirements vary from a small constant for nearly sorted + * input arrays to n/2 object references for randomly ordered input + * arrays. + * + *

The implementation takes equal advantage of ascending and + * descending order in its input array, and can take advantage of + * ascending and descending order in different parts of the same + * input array. It is well-suited to merging two or more sorted arrays: + * simply concatenate the arrays and sort the resulting array. + * + *

The implementation was adapted from Tim Peters's list sort for Python + * ( + * TimSort). It uses techniques from Peter McIlroy's "Optimistic + * Sorting and Information Theoretic Complexity", in Proceedings of the + * Fourth Annual ACM-SIAM Symposium on Discrete Algorithms, pp 467-474, + * January 1993. + * + * @param the class of the objects to be sorted + * @param a the array to be sorted + * @param fromIndex the index of the first element (inclusive) to be + * sorted + * @param toIndex the index of the last element (exclusive) to be sorted + * @param c the comparator to determine the order of the array. A + * {@code null} value indicates that the elements' + * {@linkplain Comparable natural ordering} should be used. + * @throws ClassCastException if the array contains elements that are not + * mutually comparable using the specified comparator. + * @throws IllegalArgumentException if {@code fromIndex > toIndex} or + * (optional) if the comparator is found to violate the + * {@link Comparator} contract + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + */ + public static void sort(T[] a, int fromIndex, int toIndex, + Comparator c) { + if (c == null) { + sort(a, fromIndex, toIndex); + } else { + rangeCheck(a.length, fromIndex, toIndex); + if (LegacyMergeSort.userRequested) + legacyMergeSort(a, fromIndex, toIndex, c); + else + TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0); + } + } + + /** To be removed in a future release. */ + private static void legacyMergeSort(T[] a, int fromIndex, int toIndex, + Comparator c) { + T[] aux = copyOfRange(a, fromIndex, toIndex); + if (c==null) + mergeSort(aux, a, fromIndex, toIndex, -fromIndex); + else + mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c); + } + + /** + * Src is the source array that starts at index 0 + * Dest is the (possibly larger) array destination with a possible offset + * low is the index in dest to start sorting + * high is the end index in dest to end sorting + * off is the offset into src corresponding to low in dest + * To be removed in a future release. + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private static void mergeSort(Object[] src, + Object[] dest, + int low, int high, int off, + Comparator c) { + int length = high - low; + + // Insertion sort on smallest arrays + if (length < INSERTIONSORT_THRESHOLD) { + for (int i=low; ilow && c.compare(dest[j-1], dest[j])>0; j--) + swap(dest, j, j-1); + return; + } + + // Recursively sort halves of dest into src + int destLow = low; + int destHigh = high; + low += off; + high += off; + int mid = (low + high) >>> 1; + mergeSort(dest, src, low, mid, -off, c); + mergeSort(dest, src, mid, high, -off, c); + + // If list is already sorted, just copy from src to dest. This is an + // optimization that results in faster sorts for nearly ordered lists. + if (c.compare(src[mid-1], src[mid]) <= 0) { + System.arraycopy(src, low, dest, destLow, length); + return; + } + + // Merge sorted halves (now in src) into dest + for(int i = destLow, p = low, q = mid; i < destHigh; i++) { + if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0) + dest[i] = src[p++]; + else + dest[i] = src[q++]; + } + } + + // Parallel prefix + + /** + * Cumulates, in parallel, each element of the given array in place, + * using the supplied function. For example if the array initially + * holds {@code [2, 1, 0, 3]} and the operation performs addition, + * then upon return the array holds {@code [2, 3, 3, 6]}. + * Parallel prefix computation is usually more efficient than + * sequential loops for large arrays. + * + * @param the class of the objects in the array + * @param array the array, which is modified in-place by this method + * @param op a side-effect-free, associative function to perform the + * cumulation + * @throws NullPointerException if the specified array or function is null + * @since 1.8 + */ + public static void parallelPrefix(T[] array, BinaryOperator op) { + Objects.requireNonNull(op); + if (array.length > 0) + new ArrayPrefixHelpers.CumulateTask<> + (null, op, array, 0, array.length).invoke(); + } + + /** + * Performs {@link #parallelPrefix(Object[], BinaryOperator)} + * for the given subrange of the array. + * + * @param the class of the objects in the array + * @param array the array + * @param fromIndex the index of the first element, inclusive + * @param toIndex the index of the last element, exclusive + * @param op a side-effect-free, associative function to perform the + * cumulation + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > array.length} + * @throws NullPointerException if the specified array or function is null + * @since 1.8 + */ + public static void parallelPrefix(T[] array, int fromIndex, + int toIndex, BinaryOperator op) { + Objects.requireNonNull(op); + rangeCheck(array.length, fromIndex, toIndex); + if (fromIndex < toIndex) + new ArrayPrefixHelpers.CumulateTask<> + (null, op, array, fromIndex, toIndex).invoke(); + } + + /** + * Cumulates, in parallel, each element of the given array in place, + * using the supplied function. For example if the array initially + * holds {@code [2, 1, 0, 3]} and the operation performs addition, + * then upon return the array holds {@code [2, 3, 3, 6]}. + * Parallel prefix computation is usually more efficient than + * sequential loops for large arrays. + * + * @param array the array, which is modified in-place by this method + * @param op a side-effect-free, associative function to perform the + * cumulation + * @throws NullPointerException if the specified array or function is null + * @since 1.8 + */ + public static void parallelPrefix(long[] array, LongBinaryOperator op) { + Objects.requireNonNull(op); + if (array.length > 0) + new ArrayPrefixHelpers.LongCumulateTask + (null, op, array, 0, array.length).invoke(); + } + + /** + * Performs {@link #parallelPrefix(long[], LongBinaryOperator)} + * for the given subrange of the array. + * + * @param array the array + * @param fromIndex the index of the first element, inclusive + * @param toIndex the index of the last element, exclusive + * @param op a side-effect-free, associative function to perform the + * cumulation + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > array.length} + * @throws NullPointerException if the specified array or function is null + * @since 1.8 + */ + public static void parallelPrefix(long[] array, int fromIndex, + int toIndex, LongBinaryOperator op) { + Objects.requireNonNull(op); + rangeCheck(array.length, fromIndex, toIndex); + if (fromIndex < toIndex) + new ArrayPrefixHelpers.LongCumulateTask + (null, op, array, fromIndex, toIndex).invoke(); + } + + /** + * Cumulates, in parallel, each element of the given array in place, + * using the supplied function. For example if the array initially + * holds {@code [2.0, 1.0, 0.0, 3.0]} and the operation performs addition, + * then upon return the array holds {@code [2.0, 3.0, 3.0, 6.0]}. + * Parallel prefix computation is usually more efficient than + * sequential loops for large arrays. + * + *

Because floating-point operations may not be strictly associative, + * the returned result may not be identical to the value that would be + * obtained if the operation was performed sequentially. + * + * @param array the array, which is modified in-place by this method + * @param op a side-effect-free function to perform the cumulation + * @throws NullPointerException if the specified array or function is null + * @since 1.8 + */ + public static void parallelPrefix(double[] array, DoubleBinaryOperator op) { + Objects.requireNonNull(op); + if (array.length > 0) + new ArrayPrefixHelpers.DoubleCumulateTask + (null, op, array, 0, array.length).invoke(); + } + + /** + * Performs {@link #parallelPrefix(double[], DoubleBinaryOperator)} + * for the given subrange of the array. + * + * @param array the array + * @param fromIndex the index of the first element, inclusive + * @param toIndex the index of the last element, exclusive + * @param op a side-effect-free, associative function to perform the + * cumulation + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > array.length} + * @throws NullPointerException if the specified array or function is null + * @since 1.8 + */ + public static void parallelPrefix(double[] array, int fromIndex, + int toIndex, DoubleBinaryOperator op) { + Objects.requireNonNull(op); + rangeCheck(array.length, fromIndex, toIndex); + if (fromIndex < toIndex) + new ArrayPrefixHelpers.DoubleCumulateTask + (null, op, array, fromIndex, toIndex).invoke(); + } + + /** + * Cumulates, in parallel, each element of the given array in place, + * using the supplied function. For example if the array initially + * holds {@code [2, 1, 0, 3]} and the operation performs addition, + * then upon return the array holds {@code [2, 3, 3, 6]}. + * Parallel prefix computation is usually more efficient than + * sequential loops for large arrays. + * + * @param array the array, which is modified in-place by this method + * @param op a side-effect-free, associative function to perform the + * cumulation + * @throws NullPointerException if the specified array or function is null + * @since 1.8 + */ + public static void parallelPrefix(int[] array, IntBinaryOperator op) { + Objects.requireNonNull(op); + if (array.length > 0) + new ArrayPrefixHelpers.IntCumulateTask + (null, op, array, 0, array.length).invoke(); + } + + /** + * Performs {@link #parallelPrefix(int[], IntBinaryOperator)} + * for the given subrange of the array. + * + * @param array the array + * @param fromIndex the index of the first element, inclusive + * @param toIndex the index of the last element, exclusive + * @param op a side-effect-free, associative function to perform the + * cumulation + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0} or {@code toIndex > array.length} + * @throws NullPointerException if the specified array or function is null + * @since 1.8 + */ + public static void parallelPrefix(int[] array, int fromIndex, + int toIndex, IntBinaryOperator op) { + Objects.requireNonNull(op); + rangeCheck(array.length, fromIndex, toIndex); + if (fromIndex < toIndex) + new ArrayPrefixHelpers.IntCumulateTask + (null, op, array, fromIndex, toIndex).invoke(); + } + + // Searching + + /** + * Searches the specified array of longs for the specified value using the + * binary search algorithm. The array must be sorted (as + * by the {@link #sort(long[])} method) prior to making this call. If it + * is not sorted, the results are undefined. If the array contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element greater than the key, or {@code a.length} if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + */ + public static int binarySearch(long[] a, long key) { + return binarySearch0(a, 0, a.length, key); + } + + /** + * Searches a range of + * the specified array of longs for the specified value using the + * binary search algorithm. + * The range must be sorted (as + * by the {@link #sort(long[], int, int)} method) + * prior to making this call. If it + * is not sorted, the results are undefined. If the range contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param fromIndex the index of the first element (inclusive) to be + * searched + * @param toIndex the index of the last element (exclusive) to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array + * within the specified range; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element in the range greater than the key, + * or {@code toIndex} if all + * elements in the range are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws IllegalArgumentException + * if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0 or toIndex > a.length} + * @since 1.6 + */ + public static int binarySearch(long[] a, int fromIndex, int toIndex, + long key) { + rangeCheck(a.length, fromIndex, toIndex); + return binarySearch0(a, fromIndex, toIndex, key); + } + + // Like public version, but without range checks. + private static int binarySearch0(long[] a, int fromIndex, int toIndex, + long key) { + int low = fromIndex; + int high = toIndex - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + long midVal = a[mid]; + + if (midVal < key) + low = mid + 1; + else if (midVal > key) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found. + } + + /** + * Searches the specified array of ints for the specified value using the + * binary search algorithm. The array must be sorted (as + * by the {@link #sort(int[])} method) prior to making this call. If it + * is not sorted, the results are undefined. If the array contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element greater than the key, or {@code a.length} if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + */ + public static int binarySearch(int[] a, int key) { + return binarySearch0(a, 0, a.length, key); + } + + /** + * Searches a range of + * the specified array of ints for the specified value using the + * binary search algorithm. + * The range must be sorted (as + * by the {@link #sort(int[], int, int)} method) + * prior to making this call. If it + * is not sorted, the results are undefined. If the range contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param fromIndex the index of the first element (inclusive) to be + * searched + * @param toIndex the index of the last element (exclusive) to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array + * within the specified range; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element in the range greater than the key, + * or {@code toIndex} if all + * elements in the range are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws IllegalArgumentException + * if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0 or toIndex > a.length} + * @since 1.6 + */ + public static int binarySearch(int[] a, int fromIndex, int toIndex, + int key) { + rangeCheck(a.length, fromIndex, toIndex); + return binarySearch0(a, fromIndex, toIndex, key); + } + + // Like public version, but without range checks. + private static int binarySearch0(int[] a, int fromIndex, int toIndex, + int key) { + int low = fromIndex; + int high = toIndex - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + int midVal = a[mid]; + + if (midVal < key) + low = mid + 1; + else if (midVal > key) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found. + } + + /** + * Searches the specified array of shorts for the specified value using + * the binary search algorithm. The array must be sorted + * (as by the {@link #sort(short[])} method) prior to making this call. If + * it is not sorted, the results are undefined. If the array contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element greater than the key, or {@code a.length} if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + */ + public static int binarySearch(short[] a, short key) { + return binarySearch0(a, 0, a.length, key); + } + + /** + * Searches a range of + * the specified array of shorts for the specified value using + * the binary search algorithm. + * The range must be sorted + * (as by the {@link #sort(short[], int, int)} method) + * prior to making this call. If + * it is not sorted, the results are undefined. If the range contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param fromIndex the index of the first element (inclusive) to be + * searched + * @param toIndex the index of the last element (exclusive) to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array + * within the specified range; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element in the range greater than the key, + * or {@code toIndex} if all + * elements in the range are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws IllegalArgumentException + * if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0 or toIndex > a.length} + * @since 1.6 + */ + public static int binarySearch(short[] a, int fromIndex, int toIndex, + short key) { + rangeCheck(a.length, fromIndex, toIndex); + return binarySearch0(a, fromIndex, toIndex, key); + } + + // Like public version, but without range checks. + private static int binarySearch0(short[] a, int fromIndex, int toIndex, + short key) { + int low = fromIndex; + int high = toIndex - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + short midVal = a[mid]; + + if (midVal < key) + low = mid + 1; + else if (midVal > key) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found. + } + + /** + * Searches the specified array of chars for the specified value using the + * binary search algorithm. The array must be sorted (as + * by the {@link #sort(char[])} method) prior to making this call. If it + * is not sorted, the results are undefined. If the array contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element greater than the key, or {@code a.length} if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + */ + public static int binarySearch(char[] a, char key) { + return binarySearch0(a, 0, a.length, key); + } + + /** + * Searches a range of + * the specified array of chars for the specified value using the + * binary search algorithm. + * The range must be sorted (as + * by the {@link #sort(char[], int, int)} method) + * prior to making this call. If it + * is not sorted, the results are undefined. If the range contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param fromIndex the index of the first element (inclusive) to be + * searched + * @param toIndex the index of the last element (exclusive) to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array + * within the specified range; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element in the range greater than the key, + * or {@code toIndex} if all + * elements in the range are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws IllegalArgumentException + * if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0 or toIndex > a.length} + * @since 1.6 + */ + public static int binarySearch(char[] a, int fromIndex, int toIndex, + char key) { + rangeCheck(a.length, fromIndex, toIndex); + return binarySearch0(a, fromIndex, toIndex, key); + } + + // Like public version, but without range checks. + private static int binarySearch0(char[] a, int fromIndex, int toIndex, + char key) { + int low = fromIndex; + int high = toIndex - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + char midVal = a[mid]; + + if (midVal < key) + low = mid + 1; + else if (midVal > key) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found. + } + + /** + * Searches the specified array of bytes for the specified value using the + * binary search algorithm. The array must be sorted (as + * by the {@link #sort(byte[])} method) prior to making this call. If it + * is not sorted, the results are undefined. If the array contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element greater than the key, or {@code a.length} if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + */ + public static int binarySearch(byte[] a, byte key) { + return binarySearch0(a, 0, a.length, key); + } + + /** + * Searches a range of + * the specified array of bytes for the specified value using the + * binary search algorithm. + * The range must be sorted (as + * by the {@link #sort(byte[], int, int)} method) + * prior to making this call. If it + * is not sorted, the results are undefined. If the range contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param fromIndex the index of the first element (inclusive) to be + * searched + * @param toIndex the index of the last element (exclusive) to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array + * within the specified range; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element in the range greater than the key, + * or {@code toIndex} if all + * elements in the range are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws IllegalArgumentException + * if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0 or toIndex > a.length} + * @since 1.6 + */ + public static int binarySearch(byte[] a, int fromIndex, int toIndex, + byte key) { + rangeCheck(a.length, fromIndex, toIndex); + return binarySearch0(a, fromIndex, toIndex, key); + } + + // Like public version, but without range checks. + private static int binarySearch0(byte[] a, int fromIndex, int toIndex, + byte key) { + int low = fromIndex; + int high = toIndex - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + byte midVal = a[mid]; + + if (midVal < key) + low = mid + 1; + else if (midVal > key) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found. + } + + /** + * Searches the specified array of doubles for the specified value using + * the binary search algorithm. The array must be sorted + * (as by the {@link #sort(double[])} method) prior to making this call. + * If it is not sorted, the results are undefined. If the array contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. This method considers all NaN values to be + * equivalent and equal. + * + * @param a the array to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element greater than the key, or {@code a.length} if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + */ + public static int binarySearch(double[] a, double key) { + return binarySearch0(a, 0, a.length, key); + } + + /** + * Searches a range of + * the specified array of doubles for the specified value using + * the binary search algorithm. + * The range must be sorted + * (as by the {@link #sort(double[], int, int)} method) + * prior to making this call. + * If it is not sorted, the results are undefined. If the range contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. This method considers all NaN values to be + * equivalent and equal. + * + * @param a the array to be searched + * @param fromIndex the index of the first element (inclusive) to be + * searched + * @param toIndex the index of the last element (exclusive) to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array + * within the specified range; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element in the range greater than the key, + * or {@code toIndex} if all + * elements in the range are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws IllegalArgumentException + * if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0 or toIndex > a.length} + * @since 1.6 + */ + public static int binarySearch(double[] a, int fromIndex, int toIndex, + double key) { + rangeCheck(a.length, fromIndex, toIndex); + return binarySearch0(a, fromIndex, toIndex, key); + } + + // Like public version, but without range checks. + private static int binarySearch0(double[] a, int fromIndex, int toIndex, + double key) { + int low = fromIndex; + int high = toIndex - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + double midVal = a[mid]; + + if (midVal < key) + low = mid + 1; // Neither val is NaN, thisVal is smaller + else if (midVal > key) + high = mid - 1; // Neither val is NaN, thisVal is larger + else { + long midBits = Double.doubleToLongBits(midVal); + long keyBits = Double.doubleToLongBits(key); + if (midBits == keyBits) // Values are equal + return mid; // Key found + else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN) + low = mid + 1; + else // (0.0, -0.0) or (NaN, !NaN) + high = mid - 1; + } + } + return -(low + 1); // key not found. + } + + /** + * Searches the specified array of floats for the specified value using + * the binary search algorithm. The array must be sorted + * (as by the {@link #sort(float[])} method) prior to making this call. If + * it is not sorted, the results are undefined. If the array contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. This method considers all NaN values to be + * equivalent and equal. + * + * @param a the array to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element greater than the key, or {@code a.length} if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + */ + public static int binarySearch(float[] a, float key) { + return binarySearch0(a, 0, a.length, key); + } + + /** + * Searches a range of + * the specified array of floats for the specified value using + * the binary search algorithm. + * The range must be sorted + * (as by the {@link #sort(float[], int, int)} method) + * prior to making this call. If + * it is not sorted, the results are undefined. If the range contains + * multiple elements with the specified value, there is no guarantee which + * one will be found. This method considers all NaN values to be + * equivalent and equal. + * + * @param a the array to be searched + * @param fromIndex the index of the first element (inclusive) to be + * searched + * @param toIndex the index of the last element (exclusive) to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array + * within the specified range; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element in the range greater than the key, + * or {@code toIndex} if all + * elements in the range are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws IllegalArgumentException + * if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0 or toIndex > a.length} + * @since 1.6 + */ + public static int binarySearch(float[] a, int fromIndex, int toIndex, + float key) { + rangeCheck(a.length, fromIndex, toIndex); + return binarySearch0(a, fromIndex, toIndex, key); + } + + // Like public version, but without range checks. + private static int binarySearch0(float[] a, int fromIndex, int toIndex, + float key) { + int low = fromIndex; + int high = toIndex - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + float midVal = a[mid]; + + if (midVal < key) + low = mid + 1; // Neither val is NaN, thisVal is smaller + else if (midVal > key) + high = mid - 1; // Neither val is NaN, thisVal is larger + else { + int midBits = Float.floatToIntBits(midVal); + int keyBits = Float.floatToIntBits(key); + if (midBits == keyBits) // Values are equal + return mid; // Key found + else if (midBits < keyBits) // (-0.0, 0.0) or (!NaN, NaN) + low = mid + 1; + else // (0.0, -0.0) or (NaN, !NaN) + high = mid - 1; + } + } + return -(low + 1); // key not found. + } + + /** + * Searches the specified array for the specified object using the binary + * search algorithm. The array must be sorted into ascending order + * according to the + * {@linkplain Comparable natural ordering} + * of its elements (as by the + * {@link #sort(Object[])} method) prior to making this call. + * If it is not sorted, the results are undefined. + * (If the array contains elements that are not mutually comparable (for + * example, strings and integers), it cannot be sorted according + * to the natural ordering of its elements, hence results are undefined.) + * If the array contains multiple + * elements equal to the specified object, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element greater than the key, or {@code a.length} if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws ClassCastException if the search key is not comparable to the + * elements of the array. + */ + public static int binarySearch(Object[] a, Object key) { + return binarySearch0(a, 0, a.length, key); + } + + /** + * Searches a range of + * the specified array for the specified object using the binary + * search algorithm. + * The range must be sorted into ascending order + * according to the + * {@linkplain Comparable natural ordering} + * of its elements (as by the + * {@link #sort(Object[], int, int)} method) prior to making this + * call. If it is not sorted, the results are undefined. + * (If the range contains elements that are not mutually comparable (for + * example, strings and integers), it cannot be sorted according + * to the natural ordering of its elements, hence results are undefined.) + * If the range contains multiple + * elements equal to the specified object, there is no guarantee which + * one will be found. + * + * @param a the array to be searched + * @param fromIndex the index of the first element (inclusive) to be + * searched + * @param toIndex the index of the last element (exclusive) to be searched + * @param key the value to be searched for + * @return index of the search key, if it is contained in the array + * within the specified range; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element in the range greater than the key, + * or {@code toIndex} if all + * elements in the range are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws ClassCastException if the search key is not comparable to the + * elements of the array within the specified range. + * @throws IllegalArgumentException + * if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0 or toIndex > a.length} + * @since 1.6 + */ + public static int binarySearch(Object[] a, int fromIndex, int toIndex, + Object key) { + rangeCheck(a.length, fromIndex, toIndex); + return binarySearch0(a, fromIndex, toIndex, key); + } + + // Like public version, but without range checks. + private static int binarySearch0(Object[] a, int fromIndex, int toIndex, + Object key) { + int low = fromIndex; + int high = toIndex - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + @SuppressWarnings("rawtypes") + Comparable midVal = (Comparable)a[mid]; + @SuppressWarnings("unchecked") + int cmp = midVal.compareTo(key); + + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found. + } + + /** + * Searches the specified array for the specified object using the binary + * search algorithm. The array must be sorted into ascending order + * according to the specified comparator (as by the + * {@link #sort(Object[], Comparator) sort(T[], Comparator)} + * method) prior to making this call. If it is + * not sorted, the results are undefined. + * If the array contains multiple + * elements equal to the specified object, there is no guarantee which one + * will be found. + * + * @param the class of the objects in the array + * @param a the array to be searched + * @param key the value to be searched for + * @param c the comparator by which the array is ordered. A + * {@code null} value indicates that the elements' + * {@linkplain Comparable natural ordering} should be used. + * @return index of the search key, if it is contained in the array; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element greater than the key, or {@code a.length} if all + * elements in the array are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws ClassCastException if the array contains elements that are not + * mutually comparable using the specified comparator, + * or the search key is not comparable to the + * elements of the array using this comparator. + */ + public static int binarySearch(T[] a, T key, Comparator c) { + return binarySearch0(a, 0, a.length, key, c); + } + + /** + * Searches a range of + * the specified array for the specified object using the binary + * search algorithm. + * The range must be sorted into ascending order + * according to the specified comparator (as by the + * {@link #sort(Object[], int, int, Comparator) + * sort(T[], int, int, Comparator)} + * method) prior to making this call. + * If it is not sorted, the results are undefined. + * If the range contains multiple elements equal to the specified object, + * there is no guarantee which one will be found. + * + * @param the class of the objects in the array + * @param a the array to be searched + * @param fromIndex the index of the first element (inclusive) to be + * searched + * @param toIndex the index of the last element (exclusive) to be searched + * @param key the value to be searched for + * @param c the comparator by which the array is ordered. A + * {@code null} value indicates that the elements' + * {@linkplain Comparable natural ordering} should be used. + * @return index of the search key, if it is contained in the array + * within the specified range; + * otherwise, (-(insertion point) - 1). The + * insertion point is defined as the point at which the + * key would be inserted into the array: the index of the first + * element in the range greater than the key, + * or {@code toIndex} if all + * elements in the range are less than the specified key. Note + * that this guarantees that the return value will be >= 0 if + * and only if the key is found. + * @throws ClassCastException if the range contains elements that are not + * mutually comparable using the specified comparator, + * or the search key is not comparable to the + * elements in the range using this comparator. + * @throws IllegalArgumentException + * if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code fromIndex < 0 or toIndex > a.length} + * @since 1.6 + */ + public static int binarySearch(T[] a, int fromIndex, int toIndex, + T key, Comparator c) { + rangeCheck(a.length, fromIndex, toIndex); + return binarySearch0(a, fromIndex, toIndex, key, c); + } + + // Like public version, but without range checks. + private static int binarySearch0(T[] a, int fromIndex, int toIndex, + T key, Comparator c) { + if (c == null) { + return binarySearch0(a, fromIndex, toIndex, key); + } + int low = fromIndex; + int high = toIndex - 1; + + while (low <= high) { + int mid = (low + high) >>> 1; + T midVal = a[mid]; + int cmp = c.compare(midVal, key); + if (cmp < 0) + low = mid + 1; + else if (cmp > 0) + high = mid - 1; + else + return mid; // key found + } + return -(low + 1); // key not found. + } + + // Equality Testing + + /** + * Returns {@code true} if the two specified arrays of longs are + * equal to one another. Two arrays are considered equal if both + * arrays contain the same number of elements, and all corresponding pairs + * of elements in the two arrays are equal. In other words, two arrays + * are equal if they contain the same elements in the same order. Also, + * two array references are considered equal if both are {@code null}. + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @return {@code true} if the two arrays are equal + */ + public static boolean equals(long[] a, long[] a2) { + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + return ArraysSupport.mismatch(a, a2, length) < 0; + } + + /** + * Returns true if the two specified arrays of longs, over the specified + * ranges, are equal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested fro equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static boolean equals(long[] a, int aFromIndex, int aToIndex, + long[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + return ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + aLength) < 0; + } + + /** + * Returns {@code true} if the two specified arrays of ints are + * equal to one another. Two arrays are considered equal if both + * arrays contain the same number of elements, and all corresponding pairs + * of elements in the two arrays are equal. In other words, two arrays + * are equal if they contain the same elements in the same order. Also, + * two array references are considered equal if both are {@code null}. + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @return {@code true} if the two arrays are equal + */ + public static boolean equals(int[] a, int[] a2) { + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + return ArraysSupport.mismatch(a, a2, length) < 0; + } + + /** + * Returns true if the two specified arrays of ints, over the specified + * ranges, are equal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested fro equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static boolean equals(int[] a, int aFromIndex, int aToIndex, + int[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + return ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + aLength) < 0; + } + + /** + * Returns {@code true} if the two specified arrays of shorts are + * equal to one another. Two arrays are considered equal if both + * arrays contain the same number of elements, and all corresponding pairs + * of elements in the two arrays are equal. In other words, two arrays + * are equal if they contain the same elements in the same order. Also, + * two array references are considered equal if both are {@code null}. + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @return {@code true} if the two arrays are equal + */ + public static boolean equals(short[] a, short a2[]) { + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + return ArraysSupport.mismatch(a, a2, length) < 0; + } + + /** + * Returns true if the two specified arrays of shorts, over the specified + * ranges, are equal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested fro equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static boolean equals(short[] a, int aFromIndex, int aToIndex, + short[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + return ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + aLength) < 0; + } + + /** + * Returns {@code true} if the two specified arrays of chars are + * equal to one another. Two arrays are considered equal if both + * arrays contain the same number of elements, and all corresponding pairs + * of elements in the two arrays are equal. In other words, two arrays + * are equal if they contain the same elements in the same order. Also, + * two array references are considered equal if both are {@code null}. + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @return {@code true} if the two arrays are equal + */ + @HotSpotIntrinsicCandidate + public static boolean equals(char[] a, char[] a2) { + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + return ArraysSupport.mismatch(a, a2, length) < 0; + } + + /** + * Returns true if the two specified arrays of chars, over the specified + * ranges, are equal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested fro equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static boolean equals(char[] a, int aFromIndex, int aToIndex, + char[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + return ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + aLength) < 0; + } + + /** + * Returns {@code true} if the two specified arrays of bytes are + * equal to one another. Two arrays are considered equal if both + * arrays contain the same number of elements, and all corresponding pairs + * of elements in the two arrays are equal. In other words, two arrays + * are equal if they contain the same elements in the same order. Also, + * two array references are considered equal if both are {@code null}. + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @return {@code true} if the two arrays are equal + */ + @HotSpotIntrinsicCandidate + public static boolean equals(byte[] a, byte[] a2) { + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + return ArraysSupport.mismatch(a, a2, length) < 0; + } + + /** + * Returns true if the two specified arrays of bytes, over the specified + * ranges, are equal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested fro equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static boolean equals(byte[] a, int aFromIndex, int aToIndex, + byte[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + return ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + aLength) < 0; + } + + /** + * Returns {@code true} if the two specified arrays of booleans are + * equal to one another. Two arrays are considered equal if both + * arrays contain the same number of elements, and all corresponding pairs + * of elements in the two arrays are equal. In other words, two arrays + * are equal if they contain the same elements in the same order. Also, + * two array references are considered equal if both are {@code null}. + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @return {@code true} if the two arrays are equal + */ + public static boolean equals(boolean[] a, boolean[] a2) { + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + return ArraysSupport.mismatch(a, a2, length) < 0; + } + + /** + * Returns true if the two specified arrays of booleans, over the specified + * ranges, are equal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested fro equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static boolean equals(boolean[] a, int aFromIndex, int aToIndex, + boolean[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + return ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + aLength) < 0; + } + + /** + * Returns {@code true} if the two specified arrays of doubles are + * equal to one another. Two arrays are considered equal if both + * arrays contain the same number of elements, and all corresponding pairs + * of elements in the two arrays are equal. In other words, two arrays + * are equal if they contain the same elements in the same order. Also, + * two array references are considered equal if both are {@code null}. + * + * Two doubles {@code d1} and {@code d2} are considered equal if: + *

{@code new Double(d1).equals(new Double(d2))}
+ * (Unlike the {@code ==} operator, this method considers + * {@code NaN} equals to itself, and 0.0d unequal to -0.0d.) + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @return {@code true} if the two arrays are equal + * @see Double#equals(Object) + */ + public static boolean equals(double[] a, double[] a2) { + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + return ArraysSupport.mismatch(a, a2, length) < 0; + } + + /** + * Returns true if the two specified arrays of doubles, over the specified + * ranges, are equal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + *

Two doubles {@code d1} and {@code d2} are considered equal if: + *

{@code new Double(d1).equals(new Double(d2))}
+ * (Unlike the {@code ==} operator, this method considers + * {@code NaN} equals to itself, and 0.0d unequal to -0.0d.) + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested fro equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @see Double#equals(Object) + * @since 9 + */ + public static boolean equals(double[] a, int aFromIndex, int aToIndex, + double[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + return ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, aLength) < 0; + } + + /** + * Returns {@code true} if the two specified arrays of floats are + * equal to one another. Two arrays are considered equal if both + * arrays contain the same number of elements, and all corresponding pairs + * of elements in the two arrays are equal. In other words, two arrays + * are equal if they contain the same elements in the same order. Also, + * two array references are considered equal if both are {@code null}. + * + * Two floats {@code f1} and {@code f2} are considered equal if: + *
{@code new Float(f1).equals(new Float(f2))}
+ * (Unlike the {@code ==} operator, this method considers + * {@code NaN} equals to itself, and 0.0f unequal to -0.0f.) + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @return {@code true} if the two arrays are equal + * @see Float#equals(Object) + */ + public static boolean equals(float[] a, float[] a2) { + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + return ArraysSupport.mismatch(a, a2, length) < 0; + } + + /** + * Returns true if the two specified arrays of floats, over the specified + * ranges, are equal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + *

Two floats {@code f1} and {@code f2} are considered equal if: + *

{@code new Float(f1).equals(new Float(f2))}
+ * (Unlike the {@code ==} operator, this method considers + * {@code NaN} equals to itself, and 0.0f unequal to -0.0f.) + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested fro equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @see Float#equals(Object) + * @since 9 + */ + public static boolean equals(float[] a, int aFromIndex, int aToIndex, + float[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + return ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, aLength) < 0; + } + + /** + * Returns {@code true} if the two specified arrays of Objects are + * equal to one another. The two arrays are considered equal if + * both arrays contain the same number of elements, and all corresponding + * pairs of elements in the two arrays are equal. Two objects {@code e1} + * and {@code e2} are considered equal if + * {@code Objects.equals(e1, e2)}. + * In other words, the two arrays are equal if + * they contain the same elements in the same order. Also, two array + * references are considered equal if both are {@code null}. + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @return {@code true} if the two arrays are equal + */ + public static boolean equals(Object[] a, Object[] a2) { + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + for (int i=0; iequal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + *

Two objects {@code e1} and {@code e2} are considered equal if + * {@code Objects.equals(e1, e2)}. + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested fro equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static boolean equals(Object[] a, int aFromIndex, int aToIndex, + Object[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + for (int i = 0; i < aLength; i++) { + if (!Objects.equals(a[aFromIndex++], b[bFromIndex++])) + return false; + } + + return true; + } + + /** + * Returns {@code true} if the two specified arrays of Objects are + * equal to one another. + * + *

Two arrays are considered equal if both arrays contain the same number + * of elements, and all corresponding pairs of elements in the two arrays + * are equal. In other words, the two arrays are equal if they contain the + * same elements in the same order. Also, two array references are + * considered equal if both are {@code null}. + * + *

Two objects {@code e1} and {@code e2} are considered equal if, + * given the specified comparator, {@code cmp.compare(e1, e2) == 0}. + * + * @param a one array to be tested for equality + * @param a2 the other array to be tested for equality + * @param cmp the comparator to compare array elements + * @param the type of array elements + * @return {@code true} if the two arrays are equal + * @throws NullPointerException if the comparator is {@code null} + * @since 9 + */ + public static boolean equals(T[] a, T[] a2, Comparator cmp) { + Objects.requireNonNull(cmp); + if (a==a2) + return true; + if (a==null || a2==null) + return false; + + int length = a.length; + if (a2.length != length) + return false; + + for (int i=0; iequal to one another. + * + *

Two arrays are considered equal if the number of elements covered by + * each range is the same, and all corresponding pairs of elements over the + * specified ranges in the two arrays are equal. In other words, two arrays + * are equal if they contain, over the specified ranges, the same elements + * in the same order. + * + *

Two objects {@code e1} and {@code e2} are considered equal if, + * given the specified comparator, {@code cmp.compare(e1, e2) == 0}. + * + * @param a the first array to be tested for equality + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested fro equality + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @param cmp the comparator to compare array elements + * @param the type of array elements + * @return {@code true} if the two arrays, over the specified ranges, are + * equal + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array or the comparator is {@code null} + * @since 9 + */ + public static boolean equals(T[] a, int aFromIndex, int aToIndex, + T[] b, int bFromIndex, int bToIndex, + Comparator cmp) { + Objects.requireNonNull(cmp); + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + if (aLength != bLength) + return false; + + for (int i = 0; i < aLength; i++) { + if (cmp.compare(a[aFromIndex++], b[bFromIndex++]) != 0) + return false; + } + + return true; + } + + // Filling + + /** + * Assigns the specified long value to each element of the specified array + * of longs. + * + * @param a the array to be filled + * @param val the value to be stored in all elements of the array + */ + public static void fill(long[] a, long val) { + for (int i = 0, len = a.length; i < len; i++) + a[i] = val; + } + + /** + * Assigns the specified long value to each element of the specified + * range of the specified array of longs. The range to be filled + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be filled is empty.) + * + * @param a the array to be filled + * @param fromIndex the index of the first element (inclusive) to be + * filled with the specified value + * @param toIndex the index of the last element (exclusive) to be + * filled with the specified value + * @param val the value to be stored in all elements of the array + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + */ + public static void fill(long[] a, int fromIndex, int toIndex, long val) { + rangeCheck(a.length, fromIndex, toIndex); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Assigns the specified int value to each element of the specified array + * of ints. + * + * @param a the array to be filled + * @param val the value to be stored in all elements of the array + */ + public static void fill(int[] a, int val) { + for (int i = 0, len = a.length; i < len; i++) + a[i] = val; + } + + /** + * Assigns the specified int value to each element of the specified + * range of the specified array of ints. The range to be filled + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be filled is empty.) + * + * @param a the array to be filled + * @param fromIndex the index of the first element (inclusive) to be + * filled with the specified value + * @param toIndex the index of the last element (exclusive) to be + * filled with the specified value + * @param val the value to be stored in all elements of the array + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + */ + public static void fill(int[] a, int fromIndex, int toIndex, int val) { + rangeCheck(a.length, fromIndex, toIndex); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Assigns the specified short value to each element of the specified array + * of shorts. + * + * @param a the array to be filled + * @param val the value to be stored in all elements of the array + */ + public static void fill(short[] a, short val) { + for (int i = 0, len = a.length; i < len; i++) + a[i] = val; + } + + /** + * Assigns the specified short value to each element of the specified + * range of the specified array of shorts. The range to be filled + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be filled is empty.) + * + * @param a the array to be filled + * @param fromIndex the index of the first element (inclusive) to be + * filled with the specified value + * @param toIndex the index of the last element (exclusive) to be + * filled with the specified value + * @param val the value to be stored in all elements of the array + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + */ + public static void fill(short[] a, int fromIndex, int toIndex, short val) { + rangeCheck(a.length, fromIndex, toIndex); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Assigns the specified char value to each element of the specified array + * of chars. + * + * @param a the array to be filled + * @param val the value to be stored in all elements of the array + */ + public static void fill(char[] a, char val) { + for (int i = 0, len = a.length; i < len; i++) + a[i] = val; + } + + /** + * Assigns the specified char value to each element of the specified + * range of the specified array of chars. The range to be filled + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be filled is empty.) + * + * @param a the array to be filled + * @param fromIndex the index of the first element (inclusive) to be + * filled with the specified value + * @param toIndex the index of the last element (exclusive) to be + * filled with the specified value + * @param val the value to be stored in all elements of the array + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + */ + public static void fill(char[] a, int fromIndex, int toIndex, char val) { + rangeCheck(a.length, fromIndex, toIndex); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Assigns the specified byte value to each element of the specified array + * of bytes. + * + * @param a the array to be filled + * @param val the value to be stored in all elements of the array + */ + public static void fill(byte[] a, byte val) { + for (int i = 0, len = a.length; i < len; i++) + a[i] = val; + } + + /** + * Assigns the specified byte value to each element of the specified + * range of the specified array of bytes. The range to be filled + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be filled is empty.) + * + * @param a the array to be filled + * @param fromIndex the index of the first element (inclusive) to be + * filled with the specified value + * @param toIndex the index of the last element (exclusive) to be + * filled with the specified value + * @param val the value to be stored in all elements of the array + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + */ + public static void fill(byte[] a, int fromIndex, int toIndex, byte val) { + rangeCheck(a.length, fromIndex, toIndex); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Assigns the specified boolean value to each element of the specified + * array of booleans. + * + * @param a the array to be filled + * @param val the value to be stored in all elements of the array + */ + public static void fill(boolean[] a, boolean val) { + for (int i = 0, len = a.length; i < len; i++) + a[i] = val; + } + + /** + * Assigns the specified boolean value to each element of the specified + * range of the specified array of booleans. The range to be filled + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be filled is empty.) + * + * @param a the array to be filled + * @param fromIndex the index of the first element (inclusive) to be + * filled with the specified value + * @param toIndex the index of the last element (exclusive) to be + * filled with the specified value + * @param val the value to be stored in all elements of the array + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + */ + public static void fill(boolean[] a, int fromIndex, int toIndex, + boolean val) { + rangeCheck(a.length, fromIndex, toIndex); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Assigns the specified double value to each element of the specified + * array of doubles. + * + * @param a the array to be filled + * @param val the value to be stored in all elements of the array + */ + public static void fill(double[] a, double val) { + for (int i = 0, len = a.length; i < len; i++) + a[i] = val; + } + + /** + * Assigns the specified double value to each element of the specified + * range of the specified array of doubles. The range to be filled + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be filled is empty.) + * + * @param a the array to be filled + * @param fromIndex the index of the first element (inclusive) to be + * filled with the specified value + * @param toIndex the index of the last element (exclusive) to be + * filled with the specified value + * @param val the value to be stored in all elements of the array + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + */ + public static void fill(double[] a, int fromIndex, int toIndex,double val){ + rangeCheck(a.length, fromIndex, toIndex); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Assigns the specified float value to each element of the specified array + * of floats. + * + * @param a the array to be filled + * @param val the value to be stored in all elements of the array + */ + public static void fill(float[] a, float val) { + for (int i = 0, len = a.length; i < len; i++) + a[i] = val; + } + + /** + * Assigns the specified float value to each element of the specified + * range of the specified array of floats. The range to be filled + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be filled is empty.) + * + * @param a the array to be filled + * @param fromIndex the index of the first element (inclusive) to be + * filled with the specified value + * @param toIndex the index of the last element (exclusive) to be + * filled with the specified value + * @param val the value to be stored in all elements of the array + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + */ + public static void fill(float[] a, int fromIndex, int toIndex, float val) { + rangeCheck(a.length, fromIndex, toIndex); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + /** + * Assigns the specified Object reference to each element of the specified + * array of Objects. + * + * @param a the array to be filled + * @param val the value to be stored in all elements of the array + * @throws ArrayStoreException if the specified value is not of a + * runtime type that can be stored in the specified array + */ + public static void fill(Object[] a, Object val) { + for (int i = 0, len = a.length; i < len; i++) + a[i] = val; + } + + /** + * Assigns the specified Object reference to each element of the specified + * range of the specified array of Objects. The range to be filled + * extends from index {@code fromIndex}, inclusive, to index + * {@code toIndex}, exclusive. (If {@code fromIndex==toIndex}, the + * range to be filled is empty.) + * + * @param a the array to be filled + * @param fromIndex the index of the first element (inclusive) to be + * filled with the specified value + * @param toIndex the index of the last element (exclusive) to be + * filled with the specified value + * @param val the value to be stored in all elements of the array + * @throws IllegalArgumentException if {@code fromIndex > toIndex} + * @throws ArrayIndexOutOfBoundsException if {@code fromIndex < 0} or + * {@code toIndex > a.length} + * @throws ArrayStoreException if the specified value is not of a + * runtime type that can be stored in the specified array + */ + public static void fill(Object[] a, int fromIndex, int toIndex, Object val) { + rangeCheck(a.length, fromIndex, toIndex); + for (int i = fromIndex; i < toIndex; i++) + a[i] = val; + } + + // Cloning + + /** + * Copies the specified array, truncating or padding with nulls (if necessary) + * so the copy has the specified length. For all indices that are + * valid in both the original array and the copy, the two arrays will + * contain identical values. For any indices that are valid in the + * copy but not the original, the copy will contain {@code null}. + * Such indices will exist if and only if the specified length + * is greater than that of the original array. + * The resulting array is of exactly the same class as the original array. + * + * @param the class of the objects in the array + * @param original the array to be copied + * @param newLength the length of the copy to be returned + * @return a copy of the original array, truncated or padded with nulls + * to obtain the specified length + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + @SuppressWarnings("unchecked") + public static T[] copyOf(T[] original, int newLength) { + return (T[]) copyOf(original, newLength, original.getClass()); + } + + /** + * Copies the specified array, truncating or padding with nulls (if necessary) + * so the copy has the specified length. For all indices that are + * valid in both the original array and the copy, the two arrays will + * contain identical values. For any indices that are valid in the + * copy but not the original, the copy will contain {@code null}. + * Such indices will exist if and only if the specified length + * is greater than that of the original array. + * The resulting array is of the class {@code newType}. + * + * @param the class of the objects in the original array + * @param the class of the objects in the returned array + * @param original the array to be copied + * @param newLength the length of the copy to be returned + * @param newType the class of the copy to be returned + * @return a copy of the original array, truncated or padded with nulls + * to obtain the specified length + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null + * @throws ArrayStoreException if an element copied from + * {@code original} is not of a runtime type that can be stored in + * an array of class {@code newType} + * @since 1.6 + */ + @HotSpotIntrinsicCandidate + public static T[] copyOf(U[] original, int newLength, Class newType) { + @SuppressWarnings("unchecked") + T[] copy = ((Object)newType == (Object)Object[].class) + ? (T[]) new Object[newLength] + : (T[]) Array.newInstance(newType.getComponentType(), newLength); + System.arraycopy(original, 0, copy, 0, + Math.min(original.length, newLength)); + return copy; + } + + /** + * Copies the specified array, truncating or padding with zeros (if necessary) + * so the copy has the specified length. For all indices that are + * valid in both the original array and the copy, the two arrays will + * contain identical values. For any indices that are valid in the + * copy but not the original, the copy will contain {@code (byte)0}. + * Such indices will exist if and only if the specified length + * is greater than that of the original array. + * + * @param original the array to be copied + * @param newLength the length of the copy to be returned + * @return a copy of the original array, truncated or padded with zeros + * to obtain the specified length + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static byte[] copyOf(byte[] original, int newLength) { + byte[] copy = new byte[newLength]; + System.arraycopy(original, 0, copy, 0, + Math.min(original.length, newLength)); + return copy; + } + + /** + * Copies the specified array, truncating or padding with zeros (if necessary) + * so the copy has the specified length. For all indices that are + * valid in both the original array and the copy, the two arrays will + * contain identical values. For any indices that are valid in the + * copy but not the original, the copy will contain {@code (short)0}. + * Such indices will exist if and only if the specified length + * is greater than that of the original array. + * + * @param original the array to be copied + * @param newLength the length of the copy to be returned + * @return a copy of the original array, truncated or padded with zeros + * to obtain the specified length + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static short[] copyOf(short[] original, int newLength) { + short[] copy = new short[newLength]; + System.arraycopy(original, 0, copy, 0, + Math.min(original.length, newLength)); + return copy; + } + + /** + * Copies the specified array, truncating or padding with zeros (if necessary) + * so the copy has the specified length. For all indices that are + * valid in both the original array and the copy, the two arrays will + * contain identical values. For any indices that are valid in the + * copy but not the original, the copy will contain {@code 0}. + * Such indices will exist if and only if the specified length + * is greater than that of the original array. + * + * @param original the array to be copied + * @param newLength the length of the copy to be returned + * @return a copy of the original array, truncated or padded with zeros + * to obtain the specified length + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static int[] copyOf(int[] original, int newLength) { + int[] copy = new int[newLength]; + System.arraycopy(original, 0, copy, 0, + Math.min(original.length, newLength)); + return copy; + } + + /** + * Copies the specified array, truncating or padding with zeros (if necessary) + * so the copy has the specified length. For all indices that are + * valid in both the original array and the copy, the two arrays will + * contain identical values. For any indices that are valid in the + * copy but not the original, the copy will contain {@code 0L}. + * Such indices will exist if and only if the specified length + * is greater than that of the original array. + * + * @param original the array to be copied + * @param newLength the length of the copy to be returned + * @return a copy of the original array, truncated or padded with zeros + * to obtain the specified length + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static long[] copyOf(long[] original, int newLength) { + long[] copy = new long[newLength]; + System.arraycopy(original, 0, copy, 0, + Math.min(original.length, newLength)); + return copy; + } + + /** + * Copies the specified array, truncating or padding with null characters (if necessary) + * so the copy has the specified length. For all indices that are valid + * in both the original array and the copy, the two arrays will contain + * identical values. For any indices that are valid in the copy but not + * the original, the copy will contain {@code '\\u000'}. Such indices + * will exist if and only if the specified length is greater than that of + * the original array. + * + * @param original the array to be copied + * @param newLength the length of the copy to be returned + * @return a copy of the original array, truncated or padded with null characters + * to obtain the specified length + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static char[] copyOf(char[] original, int newLength) { + char[] copy = new char[newLength]; + System.arraycopy(original, 0, copy, 0, + Math.min(original.length, newLength)); + return copy; + } + + /** + * Copies the specified array, truncating or padding with zeros (if necessary) + * so the copy has the specified length. For all indices that are + * valid in both the original array and the copy, the two arrays will + * contain identical values. For any indices that are valid in the + * copy but not the original, the copy will contain {@code 0f}. + * Such indices will exist if and only if the specified length + * is greater than that of the original array. + * + * @param original the array to be copied + * @param newLength the length of the copy to be returned + * @return a copy of the original array, truncated or padded with zeros + * to obtain the specified length + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static float[] copyOf(float[] original, int newLength) { + float[] copy = new float[newLength]; + System.arraycopy(original, 0, copy, 0, + Math.min(original.length, newLength)); + return copy; + } + + /** + * Copies the specified array, truncating or padding with zeros (if necessary) + * so the copy has the specified length. For all indices that are + * valid in both the original array and the copy, the two arrays will + * contain identical values. For any indices that are valid in the + * copy but not the original, the copy will contain {@code 0d}. + * Such indices will exist if and only if the specified length + * is greater than that of the original array. + * + * @param original the array to be copied + * @param newLength the length of the copy to be returned + * @return a copy of the original array, truncated or padded with zeros + * to obtain the specified length + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static double[] copyOf(double[] original, int newLength) { + double[] copy = new double[newLength]; + System.arraycopy(original, 0, copy, 0, + Math.min(original.length, newLength)); + return copy; + } + + /** + * Copies the specified array, truncating or padding with {@code false} (if necessary) + * so the copy has the specified length. For all indices that are + * valid in both the original array and the copy, the two arrays will + * contain identical values. For any indices that are valid in the + * copy but not the original, the copy will contain {@code false}. + * Such indices will exist if and only if the specified length + * is greater than that of the original array. + * + * @param original the array to be copied + * @param newLength the length of the copy to be returned + * @return a copy of the original array, truncated or padded with false elements + * to obtain the specified length + * @throws NegativeArraySizeException if {@code newLength} is negative + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static boolean[] copyOf(boolean[] original, int newLength) { + boolean[] copy = new boolean[newLength]; + System.arraycopy(original, 0, copy, 0, + Math.min(original.length, newLength)); + return copy; + } + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code null} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + *

+ * The resulting array is of exactly the same class as the original array. + * + * @param the class of the objects in the array + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with nulls to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + @SuppressWarnings("unchecked") + public static T[] copyOfRange(T[] original, int from, int to) { + return copyOfRange(original, from, to, (Class) original.getClass()); + } + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code null} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * The resulting array is of the class {@code newType}. + * + * @param the class of the objects in the original array + * @param the class of the objects in the returned array + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @param newType the class of the copy to be returned + * @return a new array containing the specified range from the original array, + * truncated or padded with nulls to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @throws ArrayStoreException if an element copied from + * {@code original} is not of a runtime type that can be stored in + * an array of class {@code newType}. + * @since 1.6 + */ + @HotSpotIntrinsicCandidate + public static T[] copyOfRange(U[] original, int from, int to, Class newType) { + int newLength = to - from; + if (newLength < 0) + throw new IllegalArgumentException(from + " > " + to); + @SuppressWarnings("unchecked") + T[] copy = ((Object)newType == (Object)Object[].class) + ? (T[]) new Object[newLength] + : (T[]) Array.newInstance(newType.getComponentType(), newLength); + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + return copy; + } + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code (byte)0} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with zeros to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static byte[] copyOfRange(byte[] original, int from, int to) { + int newLength = to - from; + if (newLength < 0) + throw new IllegalArgumentException(from + " > " + to); + byte[] copy = new byte[newLength]; + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + return copy; + } + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code (short)0} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with zeros to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static short[] copyOfRange(short[] original, int from, int to) { + int newLength = to - from; + if (newLength < 0) + throw new IllegalArgumentException(from + " > " + to); + short[] copy = new short[newLength]; + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + return copy; + } + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code 0} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with zeros to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static int[] copyOfRange(int[] original, int from, int to) { + int newLength = to - from; + if (newLength < 0) + throw new IllegalArgumentException(from + " > " + to); + int[] copy = new int[newLength]; + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + return copy; + } + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code 0L} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with zeros to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static long[] copyOfRange(long[] original, int from, int to) { + int newLength = to - from; + if (newLength < 0) + throw new IllegalArgumentException(from + " > " + to); + long[] copy = new long[newLength]; + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + return copy; + } + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code '\\u000'} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with null characters to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static char[] copyOfRange(char[] original, int from, int to) { + int newLength = to - from; + if (newLength < 0) + throw new IllegalArgumentException(from + " > " + to); + char[] copy = new char[newLength]; + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + return copy; + } + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code 0f} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with zeros to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static float[] copyOfRange(float[] original, int from, int to) { + int newLength = to - from; + if (newLength < 0) + throw new IllegalArgumentException(from + " > " + to); + float[] copy = new float[newLength]; + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + return copy; + } + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code 0d} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with zeros to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static double[] copyOfRange(double[] original, int from, int to) { + int newLength = to - from; + if (newLength < 0) + throw new IllegalArgumentException(from + " > " + to); + double[] copy = new double[newLength]; + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + return copy; + } + + /** + * Copies the specified range of the specified array into a new array. + * The initial index of the range ({@code from}) must lie between zero + * and {@code original.length}, inclusive. The value at + * {@code original[from]} is placed into the initial element of the copy + * (unless {@code from == original.length} or {@code from == to}). + * Values from subsequent elements in the original array are placed into + * subsequent elements in the copy. The final index of the range + * ({@code to}), which must be greater than or equal to {@code from}, + * may be greater than {@code original.length}, in which case + * {@code false} is placed in all elements of the copy whose index is + * greater than or equal to {@code original.length - from}. The length + * of the returned array will be {@code to - from}. + * + * @param original the array from which a range is to be copied + * @param from the initial index of the range to be copied, inclusive + * @param to the final index of the range to be copied, exclusive. + * (This index may lie outside the array.) + * @return a new array containing the specified range from the original array, + * truncated or padded with false elements to obtain the required length + * @throws ArrayIndexOutOfBoundsException if {@code from < 0} + * or {@code from > original.length} + * @throws IllegalArgumentException if {@code from > to} + * @throws NullPointerException if {@code original} is null + * @since 1.6 + */ + public static boolean[] copyOfRange(boolean[] original, int from, int to) { + int newLength = to - from; + if (newLength < 0) + throw new IllegalArgumentException(from + " > " + to); + boolean[] copy = new boolean[newLength]; + System.arraycopy(original, from, copy, 0, + Math.min(original.length - from, newLength)); + return copy; + } + + // Misc + + /** + * Returns a fixed-size list backed by the specified array. Changes made to + * the array will be visible in the returned list, and changes made to the + * list will be visible in the array. The returned list is + * {@link Serializable} and implements {@link RandomAccess}. + * + *

The returned list implements the optional {@code Collection} methods, except + * those that would change the size of the returned list. Those methods leave + * the list unchanged and throw {@link UnsupportedOperationException}. + * + * @apiNote + * This method acts as bridge between array-based and collection-based + * APIs, in combination with {@link Collection#toArray}. + * + *

This method provides a way to wrap an existing array: + *

{@code
+     *     Integer[] numbers = ...
+     *     ...
+     *     List values = Arrays.asList(numbers);
+     * }
+ * + *

This method also provides a convenient way to create a fixed-size + * list initialized to contain several elements: + *

{@code
+     *     List stooges = Arrays.asList("Larry", "Moe", "Curly");
+     * }
+ * + *

The list returned by this method is modifiable. + * To create an unmodifiable list, use + * {@link Collections#unmodifiableList Collections.unmodifiableList} + * or Unmodifiable Lists. + * + * @param the class of the objects in the array + * @param a the array by which the list will be backed + * @return a list view of the specified array + * @throws NullPointerException if the specified array is {@code null} + */ + @SafeVarargs + @SuppressWarnings("varargs") + public static List asList(T... a) { + return new ArrayList<>(a); + } + + /** + * @serial include + */ + private static class ArrayList extends AbstractList + implements RandomAccess, java.io.Serializable + { + private static final long serialVersionUID = -2764017481108945198L; + private final E[] a; + + ArrayList(E[] array) { + a = Objects.requireNonNull(array); + } + + @Override + public int size() { + return a.length; + } + + @Override + public Object[] toArray() { + return Arrays.copyOf(a, a.length, Object[].class); + } + + @Override + @SuppressWarnings("unchecked") + public T[] toArray(T[] a) { + int size = size(); + if (a.length < size) + return Arrays.copyOf(this.a, size, + (Class) a.getClass()); + System.arraycopy(this.a, 0, a, 0, size); + if (a.length > size) + a[size] = null; + return a; + } + + @Override + public E get(int index) { + return a[index]; + } + + @Override + public E set(int index, E element) { + E oldValue = a[index]; + a[index] = element; + return oldValue; + } + + @Override + public int indexOf(Object o) { + E[] a = this.a; + if (o == null) { + for (int i = 0; i < a.length; i++) + if (a[i] == null) + return i; + } else { + for (int i = 0; i < a.length; i++) + if (o.equals(a[i])) + return i; + } + return -1; + } + + @Override + public boolean contains(Object o) { + return indexOf(o) >= 0; + } + + @Override + public Spliterator spliterator() { + return Spliterators.spliterator(a, Spliterator.ORDERED); + } + + @Override + public void forEach(Consumer action) { + Objects.requireNonNull(action); + for (E e : a) { + action.accept(e); + } + } + + @Override + public void replaceAll(UnaryOperator operator) { + Objects.requireNonNull(operator); + E[] a = this.a; + for (int i = 0; i < a.length; i++) { + a[i] = operator.apply(a[i]); + } + } + + @Override + public void sort(Comparator c) { + Arrays.sort(a, c); + } + + @Override + public Iterator iterator() { + return new ArrayItr<>(a); + } + } + + private static class ArrayItr implements Iterator { + private int cursor; + private final E[] a; + + ArrayItr(E[] a) { + this.a = a; + } + + @Override + public boolean hasNext() { + return cursor < a.length; + } + + @Override + public E next() { + int i = cursor; + if (i >= a.length) { + throw new NoSuchElementException(); + } + cursor = i + 1; + return a[i]; + } + } + + /** + * Returns a hash code based on the contents of the specified array. + * For any two {@code long} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. + * + *

The value returned by this method is the same value that would be + * obtained by invoking the {@link List#hashCode() hashCode} + * method on a {@link List} containing a sequence of {@link Long} + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. + * + * @param a the array whose hash value to compute + * @return a content-based hash code for {@code a} + * @since 1.5 + */ + public static int hashCode(long a[]) { + if (a == null) + return 0; + + int result = 1; + for (long element : a) { + int elementHash = (int)(element ^ (element >>> 32)); + result = 31 * result + elementHash; + } + + return result; + } + + /** + * Returns a hash code based on the contents of the specified array. + * For any two non-null {@code int} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. + * + *

The value returned by this method is the same value that would be + * obtained by invoking the {@link List#hashCode() hashCode} + * method on a {@link List} containing a sequence of {@link Integer} + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. + * + * @param a the array whose hash value to compute + * @return a content-based hash code for {@code a} + * @since 1.5 + */ + public static int hashCode(int a[]) { + if (a == null) + return 0; + + int result = 1; + for (int element : a) + result = 31 * result + element; + + return result; + } + + /** + * Returns a hash code based on the contents of the specified array. + * For any two {@code short} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. + * + *

The value returned by this method is the same value that would be + * obtained by invoking the {@link List#hashCode() hashCode} + * method on a {@link List} containing a sequence of {@link Short} + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. + * + * @param a the array whose hash value to compute + * @return a content-based hash code for {@code a} + * @since 1.5 + */ + public static int hashCode(short a[]) { + if (a == null) + return 0; + + int result = 1; + for (short element : a) + result = 31 * result + element; + + return result; + } + + /** + * Returns a hash code based on the contents of the specified array. + * For any two {@code char} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. + * + *

The value returned by this method is the same value that would be + * obtained by invoking the {@link List#hashCode() hashCode} + * method on a {@link List} containing a sequence of {@link Character} + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. + * + * @param a the array whose hash value to compute + * @return a content-based hash code for {@code a} + * @since 1.5 + */ + public static int hashCode(char a[]) { + if (a == null) + return 0; + + int result = 1; + for (char element : a) + result = 31 * result + element; + + return result; + } + + /** + * Returns a hash code based on the contents of the specified array. + * For any two {@code byte} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. + * + *

The value returned by this method is the same value that would be + * obtained by invoking the {@link List#hashCode() hashCode} + * method on a {@link List} containing a sequence of {@link Byte} + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. + * + * @param a the array whose hash value to compute + * @return a content-based hash code for {@code a} + * @since 1.5 + */ + public static int hashCode(byte a[]) { + if (a == null) + return 0; + + int result = 1; + for (byte element : a) + result = 31 * result + element; + + return result; + } + + /** + * Returns a hash code based on the contents of the specified array. + * For any two {@code boolean} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. + * + *

The value returned by this method is the same value that would be + * obtained by invoking the {@link List#hashCode() hashCode} + * method on a {@link List} containing a sequence of {@link Boolean} + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. + * + * @param a the array whose hash value to compute + * @return a content-based hash code for {@code a} + * @since 1.5 + */ + public static int hashCode(boolean a[]) { + if (a == null) + return 0; + + int result = 1; + for (boolean element : a) + result = 31 * result + (element ? 1231 : 1237); + + return result; + } + + /** + * Returns a hash code based on the contents of the specified array. + * For any two {@code float} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. + * + *

The value returned by this method is the same value that would be + * obtained by invoking the {@link List#hashCode() hashCode} + * method on a {@link List} containing a sequence of {@link Float} + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. + * + * @param a the array whose hash value to compute + * @return a content-based hash code for {@code a} + * @since 1.5 + */ + public static int hashCode(float a[]) { + if (a == null) + return 0; + + int result = 1; + for (float element : a) + result = 31 * result + Float.floatToIntBits(element); + + return result; + } + + /** + * Returns a hash code based on the contents of the specified array. + * For any two {@code double} arrays {@code a} and {@code b} + * such that {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. + * + *

The value returned by this method is the same value that would be + * obtained by invoking the {@link List#hashCode() hashCode} + * method on a {@link List} containing a sequence of {@link Double} + * instances representing the elements of {@code a} in the same order. + * If {@code a} is {@code null}, this method returns 0. + * + * @param a the array whose hash value to compute + * @return a content-based hash code for {@code a} + * @since 1.5 + */ + public static int hashCode(double a[]) { + if (a == null) + return 0; + + int result = 1; + for (double element : a) { + long bits = Double.doubleToLongBits(element); + result = 31 * result + (int)(bits ^ (bits >>> 32)); + } + return result; + } + + /** + * Returns a hash code based on the contents of the specified array. If + * the array contains other arrays as elements, the hash code is based on + * their identities rather than their contents. It is therefore + * acceptable to invoke this method on an array that contains itself as an + * element, either directly or indirectly through one or more levels of + * arrays. + * + *

For any two arrays {@code a} and {@code b} such that + * {@code Arrays.equals(a, b)}, it is also the case that + * {@code Arrays.hashCode(a) == Arrays.hashCode(b)}. + * + *

The value returned by this method is equal to the value that would + * be returned by {@code Arrays.asList(a).hashCode()}, unless {@code a} + * is {@code null}, in which case {@code 0} is returned. + * + * @param a the array whose content-based hash code to compute + * @return a content-based hash code for {@code a} + * @see #deepHashCode(Object[]) + * @since 1.5 + */ + public static int hashCode(Object a[]) { + if (a == null) + return 0; + + int result = 1; + + for (Object element : a) + result = 31 * result + (element == null ? 0 : element.hashCode()); + + return result; + } + + /** + * Returns a hash code based on the "deep contents" of the specified + * array. If the array contains other arrays as elements, the + * hash code is based on their contents and so on, ad infinitum. + * It is therefore unacceptable to invoke this method on an array that + * contains itself as an element, either directly or indirectly through + * one or more levels of arrays. The behavior of such an invocation is + * undefined. + * + *

For any two arrays {@code a} and {@code b} such that + * {@code Arrays.deepEquals(a, b)}, it is also the case that + * {@code Arrays.deepHashCode(a) == Arrays.deepHashCode(b)}. + * + *

The computation of the value returned by this method is similar to + * that of the value returned by {@link List#hashCode()} on a list + * containing the same elements as {@code a} in the same order, with one + * difference: If an element {@code e} of {@code a} is itself an array, + * its hash code is computed not by calling {@code e.hashCode()}, but as + * by calling the appropriate overloading of {@code Arrays.hashCode(e)} + * if {@code e} is an array of a primitive type, or as by calling + * {@code Arrays.deepHashCode(e)} recursively if {@code e} is an array + * of a reference type. If {@code a} is {@code null}, this method + * returns 0. + * + * @param a the array whose deep-content-based hash code to compute + * @return a deep-content-based hash code for {@code a} + * @see #hashCode(Object[]) + * @since 1.5 + */ + public static int deepHashCode(Object a[]) { + if (a == null) + return 0; + + int result = 1; + + for (Object element : a) { + final int elementHash; + final Class cl; + if (element == null) + elementHash = 0; + else if ((cl = element.getClass().getComponentType()) == null) + elementHash = element.hashCode(); + else if (element instanceof Object[]) + elementHash = deepHashCode((Object[]) element); + else + elementHash = primitiveArrayHashCode(element, cl); + + result = 31 * result + elementHash; + } + + return result; + } + + private static int primitiveArrayHashCode(Object a, Class cl) { + return + (cl == byte.class) ? hashCode((byte[]) a) : + (cl == int.class) ? hashCode((int[]) a) : + (cl == long.class) ? hashCode((long[]) a) : + (cl == char.class) ? hashCode((char[]) a) : + (cl == short.class) ? hashCode((short[]) a) : + (cl == boolean.class) ? hashCode((boolean[]) a) : + (cl == double.class) ? hashCode((double[]) a) : + // If new primitive types are ever added, this method must be + // expanded or we will fail here with ClassCastException. + hashCode((float[]) a); + } + + /** + * Returns {@code true} if the two specified arrays are deeply + * equal to one another. Unlike the {@link #equals(Object[],Object[])} + * method, this method is appropriate for use with nested arrays of + * arbitrary depth. + * + *

Two array references are considered deeply equal if both + * are {@code null}, or if they refer to arrays that contain the same + * number of elements and all corresponding pairs of elements in the two + * arrays are deeply equal. + * + *

Two possibly {@code null} elements {@code e1} and {@code e2} are + * deeply equal if any of the following conditions hold: + *

    + *
  • {@code e1} and {@code e2} are both arrays of object reference + * types, and {@code Arrays.deepEquals(e1, e2) would return true} + *
  • {@code e1} and {@code e2} are arrays of the same primitive + * type, and the appropriate overloading of + * {@code Arrays.equals(e1, e2)} would return true. + *
  • {@code e1 == e2} + *
  • {@code e1.equals(e2)} would return true. + *
+ * Note that this definition permits {@code null} elements at any depth. + * + *

If either of the specified arrays contain themselves as elements + * either directly or indirectly through one or more levels of arrays, + * the behavior of this method is undefined. + * + * @param a1 one array to be tested for equality + * @param a2 the other array to be tested for equality + * @return {@code true} if the two arrays are equal + * @see #equals(Object[],Object[]) + * @see Objects#deepEquals(Object, Object) + * @since 1.5 + */ + public static boolean deepEquals(Object[] a1, Object[] a2) { + if (a1 == a2) + return true; + if (a1 == null || a2==null) + return false; + int length = a1.length; + if (a2.length != length) + return false; + + for (int i = 0; i < length; i++) { + Object e1 = a1[i]; + Object e2 = a2[i]; + + if (e1 == e2) + continue; + if (e1 == null) + return false; + + // Figure out whether the two elements are equal + boolean eq = deepEquals0(e1, e2); + + if (!eq) + return false; + } + return true; + } + + static boolean deepEquals0(Object e1, Object e2) { + assert e1 != null; + boolean eq; + if (e1 instanceof Object[] && e2 instanceof Object[]) + eq = deepEquals ((Object[]) e1, (Object[]) e2); + else if (e1 instanceof byte[] && e2 instanceof byte[]) + eq = equals((byte[]) e1, (byte[]) e2); + else if (e1 instanceof short[] && e2 instanceof short[]) + eq = equals((short[]) e1, (short[]) e2); + else if (e1 instanceof int[] && e2 instanceof int[]) + eq = equals((int[]) e1, (int[]) e2); + else if (e1 instanceof long[] && e2 instanceof long[]) + eq = equals((long[]) e1, (long[]) e2); + else if (e1 instanceof char[] && e2 instanceof char[]) + eq = equals((char[]) e1, (char[]) e2); + else if (e1 instanceof float[] && e2 instanceof float[]) + eq = equals((float[]) e1, (float[]) e2); + else if (e1 instanceof double[] && e2 instanceof double[]) + eq = equals((double[]) e1, (double[]) e2); + else if (e1 instanceof boolean[] && e2 instanceof boolean[]) + eq = equals((boolean[]) e1, (boolean[]) e2); + else + eq = e1.equals(e2); + return eq; + } + + /** + * Returns a string representation of the contents of the specified array. + * The string representation consists of a list of the array's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a + * space). Elements are converted to strings as by + * {@code String.valueOf(long)}. Returns {@code "null"} if {@code a} + * is {@code null}. + * + * @param a the array whose string representation to return + * @return a string representation of {@code a} + * @since 1.5 + */ + public static String toString(long[] a) { + if (a == null) + return "null"; + int iMax = a.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(a[i]); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } + } + + /** + * Returns a string representation of the contents of the specified array. + * The string representation consists of a list of the array's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a + * space). Elements are converted to strings as by + * {@code String.valueOf(int)}. Returns {@code "null"} if {@code a} is + * {@code null}. + * + * @param a the array whose string representation to return + * @return a string representation of {@code a} + * @since 1.5 + */ + public static String toString(int[] a) { + if (a == null) + return "null"; + int iMax = a.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(a[i]); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } + } + + /** + * Returns a string representation of the contents of the specified array. + * The string representation consists of a list of the array's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a + * space). Elements are converted to strings as by + * {@code String.valueOf(short)}. Returns {@code "null"} if {@code a} + * is {@code null}. + * + * @param a the array whose string representation to return + * @return a string representation of {@code a} + * @since 1.5 + */ + public static String toString(short[] a) { + if (a == null) + return "null"; + int iMax = a.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(a[i]); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } + } + + /** + * Returns a string representation of the contents of the specified array. + * The string representation consists of a list of the array's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a + * space). Elements are converted to strings as by + * {@code String.valueOf(char)}. Returns {@code "null"} if {@code a} + * is {@code null}. + * + * @param a the array whose string representation to return + * @return a string representation of {@code a} + * @since 1.5 + */ + public static String toString(char[] a) { + if (a == null) + return "null"; + int iMax = a.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(a[i]); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } + } + + /** + * Returns a string representation of the contents of the specified array. + * The string representation consists of a list of the array's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements + * are separated by the characters {@code ", "} (a comma followed + * by a space). Elements are converted to strings as by + * {@code String.valueOf(byte)}. Returns {@code "null"} if + * {@code a} is {@code null}. + * + * @param a the array whose string representation to return + * @return a string representation of {@code a} + * @since 1.5 + */ + public static String toString(byte[] a) { + if (a == null) + return "null"; + int iMax = a.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(a[i]); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } + } + + /** + * Returns a string representation of the contents of the specified array. + * The string representation consists of a list of the array's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a + * space). Elements are converted to strings as by + * {@code String.valueOf(boolean)}. Returns {@code "null"} if + * {@code a} is {@code null}. + * + * @param a the array whose string representation to return + * @return a string representation of {@code a} + * @since 1.5 + */ + public static String toString(boolean[] a) { + if (a == null) + return "null"; + int iMax = a.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(a[i]); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } + } + + /** + * Returns a string representation of the contents of the specified array. + * The string representation consists of a list of the array's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a + * space). Elements are converted to strings as by + * {@code String.valueOf(float)}. Returns {@code "null"} if {@code a} + * is {@code null}. + * + * @param a the array whose string representation to return + * @return a string representation of {@code a} + * @since 1.5 + */ + public static String toString(float[] a) { + if (a == null) + return "null"; + + int iMax = a.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(a[i]); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } + } + + /** + * Returns a string representation of the contents of the specified array. + * The string representation consists of a list of the array's elements, + * enclosed in square brackets ({@code "[]"}). Adjacent elements are + * separated by the characters {@code ", "} (a comma followed by a + * space). Elements are converted to strings as by + * {@code String.valueOf(double)}. Returns {@code "null"} if {@code a} + * is {@code null}. + * + * @param a the array whose string representation to return + * @return a string representation of {@code a} + * @since 1.5 + */ + public static String toString(double[] a) { + if (a == null) + return "null"; + int iMax = a.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(a[i]); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } + } + + /** + * Returns a string representation of the contents of the specified array. + * If the array contains other arrays as elements, they are converted to + * strings by the {@link Object#toString} method inherited from + * {@code Object}, which describes their identities rather than + * their contents. + * + *

The value returned by this method is equal to the value that would + * be returned by {@code Arrays.asList(a).toString()}, unless {@code a} + * is {@code null}, in which case {@code "null"} is returned. + * + * @param a the array whose string representation to return + * @return a string representation of {@code a} + * @see #deepToString(Object[]) + * @since 1.5 + */ + public static String toString(Object[] a) { + if (a == null) + return "null"; + + int iMax = a.length - 1; + if (iMax == -1) + return "[]"; + + StringBuilder b = new StringBuilder(); + b.append('['); + for (int i = 0; ; i++) { + b.append(String.valueOf(a[i])); + if (i == iMax) + return b.append(']').toString(); + b.append(", "); + } + } + + /** + * Returns a string representation of the "deep contents" of the specified + * array. If the array contains other arrays as elements, the string + * representation contains their contents and so on. This method is + * designed for converting multidimensional arrays to strings. + * + *

The string representation consists of a list of the array's + * elements, enclosed in square brackets ({@code "[]"}). Adjacent + * elements are separated by the characters {@code ", "} (a comma + * followed by a space). Elements are converted to strings as by + * {@code String.valueOf(Object)}, unless they are themselves + * arrays. + * + *

If an element {@code e} is an array of a primitive type, it is + * converted to a string as by invoking the appropriate overloading of + * {@code Arrays.toString(e)}. If an element {@code e} is an array of a + * reference type, it is converted to a string as by invoking + * this method recursively. + * + *

To avoid infinite recursion, if the specified array contains itself + * as an element, or contains an indirect reference to itself through one + * or more levels of arrays, the self-reference is converted to the string + * {@code "[...]"}. For example, an array containing only a reference + * to itself would be rendered as {@code "[[...]]"}. + * + *

This method returns {@code "null"} if the specified array + * is {@code null}. + * + * @param a the array whose string representation to return + * @return a string representation of {@code a} + * @see #toString(Object[]) + * @since 1.5 + */ + public static String deepToString(Object[] a) { + if (a == null) + return "null"; + + int bufLen = 20 * a.length; + if (a.length != 0 && bufLen <= 0) + bufLen = Integer.MAX_VALUE; + StringBuilder buf = new StringBuilder(bufLen); + deepToString(a, buf, new HashSet<>()); + return buf.toString(); + } + + private static void deepToString(Object[] a, StringBuilder buf, + Set dejaVu) { + if (a == null) { + buf.append("null"); + return; + } + int iMax = a.length - 1; + if (iMax == -1) { + buf.append("[]"); + return; + } + + dejaVu.add(a); + buf.append('['); + for (int i = 0; ; i++) { + + Object element = a[i]; + if (element == null) { + buf.append("null"); + } else { + Class eClass = element.getClass(); + + if (eClass.isArray()) { + if (eClass == byte[].class) + buf.append(toString((byte[]) element)); + else if (eClass == short[].class) + buf.append(toString((short[]) element)); + else if (eClass == int[].class) + buf.append(toString((int[]) element)); + else if (eClass == long[].class) + buf.append(toString((long[]) element)); + else if (eClass == char[].class) + buf.append(toString((char[]) element)); + else if (eClass == float[].class) + buf.append(toString((float[]) element)); + else if (eClass == double[].class) + buf.append(toString((double[]) element)); + else if (eClass == boolean[].class) + buf.append(toString((boolean[]) element)); + else { // element is an array of object references + if (dejaVu.contains(element)) + buf.append("[...]"); + else + deepToString((Object[])element, buf, dejaVu); + } + } else { // element is non-null and not an array + buf.append(element.toString()); + } + } + if (i == iMax) + break; + buf.append(", "); + } + buf.append(']'); + dejaVu.remove(a); + } + + + /** + * Set all elements of the specified array, using the provided + * generator function to compute each element. + * + *

If the generator function throws an exception, it is relayed to + * the caller and the array is left in an indeterminate state. + * + * @apiNote + * Setting a subrange of an array, using a generator function to compute + * each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.apply(i));
+     * }
+ * + * @param type of elements of the array + * @param array array to be initialized + * @param generator a function accepting an index and producing the desired + * value for that position + * @throws NullPointerException if the generator is null + * @since 1.8 + */ + public static void setAll(T[] array, IntFunction generator) { + Objects.requireNonNull(generator); + for (int i = 0; i < array.length; i++) + array[i] = generator.apply(i); + } + + /** + * Set all elements of the specified array, in parallel, using the + * provided generator function to compute each element. + * + *

If the generator function throws an exception, an unchecked exception + * is thrown from {@code parallelSetAll} and the array is left in an + * indeterminate state. + * + * @apiNote + * Setting a subrange of an array, in parallel, using a generator function + * to compute each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.apply(i));
+     * }
+ * + * @param type of elements of the array + * @param array array to be initialized + * @param generator a function accepting an index and producing the desired + * value for that position + * @throws NullPointerException if the generator is null + * @since 1.8 + */ + public static void parallelSetAll(T[] array, IntFunction generator) { + Objects.requireNonNull(generator); + IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.apply(i); }); + } + + /** + * Set all elements of the specified array, using the provided + * generator function to compute each element. + * + *

If the generator function throws an exception, it is relayed to + * the caller and the array is left in an indeterminate state. + * + * @apiNote + * Setting a subrange of an array, using a generator function to compute + * each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsInt(i));
+     * }
+ * + * @param array array to be initialized + * @param generator a function accepting an index and producing the desired + * value for that position + * @throws NullPointerException if the generator is null + * @since 1.8 + */ + public static void setAll(int[] array, IntUnaryOperator generator) { + Objects.requireNonNull(generator); + for (int i = 0; i < array.length; i++) + array[i] = generator.applyAsInt(i); + } + + /** + * Set all elements of the specified array, in parallel, using the + * provided generator function to compute each element. + * + *

If the generator function throws an exception, an unchecked exception + * is thrown from {@code parallelSetAll} and the array is left in an + * indeterminate state. + * + * @apiNote + * Setting a subrange of an array, in parallel, using a generator function + * to compute each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsInt(i));
+     * }
+ * + * @param array array to be initialized + * @param generator a function accepting an index and producing the desired + * value for that position + * @throws NullPointerException if the generator is null + * @since 1.8 + */ + public static void parallelSetAll(int[] array, IntUnaryOperator generator) { + Objects.requireNonNull(generator); + IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsInt(i); }); + } + + /** + * Set all elements of the specified array, using the provided + * generator function to compute each element. + * + *

If the generator function throws an exception, it is relayed to + * the caller and the array is left in an indeterminate state. + * + * @apiNote + * Setting a subrange of an array, using a generator function to compute + * each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsLong(i));
+     * }
+ * + * @param array array to be initialized + * @param generator a function accepting an index and producing the desired + * value for that position + * @throws NullPointerException if the generator is null + * @since 1.8 + */ + public static void setAll(long[] array, IntToLongFunction generator) { + Objects.requireNonNull(generator); + for (int i = 0; i < array.length; i++) + array[i] = generator.applyAsLong(i); + } + + /** + * Set all elements of the specified array, in parallel, using the + * provided generator function to compute each element. + * + *

If the generator function throws an exception, an unchecked exception + * is thrown from {@code parallelSetAll} and the array is left in an + * indeterminate state. + * + * @apiNote + * Setting a subrange of an array, in parallel, using a generator function + * to compute each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsLong(i));
+     * }
+ * + * @param array array to be initialized + * @param generator a function accepting an index and producing the desired + * value for that position + * @throws NullPointerException if the generator is null + * @since 1.8 + */ + public static void parallelSetAll(long[] array, IntToLongFunction generator) { + Objects.requireNonNull(generator); + IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsLong(i); }); + } + + /** + * Set all elements of the specified array, using the provided + * generator function to compute each element. + * + *

If the generator function throws an exception, it is relayed to + * the caller and the array is left in an indeterminate state. + * + * @apiNote + * Setting a subrange of an array, using a generator function to compute + * each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .forEach(i -> array[i] = generator.applyAsDouble(i));
+     * }
+ * + * @param array array to be initialized + * @param generator a function accepting an index and producing the desired + * value for that position + * @throws NullPointerException if the generator is null + * @since 1.8 + */ + public static void setAll(double[] array, IntToDoubleFunction generator) { + Objects.requireNonNull(generator); + for (int i = 0; i < array.length; i++) + array[i] = generator.applyAsDouble(i); + } + + /** + * Set all elements of the specified array, in parallel, using the + * provided generator function to compute each element. + * + *

If the generator function throws an exception, an unchecked exception + * is thrown from {@code parallelSetAll} and the array is left in an + * indeterminate state. + * + * @apiNote + * Setting a subrange of an array, in parallel, using a generator function + * to compute each element, can be written as follows: + *

{@code
+     * IntStream.range(startInclusive, endExclusive)
+     *          .parallel()
+     *          .forEach(i -> array[i] = generator.applyAsDouble(i));
+     * }
+ * + * @param array array to be initialized + * @param generator a function accepting an index and producing the desired + * value for that position + * @throws NullPointerException if the generator is null + * @since 1.8 + */ + public static void parallelSetAll(double[] array, IntToDoubleFunction generator) { + Objects.requireNonNull(generator); + IntStream.range(0, array.length).parallel().forEach(i -> { array[i] = generator.applyAsDouble(i); }); + } + + /** + * Returns a {@link Spliterator} covering all of the specified array. + * + *

The spliterator reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and + * {@link Spliterator#IMMUTABLE}. + * + * @param type of elements + * @param array the array, assumed to be unmodified during use + * @return a spliterator for the array elements + * @since 1.8 + */ + public static Spliterator spliterator(T[] array) { + return Spliterators.spliterator(array, + Spliterator.ORDERED | Spliterator.IMMUTABLE); + } + + /** + * Returns a {@link Spliterator} covering the specified range of the + * specified array. + * + *

The spliterator reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and + * {@link Spliterator#IMMUTABLE}. + * + * @param type of elements + * @param array the array, assumed to be unmodified during use + * @param startInclusive the first index to cover, inclusive + * @param endExclusive index immediately past the last index to cover + * @return a spliterator for the array elements + * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is + * negative, {@code endExclusive} is less than + * {@code startInclusive}, or {@code endExclusive} is greater than + * the array size + * @since 1.8 + */ + public static Spliterator spliterator(T[] array, int startInclusive, int endExclusive) { + return Spliterators.spliterator(array, startInclusive, endExclusive, + Spliterator.ORDERED | Spliterator.IMMUTABLE); + } + + /** + * Returns a {@link Spliterator.OfInt} covering all of the specified array. + * + *

The spliterator reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and + * {@link Spliterator#IMMUTABLE}. + * + * @param array the array, assumed to be unmodified during use + * @return a spliterator for the array elements + * @since 1.8 + */ + public static Spliterator.OfInt spliterator(int[] array) { + return Spliterators.spliterator(array, + Spliterator.ORDERED | Spliterator.IMMUTABLE); + } + + /** + * Returns a {@link Spliterator.OfInt} covering the specified range of the + * specified array. + * + *

The spliterator reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and + * {@link Spliterator#IMMUTABLE}. + * + * @param array the array, assumed to be unmodified during use + * @param startInclusive the first index to cover, inclusive + * @param endExclusive index immediately past the last index to cover + * @return a spliterator for the array elements + * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is + * negative, {@code endExclusive} is less than + * {@code startInclusive}, or {@code endExclusive} is greater than + * the array size + * @since 1.8 + */ + public static Spliterator.OfInt spliterator(int[] array, int startInclusive, int endExclusive) { + return Spliterators.spliterator(array, startInclusive, endExclusive, + Spliterator.ORDERED | Spliterator.IMMUTABLE); + } + + /** + * Returns a {@link Spliterator.OfLong} covering all of the specified array. + * + *

The spliterator reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and + * {@link Spliterator#IMMUTABLE}. + * + * @param array the array, assumed to be unmodified during use + * @return the spliterator for the array elements + * @since 1.8 + */ + public static Spliterator.OfLong spliterator(long[] array) { + return Spliterators.spliterator(array, + Spliterator.ORDERED | Spliterator.IMMUTABLE); + } + + /** + * Returns a {@link Spliterator.OfLong} covering the specified range of the + * specified array. + * + *

The spliterator reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and + * {@link Spliterator#IMMUTABLE}. + * + * @param array the array, assumed to be unmodified during use + * @param startInclusive the first index to cover, inclusive + * @param endExclusive index immediately past the last index to cover + * @return a spliterator for the array elements + * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is + * negative, {@code endExclusive} is less than + * {@code startInclusive}, or {@code endExclusive} is greater than + * the array size + * @since 1.8 + */ + public static Spliterator.OfLong spliterator(long[] array, int startInclusive, int endExclusive) { + return Spliterators.spliterator(array, startInclusive, endExclusive, + Spliterator.ORDERED | Spliterator.IMMUTABLE); + } + + /** + * Returns a {@link Spliterator.OfDouble} covering all of the specified + * array. + * + *

The spliterator reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and + * {@link Spliterator#IMMUTABLE}. + * + * @param array the array, assumed to be unmodified during use + * @return a spliterator for the array elements + * @since 1.8 + */ + public static Spliterator.OfDouble spliterator(double[] array) { + return Spliterators.spliterator(array, + Spliterator.ORDERED | Spliterator.IMMUTABLE); + } + + /** + * Returns a {@link Spliterator.OfDouble} covering the specified range of + * the specified array. + * + *

The spliterator reports {@link Spliterator#SIZED}, + * {@link Spliterator#SUBSIZED}, {@link Spliterator#ORDERED}, and + * {@link Spliterator#IMMUTABLE}. + * + * @param array the array, assumed to be unmodified during use + * @param startInclusive the first index to cover, inclusive + * @param endExclusive index immediately past the last index to cover + * @return a spliterator for the array elements + * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is + * negative, {@code endExclusive} is less than + * {@code startInclusive}, or {@code endExclusive} is greater than + * the array size + * @since 1.8 + */ + public static Spliterator.OfDouble spliterator(double[] array, int startInclusive, int endExclusive) { + return Spliterators.spliterator(array, startInclusive, endExclusive, + Spliterator.ORDERED | Spliterator.IMMUTABLE); + } + + /** + * Returns a sequential {@link Stream} with the specified array as its + * source. + * + * @param The type of the array elements + * @param array The array, assumed to be unmodified during use + * @return a {@code Stream} for the array + * @since 1.8 + */ + public static Stream stream(T[] array) { + return stream(array, 0, array.length); + } + + /** + * Returns a sequential {@link Stream} with the specified range of the + * specified array as its source. + * + * @param the type of the array elements + * @param array the array, assumed to be unmodified during use + * @param startInclusive the first index to cover, inclusive + * @param endExclusive index immediately past the last index to cover + * @return a {@code Stream} for the array range + * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is + * negative, {@code endExclusive} is less than + * {@code startInclusive}, or {@code endExclusive} is greater than + * the array size + * @since 1.8 + */ + public static Stream stream(T[] array, int startInclusive, int endExclusive) { + return StreamSupport.stream(spliterator(array, startInclusive, endExclusive), false); + } + + /** + * Returns a sequential {@link IntStream} with the specified array as its + * source. + * + * @param array the array, assumed to be unmodified during use + * @return an {@code IntStream} for the array + * @since 1.8 + */ + public static IntStream stream(int[] array) { + return stream(array, 0, array.length); + } + + /** + * Returns a sequential {@link IntStream} with the specified range of the + * specified array as its source. + * + * @param array the array, assumed to be unmodified during use + * @param startInclusive the first index to cover, inclusive + * @param endExclusive index immediately past the last index to cover + * @return an {@code IntStream} for the array range + * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is + * negative, {@code endExclusive} is less than + * {@code startInclusive}, or {@code endExclusive} is greater than + * the array size + * @since 1.8 + */ + public static IntStream stream(int[] array, int startInclusive, int endExclusive) { + return StreamSupport.intStream(spliterator(array, startInclusive, endExclusive), false); + } + + /** + * Returns a sequential {@link LongStream} with the specified array as its + * source. + * + * @param array the array, assumed to be unmodified during use + * @return a {@code LongStream} for the array + * @since 1.8 + */ + public static LongStream stream(long[] array) { + return stream(array, 0, array.length); + } + + /** + * Returns a sequential {@link LongStream} with the specified range of the + * specified array as its source. + * + * @param array the array, assumed to be unmodified during use + * @param startInclusive the first index to cover, inclusive + * @param endExclusive index immediately past the last index to cover + * @return a {@code LongStream} for the array range + * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is + * negative, {@code endExclusive} is less than + * {@code startInclusive}, or {@code endExclusive} is greater than + * the array size + * @since 1.8 + */ + public static LongStream stream(long[] array, int startInclusive, int endExclusive) { + return StreamSupport.longStream(spliterator(array, startInclusive, endExclusive), false); + } + + /** + * Returns a sequential {@link DoubleStream} with the specified array as its + * source. + * + * @param array the array, assumed to be unmodified during use + * @return a {@code DoubleStream} for the array + * @since 1.8 + */ + public static DoubleStream stream(double[] array) { + return stream(array, 0, array.length); + } + + /** + * Returns a sequential {@link DoubleStream} with the specified range of the + * specified array as its source. + * + * @param array the array, assumed to be unmodified during use + * @param startInclusive the first index to cover, inclusive + * @param endExclusive index immediately past the last index to cover + * @return a {@code DoubleStream} for the array range + * @throws ArrayIndexOutOfBoundsException if {@code startInclusive} is + * negative, {@code endExclusive} is less than + * {@code startInclusive}, or {@code endExclusive} is greater than + * the array size + * @since 1.8 + */ + public static DoubleStream stream(double[] array, int startInclusive, int endExclusive) { + return StreamSupport.doubleStream(spliterator(array, startInclusive, endExclusive), false); + } + + + // Comparison methods + + // Compare boolean + + /** + * Compares two {@code boolean} arrays lexicographically. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Boolean#compare(boolean, boolean)}, at an index within the + * respective arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(boolean[], boolean[])} for the definition of a + * common and proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + *

The comparison is consistent with {@link #equals(boolean[], boolean[]) equals}, + * more specifically the following holds for arrays {@code a} and {@code b}: + *

{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Boolean.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are equal and + * contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compare(boolean[] a, boolean[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Boolean.compare(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code boolean} arrays lexicographically over the specified + * ranges. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Boolean#compare(boolean, boolean)}, at a + * relative index within the respective arrays that is the length of the + * prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(boolean[], int, int, boolean[], int, int)} for the + * definition of a common and proper prefix.) + * + *

The comparison is consistent with + * {@link #equals(boolean[], int, int, boolean[], int, int) equals}, more + * specifically the following holds for arrays {@code a} and {@code b} with + * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively: + *

{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Boolean.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int compare(boolean[] a, int aFromIndex, int aToIndex, + boolean[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Boolean.compare(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + // Compare byte + + /** + * Compares two {@code byte} arrays lexicographically. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Byte#compare(byte, byte)}, at an index within the respective + * arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(byte[], byte[])} for the definition of a common and + * proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + *

The comparison is consistent with {@link #equals(byte[], byte[]) equals}, + * more specifically the following holds for arrays {@code a} and {@code b}: + *

{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Byte.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are equal and + * contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compare(byte[] a, byte[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Byte.compare(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code byte} arrays lexicographically over the specified + * ranges. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Byte#compare(byte, byte)}, at a relative index + * within the respective arrays that is the length of the prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(byte[], int, int, byte[], int, int)} for the + * definition of a common and proper prefix.) + * + *

The comparison is consistent with + * {@link #equals(byte[], int, int, byte[], int, int) equals}, more + * specifically the following holds for arrays {@code a} and {@code b} with + * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively: + *

{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Byte.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int compare(byte[] a, int aFromIndex, int aToIndex, + byte[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Byte.compare(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + /** + * Compares two {@code byte} arrays lexicographically, numerically treating + * elements as unsigned. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Byte#compareUnsigned(byte, byte)}, at an index within the + * respective arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(byte[], byte[])} for the definition of a common + * and proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Byte.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are + * equal and contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compareUnsigned(byte[] a, byte[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Byte.compareUnsigned(a[i], b[i]); + } + + return a.length - b.length; + } + + + /** + * Compares two {@code byte} arrays lexicographically over the specified + * ranges, numerically treating elements as unsigned. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Byte#compareUnsigned(byte, byte)}, at a + * relative index within the respective arrays that is the length of the + * prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(byte[], int, int, byte[], int, int)} for the + * definition of a common and proper prefix.) + * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Byte.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is null + * @since 9 + */ + public static int compareUnsigned(byte[] a, int aFromIndex, int aToIndex, + byte[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Byte.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + // Compare short + + /** + * Compares two {@code short} arrays lexicographically. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Short#compare(short, short)}, at an index within the respective + * arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(short[], short[])} for the definition of a common + * and proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + *

The comparison is consistent with {@link #equals(short[], short[]) equals}, + * more specifically the following holds for arrays {@code a} and {@code b}: + *

{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Short.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are equal and + * contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compare(short[] a, short[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Short.compare(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code short} arrays lexicographically over the specified + * ranges. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Short#compare(short, short)}, at a relative + * index within the respective arrays that is the length of the prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(short[], int, int, short[], int, int)} for the + * definition of a common and proper prefix.) + * + *

The comparison is consistent with + * {@link #equals(short[], int, int, short[], int, int) equals}, more + * specifically the following holds for arrays {@code a} and {@code b} with + * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively: + *

{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Short.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int compare(short[] a, int aFromIndex, int aToIndex, + short[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Short.compare(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + /** + * Compares two {@code short} arrays lexicographically, numerically treating + * elements as unsigned. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Short#compareUnsigned(short, short)}, at an index within the + * respective arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(short[], short[])} for the definition of a common + * and proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Short.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are + * equal and contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compareUnsigned(short[] a, short[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Short.compareUnsigned(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code short} arrays lexicographically over the specified + * ranges, numerically treating elements as unsigned. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Short#compareUnsigned(short, short)}, at a + * relative index within the respective arrays that is the length of the + * prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(short[], int, int, short[], int, int)} for the + * definition of a common and proper prefix.) + * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Short.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is null + * @since 9 + */ + public static int compareUnsigned(short[] a, int aFromIndex, int aToIndex, + short[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Short.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + // Compare char + + /** + * Compares two {@code char} arrays lexicographically. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Character#compare(char, char)}, at an index within the respective + * arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(char[], char[])} for the definition of a common and + * proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + *

The comparison is consistent with {@link #equals(char[], char[]) equals}, + * more specifically the following holds for arrays {@code a} and {@code b}: + *

{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Character.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are equal and + * contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compare(char[] a, char[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Character.compare(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code char} arrays lexicographically over the specified + * ranges. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Character#compare(char, char)}, at a relative + * index within the respective arrays that is the length of the prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(char[], int, int, char[], int, int)} for the + * definition of a common and proper prefix.) + * + *

The comparison is consistent with + * {@link #equals(char[], int, int, char[], int, int) equals}, more + * specifically the following holds for arrays {@code a} and {@code b} with + * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively: + *

{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Character.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int compare(char[] a, int aFromIndex, int aToIndex, + char[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Character.compare(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + // Compare int + + /** + * Compares two {@code int} arrays lexicographically. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Integer#compare(int, int)}, at an index within the respective + * arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(int[], int[])} for the definition of a common and + * proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + *

The comparison is consistent with {@link #equals(int[], int[]) equals}, + * more specifically the following holds for arrays {@code a} and {@code b}: + *

{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Integer.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are equal and + * contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compare(int[] a, int[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Integer.compare(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code int} arrays lexicographically over the specified + * ranges. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Integer#compare(int, int)}, at a relative index + * within the respective arrays that is the length of the prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(int[], int, int, int[], int, int)} for the + * definition of a common and proper prefix.) + * + *

The comparison is consistent with + * {@link #equals(int[], int, int, int[], int, int) equals}, more + * specifically the following holds for arrays {@code a} and {@code b} with + * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively: + *

{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Integer.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int compare(int[] a, int aFromIndex, int aToIndex, + int[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Integer.compare(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + /** + * Compares two {@code int} arrays lexicographically, numerically treating + * elements as unsigned. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Integer#compareUnsigned(int, int)}, at an index within the + * respective arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(int[], int[])} for the definition of a common + * and proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Integer.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are + * equal and contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compareUnsigned(int[] a, int[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Integer.compareUnsigned(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code int} arrays lexicographically over the specified + * ranges, numerically treating elements as unsigned. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Integer#compareUnsigned(int, int)}, at a + * relative index within the respective arrays that is the length of the + * prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(int[], int, int, int[], int, int)} for the + * definition of a common and proper prefix.) + * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Integer.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is null + * @since 9 + */ + public static int compareUnsigned(int[] a, int aFromIndex, int aToIndex, + int[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Integer.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + // Compare long + + /** + * Compares two {@code long} arrays lexicographically. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Long#compare(long, long)}, at an index within the respective + * arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(long[], long[])} for the definition of a common and + * proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + *

The comparison is consistent with {@link #equals(long[], long[]) equals}, + * more specifically the following holds for arrays {@code a} and {@code b}: + *

{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Long.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are equal and + * contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compare(long[] a, long[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Long.compare(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code long} arrays lexicographically over the specified + * ranges. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Long#compare(long, long)}, at a relative index + * within the respective arrays that is the length of the prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(long[], int, int, long[], int, int)} for the + * definition of a common and proper prefix.) + * + *

The comparison is consistent with + * {@link #equals(long[], int, int, long[], int, int) equals}, more + * specifically the following holds for arrays {@code a} and {@code b} with + * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively: + *

{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Long.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int compare(long[] a, int aFromIndex, int aToIndex, + long[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Long.compare(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + /** + * Compares two {@code long} arrays lexicographically, numerically treating + * elements as unsigned. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Long#compareUnsigned(long, long)}, at an index within the + * respective arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(long[], long[])} for the definition of a common + * and proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Long.compareUnsigned(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are + * equal and contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compareUnsigned(long[] a, long[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Long.compareUnsigned(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code long} arrays lexicographically over the specified + * ranges, numerically treating elements as unsigned. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Long#compareUnsigned(long, long)}, at a + * relative index within the respective arrays that is the length of the + * prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(long[], int, int, long[], int, int)} for the + * definition of a common and proper prefix.) + * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Long.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is null + * @since 9 + */ + public static int compareUnsigned(long[] a, int aFromIndex, int aToIndex, + long[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Long.compareUnsigned(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + // Compare float + + /** + * Compares two {@code float} arrays lexicographically. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Float#compare(float, float)}, at an index within the respective + * arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(float[], float[])} for the definition of a common + * and proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + *

The comparison is consistent with {@link #equals(float[], float[]) equals}, + * more specifically the following holds for arrays {@code a} and {@code b}: + *

{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Float.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are equal and + * contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compare(float[] a, float[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Float.compare(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code float} arrays lexicographically over the specified + * ranges. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Float#compare(float, float)}, at a relative + * index within the respective arrays that is the length of the prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(float[], int, int, float[], int, int)} for the + * definition of a common and proper prefix.) + * + *

The comparison is consistent with + * {@link #equals(float[], int, int, float[], int, int) equals}, more + * specifically the following holds for arrays {@code a} and {@code b} with + * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively: + *

{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Float.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int compare(float[] a, int aFromIndex, int aToIndex, + float[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Float.compare(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + // Compare double + + /** + * Compares two {@code double} arrays lexicographically. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements, as if by + * {@link Double#compare(double, double)}, at an index within the respective + * arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(double[], double[])} for the definition of a common + * and proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + *

The comparison is consistent with {@link #equals(double[], double[]) equals}, + * more specifically the following holds for arrays {@code a} and {@code b}: + *

{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return Double.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @return the value {@code 0} if the first and second array are equal and + * contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static int compare(double[] a, double[] b) { + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int i = ArraysSupport.mismatch(a, b, + Math.min(a.length, b.length)); + if (i >= 0) { + return Double.compare(a[i], b[i]); + } + + return a.length - b.length; + } + + /** + * Compares two {@code double} arrays lexicographically over the specified + * ranges. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements, as if by {@link Double#compare(double, double)}, at a relative + * index within the respective arrays that is the length of the prefix. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(double[], int, int, double[], int, int)} for the + * definition of a common and proper prefix.) + * + *

The comparison is consistent with + * {@link #equals(double[], int, int, double[], int, int) equals}, more + * specifically the following holds for arrays {@code a} and {@code b} with + * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively: + *

{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if: + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return Double.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int compare(double[] a, int aFromIndex, int aToIndex, + double[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + Math.min(aLength, bLength)); + if (i >= 0) { + return Double.compare(a[aFromIndex + i], b[bFromIndex + i]); + } + + return aLength - bLength; + } + + // Compare objects + + /** + * Compares two {@code Object} arrays, within comparable elements, + * lexicographically. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing two elements of type {@code T} at + * an index {@code i} within the respective arrays that is the prefix + * length, as if by: + *

{@code
+     *     Comparator.nullsFirst(Comparator.naturalOrder()).
+     *         compare(a[i], b[i])
+     * }
+ * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(Object[], Object[])} for the definition of a common + * and proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * A {@code null} array element is considered lexicographically than a + * non-{@code null} array element. Two {@code null} array elements are + * considered equal. + * + *

The comparison is consistent with {@link #equals(Object[], Object[]) equals}, + * more specifically the following holds for arrays {@code a} and {@code b}: + *

{@code
+     *     Arrays.equals(a, b) == (Arrays.compare(a, b) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if (for non-{@code null} array references + * and elements): + *

{@code
+     *     int i = Arrays.mismatch(a, b);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return a[i].compareTo(b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @param the type of comparable array elements + * @return the value {@code 0} if the first and second array are equal and + * contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @since 9 + */ + public static > int compare(T[] a, T[] b) { + if (a == b) + return 0; + // A null array is less than a non-null array + if (a == null || b == null) + return a == null ? -1 : 1; + + int length = Math.min(a.length, b.length); + for (int i = 0; i < length; i++) { + T oa = a[i]; + T ob = b[i]; + if (oa != ob) { + // A null element is less than a non-null element + if (oa == null || ob == null) + return oa == null ? -1 : 1; + int v = oa.compareTo(ob); + if (v != 0) { + return v; + } + } + } + + return a.length - b.length; + } + + /** + * Compares two {@code Object} arrays lexicographically over the specified + * ranges. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing two + * elements of type {@code T} at a relative index {@code i} within the + * respective arrays that is the prefix length, as if by: + *

{@code
+     *     Comparator.nullsFirst(Comparator.naturalOrder()).
+     *         compare(a[aFromIndex + i, b[bFromIndex + i])
+     * }
+ * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(Object[], int, int, Object[], int, int)} for the + * definition of a common and proper prefix.) + * + *

The comparison is consistent with + * {@link #equals(Object[], int, int, Object[], int, int) equals}, more + * specifically the following holds for arrays {@code a} and {@code b} with + * specified ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively: + *

{@code
+     *     Arrays.equals(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) ==
+     *         (Arrays.compare(a, aFromIndex, aToIndex, b, bFromIndex, bToIndex) == 0)
+     * }
+ * + * @apiNote + *

This method behaves as if (for non-{@code null} array elements): + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return a[aFromIndex + i].compareTo(b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @param the type of comparable array elements + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static > int compare( + T[] a, int aFromIndex, int aToIndex, + T[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + for (int i = 0; i < length; i++) { + T oa = a[aFromIndex++]; + T ob = b[bFromIndex++]; + if (oa != ob) { + if (oa == null || ob == null) + return oa == null ? -1 : 1; + int v = oa.compareTo(ob); + if (v != 0) { + return v; + } + } + } + + return aLength - bLength; + } + + /** + * Compares two {@code Object} arrays lexicographically using a specified + * comparator. + * + *

If the two arrays share a common prefix then the lexicographic + * comparison is the result of comparing with the specified comparator two + * elements at an index within the respective arrays that is the prefix + * length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two array lengths. + * (See {@link #mismatch(Object[], Object[])} for the definition of a common + * and proper prefix.) + * + *

A {@code null} array reference is considered lexicographically less + * than a non-{@code null} array reference. Two {@code null} array + * references are considered equal. + * + * @apiNote + *

This method behaves as if (for non-{@code null} array references): + *

{@code
+     *     int i = Arrays.mismatch(a, b, cmp);
+     *     if (i >= 0 && i < Math.min(a.length, b.length))
+     *         return cmp.compare(a[i], b[i]);
+     *     return a.length - b.length;
+     * }
+ * + * @param a the first array to compare + * @param b the second array to compare + * @param cmp the comparator to compare array elements + * @param the type of array elements + * @return the value {@code 0} if the first and second array are equal and + * contain the same elements in the same order; + * a value less than {@code 0} if the first array is + * lexicographically less than the second array; and + * a value greater than {@code 0} if the first array is + * lexicographically greater than the second array + * @throws NullPointerException if the comparator is {@code null} + * @since 9 + */ + public static int compare(T[] a, T[] b, + Comparator cmp) { + Objects.requireNonNull(cmp); + if (a == b) + return 0; + if (a == null || b == null) + return a == null ? -1 : 1; + + int length = Math.min(a.length, b.length); + for (int i = 0; i < length; i++) { + T oa = a[i]; + T ob = b[i]; + if (oa != ob) { + // Null-value comparison is deferred to the comparator + int v = cmp.compare(oa, ob); + if (v != 0) { + return v; + } + } + } + + return a.length - b.length; + } + + /** + * Compares two {@code Object} arrays lexicographically over the specified + * ranges. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the lexicographic comparison is the result of comparing with the + * specified comparator two elements at a relative index within the + * respective arrays that is the prefix length. + * Otherwise, one array is a proper prefix of the other and, lexicographic + * comparison is the result of comparing the two range lengths. + * (See {@link #mismatch(Object[], int, int, Object[], int, int)} for the + * definition of a common and proper prefix.) + * + * @apiNote + *

This method behaves as if (for non-{@code null} array elements): + *

{@code
+     *     int i = Arrays.mismatch(a, aFromIndex, aToIndex,
+     *                             b, bFromIndex, bToIndex, cmp);
+     *     if (i >= 0 && i < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     *         return cmp.compare(a[aFromIndex + i], b[bFromIndex + i]);
+     *     return (aToIndex - aFromIndex) - (bToIndex - bFromIndex);
+     * }
+ * + * @param a the first array to compare + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be compared + * @param aToIndex the index (exclusive) of the last element in the + * first array to be compared + * @param b the second array to compare + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be compared + * @param bToIndex the index (exclusive) of the last element in the + * second array to be compared + * @param cmp the comparator to compare array elements + * @param the type of array elements + * @return the value {@code 0} if, over the specified ranges, the first and + * second array are equal and contain the same elements in the same + * order; + * a value less than {@code 0} if, over the specified ranges, the + * first array is lexicographically less than the second array; and + * a value greater than {@code 0} if, over the specified ranges, the + * first array is lexicographically greater than the second array + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array or the comparator is {@code null} + * @since 9 + */ + public static int compare( + T[] a, int aFromIndex, int aToIndex, + T[] b, int bFromIndex, int bToIndex, + Comparator cmp) { + Objects.requireNonNull(cmp); + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + for (int i = 0; i < length; i++) { + T oa = a[aFromIndex++]; + T ob = b[bFromIndex++]; + if (oa != ob) { + // Null-value comparison is deferred to the comparator + int v = cmp.compare(oa, ob); + if (v != 0) { + return v; + } + } + } + + return aLength - bLength; + } + + + // Mismatch methods + + // Mismatch boolean + + /** + * Finds and returns the index of the first mismatch between two + * {@code boolean} arrays, otherwise return -1 if no mismatch is found. The + * index will be in the range of 0 (inclusive) up to the length (inclusive) + * of the smaller array. + * + *

If the two arrays share a common prefix then the returned index is the + * length of the common prefix and it follows that there is a mismatch + * between the two elements at that index within the respective arrays. + * If one array is a proper prefix of the other then the returned index is + * the length of the smaller array and it follows that the index is only + * valid for the larger array. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + * prefix if the following expression is true: + *

{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param b the second array to be tested for a mismatch + * @return the index of the first mismatch between the two arrays, + * otherwise {@code -1}. + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(boolean[] a, boolean[] b) { + int length = Math.min(a.length, b.length); // Check null array refs + if (a == b) + return -1; + + int i = ArraysSupport.mismatch(a, b, length); + return (i < 0 && a.length != b.length) ? length : i; + } + + /** + * Finds and returns the relative index of the first mismatch between two + * {@code boolean} arrays over the specified ranges, otherwise return -1 if + * no mismatch is found. The index will be in the range of 0 (inclusive) up + * to the length (inclusive) of the smaller range. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the returned relative index is the length of the common prefix and + * it follows that there is a mismatch between the two elements at that + * relative index within the respective arrays. + * If one array is a proper prefix of the other, over the specified ranges, + * then the returned relative index is the length of the smaller range and + * it follows that the relative index is only valid for the array with the + * larger range. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + * if the following expression is true: + *

{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for a mismatch + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return the relative index of the first mismatch between the two arrays + * over the specified ranges, otherwise {@code -1}. + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(boolean[] a, int aFromIndex, int aToIndex, + boolean[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + length); + return (i < 0 && aLength != bLength) ? length : i; + } + + // Mismatch byte + + /** + * Finds and returns the index of the first mismatch between two {@code byte} + * arrays, otherwise return -1 if no mismatch is found. The index will be + * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + * array. + * + *

If the two arrays share a common prefix then the returned index is the + * length of the common prefix and it follows that there is a mismatch + * between the two elements at that index within the respective arrays. + * If one array is a proper prefix of the other then the returned index is + * the length of the smaller array and it follows that the index is only + * valid for the larger array. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + * prefix if the following expression is true: + *

{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param b the second array to be tested for a mismatch + * @return the index of the first mismatch between the two arrays, + * otherwise {@code -1}. + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(byte[] a, byte[] b) { + int length = Math.min(a.length, b.length); // Check null array refs + if (a == b) + return -1; + + int i = ArraysSupport.mismatch(a, b, length); + return (i < 0 && a.length != b.length) ? length : i; + } + + /** + * Finds and returns the relative index of the first mismatch between two + * {@code byte} arrays over the specified ranges, otherwise return -1 if no + * mismatch is found. The index will be in the range of 0 (inclusive) up to + * the length (inclusive) of the smaller range. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the returned relative index is the length of the common prefix and + * it follows that there is a mismatch between the two elements at that + * relative index within the respective arrays. + * If one array is a proper prefix of the other, over the specified ranges, + * then the returned relative index is the length of the smaller range and + * it follows that the relative index is only valid for the array with the + * larger range. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + * if the following expression is true: + *

{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for a mismatch + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return the relative index of the first mismatch between the two arrays + * over the specified ranges, otherwise {@code -1}. + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(byte[] a, int aFromIndex, int aToIndex, + byte[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + length); + return (i < 0 && aLength != bLength) ? length : i; + } + + // Mismatch char + + /** + * Finds and returns the index of the first mismatch between two {@code char} + * arrays, otherwise return -1 if no mismatch is found. The index will be + * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + * array. + * + *

If the two arrays share a common prefix then the returned index is the + * length of the common prefix and it follows that there is a mismatch + * between the two elements at that index within the respective arrays. + * If one array is a proper prefix of the other then the returned index is + * the length of the smaller array and it follows that the index is only + * valid for the larger array. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + * prefix if the following expression is true: + *

{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param b the second array to be tested for a mismatch + * @return the index of the first mismatch between the two arrays, + * otherwise {@code -1}. + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(char[] a, char[] b) { + int length = Math.min(a.length, b.length); // Check null array refs + if (a == b) + return -1; + + int i = ArraysSupport.mismatch(a, b, length); + return (i < 0 && a.length != b.length) ? length : i; + } + + /** + * Finds and returns the relative index of the first mismatch between two + * {@code char} arrays over the specified ranges, otherwise return -1 if no + * mismatch is found. The index will be in the range of 0 (inclusive) up to + * the length (inclusive) of the smaller range. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the returned relative index is the length of the common prefix and + * it follows that there is a mismatch between the two elements at that + * relative index within the respective arrays. + * If one array is a proper prefix of the other, over the specified ranges, + * then the returned relative index is the length of the smaller range and + * it follows that the relative index is only valid for the array with the + * larger range. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + * if the following expression is true: + *

{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for a mismatch + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return the relative index of the first mismatch between the two arrays + * over the specified ranges, otherwise {@code -1}. + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(char[] a, int aFromIndex, int aToIndex, + char[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + length); + return (i < 0 && aLength != bLength) ? length : i; + } + + // Mismatch short + + /** + * Finds and returns the index of the first mismatch between two {@code short} + * arrays, otherwise return -1 if no mismatch is found. The index will be + * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + * array. + * + *

If the two arrays share a common prefix then the returned index is the + * length of the common prefix and it follows that there is a mismatch + * between the two elements at that index within the respective arrays. + * If one array is a proper prefix of the other then the returned index is + * the length of the smaller array and it follows that the index is only + * valid for the larger array. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + * prefix if the following expression is true: + *

{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param b the second array to be tested for a mismatch + * @return the index of the first mismatch between the two arrays, + * otherwise {@code -1}. + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(short[] a, short[] b) { + int length = Math.min(a.length, b.length); // Check null array refs + if (a == b) + return -1; + + int i = ArraysSupport.mismatch(a, b, length); + return (i < 0 && a.length != b.length) ? length : i; + } + + /** + * Finds and returns the relative index of the first mismatch between two + * {@code short} arrays over the specified ranges, otherwise return -1 if no + * mismatch is found. The index will be in the range of 0 (inclusive) up to + * the length (inclusive) of the smaller range. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the returned relative index is the length of the common prefix and + * it follows that there is a mismatch between the two elements at that + * relative index within the respective arrays. + * If one array is a proper prefix of the other, over the specified ranges, + * then the returned relative index is the length of the smaller range and + * it follows that the relative index is only valid for the array with the + * larger range. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + * if the following expression is true: + *

{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for a mismatch + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return the relative index of the first mismatch between the two arrays + * over the specified ranges, otherwise {@code -1}. + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(short[] a, int aFromIndex, int aToIndex, + short[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + length); + return (i < 0 && aLength != bLength) ? length : i; + } + + // Mismatch int + + /** + * Finds and returns the index of the first mismatch between two {@code int} + * arrays, otherwise return -1 if no mismatch is found. The index will be + * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + * array. + * + *

If the two arrays share a common prefix then the returned index is the + * length of the common prefix and it follows that there is a mismatch + * between the two elements at that index within the respective arrays. + * If one array is a proper prefix of the other then the returned index is + * the length of the smaller array and it follows that the index is only + * valid for the larger array. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + * prefix if the following expression is true: + *

{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param b the second array to be tested for a mismatch + * @return the index of the first mismatch between the two arrays, + * otherwise {@code -1}. + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(int[] a, int[] b) { + int length = Math.min(a.length, b.length); // Check null array refs + if (a == b) + return -1; + + int i = ArraysSupport.mismatch(a, b, length); + return (i < 0 && a.length != b.length) ? length : i; + } + + /** + * Finds and returns the relative index of the first mismatch between two + * {@code int} arrays over the specified ranges, otherwise return -1 if no + * mismatch is found. The index will be in the range of 0 (inclusive) up to + * the length (inclusive) of the smaller range. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the returned relative index is the length of the common prefix and + * it follows that there is a mismatch between the two elements at that + * relative index within the respective arrays. + * If one array is a proper prefix of the other, over the specified ranges, + * then the returned relative index is the length of the smaller range and + * it follows that the relative index is only valid for the array with the + * larger range. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + * if the following expression is true: + *

{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for a mismatch + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return the relative index of the first mismatch between the two arrays + * over the specified ranges, otherwise {@code -1}. + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(int[] a, int aFromIndex, int aToIndex, + int[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + length); + return (i < 0 && aLength != bLength) ? length : i; + } + + // Mismatch long + + /** + * Finds and returns the index of the first mismatch between two {@code long} + * arrays, otherwise return -1 if no mismatch is found. The index will be + * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + * array. + * + *

If the two arrays share a common prefix then the returned index is the + * length of the common prefix and it follows that there is a mismatch + * between the two elements at that index within the respective arrays. + * If one array is a proper prefix of the other then the returned index is + * the length of the smaller array and it follows that the index is only + * valid for the larger array. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     a[pl] != b[pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + * prefix if the following expression is true: + *

{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param b the second array to be tested for a mismatch + * @return the index of the first mismatch between the two arrays, + * otherwise {@code -1}. + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(long[] a, long[] b) { + int length = Math.min(a.length, b.length); // Check null array refs + if (a == b) + return -1; + + int i = ArraysSupport.mismatch(a, b, length); + return (i < 0 && a.length != b.length) ? length : i; + } + + /** + * Finds and returns the relative index of the first mismatch between two + * {@code long} arrays over the specified ranges, otherwise return -1 if no + * mismatch is found. The index will be in the range of 0 (inclusive) up to + * the length (inclusive) of the smaller range. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the returned relative index is the length of the common prefix and + * it follows that there is a mismatch between the two elements at that + * relative index within the respective arrays. + * If one array is a proper prefix of the other, over the specified ranges, + * then the returned relative index is the length of the smaller range and + * it follows that the relative index is only valid for the array with the + * larger range. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     a[aFromIndex + pl] != b[bFromIndex + pl]
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + * if the following expression is true: + *

{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for a mismatch + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return the relative index of the first mismatch between the two arrays + * over the specified ranges, otherwise {@code -1}. + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(long[] a, int aFromIndex, int aToIndex, + long[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + length); + return (i < 0 && aLength != bLength) ? length : i; + } + + // Mismatch float + + /** + * Finds and returns the index of the first mismatch between two {@code float} + * arrays, otherwise return -1 if no mismatch is found. The index will be + * in the range of 0 (inclusive) up to the length (inclusive) of the smaller + * array. + * + *

If the two arrays share a common prefix then the returned index is the + * length of the common prefix and it follows that there is a mismatch + * between the two elements at that index within the respective arrays. + * If one array is a proper prefix of the other then the returned index is + * the length of the smaller array and it follows that the index is only + * valid for the larger array. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     Float.compare(a[pl], b[pl]) != 0
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + * prefix if the following expression is true: + *

{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param b the second array to be tested for a mismatch + * @return the index of the first mismatch between the two arrays, + * otherwise {@code -1}. + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(float[] a, float[] b) { + int length = Math.min(a.length, b.length); // Check null array refs + if (a == b) + return -1; + + int i = ArraysSupport.mismatch(a, b, length); + return (i < 0 && a.length != b.length) ? length : i; + } + + /** + * Finds and returns the relative index of the first mismatch between two + * {@code float} arrays over the specified ranges, otherwise return -1 if no + * mismatch is found. The index will be in the range of 0 (inclusive) up to + * the length (inclusive) of the smaller range. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the returned relative index is the length of the common prefix and + * it follows that there is a mismatch between the two elements at that + * relative index within the respective arrays. + * If one array is a proper prefix of the other, over the specified ranges, + * then the returned relative index is the length of the smaller range and + * it follows that the relative index is only valid for the array with the + * larger range. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     Float.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + * if the following expression is true: + *

{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for a mismatch + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return the relative index of the first mismatch between the two arrays + * over the specified ranges, otherwise {@code -1}. + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(float[] a, int aFromIndex, int aToIndex, + float[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + length); + return (i < 0 && aLength != bLength) ? length : i; + } + + // Mismatch double + + /** + * Finds and returns the index of the first mismatch between two + * {@code double} arrays, otherwise return -1 if no mismatch is found. The + * index will be in the range of 0 (inclusive) up to the length (inclusive) + * of the smaller array. + * + *

If the two arrays share a common prefix then the returned index is the + * length of the common prefix and it follows that there is a mismatch + * between the two elements at that index within the respective arrays. + * If one array is a proper prefix of the other then the returned index is + * the length of the smaller array and it follows that the index is only + * valid for the larger array. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     Double.compare(a[pl], b[pl]) != 0
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + * prefix if the following expression is true: + *

{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param b the second array to be tested for a mismatch + * @return the index of the first mismatch between the two arrays, + * otherwise {@code -1}. + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(double[] a, double[] b) { + int length = Math.min(a.length, b.length); // Check null array refs + if (a == b) + return -1; + + int i = ArraysSupport.mismatch(a, b, length); + return (i < 0 && a.length != b.length) ? length : i; + } + + /** + * Finds and returns the relative index of the first mismatch between two + * {@code double} arrays over the specified ranges, otherwise return -1 if + * no mismatch is found. The index will be in the range of 0 (inclusive) up + * to the length (inclusive) of the smaller range. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the returned relative index is the length of the common prefix and + * it follows that there is a mismatch between the two elements at that + * relative index within the respective arrays. + * If one array is a proper prefix of the other, over the specified ranges, + * then the returned relative index is the length of the smaller range and + * it follows that the relative index is only valid for the array with the + * larger range. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     Double.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + * if the following expression is true: + *

{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for a mismatch + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return the relative index of the first mismatch between the two arrays + * over the specified ranges, otherwise {@code -1}. + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(double[] a, int aFromIndex, int aToIndex, + double[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + int i = ArraysSupport.mismatch(a, aFromIndex, + b, bFromIndex, + length); + return (i < 0 && aLength != bLength) ? length : i; + } + + // Mismatch objects + + /** + * Finds and returns the index of the first mismatch between two + * {@code Object} arrays, otherwise return -1 if no mismatch is found. The + * index will be in the range of 0 (inclusive) up to the length (inclusive) + * of the smaller array. + * + *

If the two arrays share a common prefix then the returned index is the + * length of the common prefix and it follows that there is a mismatch + * between the two elements at that index within the respective arrays. + * If one array is a proper prefix of the other then the returned index is + * the length of the smaller array and it follows that the index is only + * valid for the larger array. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl) &&
+     *     !Objects.equals(a[pl], b[pl])
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + * prefix if the following expression is true: + *

{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param b the second array to be tested for a mismatch + * @return the index of the first mismatch between the two arrays, + * otherwise {@code -1}. + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch(Object[] a, Object[] b) { + int length = Math.min(a.length, b.length); // Check null array refs + if (a == b) + return -1; + + for (int i = 0; i < length; i++) { + if (!Objects.equals(a[i], b[i])) + return i; + } + + return a.length != b.length ? length : -1; + } + + /** + * Finds and returns the relative index of the first mismatch between two + * {@code Object} arrays over the specified ranges, otherwise return -1 if + * no mismatch is found. The index will be in the range of 0 (inclusive) up + * to the length (inclusive) of the smaller range. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the returned relative index is the length of the common prefix and + * it follows that there is a mismatch between the two elements at that + * relative index within the respective arrays. + * If one array is a proper prefix of the other, over the specified ranges, + * then the returned relative index is the length of the smaller range and + * it follows that the relative index is only valid for the array with the + * larger range. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl) &&
+     *     !Objects.equals(a[aFromIndex + pl], b[bFromIndex + pl])
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + * if the following expression is true: + *

{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex))
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for a mismatch + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @return the relative index of the first mismatch between the two arrays + * over the specified ranges, otherwise {@code -1}. + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array is {@code null} + * @since 9 + */ + public static int mismatch( + Object[] a, int aFromIndex, int aToIndex, + Object[] b, int bFromIndex, int bToIndex) { + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + for (int i = 0; i < length; i++) { + if (!Objects.equals(a[aFromIndex++], b[bFromIndex++])) + return i; + } + + return aLength != bLength ? length : -1; + } + + /** + * Finds and returns the index of the first mismatch between two + * {@code Object} arrays, otherwise return -1 if no mismatch is found. + * The index will be in the range of 0 (inclusive) up to the length + * (inclusive) of the smaller array. + * + *

The specified comparator is used to determine if two array elements + * from the each array are not equal. + * + *

If the two arrays share a common prefix then the returned index is the + * length of the common prefix and it follows that there is a mismatch + * between the two elements at that index within the respective arrays. + * If one array is a proper prefix of the other then the returned index is + * the length of the smaller array and it follows that the index is only + * valid for the larger array. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(a.length, b.length) &&
+     *     Arrays.equals(a, 0, pl, b, 0, pl, cmp)
+     *     cmp.compare(a[pl], b[pl]) != 0
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b}, share a proper + * prefix if the following expression is true: + *

{@code
+     *     a.length != b.length &&
+     *     Arrays.equals(a, 0, Math.min(a.length, b.length),
+     *                   b, 0, Math.min(a.length, b.length),
+     *                   cmp)
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param b the second array to be tested for a mismatch + * @param cmp the comparator to compare array elements + * @param the type of array elements + * @return the index of the first mismatch between the two arrays, + * otherwise {@code -1}. + * @throws NullPointerException + * if either array or the comparator is {@code null} + * @since 9 + */ + public static int mismatch(T[] a, T[] b, Comparator cmp) { + Objects.requireNonNull(cmp); + int length = Math.min(a.length, b.length); // Check null array refs + if (a == b) + return -1; + + for (int i = 0; i < length; i++) { + T oa = a[i]; + T ob = b[i]; + if (oa != ob) { + // Null-value comparison is deferred to the comparator + int v = cmp.compare(oa, ob); + if (v != 0) { + return i; + } + } + } + + return a.length != b.length ? length : -1; + } + + /** + * Finds and returns the relative index of the first mismatch between two + * {@code Object} arrays over the specified ranges, otherwise return -1 if + * no mismatch is found. The index will be in the range of 0 (inclusive) up + * to the length (inclusive) of the smaller range. + * + *

If the two arrays, over the specified ranges, share a common prefix + * then the returned relative index is the length of the common prefix and + * it follows that there is a mismatch between the two elements at that + * relative index within the respective arrays. + * If one array is a proper prefix of the other, over the specified ranges, + * then the returned relative index is the length of the smaller range and + * it follows that the relative index is only valid for the array with the + * larger range. + * Otherwise, there is no mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a common + * prefix of length {@code pl} if the following expression is true: + *

{@code
+     *     pl >= 0 &&
+     *     pl < Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, aFromIndex, aFromIndex + pl, b, bFromIndex, bFromIndex + pl, cmp) &&
+     *     cmp.compare(a[aFromIndex + pl], b[bFromIndex + pl]) != 0
+     * }
+ * Note that a common prefix length of {@code 0} indicates that the first + * elements from each array mismatch. + * + *

Two non-{@code null} arrays, {@code a} and {@code b} with specified + * ranges [{@code aFromIndex}, {@code atoIndex}) and + * [{@code bFromIndex}, {@code btoIndex}) respectively, share a proper + * if the following expression is true: + *

{@code
+     *     (aToIndex - aFromIndex) != (bToIndex - bFromIndex) &&
+     *     Arrays.equals(a, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   b, 0, Math.min(aToIndex - aFromIndex, bToIndex - bFromIndex),
+     *                   cmp)
+     * }
+ * + * @param a the first array to be tested for a mismatch + * @param aFromIndex the index (inclusive) of the first element in the + * first array to be tested + * @param aToIndex the index (exclusive) of the last element in the + * first array to be tested + * @param b the second array to be tested for a mismatch + * @param bFromIndex the index (inclusive) of the first element in the + * second array to be tested + * @param bToIndex the index (exclusive) of the last element in the + * second array to be tested + * @param cmp the comparator to compare array elements + * @param the type of array elements + * @return the relative index of the first mismatch between the two arrays + * over the specified ranges, otherwise {@code -1}. + * @throws IllegalArgumentException + * if {@code aFromIndex > aToIndex} or + * if {@code bFromIndex > bToIndex} + * @throws ArrayIndexOutOfBoundsException + * if {@code aFromIndex < 0 or aToIndex > a.length} or + * if {@code bFromIndex < 0 or bToIndex > b.length} + * @throws NullPointerException + * if either array or the comparator is {@code null} + * @since 9 + */ + public static int mismatch( + T[] a, int aFromIndex, int aToIndex, + T[] b, int bFromIndex, int bToIndex, + Comparator cmp) { + Objects.requireNonNull(cmp); + rangeCheck(a.length, aFromIndex, aToIndex); + rangeCheck(b.length, bFromIndex, bToIndex); + + int aLength = aToIndex - aFromIndex; + int bLength = bToIndex - bFromIndex; + int length = Math.min(aLength, bLength); + for (int i = 0; i < length; i++) { + T oa = a[aFromIndex++]; + T ob = b[bFromIndex++]; + if (oa != ob) { + // Null-value comparison is deferred to the comparator + int v = cmp.compare(oa, ob); + if (v != 0) { + return i; + } + } + } + return aLength != bLength ? length : -1; + } +} --- old/src/java.base/share/classes/java/util/ArraysParallelSortHelpers.java 2019-07-17 17:04:36.548314315 +0200 +++ new/src/java.base/share/classes/java/util/ArraysParallelSortHelpers.java 2019-07-17 17:04:36.248314319 +0200 @@ -1,1010 +1,227 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package java.util; - -import java.util.concurrent.RecursiveAction; -import java.util.concurrent.CountedCompleter; - -/** - * Helper utilities for the parallel sort methods in Arrays.parallelSort. - * - * For each primitive type, plus Object, we define a static class to - * contain the Sorter and Merger implementations for that type: - * - * Sorter classes based mainly on CilkSort - * Cilk: - * Basic algorithm: - * if array size is small, just use a sequential quicksort (via Arrays.sort) - * Otherwise: - * 1. Break array in half. - * 2. For each half, - * a. break the half in half (i.e., quarters), - * b. sort the quarters - * c. merge them together - * 3. merge together the two halves. - * - * One reason for splitting in quarters is that this guarantees that - * the final sort is in the main array, not the workspace array. - * (workspace and main swap roles on each subsort step.) Leaf-level - * sorts use the associated sequential sort. - * - * Merger classes perform merging for Sorter. They are structured - * such that if the underlying sort is stable (as is true for - * TimSort), then so is the full sort. If big enough, they split the - * largest of the two partitions in half, find the greatest point in - * smaller partition less than the beginning of the second half of - * larger via binary search; and then merge in parallel the two - * partitions. In part to ensure tasks are triggered in - * stability-preserving order, the current CountedCompleter design - * requires some little tasks to serve as place holders for triggering - * completion tasks. These classes (EmptyCompleter and Relay) don't - * need to keep track of the arrays, and are never themselves forked, - * so don't hold any task state. - * - * The primitive class versions (FJByte... FJDouble) are - * identical to each other except for type declarations. - * - * The base sequential sorts rely on non-public versions of TimSort, - * ComparableTimSort, and DualPivotQuicksort sort methods that accept - * temp workspace array slices that we will have already allocated, so - * avoids redundant allocation. (Except for DualPivotQuicksort byte[] - * sort, that does not ever use a workspace array.) - */ -/*package*/ class ArraysParallelSortHelpers { - - /* - * Style note: The task classes have a lot of parameters, that are - * stored as task fields and copied to local variables and used in - * compute() methods, We pack these into as few lines as possible, - * and hoist consistency checks among them before main loops, to - * reduce distraction. - */ - - /** - * A placeholder task for Sorters, used for the lowest - * quartile task, that does not need to maintain array state. - */ - static final class EmptyCompleter extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - EmptyCompleter(CountedCompleter p) { super(p); } - public final void compute() { } - } - - /** - * A trigger for secondary merge of two merges - */ - static final class Relay extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final CountedCompleter task; - Relay(CountedCompleter task) { - super(null, 1); - this.task = task; - } - public final void compute() { } - public final void onCompletion(CountedCompleter t) { - task.compute(); - } - } - - /** Object + Comparator support class */ - static final class FJObject { - static final class Sorter extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final T[] a, w; - final int base, size, wbase, gran; - Comparator comparator; - Sorter(CountedCompleter par, T[] a, T[] w, int base, int size, - int wbase, int gran, - Comparator comparator) { - super(par); - this.a = a; this.w = w; this.base = base; this.size = size; - this.wbase = wbase; this.gran = gran; - this.comparator = comparator; - } - public final void compute() { - CountedCompleter s = this; - Comparator c = this.comparator; - T[] a = this.a, w = this.w; // localize all params - int b = this.base, n = this.size, wb = this.wbase, g = this.gran; - while (n > g) { - int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles - Relay fc = new Relay(new Merger<>(s, w, a, wb, h, - wb+h, n-h, b, g, c)); - Relay rc = new Relay(new Merger<>(fc, a, w, b+h, q, - b+u, n-u, wb+h, g, c)); - new Sorter<>(rc, a, w, b+u, n-u, wb+u, g, c).fork(); - new Sorter<>(rc, a, w, b+h, q, wb+h, g, c).fork();; - Relay bc = new Relay(new Merger<>(fc, a, w, b, q, - b+q, h-q, wb, g, c)); - new Sorter<>(bc, a, w, b+q, h-q, wb+q, g, c).fork(); - s = new EmptyCompleter(bc); - n = q; - } - TimSort.sort(a, b, b + n, c, w, wb, n); - s.tryComplete(); - } - } - - static final class Merger extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final T[] a, w; // main and workspace arrays - final int lbase, lsize, rbase, rsize, wbase, gran; - Comparator comparator; - Merger(CountedCompleter par, T[] a, T[] w, - int lbase, int lsize, int rbase, - int rsize, int wbase, int gran, - Comparator comparator) { - super(par); - this.a = a; this.w = w; - this.lbase = lbase; this.lsize = lsize; - this.rbase = rbase; this.rsize = rsize; - this.wbase = wbase; this.gran = gran; - this.comparator = comparator; - } - - public final void compute() { - Comparator c = this.comparator; - T[] a = this.a, w = this.w; // localize all params - int lb = this.lbase, ln = this.lsize, rb = this.rbase, - rn = this.rsize, k = this.wbase, g = this.gran; - if (a == null || w == null || lb < 0 || rb < 0 || k < 0 || - c == null) - throw new IllegalStateException(); // hoist checks - for (int lh, rh;;) { // split larger, find point in smaller - if (ln >= rn) { - if (ln <= g) - break; - rh = rn; - T split = a[(lh = ln >>> 1) + lb]; - for (int lo = 0; lo < rh; ) { - int rm = (lo + rh) >>> 1; - if (c.compare(split, a[rm + rb]) <= 0) - rh = rm; - else - lo = rm + 1; - } - } - else { - if (rn <= g) - break; - lh = ln; - T split = a[(rh = rn >>> 1) + rb]; - for (int lo = 0; lo < lh; ) { - int lm = (lo + lh) >>> 1; - if (c.compare(split, a[lm + lb]) <= 0) - lh = lm; - else - lo = lm + 1; - } - } - Merger m = new Merger<>(this, a, w, lb + lh, ln - lh, - rb + rh, rn - rh, - k + lh + rh, g, c); - rn = rh; - ln = lh; - addToPendingCount(1); - m.fork(); - } - - int lf = lb + ln, rf = rb + rn; // index bounds - while (lb < lf && rb < rf) { - T t, al, ar; - if (c.compare((al = a[lb]), (ar = a[rb])) <= 0) { - lb++; t = al; - } - else { - rb++; t = ar; - } - w[k++] = t; - } - if (rb < rf) - System.arraycopy(a, rb, w, k, rf - rb); - else if (lb < lf) - System.arraycopy(a, lb, w, k, lf - lb); - - tryComplete(); - } - - } - } // FJObject - - /** byte support class */ - static final class FJByte { - static final class Sorter extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final byte[] a, w; - final int base, size, wbase, gran; - Sorter(CountedCompleter par, byte[] a, byte[] w, int base, - int size, int wbase, int gran) { - super(par); - this.a = a; this.w = w; this.base = base; this.size = size; - this.wbase = wbase; this.gran = gran; - } - public final void compute() { - CountedCompleter s = this; - byte[] a = this.a, w = this.w; // localize all params - int b = this.base, n = this.size, wb = this.wbase, g = this.gran; - while (n > g) { - int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles - Relay fc = new Relay(new Merger(s, w, a, wb, h, - wb+h, n-h, b, g)); - Relay rc = new Relay(new Merger(fc, a, w, b+h, q, - b+u, n-u, wb+h, g)); - new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); - new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; - Relay bc = new Relay(new Merger(fc, a, w, b, q, - b+q, h-q, wb, g)); - new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); - s = new EmptyCompleter(bc); - n = q; - } - DualPivotQuicksort.sort(a, b, b + n - 1); - s.tryComplete(); - } - } - - static final class Merger extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final byte[] a, w; // main and workspace arrays - final int lbase, lsize, rbase, rsize, wbase, gran; - Merger(CountedCompleter par, byte[] a, byte[] w, - int lbase, int lsize, int rbase, - int rsize, int wbase, int gran) { - super(par); - this.a = a; this.w = w; - this.lbase = lbase; this.lsize = lsize; - this.rbase = rbase; this.rsize = rsize; - this.wbase = wbase; this.gran = gran; - } - - public final void compute() { - byte[] a = this.a, w = this.w; // localize all params - int lb = this.lbase, ln = this.lsize, rb = this.rbase, - rn = this.rsize, k = this.wbase, g = this.gran; - if (a == null || w == null || lb < 0 || rb < 0 || k < 0) - throw new IllegalStateException(); // hoist checks - for (int lh, rh;;) { // split larger, find point in smaller - if (ln >= rn) { - if (ln <= g) - break; - rh = rn; - byte split = a[(lh = ln >>> 1) + lb]; - for (int lo = 0; lo < rh; ) { - int rm = (lo + rh) >>> 1; - if (split <= a[rm + rb]) - rh = rm; - else - lo = rm + 1; - } - } - else { - if (rn <= g) - break; - lh = ln; - byte split = a[(rh = rn >>> 1) + rb]; - for (int lo = 0; lo < lh; ) { - int lm = (lo + lh) >>> 1; - if (split <= a[lm + lb]) - lh = lm; - else - lo = lm + 1; - } - } - Merger m = new Merger(this, a, w, lb + lh, ln - lh, - rb + rh, rn - rh, - k + lh + rh, g); - rn = rh; - ln = lh; - addToPendingCount(1); - m.fork(); - } - - int lf = lb + ln, rf = rb + rn; // index bounds - while (lb < lf && rb < rf) { - byte t, al, ar; - if ((al = a[lb]) <= (ar = a[rb])) { - lb++; t = al; - } - else { - rb++; t = ar; - } - w[k++] = t; - } - if (rb < rf) - System.arraycopy(a, rb, w, k, rf - rb); - else if (lb < lf) - System.arraycopy(a, lb, w, k, lf - lb); - tryComplete(); - } - } - } // FJByte - - /** char support class */ - static final class FJChar { - static final class Sorter extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final char[] a, w; - final int base, size, wbase, gran; - Sorter(CountedCompleter par, char[] a, char[] w, int base, - int size, int wbase, int gran) { - super(par); - this.a = a; this.w = w; this.base = base; this.size = size; - this.wbase = wbase; this.gran = gran; - } - public final void compute() { - CountedCompleter s = this; - char[] a = this.a, w = this.w; // localize all params - int b = this.base, n = this.size, wb = this.wbase, g = this.gran; - while (n > g) { - int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles - Relay fc = new Relay(new Merger(s, w, a, wb, h, - wb+h, n-h, b, g)); - Relay rc = new Relay(new Merger(fc, a, w, b+h, q, - b+u, n-u, wb+h, g)); - new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); - new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; - Relay bc = new Relay(new Merger(fc, a, w, b, q, - b+q, h-q, wb, g)); - new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); - s = new EmptyCompleter(bc); - n = q; - } - DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); - s.tryComplete(); - } - } - - static final class Merger extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final char[] a, w; // main and workspace arrays - final int lbase, lsize, rbase, rsize, wbase, gran; - Merger(CountedCompleter par, char[] a, char[] w, - int lbase, int lsize, int rbase, - int rsize, int wbase, int gran) { - super(par); - this.a = a; this.w = w; - this.lbase = lbase; this.lsize = lsize; - this.rbase = rbase; this.rsize = rsize; - this.wbase = wbase; this.gran = gran; - } - - public final void compute() { - char[] a = this.a, w = this.w; // localize all params - int lb = this.lbase, ln = this.lsize, rb = this.rbase, - rn = this.rsize, k = this.wbase, g = this.gran; - if (a == null || w == null || lb < 0 || rb < 0 || k < 0) - throw new IllegalStateException(); // hoist checks - for (int lh, rh;;) { // split larger, find point in smaller - if (ln >= rn) { - if (ln <= g) - break; - rh = rn; - char split = a[(lh = ln >>> 1) + lb]; - for (int lo = 0; lo < rh; ) { - int rm = (lo + rh) >>> 1; - if (split <= a[rm + rb]) - rh = rm; - else - lo = rm + 1; - } - } - else { - if (rn <= g) - break; - lh = ln; - char split = a[(rh = rn >>> 1) + rb]; - for (int lo = 0; lo < lh; ) { - int lm = (lo + lh) >>> 1; - if (split <= a[lm + lb]) - lh = lm; - else - lo = lm + 1; - } - } - Merger m = new Merger(this, a, w, lb + lh, ln - lh, - rb + rh, rn - rh, - k + lh + rh, g); - rn = rh; - ln = lh; - addToPendingCount(1); - m.fork(); - } - - int lf = lb + ln, rf = rb + rn; // index bounds - while (lb < lf && rb < rf) { - char t, al, ar; - if ((al = a[lb]) <= (ar = a[rb])) { - lb++; t = al; - } - else { - rb++; t = ar; - } - w[k++] = t; - } - if (rb < rf) - System.arraycopy(a, rb, w, k, rf - rb); - else if (lb < lf) - System.arraycopy(a, lb, w, k, lf - lb); - tryComplete(); - } - } - } // FJChar - - /** short support class */ - static final class FJShort { - static final class Sorter extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final short[] a, w; - final int base, size, wbase, gran; - Sorter(CountedCompleter par, short[] a, short[] w, int base, - int size, int wbase, int gran) { - super(par); - this.a = a; this.w = w; this.base = base; this.size = size; - this.wbase = wbase; this.gran = gran; - } - public final void compute() { - CountedCompleter s = this; - short[] a = this.a, w = this.w; // localize all params - int b = this.base, n = this.size, wb = this.wbase, g = this.gran; - while (n > g) { - int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles - Relay fc = new Relay(new Merger(s, w, a, wb, h, - wb+h, n-h, b, g)); - Relay rc = new Relay(new Merger(fc, a, w, b+h, q, - b+u, n-u, wb+h, g)); - new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); - new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; - Relay bc = new Relay(new Merger(fc, a, w, b, q, - b+q, h-q, wb, g)); - new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); - s = new EmptyCompleter(bc); - n = q; - } - DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); - s.tryComplete(); - } - } - - static final class Merger extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final short[] a, w; // main and workspace arrays - final int lbase, lsize, rbase, rsize, wbase, gran; - Merger(CountedCompleter par, short[] a, short[] w, - int lbase, int lsize, int rbase, - int rsize, int wbase, int gran) { - super(par); - this.a = a; this.w = w; - this.lbase = lbase; this.lsize = lsize; - this.rbase = rbase; this.rsize = rsize; - this.wbase = wbase; this.gran = gran; - } - - public final void compute() { - short[] a = this.a, w = this.w; // localize all params - int lb = this.lbase, ln = this.lsize, rb = this.rbase, - rn = this.rsize, k = this.wbase, g = this.gran; - if (a == null || w == null || lb < 0 || rb < 0 || k < 0) - throw new IllegalStateException(); // hoist checks - for (int lh, rh;;) { // split larger, find point in smaller - if (ln >= rn) { - if (ln <= g) - break; - rh = rn; - short split = a[(lh = ln >>> 1) + lb]; - for (int lo = 0; lo < rh; ) { - int rm = (lo + rh) >>> 1; - if (split <= a[rm + rb]) - rh = rm; - else - lo = rm + 1; - } - } - else { - if (rn <= g) - break; - lh = ln; - short split = a[(rh = rn >>> 1) + rb]; - for (int lo = 0; lo < lh; ) { - int lm = (lo + lh) >>> 1; - if (split <= a[lm + lb]) - lh = lm; - else - lo = lm + 1; - } - } - Merger m = new Merger(this, a, w, lb + lh, ln - lh, - rb + rh, rn - rh, - k + lh + rh, g); - rn = rh; - ln = lh; - addToPendingCount(1); - m.fork(); - } - - int lf = lb + ln, rf = rb + rn; // index bounds - while (lb < lf && rb < rf) { - short t, al, ar; - if ((al = a[lb]) <= (ar = a[rb])) { - lb++; t = al; - } - else { - rb++; t = ar; - } - w[k++] = t; - } - if (rb < rf) - System.arraycopy(a, rb, w, k, rf - rb); - else if (lb < lf) - System.arraycopy(a, lb, w, k, lf - lb); - tryComplete(); - } - } - } // FJShort - - /** int support class */ - static final class FJInt { - static final class Sorter extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final int[] a, w; - final int base, size, wbase, gran; - Sorter(CountedCompleter par, int[] a, int[] w, int base, - int size, int wbase, int gran) { - super(par); - this.a = a; this.w = w; this.base = base; this.size = size; - this.wbase = wbase; this.gran = gran; - } - public final void compute() { - CountedCompleter s = this; - int[] a = this.a, w = this.w; // localize all params - int b = this.base, n = this.size, wb = this.wbase, g = this.gran; - while (n > g) { - int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles - Relay fc = new Relay(new Merger(s, w, a, wb, h, - wb+h, n-h, b, g)); - Relay rc = new Relay(new Merger(fc, a, w, b+h, q, - b+u, n-u, wb+h, g)); - new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); - new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; - Relay bc = new Relay(new Merger(fc, a, w, b, q, - b+q, h-q, wb, g)); - new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); - s = new EmptyCompleter(bc); - n = q; - } - DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); - s.tryComplete(); - } - } - - static final class Merger extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final int[] a, w; // main and workspace arrays - final int lbase, lsize, rbase, rsize, wbase, gran; - Merger(CountedCompleter par, int[] a, int[] w, - int lbase, int lsize, int rbase, - int rsize, int wbase, int gran) { - super(par); - this.a = a; this.w = w; - this.lbase = lbase; this.lsize = lsize; - this.rbase = rbase; this.rsize = rsize; - this.wbase = wbase; this.gran = gran; - } - - public final void compute() { - int[] a = this.a, w = this.w; // localize all params - int lb = this.lbase, ln = this.lsize, rb = this.rbase, - rn = this.rsize, k = this.wbase, g = this.gran; - if (a == null || w == null || lb < 0 || rb < 0 || k < 0) - throw new IllegalStateException(); // hoist checks - for (int lh, rh;;) { // split larger, find point in smaller - if (ln >= rn) { - if (ln <= g) - break; - rh = rn; - int split = a[(lh = ln >>> 1) + lb]; - for (int lo = 0; lo < rh; ) { - int rm = (lo + rh) >>> 1; - if (split <= a[rm + rb]) - rh = rm; - else - lo = rm + 1; - } - } - else { - if (rn <= g) - break; - lh = ln; - int split = a[(rh = rn >>> 1) + rb]; - for (int lo = 0; lo < lh; ) { - int lm = (lo + lh) >>> 1; - if (split <= a[lm + lb]) - lh = lm; - else - lo = lm + 1; - } - } - Merger m = new Merger(this, a, w, lb + lh, ln - lh, - rb + rh, rn - rh, - k + lh + rh, g); - rn = rh; - ln = lh; - addToPendingCount(1); - m.fork(); - } - - int lf = lb + ln, rf = rb + rn; // index bounds - while (lb < lf && rb < rf) { - int t, al, ar; - if ((al = a[lb]) <= (ar = a[rb])) { - lb++; t = al; - } - else { - rb++; t = ar; - } - w[k++] = t; - } - if (rb < rf) - System.arraycopy(a, rb, w, k, rf - rb); - else if (lb < lf) - System.arraycopy(a, lb, w, k, lf - lb); - tryComplete(); - } - } - } // FJInt - - /** long support class */ - static final class FJLong { - static final class Sorter extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final long[] a, w; - final int base, size, wbase, gran; - Sorter(CountedCompleter par, long[] a, long[] w, int base, - int size, int wbase, int gran) { - super(par); - this.a = a; this.w = w; this.base = base; this.size = size; - this.wbase = wbase; this.gran = gran; - } - public final void compute() { - CountedCompleter s = this; - long[] a = this.a, w = this.w; // localize all params - int b = this.base, n = this.size, wb = this.wbase, g = this.gran; - while (n > g) { - int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles - Relay fc = new Relay(new Merger(s, w, a, wb, h, - wb+h, n-h, b, g)); - Relay rc = new Relay(new Merger(fc, a, w, b+h, q, - b+u, n-u, wb+h, g)); - new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); - new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; - Relay bc = new Relay(new Merger(fc, a, w, b, q, - b+q, h-q, wb, g)); - new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); - s = new EmptyCompleter(bc); - n = q; - } - DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); - s.tryComplete(); - } - } - - static final class Merger extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final long[] a, w; // main and workspace arrays - final int lbase, lsize, rbase, rsize, wbase, gran; - Merger(CountedCompleter par, long[] a, long[] w, - int lbase, int lsize, int rbase, - int rsize, int wbase, int gran) { - super(par); - this.a = a; this.w = w; - this.lbase = lbase; this.lsize = lsize; - this.rbase = rbase; this.rsize = rsize; - this.wbase = wbase; this.gran = gran; - } - - public final void compute() { - long[] a = this.a, w = this.w; // localize all params - int lb = this.lbase, ln = this.lsize, rb = this.rbase, - rn = this.rsize, k = this.wbase, g = this.gran; - if (a == null || w == null || lb < 0 || rb < 0 || k < 0) - throw new IllegalStateException(); // hoist checks - for (int lh, rh;;) { // split larger, find point in smaller - if (ln >= rn) { - if (ln <= g) - break; - rh = rn; - long split = a[(lh = ln >>> 1) + lb]; - for (int lo = 0; lo < rh; ) { - int rm = (lo + rh) >>> 1; - if (split <= a[rm + rb]) - rh = rm; - else - lo = rm + 1; - } - } - else { - if (rn <= g) - break; - lh = ln; - long split = a[(rh = rn >>> 1) + rb]; - for (int lo = 0; lo < lh; ) { - int lm = (lo + lh) >>> 1; - if (split <= a[lm + lb]) - lh = lm; - else - lo = lm + 1; - } - } - Merger m = new Merger(this, a, w, lb + lh, ln - lh, - rb + rh, rn - rh, - k + lh + rh, g); - rn = rh; - ln = lh; - addToPendingCount(1); - m.fork(); - } - - int lf = lb + ln, rf = rb + rn; // index bounds - while (lb < lf && rb < rf) { - long t, al, ar; - if ((al = a[lb]) <= (ar = a[rb])) { - lb++; t = al; - } - else { - rb++; t = ar; - } - w[k++] = t; - } - if (rb < rf) - System.arraycopy(a, rb, w, k, rf - rb); - else if (lb < lf) - System.arraycopy(a, lb, w, k, lf - lb); - tryComplete(); - } - } - } // FJLong - - /** float support class */ - static final class FJFloat { - static final class Sorter extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final float[] a, w; - final int base, size, wbase, gran; - Sorter(CountedCompleter par, float[] a, float[] w, int base, - int size, int wbase, int gran) { - super(par); - this.a = a; this.w = w; this.base = base; this.size = size; - this.wbase = wbase; this.gran = gran; - } - public final void compute() { - CountedCompleter s = this; - float[] a = this.a, w = this.w; // localize all params - int b = this.base, n = this.size, wb = this.wbase, g = this.gran; - while (n > g) { - int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles - Relay fc = new Relay(new Merger(s, w, a, wb, h, - wb+h, n-h, b, g)); - Relay rc = new Relay(new Merger(fc, a, w, b+h, q, - b+u, n-u, wb+h, g)); - new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); - new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; - Relay bc = new Relay(new Merger(fc, a, w, b, q, - b+q, h-q, wb, g)); - new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); - s = new EmptyCompleter(bc); - n = q; - } - DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); - s.tryComplete(); - } - } - - static final class Merger extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final float[] a, w; // main and workspace arrays - final int lbase, lsize, rbase, rsize, wbase, gran; - Merger(CountedCompleter par, float[] a, float[] w, - int lbase, int lsize, int rbase, - int rsize, int wbase, int gran) { - super(par); - this.a = a; this.w = w; - this.lbase = lbase; this.lsize = lsize; - this.rbase = rbase; this.rsize = rsize; - this.wbase = wbase; this.gran = gran; - } - - public final void compute() { - float[] a = this.a, w = this.w; // localize all params - int lb = this.lbase, ln = this.lsize, rb = this.rbase, - rn = this.rsize, k = this.wbase, g = this.gran; - if (a == null || w == null || lb < 0 || rb < 0 || k < 0) - throw new IllegalStateException(); // hoist checks - for (int lh, rh;;) { // split larger, find point in smaller - if (ln >= rn) { - if (ln <= g) - break; - rh = rn; - float split = a[(lh = ln >>> 1) + lb]; - for (int lo = 0; lo < rh; ) { - int rm = (lo + rh) >>> 1; - if (split <= a[rm + rb]) - rh = rm; - else - lo = rm + 1; - } - } - else { - if (rn <= g) - break; - lh = ln; - float split = a[(rh = rn >>> 1) + rb]; - for (int lo = 0; lo < lh; ) { - int lm = (lo + lh) >>> 1; - if (split <= a[lm + lb]) - lh = lm; - else - lo = lm + 1; - } - } - Merger m = new Merger(this, a, w, lb + lh, ln - lh, - rb + rh, rn - rh, - k + lh + rh, g); - rn = rh; - ln = lh; - addToPendingCount(1); - m.fork(); - } - - int lf = lb + ln, rf = rb + rn; // index bounds - while (lb < lf && rb < rf) { - float t, al, ar; - if ((al = a[lb]) <= (ar = a[rb])) { - lb++; t = al; - } - else { - rb++; t = ar; - } - w[k++] = t; - } - if (rb < rf) - System.arraycopy(a, rb, w, k, rf - rb); - else if (lb < lf) - System.arraycopy(a, lb, w, k, lf - lb); - tryComplete(); - } - } - } // FJFloat - - /** double support class */ - static final class FJDouble { - static final class Sorter extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final double[] a, w; - final int base, size, wbase, gran; - Sorter(CountedCompleter par, double[] a, double[] w, int base, - int size, int wbase, int gran) { - super(par); - this.a = a; this.w = w; this.base = base; this.size = size; - this.wbase = wbase; this.gran = gran; - } - public final void compute() { - CountedCompleter s = this; - double[] a = this.a, w = this.w; // localize all params - int b = this.base, n = this.size, wb = this.wbase, g = this.gran; - while (n > g) { - int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles - Relay fc = new Relay(new Merger(s, w, a, wb, h, - wb+h, n-h, b, g)); - Relay rc = new Relay(new Merger(fc, a, w, b+h, q, - b+u, n-u, wb+h, g)); - new Sorter(rc, a, w, b+u, n-u, wb+u, g).fork(); - new Sorter(rc, a, w, b+h, q, wb+h, g).fork();; - Relay bc = new Relay(new Merger(fc, a, w, b, q, - b+q, h-q, wb, g)); - new Sorter(bc, a, w, b+q, h-q, wb+q, g).fork(); - s = new EmptyCompleter(bc); - n = q; - } - DualPivotQuicksort.sort(a, b, b + n - 1, w, wb, n); - s.tryComplete(); - } - } - - static final class Merger extends CountedCompleter { - static final long serialVersionUID = 2446542900576103244L; - final double[] a, w; // main and workspace arrays - final int lbase, lsize, rbase, rsize, wbase, gran; - Merger(CountedCompleter par, double[] a, double[] w, - int lbase, int lsize, int rbase, - int rsize, int wbase, int gran) { - super(par); - this.a = a; this.w = w; - this.lbase = lbase; this.lsize = lsize; - this.rbase = rbase; this.rsize = rsize; - this.wbase = wbase; this.gran = gran; - } - - public final void compute() { - double[] a = this.a, w = this.w; // localize all params - int lb = this.lbase, ln = this.lsize, rb = this.rbase, - rn = this.rsize, k = this.wbase, g = this.gran; - if (a == null || w == null || lb < 0 || rb < 0 || k < 0) - throw new IllegalStateException(); // hoist checks - for (int lh, rh;;) { // split larger, find point in smaller - if (ln >= rn) { - if (ln <= g) - break; - rh = rn; - double split = a[(lh = ln >>> 1) + lb]; - for (int lo = 0; lo < rh; ) { - int rm = (lo + rh) >>> 1; - if (split <= a[rm + rb]) - rh = rm; - else - lo = rm + 1; - } - } - else { - if (rn <= g) - break; - lh = ln; - double split = a[(rh = rn >>> 1) + rb]; - for (int lo = 0; lo < lh; ) { - int lm = (lo + lh) >>> 1; - if (split <= a[lm + lb]) - lh = lm; - else - lo = lm + 1; - } - } - Merger m = new Merger(this, a, w, lb + lh, ln - lh, - rb + rh, rn - rh, - k + lh + rh, g); - rn = rh; - ln = lh; - addToPendingCount(1); - m.fork(); - } - - int lf = lb + ln, rf = rb + rn; // index bounds - while (lb < lf && rb < rf) { - double t, al, ar; - if ((al = a[lb]) <= (ar = a[rb])) { - lb++; t = al; - } - else { - rb++; t = ar; - } - w[k++] = t; - } - if (rb < rf) - System.arraycopy(a, rb, w, k, rf - rb); - else if (lb < lf) - System.arraycopy(a, lb, w, k, lf - lb); - tryComplete(); - } - } - } // FJDouble - -} +/* + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +import java.util.concurrent.CountedCompleter; + +/** + * Helper utilities for the parallel sort methods in Arrays.parallelSort. + * + * For each primitive type, plus Object, we define a static class to + * contain the Sorter and Merger implementations for that type: + * + * Sorter classes based mainly on CilkSort + * Cilk: + * Basic algorithm: + * if array size is small, just use a sequential sort (via Arrays.sort) + * Otherwise: + * 1. Break array in half. + * 2. For each half, + * a. break the half in half (i.e., quarters), + * b. sort the quarters + * c. merge them together + * 3. merge together the two halves. + * + * One reason for splitting in quarters is that this guarantees that + * the final sort is in the main array, not the workspace array + * (workspace and main swap roles on each subsort step). Leaf-level + * sorts use the associated sequential sort. + * + * Merger classes perform merging for Sorter. They are structured + * such that if the underlying sort is stable (as is true for + * TimSort), then so is the full sort. If big enough, they split the + * largest of the two partitions in half, find the greatest point in + * smaller partition less than the beginning of the second half of + * larger via binary search; and then merge in parallel the two + * partitions. In part to ensure tasks are triggered in + * stability-preserving order, the current CountedCompleter design + * requires some little tasks to serve as place holders for triggering + * completion tasks. These classes (EmptyCompleter and Relay) don't + * need to keep track of the arrays, and are never themselves forked, + * so don't hold any task state. + * + * The base sequential sorts rely on non-public versions of TimSort, + * ComparableTimSort sort methods that accept temp workspace array + * slices that we will have already allocated, so avoids redundant + * allocation. + */ +/*package*/ class ArraysParallelSortHelpers { + + /* + * Style note: The task classes have a lot of parameters, that are + * stored as task fields and copied to local variables and used in + * compute() methods, We pack these into as few lines as possible, + * and hoist consistency checks among them before main loops, to + * reduce distraction. + */ + + /** + * A placeholder task for Sorters, used for the lowest + * quartile task, that does not need to maintain array state. + */ + static final class EmptyCompleter extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + EmptyCompleter(CountedCompleter p) { super(p); } + public final void compute() { } + } + + /** + * A trigger for secondary merge of two merges + */ + static final class Relay extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final CountedCompleter task; + Relay(CountedCompleter task) { + super(null, 1); + this.task = task; + } + public final void compute() { } + public final void onCompletion(CountedCompleter t) { + task.compute(); + } + } + + /** Object + Comparator support class */ + static final class FJObject { + static final class Sorter extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final T[] a, w; + final int base, size, wbase, gran; + Comparator comparator; + Sorter(CountedCompleter par, T[] a, T[] w, int base, int size, + int wbase, int gran, + Comparator comparator) { + super(par); + this.a = a; this.w = w; this.base = base; this.size = size; + this.wbase = wbase; this.gran = gran; + this.comparator = comparator; + } + public final void compute() { + CountedCompleter s = this; + Comparator c = this.comparator; + T[] a = this.a, w = this.w; // localize all params + int b = this.base, n = this.size, wb = this.wbase, g = this.gran; + while (n > g) { + int h = n >>> 1, q = h >>> 1, u = h + q; // quartiles + Relay fc = new Relay(new Merger<>(s, w, a, wb, h, + wb+h, n-h, b, g, c)); + Relay rc = new Relay(new Merger<>(fc, a, w, b+h, q, + b+u, n-u, wb+h, g, c)); + new Sorter<>(rc, a, w, b+u, n-u, wb+u, g, c).fork(); + new Sorter<>(rc, a, w, b+h, q, wb+h, g, c).fork(); + Relay bc = new Relay(new Merger<>(fc, a, w, b, q, + b+q, h-q, wb, g, c)); + new Sorter<>(bc, a, w, b+q, h-q, wb+q, g, c).fork(); + s = new EmptyCompleter(bc); + n = q; + } + TimSort.sort(a, b, b + n, c, w, wb, n); + s.tryComplete(); + } + } + + static final class Merger extends CountedCompleter { + static final long serialVersionUID = 2446542900576103244L; + final T[] a, w; // main and workspace arrays + final int lbase, lsize, rbase, rsize, wbase, gran; + Comparator comparator; + Merger(CountedCompleter par, T[] a, T[] w, + int lbase, int lsize, int rbase, + int rsize, int wbase, int gran, + Comparator comparator) { + super(par); + this.a = a; this.w = w; + this.lbase = lbase; this.lsize = lsize; + this.rbase = rbase; this.rsize = rsize; + this.wbase = wbase; this.gran = gran; + this.comparator = comparator; + } + + public final void compute() { + Comparator c = this.comparator; + T[] a = this.a, w = this.w; // localize all params + int lb = this.lbase, ln = this.lsize, rb = this.rbase, + rn = this.rsize, k = this.wbase, g = this.gran; + if (a == null || w == null || lb < 0 || rb < 0 || k < 0 || + c == null) + throw new IllegalStateException(); // hoist checks + for (int lh, rh;;) { // split larger, find point in smaller + if (ln >= rn) { + if (ln <= g) + break; + rh = rn; + T split = a[(lh = ln >>> 1) + lb]; + for (int lo = 0; lo < rh; ) { + int rm = (lo + rh) >>> 1; + if (c.compare(split, a[rm + rb]) <= 0) + rh = rm; + else + lo = rm + 1; + } + } + else { + if (rn <= g) + break; + lh = ln; + T split = a[(rh = rn >>> 1) + rb]; + for (int lo = 0; lo < lh; ) { + int lm = (lo + lh) >>> 1; + if (c.compare(split, a[lm + lb]) <= 0) + lh = lm; + else + lo = lm + 1; + } + } + Merger m = new Merger<>(this, a, w, lb + lh, ln - lh, + rb + rh, rn - rh, + k + lh + rh, g, c); + rn = rh; + ln = lh; + addToPendingCount(1); + m.fork(); + } + + int lf = lb + ln, rf = rb + rn; // index bounds + while (lb < lf && rb < rf) { + T t, al, ar; + if (c.compare((al = a[lb]), (ar = a[rb])) <= 0) { + lb++; t = al; + } + else { + rb++; t = ar; + } + w[k++] = t; + } + if (rb < rf) + System.arraycopy(a, rb, w, k, rf - rb); + else if (lb < lf) + System.arraycopy(a, lb, w, k, lf - lb); + + tryComplete(); + } + } + } +} --- old/src/java.base/share/classes/java/util/DualPivotQuicksort.java 2019-07-17 17:04:37.096314307 +0200 +++ new/src/java.base/share/classes/java/util/DualPivotQuicksort.java 2019-07-17 17:04:36.780314312 +0200 @@ -1,16 +1,16 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this + * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * @@ -25,24 +25,28 @@ package java.util; +import java.util.concurrent.CountedCompleter; +import java.util.concurrent.RecursiveTask; + /** - * This class implements the Dual-Pivot Quicksort algorithm by - * Vladimir Yaroslavskiy, Jon Bentley, and Josh Bloch. The algorithm - * offers O(n log(n)) performance on many data sets that cause other - * quicksorts to degrade to quadratic performance, and is typically + * This class implements powerful and fully optimized versions, both + * sequential and parallel, of the Dual-Pivot Quicksort algorithm by + * Vladimir Yaroslavskiy, Jon Bentley and Josh Bloch. This algorithm + * offers O(n log(n)) performance on all data sets, and is typically * faster than traditional (one-pivot) Quicksort implementations. * - * All exposed methods are package-private, designed to be invoked - * from public methods (in class Arrays) after performing any - * necessary array bounds checks and expanding parameters into the - * required forms. + * There are also additional algorithms, invoked from the Dual-Pivot + * Quicksort, such as mixed insertion sort, merging of runs and heap + * sort, counting sort and parallel merge sort. * * @author Vladimir Yaroslavskiy * @author Jon Bentley * @author Josh Bloch + * @author Doug Lea + * + * @version 2018.08.18 * - * @version 2011.02.11 m765.827.12i:5\7pm - * @since 1.7 + * @since 14 */ final class DualPivotQuicksort { @@ -51,3131 +55,4319 @@ */ private DualPivotQuicksort() {} - /* - * Tuning parameters. + /** + * Max array size to use mixed insertion sort. */ + private static final int MAX_MIXED_INSERTION_SORT_SIZE = 114; /** - * The maximum number of runs in merge sort. + * Max array size to use insertion sort. */ - private static final int MAX_RUN_COUNT = 67; + private static final int MAX_INSERTION_SORT_SIZE = 41; /** - * If the length of an array to be sorted is less than this - * constant, Quicksort is used in preference to merge sort. + * Min array size to perform sorting in parallel. */ - private static final int QUICKSORT_THRESHOLD = 286; + private static final int MIN_PARALLEL_SORT_SIZE = 4 << 10; /** - * If the length of an array to be sorted is less than this - * constant, insertion sort is used in preference to Quicksort. + * Min array size to try merging of runs. */ - private static final int INSERTION_SORT_THRESHOLD = 47; + private static final int MIN_TRY_MERGE_SIZE = 4 << 10; /** - * If the length of a byte array to be sorted is greater than this - * constant, counting sort is used in preference to insertion sort. + * Min size of the first run to continue with scanning. */ - private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 29; + private static final int MIN_FIRST_RUN_SIZE = 16; /** - * If the length of a short or char array to be sorted is greater - * than this constant, counting sort is used in preference to Quicksort. + * Min factor for the first runs to continue scanning. */ - private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 3200; + private static final int MIN_FIRST_RUNS_FACTOR = 7; - /* - * Sorting methods for seven primitive types. + /** + * Max capacity of the index array for tracking runs. */ + private static final int MAX_RUN_CAPACITY = 5 << 10; /** - * Sorts the specified range of the array using the given - * workspace array slice if possible for merging - * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param work a workspace array (slice) - * @param workBase origin of usable space in work array - * @param workLen usable size of work array + * Min number of runs, required by parallel merging. */ - static void sort(int[] a, int left, int right, - int[] work, int workBase, int workLen) { - // Use Quicksort on small arrays - if (right - left < QUICKSORT_THRESHOLD) { - sort(a, left, right, true); - return; - } + private static final int MIN_RUN_COUNT = 4; - /* - * Index run[i] is the start of i-th run - * (ascending or descending sequence). - */ - int[] run = new int[MAX_RUN_COUNT + 1]; - int count = 0; run[0] = left; + /** + * Min array size to use parallel merging of parts. + */ + private static final int MIN_PARALLEL_MERGE_PARTS_SIZE = 4 << 10; - // Check if the array is nearly sorted - for (int k = left; k < right; run[count] = k) { - // Equal items in the beginning of the sequence - while (k < right && a[k] == a[k + 1]) - k++; - if (k == right) break; // Sequence finishes with equal items - if (a[k] < a[k + 1]) { // ascending - while (++k <= right && a[k - 1] <= a[k]); - } else if (a[k] > a[k + 1]) { // descending - while (++k <= right && a[k - 1] >= a[k]); - // Transform into an ascending sequence - for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) { - int t = a[lo]; a[lo] = a[hi]; a[hi] = t; - } - } + /** + * Min size of a byte array to use counting sort. + */ + private static final int MIN_BYTE_COUNTING_SORT_SIZE = 64; - // Merge a transformed descending sequence followed by an - // ascending sequence - if (run[count] > left && a[run[count]] >= a[run[count] - 1]) { - count--; - } + /** + * Min size of a short or char array to use counting sort. + */ + private static final int MIN_SHORT_OR_CHAR_COUNTING_SORT_SIZE = 1750; - /* - * The array is not highly structured, - * use Quicksort instead of merge sort. - */ - if (++count == MAX_RUN_COUNT) { - sort(a, left, right, true); - return; - } - } + /** + * Max double recursive partitioning depth before using heap sort. + */ + private static final int MAX_RECURSION_DEPTH = 64 << 1; - // These invariants should hold true: - // run[0] = 0 - // run[] = right + 1; (terminator) + /** + * Calculates the double depth of parallel merging. + * Depth is negative, if tasks split before sorting. + * + * @param parallelism the parallelism level + * @param size the target size + * @return the depth of parallel merging + */ + private static int getDepth(int parallelism, int size) { + int depth = 0; - if (count == 0) { - // A single equal run - return; - } else if (count == 1 && run[count] > right) { - // Either a single ascending or a transformed descending run. - // Always check that a final run is a proper terminator, otherwise - // we have an unterminated trailing run, to handle downstream. - return; - } - right++; - if (run[count] < right) { - // Corner case: the final run is not a terminator. This may happen - // if a final run is an equals run, or there is a single-element run - // at the end. Fix up by adding a proper terminator at the end. - // Note that we terminate with (right + 1), incremented earlier. - run[++count] = right; - } - - // Determine alternation base for merge - byte odd = 0; - for (int n = 1; (n <<= 1) < count; odd ^= 1); - - // Use or create temporary array b for merging - int[] b; // temp array; alternates with a - int ao, bo; // array offsets from 'left' - int blen = right - left; // space needed for b - if (work == null || workLen < blen || workBase + blen > work.length) { - work = new int[blen]; - workBase = 0; - } - if (odd == 0) { - System.arraycopy(a, left, work, workBase, blen); - b = a; - bo = 0; - a = work; - ao = workBase - left; - } else { - b = work; - ao = 0; - bo = workBase - left; - } - - // Merging - for (int last; count > 1; count = last) { - for (int k = (last = 0) + 2; k <= count; k += 2) { - int hi = run[k], mi = run[k - 1]; - for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { - b[i + bo] = a[p++ + ao]; - } else { - b[i + bo] = a[q++ + ao]; - } - } - run[++last] = hi; - } - if ((count & 1) != 0) { - for (int i = right, lo = run[count - 1]; --i >= lo; - b[i + bo] = a[i + ao] - ); - run[++last] = right; - } - int[] t = a; a = b; b = t; - int o = ao; ao = bo; bo = o; + while ((parallelism >>= 3) > 0 && (size >>= 2) > 0) { + depth -= 2; } + return depth; } /** - * Sorts the specified range of the array by Dual-Pivot Quicksort. + * Sorts the specified range of the array using parallel merge + * sort and/or Dual-Pivot Quicksort. + * + * To balance the faster splitting and parallelism of merge sort + * with the faster element partitioning of Quicksort, ranges are + * subdivided in tiers such that, if there is enough parallelism, + * the four-way parallel merge is started, still ensuring enough + * parallelism to process the partitions. * * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param leftmost indicates if this part is the leftmost in the range + * @param parallelism the parallelism level + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted */ - private static void sort(int[] a, int left, int right, boolean leftmost) { - int length = right - left + 1; + static void sort(int[] a, int parallelism, int low, int high) { + int size = high - low; - // Use insertion sort on tiny arrays - if (length < INSERTION_SORT_THRESHOLD) { - if (leftmost) { - /* - * Traditional (without sentinel) insertion sort, - * optimized for server VM, is used in case of - * the leftmost part. - */ - for (int i = left, j = i; i < right; j = ++i) { - int ai = a[i + 1]; - while (ai < a[j]) { - a[j + 1] = a[j]; - if (j-- == left) { - break; - } - } - a[j + 1] = ai; - } - } else { - /* - * Skip the longest ascending sequence. - */ - do { - if (left >= right) { - return; - } - } while (a[++left] >= a[left - 1]); - - /* - * Every element from adjoining part plays the role - * of sentinel, therefore this allows us to avoid the - * left range check on each iteration. Moreover, we use - * the more optimized algorithm, so called pair insertion - * sort, which is faster (in the context of Quicksort) - * than traditional implementation of insertion sort. - */ - for (int k = left; ++left <= right; k = ++left) { - int a1 = a[k], a2 = a[left]; - - if (a1 < a2) { - a2 = a1; a1 = a[left]; - } - while (a1 < a[--k]) { - a[k + 2] = a[k]; - } - a[++k + 1] = a1; - - while (a2 < a[--k]) { - a[k + 1] = a[k]; - } - a[k + 1] = a2; - } - int last = a[right]; - - while (last < a[--right]) { - a[right + 1] = a[right]; - } - a[right + 1] = last; - } - return; + if (parallelism > 0 && size > MIN_PARALLEL_SORT_SIZE) { + int depth = getDepth(parallelism, size >> 12); + int[] b = depth == 0 ? null : new int[size]; + new Sorter(null, a, b, low, size, low, depth).invoke(); + } else { + sort(null, a, 0, low, high); } + } - // Inexpensive approximation of length / 7 - int seventh = (length >> 3) + (length >> 6) + 1; - - /* - * Sort five evenly spaced elements around (and including) the - * center element in the range. These elements will be used for - * pivot selection as described below. The choice for spacing - * these elements was empirically determined to work well on - * a wide variety of inputs. - */ - int e3 = (left + right) >>> 1; // The midpoint - int e2 = e3 - seventh; - int e1 = e2 - seventh; - int e4 = e3 + seventh; - int e5 = e4 + seventh; - - // Sort these elements using insertion sort - if (a[e2] < a[e1]) { int t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + /** + * Sorts the specified array using the Dual-Pivot Quicksort and/or + * other sorts in special-cases, possibly with parallel partitions. + * + * @param sorter parallel context + * @param a the array to be sorted + * @param bits the combination of recursion depth and bit flag, where + * the right bit "0" indicates that array is the leftmost part + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(Sorter sorter, int[] a, int bits, int low, int high) { + while (true) { + int end = high - 1, size = high - low; - if (a[e3] < a[e2]) { int t = a[e3]; a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } - } - if (a[e4] < a[e3]) { int t = a[e4]; a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + /* + * Run mixed insertion sort on small non-leftmost parts. + */ + if (size < MAX_MIXED_INSERTION_SORT_SIZE && (bits & 1) > 0) { + mixedInsertionSort(a, low, high - 3 * ((size >> 5) << 3), high); + return; } - } - if (a[e5] < a[e4]) { int t = a[e5]; a[e5] = a[e4]; a[e4] = t; - if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } - } + + /* + * Invoke insertion sort on small leftmost part. + */ + if (size < MAX_INSERTION_SORT_SIZE) { + insertionSort(a, low, high); + return; } - } - // Pointers - int less = left; // The index of the first element of center part - int great = right; // The index before the first element of right part + /* + * Check if the whole array or large non-leftmost + * parts are nearly sorted and then merge runs. + */ + if ((bits == 0 || size > MIN_TRY_MERGE_SIZE && (bits & 1) > 0) + && tryMergeRuns(sorter, a, low, size)) { + return; + } - if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) { /* - * Use the second and fourth of the five sorted elements as pivots. - * These values are inexpensive approximations of the first and - * second terciles of the array. Note that pivot1 <= pivot2. + * Switch to heap sort if execution + * time is becoming quadratic. */ - int pivot1 = a[e2]; - int pivot2 = a[e4]; + if ((bits += 2) > MAX_RECURSION_DEPTH) { + heapSort(a, low, high); + return; + } /* - * The first and the last elements to be sorted are moved to the - * locations formerly occupied by the pivots. When partitioning - * is complete, the pivots are swapped back into their final - * positions, and excluded from subsequent sorting. + * Use an inexpensive approximation of the golden ratio + * to select five sample elements and determine pivots. */ - a[e2] = a[left]; - a[e4] = a[right]; + int step = (size >> 3) * 3 + 3; /* - * Skip elements, which are less or greater than pivot values. + * Five elements around (and including) the central element + * will be used for pivot selection as described below. The + * unequal choice of spacing these elements was empirically + * determined to work well on a wide variety of inputs. */ - while (a[++less] < pivot1); - while (a[--great] > pivot2); + int e1 = low + step; + int e5 = end - step; + int e3 = (e1 + e5) >>> 1; + int e2 = (e1 + e3) >>> 1; + int e4 = (e3 + e5) >>> 1; + int a3 = a[e3]; /* - * Partitioning: + * Sort these elements in place by the combination + * of 4-element sorting network and insertion sort. * - * left part center part right part - * +--------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +--------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (left, less) < pivot1 - * pivot1 <= all in [less, k) <= pivot2 - * all in (great, right) > pivot2 - * - * Pointer k is the first index of ?-part. + * 5 ------o-----------o----------- + * | | + * 4 ------|-----o-----o-----o----- + * | | | + * 2 ------o-----|-----o-----o----- + * | | + * 1 ------------o-----o----------- */ - outer: - for (int k = less - 1; ++k <= great; ) { - int ak = a[k]; - if (ak < pivot1) { // Move a[k] to left part - a[k] = a[less]; - /* - * Here and below we use "a[i] = b; i++;" instead - * of "a[i++] = b;" due to performance issue. - */ - a[less] = ak; - ++less; - } else if (ak > pivot2) { // Move a[k] to right part - while (a[great] > pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] < pivot1) { // a[great] <= pivot2 - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // pivot1 <= a[great] <= pivot2 - a[k] = a[great]; - } - /* - * Here and below we use "a[i] = b; i--;" instead - * of "a[i--] = b;" due to performance issue. - */ - a[great] = ak; - --great; + if (a[e5] < a[e2]) { int t = a[e5]; a[e5] = a[e2]; a[e2] = t; } + if (a[e4] < a[e1]) { int t = a[e4]; a[e4] = a[e1]; a[e1] = t; } + if (a[e5] < a[e4]) { int t = a[e5]; a[e5] = a[e4]; a[e4] = t; } + if (a[e2] < a[e1]) { int t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + if (a[e4] < a[e2]) { int t = a[e4]; a[e4] = a[e2]; a[e2] = t; } + + if (a3 < a[e2]) { + if (a3 < a[e1]) { + a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3; + } else { + a[e3] = a[e2]; a[e2] = a3; + } + } else if (a3 > a[e4]) { + if (a3 > a[e5]) { + a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3; + } else { + a[e3] = a[e4]; a[e4] = a3; } } - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivots - sort(a, left, less - 2, leftmost); - sort(a, great + 2, right, false); + // Pointers + int lower = low; // The index of the last element of the left part + int upper = end; // The index of the first element of the right part /* - * If center part is too large (comprises > 4/7 of the array), - * swap internal pivot values to ends. + * Partitioning with 2 pivots in case of different elements. */ - if (less < e1 && e5 < great) { + if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) { + /* - * Skip elements, which are equal to pivot values. + * Use the first and fifth of the five sorted elements as + * the pivots. These values are inexpensive approximation + * of tertiles. Note, that pivot1 < pivot2. */ - while (a[less] == pivot1) { - ++less; + int pivot1 = a[e1]; + int pivot2 = a[e5]; + + /* + * The first and the last elements to be sorted are moved + * to the locations formerly occupied by the pivots. When + * partitioning is completed, the pivots are swapped back + * into their final positions, and excluded from the next + * subsequent sorting. + */ + a[e1] = a[lower]; + a[e5] = a[upper]; + + /* + * Skip elements, which are less or greater than the pivots. + */ + while (a[++lower] < pivot1); + while (a[--upper] > pivot2); + + /* + * Backward 3-interval partitioning + * + * left part central part right part + * +------------------------------------------------------------+ + * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 | + * +------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper + * + * Invariants: + * + * all in (low, lower] < pivot1 + * pivot1 <= all in (k, upper) <= pivot2 + * all in [upper, end) > pivot2 + * + * Pointer k is the last index of ?-part + */ + for (int unused = --lower, k = ++upper; --k > lower; ) { + int ak = a[k]; + + if (ak < pivot1) { // Move a[k] to the left side + while (lower < k) { + if (a[++lower] >= pivot1) { + if (a[lower] > pivot2) { + a[k] = a[--upper]; + a[upper] = a[lower]; + } else { + a[k] = a[lower]; + } + a[lower] = ak; + break; + } + } + } else if (ak > pivot2) { // Move a[k] to the right side + a[k] = a[--upper]; + a[upper] = ak; + } } - while (a[great] == pivot2) { - --great; + /* + * Swap the pivots into their final positions. + */ + a[low] = a[lower]; a[lower] = pivot1; + a[end] = a[upper]; a[upper] = pivot2; + + /* + * Sort non-left parts recursively (possibly in parallel), + * excluding known pivots. + */ + if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) { + sorter.forkSorter(bits | 1, lower + 1, upper); + sorter.forkSorter(bits | 1, upper + 1, high); + } else { + sort(sorter, a, bits | 1, lower + 1, upper); + sort(sorter, a, bits | 1, upper + 1, high); } + } else { // Use single pivot in case of many equal elements + /* - * Partitioning: + * Use the third of the five sorted elements as the pivot. + * This value is inexpensive approximation of the median. + */ + int pivot = a[e3]; + + /* + * The first element to be sorted is moved to the + * location formerly occupied by the pivot. After + * completion of partitioning the pivot is swapped + * back into its final position, and excluded from + * the next subsequent sorting. + */ + a[e3] = a[lower]; + + /* + * Traditional 3-way (Dutch National Flag) partitioning * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part central part right part + * +------------------------------------------------------+ + * | < pivot | ? | == pivot | > pivot | + * +------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper * * Invariants: * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 + * all in (low, lower] < pivot + * all in (k, upper) == pivot + * all in [upper, end] > pivot * - * Pointer k is the first index of ?-part. + * Pointer k is the last index of ?-part */ - outer: - for (int k = less - 1; ++k <= great; ) { + for (int k = ++upper; --k > lower; ) { int ak = a[k]; - if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; + + if (ak != pivot) { + a[k] = pivot; + + if (ak < pivot) { // Move a[k] to the left side + while (a[++lower] < pivot); + + if (a[lower] > pivot) { + a[--upper] = a[lower]; } + a[lower] = ak; + } else { // ak > pivot - Move a[k] to the right side + a[--upper] = ak; } - if (a[great] == pivot1) { // a[great] < pivot2 - a[k] = a[less]; - /* - * Even though a[great] equals to pivot1, the - * assignment a[less] = pivot1 may be incorrect, - * if a[great] and pivot1 are floating-point zeros - * of different signs. Therefore in float and - * double sorting methods we have to use more - * accurate assignment a[less] = a[great]. - */ - a[less] = pivot1; - ++less; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great] = ak; - --great; } } + + /* + * Swap the pivot into its final position. + */ + a[low] = a[lower]; a[lower] = pivot; + + /* + * Sort the right part (possibly in parallel), excluding + * known pivot. All elements from the central part are + * equal and therefore already sorted. + */ + if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) { + sorter.forkSorter(bits | 1, upper, high); + } else { + sort(sorter, a, bits | 1, upper, high); + } } + high = lower; // Iterate along the left part + } + } - // Sort center part recursively - sort(a, less, great, false); + /** + * Sorts the specified range of the array using mixed insertion sort. + * + * Mixed insertion sort is combination of simple insertion sort, + * pin insertion sort and pair insertion sort. + * + * In the context of Dual-Pivot Quicksort, the pivot element + * from the left part plays the role of sentinel, because it + * is less than any elements from the given part. Therefore, + * expensive check of the left range can be skipped on each + * iteration unless it is the leftmost call. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param end the index of the last element for simple insertion sort + * @param high the index of the last element, exclusive, to be sorted + */ + private static void mixedInsertionSort(int[] a, int low, int end, int high) { + if (end == high) { - } else { // Partitioning with one pivot /* - * Use the third of the five sorted elements as pivot. - * This value is inexpensive approximation of the median. + * Invoke simple insertion sort on tiny array. */ - int pivot = a[e3]; + for (int i; ++low < end; ) { + int ai = a[i = low]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + } + } else { /* - * Partitioning degenerates to the traditional 3-way - * (or "Dutch National Flag") schema: - * - * left part center part right part - * +-------------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +-------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: + * Start with pin insertion sort on small part. * - * all in (left, less) < pivot - * all in [less, k) == pivot - * all in (great, right) > pivot - * - * Pointer k is the first index of ?-part. + * Pin insertion sort is extended simple insertion sort. + * The main idea of this sort is to put elements larger + * than an element called pin to the end of array (the + * proper area for such elements). It avoids expensive + * movements of these elements through the whole array. */ - for (int k = less; k <= great; ++k) { - if (a[k] == pivot) { - continue; - } - int ak = a[k]; - if (ak < pivot) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else { // a[k] > pivot - Move a[k] to right part - while (a[great] > pivot) { - --great; - } - if (a[great] < pivot) { // a[great] <= pivot - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // a[great] == pivot - /* - * Even though a[great] equals to pivot, the - * assignment a[k] = pivot may be incorrect, - * if a[great] and pivot are floating-point - * zeros of different signs. Therefore in float - * and double sorting methods we have to use - * more accurate assignment a[k] = a[great]. - */ - a[k] = pivot; + int pin = a[end]; + + for (int i, p = high; ++low < end; ) { + int ai = a[i = low]; + + if (ai < a[i - 1]) { // Small element + + /* + * Insert small element into sorted part. + */ + a[i] = a[--i]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + + } else if (p > i && ai > pin) { // Large element + + /* + * Find element smaller than pin. + */ + while (a[--p] > pin); + + /* + * Swap it with large element. + */ + if (p > i) { + ai = a[p]; + a[p] = a[i]; } - a[great] = ak; - --great; + + /* + * Insert small element into sorted part. + */ + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; } } /* - * Sort left and right parts recursively. - * All elements from center part are equal - * and, therefore, already sorted. + * Continue with pair insertion sort on remain part. */ - sort(a, left, less - 1, leftmost); - sort(a, great + 1, right, false); + for (int i; low < high; ++low) { + int a1 = a[i = low], a2 = a[++low]; + + /* + * Insert two elements per iteration: at first, insert the + * larger element and then insert the smaller element, but + * from the position where the larger element was inserted. + */ + if (a1 > a2) { + + while (a1 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a1; + + while (a2 < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = a2; + + } else if (a1 < a[i - 1]) { + + while (a2 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a2; + + while (a1 < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = a1; + } + } } } /** - * Sorts the specified range of the array using the given - * workspace array slice if possible for merging + * Sorts the specified range of the array using insertion sort. * * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param work a workspace array (slice) - * @param workBase origin of usable space in work array - * @param workLen usable size of work array + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted */ - static void sort(long[] a, int left, int right, - long[] work, int workBase, int workLen) { - // Use Quicksort on small arrays - if (right - left < QUICKSORT_THRESHOLD) { - sort(a, left, right, true); - return; + private static void insertionSort(int[] a, int low, int high) { + for (int i, k = low; ++k < high; ) { + int ai = a[i = k]; + + if (ai < a[i - 1]) { + while (--i >= low && ai < a[i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + } } + } + + /** + * Sorts the specified range of the array using heap sort. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void heapSort(int[] a, int low, int high) { + for (int k = (low + high) >>> 1; k > low; ) { + pushDown(a, --k, a[k], low, high); + } + while (--high > low) { + int max = a[low]; + pushDown(a, low, a[high], low, high); + a[high] = max; + } + } + + /** + * Pushes specified element down during heap sort. + * + * @param a the given array + * @param p the start index + * @param value the given element + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void pushDown(int[] a, int p, int value, int low, int high) { + for (int k ;; a[p] = a[p = k]) { + k = (p << 1) - low + 2; // Index of the right child + + if (k > high) { + break; + } + if (k == high || a[k] < a[k - 1]) { + --k; + } + if (a[k] <= value) { + break; + } + } + a[p] = value; + } + + /** + * Tries to sort the specified range of the array. + * + * @param sorter parallel context + * @param a the array to be sorted + * @param low the index of the first element to be sorted + * @param size the array size + * @return true if finally sorted, false otherwise + */ + private static boolean tryMergeRuns(Sorter sorter, int[] a, int low, int size) { + + /* + * The run array is constructed only if initial runs are + * long enough to continue, run[i] then holds start index + * of the i-th sequence of elements in non-descending order. + */ + int[] run = null; + int high = low + size; + int count = 1, last = low; /* - * Index run[i] is the start of i-th run - * (ascending or descending sequence). + * Identify all possible runs. */ - int[] run = new int[MAX_RUN_COUNT + 1]; - int count = 0; run[0] = left; + for (int k = low + 1; k < high; ) { - // Check if the array is nearly sorted - for (int k = left; k < right; run[count] = k) { - // Equal items in the beginning of the sequence - while (k < right && a[k] == a[k + 1]) - k++; - if (k == right) break; // Sequence finishes with equal items - if (a[k] < a[k + 1]) { // ascending - while (++k <= right && a[k - 1] <= a[k]); - } else if (a[k] > a[k + 1]) { // descending - while (++k <= right && a[k - 1] >= a[k]); - // Transform into an ascending sequence - for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) { - long t = a[lo]; a[lo] = a[hi]; a[hi] = t; + /* + * Find the end index of the current run. + */ + if (a[k - 1] < a[k]) { + + // Identify ascending sequence + while (++k < high && a[k - 1] <= a[k]); + + } else if (a[k - 1] > a[k]) { + + // Identify descending sequence + while (++k < high && a[k - 1] >= a[k]); + + // Reverse into ascending order + for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) { + int ai = a[i]; a[i] = a[j]; a[j] = ai; } - } + } else { // Identify constant sequence + for (int ak = a[k]; ++k < high && ak == a[k]; ); - // Merge a transformed descending sequence followed by an - // ascending sequence - if (run[count] > left && a[run[count]] >= a[run[count] - 1]) { - count--; + if (k < high) { + continue; + } } /* - * The array is not highly structured, - * use Quicksort instead of merge sort. + * Check special cases. */ - if (++count == MAX_RUN_COUNT) { - sort(a, left, right, true); - return; + if (run == null) { + if (k == high) { + + /* + * The array is monotonous sequence, + * and therefore already sorted. + */ + return true; + } + + if (k - low < MIN_FIRST_RUN_SIZE) { + + /* + * The first run is too small + * to proceed with scanning. + */ + return false; + } + + run = new int[((size >> 10) | 0x7F) & 0x3FF]; + run[0] = low; + + } else if (a[last - 1] > a[last]) { + + if (count > (k - low) >> MIN_FIRST_RUNS_FACTOR) { + + /* + * The first runs are not long + * enough to continue scanning. + */ + return false; + } + + if (++count == MAX_RUN_CAPACITY) { + + /* + * Array is not highly structured. + */ + return false; + } + + if (count == run.length) { + + /* + * Increase capacity of index array. + */ + run = Arrays.copyOf(run, count << 1); + } } + run[count] = (last = k); } - // These invariants should hold true: - // run[0] = 0 - // run[] = right + 1; (terminator) + /* + * Merge runs of highly structured array. + */ + if (count > 1) { + int[] b; int offset = low; - if (count == 0) { - // A single equal run - return; - } else if (count == 1 && run[count] > right) { - // Either a single ascending or a transformed descending run. - // Always check that a final run is a proper terminator, otherwise - // we have an unterminated trailing run, to handle downstream. - return; - } - right++; - if (run[count] < right) { - // Corner case: the final run is not a terminator. This may happen - // if a final run is an equals run, or there is a single-element run - // at the end. Fix up by adding a proper terminator at the end. - // Note that we terminate with (right + 1), incremented earlier. - run[++count] = right; - } - - // Determine alternation base for merge - byte odd = 0; - for (int n = 1; (n <<= 1) < count; odd ^= 1); - - // Use or create temporary array b for merging - long[] b; // temp array; alternates with a - int ao, bo; // array offsets from 'left' - int blen = right - left; // space needed for b - if (work == null || workLen < blen || workBase + blen > work.length) { - work = new long[blen]; - workBase = 0; - } - if (odd == 0) { - System.arraycopy(a, left, work, workBase, blen); - b = a; - bo = 0; - a = work; - ao = workBase - left; - } else { - b = work; - ao = 0; - bo = workBase - left; - } - - // Merging - for (int last; count > 1; count = last) { - for (int k = (last = 0) + 2; k <= count; k += 2) { - int hi = run[k], mi = run[k - 1]; - for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { - b[i + bo] = a[p++ + ao]; - } else { - b[i + bo] = a[q++ + ao]; - } - } - run[++last] = hi; + if (sorter == null || (b = (int[]) sorter.b) == null) { + b = new int[size]; + } else { + offset = sorter.offset; } - if ((count & 1) != 0) { - for (int i = right, lo = run[count - 1]; --i >= lo; - b[i + bo] = a[i + ao] - ); - run[++last] = right; + mergeRuns(a, b, offset, 1, sorter != null, run, 0, count); + } + return true; + } + + /** + * Merges the specified runs. + * + * @param a the source array + * @param b the temporary buffer used in merging + * @param offset the start index in the source, inclusive + * @param aim specifies merging: to source ( > 0), buffer ( < 0) or any ( == 0) + * @param parallel indicates whether merging is performed in parallel + * @param run the start indexes of the runs, inclusive + * @param lo the start index of the first run, inclusive + * @param hi the start index of the last run, inclusive + * @return the destination where runs are merged + */ + private static int[] mergeRuns(int[] a, int[] b, int offset, + int aim, boolean parallel, int[] run, int lo, int hi) { + + if (hi - lo == 1) { + if (aim >= 0) { + return a; } - long[] t = a; a = b; b = t; - int o = ao; ao = bo; bo = o; + for (int i = run[hi], j = i - offset, low = run[lo]; i > low; + b[--j] = a[--i] + ); + return b; + } + + /* + * Split into approximately equal parts. + */ + int mi = lo, rmi = (run[lo] + run[hi]) >>> 1; + while (run[++mi + 1] <= rmi); + + /* + * Merge the left and right parts. + */ + int[] a1, a2; + + if (parallel && hi - lo > MIN_RUN_COUNT) { + RunMerger merger = new RunMerger(a, b, offset, 0, run, mi, hi).forkMe(); + a1 = mergeRuns(a, b, offset, -aim, true, run, lo, mi); + a2 = (int[]) merger.getDestination(); + } else { + a1 = mergeRuns(a, b, offset, -aim, false, run, lo, mi); + a2 = mergeRuns(a, b, offset, 0, false, run, mi, hi); } + + int[] dst = a1 == a ? b : a; + + int k = a1 == a ? run[lo] - offset : run[lo]; + int lo1 = a1 == b ? run[lo] - offset : run[lo]; + int hi1 = a1 == b ? run[mi] - offset : run[mi]; + int lo2 = a2 == b ? run[mi] - offset : run[mi]; + int hi2 = a2 == b ? run[hi] - offset : run[hi]; + + if (parallel) { + new Merger(null, dst, k, a1, lo1, hi1, a2, lo2, hi2).invoke(); + } else { + mergeParts(null, dst, k, a1, lo1, hi1, a2, lo2, hi2); + } + return dst; } /** - * Sorts the specified range of the array by Dual-Pivot Quicksort. + * Merges the sorted parts. * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param leftmost indicates if this part is the leftmost in the range + * @param merger parallel context + * @param dst the destination where parts are merged + * @param k the start index of the destination, inclusive + * @param a1 the first part + * @param lo1 the start index of the first part, inclusive + * @param hi1 the end index of the first part, exclusive + * @param a2 the second part + * @param lo2 the start index of the second part, inclusive + * @param hi2 the end index of the second part, exclusive */ - private static void sort(long[] a, int left, int right, boolean leftmost) { - int length = right - left + 1; + private static void mergeParts(Merger merger, int[] dst, int k, + int[] a1, int lo1, int hi1, int[] a2, int lo2, int hi2) { + + if (merger != null && a1 == a2) { + + while (true) { - // Use insertion sort on tiny arrays - if (length < INSERTION_SORT_THRESHOLD) { - if (leftmost) { /* - * Traditional (without sentinel) insertion sort, - * optimized for server VM, is used in case of - * the leftmost part. + * The first part must be larger. */ - for (int i = left, j = i; i < right; j = ++i) { - long ai = a[i + 1]; - while (ai < a[j]) { - a[j + 1] = a[j]; - if (j-- == left) { - break; - } - } - a[j + 1] = ai; + if (hi1 - lo1 < hi2 - lo2) { + int lo = lo1; lo1 = lo2; lo2 = lo; + int hi = hi1; hi1 = hi2; hi2 = hi; } - } else { + /* - * Skip the longest ascending sequence. + * Small parts will be merged sequentially. */ - do { - if (left >= right) { - return; - } - } while (a[++left] >= a[left - 1]); + if (hi1 - lo1 < MIN_PARALLEL_MERGE_PARTS_SIZE) { + break; + } /* - * Every element from adjoining part plays the role - * of sentinel, therefore this allows us to avoid the - * left range check on each iteration. Moreover, we use - * the more optimized algorithm, so called pair insertion - * sort, which is faster (in the context of Quicksort) - * than traditional implementation of insertion sort. + * Find the median of the larger part. */ - for (int k = left; ++left <= right; k = ++left) { - long a1 = a[k], a2 = a[left]; + int mi1 = (lo1 + hi1) >>> 1; + int key = a1[mi1]; + int mi2 = hi2; - if (a1 < a2) { - a2 = a1; a1 = a[left]; - } - while (a1 < a[--k]) { - a[k + 2] = a[k]; - } - a[++k + 1] = a1; + /* + * Partition the smaller part. + */ + for (int loo = lo2; loo < mi2; ) { + int t = (loo + mi2) >>> 1; - while (a2 < a[--k]) { - a[k + 1] = a[k]; + if (key > a2[t]) { + loo = t + 1; + } else { + mi2 = t; } - a[k + 1] = a2; } - long last = a[right]; - while (last < a[--right]) { - a[right + 1] = a[right]; - } - a[right + 1] = last; + int d = mi2 - lo2 + mi1 - lo1; + + /* + * Merge the right sub-parts in parallel. + */ + merger.forkMerger(dst, k + d, a1, mi1, hi1, a2, mi2, hi2); + + /* + * Process the sub-left parts. + */ + hi1 = mi1; + hi2 = mi2; } - return; } - // Inexpensive approximation of length / 7 - int seventh = (length >> 3) + (length >> 6) + 1; - /* - * Sort five evenly spaced elements around (and including) the - * center element in the range. These elements will be used for - * pivot selection as described below. The choice for spacing - * these elements was empirically determined to work well on - * a wide variety of inputs. + * Merge small parts sequentially. */ - int e3 = (left + right) >>> 1; // The midpoint - int e2 = e3 - seventh; - int e1 = e2 - seventh; - int e4 = e3 + seventh; - int e5 = e4 + seventh; - - // Sort these elements using insertion sort - if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; } - - if (a[e3] < a[e2]) { long t = a[e3]; a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + while (lo1 < hi1 && lo2 < hi2) { + dst[k++] = a1[lo1] < a2[lo2] ? a1[lo1++] : a2[lo2++]; } - if (a[e4] < a[e3]) { long t = a[e4]; a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + if (dst != a1 || k < lo1) { + while (lo1 < hi1) { + dst[k++] = a1[lo1++]; } } - if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t; - if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } - } + if (dst != a2 || k < lo2) { + while (lo2 < hi2) { + dst[k++] = a2[lo2++]; } } + } - // Pointers - int less = left; // The index of the first element of center part - int great = right; // The index before the first element of right part +// [long] + + /** + * Sorts the specified range of the array using parallel merge + * sort and/or Dual-Pivot Quicksort. + * + * To balance the faster splitting and parallelism of merge sort + * with the faster element partitioning of Quicksort, ranges are + * subdivided in tiers such that, if there is enough parallelism, + * the four-way parallel merge is started, still ensuring enough + * parallelism to process the partitions. + * + * @param a the array to be sorted + * @param parallelism the parallelism level + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(long[] a, int parallelism, int low, int high) { + int size = high - low; + + if (parallelism > 0 && size > MIN_PARALLEL_SORT_SIZE) { + int depth = getDepth(parallelism, size >> 12); + long[] b = depth == 0 ? null : new long[size]; + new Sorter(null, a, b, low, size, low, depth).invoke(); + } else { + sort(null, a, 0, low, high); + } + } + + /** + * Sorts the specified array using the Dual-Pivot Quicksort and/or + * other sorts in special-cases, possibly with parallel partitions. + * + * @param sorter parallel context + * @param a the array to be sorted + * @param bits the combination of recursion depth and bit flag, where + * the right bit "0" indicates that array is the leftmost part + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(Sorter sorter, long[] a, int bits, int low, int high) { + while (true) { + int end = high - 1, size = high - low; + + /* + * Run mixed insertion sort on small non-leftmost parts. + */ + if (size < MAX_MIXED_INSERTION_SORT_SIZE && (bits & 1) > 0) { + mixedInsertionSort(a, low, high - 3 * ((size >> 5) << 3), high); + return; + } - if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) { /* - * Use the second and fourth of the five sorted elements as pivots. - * These values are inexpensive approximations of the first and - * second terciles of the array. Note that pivot1 <= pivot2. + * Invoke insertion sort on small leftmost part. */ - long pivot1 = a[e2]; - long pivot2 = a[e4]; + if (size < MAX_INSERTION_SORT_SIZE) { + insertionSort(a, low, high); + return; + } /* - * The first and the last elements to be sorted are moved to the - * locations formerly occupied by the pivots. When partitioning - * is complete, the pivots are swapped back into their final - * positions, and excluded from subsequent sorting. + * Check if the whole array or large non-leftmost + * parts are nearly sorted and then merge runs. */ - a[e2] = a[left]; - a[e4] = a[right]; + if ((bits == 0 || size > MIN_TRY_MERGE_SIZE && (bits & 1) > 0) + && tryMergeRuns(sorter, a, low, size)) { + return; + } /* - * Skip elements, which are less or greater than pivot values. + * Switch to heap sort if execution + * time is becoming quadratic. */ - while (a[++less] < pivot1); - while (a[--great] > pivot2); + if ((bits += 2) > MAX_RECURSION_DEPTH) { + heapSort(a, low, high); + return; + } /* - * Partitioning: - * - * left part center part right part - * +--------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +--------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (left, less) < pivot1 - * pivot1 <= all in [less, k) <= pivot2 - * all in (great, right) > pivot2 + * Use an inexpensive approximation of the golden ratio + * to select five sample elements and determine pivots. + */ + int step = (size >> 3) * 3 + 3; + + /* + * Five elements around (and including) the central element + * will be used for pivot selection as described below. The + * unequal choice of spacing these elements was empirically + * determined to work well on a wide variety of inputs. + */ + int e1 = low + step; + int e5 = end - step; + int e3 = (e1 + e5) >>> 1; + int e2 = (e1 + e3) >>> 1; + int e4 = (e3 + e5) >>> 1; + long a3 = a[e3]; + + /* + * Sort these elements in place by the combination + * of 4-element sorting network and insertion sort. * - * Pointer k is the first index of ?-part. + * 5 ------o-----------o----------- + * | | + * 4 ------|-----o-----o-----o----- + * | | | + * 2 ------o-----|-----o-----o----- + * | | + * 1 ------------o-----o----------- */ - outer: - for (int k = less - 1; ++k <= great; ) { - long ak = a[k]; - if (ak < pivot1) { // Move a[k] to left part - a[k] = a[less]; - /* - * Here and below we use "a[i] = b; i++;" instead - * of "a[i++] = b;" due to performance issue. - */ - a[less] = ak; - ++less; - } else if (ak > pivot2) { // Move a[k] to right part - while (a[great] > pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] < pivot1) { // a[great] <= pivot2 - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // pivot1 <= a[great] <= pivot2 - a[k] = a[great]; - } - /* - * Here and below we use "a[i] = b; i--;" instead - * of "a[i--] = b;" due to performance issue. - */ - a[great] = ak; - --great; + if (a[e5] < a[e2]) { long t = a[e5]; a[e5] = a[e2]; a[e2] = t; } + if (a[e4] < a[e1]) { long t = a[e4]; a[e4] = a[e1]; a[e1] = t; } + if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t; } + if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + if (a[e4] < a[e2]) { long t = a[e4]; a[e4] = a[e2]; a[e2] = t; } + + if (a3 < a[e2]) { + if (a3 < a[e1]) { + a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3; + } else { + a[e3] = a[e2]; a[e2] = a3; + } + } else if (a3 > a[e4]) { + if (a3 > a[e5]) { + a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3; + } else { + a[e3] = a[e4]; a[e4] = a3; } } - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivots - sort(a, left, less - 2, leftmost); - sort(a, great + 2, right, false); + // Pointers + int lower = low; // The index of the last element of the left part + int upper = end; // The index of the first element of the right part /* - * If center part is too large (comprises > 4/7 of the array), - * swap internal pivot values to ends. + * Partitioning with 2 pivots in case of different elements. */ - if (less < e1 && e5 < great) { + if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) { + + /* + * Use the first and fifth of the five sorted elements as + * the pivots. These values are inexpensive approximation + * of tertiles. Note, that pivot1 < pivot2. + */ + long pivot1 = a[e1]; + long pivot2 = a[e5]; + + /* + * The first and the last elements to be sorted are moved + * to the locations formerly occupied by the pivots. When + * partitioning is completed, the pivots are swapped back + * into their final positions, and excluded from the next + * subsequent sorting. + */ + a[e1] = a[lower]; + a[e5] = a[upper]; + /* - * Skip elements, which are equal to pivot values. + * Skip elements, which are less or greater than the pivots. */ - while (a[less] == pivot1) { - ++less; + while (a[++lower] < pivot1); + while (a[--upper] > pivot2); + + /* + * Backward 3-interval partitioning + * + * left part central part right part + * +------------------------------------------------------------+ + * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 | + * +------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper + * + * Invariants: + * + * all in (low, lower] < pivot1 + * pivot1 <= all in (k, upper) <= pivot2 + * all in [upper, end) > pivot2 + * + * Pointer k is the last index of ?-part + */ + for (int unused = --lower, k = ++upper; --k > lower; ) { + long ak = a[k]; + + if (ak < pivot1) { // Move a[k] to the left side + while (lower < k) { + if (a[++lower] >= pivot1) { + if (a[lower] > pivot2) { + a[k] = a[--upper]; + a[upper] = a[lower]; + } else { + a[k] = a[lower]; + } + a[lower] = ak; + break; + } + } + } else if (ak > pivot2) { // Move a[k] to the right side + a[k] = a[--upper]; + a[upper] = ak; + } } - while (a[great] == pivot2) { - --great; + /* + * Swap the pivots into their final positions. + */ + a[low] = a[lower]; a[lower] = pivot1; + a[end] = a[upper]; a[upper] = pivot2; + + /* + * Sort non-left parts recursively (possibly in parallel), + * excluding known pivots. + */ + if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) { + sorter.forkSorter(bits | 1, lower + 1, upper); + sorter.forkSorter(bits | 1, upper + 1, high); + } else { + sort(sorter, a, bits | 1, lower + 1, upper); + sort(sorter, a, bits | 1, upper + 1, high); } + } else { // Use single pivot in case of many equal elements + + /* + * Use the third of the five sorted elements as the pivot. + * This value is inexpensive approximation of the median. + */ + long pivot = a[e3]; + /* - * Partitioning: + * The first element to be sorted is moved to the + * location formerly occupied by the pivot. After + * completion of partitioning the pivot is swapped + * back into its final position, and excluded from + * the next subsequent sorting. + */ + a[e3] = a[lower]; + + /* + * Traditional 3-way (Dutch National Flag) partitioning * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part central part right part + * +------------------------------------------------------+ + * | < pivot | ? | == pivot | > pivot | + * +------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper * * Invariants: * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 + * all in (low, lower] < pivot + * all in (k, upper) == pivot + * all in [upper, end] > pivot * - * Pointer k is the first index of ?-part. + * Pointer k is the last index of ?-part */ - outer: - for (int k = less - 1; ++k <= great; ) { + for (int k = ++upper; --k > lower; ) { long ak = a[k]; - if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; + + if (ak != pivot) { + a[k] = pivot; + + if (ak < pivot) { // Move a[k] to the left side + while (a[++lower] < pivot); + + if (a[lower] > pivot) { + a[--upper] = a[lower]; } + a[lower] = ak; + } else { // ak > pivot - Move a[k] to the right side + a[--upper] = ak; } - if (a[great] == pivot1) { // a[great] < pivot2 - a[k] = a[less]; - /* - * Even though a[great] equals to pivot1, the - * assignment a[less] = pivot1 may be incorrect, - * if a[great] and pivot1 are floating-point zeros - * of different signs. Therefore in float and - * double sorting methods we have to use more - * accurate assignment a[less] = a[great]. - */ - a[less] = pivot1; - ++less; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great] = ak; - --great; } } + + /* + * Swap the pivot into its final position. + */ + a[low] = a[lower]; a[lower] = pivot; + + /* + * Sort the right part (possibly in parallel), excluding + * known pivot. All elements from the central part are + * equal and therefore already sorted. + */ + if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) { + sorter.forkSorter(bits | 1, upper, high); + } else { + sort(sorter, a, bits | 1, upper, high); + } } + high = lower; // Iterate along the left part + } + } - // Sort center part recursively - sort(a, less, great, false); + /** + * Sorts the specified range of the array using mixed insertion sort. + * + * Mixed insertion sort is combination of simple insertion sort, + * pin insertion sort and pair insertion sort. + * + * In the context of Dual-Pivot Quicksort, the pivot element + * from the left part plays the role of sentinel, because it + * is less than any elements from the given part. Therefore, + * expensive check of the left range can be skipped on each + * iteration unless it is the leftmost call. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param end the index of the last element for simple insertion sort + * @param high the index of the last element, exclusive, to be sorted + */ + private static void mixedInsertionSort(long[] a, int low, int end, int high) { + if (end == high) { - } else { // Partitioning with one pivot /* - * Use the third of the five sorted elements as pivot. - * This value is inexpensive approximation of the median. + * Invoke simple insertion sort on tiny array. */ - long pivot = a[e3]; + for (int i; ++low < end; ) { + long ai = a[i = low]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + } + } else { /* - * Partitioning degenerates to the traditional 3-way - * (or "Dutch National Flag") schema: - * - * left part center part right part - * +-------------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +-------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * Start with pin insertion sort on small part. * - * Invariants: - * - * all in (left, less) < pivot - * all in [less, k) == pivot - * all in (great, right) > pivot - * - * Pointer k is the first index of ?-part. + * Pin insertion sort is extended simple insertion sort. + * The main idea of this sort is to put elements larger + * than an element called pin to the end of array (the + * proper area for such elements). It avoids expensive + * movements of these elements through the whole array. */ - for (int k = less; k <= great; ++k) { - if (a[k] == pivot) { - continue; - } - long ak = a[k]; - if (ak < pivot) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else { // a[k] > pivot - Move a[k] to right part - while (a[great] > pivot) { - --great; - } - if (a[great] < pivot) { // a[great] <= pivot - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // a[great] == pivot - /* - * Even though a[great] equals to pivot, the - * assignment a[k] = pivot may be incorrect, - * if a[great] and pivot are floating-point - * zeros of different signs. Therefore in float - * and double sorting methods we have to use - * more accurate assignment a[k] = a[great]. - */ - a[k] = pivot; + long pin = a[end]; + + for (int i, p = high; ++low < end; ) { + long ai = a[i = low]; + + if (ai < a[i - 1]) { // Small element + + /* + * Insert small element into sorted part. + */ + a[i] = a[--i]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; } - a[great] = ak; - --great; + a[i + 1] = ai; + + } else if (p > i && ai > pin) { // Large element + + /* + * Find element smaller than pin. + */ + while (a[--p] > pin); + + /* + * Swap it with large element. + */ + if (p > i) { + ai = a[p]; + a[p] = a[i]; + } + + /* + * Insert small element into sorted part. + */ + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; } } /* - * Sort left and right parts recursively. - * All elements from center part are equal - * and, therefore, already sorted. + * Continue with pair insertion sort on remain part. */ - sort(a, left, less - 1, leftmost); - sort(a, great + 1, right, false); + for (int i; low < high; ++low) { + long a1 = a[i = low], a2 = a[++low]; + + /* + * Insert two elements per iteration: at first, insert the + * larger element and then insert the smaller element, but + * from the position where the larger element was inserted. + */ + if (a1 > a2) { + + while (a1 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a1; + + while (a2 < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = a2; + + } else if (a1 < a[i - 1]) { + + while (a2 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a2; + + while (a1 < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = a1; + } + } } } /** - * Sorts the specified range of the array using the given - * workspace array slice if possible for merging + * Sorts the specified range of the array using insertion sort. * * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param work a workspace array (slice) - * @param workBase origin of usable space in work array - * @param workLen usable size of work array + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted */ - static void sort(short[] a, int left, int right, - short[] work, int workBase, int workLen) { - // Use counting sort on large arrays - if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { - int[] count = new int[NUM_SHORT_VALUES]; + private static void insertionSort(long[] a, int low, int high) { + for (int i, k = low; ++k < high; ) { + long ai = a[i = k]; + + if (ai < a[i - 1]) { + while (--i >= low && ai < a[i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + } + } + } - for (int i = left - 1; ++i <= right; - count[a[i] - Short.MIN_VALUE]++ - ); - for (int i = NUM_SHORT_VALUES, k = right + 1; k > left; ) { - while (count[--i] == 0); - short value = (short) (i + Short.MIN_VALUE); - int s = count[i]; + /** + * Sorts the specified range of the array using heap sort. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void heapSort(long[] a, int low, int high) { + for (int k = (low + high) >>> 1; k > low; ) { + pushDown(a, --k, a[k], low, high); + } + while (--high > low) { + long max = a[low]; + pushDown(a, low, a[high], low, high); + a[high] = max; + } + } + + /** + * Pushes specified element down during heap sort. + * + * @param a the given array + * @param p the start index + * @param value the given element + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void pushDown(long[] a, int p, long value, int low, int high) { + for (int k ;; a[p] = a[p = k]) { + k = (p << 1) - low + 2; // Index of the right child - do { - a[--k] = value; - } while (--s > 0); + if (k > high) { + break; + } + if (k == high || a[k] < a[k - 1]) { + --k; + } + if (a[k] <= value) { + break; } - } else { // Use Dual-Pivot Quicksort on small arrays - doSort(a, left, right, work, workBase, workLen); } + a[p] = value; } - /** The number of distinct short values. */ - private static final int NUM_SHORT_VALUES = 1 << 16; - /** - * Sorts the specified range of the array. + * Tries to sort the specified range of the array. * + * @param sorter parallel context * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param work a workspace array (slice) - * @param workBase origin of usable space in work array - * @param workLen usable size of work array - */ - private static void doSort(short[] a, int left, int right, - short[] work, int workBase, int workLen) { - // Use Quicksort on small arrays - if (right - left < QUICKSORT_THRESHOLD) { - sort(a, left, right, true); - return; - } + * @param low the index of the first element to be sorted + * @param size the array size + * @return true if finally sorted, false otherwise + */ + private static boolean tryMergeRuns(Sorter sorter, long[] a, int low, int size) { + + /* + * The run array is constructed only if initial runs are + * long enough to continue, run[i] then holds start index + * of the i-th sequence of elements in non-descending order. + */ + int[] run = null; + int high = low + size; + int count = 1, last = low; /* - * Index run[i] is the start of i-th run - * (ascending or descending sequence). + * Identify all possible runs. */ - int[] run = new int[MAX_RUN_COUNT + 1]; - int count = 0; run[0] = left; + for (int k = low + 1; k < high; ) { + + /* + * Find the end index of the current run. + */ + if (a[k - 1] < a[k]) { + + // Identify ascending sequence + while (++k < high && a[k - 1] <= a[k]); - // Check if the array is nearly sorted - for (int k = left; k < right; run[count] = k) { - // Equal items in the beginning of the sequence - while (k < right && a[k] == a[k + 1]) - k++; - if (k == right) break; // Sequence finishes with equal items - if (a[k] < a[k + 1]) { // ascending - while (++k <= right && a[k - 1] <= a[k]); - } else if (a[k] > a[k + 1]) { // descending - while (++k <= right && a[k - 1] >= a[k]); - // Transform into an ascending sequence - for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) { - short t = a[lo]; a[lo] = a[hi]; a[hi] = t; + } else if (a[k - 1] > a[k]) { + + // Identify descending sequence + while (++k < high && a[k - 1] >= a[k]); + + // Reverse into ascending order + for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) { + long ai = a[i]; a[i] = a[j]; a[j] = ai; } - } + } else { // Identify constant sequence + for (long ak = a[k]; ++k < high && ak == a[k]; ); - // Merge a transformed descending sequence followed by an - // ascending sequence - if (run[count] > left && a[run[count]] >= a[run[count] - 1]) { - count--; + if (k < high) { + continue; + } } /* - * The array is not highly structured, - * use Quicksort instead of merge sort. + * Check special cases. */ - if (++count == MAX_RUN_COUNT) { - sort(a, left, right, true); - return; + if (run == null) { + if (k == high) { + + /* + * The array is monotonous sequence, + * and therefore already sorted. + */ + return true; + } + + if (k - low < MIN_FIRST_RUN_SIZE) { + + /* + * The first run is too small + * to proceed with scanning. + */ + return false; + } + + run = new int[((size >> 10) | 0x7F) & 0x3FF]; + run[0] = low; + + } else if (a[last - 1] > a[last]) { + + if (count > (k - low) >> MIN_FIRST_RUNS_FACTOR) { + + /* + * The first runs are not long + * enough to continue scanning. + */ + return false; + } + + if (++count == MAX_RUN_CAPACITY) { + + /* + * Array is not highly structured. + */ + return false; + } + + if (count == run.length) { + + /* + * Increase capacity of index array. + */ + run = Arrays.copyOf(run, count << 1); + } } + run[count] = (last = k); } - // These invariants should hold true: - // run[0] = 0 - // run[] = right + 1; (terminator) + /* + * Merge runs of highly structured array. + */ + if (count > 1) { + long[] b; int offset = low; - if (count == 0) { - // A single equal run - return; - } else if (count == 1 && run[count] > right) { - // Either a single ascending or a transformed descending run. - // Always check that a final run is a proper terminator, otherwise - // we have an unterminated trailing run, to handle downstream. - return; - } - right++; - if (run[count] < right) { - // Corner case: the final run is not a terminator. This may happen - // if a final run is an equals run, or there is a single-element run - // at the end. Fix up by adding a proper terminator at the end. - // Note that we terminate with (right + 1), incremented earlier. - run[++count] = right; - } - - // Determine alternation base for merge - byte odd = 0; - for (int n = 1; (n <<= 1) < count; odd ^= 1); - - // Use or create temporary array b for merging - short[] b; // temp array; alternates with a - int ao, bo; // array offsets from 'left' - int blen = right - left; // space needed for b - if (work == null || workLen < blen || workBase + blen > work.length) { - work = new short[blen]; - workBase = 0; - } - if (odd == 0) { - System.arraycopy(a, left, work, workBase, blen); - b = a; - bo = 0; - a = work; - ao = workBase - left; - } else { - b = work; - ao = 0; - bo = workBase - left; - } - - // Merging - for (int last; count > 1; count = last) { - for (int k = (last = 0) + 2; k <= count; k += 2) { - int hi = run[k], mi = run[k - 1]; - for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { - b[i + bo] = a[p++ + ao]; - } else { - b[i + bo] = a[q++ + ao]; - } - } - run[++last] = hi; + if (sorter == null || (b = (long[]) sorter.b) == null) { + b = new long[size]; + } else { + offset = sorter.offset; } - if ((count & 1) != 0) { - for (int i = right, lo = run[count - 1]; --i >= lo; - b[i + bo] = a[i + ao] - ); - run[++last] = right; + mergeRuns(a, b, offset, 1, sorter != null, run, 0, count); + } + return true; + } + + /** + * Merges the specified runs. + * + * @param a the source array + * @param b the temporary buffer used in merging + * @param offset the start index in the source, inclusive + * @param aim specifies merging: to source ( > 0), buffer ( < 0) or any ( == 0) + * @param parallel indicates whether merging is performed in parallel + * @param run the start indexes of the runs, inclusive + * @param lo the start index of the first run, inclusive + * @param hi the start index of the last run, inclusive + * @return the destination where runs are merged + */ + private static long[] mergeRuns(long[] a, long[] b, int offset, + int aim, boolean parallel, int[] run, int lo, int hi) { + + if (hi - lo == 1) { + if (aim >= 0) { + return a; } - short[] t = a; a = b; b = t; - int o = ao; ao = bo; bo = o; + for (int i = run[hi], j = i - offset, low = run[lo]; i > low; + b[--j] = a[--i] + ); + return b; + } + + /* + * Split into approximately equal parts. + */ + int mi = lo, rmi = (run[lo] + run[hi]) >>> 1; + while (run[++mi + 1] <= rmi); + + /* + * Merge the left and right parts. + */ + long[] a1, a2; + + if (parallel && hi - lo > MIN_RUN_COUNT) { + RunMerger merger = new RunMerger(a, b, offset, 0, run, mi, hi).forkMe(); + a1 = mergeRuns(a, b, offset, -aim, true, run, lo, mi); + a2 = (long[]) merger.getDestination(); + } else { + a1 = mergeRuns(a, b, offset, -aim, false, run, lo, mi); + a2 = mergeRuns(a, b, offset, 0, false, run, mi, hi); } + + long[] dst = a1 == a ? b : a; + + int k = a1 == a ? run[lo] - offset : run[lo]; + int lo1 = a1 == b ? run[lo] - offset : run[lo]; + int hi1 = a1 == b ? run[mi] - offset : run[mi]; + int lo2 = a2 == b ? run[mi] - offset : run[mi]; + int hi2 = a2 == b ? run[hi] - offset : run[hi]; + + if (parallel) { + new Merger(null, dst, k, a1, lo1, hi1, a2, lo2, hi2).invoke(); + } else { + mergeParts(null, dst, k, a1, lo1, hi1, a2, lo2, hi2); + } + return dst; } /** - * Sorts the specified range of the array by Dual-Pivot Quicksort. + * Merges the sorted parts. * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param leftmost indicates if this part is the leftmost in the range + * @param merger parallel context + * @param dst the destination where parts are merged + * @param k the start index of the destination, inclusive + * @param a1 the first part + * @param lo1 the start index of the first part, inclusive + * @param hi1 the end index of the first part, exclusive + * @param a2 the second part + * @param lo2 the start index of the second part, inclusive + * @param hi2 the end index of the second part, exclusive */ - private static void sort(short[] a, int left, int right, boolean leftmost) { - int length = right - left + 1; + private static void mergeParts(Merger merger, long[] dst, int k, + long[] a1, int lo1, int hi1, long[] a2, int lo2, int hi2) { + + if (merger != null && a1 == a2) { + + while (true) { - // Use insertion sort on tiny arrays - if (length < INSERTION_SORT_THRESHOLD) { - if (leftmost) { /* - * Traditional (without sentinel) insertion sort, - * optimized for server VM, is used in case of - * the leftmost part. + * The first part must be larger. */ - for (int i = left, j = i; i < right; j = ++i) { - short ai = a[i + 1]; - while (ai < a[j]) { - a[j + 1] = a[j]; - if (j-- == left) { - break; - } - } - a[j + 1] = ai; + if (hi1 - lo1 < hi2 - lo2) { + int lo = lo1; lo1 = lo2; lo2 = lo; + int hi = hi1; hi1 = hi2; hi2 = hi; } - } else { + /* - * Skip the longest ascending sequence. + * Small parts will be merged sequentially. */ - do { - if (left >= right) { - return; - } - } while (a[++left] >= a[left - 1]); + if (hi1 - lo1 < MIN_PARALLEL_MERGE_PARTS_SIZE) { + break; + } /* - * Every element from adjoining part plays the role - * of sentinel, therefore this allows us to avoid the - * left range check on each iteration. Moreover, we use - * the more optimized algorithm, so called pair insertion - * sort, which is faster (in the context of Quicksort) - * than traditional implementation of insertion sort. + * Find the median of the larger part. */ - for (int k = left; ++left <= right; k = ++left) { - short a1 = a[k], a2 = a[left]; + int mi1 = (lo1 + hi1) >>> 1; + long key = a1[mi1]; + int mi2 = hi2; - if (a1 < a2) { - a2 = a1; a1 = a[left]; - } - while (a1 < a[--k]) { - a[k + 2] = a[k]; - } - a[++k + 1] = a1; + /* + * Partition the smaller part. + */ + for (int loo = lo2; loo < mi2; ) { + int t = (loo + mi2) >>> 1; - while (a2 < a[--k]) { - a[k + 1] = a[k]; + if (key > a2[t]) { + loo = t + 1; + } else { + mi2 = t; } - a[k + 1] = a2; } - short last = a[right]; - while (last < a[--right]) { - a[right + 1] = a[right]; - } - a[right + 1] = last; + int d = mi2 - lo2 + mi1 - lo1; + + /* + * Merge the right sub-parts in parallel. + */ + merger.forkMerger(dst, k + d, a1, mi1, hi1, a2, mi2, hi2); + + /* + * Process the sub-left parts. + */ + hi1 = mi1; + hi2 = mi2; } - return; } - // Inexpensive approximation of length / 7 - int seventh = (length >> 3) + (length >> 6) + 1; - /* - * Sort five evenly spaced elements around (and including) the - * center element in the range. These elements will be used for - * pivot selection as described below. The choice for spacing - * these elements was empirically determined to work well on - * a wide variety of inputs. + * Merge small parts sequentially. */ - int e3 = (left + right) >>> 1; // The midpoint - int e2 = e3 - seventh; - int e1 = e2 - seventh; - int e4 = e3 + seventh; - int e5 = e4 + seventh; - - // Sort these elements using insertion sort - if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; } - - if (a[e3] < a[e2]) { short t = a[e3]; a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + while (lo1 < hi1 && lo2 < hi2) { + dst[k++] = a1[lo1] < a2[lo2] ? a1[lo1++] : a2[lo2++]; + } + if (dst != a1 || k < lo1) { + while (lo1 < hi1) { + dst[k++] = a1[lo1++]; + } } - if (a[e4] < a[e3]) { short t = a[e4]; a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + if (dst != a2 || k < lo2) { + while (lo2 < hi2) { + dst[k++] = a2[lo2++]; } } - if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t; - if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + } + +// [byte] + + /** + * Sorts the specified range of the array using + * counting sort or insertion sort. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(byte[] a, int low, int high) { + if (high - low > MIN_BYTE_COUNTING_SORT_SIZE) { + countingSort(a, low, high); + } else { + insertionSort(a, low, high); + } + } + + /** + * Sorts the specified range of the array using insertion sort. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void insertionSort(byte[] a, int low, int high) { + for (int i, k = low; ++k < high; ) { + byte ai = a[i = k]; + + if (ai < a[i - 1]) { + while (--i >= low && ai < a[i]) { + a[i + 1] = a[i]; } + a[i + 1] = ai; } } + } - // Pointers - int less = left; // The index of the first element of center part - int great = right; // The index before the first element of right part + /** + * The number of distinct byte values. + */ + private static final int NUM_BYTE_VALUES = 1 << 8; + + /** + * Max index of byte counter. + */ + private static final int MAX_BYTE_INDEX = Byte.MAX_VALUE + NUM_BYTE_VALUES + 1; + + /** + * Sorts the specified range of the array using counting sort. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void countingSort(byte[] a, int low, int high) { + int[] count = new int[NUM_BYTE_VALUES]; + + /* + * Compute a histogram with the number of each values. + */ + for (int i = high; i > low; ++count[a[--i] & 0xFF]); + + /* + * Place values on their final positions. + */ + for (int k = high, i = MAX_BYTE_INDEX; --i > Byte.MAX_VALUE; ) { + int value = i & 0xFF; + for (low = k - count[value]; k > low; a[--k] = (byte) value); + } + } + +// [char] + + /** + * Sorts the specified range of the array using + * counting sort or Dual-Pivot Quicksort. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(char[] a, int low, int high) { + if (high - low > MIN_SHORT_OR_CHAR_COUNTING_SORT_SIZE) { + countingSort(a, low, high); + } else { + sort(a, 0, low, high); + } + } + + /** + * Sorts the specified array using the Dual-Pivot Quicksort and/or + * other sorts in special-cases, possibly with parallel partitions. + * + * @param a the array to be sorted + * @param bits the combination of recursion depth and bit flag, where + * the right bit "0" indicates that array is the leftmost part + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(char[] a, int bits, int low, int high) { + while (true) { + int end = high - 1, size = high - low; - if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) { /* - * Use the second and fourth of the five sorted elements as pivots. - * These values are inexpensive approximations of the first and - * second terciles of the array. Note that pivot1 <= pivot2. + * Run mixed insertion sort on small non-leftmost parts. */ - short pivot1 = a[e2]; - short pivot2 = a[e4]; + if (size < MAX_MIXED_INSERTION_SORT_SIZE && (bits & 1) > 0) { + mixedInsertionSort(a, low, high - 3 * ((size >> 5) << 3), high); + return; + } /* - * The first and the last elements to be sorted are moved to the - * locations formerly occupied by the pivots. When partitioning - * is complete, the pivots are swapped back into their final - * positions, and excluded from subsequent sorting. + * Invoke insertion sort on small leftmost part. */ - a[e2] = a[left]; - a[e4] = a[right]; + if (size < MAX_INSERTION_SORT_SIZE) { + insertionSort(a, low, high); + return; + } /* - * Skip elements, which are less or greater than pivot values. + * Switch to counting sort if execution + * time is becoming quadratic. */ - while (a[++less] < pivot1); - while (a[--great] > pivot2); + if ((bits += 2) > MAX_RECURSION_DEPTH) { + countingSort(a, low, high); + return; + } /* - * Partitioning: - * - * left part center part right part - * +--------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +--------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (left, less) < pivot1 - * pivot1 <= all in [less, k) <= pivot2 - * all in (great, right) > pivot2 + * Use an inexpensive approximation of the golden ratio + * to select five sample elements and determine pivots. + */ + int step = (size >> 3) * 3 + 3; + + /* + * Five elements around (and including) the central element + * will be used for pivot selection as described below. The + * unequal choice of spacing these elements was empirically + * determined to work well on a wide variety of inputs. + */ + int e1 = low + step; + int e5 = end - step; + int e3 = (e1 + e5) >>> 1; + int e2 = (e1 + e3) >>> 1; + int e4 = (e3 + e5) >>> 1; + char a3 = a[e3]; + + /* + * Sort these elements in place by the combination + * of 4-element sorting network and insertion sort. * - * Pointer k is the first index of ?-part. + * 5 ------o-----------o----------- + * | | + * 4 ------|-----o-----o-----o----- + * | | | + * 2 ------o-----|-----o-----o----- + * | | + * 1 ------------o-----o----------- */ - outer: - for (int k = less - 1; ++k <= great; ) { - short ak = a[k]; - if (ak < pivot1) { // Move a[k] to left part - a[k] = a[less]; - /* - * Here and below we use "a[i] = b; i++;" instead - * of "a[i++] = b;" due to performance issue. - */ - a[less] = ak; - ++less; - } else if (ak > pivot2) { // Move a[k] to right part - while (a[great] > pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] < pivot1) { // a[great] <= pivot2 - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // pivot1 <= a[great] <= pivot2 - a[k] = a[great]; - } - /* - * Here and below we use "a[i] = b; i--;" instead - * of "a[i--] = b;" due to performance issue. - */ - a[great] = ak; - --great; + if (a[e5] < a[e2]) { char t = a[e5]; a[e5] = a[e2]; a[e2] = t; } + if (a[e4] < a[e1]) { char t = a[e4]; a[e4] = a[e1]; a[e1] = t; } + if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t; } + if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + if (a[e4] < a[e2]) { char t = a[e4]; a[e4] = a[e2]; a[e2] = t; } + + if (a3 < a[e2]) { + if (a3 < a[e1]) { + a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3; + } else { + a[e3] = a[e2]; a[e2] = a3; + } + } else if (a3 > a[e4]) { + if (a3 > a[e5]) { + a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3; + } else { + a[e3] = a[e4]; a[e4] = a3; } } - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivots - sort(a, left, less - 2, leftmost); - sort(a, great + 2, right, false); + // Pointers + int lower = low; // The index of the last element of the left part + int upper = end; // The index of the first element of the right part /* - * If center part is too large (comprises > 4/7 of the array), - * swap internal pivot values to ends. + * Partitioning with 2 pivots in case of different elements. */ - if (less < e1 && e5 < great) { + if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) { + /* - * Skip elements, which are equal to pivot values. + * Use the first and fifth of the five sorted elements as + * the pivots. These values are inexpensive approximation + * of tertiles. Note, that pivot1 < pivot2. */ - while (a[less] == pivot1) { - ++less; - } + char pivot1 = a[e1]; + char pivot2 = a[e5]; - while (a[great] == pivot2) { - --great; - } + /* + * The first and the last elements to be sorted are moved + * to the locations formerly occupied by the pivots. When + * partitioning is completed, the pivots are swapped back + * into their final positions, and excluded from the next + * subsequent sorting. + */ + a[e1] = a[lower]; + a[e5] = a[upper]; + + /* + * Skip elements, which are less or greater than the pivots. + */ + while (a[++lower] < pivot1); + while (a[--upper] > pivot2); /* - * Partitioning: + * Backward 3-interval partitioning * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part central part right part + * +------------------------------------------------------------+ + * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 | + * +------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper * * Invariants: * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 + * all in (low, lower] < pivot1 + * pivot1 <= all in (k, upper) <= pivot2 + * all in [upper, end) > pivot2 * - * Pointer k is the first index of ?-part. + * Pointer k is the last index of ?-part */ - outer: - for (int k = less - 1; ++k <= great; ) { - short ak = a[k]; - if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; + for (int unused = --lower, k = ++upper; --k > lower; ) { + char ak = a[k]; + + if (ak < pivot1) { // Move a[k] to the left side + while (lower < k) { + if (a[++lower] >= pivot1) { + if (a[lower] > pivot2) { + a[k] = a[--upper]; + a[upper] = a[lower]; + } else { + a[k] = a[lower]; + } + a[lower] = ak; + break; } } - if (a[great] == pivot1) { // a[great] < pivot2 - a[k] = a[less]; - /* - * Even though a[great] equals to pivot1, the - * assignment a[less] = pivot1 may be incorrect, - * if a[great] and pivot1 are floating-point zeros - * of different signs. Therefore in float and - * double sorting methods we have to use more - * accurate assignment a[less] = a[great]. - */ - a[less] = pivot1; - ++less; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; + } else if (ak > pivot2) { // Move a[k] to the right side + a[k] = a[--upper]; + a[upper] = ak; + } + } + + /* + * Swap the pivots into their final positions. + */ + a[low] = a[lower]; a[lower] = pivot1; + a[end] = a[upper]; a[upper] = pivot2; + + /* + * Sort non-left parts recursively, + * excluding known pivots. + */ + sort(a, bits | 1, lower + 1, upper); + sort(a, bits | 1, upper + 1, high); + + } else { // Use single pivot in case of many equal elements + + /* + * Use the third of the five sorted elements as the pivot. + * This value is inexpensive approximation of the median. + */ + char pivot = a[e3]; + + /* + * The first element to be sorted is moved to the + * location formerly occupied by the pivot. After + * completion of partitioning the pivot is swapped + * back into its final position, and excluded from + * the next subsequent sorting. + */ + a[e3] = a[lower]; + + /* + * Traditional 3-way (Dutch National Flag) partitioning + * + * left part central part right part + * +------------------------------------------------------+ + * | < pivot | ? | == pivot | > pivot | + * +------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper + * + * Invariants: + * + * all in (low, lower] < pivot + * all in (k, upper) == pivot + * all in [upper, end] > pivot + * + * Pointer k is the last index of ?-part + */ + for (int k = ++upper; --k > lower; ) { + char ak = a[k]; + + if (ak != pivot) { + a[k] = pivot; + + if (ak < pivot) { // Move a[k] to the left side + while (a[++lower] < pivot); + + if (a[lower] > pivot) { + a[--upper] = a[lower]; + } + a[lower] = ak; + } else { // ak > pivot - Move a[k] to the right side + a[--upper] = ak; } - a[great] = ak; - --great; } } + + /* + * Swap the pivot into its final position. + */ + a[low] = a[lower]; a[lower] = pivot; + + /* + * Sort the right part, excluding known pivot. + * All elements from the central part are + * equal and therefore already sorted. + */ + sort(a, bits | 1, upper, high); } + high = lower; // Iterate along the left part + } + } - // Sort center part recursively - sort(a, less, great, false); + /** + * Sorts the specified range of the array using mixed insertion sort. + * + * Mixed insertion sort is combination of simple insertion sort, + * pin insertion sort and pair insertion sort. + * + * In the context of Dual-Pivot Quicksort, the pivot element + * from the left part plays the role of sentinel, because it + * is less than any elements from the given part. Therefore, + * expensive check of the left range can be skipped on each + * iteration unless it is the leftmost call. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param end the index of the last element for simple insertion sort + * @param high the index of the last element, exclusive, to be sorted + */ + private static void mixedInsertionSort(char[] a, int low, int end, int high) { + if (end == high) { - } else { // Partitioning with one pivot /* - * Use the third of the five sorted elements as pivot. - * This value is inexpensive approximation of the median. + * Invoke simple insertion sort on tiny array. */ - short pivot = a[e3]; + for (int i; ++low < end; ) { + char ai = a[i = low]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + } + } else { /* - * Partitioning degenerates to the traditional 3-way - * (or "Dutch National Flag") schema: + * Start with pin insertion sort on small part. * - * left part center part right part - * +-------------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +-------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (left, less) < pivot - * all in [less, k) == pivot - * all in (great, right) > pivot - * - * Pointer k is the first index of ?-part. + * Pin insertion sort is extended simple insertion sort. + * The main idea of this sort is to put elements larger + * than an element called pin to the end of array (the + * proper area for such elements). It avoids expensive + * movements of these elements through the whole array. */ - for (int k = less; k <= great; ++k) { - if (a[k] == pivot) { - continue; - } - short ak = a[k]; - if (ak < pivot) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else { // a[k] > pivot - Move a[k] to right part - while (a[great] > pivot) { - --great; - } - if (a[great] < pivot) { // a[great] <= pivot - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // a[great] == pivot - /* - * Even though a[great] equals to pivot, the - * assignment a[k] = pivot may be incorrect, - * if a[great] and pivot are floating-point - * zeros of different signs. Therefore in float - * and double sorting methods we have to use - * more accurate assignment a[k] = a[great]. - */ - a[k] = pivot; + char pin = a[end]; + + for (int i, p = high; ++low < end; ) { + char ai = a[i = low]; + + if (ai < a[i - 1]) { // Small element + + /* + * Insert small element into sorted part. + */ + a[i] = a[--i]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; } - a[great] = ak; - --great; + a[i + 1] = ai; + + } else if (p > i && ai > pin) { // Large element + + /* + * Find element smaller than pin. + */ + while (a[--p] > pin); + + /* + * Swap it with large element. + */ + if (p > i) { + ai = a[p]; + a[p] = a[i]; + } + + /* + * Insert small element into sorted part. + */ + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; } } /* - * Sort left and right parts recursively. - * All elements from center part are equal - * and, therefore, already sorted. + * Continue with pair insertion sort on remain part. */ - sort(a, left, less - 1, leftmost); - sort(a, great + 1, right, false); + for (int i; low < high; ++low) { + char a1 = a[i = low], a2 = a[++low]; + + /* + * Insert two elements per iteration: at first, insert the + * larger element and then insert the smaller element, but + * from the position where the larger element was inserted. + */ + if (a1 > a2) { + + while (a1 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a1; + + while (a2 < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = a2; + + } else if (a1 < a[i - 1]) { + + while (a2 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a2; + + while (a1 < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = a1; + } + } } } /** - * Sorts the specified range of the array using the given - * workspace array slice if possible for merging + * Sorts the specified range of the array using insertion sort. * * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param work a workspace array (slice) - * @param workBase origin of usable space in work array - * @param workLen usable size of work array + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted */ - static void sort(char[] a, int left, int right, - char[] work, int workBase, int workLen) { - // Use counting sort on large arrays - if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) { - int[] count = new int[NUM_CHAR_VALUES]; - - for (int i = left - 1; ++i <= right; - count[a[i]]++ - ); - for (int i = NUM_CHAR_VALUES, k = right + 1; k > left; ) { - while (count[--i] == 0); - char value = (char) i; - int s = count[i]; - - do { - a[--k] = value; - } while (--s > 0); + private static void insertionSort(char[] a, int low, int high) { + for (int i, k = low; ++k < high; ) { + char ai = a[i = k]; + + if (ai < a[i - 1]) { + while (--i >= low && ai < a[i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; } - } else { // Use Dual-Pivot Quicksort on small arrays - doSort(a, left, right, work, workBase, workLen); } } - /** The number of distinct char values. */ + /** + * The number of distinct char values. + */ private static final int NUM_CHAR_VALUES = 1 << 16; /** - * Sorts the specified range of the array. + * Sorts the specified range of the array using counting sort. * * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param work a workspace array (slice) - * @param workBase origin of usable space in work array - * @param workLen usable size of work array - */ - private static void doSort(char[] a, int left, int right, - char[] work, int workBase, int workLen) { - // Use Quicksort on small arrays - if (right - left < QUICKSORT_THRESHOLD) { - sort(a, left, right, true); - return; - } + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void countingSort(char[] a, int low, int high) { + int[] count = new int[NUM_CHAR_VALUES]; /* - * Index run[i] is the start of i-th run - * (ascending or descending sequence). + * Compute a histogram with the number of each values. */ - int[] run = new int[MAX_RUN_COUNT + 1]; - int count = 0; run[0] = left; + for (int i = high; i > low; ++count[a[--i]]); - // Check if the array is nearly sorted - for (int k = left; k < right; run[count] = k) { - // Equal items in the beginning of the sequence - while (k < right && a[k] == a[k + 1]) - k++; - if (k == right) break; // Sequence finishes with equal items - if (a[k] < a[k + 1]) { // ascending - while (++k <= right && a[k - 1] <= a[k]); - } else if (a[k] > a[k + 1]) { // descending - while (++k <= right && a[k - 1] >= a[k]); - // Transform into an ascending sequence - for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) { - char t = a[lo]; a[lo] = a[hi]; a[hi] = t; - } + /* + * Place values on their final positions. + */ + for (int k = high, i = NUM_CHAR_VALUES; --i > -1; ) { + for (low = k - count[i]; k > low; a[--k] = (char) i); + } + } + +// [short] + + /** + * Sorts the specified range of the array using + * counting sort or Dual-Pivot Quicksort. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(short[] a, int low, int high) { + if (high - low > MIN_SHORT_OR_CHAR_COUNTING_SORT_SIZE) { + countingSort(a, low, high); + } else { + sort(a, 0, low, high); + } + } + + /** + * Sorts the specified array using the Dual-Pivot Quicksort and/or + * other sorts in special-cases, possibly with parallel partitions. + * + * @param a the array to be sorted + * @param bits the combination of recursion depth and bit flag, where + * the right bit "0" indicates that array is the leftmost part + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(short[] a, int bits, int low, int high) { + while (true) { + int end = high - 1, size = high - low; + + /* + * Run mixed insertion sort on small non-leftmost parts. + */ + if (size < MAX_MIXED_INSERTION_SORT_SIZE && (bits & 1) > 0) { + mixedInsertionSort(a, low, high - 3 * ((size >> 5) << 3), high); + return; } - // Merge a transformed descending sequence followed by an - // ascending sequence - if (run[count] > left && a[run[count]] >= a[run[count] - 1]) { - count--; + /* + * Invoke insertion sort on small leftmost part. + */ + if (size < MAX_INSERTION_SORT_SIZE) { + insertionSort(a, low, high); + return; } /* - * The array is not highly structured, - * use Quicksort instead of merge sort. + * Switch to counting sort if execution + * time is becoming quadratic. */ - if (++count == MAX_RUN_COUNT) { - sort(a, left, right, true); + if ((bits += 2) > MAX_RECURSION_DEPTH) { + countingSort(a, low, high); return; } - } - // These invariants should hold true: - // run[0] = 0 - // run[] = right + 1; (terminator) + /* + * Use an inexpensive approximation of the golden ratio + * to select five sample elements and determine pivots. + */ + int step = (size >> 3) * 3 + 3; - if (count == 0) { - // A single equal run - return; - } else if (count == 1 && run[count] > right) { - // Either a single ascending or a transformed descending run. - // Always check that a final run is a proper terminator, otherwise - // we have an unterminated trailing run, to handle downstream. - return; - } - right++; - if (run[count] < right) { - // Corner case: the final run is not a terminator. This may happen - // if a final run is an equals run, or there is a single-element run - // at the end. Fix up by adding a proper terminator at the end. - // Note that we terminate with (right + 1), incremented earlier. - run[++count] = right; - } - - // Determine alternation base for merge - byte odd = 0; - for (int n = 1; (n <<= 1) < count; odd ^= 1); - - // Use or create temporary array b for merging - char[] b; // temp array; alternates with a - int ao, bo; // array offsets from 'left' - int blen = right - left; // space needed for b - if (work == null || workLen < blen || workBase + blen > work.length) { - work = new char[blen]; - workBase = 0; - } - if (odd == 0) { - System.arraycopy(a, left, work, workBase, blen); - b = a; - bo = 0; - a = work; - ao = workBase - left; - } else { - b = work; - ao = 0; - bo = workBase - left; - } - - // Merging - for (int last; count > 1; count = last) { - for (int k = (last = 0) + 2; k <= count; k += 2) { - int hi = run[k], mi = run[k - 1]; - for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { - b[i + bo] = a[p++ + ao]; - } else { - b[i + bo] = a[q++ + ao]; - } + /* + * Five elements around (and including) the central element + * will be used for pivot selection as described below. The + * unequal choice of spacing these elements was empirically + * determined to work well on a wide variety of inputs. + */ + int e1 = low + step; + int e5 = end - step; + int e3 = (e1 + e5) >>> 1; + int e2 = (e1 + e3) >>> 1; + int e4 = (e3 + e5) >>> 1; + short a3 = a[e3]; + + /* + * Sort these elements in place by the combination + * of 4-element sorting network and insertion sort. + * + * 5 ------o-----------o----------- + * | | + * 4 ------|-----o-----o-----o----- + * | | | + * 2 ------o-----|-----o-----o----- + * | | + * 1 ------------o-----o----------- + */ + if (a[e5] < a[e2]) { short t = a[e5]; a[e5] = a[e2]; a[e2] = t; } + if (a[e4] < a[e1]) { short t = a[e4]; a[e4] = a[e1]; a[e1] = t; } + if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t; } + if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + if (a[e4] < a[e2]) { short t = a[e4]; a[e4] = a[e2]; a[e2] = t; } + + if (a3 < a[e2]) { + if (a3 < a[e1]) { + a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3; + } else { + a[e3] = a[e2]; a[e2] = a3; + } + } else if (a3 > a[e4]) { + if (a3 > a[e5]) { + a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3; + } else { + a[e3] = a[e4]; a[e4] = a3; } - run[++last] = hi; } - if ((count & 1) != 0) { - for (int i = right, lo = run[count - 1]; --i >= lo; - b[i + bo] = a[i + ao] - ); - run[++last] = right; + + // Pointers + int lower = low; // The index of the last element of the left part + int upper = end; // The index of the first element of the right part + + /* + * Partitioning with 2 pivots in case of different elements. + */ + if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) { + + /* + * Use the first and fifth of the five sorted elements as + * the pivots. These values are inexpensive approximation + * of tertiles. Note, that pivot1 < pivot2. + */ + short pivot1 = a[e1]; + short pivot2 = a[e5]; + + /* + * The first and the last elements to be sorted are moved + * to the locations formerly occupied by the pivots. When + * partitioning is completed, the pivots are swapped back + * into their final positions, and excluded from the next + * subsequent sorting. + */ + a[e1] = a[lower]; + a[e5] = a[upper]; + + /* + * Skip elements, which are less or greater than the pivots. + */ + while (a[++lower] < pivot1); + while (a[--upper] > pivot2); + + /* + * Backward 3-interval partitioning + * + * left part central part right part + * +------------------------------------------------------------+ + * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 | + * +------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper + * + * Invariants: + * + * all in (low, lower] < pivot1 + * pivot1 <= all in (k, upper) <= pivot2 + * all in [upper, end) > pivot2 + * + * Pointer k is the last index of ?-part + */ + for (int unused = --lower, k = ++upper; --k > lower; ) { + short ak = a[k]; + + if (ak < pivot1) { // Move a[k] to the left side + while (lower < k) { + if (a[++lower] >= pivot1) { + if (a[lower] > pivot2) { + a[k] = a[--upper]; + a[upper] = a[lower]; + } else { + a[k] = a[lower]; + } + a[lower] = ak; + break; + } + } + } else if (ak > pivot2) { // Move a[k] to the right side + a[k] = a[--upper]; + a[upper] = ak; + } + } + + /* + * Swap the pivots into their final positions. + */ + a[low] = a[lower]; a[lower] = pivot1; + a[end] = a[upper]; a[upper] = pivot2; + + /* + * Sort non-left parts recursively, + * excluding known pivots. + */ + sort(a, bits | 1, lower + 1, upper); + sort(a, bits | 1, upper + 1, high); + + } else { // Use single pivot in case of many equal elements + + /* + * Use the third of the five sorted elements as the pivot. + * This value is inexpensive approximation of the median. + */ + short pivot = a[e3]; + + /* + * The first element to be sorted is moved to the + * location formerly occupied by the pivot. After + * completion of partitioning the pivot is swapped + * back into its final position, and excluded from + * the next subsequent sorting. + */ + a[e3] = a[lower]; + + /* + * Traditional 3-way (Dutch National Flag) partitioning + * + * left part central part right part + * +------------------------------------------------------+ + * | < pivot | ? | == pivot | > pivot | + * +------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper + * + * Invariants: + * + * all in (low, lower] < pivot + * all in (k, upper) == pivot + * all in [upper, end] > pivot + * + * Pointer k is the last index of ?-part + */ + for (int k = ++upper; --k > lower; ) { + short ak = a[k]; + + if (ak != pivot) { + a[k] = pivot; + + if (ak < pivot) { // Move a[k] to the left side + while (a[++lower] < pivot); + + if (a[lower] > pivot) { + a[--upper] = a[lower]; + } + a[lower] = ak; + } else { // ak > pivot - Move a[k] to the right side + a[--upper] = ak; + } + } + } + + /* + * Swap the pivot into its final position. + */ + a[low] = a[lower]; a[lower] = pivot; + + /* + * Sort the right part, excluding known pivot. + * All elements from the central part are + * equal and therefore already sorted. + */ + sort(a, bits | 1, upper, high); } - char[] t = a; a = b; b = t; - int o = ao; ao = bo; bo = o; + high = lower; // Iterate along the left part } } /** - * Sorts the specified range of the array by Dual-Pivot Quicksort. + * Sorts the specified range of the array using mixed insertion sort. + * + * Mixed insertion sort is combination of simple insertion sort, + * pin insertion sort and pair insertion sort. + * + * In the context of Dual-Pivot Quicksort, the pivot element + * from the left part plays the role of sentinel, because it + * is less than any elements from the given part. Therefore, + * expensive check of the left range can be skipped on each + * iteration unless it is the leftmost call. * * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param leftmost indicates if this part is the leftmost in the range + * @param low the index of the first element, inclusive, to be sorted + * @param end the index of the last element for simple insertion sort + * @param high the index of the last element, exclusive, to be sorted */ - private static void sort(char[] a, int left, int right, boolean leftmost) { - int length = right - left + 1; + private static void mixedInsertionSort(short[] a, int low, int end, int high) { + if (end == high) { - // Use insertion sort on tiny arrays - if (length < INSERTION_SORT_THRESHOLD) { - if (leftmost) { - /* - * Traditional (without sentinel) insertion sort, - * optimized for server VM, is used in case of - * the leftmost part. - */ - for (int i = left, j = i; i < right; j = ++i) { - char ai = a[i + 1]; - while (ai < a[j]) { - a[j + 1] = a[j]; - if (j-- == left) { - break; - } - } - a[j + 1] = ai; + /* + * Invoke simple insertion sort on tiny array. + */ + for (int i; ++low < end; ) { + short ai = a[i = low]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; } - } else { - /* - * Skip the longest ascending sequence. - */ - do { - if (left >= right) { - return; + a[i + 1] = ai; + } + } else { + + /* + * Start with pin insertion sort on small part. + * + * Pin insertion sort is extended simple insertion sort. + * The main idea of this sort is to put elements larger + * than an element called pin to the end of array (the + * proper area for such elements). It avoids expensive + * movements of these elements through the whole array. + */ + short pin = a[end]; + + for (int i, p = high; ++low < end; ) { + short ai = a[i = low]; + + if (ai < a[i - 1]) { // Small element + + /* + * Insert small element into sorted part. + */ + a[i] = a[--i]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + + } else if (p > i && ai > pin) { // Large element + + /* + * Find element smaller than pin. + */ + while (a[--p] > pin); + + /* + * Swap it with large element. + */ + if (p > i) { + ai = a[p]; + a[p] = a[i]; } - } while (a[++left] >= a[left - 1]); + + /* + * Insert small element into sorted part. + */ + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + } + } + + /* + * Continue with pair insertion sort on remain part. + */ + for (int i; low < high; ++low) { + short a1 = a[i = low], a2 = a[++low]; /* - * Every element from adjoining part plays the role - * of sentinel, therefore this allows us to avoid the - * left range check on each iteration. Moreover, we use - * the more optimized algorithm, so called pair insertion - * sort, which is faster (in the context of Quicksort) - * than traditional implementation of insertion sort. + * Insert two elements per iteration: at first, insert the + * larger element and then insert the smaller element, but + * from the position where the larger element was inserted. */ - for (int k = left; ++left <= right; k = ++left) { - char a1 = a[k], a2 = a[left]; + if (a1 > a2) { + + while (a1 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a1; - if (a1 < a2) { - a2 = a1; a1 = a[left]; + while (a2 < a[--i]) { + a[i + 1] = a[i]; } - while (a1 < a[--k]) { - a[k + 2] = a[k]; + a[i + 1] = a2; + + } else if (a1 < a[i - 1]) { + + while (a2 < a[--i]) { + a[i + 2] = a[i]; } - a[++k + 1] = a1; + a[++i + 1] = a2; - while (a2 < a[--k]) { - a[k + 1] = a[k]; + while (a1 < a[--i]) { + a[i + 1] = a[i]; } - a[k + 1] = a2; + a[i + 1] = a1; } - char last = a[right]; + } + } + } - while (last < a[--right]) { - a[right + 1] = a[right]; + /** + * Sorts the specified range of the array using insertion sort. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void insertionSort(short[] a, int low, int high) { + for (int i, k = low; ++k < high; ) { + short ai = a[i = k]; + + if (ai < a[i - 1]) { + while (--i >= low && ai < a[i]) { + a[i + 1] = a[i]; } - a[right + 1] = last; + a[i + 1] = ai; } - return; } + } + + /** + * The number of distinct short values. + */ + private static final int NUM_SHORT_VALUES = 1 << 16; + + /** + * Max index of short counter. + */ + private static final int MAX_SHORT_INDEX = Short.MAX_VALUE + NUM_SHORT_VALUES + 1; + + /** + * Sorts the specified range of the array using counting sort. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void countingSort(short[] a, int low, int high) { + int[] count = new int[NUM_SHORT_VALUES]; + + /* + * Compute a histogram with the number of each values. + */ + for (int i = high; i > low; ++count[a[--i] & 0xFFFF]); + + /* + * Place values on their final positions. + */ + for (int k = high, i = MAX_SHORT_INDEX; --i > Short.MAX_VALUE; ) { + int value = i & 0xFFFF; + for (low = k - count[value]; k > low; a[--k] = (short) value); + } + } - // Inexpensive approximation of length / 7 - int seventh = (length >> 3) + (length >> 6) + 1; +// [float] + /** + * Sorts the specified range of the array using parallel merge + * sort and/or Dual-Pivot Quicksort. + * + * To balance the faster splitting and parallelism of merge sort + * with the faster element partitioning of Quicksort, ranges are + * subdivided in tiers such that, if there is enough parallelism, + * the four-way parallel merge is started, still ensuring enough + * parallelism to process the partitions. + * + * @param a the array to be sorted + * @param parallelism the parallelism level + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(float[] a, int parallelism, int low, int high) { /* - * Sort five evenly spaced elements around (and including) the - * center element in the range. These elements will be used for - * pivot selection as described below. The choice for spacing - * these elements was empirically determined to work well on - * a wide variety of inputs. + * Phase 1. Count the number of negative zero -0.0f, + * turn them into positive zero, and move all NaNs + * to the end of the array. */ - int e3 = (left + right) >>> 1; // The midpoint - int e2 = e3 - seventh; - int e1 = e2 - seventh; - int e4 = e3 + seventh; - int e5 = e4 + seventh; + int numNegativeZero = 0; - // Sort these elements using insertion sort - if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + for (int k = high; k > low; ) { + float ak = a[--k]; - if (a[e3] < a[e2]) { char t = a[e3]; a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } - } - if (a[e4] < a[e3]) { char t = a[e4]; a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + if (ak == 0.0f && Float.floatToRawIntBits(ak) < 0) { // ak is -0.0f + numNegativeZero += 1; + a[k] = 0.0f; + } else if (ak != ak) { // ak is NaN + a[k] = a[--high]; + a[high] = ak; } } - if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t; - if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } - } + + /* + * Phase 2. Sort everything except NaNs, + * which are already in place. + */ + int size = high - low; + + if (parallelism > 0 && size > MIN_PARALLEL_SORT_SIZE) { + int depth = getDepth(parallelism, size >> 12); + float[] b = depth == 0 ? null : new float[size]; + new Sorter(null, a, b, low, size, low, depth).invoke(); + } else { + sort(null, a, 0, low, high); + } + + /* + * Phase 3. Turn positive zero 0.0f + * back into negative zero -0.0f. + */ + if (++numNegativeZero == 1) { + return; + } + + /* + * Find the position one less than + * the index of the first zero. + */ + while (low <= high) { + int middle = (low + high) >>> 1; + + if (a[middle] < 0) { + low = middle + 1; + } else { + high = middle - 1; } } - // Pointers - int less = left; // The index of the first element of center part - int great = right; // The index before the first element of right part + /* + * Replace the required number of 0.0f by -0.0f. + */ + while (--numNegativeZero > 0) { + a[++high] = -0.0f; + } + } + + /** + * Sorts the specified array using the Dual-Pivot Quicksort and/or + * other sorts in special-cases, possibly with parallel partitions. + * + * @param sorter parallel context + * @param a the array to be sorted + * @param bits the combination of recursion depth and bit flag, where + * the right bit "0" indicates that array is the leftmost part + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(Sorter sorter, float[] a, int bits, int low, int high) { + while (true) { + int end = high - 1, size = high - low; - if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) { /* - * Use the second and fourth of the five sorted elements as pivots. - * These values are inexpensive approximations of the first and - * second terciles of the array. Note that pivot1 <= pivot2. + * Run mixed insertion sort on small non-leftmost parts. */ - char pivot1 = a[e2]; - char pivot2 = a[e4]; + if (size < MAX_MIXED_INSERTION_SORT_SIZE && (bits & 1) > 0) { + mixedInsertionSort(a, low, high - 3 * ((size >> 5) << 3), high); + return; + } /* - * The first and the last elements to be sorted are moved to the - * locations formerly occupied by the pivots. When partitioning - * is complete, the pivots are swapped back into their final - * positions, and excluded from subsequent sorting. + * Invoke insertion sort on small leftmost part. */ - a[e2] = a[left]; - a[e4] = a[right]; + if (size < MAX_INSERTION_SORT_SIZE) { + insertionSort(a, low, high); + return; + } /* - * Skip elements, which are less or greater than pivot values. + * Check if the whole array or large non-leftmost + * parts are nearly sorted and then merge runs. */ - while (a[++less] < pivot1); - while (a[--great] > pivot2); + if ((bits == 0 || size > MIN_TRY_MERGE_SIZE && (bits & 1) > 0) + && tryMergeRuns(sorter, a, low, size)) { + return; + } /* - * Partitioning: - * - * left part center part right part - * +--------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +--------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (left, less) < pivot1 - * pivot1 <= all in [less, k) <= pivot2 - * all in (great, right) > pivot2 + * Switch to heap sort if execution + * time is becoming quadratic. + */ + if ((bits += 2) > MAX_RECURSION_DEPTH) { + heapSort(a, low, high); + return; + } + + /* + * Use an inexpensive approximation of the golden ratio + * to select five sample elements and determine pivots. + */ + int step = (size >> 3) * 3 + 3; + + /* + * Five elements around (and including) the central element + * will be used for pivot selection as described below. The + * unequal choice of spacing these elements was empirically + * determined to work well on a wide variety of inputs. + */ + int e1 = low + step; + int e5 = end - step; + int e3 = (e1 + e5) >>> 1; + int e2 = (e1 + e3) >>> 1; + int e4 = (e3 + e5) >>> 1; + float a3 = a[e3]; + + /* + * Sort these elements in place by the combination + * of 4-element sorting network and insertion sort. * - * Pointer k is the first index of ?-part. + * 5 ------o-----------o----------- + * | | + * 4 ------|-----o-----o-----o----- + * | | | + * 2 ------o-----|-----o-----o----- + * | | + * 1 ------------o-----o----------- */ - outer: - for (int k = less - 1; ++k <= great; ) { - char ak = a[k]; - if (ak < pivot1) { // Move a[k] to left part - a[k] = a[less]; - /* - * Here and below we use "a[i] = b; i++;" instead - * of "a[i++] = b;" due to performance issue. - */ - a[less] = ak; - ++less; - } else if (ak > pivot2) { // Move a[k] to right part - while (a[great] > pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] < pivot1) { // a[great] <= pivot2 - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // pivot1 <= a[great] <= pivot2 - a[k] = a[great]; - } - /* - * Here and below we use "a[i] = b; i--;" instead - * of "a[i--] = b;" due to performance issue. - */ - a[great] = ak; - --great; + if (a[e5] < a[e2]) { float t = a[e5]; a[e5] = a[e2]; a[e2] = t; } + if (a[e4] < a[e1]) { float t = a[e4]; a[e4] = a[e1]; a[e1] = t; } + if (a[e5] < a[e4]) { float t = a[e5]; a[e5] = a[e4]; a[e4] = t; } + if (a[e2] < a[e1]) { float t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + if (a[e4] < a[e2]) { float t = a[e4]; a[e4] = a[e2]; a[e2] = t; } + + if (a3 < a[e2]) { + if (a3 < a[e1]) { + a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3; + } else { + a[e3] = a[e2]; a[e2] = a3; + } + } else if (a3 > a[e4]) { + if (a3 > a[e5]) { + a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3; + } else { + a[e3] = a[e4]; a[e4] = a3; } } - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivots - sort(a, left, less - 2, leftmost); - sort(a, great + 2, right, false); + // Pointers + int lower = low; // The index of the last element of the left part + int upper = end; // The index of the first element of the right part /* - * If center part is too large (comprises > 4/7 of the array), - * swap internal pivot values to ends. + * Partitioning with 2 pivots in case of different elements. */ - if (less < e1 && e5 < great) { + if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) { + /* - * Skip elements, which are equal to pivot values. + * Use the first and fifth of the five sorted elements as + * the pivots. These values are inexpensive approximation + * of tertiles. Note, that pivot1 < pivot2. */ - while (a[less] == pivot1) { - ++less; + float pivot1 = a[e1]; + float pivot2 = a[e5]; + + /* + * The first and the last elements to be sorted are moved + * to the locations formerly occupied by the pivots. When + * partitioning is completed, the pivots are swapped back + * into their final positions, and excluded from the next + * subsequent sorting. + */ + a[e1] = a[lower]; + a[e5] = a[upper]; + + /* + * Skip elements, which are less or greater than the pivots. + */ + while (a[++lower] < pivot1); + while (a[--upper] > pivot2); + + /* + * Backward 3-interval partitioning + * + * left part central part right part + * +------------------------------------------------------------+ + * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 | + * +------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper + * + * Invariants: + * + * all in (low, lower] < pivot1 + * pivot1 <= all in (k, upper) <= pivot2 + * all in [upper, end) > pivot2 + * + * Pointer k is the last index of ?-part + */ + for (int unused = --lower, k = ++upper; --k > lower; ) { + float ak = a[k]; + + if (ak < pivot1) { // Move a[k] to the left side + while (lower < k) { + if (a[++lower] >= pivot1) { + if (a[lower] > pivot2) { + a[k] = a[--upper]; + a[upper] = a[lower]; + } else { + a[k] = a[lower]; + } + a[lower] = ak; + break; + } + } + } else if (ak > pivot2) { // Move a[k] to the right side + a[k] = a[--upper]; + a[upper] = ak; + } } - while (a[great] == pivot2) { - --great; + /* + * Swap the pivots into their final positions. + */ + a[low] = a[lower]; a[lower] = pivot1; + a[end] = a[upper]; a[upper] = pivot2; + + /* + * Sort non-left parts recursively (possibly in parallel), + * excluding known pivots. + */ + if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) { + sorter.forkSorter(bits | 1, lower + 1, upper); + sorter.forkSorter(bits | 1, upper + 1, high); + } else { + sort(sorter, a, bits | 1, lower + 1, upper); + sort(sorter, a, bits | 1, upper + 1, high); } + } else { // Use single pivot in case of many equal elements + /* - * Partitioning: + * Use the third of the five sorted elements as the pivot. + * This value is inexpensive approximation of the median. + */ + float pivot = a[e3]; + + /* + * The first element to be sorted is moved to the + * location formerly occupied by the pivot. After + * completion of partitioning the pivot is swapped + * back into its final position, and excluded from + * the next subsequent sorting. + */ + a[e3] = a[lower]; + + /* + * Traditional 3-way (Dutch National Flag) partitioning * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part central part right part + * +------------------------------------------------------+ + * | < pivot | ? | == pivot | > pivot | + * +------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper * * Invariants: * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 + * all in (low, lower] < pivot + * all in (k, upper) == pivot + * all in [upper, end] > pivot * - * Pointer k is the first index of ?-part. + * Pointer k is the last index of ?-part */ - outer: - for (int k = less - 1; ++k <= great; ) { - char ak = a[k]; - if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; + for (int k = ++upper; --k > lower; ) { + float ak = a[k]; + + if (ak != pivot) { + a[k] = pivot; + + if (ak < pivot) { // Move a[k] to the left side + while (a[++lower] < pivot); + + if (a[lower] > pivot) { + a[--upper] = a[lower]; } + a[lower] = ak; + } else { // ak > pivot - Move a[k] to the right side + a[--upper] = ak; } - if (a[great] == pivot1) { // a[great] < pivot2 - a[k] = a[less]; - /* - * Even though a[great] equals to pivot1, the - * assignment a[less] = pivot1 may be incorrect, - * if a[great] and pivot1 are floating-point zeros - * of different signs. Therefore in float and - * double sorting methods we have to use more - * accurate assignment a[less] = a[great]. - */ - a[less] = pivot1; - ++less; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great] = ak; - --great; } } + + /* + * Swap the pivot into its final position. + */ + a[low] = a[lower]; a[lower] = pivot; + + /* + * Sort the right part (possibly in parallel), excluding + * known pivot. All elements from the central part are + * equal and therefore already sorted. + */ + if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) { + sorter.forkSorter(bits | 1, upper, high); + } else { + sort(sorter, a, bits | 1, upper, high); + } } + high = lower; // Iterate along the left part + } + } - // Sort center part recursively - sort(a, less, great, false); + /** + * Sorts the specified range of the array using mixed insertion sort. + * + * Mixed insertion sort is combination of simple insertion sort, + * pin insertion sort and pair insertion sort. + * + * In the context of Dual-Pivot Quicksort, the pivot element + * from the left part plays the role of sentinel, because it + * is less than any elements from the given part. Therefore, + * expensive check of the left range can be skipped on each + * iteration unless it is the leftmost call. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param end the index of the last element for simple insertion sort + * @param high the index of the last element, exclusive, to be sorted + */ + private static void mixedInsertionSort(float[] a, int low, int end, int high) { + if (end == high) { - } else { // Partitioning with one pivot /* - * Use the third of the five sorted elements as pivot. - * This value is inexpensive approximation of the median. + * Invoke simple insertion sort on tiny array. */ - char pivot = a[e3]; + for (int i; ++low < end; ) { + float ai = a[i = low]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + } + } else { /* - * Partitioning degenerates to the traditional 3-way - * (or "Dutch National Flag") schema: - * - * left part center part right part - * +-------------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +-------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * Start with pin insertion sort on small part. * - * Invariants: - * - * all in (left, less) < pivot - * all in [less, k) == pivot - * all in (great, right) > pivot - * - * Pointer k is the first index of ?-part. + * Pin insertion sort is extended simple insertion sort. + * The main idea of this sort is to put elements larger + * than an element called pin to the end of array (the + * proper area for such elements). It avoids expensive + * movements of these elements through the whole array. */ - for (int k = less; k <= great; ++k) { - if (a[k] == pivot) { - continue; - } - char ak = a[k]; - if (ak < pivot) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else { // a[k] > pivot - Move a[k] to right part - while (a[great] > pivot) { - --great; - } - if (a[great] < pivot) { // a[great] <= pivot - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // a[great] == pivot - /* - * Even though a[great] equals to pivot, the - * assignment a[k] = pivot may be incorrect, - * if a[great] and pivot are floating-point - * zeros of different signs. Therefore in float - * and double sorting methods we have to use - * more accurate assignment a[k] = a[great]. - */ - a[k] = pivot; + float pin = a[end]; + + for (int i, p = high; ++low < end; ) { + float ai = a[i = low]; + + if (ai < a[i - 1]) { // Small element + + /* + * Insert small element into sorted part. + */ + a[i] = a[--i]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; } - a[great] = ak; - --great; + a[i + 1] = ai; + + } else if (p > i && ai > pin) { // Large element + + /* + * Find element smaller than pin. + */ + while (a[--p] > pin); + + /* + * Swap it with large element. + */ + if (p > i) { + ai = a[p]; + a[p] = a[i]; + } + + /* + * Insert small element into sorted part. + */ + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; } } /* - * Sort left and right parts recursively. - * All elements from center part are equal - * and, therefore, already sorted. + * Continue with pair insertion sort on remain part. */ - sort(a, left, less - 1, leftmost); - sort(a, great + 1, right, false); + for (int i; low < high; ++low) { + float a1 = a[i = low], a2 = a[++low]; + + /* + * Insert two elements per iteration: at first, insert the + * larger element and then insert the smaller element, but + * from the position where the larger element was inserted. + */ + if (a1 > a2) { + + while (a1 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a1; + + while (a2 < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = a2; + + } else if (a1 < a[i - 1]) { + + while (a2 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a2; + + while (a1 < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = a1; + } + } } } - /** The number of distinct byte values. */ - private static final int NUM_BYTE_VALUES = 1 << 8; - /** - * Sorts the specified range of the array. + * Sorts the specified range of the array using insertion sort. * * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted */ - static void sort(byte[] a, int left, int right) { - // Use counting sort on large arrays - if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) { - int[] count = new int[NUM_BYTE_VALUES]; - - for (int i = left - 1; ++i <= right; - count[a[i] - Byte.MIN_VALUE]++ - ); - for (int i = NUM_BYTE_VALUES, k = right + 1; k > left; ) { - while (count[--i] == 0); - byte value = (byte) (i + Byte.MIN_VALUE); - int s = count[i]; - - do { - a[--k] = value; - } while (--s > 0); - } - } else { // Use insertion sort on small arrays - for (int i = left, j = i; i < right; j = ++i) { - byte ai = a[i + 1]; - while (ai < a[j]) { - a[j + 1] = a[j]; - if (j-- == left) { - break; - } + private static void insertionSort(float[] a, int low, int high) { + for (int i, k = low; ++k < high; ) { + float ai = a[i = k]; + + if (ai < a[i - 1]) { + while (--i >= low && ai < a[i]) { + a[i + 1] = a[i]; } - a[j + 1] = ai; + a[i + 1] = ai; } } } /** - * Sorts the specified range of the array using the given - * workspace array slice if possible for merging + * Sorts the specified range of the array using heap sort. * * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param work a workspace array (slice) - * @param workBase origin of usable space in work array - * @param workLen usable size of work array + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted */ - static void sort(float[] a, int left, int right, - float[] work, int workBase, int workLen) { - /* - * Phase 1: Move NaNs to the end of the array. - */ - while (left <= right && Float.isNaN(a[right])) { - --right; + private static void heapSort(float[] a, int low, int high) { + for (int k = (low + high) >>> 1; k > low; ) { + pushDown(a, --k, a[k], low, high); + } + while (--high > low) { + float max = a[low]; + pushDown(a, low, a[high], low, high); + a[high] = max; } - for (int k = right; --k >= left; ) { - float ak = a[k]; - if (ak != ak) { // a[k] is NaN - a[k] = a[right]; - a[right] = ak; - --right; + } + + /** + * Pushes specified element down during heap sort. + * + * @param a the given array + * @param p the start index + * @param value the given element + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void pushDown(float[] a, int p, float value, int low, int high) { + for (int k ;; a[p] = a[p = k]) { + k = (p << 1) - low + 2; // Index of the right child + + if (k > high) { + break; + } + if (k == high || a[k] < a[k - 1]) { + --k; + } + if (a[k] <= value) { + break; } } + a[p] = value; + } - /* - * Phase 2: Sort everything except NaNs (which are already in place). - */ - doSort(a, left, right, work, workBase, workLen); + /** + * Tries to sort the specified range of the array. + * + * @param sorter parallel context + * @param a the array to be sorted + * @param low the index of the first element to be sorted + * @param size the array size + * @return true if finally sorted, false otherwise + */ + private static boolean tryMergeRuns(Sorter sorter, float[] a, int low, int size) { /* - * Phase 3: Place negative zeros before positive zeros. + * The run array is constructed only if initial runs are + * long enough to continue, run[i] then holds start index + * of the i-th sequence of elements in non-descending order. */ - int hi = right; + int[] run = null; + int high = low + size; + int count = 1, last = low; /* - * Find the first zero, or first positive, or last negative element. + * Identify all possible runs. */ - while (left < hi) { - int middle = (left + hi) >>> 1; - float middleValue = a[middle]; + for (int k = low + 1; k < high; ) { - if (middleValue < 0.0f) { - left = middle + 1; - } else { - hi = middle; + /* + * Find the end index of the current run. + */ + if (a[k - 1] < a[k]) { + + // Identify ascending sequence + while (++k < high && a[k - 1] <= a[k]); + + } else if (a[k - 1] > a[k]) { + + // Identify descending sequence + while (++k < high && a[k - 1] >= a[k]); + + // Reverse into ascending order + for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) { + float ai = a[i]; a[i] = a[j]; a[j] = ai; + } + } else { // Identify constant sequence + for (float ak = a[k]; ++k < high && ak == a[k]; ); + + if (k < high) { + continue; + } } - } - /* - * Skip the last negative value (if any) or all leading negative zeros. - */ - while (left <= right && Float.floatToRawIntBits(a[left]) < 0) { - ++left; + /* + * Check special cases. + */ + if (run == null) { + if (k == high) { + + /* + * The array is monotonous sequence, + * and therefore already sorted. + */ + return true; + } + + if (k - low < MIN_FIRST_RUN_SIZE) { + + /* + * The first run is too small + * to proceed with scanning. + */ + return false; + } + + run = new int[((size >> 10) | 0x7F) & 0x3FF]; + run[0] = low; + + } else if (a[last - 1] > a[last]) { + + if (count > (k - low) >> MIN_FIRST_RUNS_FACTOR) { + + /* + * The first runs are not long + * enough to continue scanning. + */ + return false; + } + + if (++count == MAX_RUN_CAPACITY) { + + /* + * Array is not highly structured. + */ + return false; + } + + if (count == run.length) { + + /* + * Increase capacity of index array. + */ + run = Arrays.copyOf(run, count << 1); + } + } + run[count] = (last = k); } /* - * Move negative zeros to the beginning of the sub-range. - * - * Partitioning: - * - * +----------------------------------------------------+ - * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) | - * +----------------------------------------------------+ - * ^ ^ ^ - * | | | - * left p k - * - * Invariants: - * - * all in (*, left) < 0.0 - * all in [left, p) == -0.0 - * all in [p, k) == 0.0 - * all in [k, right] >= 0.0 - * - * Pointer k is the first index of ?-part. + * Merge runs of highly structured array. */ - for (int k = left, p = left - 1; ++k <= right; ) { - float ak = a[k]; - if (ak != 0.0f) { - break; - } - if (Float.floatToRawIntBits(ak) < 0) { // ak is -0.0f - a[k] = 0.0f; - a[++p] = -0.0f; + if (count > 1) { + float[] b; int offset = low; + + if (sorter == null || (b = (float[]) sorter.b) == null) { + b = new float[size]; + } else { + offset = sorter.offset; } + mergeRuns(a, b, offset, 1, sorter != null, run, 0, count); } + return true; } /** - * Sorts the specified range of the array. + * Merges the specified runs. * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param work a workspace array (slice) - * @param workBase origin of usable space in work array - * @param workLen usable size of work array + * @param a the source array + * @param b the temporary buffer used in merging + * @param offset the start index in the source, inclusive + * @param aim specifies merging: to source ( > 0), buffer ( < 0) or any ( == 0) + * @param parallel indicates whether merging is performed in parallel + * @param run the start indexes of the runs, inclusive + * @param lo the start index of the first run, inclusive + * @param hi the start index of the last run, inclusive + * @return the destination where runs are merged */ - private static void doSort(float[] a, int left, int right, - float[] work, int workBase, int workLen) { - // Use Quicksort on small arrays - if (right - left < QUICKSORT_THRESHOLD) { - sort(a, left, right, true); - return; + private static float[] mergeRuns(float[] a, float[] b, int offset, + int aim, boolean parallel, int[] run, int lo, int hi) { + + if (hi - lo == 1) { + if (aim >= 0) { + return a; + } + for (int i = run[hi], j = i - offset, low = run[lo]; i > low; + b[--j] = a[--i] + ); + return b; } /* - * Index run[i] is the start of i-th run - * (ascending or descending sequence). + * Split into approximately equal parts. */ - int[] run = new int[MAX_RUN_COUNT + 1]; - int count = 0; run[0] = left; + int mi = lo, rmi = (run[lo] + run[hi]) >>> 1; + while (run[++mi + 1] <= rmi); - // Check if the array is nearly sorted - for (int k = left; k < right; run[count] = k) { - // Equal items in the beginning of the sequence - while (k < right && a[k] == a[k + 1]) - k++; - if (k == right) break; // Sequence finishes with equal items - if (a[k] < a[k + 1]) { // ascending - while (++k <= right && a[k - 1] <= a[k]); - } else if (a[k] > a[k + 1]) { // descending - while (++k <= right && a[k - 1] >= a[k]); - // Transform into an ascending sequence - for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) { - float t = a[lo]; a[lo] = a[hi]; a[hi] = t; - } - } - - // Merge a transformed descending sequence followed by an - // ascending sequence - if (run[count] > left && a[run[count]] >= a[run[count] - 1]) { - count--; - } + /* + * Merge the left and right parts. + */ + float[] a1, a2; - /* - * The array is not highly structured, - * use Quicksort instead of merge sort. - */ - if (++count == MAX_RUN_COUNT) { - sort(a, left, right, true); - return; - } + if (parallel && hi - lo > MIN_RUN_COUNT) { + RunMerger merger = new RunMerger(a, b, offset, 0, run, mi, hi).forkMe(); + a1 = mergeRuns(a, b, offset, -aim, true, run, lo, mi); + a2 = (float[]) merger.getDestination(); + } else { + a1 = mergeRuns(a, b, offset, -aim, false, run, lo, mi); + a2 = mergeRuns(a, b, offset, 0, false, run, mi, hi); } - // These invariants should hold true: - // run[0] = 0 - // run[] = right + 1; (terminator) + float[] dst = a1 == a ? b : a; - if (count == 0) { - // A single equal run - return; - } else if (count == 1 && run[count] > right) { - // Either a single ascending or a transformed descending run. - // Always check that a final run is a proper terminator, otherwise - // we have an unterminated trailing run, to handle downstream. - return; - } - right++; - if (run[count] < right) { - // Corner case: the final run is not a terminator. This may happen - // if a final run is an equals run, or there is a single-element run - // at the end. Fix up by adding a proper terminator at the end. - // Note that we terminate with (right + 1), incremented earlier. - run[++count] = right; - } - - // Determine alternation base for merge - byte odd = 0; - for (int n = 1; (n <<= 1) < count; odd ^= 1); - - // Use or create temporary array b for merging - float[] b; // temp array; alternates with a - int ao, bo; // array offsets from 'left' - int blen = right - left; // space needed for b - if (work == null || workLen < blen || workBase + blen > work.length) { - work = new float[blen]; - workBase = 0; - } - if (odd == 0) { - System.arraycopy(a, left, work, workBase, blen); - b = a; - bo = 0; - a = work; - ao = workBase - left; - } else { - b = work; - ao = 0; - bo = workBase - left; - } - - // Merging - for (int last; count > 1; count = last) { - for (int k = (last = 0) + 2; k <= count; k += 2) { - int hi = run[k], mi = run[k - 1]; - for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { - b[i + bo] = a[p++ + ao]; - } else { - b[i + bo] = a[q++ + ao]; - } - } - run[++last] = hi; - } - if ((count & 1) != 0) { - for (int i = right, lo = run[count - 1]; --i >= lo; - b[i + bo] = a[i + ao] - ); - run[++last] = right; - } - float[] t = a; a = b; b = t; - int o = ao; ao = bo; bo = o; + int k = a1 == a ? run[lo] - offset : run[lo]; + int lo1 = a1 == b ? run[lo] - offset : run[lo]; + int hi1 = a1 == b ? run[mi] - offset : run[mi]; + int lo2 = a2 == b ? run[mi] - offset : run[mi]; + int hi2 = a2 == b ? run[hi] - offset : run[hi]; + + if (parallel) { + new Merger(null, dst, k, a1, lo1, hi1, a2, lo2, hi2).invoke(); + } else { + mergeParts(null, dst, k, a1, lo1, hi1, a2, lo2, hi2); } + return dst; } /** - * Sorts the specified range of the array by Dual-Pivot Quicksort. + * Merges the sorted parts. * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param leftmost indicates if this part is the leftmost in the range + * @param merger parallel context + * @param dst the destination where parts are merged + * @param k the start index of the destination, inclusive + * @param a1 the first part + * @param lo1 the start index of the first part, inclusive + * @param hi1 the end index of the first part, exclusive + * @param a2 the second part + * @param lo2 the start index of the second part, inclusive + * @param hi2 the end index of the second part, exclusive */ - private static void sort(float[] a, int left, int right, boolean leftmost) { - int length = right - left + 1; + private static void mergeParts(Merger merger, float[] dst, int k, + float[] a1, int lo1, int hi1, float[] a2, int lo2, int hi2) { + + if (merger != null && a1 == a2) { + + while (true) { - // Use insertion sort on tiny arrays - if (length < INSERTION_SORT_THRESHOLD) { - if (leftmost) { /* - * Traditional (without sentinel) insertion sort, - * optimized for server VM, is used in case of - * the leftmost part. + * The first part must be larger. */ - for (int i = left, j = i; i < right; j = ++i) { - float ai = a[i + 1]; - while (ai < a[j]) { - a[j + 1] = a[j]; - if (j-- == left) { - break; - } - } - a[j + 1] = ai; + if (hi1 - lo1 < hi2 - lo2) { + int lo = lo1; lo1 = lo2; lo2 = lo; + int hi = hi1; hi1 = hi2; hi2 = hi; } - } else { + /* - * Skip the longest ascending sequence. + * Small parts will be merged sequentially. */ - do { - if (left >= right) { - return; - } - } while (a[++left] >= a[left - 1]); + if (hi1 - lo1 < MIN_PARALLEL_MERGE_PARTS_SIZE) { + break; + } /* - * Every element from adjoining part plays the role - * of sentinel, therefore this allows us to avoid the - * left range check on each iteration. Moreover, we use - * the more optimized algorithm, so called pair insertion - * sort, which is faster (in the context of Quicksort) - * than traditional implementation of insertion sort. + * Find the median of the larger part. */ - for (int k = left; ++left <= right; k = ++left) { - float a1 = a[k], a2 = a[left]; + int mi1 = (lo1 + hi1) >>> 1; + float key = a1[mi1]; + int mi2 = hi2; - if (a1 < a2) { - a2 = a1; a1 = a[left]; - } - while (a1 < a[--k]) { - a[k + 2] = a[k]; - } - a[++k + 1] = a1; + /* + * Partition the smaller part. + */ + for (int loo = lo2; loo < mi2; ) { + int t = (loo + mi2) >>> 1; - while (a2 < a[--k]) { - a[k + 1] = a[k]; + if (key > a2[t]) { + loo = t + 1; + } else { + mi2 = t; } - a[k + 1] = a2; } - float last = a[right]; - while (last < a[--right]) { - a[right + 1] = a[right]; - } - a[right + 1] = last; + int d = mi2 - lo2 + mi1 - lo1; + + /* + * Merge the right sub-parts in parallel. + */ + merger.forkMerger(dst, k + d, a1, mi1, hi1, a2, mi2, hi2); + + /* + * Process the sub-left parts. + */ + hi1 = mi1; + hi2 = mi2; } - return; } - // Inexpensive approximation of length / 7 - int seventh = (length >> 3) + (length >> 6) + 1; + /* + * Merge small parts sequentially. + */ + while (lo1 < hi1 && lo2 < hi2) { + dst[k++] = a1[lo1] < a2[lo2] ? a1[lo1++] : a2[lo2++]; + } + if (dst != a1 || k < lo1) { + while (lo1 < hi1) { + dst[k++] = a1[lo1++]; + } + } + if (dst != a2 || k < lo2) { + while (lo2 < hi2) { + dst[k++] = a2[lo2++]; + } + } + } + +// [double] + /** + * Sorts the specified range of the array using parallel merge + * sort and/or Dual-Pivot Quicksort. + * + * To balance the faster splitting and parallelism of merge sort + * with the faster element partitioning of Quicksort, ranges are + * subdivided in tiers such that, if there is enough parallelism, + * the four-way parallel merge is started, still ensuring enough + * parallelism to process the partitions. + * + * @param a the array to be sorted + * @param parallelism the parallelism level + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(double[] a, int parallelism, int low, int high) { /* - * Sort five evenly spaced elements around (and including) the - * center element in the range. These elements will be used for - * pivot selection as described below. The choice for spacing - * these elements was empirically determined to work well on - * a wide variety of inputs. + * Phase 1. Count the number of negative zero -0.0d, + * turn them into positive zero, and move all NaNs + * to the end of the array. */ - int e3 = (left + right) >>> 1; // The midpoint - int e2 = e3 - seventh; - int e1 = e2 - seventh; - int e4 = e3 + seventh; - int e5 = e4 + seventh; + int numNegativeZero = 0; - // Sort these elements using insertion sort - if (a[e2] < a[e1]) { float t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + for (int k = high; k > low; ) { + double ak = a[--k]; - if (a[e3] < a[e2]) { float t = a[e3]; a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } - } - if (a[e4] < a[e3]) { float t = a[e4]; a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + if (ak == 0.0d && Double.doubleToRawLongBits(ak) < 0) { // ak is -0.0d + numNegativeZero += 1; + a[k] = 0.0d; + } else if (ak != ak) { // ak is NaN + a[k] = a[--high]; + a[high] = ak; } } - if (a[e5] < a[e4]) { float t = a[e5]; a[e5] = a[e4]; a[e4] = t; - if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } - } + + /* + * Phase 2. Sort everything except NaNs, + * which are already in place. + */ + int size = high - low; + + if (parallelism > 0 && size > MIN_PARALLEL_SORT_SIZE) { + int depth = getDepth(parallelism, size >> 12); + double[] b = depth == 0 ? null : new double[size]; + new Sorter(null, a, b, low, size, low, depth).invoke(); + } else { + sort(null, a, 0, low, high); + } + + /* + * Phase 3. Turn positive zero 0.0d + * back into negative zero -0.0d. + */ + if (++numNegativeZero == 1) { + return; + } + + /* + * Find the position one less than + * the index of the first zero. + */ + while (low <= high) { + int middle = (low + high) >>> 1; + + if (a[middle] < 0) { + low = middle + 1; + } else { + high = middle - 1; } } - // Pointers - int less = left; // The index of the first element of center part - int great = right; // The index before the first element of right part + /* + * Replace the required number of 0.0d by -0.0d. + */ + while (--numNegativeZero > 0) { + a[++high] = -0.0d; + } + } + + /** + * Sorts the specified array using the Dual-Pivot Quicksort and/or + * other sorts in special-cases, possibly with parallel partitions. + * + * @param sorter parallel context + * @param a the array to be sorted + * @param bits the combination of recursion depth and bit flag, where + * the right bit "0" indicates that array is the leftmost part + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + static void sort(Sorter sorter, double[] a, int bits, int low, int high) { + while (true) { + int end = high - 1, size = high - low; - if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) { /* - * Use the second and fourth of the five sorted elements as pivots. - * These values are inexpensive approximations of the first and - * second terciles of the array. Note that pivot1 <= pivot2. + * Run mixed insertion sort on small non-leftmost parts. */ - float pivot1 = a[e2]; - float pivot2 = a[e4]; + if (size < MAX_MIXED_INSERTION_SORT_SIZE && (bits & 1) > 0) { + mixedInsertionSort(a, low, high - 3 * ((size >> 5) << 3), high); + return; + } /* - * The first and the last elements to be sorted are moved to the - * locations formerly occupied by the pivots. When partitioning - * is complete, the pivots are swapped back into their final - * positions, and excluded from subsequent sorting. + * Invoke insertion sort on small leftmost part. */ - a[e2] = a[left]; - a[e4] = a[right]; + if (size < MAX_INSERTION_SORT_SIZE) { + insertionSort(a, low, high); + return; + } /* - * Skip elements, which are less or greater than pivot values. + * Check if the whole array or large non-leftmost + * parts are nearly sorted and then merge runs. */ - while (a[++less] < pivot1); - while (a[--great] > pivot2); + if ((bits == 0 || size > MIN_TRY_MERGE_SIZE && (bits & 1) > 0) + && tryMergeRuns(sorter, a, low, size)) { + return; + } /* - * Partitioning: - * - * left part center part right part - * +--------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +--------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (left, less) < pivot1 - * pivot1 <= all in [less, k) <= pivot2 - * all in (great, right) > pivot2 + * Switch to heap sort if execution + * time is becoming quadratic. + */ + if ((bits += 2) > MAX_RECURSION_DEPTH) { + heapSort(a, low, high); + return; + } + + /* + * Use an inexpensive approximation of the golden ratio + * to select five sample elements and determine pivots. + */ + int step = (size >> 3) * 3 + 3; + + /* + * Five elements around (and including) the central element + * will be used for pivot selection as described below. The + * unequal choice of spacing these elements was empirically + * determined to work well on a wide variety of inputs. + */ + int e1 = low + step; + int e5 = end - step; + int e3 = (e1 + e5) >>> 1; + int e2 = (e1 + e3) >>> 1; + int e4 = (e3 + e5) >>> 1; + double a3 = a[e3]; + + /* + * Sort these elements in place by the combination + * of 4-element sorting network and insertion sort. * - * Pointer k is the first index of ?-part. + * 5 ------o-----------o----------- + * | | + * 4 ------|-----o-----o-----o----- + * | | | + * 2 ------o-----|-----o-----o----- + * | | + * 1 ------------o-----o----------- */ - outer: - for (int k = less - 1; ++k <= great; ) { - float ak = a[k]; - if (ak < pivot1) { // Move a[k] to left part - a[k] = a[less]; - /* - * Here and below we use "a[i] = b; i++;" instead - * of "a[i++] = b;" due to performance issue. - */ - a[less] = ak; - ++less; - } else if (ak > pivot2) { // Move a[k] to right part - while (a[great] > pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] < pivot1) { // a[great] <= pivot2 - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // pivot1 <= a[great] <= pivot2 - a[k] = a[great]; - } - /* - * Here and below we use "a[i] = b; i--;" instead - * of "a[i--] = b;" due to performance issue. - */ - a[great] = ak; - --great; + if (a[e5] < a[e2]) { double t = a[e5]; a[e5] = a[e2]; a[e2] = t; } + if (a[e4] < a[e1]) { double t = a[e4]; a[e4] = a[e1]; a[e1] = t; } + if (a[e5] < a[e4]) { double t = a[e5]; a[e5] = a[e4]; a[e4] = t; } + if (a[e2] < a[e1]) { double t = a[e2]; a[e2] = a[e1]; a[e1] = t; } + if (a[e4] < a[e2]) { double t = a[e4]; a[e4] = a[e2]; a[e2] = t; } + + if (a3 < a[e2]) { + if (a3 < a[e1]) { + a[e3] = a[e2]; a[e2] = a[e1]; a[e1] = a3; + } else { + a[e3] = a[e2]; a[e2] = a3; + } + } else if (a3 > a[e4]) { + if (a3 > a[e5]) { + a[e3] = a[e4]; a[e4] = a[e5]; a[e5] = a3; + } else { + a[e3] = a[e4]; a[e4] = a3; } } - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivots - sort(a, left, less - 2, leftmost); - sort(a, great + 2, right, false); + // Pointers + int lower = low; // The index of the last element of the left part + int upper = end; // The index of the first element of the right part /* - * If center part is too large (comprises > 4/7 of the array), - * swap internal pivot values to ends. + * Partitioning with 2 pivots in case of different elements. */ - if (less < e1 && e5 < great) { + if (a[e1] < a[e2] && a[e2] < a[e3] && a[e3] < a[e4] && a[e4] < a[e5]) { + + /* + * Use the first and fifth of the five sorted elements as + * the pivots. These values are inexpensive approximation + * of tertiles. Note, that pivot1 < pivot2. + */ + double pivot1 = a[e1]; + double pivot2 = a[e5]; + /* - * Skip elements, which are equal to pivot values. + * The first and the last elements to be sorted are moved + * to the locations formerly occupied by the pivots. When + * partitioning is completed, the pivots are swapped back + * into their final positions, and excluded from the next + * subsequent sorting. */ - while (a[less] == pivot1) { - ++less; + a[e1] = a[lower]; + a[e5] = a[upper]; + + /* + * Skip elements, which are less or greater than the pivots. + */ + while (a[++lower] < pivot1); + while (a[--upper] > pivot2); + + /* + * Backward 3-interval partitioning + * + * left part central part right part + * +------------------------------------------------------------+ + * | < pivot1 | ? | pivot1 <= && <= pivot2 | > pivot2 | + * +------------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper + * + * Invariants: + * + * all in (low, lower] < pivot1 + * pivot1 <= all in (k, upper) <= pivot2 + * all in [upper, end) > pivot2 + * + * Pointer k is the last index of ?-part + */ + for (int unused = --lower, k = ++upper; --k > lower; ) { + double ak = a[k]; + + if (ak < pivot1) { // Move a[k] to the left side + while (lower < k) { + if (a[++lower] >= pivot1) { + if (a[lower] > pivot2) { + a[k] = a[--upper]; + a[upper] = a[lower]; + } else { + a[k] = a[lower]; + } + a[lower] = ak; + break; + } + } + } else if (ak > pivot2) { // Move a[k] to the right side + a[k] = a[--upper]; + a[upper] = ak; + } } - while (a[great] == pivot2) { - --great; + /* + * Swap the pivots into their final positions. + */ + a[low] = a[lower]; a[lower] = pivot1; + a[end] = a[upper]; a[upper] = pivot2; + + /* + * Sort non-left parts recursively (possibly in parallel), + * excluding known pivots. + */ + if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) { + sorter.forkSorter(bits | 1, lower + 1, upper); + sorter.forkSorter(bits | 1, upper + 1, high); + } else { + sort(sorter, a, bits | 1, lower + 1, upper); + sort(sorter, a, bits | 1, upper + 1, high); } + } else { // Use single pivot in case of many equal elements + + /* + * Use the third of the five sorted elements as the pivot. + * This value is inexpensive approximation of the median. + */ + double pivot = a[e3]; + /* - * Partitioning: + * The first element to be sorted is moved to the + * location formerly occupied by the pivot. After + * completion of partitioning the pivot is swapped + * back into its final position, and excluded from + * the next subsequent sorting. + */ + a[e3] = a[lower]; + + /* + * Traditional 3-way (Dutch National Flag) partitioning * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great + * left part central part right part + * +------------------------------------------------------+ + * | < pivot | ? | == pivot | > pivot | + * +------------------------------------------------------+ + * ^ ^ ^ + * | | | + * lower k upper * * Invariants: * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 + * all in (low, lower] < pivot + * all in (k, upper) == pivot + * all in [upper, end] > pivot * - * Pointer k is the first index of ?-part. + * Pointer k is the last index of ?-part */ - outer: - for (int k = less - 1; ++k <= great; ) { - float ak = a[k]; - if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; + for (int k = ++upper; --k > lower; ) { + double ak = a[k]; + + if (ak != pivot) { + a[k] = pivot; + + if (ak < pivot) { // Move a[k] to the left side + while (a[++lower] < pivot); + + if (a[lower] > pivot) { + a[--upper] = a[lower]; } + a[lower] = ak; + } else { // ak > pivot - Move a[k] to the right side + a[--upper] = ak; } - if (a[great] == pivot1) { // a[great] < pivot2 - a[k] = a[less]; - /* - * Even though a[great] equals to pivot1, the - * assignment a[less] = pivot1 may be incorrect, - * if a[great] and pivot1 are floating-point zeros - * of different signs. Therefore in float and - * double sorting methods we have to use more - * accurate assignment a[less] = a[great]. - */ - a[less] = a[great]; - ++less; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great] = ak; - --great; } } + + /* + * Swap the pivot into its final position. + */ + a[low] = a[lower]; a[lower] = pivot; + + /* + * Sort the right part (possibly in parallel), excluding + * known pivot. All elements from the central part are + * equal and therefore already sorted. + */ + if (size > MIN_PARALLEL_SORT_SIZE && sorter != null) { + sorter.forkSorter(bits | 1, upper, high); + } else { + sort(sorter, a, bits | 1, upper, high); + } } + high = lower; // Iterate along the left part + } + } - // Sort center part recursively - sort(a, less, great, false); + /** + * Sorts the specified range of the array using mixed insertion sort. + * + * Mixed insertion sort is combination of simple insertion sort, + * pin insertion sort and pair insertion sort. + * + * In the context of Dual-Pivot Quicksort, the pivot element + * from the left part plays the role of sentinel, because it + * is less than any elements from the given part. Therefore, + * expensive check of the left range can be skipped on each + * iteration unless it is the leftmost call. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param end the index of the last element for simple insertion sort + * @param high the index of the last element, exclusive, to be sorted + */ + private static void mixedInsertionSort(double[] a, int low, int end, int high) { + if (end == high) { - } else { // Partitioning with one pivot /* - * Use the third of the five sorted elements as pivot. - * This value is inexpensive approximation of the median. + * Invoke simple insertion sort on tiny array. */ - float pivot = a[e3]; + for (int i; ++low < end; ) { + double ai = a[i = low]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + } + } else { /* - * Partitioning degenerates to the traditional 3-way - * (or "Dutch National Flag") schema: - * - * left part center part right part - * +-------------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +-------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: + * Start with pin insertion sort on small part. * - * all in (left, less) < pivot - * all in [less, k) == pivot - * all in (great, right) > pivot - * - * Pointer k is the first index of ?-part. + * Pin insertion sort is extended simple insertion sort. + * The main idea of this sort is to put elements larger + * than an element called pin to the end of array (the + * proper area for such elements). It avoids expensive + * movements of these elements through the whole array. */ - for (int k = less; k <= great; ++k) { - if (a[k] == pivot) { - continue; - } - float ak = a[k]; - if (ak < pivot) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else { // a[k] > pivot - Move a[k] to right part - while (a[great] > pivot) { - --great; + double pin = a[end]; + + for (int i, p = high; ++low < end; ) { + double ai = a[i = low]; + + if (ai < a[i - 1]) { // Small element + + /* + * Insert small element into sorted part. + */ + a[i] = a[--i]; + + while (ai < a[--i]) { + a[i + 1] = a[i]; } - if (a[great] < pivot) { // a[great] <= pivot - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // a[great] == pivot - /* - * Even though a[great] equals to pivot, the - * assignment a[k] = pivot may be incorrect, - * if a[great] and pivot are floating-point - * zeros of different signs. Therefore in float - * and double sorting methods we have to use - * more accurate assignment a[k] = a[great]. - */ - a[k] = a[great]; + a[i + 1] = ai; + + } else if (p > i && ai > pin) { // Large element + + /* + * Find element smaller than pin. + */ + while (a[--p] > pin); + + /* + * Swap it with large element. + */ + if (p > i) { + ai = a[p]; + a[p] = a[i]; } - a[great] = ak; - --great; + + /* + * Insert small element into sorted part. + */ + while (ai < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; } } /* - * Sort left and right parts recursively. - * All elements from center part are equal - * and, therefore, already sorted. + * Continue with pair insertion sort on remain part. */ - sort(a, left, less - 1, leftmost); - sort(a, great + 1, right, false); + for (int i; low < high; ++low) { + double a1 = a[i = low], a2 = a[++low]; + + /* + * Insert two elements per iteration: at first, insert the + * larger element and then insert the smaller element, but + * from the position where the larger element was inserted. + */ + if (a1 > a2) { + + while (a1 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a1; + + while (a2 < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = a2; + + } else if (a1 < a[i - 1]) { + + while (a2 < a[--i]) { + a[i + 2] = a[i]; + } + a[++i + 1] = a2; + + while (a1 < a[--i]) { + a[i + 1] = a[i]; + } + a[i + 1] = a1; + } + } } } /** - * Sorts the specified range of the array using the given - * workspace array slice if possible for merging + * Sorts the specified range of the array using insertion sort. * * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param work a workspace array (slice) - * @param workBase origin of usable space in work array - * @param workLen usable size of work array + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted */ - static void sort(double[] a, int left, int right, - double[] work, int workBase, int workLen) { - /* - * Phase 1: Move NaNs to the end of the array. - */ - while (left <= right && Double.isNaN(a[right])) { - --right; + private static void insertionSort(double[] a, int low, int high) { + for (int i, k = low; ++k < high; ) { + double ai = a[i = k]; + + if (ai < a[i - 1]) { + while (--i >= low && ai < a[i]) { + a[i + 1] = a[i]; + } + a[i + 1] = ai; + } + } + } + + /** + * Sorts the specified range of the array using heap sort. + * + * @param a the array to be sorted + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void heapSort(double[] a, int low, int high) { + for (int k = (low + high) >>> 1; k > low; ) { + pushDown(a, --k, a[k], low, high); + } + while (--high > low) { + double max = a[low]; + pushDown(a, low, a[high], low, high); + a[high] = max; } - for (int k = right; --k >= left; ) { - double ak = a[k]; - if (ak != ak) { // a[k] is NaN - a[k] = a[right]; - a[right] = ak; - --right; + } + + /** + * Pushes specified element down during heap sort. + * + * @param a the given array + * @param p the start index + * @param value the given element + * @param low the index of the first element, inclusive, to be sorted + * @param high the index of the last element, exclusive, to be sorted + */ + private static void pushDown(double[] a, int p, double value, int low, int high) { + for (int k ;; a[p] = a[p = k]) { + k = (p << 1) - low + 2; // Index of the right child + + if (k > high) { + break; + } + if (k == high || a[k] < a[k - 1]) { + --k; + } + if (a[k] <= value) { + break; } } + a[p] = value; + } - /* - * Phase 2: Sort everything except NaNs (which are already in place). - */ - doSort(a, left, right, work, workBase, workLen); + /** + * Tries to sort the specified range of the array. + * + * @param sorter parallel context + * @param a the array to be sorted + * @param low the index of the first element to be sorted + * @param size the array size + * @return true if finally sorted, false otherwise + */ + private static boolean tryMergeRuns(Sorter sorter, double[] a, int low, int size) { /* - * Phase 3: Place negative zeros before positive zeros. + * The run array is constructed only if initial runs are + * long enough to continue, run[i] then holds start index + * of the i-th sequence of elements in non-descending order. */ - int hi = right; + int[] run = null; + int high = low + size; + int count = 1, last = low; /* - * Find the first zero, or first positive, or last negative element. + * Identify all possible runs. */ - while (left < hi) { - int middle = (left + hi) >>> 1; - double middleValue = a[middle]; + for (int k = low + 1; k < high; ) { - if (middleValue < 0.0d) { - left = middle + 1; - } else { - hi = middle; + /* + * Find the end index of the current run. + */ + if (a[k - 1] < a[k]) { + + // Identify ascending sequence + while (++k < high && a[k - 1] <= a[k]); + + } else if (a[k - 1] > a[k]) { + + // Identify descending sequence + while (++k < high && a[k - 1] >= a[k]); + + // Reverse into ascending order + for (int i = last - 1, j = k; ++i < --j && a[i] > a[j]; ) { + double ai = a[i]; a[i] = a[j]; a[j] = ai; + } + } else { // Identify constant sequence + for (double ak = a[k]; ++k < high && ak == a[k]; ); + + if (k < high) { + continue; + } } - } - /* - * Skip the last negative value (if any) or all leading negative zeros. - */ - while (left <= right && Double.doubleToRawLongBits(a[left]) < 0) { - ++left; + /* + * Check special cases. + */ + if (run == null) { + if (k == high) { + + /* + * The array is monotonous sequence, + * and therefore already sorted. + */ + return true; + } + + if (k - low < MIN_FIRST_RUN_SIZE) { + + /* + * The first run is too small + * to proceed with scanning. + */ + return false; + } + + run = new int[((size >> 10) | 0x7F) & 0x3FF]; + run[0] = low; + + } else if (a[last - 1] > a[last]) { + + if (count > (k - low) >> MIN_FIRST_RUNS_FACTOR) { + + /* + * The first runs are not long + * enough to continue scanning. + */ + return false; + } + + if (++count == MAX_RUN_CAPACITY) { + + /* + * Array is not highly structured. + */ + return false; + } + + if (count == run.length) { + + /* + * Increase capacity of index array. + */ + run = Arrays.copyOf(run, count << 1); + } + } + run[count] = (last = k); } /* - * Move negative zeros to the beginning of the sub-range. - * - * Partitioning: - * - * +----------------------------------------------------+ - * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) | - * +----------------------------------------------------+ - * ^ ^ ^ - * | | | - * left p k - * - * Invariants: - * - * all in (*, left) < 0.0 - * all in [left, p) == -0.0 - * all in [p, k) == 0.0 - * all in [k, right] >= 0.0 - * - * Pointer k is the first index of ?-part. + * Merge runs of highly structured array. */ - for (int k = left, p = left - 1; ++k <= right; ) { - double ak = a[k]; - if (ak != 0.0d) { - break; - } - if (Double.doubleToRawLongBits(ak) < 0) { // ak is -0.0d - a[k] = 0.0d; - a[++p] = -0.0d; + if (count > 1) { + double[] b; int offset = low; + + if (sorter == null || (b = (double[]) sorter.b) == null) { + b = new double[size]; + } else { + offset = sorter.offset; } + mergeRuns(a, b, offset, 1, sorter != null, run, 0, count); } + return true; } /** - * Sorts the specified range of the array. + * Merges the specified runs. * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param work a workspace array (slice) - * @param workBase origin of usable space in work array - * @param workLen usable size of work array + * @param a the source array + * @param b the temporary buffer used in merging + * @param offset the start index in the source, inclusive + * @param aim specifies merging: to source ( > 0), buffer ( < 0) or any ( == 0) + * @param parallel indicates whether merging is performed in parallel + * @param run the start indexes of the runs, inclusive + * @param lo the start index of the first run, inclusive + * @param hi the start index of the last run, inclusive + * @return the destination where runs are merged */ - private static void doSort(double[] a, int left, int right, - double[] work, int workBase, int workLen) { - // Use Quicksort on small arrays - if (right - left < QUICKSORT_THRESHOLD) { - sort(a, left, right, true); - return; + private static double[] mergeRuns(double[] a, double[] b, int offset, + int aim, boolean parallel, int[] run, int lo, int hi) { + + if (hi - lo == 1) { + if (aim >= 0) { + return a; + } + for (int i = run[hi], j = i - offset, low = run[lo]; i > low; + b[--j] = a[--i] + ); + return b; } /* - * Index run[i] is the start of i-th run - * (ascending or descending sequence). + * Split into approximately equal parts. */ - int[] run = new int[MAX_RUN_COUNT + 1]; - int count = 0; run[0] = left; + int mi = lo, rmi = (run[lo] + run[hi]) >>> 1; + while (run[++mi + 1] <= rmi); - // Check if the array is nearly sorted - for (int k = left; k < right; run[count] = k) { - // Equal items in the beginning of the sequence - while (k < right && a[k] == a[k + 1]) - k++; - if (k == right) break; // Sequence finishes with equal items - if (a[k] < a[k + 1]) { // ascending - while (++k <= right && a[k - 1] <= a[k]); - } else if (a[k] > a[k + 1]) { // descending - while (++k <= right && a[k - 1] >= a[k]); - // Transform into an ascending sequence - for (int lo = run[count] - 1, hi = k; ++lo < --hi; ) { - double t = a[lo]; a[lo] = a[hi]; a[hi] = t; - } - } - - // Merge a transformed descending sequence followed by an - // ascending sequence - if (run[count] > left && a[run[count]] >= a[run[count] - 1]) { - count--; - } + /* + * Merge the left and right parts. + */ + double[] a1, a2; - /* - * The array is not highly structured, - * use Quicksort instead of merge sort. - */ - if (++count == MAX_RUN_COUNT) { - sort(a, left, right, true); - return; - } + if (parallel && hi - lo > MIN_RUN_COUNT) { + RunMerger merger = new RunMerger(a, b, offset, 0, run, mi, hi).forkMe(); + a1 = mergeRuns(a, b, offset, -aim, true, run, lo, mi); + a2 = (double[]) merger.getDestination(); + } else { + a1 = mergeRuns(a, b, offset, -aim, false, run, lo, mi); + a2 = mergeRuns(a, b, offset, 0, false, run, mi, hi); } - // These invariants should hold true: - // run[0] = 0 - // run[] = right + 1; (terminator) + double[] dst = a1 == a ? b : a; - if (count == 0) { - // A single equal run - return; - } else if (count == 1 && run[count] > right) { - // Either a single ascending or a transformed descending run. - // Always check that a final run is a proper terminator, otherwise - // we have an unterminated trailing run, to handle downstream. - return; - } - right++; - if (run[count] < right) { - // Corner case: the final run is not a terminator. This may happen - // if a final run is an equals run, or there is a single-element run - // at the end. Fix up by adding a proper terminator at the end. - // Note that we terminate with (right + 1), incremented earlier. - run[++count] = right; - } - - // Determine alternation base for merge - byte odd = 0; - for (int n = 1; (n <<= 1) < count; odd ^= 1); - - // Use or create temporary array b for merging - double[] b; // temp array; alternates with a - int ao, bo; // array offsets from 'left' - int blen = right - left; // space needed for b - if (work == null || workLen < blen || workBase + blen > work.length) { - work = new double[blen]; - workBase = 0; - } - if (odd == 0) { - System.arraycopy(a, left, work, workBase, blen); - b = a; - bo = 0; - a = work; - ao = workBase - left; - } else { - b = work; - ao = 0; - bo = workBase - left; - } - - // Merging - for (int last; count > 1; count = last) { - for (int k = (last = 0) + 2; k <= count; k += 2) { - int hi = run[k], mi = run[k - 1]; - for (int i = run[k - 2], p = i, q = mi; i < hi; ++i) { - if (q >= hi || p < mi && a[p + ao] <= a[q + ao]) { - b[i + bo] = a[p++ + ao]; - } else { - b[i + bo] = a[q++ + ao]; - } - } - run[++last] = hi; - } - if ((count & 1) != 0) { - for (int i = right, lo = run[count - 1]; --i >= lo; - b[i + bo] = a[i + ao] - ); - run[++last] = right; - } - double[] t = a; a = b; b = t; - int o = ao; ao = bo; bo = o; + int k = a1 == a ? run[lo] - offset : run[lo]; + int lo1 = a1 == b ? run[lo] - offset : run[lo]; + int hi1 = a1 == b ? run[mi] - offset : run[mi]; + int lo2 = a2 == b ? run[mi] - offset : run[mi]; + int hi2 = a2 == b ? run[hi] - offset : run[hi]; + + if (parallel) { + new Merger(null, dst, k, a1, lo1, hi1, a2, lo2, hi2).invoke(); + } else { + mergeParts(null, dst, k, a1, lo1, hi1, a2, lo2, hi2); } + return dst; } /** - * Sorts the specified range of the array by Dual-Pivot Quicksort. + * Merges the sorted parts. * - * @param a the array to be sorted - * @param left the index of the first element, inclusive, to be sorted - * @param right the index of the last element, inclusive, to be sorted - * @param leftmost indicates if this part is the leftmost in the range + * @param merger parallel context + * @param dst the destination where parts are merged + * @param k the start index of the destination, inclusive + * @param a1 the first part + * @param lo1 the start index of the first part, inclusive + * @param hi1 the end index of the first part, exclusive + * @param a2 the second part + * @param lo2 the start index of the second part, inclusive + * @param hi2 the end index of the second part, exclusive */ - private static void sort(double[] a, int left, int right, boolean leftmost) { - int length = right - left + 1; + private static void mergeParts(Merger merger, double[] dst, int k, + double[] a1, int lo1, int hi1, double[] a2, int lo2, int hi2) { + + if (merger != null && a1 == a2) { + + while (true) { - // Use insertion sort on tiny arrays - if (length < INSERTION_SORT_THRESHOLD) { - if (leftmost) { /* - * Traditional (without sentinel) insertion sort, - * optimized for server VM, is used in case of - * the leftmost part. + * The first part must be larger. */ - for (int i = left, j = i; i < right; j = ++i) { - double ai = a[i + 1]; - while (ai < a[j]) { - a[j + 1] = a[j]; - if (j-- == left) { - break; - } - } - a[j + 1] = ai; + if (hi1 - lo1 < hi2 - lo2) { + int lo = lo1; lo1 = lo2; lo2 = lo; + int hi = hi1; hi1 = hi2; hi2 = hi; } - } else { + /* - * Skip the longest ascending sequence. + * Small parts will be merged sequentially. */ - do { - if (left >= right) { - return; - } - } while (a[++left] >= a[left - 1]); + if (hi1 - lo1 < MIN_PARALLEL_MERGE_PARTS_SIZE) { + break; + } /* - * Every element from adjoining part plays the role - * of sentinel, therefore this allows us to avoid the - * left range check on each iteration. Moreover, we use - * the more optimized algorithm, so called pair insertion - * sort, which is faster (in the context of Quicksort) - * than traditional implementation of insertion sort. + * Find the median of the larger part. */ - for (int k = left; ++left <= right; k = ++left) { - double a1 = a[k], a2 = a[left]; + int mi1 = (lo1 + hi1) >>> 1; + double key = a1[mi1]; + int mi2 = hi2; - if (a1 < a2) { - a2 = a1; a1 = a[left]; - } - while (a1 < a[--k]) { - a[k + 2] = a[k]; - } - a[++k + 1] = a1; + /* + * Partition the smaller part. + */ + for (int loo = lo2; loo < mi2; ) { + int t = (loo + mi2) >>> 1; - while (a2 < a[--k]) { - a[k + 1] = a[k]; + if (key > a2[t]) { + loo = t + 1; + } else { + mi2 = t; } - a[k + 1] = a2; } - double last = a[right]; - while (last < a[--right]) { - a[right + 1] = a[right]; - } - a[right + 1] = last; + int d = mi2 - lo2 + mi1 - lo1; + + /* + * Merge the right sub-parts in parallel. + */ + merger.forkMerger(dst, k + d, a1, mi1, hi1, a2, mi2, hi2); + + /* + * Process the sub-left parts. + */ + hi1 = mi1; + hi2 = mi2; } - return; } - // Inexpensive approximation of length / 7 - int seventh = (length >> 3) + (length >> 6) + 1; - /* - * Sort five evenly spaced elements around (and including) the - * center element in the range. These elements will be used for - * pivot selection as described below. The choice for spacing - * these elements was empirically determined to work well on - * a wide variety of inputs. + * Merge small parts sequentially. */ - int e3 = (left + right) >>> 1; // The midpoint - int e2 = e3 - seventh; - int e1 = e2 - seventh; - int e4 = e3 + seventh; - int e5 = e4 + seventh; - - // Sort these elements using insertion sort - if (a[e2] < a[e1]) { double t = a[e2]; a[e2] = a[e1]; a[e1] = t; } - - if (a[e3] < a[e2]) { double t = a[e3]; a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + while (lo1 < hi1 && lo2 < hi2) { + dst[k++] = a1[lo1] < a2[lo2] ? a1[lo1++] : a2[lo2++]; } - if (a[e4] < a[e3]) { double t = a[e4]; a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } + if (dst != a1 || k < lo1) { + while (lo1 < hi1) { + dst[k++] = a1[lo1++]; } } - if (a[e5] < a[e4]) { double t = a[e5]; a[e5] = a[e4]; a[e4] = t; - if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t; - if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t; - if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; } - } + if (dst != a2 || k < lo2) { + while (lo2 < hi2) { + dst[k++] = a2[lo2++]; } } + } - // Pointers - int less = left; // The index of the first element of center part - int great = right; // The index before the first element of right part - - if (a[e1] != a[e2] && a[e2] != a[e3] && a[e3] != a[e4] && a[e4] != a[e5]) { - /* - * Use the second and fourth of the five sorted elements as pivots. - * These values are inexpensive approximations of the first and - * second terciles of the array. Note that pivot1 <= pivot2. - */ - double pivot1 = a[e2]; - double pivot2 = a[e4]; +// [class] - /* - * The first and the last elements to be sorted are moved to the - * locations formerly occupied by the pivots. When partitioning - * is complete, the pivots are swapped back into their final - * positions, and excluded from subsequent sorting. - */ - a[e2] = a[left]; - a[e4] = a[right]; + /** + * This class implements parallel sorting. + */ + private static final class Sorter extends CountedCompleter { + private static final long serialVersionUID = 20180818L; + private final Object a, b; + private final int low, size, offset, depth; + + private Sorter(CountedCompleter parent, + Object a, Object b, int low, int size, int offset, int depth) { + super(parent); + this.a = a; + this.b = b; + this.low = low; + this.size = size; + this.offset = offset; + this.depth = depth; + } + + @Override + public final void compute() { + if (depth < 0) { + setPendingCount(2); + int half = size >> 1; + new Sorter(this, b, a, low, half, offset, depth + 1).fork(); + new Sorter(this, b, a, low + half, size - half, offset, depth + 1).compute(); + } else { + if (a instanceof int[]) { + sort(this, (int[]) a, depth, low, low + size); + } else if (a instanceof long[]) { + sort(this, (long[]) a, depth, low, low + size); + } else if (a instanceof float[]) { + sort(this, (float[]) a, depth, low, low + size); + } else if (a instanceof double[]) { + sort(this, (double[]) a, depth, low, low + size); + } else { + throw new IllegalArgumentException( + "Unknown type of array: " + a.getClass().getName()); + } + } + tryComplete(); + } + + @Override + public final void onCompletion(CountedCompleter caller) { + if (depth < 0) { + int mi = low + (size >> 1); + boolean src = (depth & 1) == 0; + + new Merger(null, + a, + src ? low : low - offset, + b, + src ? low - offset : low, + src ? mi - offset : mi, + b, + src ? mi - offset : mi, + src ? low + size - offset : low + size + ).invoke(); + } + } - /* - * Skip elements, which are less or greater than pivot values. - */ - while (a[++less] < pivot1); - while (a[--great] > pivot2); + private void forkSorter(int depth, int low, int high) { + addToPendingCount(1); + Object a = this.a; // Use local variable for performance + new Sorter(this, a, b, low, high - low, offset, depth).fork(); + } + } - /* - * Partitioning: - * - * left part center part right part - * +--------------------------------------------------------------+ - * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 | - * +--------------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (left, less) < pivot1 - * pivot1 <= all in [less, k) <= pivot2 - * all in (great, right) > pivot2 - * - * Pointer k is the first index of ?-part. - */ - outer: - for (int k = less - 1; ++k <= great; ) { - double ak = a[k]; - if (ak < pivot1) { // Move a[k] to left part - a[k] = a[less]; - /* - * Here and below we use "a[i] = b; i++;" instead - * of "a[i++] = b;" due to performance issue. - */ - a[less] = ak; - ++less; - } else if (ak > pivot2) { // Move a[k] to right part - while (a[great] > pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] < pivot1) { // a[great] <= pivot2 - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // pivot1 <= a[great] <= pivot2 - a[k] = a[great]; - } - /* - * Here and below we use "a[i] = b; i--;" instead - * of "a[i--] = b;" due to performance issue. - */ - a[great] = ak; - --great; - } + /** + * This class implements parallel merging. + */ + private static final class Merger extends CountedCompleter { + private static final long serialVersionUID = 20180818L; + private final Object dst, a1, a2; + private final int k, lo1, hi1, lo2, hi2; + + private Merger(CountedCompleter parent, Object dst, int k, + Object a1, int lo1, int hi1, Object a2, int lo2, int hi2) { + super(parent); + this.dst = dst; + this.k = k; + this.a1 = a1; + this.lo1 = lo1; + this.hi1 = hi1; + this.a2 = a2; + this.lo2 = lo2; + this.hi2 = hi2; + } + + @Override + public final void compute() { + if (dst instanceof int[]) { + mergeParts(this, (int[]) dst, k, + (int[]) a1, lo1, hi1, (int[]) a2, lo2, hi2); + } else if (dst instanceof long[]) { + mergeParts(this, (long[]) dst, k, + (long[]) a1, lo1, hi1, (long[]) a2, lo2, hi2); + } else if (dst instanceof float[]) { + mergeParts(this, (float[]) dst, k, + (float[]) a1, lo1, hi1, (float[]) a2, lo2, hi2); + } else if (dst instanceof double[]) { + mergeParts(this, (double[]) dst, k, + (double[]) a1, lo1, hi1, (double[]) a2, lo2, hi2); + } else { + throw new IllegalArgumentException( + "Unknown type of array: " + dst.getClass().getName()); } + propagateCompletion(); + } - // Swap pivots into their final positions - a[left] = a[less - 1]; a[less - 1] = pivot1; - a[right] = a[great + 1]; a[great + 1] = pivot2; - - // Sort left and right parts recursively, excluding known pivots - sort(a, left, less - 2, leftmost); - sort(a, great + 2, right, false); + private void forkMerger(Object dst, int k, + Object a1, int lo1, int hi1, Object a2, int lo2, int hi2) { + addToPendingCount(1); + new Merger(this, dst, k, a1, lo1, hi1, a2, lo2, hi2).fork(); + } + } - /* - * If center part is too large (comprises > 4/7 of the array), - * swap internal pivot values to ends. - */ - if (less < e1 && e5 < great) { - /* - * Skip elements, which are equal to pivot values. - */ - while (a[less] == pivot1) { - ++less; - } + /** + * This class implements parallel merging of runs. + */ + private static final class RunMerger extends RecursiveTask { + private static final long serialVersionUID = 20180818L; + private final Object a, b; + private final int[] run; + private final int offset, aim, lo, hi; - while (a[great] == pivot2) { - --great; - } + private RunMerger(Object a, Object b, int offset, + int aim, int[] run, int lo, int hi) { + this.a = a; + this.b = b; + this.offset = offset; + this.aim = aim; + this.run = run; + this.lo = lo; + this.hi = hi; + } - /* - * Partitioning: - * - * left part center part right part - * +----------------------------------------------------------+ - * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 | - * +----------------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (*, less) == pivot1 - * pivot1 < all in [less, k) < pivot2 - * all in (great, *) == pivot2 - * - * Pointer k is the first index of ?-part. - */ - outer: - for (int k = less - 1; ++k <= great; ) { - double ak = a[k]; - if (ak == pivot1) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else if (ak == pivot2) { // Move a[k] to right part - while (a[great] == pivot2) { - if (great-- == k) { - break outer; - } - } - if (a[great] == pivot1) { // a[great] < pivot2 - a[k] = a[less]; - /* - * Even though a[great] equals to pivot1, the - * assignment a[less] = pivot1 may be incorrect, - * if a[great] and pivot1 are floating-point zeros - * of different signs. Therefore in float and - * double sorting methods we have to use more - * accurate assignment a[less] = a[great]. - */ - a[less] = a[great]; - ++less; - } else { // pivot1 < a[great] < pivot2 - a[k] = a[great]; - } - a[great] = ak; - --great; - } - } + @Override + protected final Object compute() { + if (a instanceof int[]) { + return mergeRuns((int[]) a, (int[]) b, offset, aim, true, run, lo, hi); } - - // Sort center part recursively - sort(a, less, great, false); - - } else { // Partitioning with one pivot - /* - * Use the third of the five sorted elements as pivot. - * This value is inexpensive approximation of the median. - */ - double pivot = a[e3]; - - /* - * Partitioning degenerates to the traditional 3-way - * (or "Dutch National Flag") schema: - * - * left part center part right part - * +-------------------------------------------------+ - * | < pivot | == pivot | ? | > pivot | - * +-------------------------------------------------+ - * ^ ^ ^ - * | | | - * less k great - * - * Invariants: - * - * all in (left, less) < pivot - * all in [less, k) == pivot - * all in (great, right) > pivot - * - * Pointer k is the first index of ?-part. - */ - for (int k = less; k <= great; ++k) { - if (a[k] == pivot) { - continue; - } - double ak = a[k]; - if (ak < pivot) { // Move a[k] to left part - a[k] = a[less]; - a[less] = ak; - ++less; - } else { // a[k] > pivot - Move a[k] to right part - while (a[great] > pivot) { - --great; - } - if (a[great] < pivot) { // a[great] <= pivot - a[k] = a[less]; - a[less] = a[great]; - ++less; - } else { // a[great] == pivot - /* - * Even though a[great] equals to pivot, the - * assignment a[k] = pivot may be incorrect, - * if a[great] and pivot are floating-point - * zeros of different signs. Therefore in float - * and double sorting methods we have to use - * more accurate assignment a[k] = a[great]. - */ - a[k] = a[great]; - } - a[great] = ak; - --great; - } + if (a instanceof long[]) { + return mergeRuns((long[]) a, (long[]) b, offset, aim, true, run, lo, hi); + } + if (a instanceof float[]) { + return mergeRuns((float[]) a, (float[]) b, offset, aim, true, run, lo, hi); } + if (a instanceof double[]) { + return mergeRuns((double[]) a, (double[]) b, offset, aim, true, run, lo, hi); + } + throw new IllegalArgumentException( + "Unknown type of array: " + a.getClass().getName()); + } - /* - * Sort left and right parts recursively. - * All elements from center part are equal - * and, therefore, already sorted. - */ - sort(a, left, less - 1, leftmost); - sort(a, great + 1, right, false); + private RunMerger forkMe() { + fork(); + return this; + } + + private Object getDestination() { + join(); + return getRawResult(); } } } --- old/test/jdk/java/util/Arrays/Sorting.java 2019-07-17 17:04:37.820314297 +0200 +++ new/test/jdk/java/util/Arrays/Sorting.java 2019-07-17 17:04:37.512314302 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -8,7 +8,7 @@ * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * @@ -23,213 +23,301 @@ /* * @test - * @bug 6880672 6896573 6899694 6976036 7013585 7018258 - * @summary Exercise Arrays.sort + * @compile/module=java.base java/util/SortingHelper.java + * @bug 6880672 6896573 6899694 6976036 7013585 7018258 8003981 8226297 * @build Sorting * @run main Sorting -shortrun + * @summary Exercise Arrays.sort, Arrays.parallelSort * * @author Vladimir Yaroslavskiy * @author Jon Bentley * @author Josh Bloch */ +import java.io.PrintStream; import java.util.Arrays; +import java.util.Comparator; import java.util.Random; -import java.io.PrintStream; +import java.util.SortingHelper; public class Sorting { + private static final PrintStream out = System.out; private static final PrintStream err = System.err; // Array lengths used in a long run (default) private static final int[] LONG_RUN_LENGTHS = { - 1, 2, 3, 5, 8, 13, 21, 34, 55, 100, 1000, 10000, 100000, 1000000 }; + 1, 2, 3, 5, 8, 13, 21, 34, 55, 88, 100, 1000, 10000, 100000, 1000000 }; // Array lengths used in a short run private static final int[] SHORT_RUN_LENGTHS = { - 1, 2, 3, 21, 55, 1000, 10000 }; + 1, 2, 3, 21, 55, 1000, 10000, 17000 }; // Random initial values used in a long run (default) - private static final long[] LONG_RUN_RANDOMS = { 666, 0xC0FFEE, 999 }; + private static final long[] LONG_RUN_RANDOMS = { 0xBABA, 0xDEDA, 0xC0FFEE }; // Random initial values used in a short run - private static final long[] SHORT_RUN_RANDOMS = { 666 }; + private static final long[] SHORT_RUN_RANDOMS = { 0xC0FFEE }; + + // Constants used in subarray sorting + private static final int A380 = 0xA380; + private static final int B747 = 0xB747; + + private static SortingHelper sortingHelper; + private static String name; public static void main(String[] args) { boolean shortRun = args.length > 0 && args[0].equals("-shortrun"); long start = System.currentTimeMillis(); + // Check Dual-Pivot Quicksort + sortingHelper = SortingHelper.getDualPivotQuicksortHelper(); + if (shortRun) { - testAndCheck(SHORT_RUN_LENGTHS, SHORT_RUN_RANDOMS); + testQuicksort(SHORT_RUN_LENGTHS, SHORT_RUN_RANDOMS); } else { - testAndCheck(LONG_RUN_LENGTHS, LONG_RUN_RANDOMS); + testQuicksort(LONG_RUN_LENGTHS, LONG_RUN_RANDOMS); + } + + // Check Parallel sort + sortingHelper = SortingHelper.getParallelSortHelper(); + + if (shortRun) { + testQuicksort(SHORT_RUN_LENGTHS, SHORT_RUN_RANDOMS); + } else { + testQuicksort(LONG_RUN_LENGTHS, LONG_RUN_RANDOMS); } - long end = System.currentTimeMillis(); - out.format("PASSED in %d sec.\n", Math.round((end - start) / 1E3)); + // Check Heap sort + sortingHelper = SortingHelper.getHeapSortHelper(); + testHeapSort(shortRun ? SHORT_RUN_RANDOMS : LONG_RUN_RANDOMS); + + // Check Object sort + if (shortRun) { + testObject(SHORT_RUN_LENGTHS, SHORT_RUN_RANDOMS); + } else { + testObject(LONG_RUN_LENGTHS, LONG_RUN_RANDOMS); + } + + long end = System.currentTimeMillis(); + out.format("\nPASSED in %d sec.\n", (end - start) / 1000); } - private static void testAndCheck(int[] lengths, long[] randoms) { + private static void testQuicksort(int[] lengths, long[] randoms) { testEmptyAndNullIntArray(); testEmptyAndNullLongArray(); - testEmptyAndNullShortArray(); - testEmptyAndNullCharArray(); testEmptyAndNullByteArray(); + testEmptyAndNullCharArray(); + testEmptyAndNullShortArray(); testEmptyAndNullFloatArray(); testEmptyAndNullDoubleArray(); for (int length : lengths) { - testMergeSort(length); + testMergingSort(length); testAndCheckRange(length); testAndCheckSubArray(length); } - for (long seed : randoms) { + + for (long random : randoms) { for (int length : lengths) { - testAndCheckWithInsertionSort(length, new MyRandom(seed)); - testAndCheckWithCheckSum(length, new MyRandom(seed)); - testAndCheckWithScrambling(length, new MyRandom(seed)); - testAndCheckFloat(length, new MyRandom(seed)); - testAndCheckDouble(length, new MyRandom(seed)); - testStable(length, new MyRandom(seed)); + testAndCheckWithInsertionSort(length, new TestRandom(random)); + testAndCheckWithCheckSum(length, new TestRandom(random)); + testAndCheckWithScrambling(length, new TestRandom(random)); + testFloatNegativeZero(length, new TestRandom(random)); + testAndCheckFloat(length, new TestRandom(random)); + testDoubleNegativeZero(length, new TestRandom(random)); + testAndCheckDouble(length, new TestRandom(random)); } } } + private static void testHeapSort(long[] randoms) { + for (long random : randoms) { + for (int length : SHORT_RUN_LENGTHS) { + testAndCheckWithCheckSum(length, new TestRandom(random)); + testAndCheckWithScrambling(length, new TestRandom(random)); + } + } + } + + private static void testObject(int[] lengths, long[] randoms) { + for (long random : randoms) { + for (int length : lengths) { + testObject(length, new TestRandom(random)); + testParallelObject(length, new TestRandom(random)); + } + } + } + + private static void testObject(int length, TestRandom random) { + name = "sorting is stable"; + Pair[] a = build(length, random); + out.println("[Object Sorting] 'stable' random = " + + random.getSeed() + ", length = " + length); + Arrays.sort(a); + checkSorted(a); + checkStable(a); + + a = build(length, random); + out.println("[Object Sorting] 'comparator' " + + " random = " + random.getSeed() + ", length = " + length); + Arrays.sort(a, pairComparator); + checkSorted(a); + checkStable(a); + } + + private static void testParallelObject(int length, TestRandom random) { + name = "parallel sorting is stable"; + Pair[] a = build(length, random); + out.println("[Object Sorting] 'parallel stable' random = " + + random.getSeed() + ", length = " + length); + Arrays.parallelSort(a); + checkSorted(a); + checkStable(a); + + a = build(length, random); + out.println("[Object Sorting] 'parallel comparator'" + + " random = " + random.getSeed() + ", length = " + length); + Arrays.parallelSort(a, pairComparator); + checkSorted(a); + checkStable(a); + } + private static void testEmptyAndNullIntArray() { - ourDescription = "Check empty and null array"; - Arrays.sort(new int[] {}); - Arrays.sort(new int[] {}, 0, 0); + name = "Empty and null array"; + sortingHelper.sort(new int[] {}); + sortingHelper.sort(new int[] {}, 0, 0); try { - Arrays.sort((int[]) null); + sortingHelper.sort((int[]) null); } catch (NullPointerException expected) { try { - Arrays.sort((int[]) null, 0, 0); + sortingHelper.sort((int[]) null, 0, 0); } catch (NullPointerException expected2) { return; } - failed("Arrays.sort(int[],fromIndex,toIndex) shouldn't " + + fail(sortingHelper + "(int[],fromIndex,toIndex) shouldn't " + "catch null array"); } - failed("Arrays.sort(int[]) shouldn't catch null array"); + fail(sortingHelper + "(int[]) shouldn't catch null array"); } private static void testEmptyAndNullLongArray() { - ourDescription = "Check empty and null array"; - Arrays.sort(new long[] {}); - Arrays.sort(new long[] {}, 0, 0); + name = "Empty and null array"; + sortingHelper.sort(new long[] {}); + sortingHelper.sort(new long[] {}, 0, 0); try { - Arrays.sort((long[]) null); + sortingHelper.sort((long[]) null); } catch (NullPointerException expected) { try { - Arrays.sort((long[]) null, 0, 0); + sortingHelper.sort((long[]) null, 0, 0); } catch (NullPointerException expected2) { return; } - failed("Arrays.sort(long[],fromIndex,toIndex) shouldn't " + + fail(sortingHelper + "(long[],fromIndex,toIndex) shouldn't " + "catch null array"); } - failed("Arrays.sort(long[]) shouldn't catch null array"); + fail(sortingHelper + "(long[]) shouldn't catch null array"); } - private static void testEmptyAndNullShortArray() { - ourDescription = "Check empty and null array"; - Arrays.sort(new short[] {}); - Arrays.sort(new short[] {}, 0, 0); + private static void testEmptyAndNullByteArray() { + name = "Empty and null array"; + sortingHelper.sort(new byte[] {}); + sortingHelper.sort(new byte[] {}, 0, 0); try { - Arrays.sort((short[]) null); + sortingHelper.sort((byte[]) null); } catch (NullPointerException expected) { try { - Arrays.sort((short[]) null, 0, 0); + sortingHelper.sort((byte[]) null, 0, 0); } catch (NullPointerException expected2) { return; } - failed("Arrays.sort(short[],fromIndex,toIndex) shouldn't " + + fail(sortingHelper + "(byte[],fromIndex,toIndex) shouldn't " + "catch null array"); } - failed("Arrays.sort(short[]) shouldn't catch null array"); + fail(sortingHelper + "(byte[]) shouldn't catch null array"); } private static void testEmptyAndNullCharArray() { - ourDescription = "Check empty and null array"; - Arrays.sort(new char[] {}); - Arrays.sort(new char[] {}, 0, 0); + name = "Empty and null array"; + sortingHelper.sort(new char[] {}); + sortingHelper.sort(new char[] {}, 0, 0); try { - Arrays.sort((char[]) null); + sortingHelper.sort((char[]) null); } catch (NullPointerException expected) { try { - Arrays.sort((char[]) null, 0, 0); + sortingHelper.sort((char[]) null, 0, 0); } catch (NullPointerException expected2) { return; } - failed("Arrays.sort(char[],fromIndex,toIndex) shouldn't " + + fail(sortingHelper + "(char[],fromIndex,toIndex) shouldn't " + "catch null array"); } - failed("Arrays.sort(char[]) shouldn't catch null array"); + fail(sortingHelper + "(char[]) shouldn't catch null array"); } - private static void testEmptyAndNullByteArray() { - ourDescription = "Check empty and null array"; - Arrays.sort(new byte[] {}); - Arrays.sort(new byte[] {}, 0, 0); + private static void testEmptyAndNullShortArray() { + name = "Empty and null array"; + sortingHelper.sort(new short[] {}); + sortingHelper.sort(new short[] {}, 0, 0); try { - Arrays.sort((byte[]) null); + sortingHelper.sort((short[]) null); } catch (NullPointerException expected) { try { - Arrays.sort((byte[]) null, 0, 0); + sortingHelper.sort((short[]) null, 0, 0); } catch (NullPointerException expected2) { return; } - failed("Arrays.sort(byte[],fromIndex,toIndex) shouldn't " + + fail(sortingHelper + "(short[],fromIndex,toIndex) shouldn't " + "catch null array"); } - failed("Arrays.sort(byte[]) shouldn't catch null array"); + fail(sortingHelper + "(short[]) shouldn't catch null array"); } private static void testEmptyAndNullFloatArray() { - ourDescription = "Check empty and null array"; - Arrays.sort(new float[] {}); - Arrays.sort(new float[] {}, 0, 0); + name = "Empty and null array"; + sortingHelper.sort(new float[] {}); + sortingHelper.sort(new float[] {}, 0, 0); try { - Arrays.sort((float[]) null); + sortingHelper.sort((float[]) null); } catch (NullPointerException expected) { try { - Arrays.sort((float[]) null, 0, 0); + sortingHelper.sort((float[]) null, 0, 0); } catch (NullPointerException expected2) { return; } - failed("Arrays.sort(float[],fromIndex,toIndex) shouldn't " + + fail(sortingHelper + "(float[],fromIndex,toIndex) shouldn't " + "catch null array"); } - failed("Arrays.sort(float[]) shouldn't catch null array"); + fail(sortingHelper + "(float[]) shouldn't catch null array"); } private static void testEmptyAndNullDoubleArray() { - ourDescription = "Check empty and null array"; - Arrays.sort(new double[] {}); - Arrays.sort(new double[] {}, 0, 0); + name = "Empty and null array"; + sortingHelper.sort(new double[] {}); + sortingHelper.sort(new double[] {}, 0, 0); try { - Arrays.sort((double[]) null); + sortingHelper.sort((double[]) null); } catch (NullPointerException expected) { try { - Arrays.sort((double[]) null, 0, 0); + sortingHelper.sort((double[]) null, 0, 0); } catch (NullPointerException expected2) { return; } - failed("Arrays.sort(double[],fromIndex,toIndex) shouldn't " + + fail(sortingHelper + "(double[],fromIndex,toIndex) shouldn't " + "catch null array"); } - failed("Arrays.sort(double[]) shouldn't catch null array"); + fail(sortingHelper + "(double[]) shouldn't catch null array"); } private static void testAndCheckSubArray(int length) { - ourDescription = "Check sorting of subarray"; + name = "Sorting of subarray"; int[] golden = new int[length]; boolean newLine = false; @@ -238,16 +326,15 @@ int fromIndex = m; int toIndex = length - m; - prepareSubArray(golden, fromIndex, toIndex, m); + prepareSubArray(golden, fromIndex, toIndex); int[] test = golden.clone(); for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'subarray': " + converter + - " length = " + length + ", m = " + m); - Object convertedGolden = converter.convert(golden); + out.println(getTestName() + converter + + " length = " + length + ", m = " + m); Object convertedTest = converter.convert(test); sortSubArray(convertedTest, fromIndex, toIndex); - checkSubArray(convertedTest, fromIndex, toIndex, m); + checkSubArray(convertedTest, fromIndex, toIndex); } } if (newLine) { @@ -256,16 +343,16 @@ } private static void testAndCheckRange(int length) { - ourDescription = "Check range check"; + name = "Range check"; int[] golden = new int[length]; for (int m = 1; m < 2 * length; m *= 2) { - for (int i = 1; i <= length; i++) { + for (int i = 1; i <= length; ++i) { golden[i - 1] = i % m + m % i; } for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'range': " + converter + - ", length = " + length + ", m = " + m); + out.println(getTestName() + converter + + " length = " + length + ", m = " + m); Object convertedGolden = converter.convert(golden); checkRange(convertedGolden, m); } @@ -273,22 +360,10 @@ out.println(); } - private static void testStable(int length, MyRandom random) { - ourDescription = "Check if sorting is stable"; - Pair[] a = build(length, random); - - out.println("Test 'stable': " + "random = " + random.getSeed() + - ", length = " + length); - Arrays.sort(a); - checkSorted(a); - checkStable(a); - out.println(); - } - private static void checkSorted(Pair[] a) { - for (int i = 0; i < a.length - 1; i++) { + for (int i = 0; i < a.length - 1; ++i) { if (a[i].getKey() > a[i + 1].getKey()) { - failedSort(i, "" + a[i].getKey(), "" + a[i + 1].getKey()); + failSort(i, "" + a[i].getKey(), "" + a[i + 1].getKey()); } } } @@ -305,12 +380,12 @@ int value4 = a[i++].getValue(); if (!(key1 == key2 && key2 == key3 && key3 == key4)) { - failed("On position " + i + " keys are different " + + fail("On position " + i + " keys are different " + key1 + ", " + key2 + ", " + key3 + ", " + key4); } if (!(value1 < value2 && value2 < value3 && value3 < value4)) { - failed("Sorting is not stable at position " + i + - ". Second values have been changed: " + value1 + ", " + + fail("Sorting is not stable at position " + i + + ". Second values have been changed: " + value1 + ", " + value2 + ", " + value3 + ", " + value4); } } @@ -329,45 +404,48 @@ return a; } - private static final class Pair implements Comparable { - Pair(int key, int value) { - myKey = key; - myValue = value; + private static Comparator pairComparator = new Comparator() { + + @Override + public int compare(Pair p1, Pair p2) { + return p1.compareTo(p2); + } + }; + + private static class Pair implements Comparable { + + private Pair(int key, int value) { + this.key = key; + this.value = value; } int getKey() { - return myKey; + return key; } int getValue() { - return myValue; + return value; } + @Override public int compareTo(Pair pair) { - if (myKey < pair.myKey) { - return -1; - } - if (myKey > pair.myKey) { - return 1; - } - return 0; + return Integer.compare(key, pair.key); } @Override public String toString() { - return "(" + myKey + ", " + myValue + ")"; + return "(" + key + ", " + value + ")"; } - private int myKey; - private int myValue; + private int key; + private int value; } - - private static void testAndCheckWithInsertionSort(int length, MyRandom random) { + private static void testAndCheckWithInsertionSort(int length, TestRandom random) { if (length > 1000) { return; } - ourDescription = "Check sorting with insertion sort"; + name = "Sorting with insertion sort"; int[] golden = new int[length]; for (int m = 1; m < 2 * length; m *= 2) { @@ -376,10 +454,9 @@ int[] test = golden.clone(); for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'insertion sort': " + converter + - " " + builder + "random = " + random.getSeed() + - ", length = " + length + ", m = " + m); - Object convertedGolden = converter.convert(golden); + out.println(getTestName() + converter + " " + + builder + "random = " + random.getSeed() + ", length = " + + length + ", m = " + m); Object convertedTest1 = converter.convert(test); Object convertedTest2 = converter.convert(test); sort(convertedTest1); @@ -391,22 +468,21 @@ out.println(); } - private static void testMergeSort(int length) { + private static void testMergingSort(int length) { if (length < 1000) { return; } - ourDescription = "Check merge sorting"; + name = "Merging sort"; int[] golden = new int[length]; - int period = 67; // java.util.DualPivotQuicksort.MAX_RUN_COUNT + final int PERIOD = 50; - for (int m = period - 2; m <= period + 2; m++) { - for (MergeBuilder builder : MergeBuilder.values()) { + for (int m = PERIOD - 2; m <= PERIOD + 2; ++m) { + for (MergingBuilder builder : MergingBuilder.values()) { builder.build(golden, m); - int[] test = golden.clone(); for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'merge sort': " + converter + " " + - builder + "length = " + length + ", m = " + m); + out.println(getTestName() + converter + + " " + builder + "length = " + length + ", m = " + m); Object convertedGolden = converter.convert(golden); sort(convertedGolden); checkSorted(convertedGolden); @@ -416,8 +492,8 @@ out.println(); } - private static void testAndCheckWithCheckSum(int length, MyRandom random) { - ourDescription = "Check sorting with check sum"; + private static void testAndCheckWithCheckSum(int length, TestRandom random) { + name = "Sorting with check sum"; int[] golden = new int[length]; for (int m = 1; m < 2 * length; m *= 2) { @@ -426,7 +502,7 @@ int[] test = golden.clone(); for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'check sum': " + converter + + out.println(getTestName() + converter + " " + builder + "random = " + random.getSeed() + ", length = " + length + ", m = " + m); Object convertedGolden = converter.convert(golden); @@ -439,11 +515,11 @@ out.println(); } - private static void testAndCheckWithScrambling(int length, MyRandom random) { - ourDescription = "Check sorting with scrambling"; + private static void testAndCheckWithScrambling(int length, TestRandom random) { + name = "Sorting with scrambling"; int[] golden = new int[length]; - for (int m = 1; m <= 7; m++) { + for (int m = 1; m < 8; ++m) { if (m > length) { break; } @@ -453,9 +529,9 @@ scramble(test, random); for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'scrambling': " + converter + - " " + builder + "random = " + random.getSeed() + - ", length = " + length + ", m = " + m); + out.println(getTestName() + converter + + " " + builder + "random = " + random.getSeed() + + ", length = " + length + ", m = " + m); Object convertedGolden = converter.convert(golden); Object convertedTest = converter.convert(test); sort(convertedTest); @@ -466,27 +542,25 @@ out.println(); } - private static void testAndCheckFloat(int length, MyRandom random) { - ourDescription = "Check float sorting"; + private static void testAndCheckFloat(int length, TestRandom random) { + name = "Float sorting"; float[] golden = new float[length]; - final int MAX = 10; boolean newLine = false; + final int MAX = 13; - for (int a = 0; a <= MAX; a++) { - for (int g = 0; g <= MAX; g++) { - for (int z = 0; z <= MAX; z++) { - for (int n = 0; n <= MAX; n++) { - for (int p = 0; p <= MAX; p++) { - if (a + g + z + n + p > length) { - continue; - } - if (a + g + z + n + p < length) { + for (int a = 0; a < MAX; ++a) { + for (int g = 0; g < MAX; ++g) { + for (int z = 0; z < MAX; ++z) { + for (int n = 0; n < MAX; ++n) { + for (int p = 0; p < MAX; ++p) { + if (a + g + z + n + p != length) { continue; } for (FloatBuilder builder : FloatBuilder.values()) { - out.println("Test 'float': random = " + random.getSeed() + - ", length = " + length + ", a = " + a + ", g = " + - g + ", z = " + z + ", n = " + n + ", p = " + p); + out.println(getTestName() + "random = " + + random.getSeed() + " length = " + length + + ", a = " + a + ", g = " + g + ", z = " + z + + ", n = " + n + ", p = " + p); builder.build(golden, a, g, z, n, p, random); float[] test = golden.clone(); scramble(test, random); @@ -502,29 +576,59 @@ if (newLine) { out.println(); } + + for (int m = 13; m > 4; --m) { + int t = length / m; + int g = t, z = t, n = t, p = t; + int a = length - g - z - n - p; + + for (FloatBuilder builder : FloatBuilder.values()) { + out.println(getTestName() + "random = " + + random.getSeed() + " length = " + length + + ", a = " + a + ", g = " + g + ", z = " + z + + ", n = " + n + ", p = " + p); + builder.build(golden, a, g, z, n, p, random); + float[] test = golden.clone(); + scramble(test, random); + sort(test); + compare(test, golden, a, n, g); + } + } + out.println(); } - private static void testAndCheckDouble(int length, MyRandom random) { - ourDescription = "Check double sorting"; + private static void testFloatNegativeZero(int length, TestRandom random) { + name = "Float -0.0"; + out.println(getTestName() + "random = " + random.getSeed() + " length = " + length); + float[] a = new float[length]; + + for (int i = 0; i < length; ++i) { + a[i] = random.nextBoolean() ? -0.0f : 0.0f; + } + sort(a); + checkNegativeZero(a); + out.println(); + } + + private static void testAndCheckDouble(int length, TestRandom random) { + name = "Double sorting"; double[] golden = new double[length]; - final int MAX = 10; boolean newLine = false; + final int MAX = 13; - for (int a = 0; a <= MAX; a++) { - for (int g = 0; g <= MAX; g++) { - for (int z = 0; z <= MAX; z++) { - for (int n = 0; n <= MAX; n++) { - for (int p = 0; p <= MAX; p++) { - if (a + g + z + n + p > length) { - continue; - } - if (a + g + z + n + p < length) { + for (int a = 0; a < MAX; ++a) { + for (int g = 0; g < MAX; ++g) { + for (int z = 0; z < MAX; ++z) { + for (int n = 0; n < MAX; ++n) { + for (int p = 0; p < MAX; ++p) { + if (a + g + z + n + p != length) { continue; } for (DoubleBuilder builder : DoubleBuilder.values()) { - out.println("Test 'double': random = " + random.getSeed() + - ", length = " + length + ", a = " + a + ", g = " + - g + ", z = " + z + ", n = " + n + ", p = " + p); + out.println(getTestName() + "random = " + + random.getSeed() + " length = " + length + + ", a = " + a + ", g = " + g + ", z = " + z + + ", n = " + n + ", p = " + p); builder.build(golden, a, g, z, n, p, random); double[] test = golden.clone(); scramble(test, random); @@ -540,40 +644,72 @@ if (newLine) { out.println(); } + + for (int m = 13; m > 4; --m) { + int t = length / m; + int g = t, z = t, n = t, p = t; + int a = length - g - z - n - p; + + for (DoubleBuilder builder : DoubleBuilder.values()) { + out.println(getTestName() + "random = " + + random.getSeed() + " length = " + length + + ", a = " + a + ", g = " + g + ", z = " + z + + ", n = " + n + ", p = " + p); + builder.build(golden, a, g, z, n, p, random); + double[] test = golden.clone(); + scramble(test, random); + sort(test); + compare(test, golden, a, n, g); + } + } + out.println(); + } + + private static void testDoubleNegativeZero(int length, TestRandom random) { + name = "Double -0.0"; + out.println(getTestName() + "random = " + random.getSeed() + " length = " + length); + double[] a = new double[length]; + + for (int i = 0; i < length; ++i) { + a[i] = random.nextBoolean() ? -0.0d : 0.0d; + } + sort(a); + checkNegativeZero(a); + out.println(); } - private static void prepareSubArray(int[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - a[i] = 0xDEDA; + private static void prepareSubArray(int[] a, int fromIndex, int toIndex) { + for (int i = 0; i < fromIndex; ++i) { + a[i] = A380; } int middle = (fromIndex + toIndex) >>> 1; int k = 0; - for (int i = fromIndex; i < middle; i++) { + for (int i = fromIndex; i < middle; ++i) { a[i] = k++; } - for (int i = middle; i < toIndex; i++) { + for (int i = middle; i < toIndex; ++i) { a[i] = k--; } - for (int i = toIndex; i < a.length; i++) { - a[i] = 0xBABA; + for (int i = toIndex; i < a.length; ++i) { + a[i] = B747; } } private static void scramble(int[] a, Random random) { - for (int i = 0; i < a.length * 7; i++) { + for (int i = 0; i < a.length * 7; ++i) { swap(a, random.nextInt(a.length), random.nextInt(a.length)); } } private static void scramble(float[] a, Random random) { - for (int i = 0; i < a.length * 7; i++) { + for (int i = 0; i < a.length * 7; ++i) { swap(a, random.nextInt(a.length), random.nextInt(a.length)); } } private static void scramble(double[] a, Random random) { - for (int i = 0; i < a.length * 7; i++) { + for (int i = 0; i < a.length * 7; ++i) { swap(a, random.nextInt(a.length), random.nextInt(a.length)); } } @@ -596,96 +732,95 @@ a[j] = t; } - private static enum TypeConverter { + private enum TypeConverter { + INT { Object convert(int[] a) { return a.clone(); } }, + LONG { Object convert(int[] a) { long[] b = new long[a.length]; - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { b[i] = (long) a[i]; } return b; } }, + BYTE { Object convert(int[] a) { byte[] b = new byte[a.length]; - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { b[i] = (byte) a[i]; } return b; } }, + SHORT { Object convert(int[] a) { short[] b = new short[a.length]; - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { b[i] = (short) a[i]; } return b; } }, + CHAR { Object convert(int[] a) { char[] b = new char[a.length]; - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { b[i] = (char) a[i]; } return b; } }, + FLOAT { Object convert(int[] a) { float[] b = new float[a.length]; - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { b[i] = (float) a[i]; } return b; } }, + DOUBLE { Object convert(int[] a) { double[] b = new double[a.length]; - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { b[i] = (double) a[i]; } return b; } - }, - INTEGER { - Object convert(int[] a) { - Integer[] b = new Integer[a.length]; - - for (int i = 0; i < a.length; i++) { - b[i] = new Integer(a[i]); - } - return b; - } }; abstract Object convert(int[] a); - @Override public String toString() { + @Override + public String toString() { String name = name(); - for (int i = name.length(); i < 9; i++) { + for (int i = name.length(); i < 9; ++i) { name += " "; } return name; } } - private static enum FloatBuilder { + private enum FloatBuilder { + SIMPLE { void build(float[] x, int a, int g, int z, int n, int p, Random random) { int fromIndex = 0; @@ -711,7 +846,8 @@ abstract void build(float[] x, int a, int g, int z, int n, int p, Random random); } - private static enum DoubleBuilder { + private enum DoubleBuilder { + SIMPLE { void build(double[] x, int a, int g, int z, int n, int p, Random random) { int fromIndex = 0; @@ -738,66 +874,85 @@ } private static void writeValue(float[] a, float value, int fromIndex, int count) { - for (int i = fromIndex; i < fromIndex + count; i++) { + for (int i = fromIndex; i < fromIndex + count; ++i) { a[i] = value; } } private static void compare(float[] a, float[] b, int numNaN, int numNeg, int numNegZero) { - for (int i = a.length - numNaN; i < a.length; i++) { + for (int i = a.length - numNaN; i < a.length; ++i) { if (a[i] == a[i]) { - failed("On position " + i + " must be NaN instead of " + a[i]); + fail("On position " + i + " must be NaN instead of " + a[i]); } } final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f); - for (int i = numNeg; i < numNeg + numNegZero; i++) { + for (int i = numNeg; i < numNeg + numNegZero; ++i) { if (NEGATIVE_ZERO != Float.floatToIntBits(a[i])) { - failed("On position " + i + " must be -0.0 instead of " + a[i]); + fail("On position " + i + " must be -0.0 instead of " + a[i]); } } - for (int i = 0; i < a.length - numNaN; i++) { + + for (int i = 0; i < a.length - numNaN; ++i) { if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); + failCompare(i, "" + a[i], "" + b[i]); + } + } + } + + private static void checkNegativeZero(float[] a) { + for (int i = 0; i < a.length - 1; ++i) { + if (Float.floatToRawIntBits(a[i]) == 0 && Float.floatToRawIntBits(a[i + 1]) < 0) { + fail(a[i] + " goes before " + a[i + 1] + " at " + i); } } } private static void writeValue(double[] a, double value, int fromIndex, int count) { - for (int i = fromIndex; i < fromIndex + count; i++) { + for (int i = fromIndex; i < fromIndex + count; ++i) { a[i] = value; } } private static void compare(double[] a, double[] b, int numNaN, int numNeg, int numNegZero) { - for (int i = a.length - numNaN; i < a.length; i++) { + for (int i = a.length - numNaN; i < a.length; ++i) { if (a[i] == a[i]) { - failed("On position " + i + " must be NaN instead of " + a[i]); + fail("On position " + i + " must be NaN instead of " + a[i]); } } final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d); - for (int i = numNeg; i < numNeg + numNegZero; i++) { + for (int i = numNeg; i < numNeg + numNegZero; ++i) { if (NEGATIVE_ZERO != Double.doubleToLongBits(a[i])) { - failed("On position " + i + " must be -0.0 instead of " + a[i]); + fail("On position " + i + " must be -0.0 instead of " + a[i]); } } - for (int i = 0; i < a.length - numNaN; i++) { + + for (int i = 0; i < a.length - numNaN; ++i) { if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); + failCompare(i, "" + a[i], "" + b[i]); } } } - private static enum SortedBuilder { - REPEATED { + private static void checkNegativeZero(double[] a) { + for (int i = 0; i < a.length - 1; ++i) { + if (Double.doubleToRawLongBits(a[i]) == 0 && Double.doubleToRawLongBits(a[i + 1]) < 0) { + fail(a[i] + " goes before " + a[i + 1] + " at " + i); + } + } + } + + private enum SortedBuilder { + + STEPS { void build(int[] a, int m) { int period = a.length / m; int i = 0; int k = 0; while (true) { - for (int t = 1; t <= period; t++) { + for (int t = 1; t <= period; ++t) { if (i >= a.length) { return; } @@ -806,115 +961,58 @@ if (i >= a.length) { return; } - k++; - } - } - }, - ORGAN_PIPES { - void build(int[] a, int m) { - int i = 0; - int k = m; - - while (true) { - for (int t = 1; t <= m; t++) { - if (i >= a.length) { - return; - } - a[i++] = k; - } + ++k; } } }; abstract void build(int[] a, int m); - @Override public String toString() { + @Override + public String toString() { String name = name(); - for (int i = name.length(); i < 12; i++) { + for (int i = name.length(); i < 12; ++i) { name += " "; } return name; } } - private static enum MergeBuilder { - ASCENDING { - void build(int[] a, int m) { - int period = a.length / m; - int v = 1, i = 0; + private enum UnsortedBuilder { - for (int k = 0; k < m; k++) { - v = 1; - for (int p = 0; p < period; p++) { - a[i++] = v++; - } - } - for (int j = i; j < a.length - 1; j++) { - a[j] = v++; - } - a[a.length - 1] = 0; - } - }, - DESCENDING { - void build(int[] a, int m) { - int period = a.length / m; - int v = -1, i = 0; - - for (int k = 0; k < m; k++) { - v = -1; - for (int p = 0; p < period; p++) { - a[i++] = v--; - } - } - for (int j = i; j < a.length - 1; j++) { - a[j] = v--; - } - a[a.length - 1] = 0; - } - }; - - abstract void build(int[] a, int m); - - @Override public String toString() { - String name = name(); - - for (int i = name.length(); i < 12; i++) { - name += " "; - } - return name; - } - } - - private static enum UnsortedBuilder { RANDOM { void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { a[i] = random.nextInt(); } } }, + ASCENDING { void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { a[i] = m + i; } } }, + DESCENDING { void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { a[i] = a.length - m - i; } } }, - ALL_EQUAL { + + EQUAL { void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { a[i] = m; } } }, + SAW { void build(int[] a, int m, Random random) { int incCount = 1; @@ -923,7 +1021,7 @@ int period = m--; while (true) { - for (int k = 1; k <= period; k++) { + for (int k = 1; k <= period; ++k) { if (i >= a.length) { return; } @@ -931,7 +1029,7 @@ } period += m; - for (int k = 1; k <= period; k++) { + for (int k = 1; k <= period; ++k) { if (i >= a.length) { return; } @@ -941,84 +1039,205 @@ } } }, + REPEATED { void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { a[i] = i % m; } } }, + DUPLICATED { void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { a[i] = random.nextInt(m); } } }, + ORGAN_PIPES { void build(int[] a, int m, Random random) { int middle = a.length / (m + 1); - for (int i = 0; i < middle; i++) { + for (int i = 0; i < middle; ++i) { a[i] = i; } - for (int i = middle; i < a.length; i++) { + for (int i = middle; i < a.length; ++i) { a[i] = a.length - i - 1; } } }, + STAGGER { void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { a[i] = (i * m + i) % a.length; } } }, + PLATEAU { void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { a[i] = Math.min(i, m); } } }, + SHUFFLE { void build(int[] a, int m, Random random) { int x = 0, y = 0; - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { a[i] = random.nextBoolean() ? (x += 2) : (y += 2); } } + }, + + LATCH { + void build(int[] a, int m, Random random) { + int max = a.length / m; + max = max < 2 ? 2 : max; + + for (int i = 0; i < a.length; ++i) { + a[i] = i % max; + } + } }; abstract void build(int[] a, int m, Random random); - @Override public String toString() { + @Override + public String toString() { + String name = name(); + + for (int i = name.length(); i < 12; ++i) { + name += " "; + } + return name; + } + } + + private enum MergingBuilder { + + ASCENDING { + void build(int[] a, int m) { + int period = a.length / m; + int v = 1, i = 0; + + for (int k = 0; k < m; ++k) { + v = 1; + for (int p = 0; p < period; ++p) { + a[i++] = v++; + } + } + for (int j = i; j < a.length - 1; ++j) { + a[j] = v++; + } + a[a.length - 1] = 0; + } + }, + + DESCENDING { + void build(int[] a, int m) { + int period = a.length / m; + int v = -1, i = 0; + + for (int k = 0; k < m; ++k) { + v = -1; + for (int p = 0; p < period; ++p) { + a[i++] = v--; + } + } + for (int j = i; j < a.length - 1; ++j) { + a[j] = v--; + } + a[a.length - 1] = 0; + } + }, + + POINT { + void build(int[] a, int m) { + for (int i = 0; i < a.length; ++i) { + a[i] = 0; + } + a[a.length / 2] = m; + } + }, + + LINE { + void build(int[] a, int m) { + for (int i = 0; i < a.length; ++i) { + a[i] = i; + } + reverse(a, 0, a.length - 1); + } + }, + + PEARL { + void build(int[] a, int m) { + for (int i = 0; i < a.length; ++i) { + a[i] = i; + } + reverse(a, 0, 2); + } + }, + + RING { + void build(int[] a, int m) { + int k1 = a.length / 3; + int k2 = a.length / 3 * 2; + int level = a.length / 3; + + for (int i = 0, k = level; i < k1; ++i) { + a[i] = k--; + } + for (int i = k1; i < k2; ++i) { + a[i] = 0; + } + for (int i = k2, k = level; i < a.length; ++i) { + a[i] = k--; + } + } + }; + + abstract void build(int[] a, int m); + + @Override + public String toString() { String name = name(); - for (int i = name.length(); i < 12; i++) { + for (int i = name.length(); i < 12; ++i) { name += " "; } return name; } } + private static void reverse(int[] a, int lo, int hi) { + for (--hi; lo < hi; ) { + int tmp = a[lo]; + a[lo++] = a[hi]; + a[hi--] = tmp; + } + } + private static void checkWithCheckSum(Object test, Object golden) { checkSorted(test); checkCheckSum(test, golden); } - private static void failed(String message) { - err.format("\n*** TEST FAILED - %s.\n\n%s.\n\n", ourDescription, message); + private static void fail(String message) { + err.format("\n*** TEST FAILED *** %s.\n\n%s.\n\n", name, message); throw new RuntimeException("Test failed - see log file for details"); } - private static void failedSort(int index, String value1, String value2) { - failed("Array is not sorted at " + index + "-th position: " + - value1 + " and " + value2); + private static void failSort(int index, String value1, String value2) { + fail("Array is not sorted at " + index + "-th position: " + value1 + " and " + value2); } - private static void failedCompare(int index, String value1, String value2) { - failed("On position " + index + " must be " + value2 + " instead of " + value1); + private static void failCompare(int index, String value1, String value2) { + fail("On position " + index + " must be " + value2 + " instead of " + value1); } private static void compare(Object test, Object golden) { @@ -1036,74 +1255,64 @@ compare((float[]) test, (float[]) golden); } else if (test instanceof double[]) { compare((double[]) test, (double[]) golden); - } else if (test instanceof Integer[]) { - compare((Integer[]) test, (Integer[]) golden); } else { - failed("Unknow type of array: " + test + " of class " + + fail("Unknown type of array: " + test + " of class " + test.getClass().getName()); } } private static void compare(int[] a, int[] b) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); + failCompare(i, "" + a[i], "" + b[i]); } } } private static void compare(long[] a, long[] b) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); + failCompare(i, "" + a[i], "" + b[i]); } } } private static void compare(short[] a, short[] b) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); + failCompare(i, "" + a[i], "" + b[i]); } } } private static void compare(byte[] a, byte[] b) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); + failCompare(i, "" + a[i], "" + b[i]); } } } private static void compare(char[] a, char[] b) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); + failCompare(i, "" + a[i], "" + b[i]); } } } private static void compare(float[] a, float[] b) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); + failCompare(i, "" + a[i], "" + b[i]); } } } private static void compare(double[] a, double[] b) { - for (int i = 0; i < a.length; i++) { + for (int i = 0; i < a.length; ++i) { if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static void compare(Integer[] a, Integer[] b) { - for (int i = 0; i < a.length; i++) { - if (a[i].compareTo(b[i]) != 0) { - failedCompare(i, "" + a[i], "" + b[i]); + failCompare(i, "" + a[i], "" + b[i]); } } } @@ -1123,84 +1332,74 @@ checkSorted((float[]) object); } else if (object instanceof double[]) { checkSorted((double[]) object); - } else if (object instanceof Integer[]) { - checkSorted((Integer[]) object); } else { - failed("Unknow type of array: " + object + " of class " + + fail("Unknown type of array: " + object + " of class " + object.getClass().getName()); } } private static void checkSorted(int[] a) { - for (int i = 0; i < a.length - 1; i++) { + for (int i = 0; i < a.length - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } } private static void checkSorted(long[] a) { - for (int i = 0; i < a.length - 1; i++) { + for (int i = 0; i < a.length - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } } private static void checkSorted(short[] a) { - for (int i = 0; i < a.length - 1; i++) { + for (int i = 0; i < a.length - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } } private static void checkSorted(byte[] a) { - for (int i = 0; i < a.length - 1; i++) { + for (int i = 0; i < a.length - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } } private static void checkSorted(char[] a) { - for (int i = 0; i < a.length - 1; i++) { + for (int i = 0; i < a.length - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } } private static void checkSorted(float[] a) { - for (int i = 0; i < a.length - 1; i++) { + for (int i = 0; i < a.length - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } } private static void checkSorted(double[] a) { - for (int i = 0; i < a.length - 1; i++) { + for (int i = 0; i < a.length - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - } - - private static void checkSorted(Integer[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i].intValue() > a[i + 1].intValue()) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } } private static void checkCheckSum(Object test, Object golden) { if (checkSumXor(test) != checkSumXor(golden)) { - failed("Original and sorted arrays are not identical [xor]"); + fail("Original and sorted arrays are not identical [xor]"); } if (checkSumPlus(test) != checkSumPlus(golden)) { - failed("Original and sorted arrays are not identical [plus]"); + fail("Original and sorted arrays are not identical [plus]"); } } @@ -1219,24 +1418,13 @@ return checkSumXor((float[]) object); } else if (object instanceof double[]) { return checkSumXor((double[]) object); - } else if (object instanceof Integer[]) { - return checkSumXor((Integer[]) object); } else { - failed("Unknow type of array: " + object + " of class " + + fail("Unknown type of array: " + object + " of class " + object.getClass().getName()); return -1; } } - private static int checkSumXor(Integer[] a) { - int checkSum = 0; - - for (Integer e : a) { - checkSum ^= e.intValue(); - } - return checkSum; - } - private static int checkSumXor(int[] a) { int checkSum = 0; @@ -1315,10 +1503,8 @@ return checkSumPlus((float[]) object); } else if (object instanceof double[]) { return checkSumPlus((double[]) object); - } else if (object instanceof Integer[]) { - return checkSumPlus((Integer[]) object); } else { - failed("Unknow type of array: " + object + " of class " + + fail("Unknown type of array: " + object + " of class " + object.getClass().getName()); return -1; } @@ -1387,15 +1573,6 @@ return checkSum; } - private static int checkSumPlus(Integer[] a) { - int checkSum = 0; - - for (Integer e : a) { - checkSum += e.intValue(); - } - return checkSum; - } - private static void sortByInsertionSort(Object object) { if (object instanceof int[]) { sortByInsertionSort((int[]) object); @@ -1411,18 +1588,16 @@ sortByInsertionSort((float[]) object); } else if (object instanceof double[]) { sortByInsertionSort((double[]) object); - } else if (object instanceof Integer[]) { - sortByInsertionSort((Integer[]) object); } else { - failed("Unknow type of array: " + object + " of class " + + fail("Unknown type of array: " + object + " of class " + object.getClass().getName()); } } private static void sortByInsertionSort(int[] a) { - for (int j, i = 1; i < a.length; i++) { + for (int j, i = 1; i < a.length; ++i) { int ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { + for (j = i - 1; j >= 0 && ai < a[j]; --j) { a[j + 1] = a[j]; } a[j + 1] = ai; @@ -1430,9 +1605,9 @@ } private static void sortByInsertionSort(long[] a) { - for (int j, i = 1; i < a.length; i++) { + for (int j, i = 1; i < a.length; ++i) { long ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { + for (j = i - 1; j >= 0 && ai < a[j]; --j) { a[j + 1] = a[j]; } a[j + 1] = ai; @@ -1440,9 +1615,9 @@ } private static void sortByInsertionSort(short[] a) { - for (int j, i = 1; i < a.length; i++) { + for (int j, i = 1; i < a.length; ++i) { short ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { + for (j = i - 1; j >= 0 && ai < a[j]; --j) { a[j + 1] = a[j]; } a[j + 1] = ai; @@ -1450,9 +1625,9 @@ } private static void sortByInsertionSort(byte[] a) { - for (int j, i = 1; i < a.length; i++) { + for (int j, i = 1; i < a.length; ++i) { byte ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { + for (j = i - 1; j >= 0 && ai < a[j]; --j) { a[j + 1] = a[j]; } a[j + 1] = ai; @@ -1460,9 +1635,9 @@ } private static void sortByInsertionSort(char[] a) { - for (int j, i = 1; i < a.length; i++) { + for (int j, i = 1; i < a.length; ++i) { char ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { + for (j = i - 1; j >= 0 && ai < a[j]; --j) { a[j + 1] = a[j]; } a[j + 1] = ai; @@ -1470,9 +1645,9 @@ } private static void sortByInsertionSort(float[] a) { - for (int j, i = 1; i < a.length; i++) { + for (int j, i = 1; i < a.length; ++i) { float ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { + for (j = i - 1; j >= 0 && ai < a[j]; --j) { a[j + 1] = a[j]; } a[j + 1] = ai; @@ -1480,19 +1655,9 @@ } private static void sortByInsertionSort(double[] a) { - for (int j, i = 1; i < a.length; i++) { + for (int j, i = 1; i < a.length; ++i) { double ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } - - private static void sortByInsertionSort(Integer[] a) { - for (int j, i = 1; i < a.length; i++) { - Integer ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { + for (j = i - 1; j >= 0 && ai < a[j]; --j) { a[j + 1] = a[j]; } a[j + 1] = ai; @@ -1501,245 +1666,217 @@ private static void sort(Object object) { if (object instanceof int[]) { - Arrays.sort((int[]) object); + sortingHelper.sort((int[]) object); } else if (object instanceof long[]) { - Arrays.sort((long[]) object); + sortingHelper.sort((long[]) object); } else if (object instanceof short[]) { - Arrays.sort((short[]) object); + sortingHelper.sort((short[]) object); } else if (object instanceof byte[]) { - Arrays.sort((byte[]) object); + sortingHelper.sort((byte[]) object); } else if (object instanceof char[]) { - Arrays.sort((char[]) object); + sortingHelper.sort((char[]) object); } else if (object instanceof float[]) { - Arrays.sort((float[]) object); + sortingHelper.sort((float[]) object); } else if (object instanceof double[]) { - Arrays.sort((double[]) object); - } else if (object instanceof Integer[]) { - Arrays.sort((Integer[]) object); + sortingHelper.sort((double[]) object); } else { - failed("Unknow type of array: " + object + " of class " + + fail("Unknown type of array: " + object + " of class " + object.getClass().getName()); } } private static void sortSubArray(Object object, int fromIndex, int toIndex) { if (object instanceof int[]) { - Arrays.sort((int[]) object, fromIndex, toIndex); + sortingHelper.sort((int[]) object, fromIndex, toIndex); } else if (object instanceof long[]) { - Arrays.sort((long[]) object, fromIndex, toIndex); + sortingHelper.sort((long[]) object, fromIndex, toIndex); } else if (object instanceof short[]) { - Arrays.sort((short[]) object, fromIndex, toIndex); + sortingHelper.sort((short[]) object, fromIndex, toIndex); } else if (object instanceof byte[]) { - Arrays.sort((byte[]) object, fromIndex, toIndex); + sortingHelper.sort((byte[]) object, fromIndex, toIndex); } else if (object instanceof char[]) { - Arrays.sort((char[]) object, fromIndex, toIndex); + sortingHelper.sort((char[]) object, fromIndex, toIndex); } else if (object instanceof float[]) { - Arrays.sort((float[]) object, fromIndex, toIndex); + sortingHelper.sort((float[]) object, fromIndex, toIndex); } else if (object instanceof double[]) { - Arrays.sort((double[]) object, fromIndex, toIndex); - } else if (object instanceof Integer[]) { - Arrays.sort((Integer[]) object, fromIndex, toIndex); + sortingHelper.sort((double[]) object, fromIndex, toIndex); } else { - failed("Unknow type of array: " + object + " of class " + + fail("Unknown type of array: " + object + " of class " + object.getClass().getName()); } } - private static void checkSubArray(Object object, int fromIndex, int toIndex, int m) { + private static void checkSubArray(Object object, int fromIndex, int toIndex) { if (object instanceof int[]) { - checkSubArray((int[]) object, fromIndex, toIndex, m); + checkSubArray((int[]) object, fromIndex, toIndex); } else if (object instanceof long[]) { - checkSubArray((long[]) object, fromIndex, toIndex, m); + checkSubArray((long[]) object, fromIndex, toIndex); } else if (object instanceof short[]) { - checkSubArray((short[]) object, fromIndex, toIndex, m); + checkSubArray((short[]) object, fromIndex, toIndex); } else if (object instanceof byte[]) { - checkSubArray((byte[]) object, fromIndex, toIndex, m); + checkSubArray((byte[]) object, fromIndex, toIndex); } else if (object instanceof char[]) { - checkSubArray((char[]) object, fromIndex, toIndex, m); + checkSubArray((char[]) object, fromIndex, toIndex); } else if (object instanceof float[]) { - checkSubArray((float[]) object, fromIndex, toIndex, m); + checkSubArray((float[]) object, fromIndex, toIndex); } else if (object instanceof double[]) { - checkSubArray((double[]) object, fromIndex, toIndex, m); - } else if (object instanceof Integer[]) { - checkSubArray((Integer[]) object, fromIndex, toIndex, m); + checkSubArray((double[]) object, fromIndex, toIndex); } else { - failed("Unknow type of array: " + object + " of class " + + fail("Unknown type of array: " + object + " of class " + object.getClass().getName()); } } - private static void checkSubArray(Integer[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i].intValue() != 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); - } - } - - for (int i = fromIndex; i < toIndex - 1; i++) { - if (a[i].intValue() > a[i + 1].intValue()) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - - for (int i = toIndex; i < a.length; i++) { - if (a[i].intValue() != 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); - } - } - } - - private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); + private static void checkSubArray(int[] a, int fromIndex, int toIndex) { + for (int i = 0; i < fromIndex; ++i) { + if (a[i] != A380) { + fail("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + A380); } } - for (int i = fromIndex; i < toIndex - 1; i++) { + for (int i = fromIndex; i < toIndex - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } - for (int i = toIndex; i < a.length; i++) { - if (a[i] != 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); + for (int i = toIndex; i < a.length; ++i) { + if (a[i] != B747) { + fail("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + B747); } } } - private static void checkSubArray(byte[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (byte) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); + private static void checkSubArray(byte[] a, int fromIndex, int toIndex) { + for (int i = 0; i < fromIndex; ++i) { + if (a[i] != (byte) A380) { + fail("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + A380); } } - for (int i = fromIndex; i < toIndex - 1; i++) { + for (int i = fromIndex; i < toIndex - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (byte) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); + for (int i = toIndex; i < a.length; ++i) { + if (a[i] != (byte) B747) { + fail("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + B747); } } } - private static void checkSubArray(long[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (long) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); + private static void checkSubArray(long[] a, int fromIndex, int toIndex) { + for (int i = 0; i < fromIndex; ++i) { + if (a[i] != (long) A380) { + fail("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + A380); } } - for (int i = fromIndex; i < toIndex - 1; i++) { + for (int i = fromIndex; i < toIndex - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (long) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); + for (int i = toIndex; i < a.length; ++i) { + if (a[i] != (long) B747) { + fail("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + B747); } } } - private static void checkSubArray(char[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (char) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); + private static void checkSubArray(char[] a, int fromIndex, int toIndex) { + for (int i = 0; i < fromIndex; ++i) { + if (a[i] != (char) A380) { + fail("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + A380); } } - for (int i = fromIndex; i < toIndex - 1; i++) { + for (int i = fromIndex; i < toIndex - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (char) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); + for (int i = toIndex; i < a.length; ++i) { + if (a[i] != (char) B747) { + fail("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + B747); } } } - private static void checkSubArray(short[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (short) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); + private static void checkSubArray(short[] a, int fromIndex, int toIndex) { + for (int i = 0; i < fromIndex; ++i) { + if (a[i] != (short) A380) { + fail("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + A380); } } - for (int i = fromIndex; i < toIndex - 1; i++) { + for (int i = fromIndex; i < toIndex - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (short) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); + for (int i = toIndex; i < a.length; ++i) { + if (a[i] != (short) B747) { + fail("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + B747); } } } - private static void checkSubArray(float[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (float) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); + private static void checkSubArray(float[] a, int fromIndex, int toIndex) { + for (int i = 0; i < fromIndex; ++i) { + if (a[i] != (float) A380) { + fail("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + A380); } } - for (int i = fromIndex; i < toIndex - 1; i++) { + for (int i = fromIndex; i < toIndex - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (float) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); + for (int i = toIndex; i < a.length; ++i) { + if (a[i] != (float) B747) { + fail("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + B747); } } } - private static void checkSubArray(double[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (double) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); + private static void checkSubArray(double[] a, int fromIndex, int toIndex) { + for (int i = 0; i < fromIndex; ++i) { + if (a[i] != (double) A380) { + fail("Range sort changes left element on position " + i + + ": " + a[i] + ", must be " + A380); } } - for (int i = fromIndex; i < toIndex - 1; i++) { + for (int i = fromIndex; i < toIndex - 1; ++i) { if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); + failSort(i, "" + a[i], "" + a[i + 1]); } } - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (double) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); + for (int i = toIndex; i < a.length; ++i) { + if (a[i] != (double) B747) { + fail("Range sort changes right element on position " + i + + ": " + a[i] + ", must be " + B747); } } } @@ -1759,67 +1896,31 @@ checkRange((float[]) object, m); } else if (object instanceof double[]) { checkRange((double[]) object, m); - } else if (object instanceof Integer[]) { - checkRange((Integer[]) object, m); } else { - failed("Unknow type of array: " + object + " of class " + + fail("Unknown type of array: " + object + " of class " + object.getClass().getName()); } } - private static void checkRange(Integer[] a, int m) { - try { - Arrays.sort(a, m + 1, m); - - failed("Sort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { - try { - Arrays.sort(a, -m, a.length); - - failed("Sort does not throw ArrayIndexOutOfBoundsException " + - " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { - try { - Arrays.sort(a, 0, a.length + m); - - failed("Sort does not throw ArrayIndexOutOfBoundsException " + - " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; - } - } - } - } - private static void checkRange(int[] a, int m) { try { - Arrays.sort(a, m + 1, m); + sortingHelper.sort(a, m + 1, m); - failed("Sort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { + fail(sortingHelper + "() does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + " toIndex = " + m); + } catch (IllegalArgumentException iae) { try { - Arrays.sort(a, -m, a.length); + sortingHelper.sort(a, -m, a.length); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { + } catch (ArrayIndexOutOfBoundsException aoe) { try { - Arrays.sort(a, 0, a.length + m); + sortingHelper.sort(a, 0, a.length + m); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; + } catch (ArrayIndexOutOfBoundsException expected) { } } } @@ -1827,28 +1928,23 @@ private static void checkRange(long[] a, int m) { try { - Arrays.sort(a, m + 1, m); + sortingHelper.sort(a, m + 1, m); - failed("Sort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { + fail(sortingHelper + "() does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + " toIndex = " + m); + } catch (IllegalArgumentException iae) { try { - Arrays.sort(a, -m, a.length); + sortingHelper.sort(a, -m, a.length); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { + } catch (ArrayIndexOutOfBoundsException aoe) { try { - Arrays.sort(a, 0, a.length + m); + sortingHelper.sort(a, 0, a.length + m); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; + } catch (ArrayIndexOutOfBoundsException expected) { } } } @@ -1856,28 +1952,23 @@ private static void checkRange(byte[] a, int m) { try { - Arrays.sort(a, m + 1, m); + sortingHelper.sort(a, m + 1, m); - failed("Sort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { + fail(sortingHelper + "() does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + " toIndex = " + m); + } catch (IllegalArgumentException iae) { try { - Arrays.sort(a, -m, a.length); + sortingHelper.sort(a, -m, a.length); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { + } catch (ArrayIndexOutOfBoundsException aoe) { try { - Arrays.sort(a, 0, a.length + m); + sortingHelper.sort(a, 0, a.length + m); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; + } catch (ArrayIndexOutOfBoundsException expected) { } } } @@ -1885,28 +1976,23 @@ private static void checkRange(short[] a, int m) { try { - Arrays.sort(a, m + 1, m); + sortingHelper.sort(a, m + 1, m); - failed("Sort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { + fail(sortingHelper + "() does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + " toIndex = " + m); + } catch (IllegalArgumentException iae) { try { - Arrays.sort(a, -m, a.length); + sortingHelper.sort(a, -m, a.length); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { + } catch (ArrayIndexOutOfBoundsException aoe) { try { - Arrays.sort(a, 0, a.length + m); + sortingHelper.sort(a, 0, a.length + m); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; + } catch (ArrayIndexOutOfBoundsException expected) { } } } @@ -1914,28 +2000,23 @@ private static void checkRange(char[] a, int m) { try { - Arrays.sort(a, m + 1, m); + sortingHelper.sort(a, m + 1, m); - failed("Sort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { + fail(sortingHelper + "() does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + " toIndex = " + m); + } catch (IllegalArgumentException iae) { try { - Arrays.sort(a, -m, a.length); + sortingHelper.sort(a, -m, a.length); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { + } catch (ArrayIndexOutOfBoundsException aoe) { try { - Arrays.sort(a, 0, a.length + m); + sortingHelper.sort(a, 0, a.length + m); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; + } catch (ArrayIndexOutOfBoundsException expected) { } } } @@ -1943,28 +2024,23 @@ private static void checkRange(float[] a, int m) { try { - Arrays.sort(a, m + 1, m); + sortingHelper.sort(a, m + 1, m); - failed("Sort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { + fail(sortingHelper + "() does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + " toIndex = " + m); + } catch (IllegalArgumentException iae) { try { - Arrays.sort(a, -m, a.length); + sortingHelper.sort(a, -m, a.length); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { + } catch (ArrayIndexOutOfBoundsException aoe) { try { - Arrays.sort(a, 0, a.length + m); + sortingHelper.sort(a, 0, a.length + m); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; + } catch (ArrayIndexOutOfBoundsException expected) { } } } @@ -1972,73 +2048,43 @@ private static void checkRange(double[] a, int m) { try { - Arrays.sort(a, m + 1, m); + sortingHelper.sort(a, m + 1, m); - failed("Sort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { + fail(sortingHelper + "() does not throw IllegalArgumentException " + + " as expected: fromIndex = " + (m + 1) + " toIndex = " + m); + } catch (IllegalArgumentException iae) { try { - Arrays.sort(a, -m, a.length); + sortingHelper.sort(a, -m, a.length); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { + } catch (ArrayIndexOutOfBoundsException aoe) { try { - Arrays.sort(a, 0, a.length + m); + sortingHelper.sort(a, 0, a.length + m); - failed("Sort does not throw ArrayIndexOutOfBoundsException " + + fail(sortingHelper + "() does not throw ArrayIndexOutOfBoundsException " + " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; + } catch (ArrayIndexOutOfBoundsException expected) { } } } } - private static void outArray(Object[] a) { - for (int i = 0; i < a.length; i++) { - out.print(a[i] + " "); - } - out.println(); - } - - private static void outArray(int[] a) { - for (int i = 0; i < a.length; i++) { - out.print(a[i] + " "); - } - out.println(); + private static String getTestName() { + return "[" + sortingHelper + "] '" + name + "' "; } - private static void outArray(float[] a) { - for (int i = 0; i < a.length; i++) { - out.print(a[i] + " "); - } - out.println(); - } + private static class TestRandom extends Random { - private static void outArray(double[] a) { - for (int i = 0; i < a.length; i++) { - out.print(a[i] + " "); - } - out.println(); - } - - private static class MyRandom extends Random { - MyRandom(long seed) { + private TestRandom(long seed) { super(seed); - mySeed = seed; + this.seed = Long.toHexString(seed).toUpperCase(); } - long getSeed() { - return mySeed; + String getSeed() { + return seed; } - private long mySeed; + private String seed; } - - private static String ourDescription; } --- old/test/jdk/java/util/Arrays/ParallelSorting.java 2019-07-17 17:04:38.412314289 +0200 +++ /dev/null 2019-07-17 10:17:39.064651967 +0200 @@ -1,2067 +0,0 @@ -/* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* Adapted from test/java/util/Arrays/Sorting.java - * - * Where that test checks Arrays.sort against manual quicksort routines, - * this test checks parallelSort against either Arrays.sort or manual - * quicksort routines. - */ - -/* - * @test - * @bug 8003981 - * @run main ParallelSorting -shortrun - * @summary Exercise Arrays.parallelSort (adapted from test Sorting) - * - * @author Vladimir Yaroslavskiy - * @author Jon Bentley - * @author Josh Bloch - */ - -import java.util.Arrays; -import java.util.Random; -import java.io.PrintStream; -import java.util.Comparator; - -public class ParallelSorting { - private static final PrintStream out = System.out; - private static final PrintStream err = System.err; - - // Array lengths used in a long run (default) - private static final int[] LONG_RUN_LENGTHS = { - 1000, 10000, 100000, 1000000 }; - - // Array lengths used in a short run - private static final int[] SHORT_RUN_LENGTHS = { - 5000, 9000, 10000, 12000 }; - - // Random initial values used in a long run (default) - private static final long[] LONG_RUN_RANDOMS = { 666, 0xC0FFEE, 999 }; - - // Random initial values used in a short run - private static final long[] SHORT_RUN_RANDOMS = { 666 }; - - public static void main(String[] args) { - boolean shortRun = args.length > 0 && args[0].equals("-shortrun"); - long start = System.currentTimeMillis(); - - if (shortRun) { - testAndCheck(SHORT_RUN_LENGTHS, SHORT_RUN_RANDOMS); - } else { - testAndCheck(LONG_RUN_LENGTHS, LONG_RUN_RANDOMS); - } - long end = System.currentTimeMillis(); - - out.format("PASSED in %d sec.\n", Math.round((end - start) / 1E3)); - } - - private static void testAndCheck(int[] lengths, long[] randoms) { - testEmptyAndNullIntArray(); - testEmptyAndNullLongArray(); - testEmptyAndNullShortArray(); - testEmptyAndNullCharArray(); - testEmptyAndNullByteArray(); - testEmptyAndNullFloatArray(); - testEmptyAndNullDoubleArray(); - - for (int length : lengths) { - testMergeSort(length); - testAndCheckRange(length); - testAndCheckSubArray(length); - } - for (long seed : randoms) { - for (int length : lengths) { - testAndCheckWithInsertionSort(length, new MyRandom(seed)); - testAndCheckWithCheckSum(length, new MyRandom(seed)); - testAndCheckWithScrambling(length, new MyRandom(seed)); - testAndCheckFloat(length, new MyRandom(seed)); - testAndCheckDouble(length, new MyRandom(seed)); - testStable(length, new MyRandom(seed)); - } - } - } - - private static void testEmptyAndNullIntArray() { - ourDescription = "Check empty and null array"; - Arrays.parallelSort(new int[]{}); - Arrays.parallelSort(new int[]{}, 0, 0); - - try { - Arrays.parallelSort((int[]) null); - } catch (NullPointerException expected) { - try { - Arrays.parallelSort((int[]) null, 0, 0); - } catch (NullPointerException expected2) { - return; - } - failed("Arrays.parallelSort(int[],fromIndex,toIndex) shouldn't " + - "catch null array"); - } - failed("Arrays.parallelSort(int[]) shouldn't catch null array"); - } - - private static void testEmptyAndNullLongArray() { - ourDescription = "Check empty and null array"; - Arrays.parallelSort(new long[]{}); - Arrays.parallelSort(new long[]{}, 0, 0); - - try { - Arrays.parallelSort((long[]) null); - } catch (NullPointerException expected) { - try { - Arrays.parallelSort((long[]) null, 0, 0); - } catch (NullPointerException expected2) { - return; - } - failed("Arrays.parallelSort(long[],fromIndex,toIndex) shouldn't " + - "catch null array"); - } - failed("Arrays.parallelSort(long[]) shouldn't catch null array"); - } - - private static void testEmptyAndNullShortArray() { - ourDescription = "Check empty and null array"; - Arrays.parallelSort(new short[]{}); - Arrays.parallelSort(new short[]{}, 0, 0); - - try { - Arrays.parallelSort((short[]) null); - } catch (NullPointerException expected) { - try { - Arrays.parallelSort((short[]) null, 0, 0); - } catch (NullPointerException expected2) { - return; - } - failed("Arrays.parallelSort(short[],fromIndex,toIndex) shouldn't " + - "catch null array"); - } - failed("Arrays.parallelSort(short[]) shouldn't catch null array"); - } - - private static void testEmptyAndNullCharArray() { - ourDescription = "Check empty and null array"; - Arrays.parallelSort(new char[]{}); - Arrays.parallelSort(new char[]{}, 0, 0); - - try { - Arrays.parallelSort((char[]) null); - } catch (NullPointerException expected) { - try { - Arrays.parallelSort((char[]) null, 0, 0); - } catch (NullPointerException expected2) { - return; - } - failed("Arrays.parallelSort(char[],fromIndex,toIndex) shouldn't " + - "catch null array"); - } - failed("Arrays.parallelSort(char[]) shouldn't catch null array"); - } - - private static void testEmptyAndNullByteArray() { - ourDescription = "Check empty and null array"; - Arrays.parallelSort(new byte[]{}); - Arrays.parallelSort(new byte[]{}, 0, 0); - - try { - Arrays.parallelSort((byte[]) null); - } catch (NullPointerException expected) { - try { - Arrays.parallelSort((byte[]) null, 0, 0); - } catch (NullPointerException expected2) { - return; - } - failed("Arrays.parallelSort(byte[],fromIndex,toIndex) shouldn't " + - "catch null array"); - } - failed("Arrays.parallelSort(byte[]) shouldn't catch null array"); - } - - private static void testEmptyAndNullFloatArray() { - ourDescription = "Check empty and null array"; - Arrays.parallelSort(new float[]{}); - Arrays.parallelSort(new float[]{}, 0, 0); - - try { - Arrays.parallelSort((float[]) null); - } catch (NullPointerException expected) { - try { - Arrays.parallelSort((float[]) null, 0, 0); - } catch (NullPointerException expected2) { - return; - } - failed("Arrays.parallelSort(float[],fromIndex,toIndex) shouldn't " + - "catch null array"); - } - failed("Arrays.parallelSort(float[]) shouldn't catch null array"); - } - - private static void testEmptyAndNullDoubleArray() { - ourDescription = "Check empty and null array"; - Arrays.parallelSort(new double[]{}); - Arrays.parallelSort(new double[]{}, 0, 0); - - try { - Arrays.parallelSort((double[]) null); - } catch (NullPointerException expected) { - try { - Arrays.parallelSort((double[]) null, 0, 0); - } catch (NullPointerException expected2) { - return; - } - failed("Arrays.parallelSort(double[],fromIndex,toIndex) shouldn't " + - "catch null array"); - } - failed("Arrays.parallelSort(double[]) shouldn't catch null array"); - } - - private static void testAndCheckSubArray(int length) { - ourDescription = "Check sorting of subarray"; - int[] golden = new int[length]; - boolean newLine = false; - - for (int m = 1; m < length / 2; m *= 2) { - newLine = true; - int fromIndex = m; - int toIndex = length - m; - - prepareSubArray(golden, fromIndex, toIndex, m); - int[] test = golden.clone(); - - for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'subarray': " + converter + - " length = " + length + ", m = " + m); - Object convertedGolden = converter.convert(golden); - Object convertedTest = converter.convert(test); - sortSubArray(convertedTest, fromIndex, toIndex); - checkSubArray(convertedTest, fromIndex, toIndex, m); - } - } - if (newLine) { - out.println(); - } - } - - private static void testAndCheckRange(int length) { - ourDescription = "Check range check"; - int[] golden = new int[length]; - - for (int m = 1; m < 2 * length; m *= 2) { - for (int i = 1; i <= length; i++) { - golden[i - 1] = i % m + m % i; - } - for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'range': " + converter + - ", length = " + length + ", m = " + m); - Object convertedGolden = converter.convert(golden); - checkRange(convertedGolden, m); - } - } - out.println(); - } - - private static void testStable(int length, MyRandom random) { - ourDescription = "Check if sorting is stable"; - Pair[] a = build(length, random); - - out.println("Test 'stable': " + "random = " + random.getSeed() + - ", length = " + length); - Arrays.parallelSort(a); - checkSorted(a); - checkStable(a); - out.println(); - - a = build(length, random); - - out.println("Test 'stable' comparator: " + "random = " + random.getSeed() + - ", length = " + length); - Arrays.parallelSort(a, pairCmp); - checkSorted(a); - checkStable(a); - out.println(); - - } - - private static void checkSorted(Pair[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i].getKey() > a[i + 1].getKey()) { - failedSort(i, "" + a[i].getKey(), "" + a[i + 1].getKey()); - } - } - } - - private static void checkStable(Pair[] a) { - for (int i = 0; i < a.length / 4; ) { - int key1 = a[i].getKey(); - int value1 = a[i++].getValue(); - int key2 = a[i].getKey(); - int value2 = a[i++].getValue(); - int key3 = a[i].getKey(); - int value3 = a[i++].getValue(); - int key4 = a[i].getKey(); - int value4 = a[i++].getValue(); - - if (!(key1 == key2 && key2 == key3 && key3 == key4)) { - failed("On position " + i + " keys are different " + - key1 + ", " + key2 + ", " + key3 + ", " + key4); - } - if (!(value1 < value2 && value2 < value3 && value3 < value4)) { - failed("Sorting is not stable at position " + i + - ". Second values have been changed: " + value1 + ", " + - value2 + ", " + value3 + ", " + value4); - } - } - } - - private static Pair[] build(int length, Random random) { - Pair[] a = new Pair[length * 4]; - - for (int i = 0; i < a.length; ) { - int key = random.nextInt(); - a[i++] = new Pair(key, 1); - a[i++] = new Pair(key, 2); - a[i++] = new Pair(key, 3); - a[i++] = new Pair(key, 4); - } - return a; - } - - private static Comparator pairCmp = new Comparator() { - public int compare(Pair p1, Pair p2) { - return p1.compareTo(p2); - } - }; - - private static final class Pair implements Comparable { - Pair(int key, int value) { - myKey = key; - myValue = value; - } - - int getKey() { - return myKey; - } - - int getValue() { - return myValue; - } - - public int compareTo(Pair pair) { - if (myKey < pair.myKey) { - return -1; - } - if (myKey > pair.myKey) { - return 1; - } - return 0; - } - - @Override - public String toString() { - return "(" + myKey + ", " + myValue + ")"; - } - - private int myKey; - private int myValue; - } - - - private static void testAndCheckWithInsertionSort(int length, MyRandom random) { - if (length > 1000) { - return; - } - ourDescription = "Check sorting with insertion sort"; - int[] golden = new int[length]; - - for (int m = 1; m < 2 * length; m *= 2) { - for (UnsortedBuilder builder : UnsortedBuilder.values()) { - builder.build(golden, m, random); - int[] test = golden.clone(); - - for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'insertion sort': " + converter + - " " + builder + "random = " + random.getSeed() + - ", length = " + length + ", m = " + m); - Object convertedGolden = converter.convert(golden); - Object convertedTest1 = converter.convert(test); - Object convertedTest2 = converter.convert(test); - sort(convertedTest1); - sortByInsertionSort(convertedTest2); - compare(convertedTest1, convertedTest2); - } - } - } - out.println(); - } - - private static void testMergeSort(int length) { - if (length < 1000) { - return; - } - ourDescription = "Check merge sorting"; - int[] golden = new int[length]; - int period = 67; // java.util.DualPivotQuicksort.MAX_RUN_COUNT - - for (int m = period - 2; m <= period + 2; m++) { - for (MergeBuilder builder : MergeBuilder.values()) { - builder.build(golden, m); - int[] test = golden.clone(); - - for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'merge sort': " + converter + " " + - builder + "length = " + length + ", m = " + m); - Object convertedGolden = converter.convert(golden); - sort(convertedGolden); - checkSorted(convertedGolden); - } - } - } - out.println(); - } - - private static void testAndCheckWithCheckSum(int length, MyRandom random) { - ourDescription = "Check sorting with check sum"; - int[] golden = new int[length]; - - for (int m = 1; m < 2 * length; m *= 2) { - for (UnsortedBuilder builder : UnsortedBuilder.values()) { - builder.build(golden, m, random); - int[] test = golden.clone(); - - for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'check sum': " + converter + - " " + builder + "random = " + random.getSeed() + - ", length = " + length + ", m = " + m); - Object convertedGolden = converter.convert(golden); - Object convertedTest = converter.convert(test); - sort(convertedTest); - checkWithCheckSum(convertedTest, convertedGolden); - } - } - } - out.println(); - } - - private static void testAndCheckWithScrambling(int length, MyRandom random) { - ourDescription = "Check sorting with scrambling"; - int[] golden = new int[length]; - - for (int m = 1; m <= 7; m++) { - if (m > length) { - break; - } - for (SortedBuilder builder : SortedBuilder.values()) { - builder.build(golden, m); - int[] test = golden.clone(); - scramble(test, random); - - for (TypeConverter converter : TypeConverter.values()) { - out.println("Test 'scrambling': " + converter + - " " + builder + "random = " + random.getSeed() + - ", length = " + length + ", m = " + m); - Object convertedGolden = converter.convert(golden); - Object convertedTest = converter.convert(test); - sort(convertedTest); - compare(convertedTest, convertedGolden); - } - } - } - out.println(); - } - - private static void testAndCheckFloat(int length, MyRandom random) { - ourDescription = "Check float sorting"; - float[] golden = new float[length]; - final int MAX = 10; - boolean newLine = false; - - for (int a = 0; a <= MAX; a++) { - for (int g = 0; g <= MAX; g++) { - for (int z = 0; z <= MAX; z++) { - for (int n = 0; n <= MAX; n++) { - for (int p = 0; p <= MAX; p++) { - if (a + g + z + n + p > length) { - continue; - } - if (a + g + z + n + p < length) { - continue; - } - for (FloatBuilder builder : FloatBuilder.values()) { - out.println("Test 'float': random = " + random.getSeed() + - ", length = " + length + ", a = " + a + ", g = " + - g + ", z = " + z + ", n = " + n + ", p = " + p); - builder.build(golden, a, g, z, n, p, random); - float[] test = golden.clone(); - scramble(test, random); - sort(test); - compare(test, golden, a, n, g); - } - newLine = true; - } - } - } - } - } - if (newLine) { - out.println(); - } - } - - private static void testAndCheckDouble(int length, MyRandom random) { - ourDescription = "Check double sorting"; - double[] golden = new double[length]; - final int MAX = 10; - boolean newLine = false; - - for (int a = 0; a <= MAX; a++) { - for (int g = 0; g <= MAX; g++) { - for (int z = 0; z <= MAX; z++) { - for (int n = 0; n <= MAX; n++) { - for (int p = 0; p <= MAX; p++) { - if (a + g + z + n + p > length) { - continue; - } - if (a + g + z + n + p < length) { - continue; - } - for (DoubleBuilder builder : DoubleBuilder.values()) { - out.println("Test 'double': random = " + random.getSeed() + - ", length = " + length + ", a = " + a + ", g = " + - g + ", z = " + z + ", n = " + n + ", p = " + p); - builder.build(golden, a, g, z, n, p, random); - double[] test = golden.clone(); - scramble(test, random); - sort(test); - compare(test, golden, a, n, g); - } - newLine = true; - } - } - } - } - } - if (newLine) { - out.println(); - } - } - - private static void prepareSubArray(int[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - a[i] = 0xDEDA; - } - int middle = (fromIndex + toIndex) >>> 1; - int k = 0; - - for (int i = fromIndex; i < middle; i++) { - a[i] = k++; - } - for (int i = middle; i < toIndex; i++) { - a[i] = k--; - } - for (int i = toIndex; i < a.length; i++) { - a[i] = 0xBABA; - } - } - - private static void scramble(int[] a, Random random) { - for (int i = 0; i < a.length * 7; i++) { - swap(a, random.nextInt(a.length), random.nextInt(a.length)); - } - } - - private static void scramble(float[] a, Random random) { - for (int i = 0; i < a.length * 7; i++) { - swap(a, random.nextInt(a.length), random.nextInt(a.length)); - } - } - - private static void scramble(double[] a, Random random) { - for (int i = 0; i < a.length * 7; i++) { - swap(a, random.nextInt(a.length), random.nextInt(a.length)); - } - } - - private static void swap(int[] a, int i, int j) { - int t = a[i]; - a[i] = a[j]; - a[j] = t; - } - - private static void swap(float[] a, int i, int j) { - float t = a[i]; - a[i] = a[j]; - a[j] = t; - } - - private static void swap(double[] a, int i, int j) { - double t = a[i]; - a[i] = a[j]; - a[j] = t; - } - - private static enum TypeConverter { - INT { - Object convert(int[] a) { - return a.clone(); - } - }, - LONG { - Object convert(int[] a) { - long[] b = new long[a.length]; - - for (int i = 0; i < a.length; i++) { - b[i] = (long) a[i]; - } - return b; - } - }, - BYTE { - Object convert(int[] a) { - byte[] b = new byte[a.length]; - - for (int i = 0; i < a.length; i++) { - b[i] = (byte) a[i]; - } - return b; - } - }, - SHORT { - Object convert(int[] a) { - short[] b = new short[a.length]; - - for (int i = 0; i < a.length; i++) { - b[i] = (short) a[i]; - } - return b; - } - }, - CHAR { - Object convert(int[] a) { - char[] b = new char[a.length]; - - for (int i = 0; i < a.length; i++) { - b[i] = (char) a[i]; - } - return b; - } - }, - FLOAT { - Object convert(int[] a) { - float[] b = new float[a.length]; - - for (int i = 0; i < a.length; i++) { - b[i] = (float) a[i]; - } - return b; - } - }, - DOUBLE { - Object convert(int[] a) { - double[] b = new double[a.length]; - - for (int i = 0; i < a.length; i++) { - b[i] = (double) a[i]; - } - return b; - } - }, - INTEGER { - Object convert(int[] a) { - Integer[] b = new Integer[a.length]; - - for (int i = 0; i < a.length; i++) { - b[i] = new Integer(a[i]); - } - return b; - } - }; - - abstract Object convert(int[] a); - - @Override public String toString() { - String name = name(); - - for (int i = name.length(); i < 9; i++) { - name += " "; - } - return name; - } - } - - private static enum FloatBuilder { - SIMPLE { - void build(float[] x, int a, int g, int z, int n, int p, Random random) { - int fromIndex = 0; - float negativeValue = -random.nextFloat(); - float positiveValue = random.nextFloat(); - - writeValue(x, negativeValue, fromIndex, n); - fromIndex += n; - - writeValue(x, -0.0f, fromIndex, g); - fromIndex += g; - - writeValue(x, 0.0f, fromIndex, z); - fromIndex += z; - - writeValue(x, positiveValue, fromIndex, p); - fromIndex += p; - - writeValue(x, Float.NaN, fromIndex, a); - } - }; - - abstract void build(float[] x, int a, int g, int z, int n, int p, Random random); - } - - private static enum DoubleBuilder { - SIMPLE { - void build(double[] x, int a, int g, int z, int n, int p, Random random) { - int fromIndex = 0; - double negativeValue = -random.nextFloat(); - double positiveValue = random.nextFloat(); - - writeValue(x, negativeValue, fromIndex, n); - fromIndex += n; - - writeValue(x, -0.0d, fromIndex, g); - fromIndex += g; - - writeValue(x, 0.0d, fromIndex, z); - fromIndex += z; - - writeValue(x, positiveValue, fromIndex, p); - fromIndex += p; - - writeValue(x, Double.NaN, fromIndex, a); - } - }; - - abstract void build(double[] x, int a, int g, int z, int n, int p, Random random); - } - - private static void writeValue(float[] a, float value, int fromIndex, int count) { - for (int i = fromIndex; i < fromIndex + count; i++) { - a[i] = value; - } - } - - private static void compare(float[] a, float[] b, int numNaN, int numNeg, int numNegZero) { - for (int i = a.length - numNaN; i < a.length; i++) { - if (a[i] == a[i]) { - failed("On position " + i + " must be NaN instead of " + a[i]); - } - } - final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f); - - for (int i = numNeg; i < numNeg + numNegZero; i++) { - if (NEGATIVE_ZERO != Float.floatToIntBits(a[i])) { - failed("On position " + i + " must be -0.0 instead of " + a[i]); - } - } - for (int i = 0; i < a.length - numNaN; i++) { - if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static void writeValue(double[] a, double value, int fromIndex, int count) { - for (int i = fromIndex; i < fromIndex + count; i++) { - a[i] = value; - } - } - - private static void compare(double[] a, double[] b, int numNaN, int numNeg, int numNegZero) { - for (int i = a.length - numNaN; i < a.length; i++) { - if (a[i] == a[i]) { - failed("On position " + i + " must be NaN instead of " + a[i]); - } - } - final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d); - - for (int i = numNeg; i < numNeg + numNegZero; i++) { - if (NEGATIVE_ZERO != Double.doubleToLongBits(a[i])) { - failed("On position " + i + " must be -0.0 instead of " + a[i]); - } - } - for (int i = 0; i < a.length - numNaN; i++) { - if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static enum SortedBuilder { - REPEATED { - void build(int[] a, int m) { - int period = a.length / m; - int i = 0; - int k = 0; - - while (true) { - for (int t = 1; t <= period; t++) { - if (i >= a.length) { - return; - } - a[i++] = k; - } - if (i >= a.length) { - return; - } - k++; - } - } - }, - ORGAN_PIPES { - void build(int[] a, int m) { - int i = 0; - int k = m; - - while (true) { - for (int t = 1; t <= m; t++) { - if (i >= a.length) { - return; - } - a[i++] = k; - } - } - } - }; - - abstract void build(int[] a, int m); - - @Override public String toString() { - String name = name(); - - for (int i = name.length(); i < 12; i++) { - name += " "; - } - return name; - } - } - - private static enum MergeBuilder { - ASCENDING { - void build(int[] a, int m) { - int period = a.length / m; - int v = 1, i = 0; - - for (int k = 0; k < m; k++) { - v = 1; - for (int p = 0; p < period; p++) { - a[i++] = v++; - } - } - for (int j = i; j < a.length - 1; j++) { - a[j] = v++; - } - a[a.length - 1] = 0; - } - }, - DESCENDING { - void build(int[] a, int m) { - int period = a.length / m; - int v = -1, i = 0; - - for (int k = 0; k < m; k++) { - v = -1; - for (int p = 0; p < period; p++) { - a[i++] = v--; - } - } - for (int j = i; j < a.length - 1; j++) { - a[j] = v--; - } - a[a.length - 1] = 0; - } - }; - - abstract void build(int[] a, int m); - - @Override public String toString() { - String name = name(); - - for (int i = name.length(); i < 12; i++) { - name += " "; - } - return name; - } - } - - private static enum UnsortedBuilder { - RANDOM { - void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { - a[i] = random.nextInt(); - } - } - }, - ASCENDING { - void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { - a[i] = m + i; - } - } - }, - DESCENDING { - void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { - a[i] = a.length - m - i; - } - } - }, - ALL_EQUAL { - void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { - a[i] = m; - } - } - }, - SAW { - void build(int[] a, int m, Random random) { - int incCount = 1; - int decCount = a.length; - int i = 0; - int period = m--; - - while (true) { - for (int k = 1; k <= period; k++) { - if (i >= a.length) { - return; - } - a[i++] = incCount++; - } - period += m; - - for (int k = 1; k <= period; k++) { - if (i >= a.length) { - return; - } - a[i++] = decCount--; - } - period += m; - } - } - }, - REPEATED { - void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { - a[i] = i % m; - } - } - }, - DUPLICATED { - void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { - a[i] = random.nextInt(m); - } - } - }, - ORGAN_PIPES { - void build(int[] a, int m, Random random) { - int middle = a.length / (m + 1); - - for (int i = 0; i < middle; i++) { - a[i] = i; - } - for (int i = middle; i < a.length; i++) { - a[i] = a.length - i - 1; - } - } - }, - STAGGER { - void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { - a[i] = (i * m + i) % a.length; - } - } - }, - PLATEAU { - void build(int[] a, int m, Random random) { - for (int i = 0; i < a.length; i++) { - a[i] = Math.min(i, m); - } - } - }, - SHUFFLE { - void build(int[] a, int m, Random random) { - int x = 0, y = 0; - for (int i = 0; i < a.length; i++) { - a[i] = random.nextBoolean() ? (x += 2) : (y += 2); - } - } - }; - - abstract void build(int[] a, int m, Random random); - - @Override public String toString() { - String name = name(); - - for (int i = name.length(); i < 12; i++) { - name += " "; - } - return name; - } - } - - private static void checkWithCheckSum(Object test, Object golden) { - checkSorted(test); - checkCheckSum(test, golden); - } - - private static void failed(String message) { - err.format("\n*** TEST FAILED - %s.\n\n%s.\n\n", ourDescription, message); - throw new RuntimeException("Test failed - see log file for details"); - } - - private static void failedSort(int index, String value1, String value2) { - failed("Array is not sorted at " + index + "-th position: " + - value1 + " and " + value2); - } - - private static void failedCompare(int index, String value1, String value2) { - failed("On position " + index + " must be " + value2 + " instead of " + value1); - } - - private static void compare(Object test, Object golden) { - if (test instanceof int[]) { - compare((int[]) test, (int[]) golden); - } else if (test instanceof long[]) { - compare((long[]) test, (long[]) golden); - } else if (test instanceof short[]) { - compare((short[]) test, (short[]) golden); - } else if (test instanceof byte[]) { - compare((byte[]) test, (byte[]) golden); - } else if (test instanceof char[]) { - compare((char[]) test, (char[]) golden); - } else if (test instanceof float[]) { - compare((float[]) test, (float[]) golden); - } else if (test instanceof double[]) { - compare((double[]) test, (double[]) golden); - } else if (test instanceof Integer[]) { - compare((Integer[]) test, (Integer[]) golden); - } else { - failed("Unknow type of array: " + test + " of class " + - test.getClass().getName()); - } - } - - private static void compare(int[] a, int[] b) { - for (int i = 0; i < a.length; i++) { - if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static void compare(long[] a, long[] b) { - for (int i = 0; i < a.length; i++) { - if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static void compare(short[] a, short[] b) { - for (int i = 0; i < a.length; i++) { - if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static void compare(byte[] a, byte[] b) { - for (int i = 0; i < a.length; i++) { - if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static void compare(char[] a, char[] b) { - for (int i = 0; i < a.length; i++) { - if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static void compare(float[] a, float[] b) { - for (int i = 0; i < a.length; i++) { - if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static void compare(double[] a, double[] b) { - for (int i = 0; i < a.length; i++) { - if (a[i] != b[i]) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static void compare(Integer[] a, Integer[] b) { - for (int i = 0; i < a.length; i++) { - if (a[i].compareTo(b[i]) != 0) { - failedCompare(i, "" + a[i], "" + b[i]); - } - } - } - - private static void checkSorted(Object object) { - if (object instanceof int[]) { - checkSorted((int[]) object); - } else if (object instanceof long[]) { - checkSorted((long[]) object); - } else if (object instanceof short[]) { - checkSorted((short[]) object); - } else if (object instanceof byte[]) { - checkSorted((byte[]) object); - } else if (object instanceof char[]) { - checkSorted((char[]) object); - } else if (object instanceof float[]) { - checkSorted((float[]) object); - } else if (object instanceof double[]) { - checkSorted((double[]) object); - } else if (object instanceof Integer[]) { - checkSorted((Integer[]) object); - } else { - failed("Unknow type of array: " + object + " of class " + - object.getClass().getName()); - } - } - - private static void checkSorted(int[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - } - - private static void checkSorted(long[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - } - - private static void checkSorted(short[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - } - - private static void checkSorted(byte[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - } - - private static void checkSorted(char[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - } - - private static void checkSorted(float[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - } - - private static void checkSorted(double[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - } - - private static void checkSorted(Integer[] a) { - for (int i = 0; i < a.length - 1; i++) { - if (a[i].intValue() > a[i + 1].intValue()) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - } - - private static void checkCheckSum(Object test, Object golden) { - if (checkSumXor(test) != checkSumXor(golden)) { - failed("Original and sorted arrays are not identical [xor]"); - } - if (checkSumPlus(test) != checkSumPlus(golden)) { - failed("Original and sorted arrays are not identical [plus]"); - } - } - - private static int checkSumXor(Object object) { - if (object instanceof int[]) { - return checkSumXor((int[]) object); - } else if (object instanceof long[]) { - return checkSumXor((long[]) object); - } else if (object instanceof short[]) { - return checkSumXor((short[]) object); - } else if (object instanceof byte[]) { - return checkSumXor((byte[]) object); - } else if (object instanceof char[]) { - return checkSumXor((char[]) object); - } else if (object instanceof float[]) { - return checkSumXor((float[]) object); - } else if (object instanceof double[]) { - return checkSumXor((double[]) object); - } else if (object instanceof Integer[]) { - return checkSumXor((Integer[]) object); - } else { - failed("Unknow type of array: " + object + " of class " + - object.getClass().getName()); - return -1; - } - } - - private static int checkSumXor(Integer[] a) { - int checkSum = 0; - - for (Integer e : a) { - checkSum ^= e.intValue(); - } - return checkSum; - } - - private static int checkSumXor(int[] a) { - int checkSum = 0; - - for (int e : a) { - checkSum ^= e; - } - return checkSum; - } - - private static int checkSumXor(long[] a) { - long checkSum = 0; - - for (long e : a) { - checkSum ^= e; - } - return (int) checkSum; - } - - private static int checkSumXor(short[] a) { - short checkSum = 0; - - for (short e : a) { - checkSum ^= e; - } - return (int) checkSum; - } - - private static int checkSumXor(byte[] a) { - byte checkSum = 0; - - for (byte e : a) { - checkSum ^= e; - } - return (int) checkSum; - } - - private static int checkSumXor(char[] a) { - char checkSum = 0; - - for (char e : a) { - checkSum ^= e; - } - return (int) checkSum; - } - - private static int checkSumXor(float[] a) { - int checkSum = 0; - - for (float e : a) { - checkSum ^= (int) e; - } - return checkSum; - } - - private static int checkSumXor(double[] a) { - int checkSum = 0; - - for (double e : a) { - checkSum ^= (int) e; - } - return checkSum; - } - - private static int checkSumPlus(Object object) { - if (object instanceof int[]) { - return checkSumPlus((int[]) object); - } else if (object instanceof long[]) { - return checkSumPlus((long[]) object); - } else if (object instanceof short[]) { - return checkSumPlus((short[]) object); - } else if (object instanceof byte[]) { - return checkSumPlus((byte[]) object); - } else if (object instanceof char[]) { - return checkSumPlus((char[]) object); - } else if (object instanceof float[]) { - return checkSumPlus((float[]) object); - } else if (object instanceof double[]) { - return checkSumPlus((double[]) object); - } else if (object instanceof Integer[]) { - return checkSumPlus((Integer[]) object); - } else { - failed("Unknow type of array: " + object + " of class " + - object.getClass().getName()); - return -1; - } - } - - private static int checkSumPlus(int[] a) { - int checkSum = 0; - - for (int e : a) { - checkSum += e; - } - return checkSum; - } - - private static int checkSumPlus(long[] a) { - long checkSum = 0; - - for (long e : a) { - checkSum += e; - } - return (int) checkSum; - } - - private static int checkSumPlus(short[] a) { - short checkSum = 0; - - for (short e : a) { - checkSum += e; - } - return (int) checkSum; - } - - private static int checkSumPlus(byte[] a) { - byte checkSum = 0; - - for (byte e : a) { - checkSum += e; - } - return (int) checkSum; - } - - private static int checkSumPlus(char[] a) { - char checkSum = 0; - - for (char e : a) { - checkSum += e; - } - return (int) checkSum; - } - - private static int checkSumPlus(float[] a) { - int checkSum = 0; - - for (float e : a) { - checkSum += (int) e; - } - return checkSum; - } - - private static int checkSumPlus(double[] a) { - int checkSum = 0; - - for (double e : a) { - checkSum += (int) e; - } - return checkSum; - } - - private static int checkSumPlus(Integer[] a) { - int checkSum = 0; - - for (Integer e : a) { - checkSum += e.intValue(); - } - return checkSum; - } - - private static void sortByInsertionSort(Object object) { - if (object instanceof int[]) { - sortByInsertionSort((int[]) object); - } else if (object instanceof long[]) { - sortByInsertionSort((long[]) object); - } else if (object instanceof short[]) { - sortByInsertionSort((short[]) object); - } else if (object instanceof byte[]) { - sortByInsertionSort((byte[]) object); - } else if (object instanceof char[]) { - sortByInsertionSort((char[]) object); - } else if (object instanceof float[]) { - sortByInsertionSort((float[]) object); - } else if (object instanceof double[]) { - sortByInsertionSort((double[]) object); - } else if (object instanceof Integer[]) { - sortByInsertionSort((Integer[]) object); - } else { - failed("Unknow type of array: " + object + " of class " + - object.getClass().getName()); - } - } - - private static void sortByInsertionSort(int[] a) { - for (int j, i = 1; i < a.length; i++) { - int ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } - - private static void sortByInsertionSort(long[] a) { - for (int j, i = 1; i < a.length; i++) { - long ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } - - private static void sortByInsertionSort(short[] a) { - for (int j, i = 1; i < a.length; i++) { - short ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } - - private static void sortByInsertionSort(byte[] a) { - for (int j, i = 1; i < a.length; i++) { - byte ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } - - private static void sortByInsertionSort(char[] a) { - for (int j, i = 1; i < a.length; i++) { - char ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } - - private static void sortByInsertionSort(float[] a) { - for (int j, i = 1; i < a.length; i++) { - float ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } - - private static void sortByInsertionSort(double[] a) { - for (int j, i = 1; i < a.length; i++) { - double ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } - - private static void sortByInsertionSort(Integer[] a) { - for (int j, i = 1; i < a.length; i++) { - Integer ai = a[i]; - for (j = i - 1; j >= 0 && ai < a[j]; j--) { - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } - - private static void sort(Object object) { - if (object instanceof int[]) { - Arrays.parallelSort((int[]) object); - } else if (object instanceof long[]) { - Arrays.parallelSort((long[]) object); - } else if (object instanceof short[]) { - Arrays.parallelSort((short[]) object); - } else if (object instanceof byte[]) { - Arrays.parallelSort((byte[]) object); - } else if (object instanceof char[]) { - Arrays.parallelSort((char[]) object); - } else if (object instanceof float[]) { - Arrays.parallelSort((float[]) object); - } else if (object instanceof double[]) { - Arrays.parallelSort((double[]) object); - } else if (object instanceof Integer[]) { - Arrays.parallelSort((Integer[]) object); - } else { - failed("Unknow type of array: " + object + " of class " + - object.getClass().getName()); - } - } - - private static void sortSubArray(Object object, int fromIndex, int toIndex) { - if (object instanceof int[]) { - Arrays.parallelSort((int[]) object, fromIndex, toIndex); - } else if (object instanceof long[]) { - Arrays.parallelSort((long[]) object, fromIndex, toIndex); - } else if (object instanceof short[]) { - Arrays.parallelSort((short[]) object, fromIndex, toIndex); - } else if (object instanceof byte[]) { - Arrays.parallelSort((byte[]) object, fromIndex, toIndex); - } else if (object instanceof char[]) { - Arrays.parallelSort((char[]) object, fromIndex, toIndex); - } else if (object instanceof float[]) { - Arrays.parallelSort((float[]) object, fromIndex, toIndex); - } else if (object instanceof double[]) { - Arrays.parallelSort((double[]) object, fromIndex, toIndex); - } else if (object instanceof Integer[]) { - Arrays.parallelSort((Integer[]) object, fromIndex, toIndex); - } else { - failed("Unknow type of array: " + object + " of class " + - object.getClass().getName()); - } - } - - private static void checkSubArray(Object object, int fromIndex, int toIndex, int m) { - if (object instanceof int[]) { - checkSubArray((int[]) object, fromIndex, toIndex, m); - } else if (object instanceof long[]) { - checkSubArray((long[]) object, fromIndex, toIndex, m); - } else if (object instanceof short[]) { - checkSubArray((short[]) object, fromIndex, toIndex, m); - } else if (object instanceof byte[]) { - checkSubArray((byte[]) object, fromIndex, toIndex, m); - } else if (object instanceof char[]) { - checkSubArray((char[]) object, fromIndex, toIndex, m); - } else if (object instanceof float[]) { - checkSubArray((float[]) object, fromIndex, toIndex, m); - } else if (object instanceof double[]) { - checkSubArray((double[]) object, fromIndex, toIndex, m); - } else if (object instanceof Integer[]) { - checkSubArray((Integer[]) object, fromIndex, toIndex, m); - } else { - failed("Unknow type of array: " + object + " of class " + - object.getClass().getName()); - } - } - - private static void checkSubArray(Integer[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i].intValue() != 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); - } - } - - for (int i = fromIndex; i < toIndex - 1; i++) { - if (a[i].intValue() > a[i + 1].intValue()) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - - for (int i = toIndex; i < a.length; i++) { - if (a[i].intValue() != 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); - } - } - } - - private static void checkSubArray(int[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); - } - } - - for (int i = fromIndex; i < toIndex - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - - for (int i = toIndex; i < a.length; i++) { - if (a[i] != 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); - } - } - } - - private static void checkSubArray(byte[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (byte) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); - } - } - - for (int i = fromIndex; i < toIndex - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (byte) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); - } - } - } - - private static void checkSubArray(long[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (long) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); - } - } - - for (int i = fromIndex; i < toIndex - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (long) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); - } - } - } - - private static void checkSubArray(char[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (char) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); - } - } - - for (int i = fromIndex; i < toIndex - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (char) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); - } - } - } - - private static void checkSubArray(short[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (short) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); - } - } - - for (int i = fromIndex; i < toIndex - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (short) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); - } - } - } - - private static void checkSubArray(float[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (float) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); - } - } - - for (int i = fromIndex; i < toIndex - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (float) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); - } - } - } - - private static void checkSubArray(double[] a, int fromIndex, int toIndex, int m) { - for (int i = 0; i < fromIndex; i++) { - if (a[i] != (double) 0xDEDA) { - failed("Range sort changes left element on position " + i + - ": " + a[i] + ", must be " + 0xDEDA); - } - } - - for (int i = fromIndex; i < toIndex - 1; i++) { - if (a[i] > a[i + 1]) { - failedSort(i, "" + a[i], "" + a[i + 1]); - } - } - - for (int i = toIndex; i < a.length; i++) { - if (a[i] != (double) 0xBABA) { - failed("Range sort changes right element on position " + i + - ": " + a[i] + ", must be " + 0xBABA); - } - } - } - - private static void checkRange(Object object, int m) { - if (object instanceof int[]) { - checkRange((int[]) object, m); - } else if (object instanceof long[]) { - checkRange((long[]) object, m); - } else if (object instanceof short[]) { - checkRange((short[]) object, m); - } else if (object instanceof byte[]) { - checkRange((byte[]) object, m); - } else if (object instanceof char[]) { - checkRange((char[]) object, m); - } else if (object instanceof float[]) { - checkRange((float[]) object, m); - } else if (object instanceof double[]) { - checkRange((double[]) object, m); - } else if (object instanceof Integer[]) { - checkRange((Integer[]) object, m); - } else { - failed("Unknow type of array: " + object + " of class " + - object.getClass().getName()); - } - } - - private static void checkRange(Integer[] a, int m) { - try { - Arrays.parallelSort(a, m + 1, m); - - failed("ParallelSort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { - try { - Arrays.parallelSort(a, -m, a.length); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { - try { - Arrays.parallelSort(a, 0, a.length + m); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; - } - } - } - } - - private static void checkRange(int[] a, int m) { - try { - Arrays.parallelSort(a, m + 1, m); - - failed("ParallelSort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { - try { - Arrays.parallelSort(a, -m, a.length); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { - try { - Arrays.parallelSort(a, 0, a.length + m); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; - } - } - } - } - - private static void checkRange(long[] a, int m) { - try { - Arrays.parallelSort(a, m + 1, m); - - failed("ParallelSort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { - try { - Arrays.parallelSort(a, -m, a.length); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { - try { - Arrays.parallelSort(a, 0, a.length + m); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; - } - } - } - } - - private static void checkRange(byte[] a, int m) { - try { - Arrays.parallelSort(a, m + 1, m); - - failed("ParallelSort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { - try { - Arrays.parallelSort(a, -m, a.length); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { - try { - Arrays.parallelSort(a, 0, a.length + m); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; - } - } - } - } - - private static void checkRange(short[] a, int m) { - try { - Arrays.parallelSort(a, m + 1, m); - - failed("ParallelSort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { - try { - Arrays.parallelSort(a, -m, a.length); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { - try { - Arrays.parallelSort(a, 0, a.length + m); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; - } - } - } - } - - private static void checkRange(char[] a, int m) { - try { - Arrays.parallelSort(a, m + 1, m); - - failed("ParallelSort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { - try { - Arrays.parallelSort(a, -m, a.length); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { - try { - Arrays.parallelSort(a, 0, a.length + m); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; - } - } - } - } - - private static void checkRange(float[] a, int m) { - try { - Arrays.parallelSort(a, m + 1, m); - - failed("ParallelSort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { - try { - Arrays.parallelSort(a, -m, a.length); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { - try { - Arrays.parallelSort(a, 0, a.length + m); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; - } - } - } - } - - private static void checkRange(double[] a, int m) { - try { - Arrays.parallelSort(a, m + 1, m); - - failed("ParallelSort does not throw IllegalArgumentException " + - " as expected: fromIndex = " + (m + 1) + - " toIndex = " + m); - } - catch (IllegalArgumentException iae) { - try { - Arrays.parallelSort(a, -m, a.length); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: fromIndex = " + (-m)); - } - catch (ArrayIndexOutOfBoundsException aoe) { - try { - Arrays.parallelSort(a, 0, a.length + m); - - failed("ParallelSort does not throw ArrayIndexOutOfBoundsException " + - " as expected: toIndex = " + (a.length + m)); - } - catch (ArrayIndexOutOfBoundsException aie) { - return; - } - } - } - } - - private static void outArray(Object[] a) { - for (int i = 0; i < a.length; i++) { - out.print(a[i] + " "); - } - out.println(); - } - - private static void outArray(int[] a) { - for (int i = 0; i < a.length; i++) { - out.print(a[i] + " "); - } - out.println(); - } - - private static void outArray(float[] a) { - for (int i = 0; i < a.length; i++) { - out.print(a[i] + " "); - } - out.println(); - } - - private static void outArray(double[] a) { - for (int i = 0; i < a.length; i++) { - out.print(a[i] + " "); - } - out.println(); - } - - private static class MyRandom extends Random { - MyRandom(long seed) { - super(seed); - mySeed = seed; - } - - long getSeed() { - return mySeed; - } - - private long mySeed; - } - - private static String ourDescription; -} --- /dev/null 2019-07-17 10:17:39.064651967 +0200 +++ new/test/jdk/java/util/Arrays/java.base/java/util/SortingHelper.java 2019-07-17 17:04:38.524314288 +0200 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.util; + +/** + * This class provides access to package-private + * methods of DualPivotQuicksort class. + * + * @author Vladimir Yaroslavskiy + * + * @version 2018.08.18 + * + * @since 14 + */ +public final class SortingHelper { + + // Heap sort is invoked for this depth + private static final int BIG_DEPTH = 100; + + private static final SortingHelper DUAL_PIVOT_QUICKSORT_HELPER = new SortingHelper(0); + private static final SortingHelper PARALLEL_SORT_HELPER = new SortingHelper(87); + private static final SortingHelper HEAP_SORT_HELPER = new SortingHelper(-1); + + private int parallelism; + + public static SortingHelper getDualPivotQuicksortHelper() { + return DUAL_PIVOT_QUICKSORT_HELPER; + } + + public static SortingHelper getParallelSortHelper() { + return PARALLEL_SORT_HELPER; + } + + public static SortingHelper getHeapSortHelper() { + return HEAP_SORT_HELPER; + } + + private SortingHelper(int parallelism) { + this.parallelism = parallelism; + } + + public void sort(int[] a) { + if (parallelism < 0) { + DualPivotQuicksort.sort(null, a, BIG_DEPTH, 0, a.length); + } else { + DualPivotQuicksort.sort(a, parallelism, 0, a.length); + } + } + + public void sort(int[] a, int low, int high) { + Arrays.rangeCheck(a.length, low, high); + + if (parallelism < 0) { + DualPivotQuicksort.sort(null, a, BIG_DEPTH, low, high); + } else { + DualPivotQuicksort.sort(a, parallelism, low, high); + } + } + + public void sort(long[] a) { + if (parallelism < 0) { + DualPivotQuicksort.sort(null, a, BIG_DEPTH, 0, a.length); + } else { + DualPivotQuicksort.sort(a, parallelism, 0, a.length); + } + } + + public void sort(long[] a, int low, int high) { + Arrays.rangeCheck(a.length, low, high); + + if (parallelism < 0) { + DualPivotQuicksort.sort(null, a, BIG_DEPTH, low, high); + } else { + DualPivotQuicksort.sort(a, parallelism, low, high); + } + } + + public void sort(byte[] a) { + DualPivotQuicksort.sort(a, 0, a.length); + } + + public void sort(byte[] a, int low, int high) { + Arrays.rangeCheck(a.length, low, high); + DualPivotQuicksort.sort(a, low, high); + } + + public void sort(char[] a) { + if (parallelism < 0) { + DualPivotQuicksort.sort(a, BIG_DEPTH, 0, a.length); + } else { + DualPivotQuicksort.sort(a, 0, a.length); + } + } + + public void sort(char[] a, int low, int high) { + Arrays.rangeCheck(a.length, low, high); + + if (parallelism < 0) { + DualPivotQuicksort.sort(a, BIG_DEPTH, low, high); + } else { + DualPivotQuicksort.sort(a, low, high); + } + } + + public void sort(short[] a) { + if (parallelism < 0) { + DualPivotQuicksort.sort(a, BIG_DEPTH, 0, a.length); + } else { + DualPivotQuicksort.sort(a, 0, a.length); + } + } + + public void sort(short[] a, int low, int high) { + Arrays.rangeCheck(a.length, low, high); + + if (parallelism < 0) { + DualPivotQuicksort.sort(a, BIG_DEPTH, low, high); + } else { + DualPivotQuicksort.sort(a, low, high); + } + } + + public void sort(float[] a) { + if (parallelism < 0) { + DualPivotQuicksort.sort(null, a, BIG_DEPTH, 0, a.length); + } else { + DualPivotQuicksort.sort(a, parallelism, 0, a.length); + } + } + + public void sort(float[] a, int low, int high) { + Arrays.rangeCheck(a.length, low, high); + + if (parallelism < 0) { + DualPivotQuicksort.sort(null, a, BIG_DEPTH, low, high); + } else { + DualPivotQuicksort.sort(a, parallelism, low, high); + } + } + + public void sort(double[] a) { + if (parallelism < 0) { + DualPivotQuicksort.sort(null, a, BIG_DEPTH, 0, a.length); + } else { + DualPivotQuicksort.sort(a, parallelism, 0, a.length); + } + } + + public void sort(double[] a, int low, int high) { + Arrays.rangeCheck(a.length, low, high); + + if (parallelism < 0) { + DualPivotQuicksort.sort(null, a, BIG_DEPTH, low, high); + } else { + DualPivotQuicksort.sort(a, parallelism, low, high); + } + } + + @Override + public String toString() { + if (parallelism < 0) { + return "Heap sort"; + } + if (parallelism == 0) { + return "Dual-Pivot Quicksort"; + } + return "Parallel Sorting"; + } +}