/*
 * Copyright (C) 2002-2022 Sebastiano Vigna
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *
 *
 * For the sorting and binary search code:
 *
 * Copyright (C) 1999 CERN - European Organization for Nuclear Research.
 *
 *   Permission to use, copy, modify, distribute and sell this software and
 *   its documentation for any purpose is hereby granted without fee,
 *   provided that the above copyright notice appear in all copies and that
 *   both that copyright notice and this permission notice appear in
 *   supporting documentation. CERN makes no representations about the
 *   suitability of this software for any purpose. It is provided "as is"
 *   without expressed or implied warranty.
 */

package PACKAGE;

import it.unimi.dsi.fastutil.Arrays;
import it.unimi.dsi.fastutil.Hash;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveAction;

#if ! KEY_CLASS_Integer
import it.unimi.dsi.fastutil.ints.IntArrays;
#endif

#if KEYS_PRIMITIVE

#if ! KEY_CLASS_Boolean
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
#endif

/** A class providing static methods and objects that do useful things with type-specific arrays.
 *
 * <p>In particular, the {@code forceCapacity()}, {@code ensureCapacity()}, {@code grow()},
 * {@code trim()} and {@code setLength()} methods allow to handle
 * arrays much like array lists. This can be very useful when efficiency (or
 * syntactic simplicity) reasons make array lists unsuitable.
 *
 * <p>Note that {@link it.unimi.dsi.fastutil.io.BinIO} and {@link it.unimi.dsi.fastutil.io.TextIO}
 * contain several methods make it possible to load and save arrays of primitive types as sequences
 * of elements in {@link java.io.DataInput} format (i.e., not as objects) or as sequences of lines of text.
 *
 * <h2>Sorting</h2>
 *
 * <p>There are several sorting methods available. The main theme is that of letting you choose
 * the sorting algorithm you prefer (i.e., trading stability of mergesort for no memory allocation in quicksort).
 * 
 * <h3>Parallel operations</h3>
 * Some algorithms provide a parallel version that will by default use the
 * {@linkplain ForkJoinPool#commonPool() common pool}, but this can be overridden by calling the
 * function in a task already in the {@link ForkJoinPool} that the operation should run in. For example,
 * something along the lines of "{@code poolToParallelSortIn.invoke(() -> parallelQuickSort(arrayToSort))}" 
 * will run the parallel sort in {@code poolToParallelSortIn} instead of the default pool.
 *
 * Some algorithms also provide an explicit <em>indirect</em> sorting facility, which makes it possible
 * to sort an array using the values in another array as comparator.
 *
 * <p>However, if you wish to let the implementation choose an algorithm for you, both
 * {@link #stableSort} and {@link #unstableSort} methods are available, which dynamically
 * chooses an algorithm based on unspecified criteria (but most likely stability, array size, and array element type).
 *
 * <p>All comparison-based algorithm have an implementation based on a type-specific comparator.
 *
 * <p>As a general rule, sequential radix sort is significantly faster than quicksort or mergesort, in particular
 * on random-looking data. In
 * the parallel case, up to a few cores parallel radix sort is still the fastest, but at some point quicksort
 * exploits parallelism better.
 *
 * <p>If you are fine with not knowing exactly which algorithm will be run (in particular, not knowing exactly whether a support array will be allocated),
 * the dual-pivot parallel sorts in {@link java.util.Arrays}
 * are about 50% faster than the classical single-pivot implementation used here.
 *
 * <p>In any case, if sorting time is important I suggest that you benchmark your sorting load
 * with your data distribution and on your architecture.
 *
 * @see java.util.Arrays
 */

public final class ARRAYS {

#else

import java.util.Comparator;

/** A class providing static methods and objects that do useful things with type-specific arrays.
 *
 * In particular, the {@code ensureCapacity()}, {@code grow()},
 * {@code trim()} and {@code setLength()} methods allow to handle
 * arrays much like array lists. This can be very useful when efficiency (or
 * syntactic simplicity) reasons make array lists unsuitable.
 *
 * <p><strong>Warning:</strong> if your array is not of type {@code Object[]},
 * {@link #ensureCapacity(Object[],int,int)} and {@link #grow(Object[],int,int)}
 * will use {@linkplain java.lang.reflect.Array#newInstance(Class,int) reflection}
 * to preserve your array type. Reflection is <em>significantly slower</em> than using {@code new}.
 * This phenomenon is particularly
 * evident in the first growth phases of an array reallocated with doubling (or similar) logic.
 *
 * <h2>Sorting</h2>
 *
 * <p>There are several sorting methods available. The main theme is that of letting you choose
 * the sorting algorithm you prefer (i.e., trading stability of mergesort for no memory allocation in quicksort).
 *
 * <h3>Parallel operations</h3>
 * Some algorithms provide a parallel version that will by default use the
 * {@linkplain ForkJoinPool#commonPool() common pool}, but this can be overridden by calling the
 * function in a task already in the {@link ForkJoinPool} that the operation should run in. For example,
 * something along the lines of "{@code poolToParallelSortIn.invoke(() -> parallelQuickSort(arrayToSort))}" 
 * will run the parallel sort in {@code poolToParallelSortIn} instead of the default pool.
 *
 * <p>All comparison-based algorithm have an implementation based on a type-specific comparator.
 *
 * <p>If you are fine with not knowing exactly which algorithm will be run (in particular, not knowing exactly whether a support array will be allocated),
 * the dual-pivot parallel sorts in {@link java.util.Arrays}
 * are about 50% faster than the classical single-pivot implementation used here.
 *
 * <p>In any case, if sorting time is important I suggest that you benchmark your sorting load
 * with your data distribution and on your architecture.
 *
 * @see java.util.Arrays
 */

public final class ARRAYS {

#endif
	private ARRAYS() {}

	/** A static, final, empty array. */
	public static final KEY_TYPE[] EMPTY_ARRAY = {};

	/** A static, final, empty array to be used as default array in allocations. An
	  * object distinct from {@link #EMPTY_ARRAY} makes it possible to have different
	  * behaviors depending on whether the user required an empty allocation, or we are
	  * just lazily delaying allocation.
	  *
	  * @see java.util.ArrayList
	  */
	public static final KEY_TYPE[] DEFAULT_EMPTY_ARRAY = {};


#if KEY_CLASS_Object
	/** Creates a new array using a the given one as prototype.
	 *
	 * <p>This method returns a new array of the given length whose element
	 * are of the same class as of those of {@code prototype}. In case
	 * of an empty array, it tries to return {@link #EMPTY_ARRAY}, if possible.
	 *
	 * @param prototype an array that will be used to type the new one.
	 * @param length the length of the new array.
	 * @return a new array of given type and length.
	 */

	SUPPRESS_WARNINGS_KEY_UNCHECKED
	private static <K> K[] newArray(final K[] prototype, final int length) {
		final Class<?> klass = prototype.getClass();
		if (klass == Object[].class) return (K[])(length == 0 ? EMPTY_ARRAY : new Object[length]);
		return (K[])java.lang.reflect.Array.newInstance(klass.getComponentType(), length);
	}
#endif

	/** Forces an array to contain the given number of entries, preserving just a part of the array.
	 *
	 * @param array an array.
	 * @param length the new minimum length for this array.
	 * @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary.
	 * @return an array with {@code length} entries whose first {@code preserve}
	 * entries are the same as those of {@code array}.
	 */
	public static KEY_GENERIC KEY_GENERIC_TYPE[] forceCapacity(final KEY_GENERIC_TYPE[] array, final int length, final int preserve) {
		final KEY_GENERIC_TYPE t[] =
#if KEY_CLASS_Object
			newArray(array, length);
#else
			new KEY_TYPE[length];
#endif
		System.arraycopy(array, 0, t, 0, preserve);
		return t;
	}

	/** Ensures that an array can contain the given number of entries.
	 *
	 * <p>If you cannot foresee whether this array will need again to be
	 * enlarged, you should probably use {@code grow()} instead.
	 *
	 * @param array an array.
	 * @param length the new minimum length for this array.
	 * @return {@code array}, if it contains {@code length} entries or more; otherwise,
	 * an array with {@code length} entries whose first {@code array.length}
	 * entries are the same as those of {@code array}.
	 */
	public static KEY_GENERIC KEY_GENERIC_TYPE[] ensureCapacity(final KEY_GENERIC_TYPE[] array, final int length) {
		return ensureCapacity(array, length, array.length);
	}

	/** Ensures that an array can contain the given number of entries, preserving just a part of the array.
	 *
	 * @param array an array.
	 * @param length the new minimum length for this array.
	 * @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary.
	 * @return {@code array}, if it can contain {@code length} entries or more; otherwise,
	 * an array with {@code length} entries whose first {@code preserve}
	 * entries are the same as those of {@code array}.
	 */
	public static KEY_GENERIC KEY_GENERIC_TYPE[] ensureCapacity(final KEY_GENERIC_TYPE[] array, final int length, final int preserve) {
		return length > array.length ? forceCapacity(array, length, preserve) : array;
	}

	/** Grows the given array to the maximum between the given length and
	 * the current length increased by 50%, provided that the given
	 * length is larger than the current length.
	 *
	 * <p>If you want complete control on the array growth, you
	 * should probably use {@code ensureCapacity()} instead.
	 *
	 * @param array an array.
	 * @param length the new minimum length for this array.
	 * @return {@code array}, if it can contain {@code length}
	 * entries; otherwise, an array with
	 * max({@code length},{@code array.length}/&phi;) entries whose first
	 * {@code array.length} entries are the same as those of {@code array}.
	 * */

	public static KEY_GENERIC KEY_GENERIC_TYPE[] grow(final KEY_GENERIC_TYPE[] array, final int length) {
		return grow(array, length, array.length);
	}

	/** Grows the given array to the maximum between the given length and
	 * the current length increased by 50%, provided that the given
	 * length is larger than the current length, preserving just a part of the array.
	 *
	 * <p>If you want complete control on the array growth, you
	 * should probably use {@code ensureCapacity()} instead.
	 *
	 * @param array an array.
	 * @param length the new minimum length for this array.
	 * @param preserve the number of elements of the array that must be preserved in case a new allocation is necessary.
	 * @return {@code array}, if it can contain {@code length}
	 * entries; otherwise, an array with
	 * max({@code length},{@code array.length}/&phi;) entries whose first
	 * {@code preserve} entries are the same as those of {@code array}.
	 * */

	public static KEY_GENERIC KEY_GENERIC_TYPE[] grow(final KEY_GENERIC_TYPE[] array, final int length, final int preserve) {
		if (length > array.length) {
			final int newLength = (int)Math.max(Math.min((long)array.length + (array.length >> 1), Arrays.MAX_ARRAY_SIZE), length);

			final KEY_GENERIC_TYPE t[] =
#if KEY_CLASS_Object
				newArray(array, newLength);
#else
				new KEY_TYPE[newLength];
#endif
			System.arraycopy(array, 0, t, 0, preserve);

			return t;
		}
		return array;

	}

	/** Trims the given array to the given length.
	 *
	 * @param array an array.
	 * @param length the new maximum length for the array.
	 * @return {@code array}, if it contains {@code length}
	 * entries or less; otherwise, an array with
	 * {@code length} entries whose entries are the same as
	 * the first {@code length} entries of {@code array}.
	 *
	 */

	public static KEY_GENERIC KEY_GENERIC_TYPE[] trim(final KEY_GENERIC_TYPE[] array, final int length) {
		if (length >= array.length) return array;
		final KEY_GENERIC_TYPE t[] =
#if KEY_CLASS_Object
			newArray(array, length);
#else
			length == 0 ? EMPTY_ARRAY : new KEY_TYPE[length];
#endif
		System.arraycopy(array, 0, t, 0, length);
		return t;
	}

	/** Sets the length of the given array.
	 *
	 * @param array an array.
	 * @param length the new length for the array.
	 * @return {@code array}, if it contains exactly {@code length}
	 * entries; otherwise, if it contains <em>more</em> than
	 * {@code length} entries, an array with {@code length} entries
	 * whose entries are the same as the first {@code length} entries of
	 * {@code array}; otherwise, an array with {@code length} entries
	 * whose first {@code array.length} entries are the same as those of
	 * {@code array}.
	 *
	 */

	public static KEY_GENERIC KEY_GENERIC_TYPE[] setLength(final KEY_GENERIC_TYPE[] array, final int length) {
		if (length == array.length) return array;
		if (length < array.length) return trim(array, length);
		return ensureCapacity(array, length);
	}

	/** Returns a copy of a portion of an array.
	 *
	 * @param array an array.
	 * @param offset the first element to copy.
	 * @param length the number of elements to copy.
	 * @return a new array containing {@code length} elements of {@code array} starting at {@code offset}.
	 */

	public static KEY_GENERIC KEY_GENERIC_TYPE[] copy(final KEY_GENERIC_TYPE[] array, final int offset, final int length) {
		ensureOffsetLength(array, offset, length);
		final KEY_GENERIC_TYPE[] a =
#if KEY_CLASS_Object
			newArray(array, length);
#else
			length == 0 ? EMPTY_ARRAY : new KEY_TYPE[length];
#endif
		System.arraycopy(array, offset, a, 0, length);
		return a;
	}

	/** Returns a copy of an array.
	 *
	 * @param array an array.
	 * @return a copy of {@code array}.
	 */

	public static KEY_GENERIC KEY_GENERIC_TYPE[] copy(final KEY_GENERIC_TYPE[] array) {
		return array.clone();
	}

	/** Fills the given array with the given value.
	 *
	 * @param array an array.
	 * @param value the new value for all elements of the array.
	 * @deprecated Please use the corresponding {@link java.util.Arrays} method.
	 */

	@Deprecated
	public static KEY_GENERIC void fill(final KEY_GENERIC_TYPE[] array, final KEY_GENERIC_TYPE value) {
		int i = array.length;
		while(i-- != 0) array[i] = value;
	}

	/** Fills a portion of the given array with the given value.
	 *
	 * @param array an array.
	 * @param from the starting index of the portion to fill (inclusive).
	 * @param to the end index of the portion to fill (exclusive).
	 * @param value the new value for all elements of the specified portion of the array.
	 * @deprecated Please use the corresponding {@link java.util.Arrays} method.
	 */

	@Deprecated
	public static KEY_GENERIC void fill(final KEY_GENERIC_TYPE[] array, final int from, int to, final KEY_GENERIC_TYPE value) {
		ensureFromTo(array, from, to);
		if (from == 0) while(to-- != 0) array[to] = value;
		else for(int i = from; i < to; i++) array[i] = value;
	}



	/** Returns true if the two arrays are elementwise equal.
	 *
	 * @param a1 an array.
	 * @param a2 another array.
	 * @return true if the two arrays are of the same length, and their elements are equal.
	 * @deprecated Please use the corresponding {@link java.util.Arrays} method, which is intrinsified in recent JVMs.
	 */

	@Deprecated
	public static KEY_GENERIC boolean equals(final KEY_GENERIC_TYPE[] a1, final KEY_GENERIC_TYPE a2[]) {
		int i = a1.length;
		if (i != a2.length) return false;
		while(i-- != 0) if (! KEY_EQUALS(a1[i], a2[i])) return false;
		return true;
	}




	/** Ensures that a range given by its first (inclusive) and last (exclusive) elements fits an array.
	 *
	 * <p>This method may be used whenever an array range check is needed.
	 *
	 * <p>In Java 9 and up, this method should be considered deprecated in favor of the
	 * {@link java.util.Objects#checkFromToIndex(int, int, int)} method, which may be intrinsified in recent JVMs.
	 *
	 * @param a an array.
	 * @param from a start index (inclusive).
	 * @param to an end index (exclusive).
	 * @throws IllegalArgumentException if {@code from} is greater than {@code to}.
	 * @throws ArrayIndexOutOfBoundsException if {@code from} or {@code to} are greater than the array length or negative.
	 */
	public static KEY_GENERIC void ensureFromTo(final KEY_GENERIC_TYPE[] a, final int from, final int to) {
		Arrays.ensureFromTo(a.length, from, to);
	}

	/** Ensures that a range given by an offset and a length fits an array.
	 *
	 * <p>This method may be used whenever an array range check is needed.
	 *
	 * <p>In Java 9 and up, this method should be considered deprecated in favor of the
	 * {@link java.util.Objects#checkFromIndexSize(int, int, int)} method, which may be intrinsified in recent JVMs.
	 *
	 * @param a an array.
	 * @param offset a start index.
	 * @param length a length (the number of elements in the range).
	 * @throws IllegalArgumentException if {@code length} is negative.
	 * @throws ArrayIndexOutOfBoundsException if {@code offset} is negative or {@code offset}+{@code length} is greater than the array length.
	 */
	public static KEY_GENERIC void ensureOffsetLength(final KEY_GENERIC_TYPE[] a, final int offset, final int length) {
		Arrays.ensureOffsetLength(a.length, offset, length);
	}

	/** Ensures that two arrays are of the same length.
	 *
	 * @param a an array.
	 * @param b another array.
	 * @throws IllegalArgumentException if the two argument arrays are not of the same length.
	 */
	public static KEY_GENERIC void ensureSameLength(final KEY_GENERIC_TYPE[] a, final KEY_GENERIC_TYPE[] b) {
		if (a.length != b.length) throw new IllegalArgumentException("Array size mismatch: " + a.length + " != " + b.length);
	}

	private static final int QUICKSORT_NO_REC = 16;
	private static final int PARALLEL_QUICKSORT_NO_FORK = 8192;
	private static final int QUICKSORT_MEDIAN_OF_9 = 128;
	private static final int MERGESORT_NO_REC = 16;

	private static ForkJoinPool getPool() {
		// Make sure to update Arrays.drv, BigArrays.drv, and src/it/unimi/dsi/fastutil/Arrays.java as well
		ForkJoinPool current = ForkJoinTask.getPool();
		return current == null ? ForkJoinPool.commonPool() : current;
	}

	/** Swaps two elements of an anrray.
	 *
	 * @param x an array.
	 * @param a a position in {@code x}.
	 * @param b another position in {@code x}.
	 */
	public static KEY_GENERIC void swap(final KEY_GENERIC_TYPE x[], final int a, final int b) {
		final KEY_GENERIC_TYPE t = x[a];
		x[a] = x[b];
		x[b] = t;
	}

	/** Swaps two sequences of elements of an array.
	 *
	 * @param x an array.
	 * @param a a position in {@code x}.
	 * @param b another position in {@code x}.
	 * @param n the number of elements to exchange starting at {@code a} and {@code b}.
	 */
	public static KEY_GENERIC void swap(final KEY_GENERIC_TYPE[] x, int a, int b, final int n) {
		for(int i = 0; i < n; i++, a++, b++) swap(x, a, b);
	}

	private static KEY_GENERIC int med3(final KEY_GENERIC_TYPE x[], final int a, final int b, final int c, KEY_COMPARATOR KEY_GENERIC comp) {
		final int ab = comp.compare(x[a], x[b]);
		final int ac = comp.compare(x[a], x[c]);
		final int bc = comp.compare(x[b], x[c]);
		return (ab < 0 ?
			(bc < 0 ? b : ac < 0 ? c : a) :
			(bc > 0 ? b : ac > 0 ? c : a));
	}

	private static KEY_GENERIC void selectionSort(final KEY_GENERIC_TYPE[] a, final int from, final int to, final KEY_COMPARATOR KEY_GENERIC comp) {
		for(int i = from; i < to - 1; i++) {
			int m = i;
			for(int j = i + 1; j < to; j++) if (comp.compare(a[j], a[m]) < 0) m = j;
			if (m != i) {
				final KEY_GENERIC_TYPE u = a[i];
				a[i] = a[m];
				a[m] = u;
			}
		}
	}

	private static KEY_GENERIC void insertionSort(final KEY_GENERIC_TYPE[] a, final int from, final int to, final KEY_COMPARATOR KEY_GENERIC comp) {
		for (int i = from; ++i < to;) {
			KEY_GENERIC_TYPE t = a[i];
			int j = i;
			for (KEY_GENERIC_TYPE u = a[j - 1]; comp.compare(t, u) < 0; u = a[--j - 1]) {
				a[j] = u;
				if (from == j - 1) {
					--j;
					break;
				}
			}
			a[j] = t;
		}
	}



	/** Sorts the specified range of elements according to the order induced by the specified
	 * comparator using quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>Note that this implementation does not allocate any object, contrarily to the implementation
	 * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
	 *
	 * @param x the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 *
	 */
	public static KEY_GENERIC void quickSort(final KEY_GENERIC_TYPE[] x, final int from, final int to, final KEY_COMPARATOR KEY_GENERIC comp) {
		final int len = to - from;
		// Selection sort on smallest arrays
		if (len < QUICKSORT_NO_REC) {
			selectionSort(x, from, to, comp);
			return;
		}

		// Choose a partition element, v
		int m = from + len / 2;
		int l = from;
		int n = to - 1;
		if (len > QUICKSORT_MEDIAN_OF_9) {		// Big arrays, pseudomedian of 9
			int s = len / 8;
			l = med3(x, l, l + s, l + 2 * s, comp);
			m = med3(x, m - s, m, m + s, comp);
			n = med3(x, n - 2 * s, n - s, n, comp);
		}
		m = med3(x, l, m, n, comp); // Mid-size, med of 3

		final KEY_GENERIC_TYPE v = x[m];

		// Establish Invariant: v* (<v)* (>v)* v*
		int a = from, b = a, c = to - 1, d = c;
		while(true) {
			int comparison;
			while (b <= c && (comparison = comp.compare(x[b], v)) <= 0) {
				if (comparison == 0) swap(x, a++, b);
				b++;
			}
			while (c >= b && (comparison = comp.compare(x[c], v)) >=0) {
				if (comparison == 0) swap(x, c, d--);
				c--;
			}
			if (b > c) break;
			swap(x, b++, c--);
		}

		// Swap partition elements back to middle
		int s;
		s = Math.min(a - from, b - a);
		swap(x, from, b - s, s);
		s = Math.min(d - c, to - d - 1);
		swap(x, b, to - s, s);

		// Recursively sort non-partition-elements
		if ((s = b - a) > 1) quickSort(x, from, from + s, comp);
		if ((s = d - c) > 1) quickSort(x, to - s, to, comp);
	}

	/** Sorts an array according to the order induced by the specified
	 * comparator using quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>Note that this implementation does not allocate any object, contrarily to the implementation
	 * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
	 *
	 * @param x the array to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 *
	 */
	public static KEY_GENERIC void quickSort(final KEY_GENERIC_TYPE[] x, final KEY_COMPARATOR KEY_GENERIC comp) {
		quickSort(x, 0, x.length, comp);
	}


	protected static class ForkJoinQuickSortComp KEY_GENERIC extends RecursiveAction {
		private static final long serialVersionUID = 1L;
		private final int from;
		private final int to;
		private final KEY_GENERIC_TYPE[] x;
		private final KEY_COMPARATOR KEY_GENERIC comp;

		public ForkJoinQuickSortComp(final KEY_GENERIC_TYPE[] x , final int from , final int to, final KEY_COMPARATOR KEY_GENERIC comp) {
			this.from = from;
			this.to = to;
			this.x = x;
			this.comp = comp;
		}

		@Override
		protected void compute() {
			final KEY_GENERIC_TYPE[] x = this.x;
			final int len = to - from;
			if (len < PARALLEL_QUICKSORT_NO_FORK) {
				quickSort(x, from, to, comp);
				return;
			}
			// Choose a partition element, v
			int m = from + len / 2;
			int l = from;
			int n = to - 1;
			int s = len / 8;
			l = med3(x, l, l + s, l + 2 * s, comp);
			m = med3(x, m - s, m, m + s, comp);
			n = med3(x, n - 2 * s, n - s, n, comp);
			m = med3(x, l, m, n, comp);
			final KEY_GENERIC_TYPE v = x[m];
			// Establish Invariant: v* (<v)* (>v)* v*
			int a = from, b = a, c = to - 1, d = c;
			while (true) {
				int comparison;
				while (b <= c && (comparison = comp.compare(x[b], v)) <= 0) {
					if (comparison == 0) swap(x, a++, b);
					b++;
				}
				while (c >= b && (comparison = comp.compare(x[c], v)) >= 0) {
					if (comparison == 0) swap(x, c, d--);
					c--;
				}
				if (b > c) break;
				swap(x, b++, c--);
			}
			// Swap partition elements back to middle
			int t;
			s = Math.min(a - from, b - a);
			swap(x, from, b - s, s);
			s = Math.min(d - c, to - d - 1);
			swap(x, b, to - s, s);
			// Recursively sort non-partition-elements
			s = b - a;
			t = d - c;
			if (s > 1 && t > 1) invokeAll(new ForkJoinQuickSortComp KEY_GENERIC_DIAMOND(x, from, from + s, comp), new ForkJoinQuickSortComp KEY_GENERIC_DIAMOND(x, to - t, to, comp));
			else if (s > 1) invokeAll(new ForkJoinQuickSortComp KEY_GENERIC_DIAMOND(x, from, from + s, comp));
			else invokeAll(new ForkJoinQuickSortComp KEY_GENERIC_DIAMOND(x, to - t, to, comp));
		}
	}

	/** Sorts the specified range of elements according to the order induced by the specified
	 * comparator using a parallel quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * @param x the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 */
	public static KEY_GENERIC void parallelQuickSort(final KEY_GENERIC_TYPE[] x, final int from, final int to, final KEY_COMPARATOR KEY_GENERIC comp) {
		ForkJoinPool pool = getPool();
		if (to - from < PARALLEL_QUICKSORT_NO_FORK || pool.getParallelism() == 1) quickSort(x, from, to, comp);
		else {
			pool.invoke(new ForkJoinQuickSortComp KEY_GENERIC_DIAMOND(x, from, to, comp));
		}
	}

	/** Sorts an array according to the order induced by the specified
	 * comparator using a parallel quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * @param x the array to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 */
	public static KEY_GENERIC void parallelQuickSort(final KEY_GENERIC_TYPE[] x, final KEY_COMPARATOR KEY_GENERIC comp) {
		parallelQuickSort(x, 0, x.length, comp);
	}


	SUPPRESS_WARNINGS_KEY_UNCHECKED
	private static KEY_GENERIC int med3(final KEY_GENERIC_TYPE x[], final int a, final int b, final int c) {
		final int ab = KEY_CMP(x[a], x[b]);
		final int ac = KEY_CMP(x[a], x[c]);
		final int bc = KEY_CMP(x[b], x[c]);
		return (ab < 0 ?
			(bc < 0 ? b : ac < 0 ? c : a) :
			(bc > 0 ? b : ac > 0 ? c : a));
	}

	SUPPRESS_WARNINGS_KEY_UNCHECKED
	private static KEY_GENERIC void selectionSort(final KEY_GENERIC_TYPE[] a, final int from, final int to) {
		for(int i = from; i < to - 1; i++) {
			int m = i;
			for(int j = i + 1; j < to; j++) if (KEY_LESS(a[j], a[m])) m = j;
			if (m != i) {
				final KEY_GENERIC_TYPE u = a[i];
				a[i] = a[m];
				a[m] = u;
			}
		}
	}

	SUPPRESS_WARNINGS_KEY_UNCHECKED
	private static KEY_GENERIC void insertionSort(final KEY_GENERIC_TYPE[] a, final int from, final int to) {
		for (int i = from; ++i < to;) {
			KEY_GENERIC_TYPE t = a[i];
			int j = i;
			for (KEY_GENERIC_TYPE u = a[j - 1]; KEY_LESS(t, u); u = a[--j - 1]) {
				a[j] = u;
				if (from == j - 1) {
					--j;
					break;
				}
			}
			a[j] = t;
		}
	}

	/** Sorts the specified range of elements according to the natural ascending order using quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>Note that this implementation does not allocate any object, contrarily to the implementation
	 * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
	 *
	 * @param x the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */

	SUPPRESS_WARNINGS_KEY_UNCHECKED
	public static KEY_GENERIC void quickSort(final KEY_GENERIC_TYPE[] x, final int from, final int to) {
		final int len = to - from;
		// Selection sort on smallest arrays
		if (len < QUICKSORT_NO_REC) {
			selectionSort(x, from, to);
			return;
		}

		// Choose a partition element, v
		int m = from + len / 2;
		int l = from;
		int n = to - 1;
		if (len > QUICKSORT_MEDIAN_OF_9) {		// Big arrays, pseudomedian of 9
			int s = len / 8;
			l = med3(x, l, l + s, l + 2 * s);
			m = med3(x, m - s, m, m + s);
			n = med3(x, n - 2 * s, n - s, n);
		}
		m = med3(x, l, m, n); // Mid-size, med of 3

		final KEY_GENERIC_TYPE v = x[m];

		// Establish Invariant: v* (<v)* (>v)* v*
		int a = from, b = a, c = to - 1, d = c;
		while(true) {
			int comparison;
			while (b <= c && (comparison = KEY_CMP(x[b], v)) <= 0) {
				if (comparison == 0) swap(x, a++, b);
				b++;
			}
			while (c >= b && (comparison = KEY_CMP(x[c], v)) >=0) {
				if (comparison == 0) swap(x, c, d--);
				c--;
			}
			if (b > c) break;
			swap(x, b++, c--);
		}

		// Swap partition elements back to middle
		int s;
		s = Math.min(a - from, b - a);
		swap(x, from, b - s, s);
		s = Math.min(d - c, to - d - 1);
		swap(x, b, to - s, s);

		// Recursively sort non-partition-elements
		if ((s = b - a) > 1) quickSort(x, from, from + s);
		if ((s = d - c) > 1) quickSort(x, to - s, to);
	}

	/** Sorts an array according to the natural ascending order using quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>Note that this implementation does not allocate any object, contrarily to the implementation
	 * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
	 *
	 * @param x the array to be sorted.
	 *
	 */
	public static KEY_GENERIC void quickSort(final KEY_GENERIC_TYPE[] x) {
		quickSort(x, 0, x.length);
	}

	protected static class ForkJoinQuickSort KEY_GENERIC extends RecursiveAction {
		private static final long serialVersionUID = 1L;
		private final int from;
		private final int to;
		private final KEY_GENERIC_TYPE[] x;

		public ForkJoinQuickSort(final KEY_GENERIC_TYPE[] x , final int from , final int to) {
			this.from = from;
			this.to = to;
			this.x = x;
		}

		@Override
		SUPPRESS_WARNINGS_KEY_UNCHECKED
		protected void compute() {
			final KEY_GENERIC_TYPE[] x = this.x;
			final int len = to - from;
			if (len < PARALLEL_QUICKSORT_NO_FORK) {
				quickSort(x, from, to);
				return;
			}
			// Choose a partition element, v
			int m = from + len / 2;
			int l = from;
			int n = to - 1;
			int s = len / 8;
			l = med3(x, l, l + s, l + 2 * s);
			m = med3(x, m - s, m, m + s);
			n = med3(x, n - 2 * s, n - s, n);
			m = med3(x, l, m, n);
			final KEY_GENERIC_TYPE v = x[m];
			// Establish Invariant: v* (<v)* (>v)* v*
			int a = from, b = a, c = to - 1, d = c;
			while (true) {
				int comparison;
				while (b <= c && (comparison = KEY_CMP(x[b], v)) <= 0) {
					if (comparison == 0) swap(x, a++, b);
					b++;
				}
				while (c >= b && (comparison = KEY_CMP(x[c], v)) >= 0) {
					if (comparison == 0) swap(x, c, d--);
					c--;
				}
				if (b > c) break;
				swap(x, b++, c--);
			}
			// Swap partition elements back to middle
			int t;
			s = Math.min(a - from, b - a);
			swap(x, from, b - s, s);
			s = Math.min(d - c, to - d - 1);
			swap(x, b, to - s, s);
			// Recursively sort non-partition-elements
			s = b - a;
			t = d - c;
			if (s > 1 && t > 1) invokeAll(new ForkJoinQuickSort KEY_GENERIC_DIAMOND(x, from, from + s), new ForkJoinQuickSort KEY_GENERIC_DIAMOND(x, to - t, to));
			else if (s > 1) invokeAll(new ForkJoinQuickSort KEY_GENERIC_DIAMOND(x, from, from + s));
			else invokeAll(new ForkJoinQuickSort KEY_GENERIC_DIAMOND(x, to - t, to));
		}
	}

	/**  Sorts the specified range of elements according to the natural ascending order using a parallel quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * @param x the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */
	public static KEY_GENERIC void parallelQuickSort(final KEY_GENERIC_TYPE[] x, final int from, final int to) {
		ForkJoinPool pool = getPool();
		if (to - from < PARALLEL_QUICKSORT_NO_FORK || pool.getParallelism() == 1) quickSort(x, from, to);
		else {
			pool.invoke(new ForkJoinQuickSort KEY_GENERIC_DIAMOND(x, from, to));
		}
	}

	/** Sorts an array according to the natural ascending order using a parallel quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * @param x the array to be sorted.
	 *
	 */
	public static KEY_GENERIC void parallelQuickSort(final KEY_GENERIC_TYPE[] x) {
		parallelQuickSort(x, 0, x.length);
	}


	SUPPRESS_WARNINGS_KEY_UNCHECKED
	private static KEY_GENERIC int med3Indirect(final int perm[], final KEY_GENERIC_TYPE x[], final int a, final int b, final int c) {
		final KEY_GENERIC_TYPE aa = x[perm[a]];
		final KEY_GENERIC_TYPE bb = x[perm[b]];
		final KEY_GENERIC_TYPE cc = x[perm[c]];
		final int ab = KEY_CMP(aa, bb);
		final int ac = KEY_CMP(aa, cc);
		final int bc = KEY_CMP(bb, cc);
		return (ab < 0 ?
			(bc < 0 ? b : ac < 0 ? c : a) :
			(bc > 0 ? b : ac > 0 ? c : a));
	}

	SUPPRESS_WARNINGS_KEY_UNCHECKED
	private static KEY_GENERIC void insertionSortIndirect(final int[] perm, final KEY_GENERIC_TYPE[] a, final int from, final int to) {
		for (int i = from; ++i < to;) {
			int t = perm[i];
			int j = i;
			for (int u = perm[j - 1]; KEY_LESS(a[t], a[u]); u = perm[--j - 1]) {
				perm[j] = u;
				if (from == j - 1) {
					--j;
					break;
				}
			}
			perm[j] = t;
		}
	}

	/** Sorts the specified range of elements according to the natural ascending order using indirect quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>This method implement an <em>indirect</em> sort. The elements of {@code perm} (which must
	 * be exactly the numbers in the interval {@code [0..perm.length)}) will be permuted so that
	 * {@code x[perm[i]] &le; x[perm[i + 1]]}.
	 *
	 * <p>Note that this implementation does not allocate any object, contrarily to the implementation
	 * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
	 *
	 * @param perm a permutation array indexing {@code x}.
	 * @param x the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */

	SUPPRESS_WARNINGS_KEY_UNCHECKED
	public static KEY_GENERIC void quickSortIndirect(final int[] perm, final KEY_GENERIC_TYPE[] x, final int from, final int to) {
		final int len = to - from;
		// Selection sort on smallest arrays
		if (len < QUICKSORT_NO_REC) {
			insertionSortIndirect(perm, x, from, to);
			return;
		}

		// Choose a partition element, v
		int m = from + len / 2;
		int l = from;
		int n = to - 1;
		if (len > QUICKSORT_MEDIAN_OF_9) {		// Big arrays, pseudomedian of 9
			int s = len / 8;
			l = med3Indirect(perm, x, l, l + s, l + 2 * s);
			m = med3Indirect(perm, x, m - s, m, m + s);
			n = med3Indirect(perm, x, n - 2 * s, n - s, n);
		}
		m = med3Indirect(perm, x, l, m, n); // Mid-size, med of 3

		final KEY_GENERIC_TYPE v = x[perm[m]];

		// Establish Invariant: v* (<v)* (>v)* v*
		int a = from, b = a, c = to - 1, d = c;
		while(true) {
			int comparison;
			while (b <= c && (comparison = KEY_CMP(x[perm[b]], v)) <= 0) {
				if (comparison == 0) IntArrays.swap(perm, a++, b);
				b++;
			}
			while (c >= b && (comparison = KEY_CMP(x[perm[c]], v)) >=0) {
				if (comparison == 0) IntArrays.swap(perm, c, d--);
				c--;
			}
			if (b > c) break;
			IntArrays.swap(perm, b++, c--);
		}

		// Swap partition elements back to middle
		int s;
		s = Math.min(a - from, b - a);
		IntArrays.swap(perm, from, b - s, s);
		s = Math.min(d - c, to - d - 1);
		IntArrays.swap(perm, b, to - s, s);

		// Recursively sort non-partition-elements
		if ((s = b - a) > 1) quickSortIndirect(perm, x, from, from + s);
		if ((s = d - c) > 1) quickSortIndirect(perm, x, to - s, to);
	}

	/** Sorts an array according to the natural ascending order using indirect quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>This method implement an <em>indirect</em> sort. The elements of {@code perm} (which must
	 * be exactly the numbers in the interval {@code [0..perm.length)}) will be permuted so that
	 * {@code x[perm[i]] &le; x[perm[i + 1]]}.
	 *
	 * <p>Note that this implementation does not allocate any object, contrarily to the implementation
	 * used to sort primitive types in {@link java.util.Arrays}, which switches to mergesort on large inputs.
	 *
	 * @param perm a permutation array indexing {@code x}.
	 * @param x the array to be sorted.
	 */
	public static KEY_GENERIC void quickSortIndirect(final int perm[], final KEY_GENERIC_TYPE[] x) {
		quickSortIndirect(perm, x, 0, x.length);
	}

	protected static class ForkJoinQuickSortIndirect KEY_GENERIC extends RecursiveAction {
		private static final long serialVersionUID = 1L;
		private final int from;
		private final int to;
		private final int[] perm;
		private final KEY_GENERIC_TYPE[] x;

		public ForkJoinQuickSortIndirect(final int perm[], final KEY_GENERIC_TYPE[] x , final int from , final int to) {
			this.from = from;
			this.to = to;
			this.x = x;
			this.perm = perm;
		}

		@Override
		SUPPRESS_WARNINGS_KEY_UNCHECKED
		protected void compute() {
			final KEY_GENERIC_TYPE[] x = this.x;
			final int len = to - from;
			if (len < PARALLEL_QUICKSORT_NO_FORK) {
				quickSortIndirect(perm, x, from, to);
				return;
			}
			// Choose a partition element, v
			int m = from + len / 2;
			int l = from;
			int n = to - 1;
			int s = len / 8;
			l = med3Indirect(perm, x, l, l + s, l + 2 * s);
			m = med3Indirect(perm, x, m - s, m, m + s);
			n = med3Indirect(perm, x, n - 2 * s, n - s, n);
			m = med3Indirect(perm, x, l, m, n);
			final KEY_GENERIC_TYPE v = x[perm[m]];
			// Establish Invariant: v* (<v)* (>v)* v*
			int a = from, b = a, c = to - 1, d = c;
			while (true) {
				int comparison;
				while (b <= c && (comparison = KEY_CMP(x[perm[b]], v)) <= 0) {
					if (comparison == 0) IntArrays.swap(perm, a++, b);
					b++;
				}
				while (c >= b && (comparison = KEY_CMP(x[perm[c]], v)) >= 0) {
					if (comparison == 0) IntArrays.swap(perm, c, d--);
					c--;
				}
				if (b > c) break;
				IntArrays.swap(perm, b++, c--);
			}
			// Swap partition elements back to middle
			int t;
			s = Math.min(a - from, b - a);
			IntArrays.swap(perm, from, b - s, s);
			s = Math.min(d - c, to - d - 1);
			IntArrays.swap(perm, b, to - s, s);
			// Recursively sort non-partition-elements
			s = b - a;
			t = d - c;
			if (s > 1 && t > 1) invokeAll(new ForkJoinQuickSortIndirect KEY_GENERIC_DIAMOND(perm, x, from, from + s), new ForkJoinQuickSortIndirect KEY_GENERIC_DIAMOND(perm, x, to - t, to));
			else if (s > 1) invokeAll(new ForkJoinQuickSortIndirect KEY_GENERIC_DIAMOND(perm, x, from, from + s));
			else invokeAll(new ForkJoinQuickSortIndirect KEY_GENERIC_DIAMOND(perm, x, to - t, to));
		}
	}

	/**  Sorts the specified range of elements according to the natural ascending order using a parallel indirect quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>This method implement an <em>indirect</em> sort. The elements of {@code perm} (which must
	 * be exactly the numbers in the interval {@code [0..perm.length)}) will be permuted so that
	 * {@code x[perm[i]] &le; x[perm[i + 1]]}.
	 *
	 * @param perm a permutation array indexing {@code x}.
	 * @param x the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */
	public static KEY_GENERIC void parallelQuickSortIndirect(final int[] perm, final KEY_GENERIC_TYPE[] x, final int from, final int to) {
		ForkJoinPool pool = getPool();
		if (to - from < PARALLEL_QUICKSORT_NO_FORK || pool.getParallelism() == 1) quickSortIndirect(perm, x, from, to);
		else {
			pool.invoke(new ForkJoinQuickSortIndirect KEY_GENERIC_DIAMOND(perm, x, from, to));
		}
	}

	/** Sorts an array according to the natural ascending order using a parallel indirect quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>This method implement an <em>indirect</em> sort. The elements of {@code perm} (which must
	 * be exactly the numbers in the interval {@code [0..perm.length)}) will be permuted so that
	 * {@code x[perm[i]] &le; x[perm[i + 1]]}.
	 *
	 * @param perm a permutation array indexing {@code x}.
	 * @param x the array to be sorted.
	 *
	 */
	public static KEY_GENERIC void parallelQuickSortIndirect(final int perm[], final KEY_GENERIC_TYPE[] x) {
		parallelQuickSortIndirect(perm, x, 0, x.length);
	}

	/** Stabilizes a permutation.
	 *
	 * <p>This method can be used to stabilize the permutation generated by an indirect sorting, assuming that
	 * initially the permutation array was in ascending order (e.g., the identity, as usually happens). This method
	 * scans the permutation, and for each non-singleton block of elements with the same associated values in {@code x},
	 * permutes them in ascending order. The resulting permutation corresponds to a stable sort.
	 *
	 * <p>Usually combining an unstable indirect sort and this method is more efficient than using a stable sort,
	 * as most stable sort algorithms require a support array.
	 *
	 * <p>More precisely, assuming that {@code x[perm[i]] &le; x[perm[i + 1]]}, after
	 * stabilization we will also have that {@code x[perm[i]] = x[perm[i + 1]]} implies
	 * {@code perm[i] &le; perm[i + 1]}.
	 *
	 * @param perm a permutation array indexing {@code x} so that it is sorted.
	 * @param x the sorted array to be stabilized.
	 * @param from the index of the first element (inclusive) to be stabilized.
	 * @param to the index of the last element (exclusive) to be stabilized.
	 */
	public static KEY_GENERIC void stabilize(final int perm[], final KEY_GENERIC_TYPE[] x, final int from, final int to) {
		int curr = from;
		for(int i = from + 1; i < to; i++) {
			if (x[perm[i]] != x[perm[curr]]) {
				if (i - curr > 1) IntArrays.parallelQuickSort(perm, curr, i);
				curr = i;
			}
		}
		if (to - curr > 1) IntArrays.parallelQuickSort(perm, curr, to);
	}

	/** Stabilizes a permutation.
	 *
	 * <p>This method can be used to stabilize the permutation generated by an indirect sorting, assuming that
	 * initially the permutation array was in ascending order (e.g., the identity, as usually happens). This method
	 * scans the permutation, and for each non-singleton block of elements with the same associated values in {@code x},
	 * permutes them in ascending order. The resulting permutation corresponds to a stable sort.
	 *
	 * <p>Usually combining an unstable indirect sort and this method is more efficient than using a stable sort,
	 * as most stable sort algorithms require a support array.
	 *
	 * <p>More precisely, assuming that {@code x[perm[i]] &le; x[perm[i + 1]]}, after
	 * stabilization we will also have that {@code x[perm[i]] = x[perm[i + 1]]} implies
	 * {@code perm[i] &le; perm[i + 1]}.
	 *
	 * @param perm a permutation array indexing {@code x} so that it is sorted.
	 * @param x the sorted array to be stabilized.
	 */
	public static KEY_GENERIC void stabilize(final int perm[], final KEY_GENERIC_TYPE[] x) {
		stabilize(perm, x, 0, perm.length);
	}

	SUPPRESS_WARNINGS_KEY_UNCHECKED
	private static KEY_GENERIC int med3(final KEY_GENERIC_TYPE x[], final KEY_GENERIC_TYPE[] y, final int a, final int b, final int c) {
		int t;
		final int ab = (t = KEY_CMP(x[a], x[b])) == 0 ? KEY_CMP(y[a], y[b]) : t;
		final int ac = (t = KEY_CMP(x[a], x[c])) == 0 ? KEY_CMP(y[a], y[c]) : t;
		final int bc = (t = KEY_CMP(x[b], x[c])) == 0 ? KEY_CMP(y[b], y[c]) : t;
		return (ab < 0 ?
				(bc < 0 ? b : ac < 0 ? c : a) :
				(bc > 0 ? b : ac > 0 ? c : a));
	}

	private static KEY_GENERIC void swap(final KEY_GENERIC_TYPE x[], final KEY_GENERIC_TYPE[] y, final int a, final int b) {
		final KEY_GENERIC_TYPE t = x[a];
		final KEY_GENERIC_TYPE u = y[a];
		x[a] = x[b];
		y[a] = y[b];
		x[b] = t;
		y[b] = u;
	}

	private static KEY_GENERIC void swap(final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y, int a, int b, final int n) {
		for (int i = 0; i < n; i++, a++, b++) swap(x, y, a, b);
	}

	SUPPRESS_WARNINGS_KEY_UNCHECKED
	private static KEY_GENERIC void selectionSort(final KEY_GENERIC_TYPE[] a, final KEY_GENERIC_TYPE[] b, final int from, final int to) {
		for(int i = from; i < to - 1; i++) {
			int m = i, u;
			for(int j = i + 1; j < to; j++)
				if ((u = KEY_CMP(a[j], a[m])) < 0 || u == 0 && KEY_LESS(b[j], b[m])) m = j;

			if (m != i) {
				KEY_GENERIC_TYPE t = a[i];
				a[i] = a[m];
				a[m] = t;
				t = b[i];
				b[i] = b[m];
				b[m] = t;
			}
		}
	}

	/** Sorts the specified range of elements of two arrays according to the natural lexicographical
	 *  ascending order using quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>This method implements a <em>lexicographical</em> sorting of the arguments. Pairs of
	 * elements in the same position in the two provided arrays will be considered a single key, and
	 * permuted accordingly. In the end, either {@code x[i] &lt; x[i + 1]} or {@code x[i]
	 * == x[i + 1]} and {@code y[i] &le; y[i + 1]}.
	 *
	 * @param x the first array to be sorted.
	 * @param y the second array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */

	SUPPRESS_WARNINGS_KEY_UNCHECKED
	public static KEY_GENERIC void quickSort(final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y, final int from, final int to) {
		final int len = to - from;
		if (len < QUICKSORT_NO_REC) {
			selectionSort(x, y, from, to);
			return;
		}
		// Choose a partition element, v
		int m = from + len / 2;
		int l = from;
		int n = to - 1;
		if (len > QUICKSORT_MEDIAN_OF_9) { // Big arrays, pseudomedian of 9
			int s = len / 8;
			l = med3(x, y, l, l + s, l + 2 * s);
			m = med3(x, y, m - s, m, m + s);
			n = med3(x, y, n - 2 * s, n - s, n);
		}
		m = med3(x, y, l, m, n); // Mid-size, med of 3
		final KEY_GENERIC_TYPE v = x[m], w = y[m];
		// Establish Invariant: v* (<v)* (>v)* v*
		int a = from, b = a, c = to - 1, d = c;
		while (true) {
			int comparison, t;
			while (b <= c && (comparison = (t = KEY_CMP(x[b], v)) == 0 ? KEY_CMP(y[b], w) : t) <= 0) {
				if (comparison == 0) swap(x, y, a++, b);
				b++;
			}
			while (c >= b && (comparison = (t = KEY_CMP(x[c], v)) == 0 ? KEY_CMP(y[c], w) : t) >= 0) {
				if (comparison == 0) swap(x, y, c, d--);
				c--;
			}
			if (b > c) break;
			swap(x, y, b++, c--);
		}
		// Swap partition elements back to middle
		int s;
		s = Math.min(a - from, b - a);
		swap(x, y, from, b - s, s);
		s = Math.min(d - c, to - d - 1);
		swap(x, y, b, to - s, s);
		// Recursively sort non-partition-elements
		if ((s = b - a) > 1) quickSort(x, y, from, from + s);
		if ((s = d - c) > 1) quickSort(x, y, to - s, to);
	}

	/** Sorts two arrays according to the natural lexicographical ascending order using quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>This method implements a <em>lexicographical</em> sorting of the arguments. Pairs of
	 * elements in the same position in the two provided arrays will be considered a single key, and
	 * permuted accordingly. In the end, either {@code x[i] &lt; x[i + 1]} or {@code x[i]
	 * == x[i + 1]} and {@code y[i] &le; y[i + 1]}.
	 *
	 * @param x the first array to be sorted.
	 * @param y the second array to be sorted.
	 */
	public static KEY_GENERIC void quickSort(final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y) {
		ensureSameLength(x, y);
		quickSort(x, y, 0, x.length);
	}

	protected static class ForkJoinQuickSort2 KEY_GENERIC extends RecursiveAction {
		private static final long serialVersionUID = 1L;
		private final int from;
		private final int to;
		private final KEY_GENERIC_TYPE[] x, y;

		public ForkJoinQuickSort2(final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y, final int from , final int to) {
			this.from = from;
			this.to = to;
			this.x = x;
			this.y = y;
		}

		@Override
		SUPPRESS_WARNINGS_KEY_UNCHECKED
		protected void compute() {
			final KEY_GENERIC_TYPE[] x = this.x;
			final KEY_GENERIC_TYPE[] y = this.y;
			final int len = to - from;
			if (len < PARALLEL_QUICKSORT_NO_FORK) {
				quickSort(x, y, from, to);
				return;
			}
			// Choose a partition element, v
			int m = from + len / 2;
			int l = from;
			int n = to - 1;
			int s = len / 8;
			l = med3(x, y, l, l + s, l + 2 * s);
			m = med3(x, y, m - s, m, m + s);
			n = med3(x, y, n - 2 * s, n - s, n);
			m = med3(x, y, l, m, n);
			final KEY_GENERIC_TYPE v = x[m], w = y[m];
			// Establish Invariant: v* (<v)* (>v)* v*
			int a = from, b = a, c = to - 1, d = c;
			while (true) {
				int comparison, t;
				while (b <= c && (comparison = (t = KEY_CMP(x[b], v)) == 0 ? KEY_CMP(y[b], w) : t) <= 0) {
					if (comparison == 0) swap(x, y, a++, b);
					b++;
				}
				while (c >= b && (comparison = (t = KEY_CMP(x[c], v)) == 0 ? KEY_CMP(y[c], w) : t) >= 0) {
					if (comparison == 0) swap(x, y, c, d--);
					c--;
				}
				if (b > c) break;
				swap(x, y, b++, c--);
			}
			// Swap partition elements back to middle
			int t;
			s = Math.min(a - from, b - a);
			swap(x, y, from, b - s, s);
			s = Math.min(d - c, to - d - 1);
			swap(x, y, b, to - s, s);
			s = b - a;
			t = d - c;
			// Recursively sort non-partition-elements
			if (s > 1 && t > 1) invokeAll(new ForkJoinQuickSort2 KEY_GENERIC_DIAMOND(x, y, from, from + s), new ForkJoinQuickSort2 KEY_GENERIC_DIAMOND(x, y, to - t, to));
			else if (s > 1) invokeAll(new ForkJoinQuickSort2 KEY_GENERIC_DIAMOND(x, y, from, from + s));
			else invokeAll(new ForkJoinQuickSort2 KEY_GENERIC_DIAMOND(x, y, to - t, to));
		}
	}

	/** Sorts the specified range of elements of two arrays according to the natural lexicographical
	 *  ascending order using a parallel quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>This method implements a <em>lexicographical</em> sorting of the arguments. Pairs of
	 * elements in the same position in the two provided arrays will be considered a single key, and
	 * permuted accordingly. In the end, either {@code x[i] &lt; x[i + 1]} or {@code x[i]
	 * == x[i + 1]} and {@code y[i] &le; y[i + 1]}.
	 *
	 * @param x the first array to be sorted.
	 * @param y the second array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */
	public static KEY_GENERIC void parallelQuickSort(final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y, final int from, final int to) {
		ForkJoinPool pool = getPool();
		if (to - from < PARALLEL_QUICKSORT_NO_FORK || pool.getParallelism() == 1) quickSort(x, y, from, to);
		else {
			pool.invoke(new ForkJoinQuickSort2 KEY_GENERIC_DIAMOND(x, y, from, to));
		}
	}

	/** Sorts two arrays according to the natural lexicographical
	 *  ascending order using a parallel quicksort.
	 *
	 * <p>The sorting algorithm is a tuned quicksort adapted from Jon L. Bentley and M. Douglas
	 * McIlroy, &ldquo;Engineering a Sort Function&rdquo;, <i>Software: Practice and Experience</i>, 23(11), pages
	 * 1249&minus;1265, 1993.
	 *
	 * <p>This method implements a <em>lexicographical</em> sorting of the arguments. Pairs of
	 * elements in the same position in the two provided arrays will be considered a single key, and
	 * permuted accordingly. In the end, either {@code x[i] &lt; x[i + 1]} or {@code x[i]
	 * == x[i + 1]} and {@code y[i] &le; y[i + 1]}.
	 *
	 * @param x the first array to be sorted.
	 * @param y the second array to be sorted.
	 */
	public static KEY_GENERIC void parallelQuickSort(final KEY_GENERIC_TYPE[] x, final KEY_GENERIC_TYPE[] y) {
		ensureSameLength(x, y);
		parallelQuickSort(x, y, 0, x.length);
	}

	/** Sorts an array according to the natural ascending order,
	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array. The
	 * sort will be stable unless it is provable that it would be impossible for there to be any difference
	 * between a stable and unstable sort for the given type, in which case stability is meaningless and thus
	 * unspecified.
	 *
	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 * @since 8.3.0
	 */
	public static KEY_GENERIC void unstableSort(final KEY_GENERIC_TYPE a[], final int from, final int to) {
#if KEYS_PRIMITIVE && !KEY_CLASS_Boolean
#if KEY_CLASS_Byte
			// JDK's sort for bytes uses bucket sort; not even radix sort can beat that.
			java.util.Arrays.sort(a, from, to);
#else
			// TODO For some TBD threshold, delegate to java.util.Arrays.sort if under it.
			if (to - from >= RADIX_SORT_MIN_THRESHOLD) {
				radixSort(a, from, to);
			} else {
				quickSort(a, from, to);
			}
#endif
#else
			quickSort(a, from, to);
#endif
	}

	/** Sorts the specified range of elements according to the natural ascending order
	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
	 * No assurance is made of the stability of the sort.
	 *
	 * @param a the array to be sorted.
	 * @since 8.3.0
	 */
	public static KEY_GENERIC void unstableSort(final KEY_GENERIC_TYPE a[]) {
		unstableSort(a, 0, a.length);
	}

	/** Sorts the specified range of elements according to the order induced by the specified comparator,
	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
	 * No assurance is made of the stability of the sort.
	 *
	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 * @since 8.3.0
	 */
	public static KEY_GENERIC void unstableSort(final KEY_GENERIC_TYPE a[], final int from, final int to, KEY_COMPARATOR KEY_GENERIC comp) {
		quickSort(a, from, to, comp);
	}

	/** Sorts an array according to the order induced by the specified comparator,
	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array.
	 * No assurance is made of the stability of the sort.
	 *
	 * @param a the array to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 * @since 8.3.0
	 */
	public static KEY_GENERIC void unstableSort(final KEY_GENERIC_TYPE a[], KEY_COMPARATOR KEY_GENERIC comp) {
		unstableSort(a, 0, a.length, comp);
	}

	/** Sorts the specified range of elements according to the natural ascending order using mergesort, using a given pre-filled support array.
	 *
	 * <p>This sort is guaranteed to be <i>stable</i>: equal elements will not be reordered as a result
	 * of the sort. Moreover, no support arrays will be allocated.
	 *
	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 * @param supp a support array containing at least {@code to} elements, and whose entries are identical to those
	 * of {@code a} in the specified range. It can be {@code null}, in which case {@code a} will be cloned.
	 */

	SUPPRESS_WARNINGS_KEY_UNCHECKED
	public static KEY_GENERIC void mergeSort(final KEY_GENERIC_TYPE a[], final int from, final int to, KEY_GENERIC_TYPE supp[]) {
		int len = to - from;

		// Insertion sort on smallest arrays
		if (len < MERGESORT_NO_REC) {
			insertionSort(a, from, to);
			return;
		}

		if (supp == null) supp = java.util.Arrays.copyOf(a, to);

		// Recursively sort halves of a into supp
		final int mid = (from + to) >>> 1;
		mergeSort(supp, from, mid, a);
		mergeSort(supp, mid, to, a);

		// If list is already sorted, just copy from supp to a.  This is an
		// optimization that results in faster sorts for nearly ordered lists.
		if (KEY_LESSEQ(supp[mid - 1], supp[mid])) {
			System.arraycopy(supp, from, a, from, len);
			return;
		}

		// Merge sorted halves (now in supp) into a
		for(int i = from, p = from, q = mid; i < to; i++) {
			if (q >= to || p < mid && KEY_LESSEQ(supp[p], supp[q])) a[i] = supp[p++];
			else a[i] = supp[q++];
		}
	}

	/** Sorts the specified range of elements according to the natural ascending order using mergesort.
	 *
	 * <p>This sort is guaranteed to be <i>stable</i>: equal elements will not be reordered as a result
	 * of the sort. An array as large as {@code a} will be allocated by this method.

	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */
	public static KEY_GENERIC void mergeSort(final KEY_GENERIC_TYPE a[], final int from, final int to) {
		mergeSort(a, from, to, (KEY_GENERIC_TYPE[])null);
	}

	/**	Sorts an array according to the natural ascending order using mergesort.
	 *
	 * <p>This sort is guaranteed to be <i>stable</i>: equal elements will not be reordered as a result
	 * of the sort. An array as large as {@code a} will be allocated by this method.

	 * @param a the array to be sorted.
	 */
	public static KEY_GENERIC void mergeSort(final KEY_GENERIC_TYPE a[]) {
		mergeSort(a, 0, a.length);
	}

	/** Sorts the specified range of elements according to the order induced by the specified
	 * comparator using mergesort, using a given pre-filled support array.
	 *
	 * <p>This sort is guaranteed to be <i>stable</i>: equal elements will not be reordered as a result
	 * of the sort. Moreover, no support arrays will be allocated.

	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 * @param supp a support array containing at least {@code to} elements, and whose entries are identical to those
	 * of {@code a} in the specified range. It can be {@code null}, in which case {@code a} will be cloned.
	 */
	public static KEY_GENERIC void mergeSort(final KEY_GENERIC_TYPE a[], final int from, final int to, KEY_COMPARATOR KEY_GENERIC comp, KEY_GENERIC_TYPE supp[]) {
		int len = to - from;

		// Insertion sort on smallest arrays
		if (len < MERGESORT_NO_REC) {
			insertionSort(a, from, to, comp);
			return;
		}

		if (supp == null) supp = java.util.Arrays.copyOf(a, to);

		// Recursively sort halves of a into supp
		final int mid = (from + to) >>> 1;
		mergeSort(supp, from, mid, comp, a);
		mergeSort(supp, mid, to, comp, a);

		// If list is already sorted, just copy from supp to a.  This is an
		// optimization that results in faster sorts for nearly ordered lists.
		if (comp.compare(supp[mid - 1], supp[mid]) <= 0) {
			System.arraycopy(supp, from, a, from, len);
			return;
		}

		// Merge sorted halves (now in supp) into a
		for(int i = from, p = from, q = mid; i < to; i++) {
			if (q >= to || p < mid && comp.compare(supp[p], supp[q]) <= 0) a[i] = supp[p++];
			else a[i] = supp[q++];
		}
	}

	/** Sorts the specified range of elements according to the order induced by the specified
	 * comparator using mergesort.
	 *
	 * <p>This sort is guaranteed to be <i>stable</i>: equal elements will not be reordered as a result
	 * of the sort. An array as large as {@code a} will be allocated by this method.
	 *
	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 */
	public static KEY_GENERIC void mergeSort(final KEY_GENERIC_TYPE a[], final int from, final int to, KEY_COMPARATOR KEY_GENERIC comp) {
		mergeSort(a, from, to, comp, (KEY_GENERIC_TYPE[])null);
	}

	/** Sorts an array according to the order induced by the specified
	 * comparator using mergesort.
	 *
	 * <p>This sort is guaranteed to be <i>stable</i>: equal elements will not be reordered as a result
	 * of the sort.  An array as large as {@code a} will be allocated by this method.

	 * @param a the array to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 */
	public static KEY_GENERIC void mergeSort(final KEY_GENERIC_TYPE a[], KEY_COMPARATOR KEY_GENERIC comp) {
		mergeSort(a, 0, a.length, comp);
	}

	/** Sorts an array according to the natural ascending order,
	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array. The
	 * sort will be stable unless it is provable that it would be impossible for there to be any difference
	 * between a stable and unstable sort for the given type, in which case stability is meaningless and thus
	 * unspecified.
	 *
	 * <p>An array as large as {@code a} may be allocated by this method.
	 *
	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 * @since 8.3.0
	 */
	public static KEY_GENERIC void stableSort(final KEY_GENERIC_TYPE a[], final int from, final int to) {
#if KEYS_REFERENCE
		// Use JDK's sort, which is likely to be adaptive and still be stable.
		java.util.Arrays.sort(a, from, to);
#elif KEYS_PRIMITIVE && !(KEY_CLASS_Float || KEY_CLASS_Double)
		// For non-floating point primitive types, when comparing naturally,
		// it is impossible to tell the difference between a stable and not-stable sort.
		// So just use the probably faster unstable sort.
		unstableSort(a, from, to);
#else
		// Due to subtle differences between Float/Double.compare and operator compare, it is
		// not safe to delegate this to java.util.Arrays.sort(double[], int, int)
		mergeSort(a, from, to);
#endif
	}

	/** Sorts the specified range of elements according to the natural ascending order
	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array. The
	 * sort will be stable unless it is provable that it would be impossible for there to be any difference
	 * between a stable and unstable sort for the given type, in which case stability is meaningless and thus
	 * unspecified.
	 *
	 * <p>An array as large as {@code a} may be allocated by this method.
	 *
	 * @param a the array to be sorted.
	 * @since 8.3.0
	 */
	public static KEY_GENERIC void stableSort(final KEY_GENERIC_TYPE a[]) {
		stableSort(a, 0, a.length);
	}

	/** Sorts the specified range of elements according to the order induced by the specified comparator,
	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array. The
	 * sort will be stable unless it is provable that it would be impossible for there to be any difference
	 * between a stable and unstable sort for the given type, in which case stability is meaningless and thus
	 * unspecified.
	 *
	 * <p>An array as large as {@code a} may be allocated by this method.
	 *
	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 * @since 8.3.0
	 */
	public static KEY_GENERIC void stableSort(final KEY_GENERIC_TYPE a[], final int from, final int to, KEY_COMPARATOR KEY_GENERIC comp) {
#if KEYS_REFERENCE
		// Use JDK's sort, which is likely to be adaptive and still be stable.
		java.util.Arrays.sort(a, from, to, comp);
#else
		mergeSort(a, from, to, comp);
#endif
	}

	/** Sorts an array according to the order induced by the specified comparator,
	 * potentially dynamically choosing an appropriate algorithm given the type and size of the array. The
	 * sort will be stable unless it is provable that it would be impossible for there to be any difference
	 * between a stable and unstable sort for the given type, in which case stability is meaningless and thus
	 * unspecified.
	 *
	 * <p>An array as large as {@code a} may be allocated by this method.
	 *
	 * @param a the array to be sorted.
	 * @param comp the comparator to determine the sorting order.
	 * @since 8.3.0
	 */
	public static KEY_GENERIC void stableSort(final KEY_GENERIC_TYPE a[], KEY_COMPARATOR KEY_GENERIC comp) {
		stableSort(a, 0, a.length, comp);
	}

#if ! KEY_CLASS_Boolean

	/**
	 * Searches a range of the specified array for the specified value using
	 * the binary search algorithm. The range must be sorted 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 from  the index of the first element (inclusive) to be searched.
	 * @param to  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;
	 *             otherwise, {@code (-(<i>insertion point</i>) - 1)}.  The <i>insertion
	 *             point</i> is defined as the the point at which the value would
	 *             be inserted into the array: the index of the first
	 *             element greater than the key, or the length of the array, if all
	 *             elements in the array are less than the specified key.  Note
	 *             that this guarantees that the return value will be &ge; 0 if
	 *             and only if the key is found.
	 * @see java.util.Arrays
	 */
	SUPPRESS_WARNINGS_KEY_UNCHECKED
	public static KEY_GENERIC int binarySearch(final KEY_GENERIC_TYPE[] a, int from, int to, final KEY_GENERIC_TYPE key) {
		KEY_GENERIC_TYPE midVal;
		to--;
		while (from <= to) {
			final int mid = (from + to) >>> 1;
			midVal = a[mid];
#if KEYS_PRIMITIVE
			if (midVal < key) from = mid + 1;
			else if (midVal > key) to = mid - 1;
			else return mid;
#else
			final int cmp = ((Comparable KEY_SUPER_GENERIC)midVal).compareTo(key);
			if (cmp < 0) from = mid + 1;
			else if (cmp > 0) to = mid - 1;
			else return mid;
#endif
		}
		return -(from + 1);
	}

	/**
	 * Searches an array for the specified value using
	 * the binary search algorithm. The range must be sorted 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 key the value to be searched for.
	 * @return index of the search key, if it is contained in the array;
	 *             otherwise, {@code (-(<i>insertion point</i>) - 1)}.  The <i>insertion
	 *             point</i> is defined as the the point at which the value would
	 *             be inserted into the array: the index of the first
	 *             element greater than the key, or the length of the array, if all
	 *             elements in the array are less than the specified key.  Note
	 *             that this guarantees that the return value will be &ge; 0 if
	 *             and only if the key is found.
	 * @see java.util.Arrays
	 */
	public static KEY_GENERIC int binarySearch(final KEY_GENERIC_TYPE[] a, final KEY_GENERIC_TYPE key) {
		return binarySearch(a, 0, a.length, key);
	}

	/**
	 * Searches a range of the specified array for the specified value using
	 * the binary search algorithm and a specified comparator. The range must be sorted following the comparator 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 from  the index of the first element (inclusive) to be searched.
	 * @param to  the index of the last element (exclusive) to be searched.
	 * @param key the value to be searched for.
	 * @param c a comparator.
	 * @return index of the search key, if it is contained in the array;
	 *             otherwise, {@code (-(<i>insertion point</i>) - 1)}.  The <i>insertion
	 *             point</i> is defined as the the point at which the value would
	 *             be inserted into the array: the index of the first
	 *             element greater than the key, or the length of the array, if all
	 *             elements in the array are less than the specified key.  Note
	 *             that this guarantees that the return value will be &ge; 0 if
	 *             and only if the key is found.
	 * @see java.util.Arrays
	 */
	public static KEY_GENERIC int binarySearch(final KEY_GENERIC_TYPE[] a, int from, int to, final KEY_GENERIC_TYPE key, final KEY_COMPARATOR KEY_GENERIC c) {
		KEY_GENERIC_TYPE midVal;
		to--;
		while (from <= to) {
			final int mid = (from + to) >>> 1;
			midVal = a[mid];
			final int cmp = c.compare(midVal, key);
			if (cmp < 0) from = mid + 1;
			else if (cmp > 0) to = mid - 1;
			else return mid; // key found
		}
		return -(from + 1);
	}

	/**
	 * Searches an array for the specified value using
	 * the binary search algorithm and a specified comparator. The range must be sorted following the comparator 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 key the value to be searched for.
	 * @param c a comparator.
	 * @return index of the search key, if it is contained in the array;
	 *             otherwise, {@code (-(<i>insertion point</i>) - 1)}.  The <i>insertion
	 *             point</i> is defined as the the point at which the value would
	 *             be inserted into the array: the index of the first
	 *             element greater than the key, or the length of the array, if all
	 *             elements in the array are less than the specified key.  Note
	 *             that this guarantees that the return value will be &ge; 0 if
	 *             and only if the key is found.
	 * @see java.util.Arrays
	 */
	public static KEY_GENERIC int binarySearch(final KEY_GENERIC_TYPE[] a, final KEY_GENERIC_TYPE key, final KEY_COMPARATOR KEY_GENERIC c) {
		return binarySearch(a, 0, a.length, key, c);
	}


#if KEYS_PRIMITIVE
	/** The size of a digit used during radix sort (must be a power of 2). */
	private static final int DIGIT_BITS = 8;
	/** The mask to extract a digit of {@link #DIGIT_BITS} bits. */
	private static final int DIGIT_MASK = (1 << DIGIT_BITS) - 1;
	/** The number of digits per element. */
	private static final int DIGITS_PER_ELEMENT = KEY_CLASS.SIZE / DIGIT_BITS;
	private static final int RADIXSORT_NO_REC = 1024;
	private static final int RADIXSORT_NO_REC_SMALL = 64;
	private static final int PARALLEL_RADIXSORT_NO_FORK = 1024;

	// The thresholds were determined on an Intel i7 8700K.
	/** Threshold <em>hint</em> for using a radix sort vs a comparison based sort. */
#if KEY_CLASS_Byte || KEY_CLASS_Short
	static final int RADIX_SORT_MIN_THRESHOLD = 1000;
#elif KEY_CLASS_Long || KEY_CLASS_Double
	static final int RADIX_SORT_MIN_THRESHOLD = 4000;
#else
	static final int RADIX_SORT_MIN_THRESHOLD = 2000;
#endif

	/** This method fixes negative numbers so that the combination exponent/significand is lexicographically sorted. */
#if KEY_CLASS_Double
	private static final long fixDouble(final double d) {
		final long l = Double.doubleToLongBits(d);
		return l >= 0 ? l : l ^ 0x7FFFFFFFFFFFFFFFL;
	}
#elif KEY_CLASS_Float
	private static final int fixFloat(final float f) {
		final int i = Float.floatToIntBits(f);
		return i >= 0 ? i : i ^ 0x7FFFFFFF;
	}
#endif


	/** Sorts the specified array using radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * @implSpec This implementation is significantly faster than quicksort
	 * already at small sizes (say, more than 5000 elements), but it can only
	 * sort in ascending order.
	 *
	 * @param a the array to be sorted.
	 */
	public static void radixSort(final KEY_TYPE[] a) {
		radixSort(a, 0, a.length);
	}

	/** Sorts the specified range of an array using radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * @implSpec This implementation is significantly faster than quicksort
	 * already at small sizes (say, more than 5000 elements), but it can only
	 * sort in ascending order.
	 *
	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */
	public static void radixSort(final KEY_TYPE[] a, final int from, final int to) {
		if (to - from < RADIXSORT_NO_REC) {
			quickSort(a, from, to);
			return;
		}

		final int maxLevel = DIGITS_PER_ELEMENT - 1;

		final int stackSize = ((1 << DIGIT_BITS) - 1) * (DIGITS_PER_ELEMENT - 1) + 1;
		int stackPos = 0;
		final int[] offsetStack = new int[stackSize];
		final int[] lengthStack = new int[stackSize];
		final int[] levelStack = new int[stackSize];

		offsetStack[stackPos] = from;
		lengthStack[stackPos] = to - from;
		levelStack[stackPos++] = 0;

		final int[] count = new int[1 << DIGIT_BITS];
		final int[] pos = new int[1 << DIGIT_BITS];

		while(stackPos > 0) {
			final int first = offsetStack[--stackPos];
			final int length = lengthStack[stackPos];
			final int level = levelStack[stackPos];
#if KEY_CLASS_Character
			final int signMask = 0;
#else
			final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif
			final int shift = (DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT) * DIGIT_BITS; // This is the shift that extract the right byte from a key

			// Count keys.
			for(int i = first + length; i-- != first;) count[INT(KEY2LEXINT(a[i]) >>> shift & DIGIT_MASK ^ signMask)]++;
			// Compute cumulative distribution
			int lastUsed = -1;
			for (int i = 0, p = first; i < 1 << DIGIT_BITS; i++) {
				if (count[i] != 0) lastUsed = i;
				pos[i] = (p += count[i]);
			}

			final int end = first + length - count[lastUsed];
			// i moves through the start of each block
			for(int i = first, c = -1, d; i <= end; i += count[c], count[c] = 0) {
				KEY_TYPE t = a[i];
				c = INT(KEY2LEXINT(t) >>> shift & DIGIT_MASK ^ signMask);

				if (i < end) { // When all slots are OK, the last slot is necessarily OK.
					while ((d = --pos[c]) > i) {
						final KEY_TYPE z = t;
						t = a[d];
						a[d] = z;
						c = INT(KEY2LEXINT(t) >>> shift & DIGIT_MASK ^ signMask);
					}
					a[i] = t;
				}

				if (level < maxLevel && count[c] > 1) {
					if (count[c] < RADIXSORT_NO_REC) quickSort(a, i, i + count[c]);
					else {
						offsetStack[stackPos] = i;
						lengthStack[stackPos] = count[c];
						levelStack[stackPos++] = level + 1;
					}
				}
			}
		}
	}

	protected static final class Segment {
		protected final int offset, length, level;
		protected Segment(final int offset, final int length, final int level) {
			this.offset = offset;
			this.length = length;
			this.level = level;
		}

		@Override
		public String toString() { return "Segment [offset=" + offset + ", length=" + length + ", level=" + level + "]"; }
	}

	protected static final Segment POISON_PILL = new Segment(-1, -1, -1);


	/** Sorts the specified range of an array using parallel radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */
	public static void parallelRadixSort(final KEY_TYPE[] a, final int from, final int to) {
		ForkJoinPool pool = getPool();
		if (to - from < PARALLEL_RADIXSORT_NO_FORK || pool.getParallelism() == 1) {
			quickSort(a, from, to);
			return;
		}
		final int maxLevel = DIGITS_PER_ELEMENT - 1;
		final LinkedBlockingQueue<Segment> queue = new LinkedBlockingQueue<>();
		queue.add(new Segment(from, to - from, 0));
		final AtomicInteger queueSize = new AtomicInteger(1);
		final int numberOfThreads = pool.getParallelism();
		final ExecutorCompletionService<Void> executorCompletionService = new ExecutorCompletionService<>(pool);

		for(int j = numberOfThreads; j-- != 0;) executorCompletionService.submit(() -> {
			final int[] count = new int[1 << DIGIT_BITS];
			final int[] pos = new int[1 << DIGIT_BITS];

			for(;;) {
				if (queueSize.get() == 0) for(int i = numberOfThreads; i-- != 0;) queue.add(POISON_PILL);
				final Segment segment = queue.take();
				if (segment == POISON_PILL) return null;

				final int first = segment.offset;
				final int length = segment.length;
				final int level = segment.level;

#if KEY_CLASS_Character
				final int signMask = 0;
#else
				final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif
				final int shift = (DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT) * DIGIT_BITS; // This is the shift that extract the right byte from a key

				// Count keys.
				for(int i = first + length; i-- != first;) count[INT(KEY2LEXINT(a[i]) >>> shift & DIGIT_MASK ^ signMask)]++;
				// Compute cumulative distribution
				int lastUsed = -1;
				for(int i = 0, p = first; i < 1 << DIGIT_BITS; i++) {
					if (count[i] != 0) lastUsed = i;
					pos[i] = (p += count[i]);
				}

				final int end = first + length - count[lastUsed];
				// i moves through the start of each block
				for(int i = first, c = -1, d; i <= end; i += count[c], count[c] = 0) {
					KEY_TYPE t = a[i];
					c = INT(KEY2LEXINT(t) >>> shift & DIGIT_MASK ^ signMask);
					if (i < end) {
						while((d = --pos[c]) > i) {
							final KEY_TYPE z = t;
							t = a[d];
							a[d] = z;
							c = INT(KEY2LEXINT(t) >>> shift & DIGIT_MASK ^ signMask);
						}
						a[i] = t;
					}

					if (level < maxLevel && count[c] > 1) {
						if (count[c] < PARALLEL_RADIXSORT_NO_FORK) quickSort(a, i, i + count[c]);
						else {
							queueSize.incrementAndGet();
							queue.add(new Segment(i, count[c], level + 1));
						}
					}
				}
				queueSize.decrementAndGet();
			}
		});

		Throwable problem = null;
		for(int i = numberOfThreads; i-- != 0;)
			try {
				executorCompletionService.take().get();
			}
			catch(Exception e) {
				problem = e.getCause(); // We keep only the last one. They will be logged anyway.
			}

		if (problem != null) throw (problem instanceof RuntimeException) ? (RuntimeException)problem : new RuntimeException(problem);
	}

	/** Sorts the specified array using parallel radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * @param a the array to be sorted.
	 */
	public static void parallelRadixSort(final KEY_TYPE[] a) {
		parallelRadixSort(a, 0, a.length);
	}

	/** Sorts the specified array using indirect radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implement an <em>indirect</em> sort. The elements of {@code perm} (which must
	 * be exactly the numbers in the interval {@code [0..perm.length)}) will be permuted so that
	 * {@code a[perm[i]] &le; a[perm[i + 1]]}.
	 *
	 * @implSpec This implementation will allocate, in the stable case, a support array as large as {@code perm} (note that the stable
	 * version is slightly faster).
	 *
	 * @param perm a permutation array indexing {@code a}.
	 * @param a the array to be sorted.
	 * @param stable whether the sorting algorithm should be stable.
	 */
	public static void radixSortIndirect(final int[] perm, final KEY_TYPE[] a, final boolean stable) {
		radixSortIndirect(perm, a, 0, perm.length, stable);
	}

	/** Sorts the specified array using indirect radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implement an <em>indirect</em> sort. The elements of {@code perm} (which must
	 * be exactly the numbers in the interval {@code [0..perm.length)}) will be permuted so that
	 * {@code a[perm[i]] &le; a[perm[i + 1]]}.
	 *
	 * @implSpec This implementation will allocate, in the stable case, a support array as large as {@code perm} (note that the stable
	 * version is slightly faster).
	 *
	 * @param perm a permutation array indexing {@code a}.
	 * @param a the array to be sorted.
	 * @param from the index of the first element of {@code perm} (inclusive) to be permuted.
	 * @param to the index of the last element of {@code perm} (exclusive) to be permuted.
	 * @param stable whether the sorting algorithm should be stable.
	 */
	public static void radixSortIndirect(final int[] perm, final KEY_TYPE[] a, final int from, final int to, final boolean stable) {
		if (to - from < RADIXSORT_NO_REC) {
			quickSortIndirect(perm, a, from, to);
			if (stable) stabilize(perm, a, from, to);
			return;
		}

		final int maxLevel = DIGITS_PER_ELEMENT - 1;

		final int stackSize = ((1 << DIGIT_BITS) - 1) * (DIGITS_PER_ELEMENT - 1) + 1;
		int stackPos = 0;
		final int[] offsetStack = new int[stackSize];
		final int[] lengthStack = new int[stackSize];
		final int[] levelStack = new int[stackSize];

		offsetStack[stackPos] = from;
		lengthStack[stackPos] = to - from;
		levelStack[stackPos++] = 0;

		final int[] count = new int[1 << DIGIT_BITS];
		final int[] pos = new int[1 << DIGIT_BITS];
		final int[] support = stable ? new int[perm.length] : null;

		while(stackPos > 0) {
			final int first = offsetStack[--stackPos];
			final int length = lengthStack[stackPos];
			final int level = levelStack[stackPos];
#if KEY_CLASS_Character
			final int signMask = 0;
#else
			final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif

			final int shift = (DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT) * DIGIT_BITS; // This is the shift that extract the right byte from a key

			// Count keys.
			for(int i = first + length; i-- != first;) count[INT(KEY2LEXINT(a[perm[i]]) >>> shift & DIGIT_MASK ^ signMask)]++;
			// Compute cumulative distribution
			int lastUsed = -1;
			for (int i = 0, p = stable ? 0 : first; i < 1 << DIGIT_BITS; i++) {
				if (count[i] != 0) lastUsed = i;
				pos[i] = (p += count[i]);
			}

			if (stable) {
				for(int i = first + length; i-- != first;) support[--pos[INT(KEY2LEXINT(a[perm[i]]) >>> shift & DIGIT_MASK ^ signMask)]] = perm[i];
				System.arraycopy(support, 0, perm, first, length);
				for(int i = 0, p = first; i <= lastUsed; i++) {
					if (level < maxLevel && count[i] > 1) {
						if (count[i] < RADIXSORT_NO_REC) {
							quickSortIndirect(perm, a, p, p + count[i]);
							if (stable) stabilize(perm, a, p, p + count[i]);
						}
						else {
							offsetStack[stackPos] = p;
							lengthStack[stackPos] = count[i];
							levelStack[stackPos++] = level + 1;
						}
					}
					p += count[i];
				}
				java.util.Arrays.fill(count, 0);
			}
			else {
				final int end = first + length - count[lastUsed];
				// i moves through the start of each block
				for(int i = first, c = -1, d; i <= end; i += count[c], count[c] = 0) {
					int t = perm[i];
					c = INT(KEY2LEXINT(a[t]) >>> shift & DIGIT_MASK ^ signMask);

					if (i < end) { // When all slots are OK, the last slot is necessarily OK.
						while((d = --pos[c]) > i) {
							final int z = t;
							t = perm[d];
							perm[d] = z;
							c = INT(KEY2LEXINT(a[t]) >>> shift & DIGIT_MASK ^ signMask);
						}
						perm[i] = t;
					}

					if (level < maxLevel && count[c] > 1) {
						if (count[c] < RADIXSORT_NO_REC) {
							quickSortIndirect(perm, a, i, i + count[c]);
							if (stable) stabilize(perm, a, i, i + count[c]);
						}
						else {
							offsetStack[stackPos] = i;
							lengthStack[stackPos] = count[c];
							levelStack[stackPos++] = level + 1;
						}
					}
				}
			}
		}
	}

	/** Sorts the specified range of an array using parallel indirect radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implement an <em>indirect</em> sort. The elements of {@code perm} (which must
	 * be exactly the numbers in the interval {@code [0..perm.length)}) will be permuted so that
	 * {@code a[perm[i]] &le; a[perm[i + 1]]}.
	 *
	 * @param perm a permutation array indexing {@code a}.
	 * @param a the array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 * @param stable whether the sorting algorithm should be stable.
	 */
	public static void parallelRadixSortIndirect(final int perm[], final KEY_TYPE[] a, final int from, final int to, final boolean stable) {
		ForkJoinPool pool = getPool();
		if (to - from < PARALLEL_RADIXSORT_NO_FORK || pool.getParallelism() == 1) {
			radixSortIndirect(perm, a, from, to, stable);
			return;
		}
		final int maxLevel = DIGITS_PER_ELEMENT - 1;
		final LinkedBlockingQueue<Segment> queue = new LinkedBlockingQueue<>();
		queue.add(new Segment(from, to - from, 0));
		final AtomicInteger queueSize = new AtomicInteger(1);
		final int numberOfThreads = pool.getParallelism();
		final ExecutorCompletionService<Void> executorCompletionService = new ExecutorCompletionService<>(pool);
		final int[] support = stable ? new int[perm.length] : null;

		for(int j = numberOfThreads; j-- != 0;) executorCompletionService.submit(() -> {
			final int[] count = new int[1 << DIGIT_BITS];
			final int[] pos = new int[1 << DIGIT_BITS];

			for(;;) {
				if (queueSize.get() == 0) for(int i = numberOfThreads; i-- != 0;) queue.add(POISON_PILL);
				final Segment segment = queue.take();
				if (segment == POISON_PILL) return null;

				final int first = segment.offset;
				final int length = segment.length;
				final int level = segment.level;

#if KEY_CLASS_Character
				final int signMask = 0;
#else
				final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif
				final int shift = (DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT) * DIGIT_BITS; // This is the shift that extract the right byte from a key


				// Count keys.
				for(int i = first + length; i-- != first;) count[INT(KEY2LEXINT(a[perm[i]]) >>> shift & DIGIT_MASK ^ signMask)]++;
				// Compute cumulative distribution
				int lastUsed = -1;
				for (int i = 0, p = first; i < 1 << DIGIT_BITS; i++) {
					if (count[i] != 0) lastUsed = i;
					pos[i] = (p += count[i]);
				}

				if (stable) {
					for(int i = first + length; i-- != first;) support[--pos[INT(KEY2LEXINT(a[perm[i]]) >>> shift & DIGIT_MASK ^ signMask)]] = perm[i];
					System.arraycopy(support, first, perm, first, length);
					for(int i = 0, p = first; i <= lastUsed; i++) {
						if (level < maxLevel && count[i] > 1) {
							if (count[i] < PARALLEL_RADIXSORT_NO_FORK) radixSortIndirect(perm, a, p, p + count[i], stable);
							else {
								queueSize.incrementAndGet();
								queue.add(new Segment(p, count[i], level + 1));
							}
						}
						p += count[i];
					}
					java.util.Arrays.fill(count, 0);
				}
				else {
					final int end = first + length - count[lastUsed];
					// i moves through the start of each block
					for(int i = first, c = -1, d; i <= end; i += count[c], count[c] = 0) {
						int t = perm[i];
						c = INT(KEY2LEXINT(a[t]) >>> shift & DIGIT_MASK ^ signMask);

						if (i < end) { // When all slots are OK, the last slot is necessarily OK.
							while((d = --pos[c]) > i) {
								final int z = t;
								t = perm[d];
								perm[d] = z;
								c = INT(KEY2LEXINT(a[t]) >>> shift & DIGIT_MASK ^ signMask);
							}
							perm[i] = t;
						}

						if (level < maxLevel && count[c] > 1) {
							if (count[c] < PARALLEL_RADIXSORT_NO_FORK) radixSortIndirect(perm, a, i, i + count[c], stable);
							else {
								queueSize.incrementAndGet();
								queue.add(new Segment(i, count[c], level + 1));
							}
						}
					}
				}
				queueSize.decrementAndGet();
			}
		});

		Throwable problem = null;
		for(int i = numberOfThreads; i-- != 0;)
			try {
				executorCompletionService.take().get();
			}
			catch(Exception e) {
				problem = e.getCause(); // We keep only the last one. They will be logged anyway.
			}

		if (problem != null) throw (problem instanceof RuntimeException) ? (RuntimeException)problem : new RuntimeException(problem);
	}

	/** Sorts the specified array using parallel indirect radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implement an <em>indirect</em> sort. The elements of {@code perm} (which must
	 * be exactly the numbers in the interval {@code [0..perm.length)}) will be permuted so that
	 * {@code a[perm[i]] &le; a[perm[i + 1]]}.
	 *
	 * @param perm a permutation array indexing {@code a}.
	 * @param a the array to be sorted.
	 * @param stable whether the sorting algorithm should be stable.
	 */
	public static void parallelRadixSortIndirect(final int perm[], final KEY_TYPE[] a, final boolean stable) {
		parallelRadixSortIndirect(perm, a, 0, a.length, stable);
	}

	/** Sorts the specified pair of arrays lexicographically using radix sort.
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implements a <em>lexicographical</em> sorting of the arguments. Pairs of elements
	 * in the same position in the two provided arrays will be considered a single key, and permuted
	 * accordingly. In the end, either {@code a[i] &lt; a[i + 1]} or {@code a[i] == a[i + 1]} and {@code b[i] &le; b[i + 1]}.
	 *
	 * @param a the first array to be sorted.
	 * @param b the second array to be sorted.
	 */

	public static void radixSort(final KEY_TYPE[] a, final KEY_TYPE[] b) {
		ensureSameLength(a, b);
		radixSort(a, b, 0, a.length);
	}

	/** Sorts the specified range of elements of two arrays using radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implements a <em>lexicographical</em> sorting of the arguments. Pairs of elements
	 * in the same position in the two provided arrays will be considered a single key, and permuted
	 * accordingly. In the end, either {@code a[i] &lt; a[i + 1]} or {@code a[i] == a[i + 1]} and {@code b[i] &le; b[i + 1]}.
	 *
	 * @param a the first array to be sorted.
	 * @param b the second array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */
	public static void radixSort(final KEY_TYPE[] a, final KEY_TYPE[] b, final int from, final int to) {
		if (to - from < RADIXSORT_NO_REC) {
			quickSort(a, b, from, to);
			return;
		}

		final int layers = 2;
		final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;

		final int stackSize = ((1 << DIGIT_BITS) - 1) * (layers * DIGITS_PER_ELEMENT - 1) + 1;
		int stackPos = 0;
		final int[] offsetStack = new int[stackSize];
		final int[] lengthStack = new int[stackSize];
		final int[] levelStack = new int[stackSize];

		offsetStack[stackPos] = from;
		lengthStack[stackPos] = to - from;
		levelStack[stackPos++] = 0;

		final int[] count = new int[1 << DIGIT_BITS];
		final int[] pos = new int[1 << DIGIT_BITS];

		while(stackPos > 0) {
			final int first = offsetStack[--stackPos];
			final int length = lengthStack[stackPos];
			final int level = levelStack[stackPos];
#if KEY_CLASS_Character
			final int signMask = 0;
#else
			final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif

			final KEY_TYPE[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array
			final int shift = (DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT) * DIGIT_BITS; // This is the shift that extract the right byte from a key

			// Count keys.
			for(int i = first + length; i-- != first;) count[INT(KEY2LEXINT(k[i]) >>> shift & DIGIT_MASK ^ signMask)]++;

			// Compute cumulative distribution
			int lastUsed = -1;
			for (int i = 0, p = first; i < 1 << DIGIT_BITS; i++) {
				if (count[i] != 0) lastUsed = i;
				pos[i] = (p += count[i]);
			}


			final int end = first + length - count[lastUsed];
			// i moves through the start of each block
			for(int i = first, c = -1, d; i <= end; i += count[c], count[c] = 0) {
				KEY_TYPE t = a[i];
				KEY_TYPE u = b[i];
				c = INT(KEY2LEXINT(k[i]) >>> shift & DIGIT_MASK ^ signMask);

				if (i < end) { // When all slots are OK, the last slot is necessarily OK.
					while((d = --pos[c]) > i) {
						c = INT(KEY2LEXINT(k[d]) >>> shift & DIGIT_MASK ^ signMask);
						KEY_TYPE z = t;
						t = a[d];
						a[d] = z;
						z = u;
						u = b[d];
						b[d] = z;
					}
					a[i] = t;
					b[i] = u;

				}

				if (level < maxLevel && count[c] > 1) {
					if (count[c] < RADIXSORT_NO_REC) quickSort(a, b, i, i + count[c]);
					else {
						offsetStack[stackPos] = i;
						lengthStack[stackPos] = count[c];
						levelStack[stackPos++] = level + 1;
					}
				}
			}
		}
	}

	/** Sorts the specified range of elements of two arrays using a parallel radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implements a <em>lexicographical</em> sorting of the arguments. Pairs of elements
	 * in the same position in the two provided arrays will be considered a single key, and permuted
	 * accordingly. In the end, either {@code a[i] &lt; a[i + 1]} or {@code a[i] == a[i + 1]} and {@code b[i] &le; b[i + 1]}.
	 *
	 * @param a the first array to be sorted.
	 * @param b the second array to be sorted.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */
	public static void parallelRadixSort(final KEY_TYPE[] a, final KEY_TYPE[] b, final int from, final int to) {
		ForkJoinPool pool = getPool();
		if (to - from < PARALLEL_RADIXSORT_NO_FORK || pool.getParallelism() == 1) {
			quickSort(a, b, from, to);
			return;
		}
		final int layers = 2;
		if (a.length != b.length) throw new IllegalArgumentException("Array size mismatch.");
		final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;
		final LinkedBlockingQueue<Segment> queue = new LinkedBlockingQueue<>();
		queue.add(new Segment(from, to - from, 0));
		final AtomicInteger queueSize = new AtomicInteger(1);
		final int numberOfThreads = pool.getParallelism();
		final ExecutorCompletionService<Void> executorCompletionService = new ExecutorCompletionService<>(pool);
		for (int j = numberOfThreads; j-- != 0;) executorCompletionService.submit(() -> {
				final int[] count = new int[1 << DIGIT_BITS];
				final int[] pos = new int[1 << DIGIT_BITS];
				for (;;) {
					if (queueSize.get() == 0) for (int i = numberOfThreads; i-- != 0;)
						queue.add(POISON_PILL);
					final Segment segment = queue.take();
					if (segment == POISON_PILL) return null;
					final int first = segment.offset;
					final int length = segment.length;
					final int level = segment.level;
					final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
					final KEY_TYPE[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array
					final int shift = (DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT) * DIGIT_BITS;
					// Count keys.
					for (int i = first + length; i-- != first;)
						count[INT(KEY2LEXINT(k[i]) >>> shift & DIGIT_MASK ^ signMask)]++;
					// Compute cumulative distribution
					int lastUsed = -1;
					for (int i = 0, p = first; i < 1 << DIGIT_BITS; i++) {
						if (count[i] != 0) lastUsed = i;
						pos[i] = (p += count[i]);
					}
					final int end = first + length - count[lastUsed];
					for (int i = first, c = -1, d; i <= end; i += count[c], count[c] = 0) {
						KEY_TYPE t = a[i];
						KEY_TYPE u = b[i];
						c = INT(KEY2LEXINT(k[i]) >>> shift & DIGIT_MASK ^ signMask);
						if (i < end) { // When all slots are OK, the last slot is necessarily OK.
							while ((d = --pos[c]) > i) {
								c = INT(KEY2LEXINT(k[d]) >>> shift & DIGIT_MASK ^ signMask);
								final KEY_TYPE z = t;
								final KEY_TYPE w = u;
								t = a[d];
								u = b[d];
								a[d] = z;
								b[d] = w;
							}
							a[i] = t;
							b[i] = u;
						}
						if (level < maxLevel && count[c] > 1) {
							if (count[c] < PARALLEL_RADIXSORT_NO_FORK) quickSort(a, b, i, i + count[c]);
							else {
								queueSize.incrementAndGet();
								queue.add(new Segment(i, count[c], level + 1));
							}
						}
					}
					queueSize.decrementAndGet();
				}
			});
		Throwable problem = null;
		for (int i = numberOfThreads; i-- != 0;)
			try {
				executorCompletionService.take().get();
			}
			catch (Exception e) {
				problem = e.getCause(); // We keep only the last one. They will be logged anyway.
			}
		if (problem != null) throw (problem instanceof RuntimeException) ? (RuntimeException)problem : new RuntimeException(problem);
	}


	/** Sorts two arrays using a parallel radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implements a <em>lexicographical</em> sorting of the arguments. Pairs of elements
	 * in the same position in the two provided arrays will be considered a single key, and permuted
	 * accordingly. In the end, either {@code a[i] &lt; a[i + 1]} or {@code a[i] == a[i + 1]} and {@code b[i] &le; b[i + 1]}.
	 *
	 * @param a the first array to be sorted.
	 * @param b the second array to be sorted.
	 */
	public static void parallelRadixSort(final KEY_TYPE[] a, final KEY_TYPE[] b) {
		ensureSameLength(a, b);
		parallelRadixSort(a, b, 0, a.length);
	}


	private static KEY_GENERIC void insertionSortIndirect(final int[] perm, final KEY_TYPE[] a, final KEY_TYPE[] b, final int from, final int to) {
		for (int i = from; ++i < to;) {
			int t = perm[i];
			int j = i;
			for (int u = perm[j - 1]; KEY_LESS(a[t], a[u]) || KEY_CMP_EQ(a[t], a[u]) && KEY_LESS(b[t], b[u]); u = perm[--j - 1]) {
				perm[j] = u;
				if (from == j - 1) {
					--j;
					break;
				}
			}
			perm[j] = t;
		}
	}

	/** Sorts the specified pair of arrays lexicographically using indirect radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implement an <em>indirect</em> sort. The elements of {@code perm} (which must
	 * be exactly the numbers in the interval {@code [0..perm.length)}) will be permuted so that
	 * {@code a[perm[i]] &le; a[perm[i + 1]]} or {@code a[perm[i]] == a[perm[i + 1]]} and {@code b[perm[i]] &le; b[perm[i + 1]]}.
	 *
	 * @implSpec This implementation will allocate, in the stable case, a further support array as large as {@code perm} (note that the stable
	 * version is slightly faster).
	 *
	 * @param perm a permutation array indexing {@code a}.
	 * @param a the array to be sorted.
	 * @param b the second array to be sorted.
	 * @param stable whether the sorting algorithm should be stable.
	 */
	public static void radixSortIndirect(final int[] perm, final KEY_TYPE[] a, final KEY_TYPE[] b, final boolean stable) {
		ensureSameLength(a, b);
		radixSortIndirect(perm, a, b, 0, a.length, stable);
	}

	/** Sorts the specified pair of arrays lexicographically using indirect radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implement an <em>indirect</em> sort. The elements of {@code perm} (which must
	 * be exactly the numbers in the interval {@code [0..perm.length)}) will be permuted so that
	 * {@code a[perm[i]] &le; a[perm[i + 1]]} or {@code a[perm[i]] == a[perm[i + 1]]} and {@code b[perm[i]] &le; b[perm[i + 1]]}.
	 *
	 * @implSpec This implementation will allocate, in the stable case, a further support array as large as {@code perm} (note that the stable
	 * version is slightly faster).
	 *
	 * @param perm a permutation array indexing {@code a}.
	 * @param a the array to be sorted.
	 * @param b the second array to be sorted.
	 * @param from the index of the first element of {@code perm} (inclusive) to be permuted.
	 * @param to the index of the last element of {@code perm} (exclusive) to be permuted.
	 * @param stable whether the sorting algorithm should be stable.
	 */
	public static void radixSortIndirect(final int[] perm, final KEY_TYPE[] a, final KEY_TYPE[] b, final int from, final int to, final boolean stable) {
		if (to - from < RADIXSORT_NO_REC_SMALL) {
			insertionSortIndirect(perm, a, b, from, to);
			return;
		}

		final int layers = 2;
		final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;

		final int stackSize = ((1 << DIGIT_BITS) - 1) * (layers * DIGITS_PER_ELEMENT - 1) + 1;
		int stackPos = 0;
		final int[] offsetStack = new int[stackSize];
		final int[] lengthStack = new int[stackSize];
		final int[] levelStack = new int[stackSize];

		offsetStack[stackPos] = from;
		lengthStack[stackPos] = to - from;
		levelStack[stackPos++] = 0;

		final int[] count = new int[1 << DIGIT_BITS];
		final int[] pos = new int[1 << DIGIT_BITS];
		final int[] support = stable ? new int[perm.length] : null;

		while(stackPos > 0) {
			final int first = offsetStack[--stackPos];
			final int length = lengthStack[stackPos];
			final int level = levelStack[stackPos];
#if KEY_CLASS_Character
			final int signMask = 0;
#else
			final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif

			final KEY_TYPE[] k = level < DIGITS_PER_ELEMENT ? a : b; // This is the key array
			final int shift = (DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT) * DIGIT_BITS; // This is the shift that extract the right byte from a key

			// Count keys.
			for(int i = first + length; i-- != first;) count[INT(KEY2LEXINT(k[perm[i]]) >>> shift & DIGIT_MASK ^ signMask)]++;

			// Compute cumulative distribution
			int lastUsed = -1;
			for (int i = 0, p = stable ? 0 : first; i < 1 << DIGIT_BITS; i++) {
				if (count[i] != 0) lastUsed = i;
				pos[i] = (p += count[i]);
			}

			if (stable) {
				for(int i = first + length; i-- != first;) support[--pos[INT(KEY2LEXINT(k[perm[i]]) >>> shift & DIGIT_MASK ^ signMask)]] = perm[i];
				System.arraycopy(support, 0, perm, first, length);
				for(int i = 0, p = first; i < 1 << DIGIT_BITS; i++) {
					if (level < maxLevel && count[i] > 1) {
						if (count[i] < RADIXSORT_NO_REC_SMALL) insertionSortIndirect(perm, a, b, p, p + count[i]);
						else {
							offsetStack[stackPos] = p;
							lengthStack[stackPos] = count[i];
							levelStack[stackPos++] = level + 1;
						}
					}
					p += count[i];
				}
				java.util.Arrays.fill(count, 0);
			}
			else {
				final int end = first + length - count[lastUsed];
				// i moves through the start of each block
				for(int i = first, c = -1, d; i <= end; i += count[c], count[c] = 0) {
					int t = perm[i];
					c = INT(KEY2LEXINT(k[t]) >>> shift & DIGIT_MASK ^ signMask);

					if (i < end) { // When all slots are OK, the last slot is necessarily OK.
						while((d = --pos[c]) > i) {
							final int z = t;
							t = perm[d];
							perm[d] = z;
							c = INT(KEY2LEXINT(k[t]) >>> shift & DIGIT_MASK ^ signMask);
						}
						perm[i] = t;
					}


					if (level < maxLevel && count[c] > 1) {
						if (count[c] < RADIXSORT_NO_REC_SMALL) insertionSortIndirect(perm, a, b, i, i + count[c]);
						else {
							offsetStack[stackPos] = i;
							lengthStack[stackPos] = count[c];
							levelStack[stackPos++] = level + 1;
						}
					}
				}
			}
		}
	}




	private static void selectionSort(final KEY_TYPE[][] a, final int from, final int to, final int level) {
		final int layers = a.length;
		final int firstLayer = level / DIGITS_PER_ELEMENT;

		for(int i = from; i < to - 1; i++) {
			int m = i;
			for(int j = i + 1; j < to; j++) {
				for(int p = firstLayer; p < layers; p++) {
					if (a[p][j] < a[p][m]) {
						m = j;
						break;
					}
					else if (a[p][j] > a[p][m]) break;
				}
			}
			if (m != i) {
				for(int p = layers; p-- != 0;) {
					final KEY_TYPE u = a[p][i];
					a[p][i] = a[p][m];
					a[p][m] = u;
				}
			}
		}
	}



	/** Sorts the specified array of arrays lexicographically using radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implements a <em>lexicographical</em> sorting of the provided arrays. Tuples of elements
	 * in the same position will be considered a single key, and permuted
	 * accordingly.
	 *
	 * @param a an array containing arrays of equal length to be sorted lexicographically in parallel.
	 */
	public static void radixSort(final KEY_TYPE[][] a) {
		radixSort(a, 0, a[0].length);
	}

	/** Sorts the specified array of arrays lexicographically using radix sort.
	 *
	 * <p>The sorting algorithm is a tuned radix sort adapted from Peter M. McIlroy, Keith Bostic and M. Douglas
	 * McIlroy, &ldquo;Engineering radix sort&rdquo;, <i>Computing Systems</i>, 6(1), pages 5&minus;27 (1993).
	 *
	 * <p>This method implements a <em>lexicographical</em> sorting of the provided arrays. Tuples of elements
	 * in the same position will be considered a single key, and permuted
	 * accordingly.
	 *
	 * @param a an array containing arrays of equal length to be sorted lexicographically in parallel.
	 * @param from the index of the first element (inclusive) to be sorted.
	 * @param to the index of the last element (exclusive) to be sorted.
	 */
	public static void radixSort(final KEY_TYPE[][] a, final int from, final int to) {
		if (to - from < RADIXSORT_NO_REC_SMALL) {
			selectionSort(a, from, to, 0);
			return;
		}

		final int layers = a.length;
		final int maxLevel = DIGITS_PER_ELEMENT * layers - 1;
		for(int p = layers, l = a[0].length; p-- != 0;) if (a[p].length != l) throw new IllegalArgumentException("The array of index " + p + " has not the same length of the array of index 0.");

		final int stackSize = ((1 << DIGIT_BITS) - 1) * (layers * DIGITS_PER_ELEMENT - 1) + 1;
		int stackPos = 0;
		final int[] offsetStack = new int[stackSize];
		final int[] lengthStack = new int[stackSize];
		final int[] levelStack = new int[stackSize];

		offsetStack[stackPos] = from;
		lengthStack[stackPos] = to - from;
		levelStack[stackPos++] = 0;

		final int[] count = new int[1 << DIGIT_BITS];
		final int[] pos = new int[1 << DIGIT_BITS];
		final KEY_TYPE[] t = new KEY_TYPE[layers];

		while(stackPos > 0) {
			final int first = offsetStack[--stackPos];
			final int length = lengthStack[stackPos];
			final int level = levelStack[stackPos];
#if KEY_CLASS_Character
			final int signMask = 0;
#else
			final int signMask = level % DIGITS_PER_ELEMENT == 0 ? 1 << DIGIT_BITS - 1 : 0;
#endif

			final KEY_TYPE[] k = a[level / DIGITS_PER_ELEMENT]; // This is the key array
			final int shift = (DIGITS_PER_ELEMENT - 1 - level % DIGITS_PER_ELEMENT) * DIGIT_BITS; // This is the shift that extract the right byte from a key

			// Count keys.
			for(int i = first + length; i-- != first;) count[INT(KEY2LEXINT(k[i]) >>> shift & DIGIT_MASK ^ signMask)]++;

			// Compute cumulative distribution
			int lastUsed = -1;
			for (int i = 0, p = first; i < 1 << DIGIT_BITS; i++) {
				if (count[i] != 0) lastUsed = i;
				pos[i] = (p += count[i]);
			}

			final int end = first + length - count[lastUsed];
			// i moves through the start of each block
			for(int i = first, c = -1, d; i <= end; i += count[c], count[c] = 0) {
				for(int p = layers; p-- != 0;) t[p] = a[p][i];
				c = INT(KEY2LEXINT(k[i]) >>> shift & DIGIT_MASK ^ signMask);

				if (i < end) { // When all slots are OK, the last slot is necessarily OK.
					while((d = --pos[c]) > i) {
						c = INT(KEY2LEXINT(k[d]) >>> shift & DIGIT_MASK ^ signMask);
						for(int p = layers; p-- != 0;) {
							final KEY_TYPE u = t[p];
							t[p] = a[p][d];
							a[p][d] = u;
						}
					}
					for(int p = layers; p-- != 0;) a[p][i] = t[p];
				}

				if (level < maxLevel && count[c] > 1) {
					if (count[c] < RADIXSORT_NO_REC_SMALL) selectionSort(a, i, i + count[c], level + 1);
					else {
						offsetStack[stackPos] = i;
						lengthStack[stackPos] = count[c];
						levelStack[stackPos++] = level + 1;
					}
				}
			}
		}
	}


#endif

#endif

	/** Shuffles the specified array fragment using the specified pseudorandom number generator.
	 *
	 * @param a the array to be shuffled.
	 * @param from the index of the first element (inclusive) to be shuffled.
	 * @param to the index of the last element (exclusive) to be shuffled.
	 * @param random a pseudorandom number generator.
	 * @return {@code a}.
	 */
	public static KEY_GENERIC KEY_GENERIC_TYPE[] shuffle(final KEY_GENERIC_TYPE[] a, final int from, final int to, final Random random) {
		for(int i = to - from; i-- != 0;) {
			final int p = random.nextInt(i + 1);
			final KEY_GENERIC_TYPE t = a[from + i];
			a[from + i] = a[from + p];
			a[from + p] = t;
		}
		return a;
	}

	/** Shuffles the specified array using the specified pseudorandom number generator.
	 *
	 * @param a the array to be shuffled.
	 * @param random a pseudorandom number generator.
	 * @return {@code a}.
	 */
	public static KEY_GENERIC KEY_GENERIC_TYPE[] shuffle(final KEY_GENERIC_TYPE[] a, final Random random) {
		for(int i = a.length; i-- != 0;) {
			final int p = random.nextInt(i + 1);
			final KEY_GENERIC_TYPE t = a[i];
			a[i] = a[p];
			a[p] = t;
		}
		return a;
	}

	/** Reverses the order of the elements in the specified array.
	 *
	 * @param a the array to be reversed.
	 * @return {@code a}.
	 */
	public static KEY_GENERIC KEY_GENERIC_TYPE[] reverse(final KEY_GENERIC_TYPE[] a) {
		final int length = a.length;
		for(int i = length / 2; i-- != 0;) {
			final KEY_GENERIC_TYPE t = a[length - i - 1];
			a[length - i - 1] = a[i];
			a[i] = t;
		}
		return a;
	}

	/** Reverses the order of the elements in the specified array fragment.
	 *
	 * @param a the array to be reversed.
	 * @param from the index of the first element (inclusive) to be reversed.
	 * @param to the index of the last element (exclusive) to be reversed.
	 * @return {@code a}.
	 */
	public static KEY_GENERIC KEY_GENERIC_TYPE[] reverse(final KEY_GENERIC_TYPE[] a, final int from, final int to) {
		final int length = to - from;
		for(int i = length / 2; i-- != 0;) {
			final KEY_GENERIC_TYPE t = a[from + length - i - 1];
			a[from + length - i - 1] = a[from + i];
			a[from + i] = t;
		}
		return a;
	}

	/** A type-specific content-based hash strategy for arrays. */

	private static final class ArrayHashStrategy KEY_GENERIC implements Hash.Strategy<KEY_GENERIC_TYPE[]>, java.io.Serializable {
		private static final long serialVersionUID = -7046029254386353129L;

		@Override
		public int hashCode(final KEY_GENERIC_TYPE[] o) { return java.util.Arrays.hashCode(o); }

		@Override
		public boolean equals(final KEY_GENERIC_TYPE[] a, final KEY_GENERIC_TYPE[] b) { return java.util.Arrays.equals(a, b); }
	}

	/** A type-specific content-based hash strategy for arrays.
	 *
	 * <p>This hash strategy may be used in custom hash collections whenever keys are
	 * arrays, and they must be considered equal by content. This strategy
	 * will handle {@code null} correctly, and it is serializable.
	 */

#if KEYS_PRIMITIVE
	public static final Hash.Strategy<KEY_TYPE[]> HASH_STRATEGY = new ArrayHashStrategy();
#else
	@SuppressWarnings({"rawtypes"})
	public static final Hash.Strategy HASH_STRATEGY = new ArrayHashStrategy();
#endif

#ifdef TEST
#if KEYS_PRIMITIVE && ! KEY_CLASS_Boolean
	private static long seed = System.currentTimeMillis();
	private static java.util.Random r = new java.util.Random(seed);

	private static final KEY_TYPE[] fillArrayForBenchmark(KEY_TYPE[] a, int uniqueValues) {
		for(int i = a.length; i-- != 0;) a[i] = (KEY_TYPE)(uniqueValues - (i % uniqueValues));
		a = shuffle(a, r);
		return a;
	}

	private static final int WARMUP_RUNS = 100;
	private static final int GC_EVERY = 100;
	private static final int DEFAULT_MAX = 1000;
	private static final int RUNS = 30;
	public static final void main(String... args) {
		int max = DEFAULT_MAX;
		if (args.length > 1) max = Integer.parseInt(args[1]);
		if (args.length > 2) {
			seed = Integer.parseInt(args[2]);
			r = new java.util.Random(seed);
		}
		final int uniqueValues = 5 * max / 8;
		KEY_TYPE[] a = new KEY_TYPE[max];
		KEY_TYPE[] b = new KEY_TYPE[max];
		KEY_TYPE[] c = new KEY_TYPE[max];
		for (int n = 0; n < WARMUP_RUNS; ++n) {
			a = fillArrayForBenchmark(a, uniqueValues);
			System.arraycopy(a, 0, b, 0, max);
			System.arraycopy(a, 0, c, 0, max);
			java.util.Arrays.sort(a);
			quickSort(b);
			radixSort(c);
		}
		long arraysSortSum = 0;
		long quickSortSum = 0;
		long radixSortSum = 0;
		System.gc();
		for (int n = 0; n < RUNS; ++n) {
			a = fillArrayForBenchmark(a, uniqueValues);
			System.arraycopy(a, 0, b, 0, max);
			System.arraycopy(a, 0, c, 0, max);

			if (n > 0 && n % GC_EVERY == 0) System.gc();
			long start = System.nanoTime();
			java.util.Arrays.sort(a);
			long end = System.nanoTime();
			arraysSortSum += end - start;

			if (n > 0 && n % GC_EVERY == 0) System.gc();
			start = System.nanoTime();
			quickSort(b);
			end = System.nanoTime();
			quickSortSum += end - start;

			if (n > 0 && n % GC_EVERY == 0) System.gc();
			start = System.nanoTime();
			radixSort(c);
			end = System.nanoTime();
			radixSortSum += end - start;
		}
	 	System.out.println(String.format("%s: Quicksort vs radix sort for arrays of length %d with %d unique values",
	 									 ARRAYS.class.getSimpleName(), max, uniqueValues));
		double averageArraysSort = (double)arraysSortSum / RUNS;
		System.out.println("java.util.Arrays.sort() average time " + averageArraysSort);
		double averageQuickSort = (double)quickSortSum / RUNS;
		System.out.println("Average quicksort average time " + averageQuickSort);
		double averageRadixSort = (double)radixSortSum / RUNS;
		System.out.println("Average radixsort average time " + averageRadixSort);
	}
#endif
#endif

}
