diff --git a/jdk/make/java/java/FILES_java.gmk b/jdk/make/java/java/FILES_java.gmk
index d9b7e153d72..a6ab86058f7 100644
--- a/jdk/make/java/java/FILES_java.gmk
+++ b/jdk/make/java/java/FILES_java.gmk
@@ -251,6 +251,7 @@ JAVA_JAVA_java = \
java/util/IdentityHashMap.java \
java/util/EnumMap.java \
java/util/Arrays.java \
+ java/util/DualPivotQuicksort.java \
java/util/TimSort.java \
java/util/ComparableTimSort.java \
java/util/ConcurrentModificationException.java \
diff --git a/jdk/src/share/classes/java/util/Arrays.java b/jdk/src/share/classes/java/util/Arrays.java
index 55c54115389..f51fcac80a9 100644
--- a/jdk/src/share/classes/java/util/Arrays.java
+++ b/jdk/src/share/classes/java/util/Arrays.java
@@ -1,5 +1,5 @@
/*
- * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,1047 +29,458 @@ import java.lang.reflect.*;
/**
* This class contains various methods for manipulating arrays (such as
- * sorting and searching). This class also contains a static factory
+ * sorting and searching). This class also contains a static factory
* that allows arrays to be viewed as lists.
*
- *
The methods in this class all throw a NullPointerException if
- * the specified array reference is null, except where noted.
+ *
The methods in this class all throw a {@code NullPointerException},
+ * if the specified array reference is null, except where noted.
*
*
The documentation for the methods contained in this class includes
- * briefs description of the implementations. Such descriptions should
+ * briefs description of the implementations. Such descriptions should
* be regarded as implementation notes, rather than parts of the
- * specification. Implementors should feel free to substitute other
- * algorithms, so long as the specification itself is adhered to. (For
- * example, the algorithm used by sort(Object[]) does not have to be
- * a mergesort, but it does have to be stable.)
+ * specification. Implementors should feel free to substitute other
+ * algorithms, so long as the specification itself is adhered to. (For
+ * example, the algorithm used by {@code sort(Object[])} does not have to be
+ * a MergeSort, but it does have to be stable.)
*
*
This class is a member of the
*
* Java Collections Framework.
*
- * @author Josh Bloch
- * @author Neal Gafter
- * @author John Rose
- * @since 1.2
+ * @author Josh Bloch
+ * @author Neal Gafter
+ * @author John Rose
+ * @since 1.2
*/
-
public class Arrays {
+
// Suppresses default constructor, ensuring non-instantiability.
- private Arrays() {
- }
+ private Arrays() {}
// Sorting
/**
- * Sorts the specified array of longs into ascending numerical order.
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ * Sorts the specified array into ascending numerical order.
+ *
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(long[] a) {
- sort1(a, 0, a.length);
+ sort(a, 0, a.length);
}
/**
- * Sorts the specified range of the specified array of longs into
- * ascending numerical order. The range to be sorted extends from index
- * fromIndex, inclusive, to index toIndex, exclusive.
- * (If fromIndex==toIndex, the range to be sorted is empty.)
+ * Sorts the specified range of the specified array into ascending order. The
+ * range of to be sorted extends from the index {@code fromIndex}, inclusive,
+ * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+ * the range to be sorted is empty.
*
- *
The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
- * @param fromIndex the index of the first element (inclusive) to be
- * sorted
- * @param toIndex the index of the last element (exclusive) to be sorted
- * @throws IllegalArgumentException if fromIndex > toIndex
- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or
- * toIndex > a.length
+ * @param fromIndex the index of the first element, inclusively, to be sorted
+ * @param toIndex the index of the last element, exclusively, to be sorted
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(long[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- sort1(a, fromIndex, toIndex-fromIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
- * Sorts the specified array of ints into ascending numerical order.
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ * Sorts the specified array into ascending numerical order.
+ *
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(int[] a) {
- sort1(a, 0, a.length);
+ sort(a, 0, a.length);
}
/**
- * Sorts the specified range of the specified array of ints into
- * ascending numerical order. The range to be sorted extends from index
- * fromIndex, inclusive, to index toIndex, exclusive.
- * (If fromIndex==toIndex, the range to be sorted is empty.)
+ * Sorts the specified range of the specified array into ascending order. The
+ * range of to be sorted extends from the index {@code fromIndex}, inclusive,
+ * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+ * the range to be sorted is empty.
*
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
- * @param fromIndex the index of the first element (inclusive) to be
- * sorted
- * @param toIndex the index of the last element (exclusive) to be sorted
- * @throws IllegalArgumentException if fromIndex > toIndex
- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or
- * toIndex > a.length
+ * @param fromIndex the index of the first element, inclusively, to be sorted
+ * @param toIndex the index of the last element, exclusively, to be sorted
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(int[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- sort1(a, fromIndex, toIndex-fromIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
- * Sorts the specified array of shorts into ascending numerical order.
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ * Sorts the specified array into ascending numerical order.
+ *
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(short[] a) {
- sort1(a, 0, a.length);
+ sort(a, 0, a.length);
}
/**
- * Sorts the specified range of the specified array of shorts into
- * ascending numerical order. The range to be sorted extends from index
- * fromIndex, inclusive, to index toIndex, exclusive.
- * (If fromIndex==toIndex, the range to be sorted is empty.)
+ * Sorts the specified range of the specified array into ascending order. The
+ * range of to be sorted extends from the index {@code fromIndex}, inclusive,
+ * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+ * the range to be sorted is empty.
*
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
- * @param fromIndex the index of the first element (inclusive) to be
- * sorted
- * @param toIndex the index of the last element (exclusive) to be sorted
- * @throws IllegalArgumentException if fromIndex > toIndex
- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or
- * toIndex > a.length
+ * @param fromIndex the index of the first element, inclusively, to be sorted
+ * @param toIndex the index of the last element, exclusively, to be sorted
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(short[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- sort1(a, fromIndex, toIndex-fromIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
- * Sorts the specified array of chars into ascending numerical order.
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ * Sorts the specified array into ascending numerical order.
+ *
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(char[] a) {
- sort1(a, 0, a.length);
+ sort(a, 0, a.length);
}
/**
- * Sorts the specified range of the specified array of chars into
- * ascending numerical order. The range to be sorted extends from index
- * fromIndex, inclusive, to index toIndex, exclusive.
- * (If fromIndex==toIndex, the range to be sorted is empty.)
+ * Sorts the specified range of the specified array into ascending order. The
+ * range of to be sorted extends from the index {@code fromIndex}, inclusive,
+ * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+ * the range to be sorted is empty.
*
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
- * @param fromIndex the index of the first element (inclusive) to be
- * sorted
- * @param toIndex the index of the last element (exclusive) to be sorted
- * @throws IllegalArgumentException if fromIndex > toIndex
- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or
- * toIndex > a.length
+ * @param fromIndex the index of the first element, inclusively, to be sorted
+ * @param toIndex the index of the last element, exclusively, to be sorted
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(char[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- sort1(a, fromIndex, toIndex-fromIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
- * Sorts the specified array of bytes into ascending numerical order.
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ * Sorts the specified array into ascending numerical order.
+ *
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(byte[] a) {
- sort1(a, 0, a.length);
+ sort(a, 0, a.length);
}
/**
- * Sorts the specified range of the specified array of bytes into
- * ascending numerical order. The range to be sorted extends from index
- * fromIndex, inclusive, to index toIndex, exclusive.
- * (If fromIndex==toIndex, the range to be sorted is empty.)
+ * Sorts the specified range of the specified array into ascending order. The
+ * range of to be sorted extends from the index {@code fromIndex}, inclusive,
+ * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+ * the range to be sorted is empty.
*
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
- * @param fromIndex the index of the first element (inclusive) to be
- * sorted
- * @param toIndex the index of the last element (exclusive) to be sorted
- * @throws IllegalArgumentException if fromIndex > toIndex
- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or
- * toIndex > a.length
+ * @param fromIndex the index of the first element, inclusively, to be sorted
+ * @param toIndex the index of the last element, exclusively, to be sorted
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(byte[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- sort1(a, fromIndex, toIndex-fromIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
- * Sorts the specified array of doubles into ascending numerical order.
- *
- * The <
relation does not provide a total order on
+ * Sorts the specified array into ascending numerical order.
+ *
+ *
The {@code <} relation does not provide a total order on
* all floating-point values; although they are distinct numbers
- * -0.0 == 0.0
is true
and a NaN value
- * compares neither less than, greater than, nor equal to any
- * floating-point value, even itself. To allow the sort to
- * proceed, instead of using the <
relation to
- * determine ascending numerical order, this method uses the total
- * order imposed by {@link Double#compareTo}. This ordering
- * differs from the <
relation in that
- * -0.0
is treated as less than 0.0
and
- * NaN is considered greater than any other floating-point value.
- * For the purposes of sorting, all NaN values are considered
- * equivalent and equal.
- *
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ * {@code -0.0d == 0.0d} is {@code true} and a NaN value compares
+ * neither less than, greater than, nor equal to any floating-point
+ * value, even itself. To allow the sort to proceed, instead of using
+ * the {@code <} relation to determine ascending numerical order,
+ * this method uses the total order imposed by {@link Double#compareTo}.
+ * This ordering differs from the {@code <} relation in that {@code -0.0d}
+ * is treated as less than {@code 0.0d} and NaN is considered greater than
+ * any other floating-point value. For the purposes of sorting, all NaN
+ * values are considered equivalent and equal.
+ *
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
*/
public static void sort(double[] a) {
- sort2(a, 0, a.length);
+ sort(a, 0, a.length);
}
/**
- * Sorts the specified range of the specified array of doubles into
- * ascending numerical order. The range to be sorted extends from index
- * fromIndex, inclusive, to index toIndex, exclusive.
- * (If fromIndex==toIndex, the range to be sorted is empty.)
- *
- * The <
relation does not provide a total order on
+ * Sorts the specified range of the specified array into ascending order. The
+ * range of to be sorted extends from the index {@code fromIndex}, inclusive,
+ * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+ * the range to be sorted is empty.
+ *
+ *
The {@code <} relation does not provide a total order on
* all floating-point values; although they are distinct numbers
- * -0.0 == 0.0
is true
and a NaN value
- * compares neither less than, greater than, nor equal to any
- * floating-point value, even itself. To allow the sort to
- * proceed, instead of using the <
relation to
- * determine ascending numerical order, this method uses the total
- * order imposed by {@link Double#compareTo}. This ordering
- * differs from the <
relation in that
- * -0.0
is treated as less than 0.0
and
- * NaN is considered greater than any other floating-point value.
- * For the purposes of sorting, all NaN values are considered
- * equivalent and equal.
- *
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
+ * {@code -0.0d == 0.0d} is {@code true} and a NaN value compares
+ * neither less than, greater than, nor equal to any floating-point
+ * value, even itself. To allow the sort to proceed, instead of using
+ * the {@code <} relation to determine ascending numerical order,
+ * this method uses the total order imposed by {@link Double#compareTo}.
+ * This ordering differs from the {@code <} relation in that {@code -0.0d}
+ * is treated as less than {@code 0.0d} and NaN is considered greater than
+ * any other floating-point value. For the purposes of sorting, all NaN
+ * values are considered equivalent and equal.
+ *
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
*
* @param a the array to be sorted
- * @param fromIndex the index of the first element (inclusive) to be
- * sorted
- * @param toIndex the index of the last element (exclusive) to be sorted
- * @throws IllegalArgumentException if fromIndex > toIndex
- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or
- * toIndex > a.length
+ * @param fromIndex the index of the first element, inclusively, to be sorted
+ * @param toIndex the index of the last element, exclusively, to be sorted
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(double[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- sort2(a, fromIndex, toIndex);
+ sortNegZeroAndNaN(a, fromIndex, toIndex);
}
- /**
- * Sorts the specified array of floats into ascending numerical order.
- *
- * The <
relation does not provide a total order on
- * all floating-point values; although they are distinct numbers
- * -0.0f == 0.0f
is true
and a NaN value
- * compares neither less than, greater than, nor equal to any
- * floating-point value, even itself. To allow the sort to
- * proceed, instead of using the <
relation to
- * determine ascending numerical order, this method uses the total
- * order imposed by {@link Float#compareTo}. This ordering
- * differs from the <
relation in that
- * -0.0f
is treated as less than 0.0f
and
- * NaN is considered greater than any other floating-point value.
- * For the purposes of sorting, all NaN values are considered
- * equivalent and equal.
- *
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
- *
- * @param a the array to be sorted
- */
- public static void sort(float[] a) {
- sort2(a, 0, a.length);
- }
-
- /**
- * Sorts the specified range of the specified array of floats into
- * ascending numerical order. The range to be sorted extends from index
- * fromIndex, inclusive, to index toIndex, exclusive.
- * (If fromIndex==toIndex, the range to be sorted is empty.)
- *
- * The <
relation does not provide a total order on
- * all floating-point values; although they are distinct numbers
- * -0.0f == 0.0f
is true
and a NaN value
- * compares neither less than, greater than, nor equal to any
- * floating-point value, even itself. To allow the sort to
- * proceed, instead of using the <
relation to
- * determine ascending numerical order, this method uses the total
- * order imposed by {@link Float#compareTo}. This ordering
- * differs from the <
relation in that
- * -0.0f
is treated as less than 0.0f
and
- * NaN is considered greater than any other floating-point value.
- * For the purposes of sorting, all NaN values are considered
- * equivalent and equal.
- *
- * The sorting algorithm is a tuned quicksort, adapted from Jon
- * L. Bentley and M. Douglas McIlroy's "Engineering a Sort Function",
- * Software-Practice and Experience, Vol. 23(11) P. 1249-1265 (November
- * 1993). This algorithm offers n*log(n) performance on many data sets
- * that cause other quicksorts to degrade to quadratic performance.
- *
- * @param a the array to be sorted
- * @param fromIndex the index of the first element (inclusive) to be
- * sorted
- * @param toIndex the index of the last element (exclusive) to be sorted
- * @throws IllegalArgumentException if fromIndex > toIndex
- * @throws ArrayIndexOutOfBoundsException if fromIndex < 0 or
- * toIndex > a.length
- */
- public static void sort(float[] a, int fromIndex, int toIndex) {
- rangeCheck(a.length, fromIndex, toIndex);
- sort2(a, fromIndex, toIndex);
- }
-
- private static void sort2(double a[], int fromIndex, int toIndex) {
+ private static void sortNegZeroAndNaN(double[] a, int fromIndex, int toIndex) {
final long NEG_ZERO_BITS = Double.doubleToLongBits(-0.0d);
/*
* The sort is done in three phases to avoid the expense of using
- * NaN and -0.0 aware comparisons during the main sort.
- */
-
- /*
- * Preprocessing phase: Move any NaN's to end of array, count the
- * number of -0.0's, and turn them into 0.0's.
+ * NaN and -0.0d aware comparisons during the main sort.
+ *
+ * Preprocessing phase: move any NaN's to end of array, count the
+ * number of -0.0d's, and turn them into 0.0d's.
*/
int numNegZeros = 0;
- int i = fromIndex, n = toIndex;
- while(i < n) {
+ int i = fromIndex;
+ int n = toIndex;
+ double temp;
+
+ while (i < n) {
if (a[i] != a[i]) {
- swap(a, i, --n);
- } else {
- if (a[i]==0 && Double.doubleToLongBits(a[i])==NEG_ZERO_BITS) {
+ n--;
+ temp = a[i];
+ a[i] = a[n];
+ a[n] = temp;
+ }
+ else {
+ if (a[i] == 0 && Double.doubleToLongBits(a[i]) == NEG_ZERO_BITS) {
a[i] = 0.0d;
numNegZeros++;
}
i++;
}
}
-
// Main sort phase: quicksort everything but the NaN's
- sort1(a, fromIndex, n-fromIndex);
+ DualPivotQuicksort.sort(a, fromIndex, n - 1);
- // Postprocessing phase: change 0.0's to -0.0's as required
+ // Postprocessing phase: change 0.0d's to -0.0d's as required
if (numNegZeros != 0) {
- int j = binarySearch0(a, fromIndex, n, 0.0d); // posn of ANY zero
+ int j = binarySearch0(a, fromIndex, n, 0.0d); // position of ANY zero
+
do {
j--;
- } while (j>=fromIndex && a[j]==0.0d);
+ }
+ while (j >= fromIndex && a[j] == 0.0d);
// j is now one less than the index of the FIRST zero
- for (int k=0; kThe {@code <} relation does not provide a total order on
+ * all floating-point values; although they are distinct numbers
+ * {@code -0.0f == 0.0f} is {@code true} and a NaN value compares
+ * neither less than, greater than, nor equal to any floating-point
+ * value, even itself. To allow the sort to proceed, instead of using
+ * the {@code <} relation to determine ascending numerical order,
+ * this method uses the total order imposed by {@link Float#compareTo}.
+ * This ordering differs from the {@code <} relation in that {@code -0.0f}
+ * is treated as less than {@code 0.0f} and NaN is considered greater than
+ * any other floating-point value. For the purposes of sorting, all NaN
+ * values are considered equivalent and equal.
+ *
+ * Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
+ *
+ * @param a the array to be sorted
+ */
+ public static void sort(float[] a) {
+ sort(a, 0, a.length);
+ }
- private static void sort2(float a[], int fromIndex, int toIndex) {
+ /**
+ * Sorts the specified range of the specified array into ascending order. The
+ * range of to be sorted extends from the index {@code fromIndex}, inclusive,
+ * to the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
+ * the range to be sorted is empty.
+ *
+ *
The {@code <} relation does not provide a total order on
+ * all floating-point values; although they are distinct numbers
+ * {@code -0.0f == 0.0f} is {@code true} and a NaN value compares
+ * neither less than, greater than, nor equal to any floating-point
+ * value, even itself. To allow the sort to proceed, instead of using
+ * the {@code <} relation to determine ascending numerical order,
+ * this method uses the total order imposed by {@link Float#compareTo}.
+ * This ordering differs from the {@code <} relation in that {@code -0.0f}
+ * is treated as less than {@code 0.0f} and NaN is considered greater than
+ * any other floating-point value. For the purposes of sorting, all NaN
+ * values are considered equivalent and equal.
+ *
+ *
Implementation note: The sorting algorithm is a Dual-Pivot Quicksort,
+ * by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. This algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
+ *
+ * @param a the array to be sorted
+ * @param fromIndex the index of the first element, inclusively, to be sorted
+ * @param toIndex the index of the last element, exclusively, to be sorted
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > a.length}
+ */
+ public static void sort(float[] a, int fromIndex, int toIndex) {
+ rangeCheck(a.length, fromIndex, toIndex);
+ sortNegZeroAndNaN(a, fromIndex, toIndex);
+ }
+
+ private static void sortNegZeroAndNaN(float[] a, int fromIndex, int toIndex) {
final int NEG_ZERO_BITS = Float.floatToIntBits(-0.0f);
/*
* The sort is done in three phases to avoid the expense of using
- * NaN and -0.0 aware comparisons during the main sort.
- */
-
- /*
- * Preprocessing phase: Move any NaN's to end of array, count the
- * number of -0.0's, and turn them into 0.0's.
+ * NaN and -0.0f aware comparisons during the main sort.
+ *
+ * Preprocessing phase: move any NaN's to end of array, count the
+ * number of -0.0f's, and turn them into 0.0f's.
*/
int numNegZeros = 0;
- int i = fromIndex, n = toIndex;
- while(i < n) {
+ int i = fromIndex;
+ int n = toIndex;
+ float temp;
+
+ while (i < n) {
if (a[i] != a[i]) {
- swap(a, i, --n);
- } else {
- if (a[i]==0 && Float.floatToIntBits(a[i])==NEG_ZERO_BITS) {
+ n--;
+ temp = a[i];
+ a[i] = a[n];
+ a[n] = temp;
+ }
+ else {
+ if (a[i] == 0 && Float.floatToIntBits(a[i]) == NEG_ZERO_BITS) {
a[i] = 0.0f;
numNegZeros++;
}
i++;
}
}
-
// Main sort phase: quicksort everything but the NaN's
- sort1(a, fromIndex, n-fromIndex);
+ DualPivotQuicksort.sort(a, fromIndex, n - 1);
- // Postprocessing phase: change 0.0's to -0.0's as required
+ // Postprocessing phase: change 0.0f's to -0.0f's as required
if (numNegZeros != 0) {
- int j = binarySearch0(a, fromIndex, n, 0.0f); // posn of ANY zero
+ int j = binarySearch0(a, fromIndex, n, 0.0f); // position of ANY zero
+
do {
j--;
- } while (j>=fromIndex && a[j]==0.0f);
+ }
+ while (j >= fromIndex && a[j] == 0.0f);
// j is now one less than the index of the FIRST zero
- for (int k=0; koff && x[j-1]>x[j]; j--)
- swap(x, j, j-1);
- return;
- }
-
- // Choose a partition element, v
- int m = off + (len >> 1); // Small arrays, middle element
- if (len > 7) {
- int l = off;
- int n = off + len - 1;
- if (len > 40) { // 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
}
- long v = x[m];
-
- // Establish Invariant: v* (v)* v*
- int a = off, b = a, c = off + len - 1, d = c;
- while(true) {
- while (b <= c && x[b] <= v) {
- if (x[b] == v)
- swap(x, a++, b);
- b++;
- }
- while (c >= b && x[c] >= v) {
- if (x[c] == v)
- swap(x, c, d--);
- c--;
- }
- if (b > c)
- break;
- swap(x, b++, c--);
- }
-
- // Swap partition elements back to middle
- int s, n = off + len;
- s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s);
- s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s);
-
- // Recursively sort non-partition-elements
- if ((s = b-a) > 1)
- sort1(x, off, s);
- if ((s = d-c) > 1)
- sort1(x, n-s, s);
- }
-
- /**
- * Swaps x[a] with x[b].
- */
- private static void swap(long x[], int a, int b) {
- long t = x[a];
- x[a] = x[b];
- x[b] = t;
- }
-
- /**
- * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
- */
- private static void vecswap(long x[], int a, int b, int n) {
- for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a));
- }
-
- /**
- * Sorts the specified sub-array of integers into ascending order.
- */
- private static void sort1(int x[], int off, int len) {
- // Insertion sort on smallest arrays
- if (len < 7) {
- for (int i=off; ioff && x[j-1]>x[j]; j--)
- swap(x, j, j-1);
- return;
- }
-
- // Choose a partition element, v
- int m = off + (len >> 1); // Small arrays, middle element
- if (len > 7) {
- int l = off;
- int n = off + len - 1;
- if (len > 40) { // 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
- }
- int v = x[m];
-
- // Establish Invariant: v* (v)* v*
- int a = off, b = a, c = off + len - 1, d = c;
- while(true) {
- while (b <= c && x[b] <= v) {
- if (x[b] == v)
- swap(x, a++, b);
- b++;
- }
- while (c >= b && x[c] >= v) {
- if (x[c] == v)
- swap(x, c, d--);
- c--;
- }
- if (b > c)
- break;
- swap(x, b++, c--);
- }
-
- // Swap partition elements back to middle
- int s, n = off + len;
- s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s);
- s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s);
-
- // Recursively sort non-partition-elements
- if ((s = b-a) > 1)
- sort1(x, off, s);
- if ((s = d-c) > 1)
- sort1(x, n-s, s);
- }
-
- /**
- * Swaps x[a] with x[b].
- */
- private static void swap(int x[], int a, int b) {
- int t = x[a];
- x[a] = x[b];
- x[b] = t;
- }
-
- /**
- * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
- */
- private static void vecswap(int x[], int a, int b, int n) {
- for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a));
- }
-
- /**
- * Sorts the specified sub-array of shorts into ascending order.
- */
- private static void sort1(short x[], int off, int len) {
- // Insertion sort on smallest arrays
- if (len < 7) {
- for (int i=off; ioff && x[j-1]>x[j]; j--)
- swap(x, j, j-1);
- return;
- }
-
- // Choose a partition element, v
- int m = off + (len >> 1); // Small arrays, middle element
- if (len > 7) {
- int l = off;
- int n = off + len - 1;
- if (len > 40) { // 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
- }
- short v = x[m];
-
- // Establish Invariant: v* (v)* v*
- int a = off, b = a, c = off + len - 1, d = c;
- while(true) {
- while (b <= c && x[b] <= v) {
- if (x[b] == v)
- swap(x, a++, b);
- b++;
- }
- while (c >= b && x[c] >= v) {
- if (x[c] == v)
- swap(x, c, d--);
- c--;
- }
- if (b > c)
- break;
- swap(x, b++, c--);
- }
-
- // Swap partition elements back to middle
- int s, n = off + len;
- s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s);
- s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s);
-
- // Recursively sort non-partition-elements
- if ((s = b-a) > 1)
- sort1(x, off, s);
- if ((s = d-c) > 1)
- sort1(x, n-s, s);
- }
-
- /**
- * Swaps x[a] with x[b].
- */
- private static void swap(short x[], int a, int b) {
- short t = x[a];
- x[a] = x[b];
- x[b] = t;
- }
-
- /**
- * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
- */
- private static void vecswap(short x[], int a, int b, int n) {
- for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a));
- }
-
-
- /**
- * Sorts the specified sub-array of chars into ascending order.
- */
- private static void sort1(char x[], int off, int len) {
- // Insertion sort on smallest arrays
- if (len < 7) {
- for (int i=off; ioff && x[j-1]>x[j]; j--)
- swap(x, j, j-1);
- return;
- }
-
- // Choose a partition element, v
- int m = off + (len >> 1); // Small arrays, middle element
- if (len > 7) {
- int l = off;
- int n = off + len - 1;
- if (len > 40) { // 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
- }
- char v = x[m];
-
- // Establish Invariant: v* (v)* v*
- int a = off, b = a, c = off + len - 1, d = c;
- while(true) {
- while (b <= c && x[b] <= v) {
- if (x[b] == v)
- swap(x, a++, b);
- b++;
- }
- while (c >= b && x[c] >= v) {
- if (x[c] == v)
- swap(x, c, d--);
- c--;
- }
- if (b > c)
- break;
- swap(x, b++, c--);
- }
-
- // Swap partition elements back to middle
- int s, n = off + len;
- s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s);
- s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s);
-
- // Recursively sort non-partition-elements
- if ((s = b-a) > 1)
- sort1(x, off, s);
- if ((s = d-c) > 1)
- sort1(x, n-s, s);
- }
-
- /**
- * Swaps x[a] with x[b].
- */
- private static void swap(char x[], int a, int b) {
- char t = x[a];
- x[a] = x[b];
- x[b] = t;
- }
-
- /**
- * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
- */
- private static void vecswap(char x[], int a, int b, int n) {
- for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a));
- }
-
-
- /**
- * Sorts the specified sub-array of bytes into ascending order.
- */
- private static void sort1(byte x[], int off, int len) {
- // Insertion sort on smallest arrays
- if (len < 7) {
- for (int i=off; ioff && x[j-1]>x[j]; j--)
- swap(x, j, j-1);
- return;
- }
-
- // Choose a partition element, v
- int m = off + (len >> 1); // Small arrays, middle element
- if (len > 7) {
- int l = off;
- int n = off + len - 1;
- if (len > 40) { // 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
- }
- byte v = x[m];
-
- // Establish Invariant: v* (v)* v*
- int a = off, b = a, c = off + len - 1, d = c;
- while(true) {
- while (b <= c && x[b] <= v) {
- if (x[b] == v)
- swap(x, a++, b);
- b++;
- }
- while (c >= b && x[c] >= v) {
- if (x[c] == v)
- swap(x, c, d--);
- c--;
- }
- if (b > c)
- break;
- swap(x, b++, c--);
- }
-
- // Swap partition elements back to middle
- int s, n = off + len;
- s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s);
- s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s);
-
- // Recursively sort non-partition-elements
- if ((s = b-a) > 1)
- sort1(x, off, s);
- if ((s = d-c) > 1)
- sort1(x, n-s, s);
- }
-
- /**
- * Swaps x[a] with x[b].
- */
- private static void swap(byte x[], int a, int b) {
- byte t = x[a];
- x[a] = x[b];
- x[b] = t;
- }
-
- /**
- * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
- */
- private static void vecswap(byte x[], int a, int b, int n) {
- for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a));
- }
-
-
- /**
- * Sorts the specified sub-array of doubles into ascending order.
- */
- private static void sort1(double x[], int off, int len) {
- // Insertion sort on smallest arrays
- if (len < 7) {
- for (int i=off; ioff && x[j-1]>x[j]; j--)
- swap(x, j, j-1);
- return;
- }
-
- // Choose a partition element, v
- int m = off + (len >> 1); // Small arrays, middle element
- if (len > 7) {
- int l = off;
- int n = off + len - 1;
- if (len > 40) { // 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
- }
- double v = x[m];
-
- // Establish Invariant: v* (v)* v*
- int a = off, b = a, c = off + len - 1, d = c;
- while(true) {
- while (b <= c && x[b] <= v) {
- if (x[b] == v)
- swap(x, a++, b);
- b++;
- }
- while (c >= b && x[c] >= v) {
- if (x[c] == v)
- swap(x, c, d--);
- c--;
- }
- if (b > c)
- break;
- swap(x, b++, c--);
- }
-
- // Swap partition elements back to middle
- int s, n = off + len;
- s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s);
- s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s);
-
- // Recursively sort non-partition-elements
- if ((s = b-a) > 1)
- sort1(x, off, s);
- if ((s = d-c) > 1)
- sort1(x, n-s, s);
- }
-
- /**
- * Swaps x[a] with x[b].
- */
- private static void swap(double x[], int a, int b) {
- double t = x[a];
- x[a] = x[b];
- x[b] = t;
- }
-
- /**
- * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
- */
- private static void vecswap(double x[], int a, int b, int n) {
- for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a));
- }
-
-
- /**
- * Sorts the specified sub-array of floats into ascending order.
- */
- private static void sort1(float x[], int off, int len) {
- // Insertion sort on smallest arrays
- if (len < 7) {
- for (int i=off; ioff && x[j-1]>x[j]; j--)
- swap(x, j, j-1);
- return;
- }
-
- // Choose a partition element, v
- int m = off + (len >> 1); // Small arrays, middle element
- if (len > 7) {
- int l = off;
- int n = off + len - 1;
- if (len > 40) { // 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
- }
- float v = x[m];
-
- // Establish Invariant: v* (v)* v*
- int a = off, b = a, c = off + len - 1, d = c;
- while(true) {
- while (b <= c && x[b] <= v) {
- if (x[b] == v)
- swap(x, a++, b);
- b++;
- }
- while (c >= b && x[c] >= v) {
- if (x[c] == v)
- swap(x, c, d--);
- c--;
- }
- if (b > c)
- break;
- swap(x, b++, c--);
- }
-
- // Swap partition elements back to middle
- int s, n = off + len;
- s = Math.min(a-off, b-a ); vecswap(x, off, b-s, s);
- s = Math.min(d-c, n-d-1); vecswap(x, b, n-s, s);
-
- // Recursively sort non-partition-elements
- if ((s = b-a) > 1)
- sort1(x, off, s);
- if ((s = d-c) > 1)
- sort1(x, n-s, s);
- }
-
- /**
- * Swaps x[a] with x[b].
- */
- private static void swap(float x[], int a, int b) {
- float t = x[a];
- x[a] = x[b];
- x[b] = t;
- }
-
- /**
- * Swaps x[a .. (a+n-1)] with x[b .. (b+n-1)].
- */
- private static void vecswap(float x[], int a, int b, int n) {
- for (int i=0; i x[c] ? b : x[a] > x[c] ? c : a));
}
/**
* Old merge sort implementation can be selected (for
* compatibility with broken comparators) using a system property.
* Cannot be a static boolean in the enclosing class due to
- * circular dependencies. To be removed in a future release.
+ * circular dependencies. To be removed in a future release.
*/
static final class LegacyMergeSort {
private static final boolean userRequested =
@@ -1235,7 +646,7 @@ public class Arrays {
/**
* Tuning parameter: list size at or below which insertion sort will be
- * used in preference to mergesort or quicksort.
+ * used in preference to mergesort.
* To be removed in a future release.
*/
private static final int INSERTIONSORT_THRESHOLD = 7;
@@ -1474,17 +885,20 @@ public class Arrays {
}
/**
- * Check that fromIndex and toIndex are in range, and throw an
- * appropriate exception if they aren't.
+ * Checks that {@code fromIndex} and {@code toIndex} are in
+ * the range and throws an appropriate exception, if they aren't.
*/
- private static void rangeCheck(int arrayLen, int fromIndex, int toIndex) {
- if (fromIndex > toIndex)
- throw new IllegalArgumentException("fromIndex(" + fromIndex +
- ") > toIndex(" + toIndex+")");
- if (fromIndex < 0)
+ private static void rangeCheck(int length, int fromIndex, int toIndex) {
+ if (fromIndex > toIndex) {
+ throw new IllegalArgumentException(
+ "fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
+ }
+ if (fromIndex < 0) {
throw new ArrayIndexOutOfBoundsException(fromIndex);
- if (toIndex > arrayLen)
+ }
+ if (toIndex > length) {
throw new ArrayIndexOutOfBoundsException(toIndex);
+ }
}
// Searching
@@ -1987,21 +1401,21 @@ public class Arrays {
/**
* Searches the specified array of floats for the specified value using
- * the binary search algorithm. The array must be sorted
- * (as by the {@link #sort(float[])} method) prior to making this call. If
- * it is not sorted, the results are undefined. If the array contains
+ * the binary search algorithm. The array must be sorted
+ * (as by the {@link #sort(float[])} method) prior to making this call. If
+ * it is not sorted, the results are undefined. If the array contains
* multiple elements with the specified value, there is no guarantee which
- * one will be found. This method considers all NaN values to be
+ * one will be found. This method considers all NaN values to be
* equivalent and equal.
*
* @param a the array to be searched
* @param key the value to be searched for
* @return index of the search key, if it is contained in the array;
- * otherwise, (-(insertion point) - 1). The
+ * otherwise, (-(insertion point) - 1). The
* insertion point is defined as the point at which the
* key would be inserted into the array: the index of the first
* element greater than the key, or a.length if all
- * elements in the array are less than the specified key. Note
+ * elements in the array are less than the specified key. Note
* that this guarantees that the return value will be >= 0 if
* and only if the key is found.
*/
@@ -2015,10 +1429,10 @@ public class Arrays {
* the binary search algorithm.
* The range must be sorted
* (as by the {@link #sort(float[], int, int)} method)
- * prior to making this call. If
- * it is not sorted, the results are undefined. If the range contains
+ * prior to making this call. If
+ * it is not sorted, the results are undefined. If the range contains
* multiple elements with the specified value, there is no guarantee which
- * one will be found. This method considers all NaN values to be
+ * one will be found. This method considers all NaN values to be
* equivalent and equal.
*
* @param a the array to be searched
@@ -2028,12 +1442,12 @@ public class Arrays {
* @param key the value to be searched for
* @return index of the search key, if it is contained in the array
* within the specified range;
- * otherwise, (-(insertion point) - 1). The
+ * otherwise, (-(insertion point) - 1). The
* insertion point is defined as the point at which the
* key would be inserted into the array: the index of the first
* element in the range greater than the key,
* or toIndex if all
- * elements in the range are less than the specified key. Note
+ * elements in the range are less than the specified key. Note
* that this guarantees that the return value will be >= 0 if
* and only if the key is found.
* @throws IllegalArgumentException
@@ -2076,10 +1490,9 @@ public class Arrays {
return -(low + 1); // key not found.
}
-
/**
* Searches the specified array for the specified object using the binary
- * search algorithm. The array must be sorted into ascending order
+ * search algorithm. The array must be sorted into ascending order
* according to the
* {@linkplain Comparable natural ordering}
* of its elements (as by the
@@ -2269,7 +1682,6 @@ public class Arrays {
int mid = (low + high) >>> 1;
T midVal = a[mid];
int cmp = c.compare(midVal, key);
-
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
@@ -2280,7 +1692,6 @@ public class Arrays {
return -(low + 1); // key not found.
}
-
// Equality Testing
/**
@@ -2527,7 +1938,6 @@ public class Arrays {
return true;
}
-
/**
* Returns true if the two specified arrays of Objects are
* equal to one another. The two arrays are considered equal if
@@ -2562,7 +1972,6 @@ public class Arrays {
return true;
}
-
// Filling
/**
@@ -2885,8 +2294,8 @@ public class Arrays {
a[i] = val;
}
-
// Cloning
+
/**
* Copies the specified array, truncating or padding with nulls (if necessary)
* so the copy has the specified length. For all indices that are
@@ -3495,7 +2904,6 @@ public class Arrays {
return copy;
}
-
// Misc
/**
@@ -4180,6 +3588,7 @@ public class Arrays {
public static String toString(float[] a) {
if (a == null)
return "null";
+
int iMax = a.length - 1;
if (iMax == -1)
return "[]";
@@ -4243,6 +3652,7 @@ public class Arrays {
public static String toString(Object[] a) {
if (a == null)
return "null";
+
int iMax = a.length - 1;
if (iMax == -1)
return "[]";
diff --git a/jdk/src/share/classes/java/util/DualPivotQuicksort.java b/jdk/src/share/classes/java/util/DualPivotQuicksort.java
new file mode 100644
index 00000000000..fa273a051a2
--- /dev/null
+++ b/jdk/src/share/classes/java/util/DualPivotQuicksort.java
@@ -0,0 +1,1554 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.util;
+
+/**
+ * This class implements the Dual-Pivot Quicksort algorithm by
+ * Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. The algorithm
+ * offers O(n log(n)) performance on many data sets that cause other
+ * quicksorts to degrade to quadratic performance, and is typically
+ * faster than traditional (one-pivot) Quicksort implementations.
+ *
+ * @author Vladimir Yaroslavskiy
+ * @author Jon Bentley
+ * @author Josh Bloch
+ *
+ * @version 2009.10.22 m765.827.v4
+ */
+final class DualPivotQuicksort {
+
+ // Suppresses default constructor, ensuring non-instantiability.
+ private DualPivotQuicksort() {}
+
+ /*
+ * Tuning Parameters.
+ */
+
+ /**
+ * If the length of an array to be sorted is less than this
+ * constant, insertion sort is used in preference to Quicksort.
+ */
+ private static final int INSERTION_SORT_THRESHOLD = 32;
+
+ /**
+ * If the length of a byte array to be sorted is greater than
+ * this constant, counting sort is used in preference to Quicksort.
+ */
+ private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 128;
+
+ /**
+ * If the length of a short or char array to be sorted is greater
+ * than this constant, counting sort is used in preference to Quicksort.
+ */
+ private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 32768;
+
+ /*
+ * Sorting methods for the seven primitive types.
+ */
+
+ /**
+ * Sorts the specified range of the array into ascending order.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ static void sort(int[] a, int left, int right) {
+ // Use insertion sort on tiny arrays
+ if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
+ for (int k = left + 1; k <= right; k++) {
+ int ak = a[k];
+ int j;
+
+ for (j = k - 1; j >= left && ak < a[j]; j--) {
+ a[j + 1] = a[j];
+ }
+ a[j + 1] = ak;
+ }
+ } else { // Use Dual-Pivot Quicksort on large arrays
+ dualPivotQuicksort(a, left, right);
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array into ascending order
+ * by Dual-Pivot Quicksort.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ private static void dualPivotQuicksort(int[] a, int left, int right) {
+ // Compute indices of five evenly spaced elements
+ int sixth = (right - left + 1) / 6;
+ int e1 = left + sixth;
+ int e5 = right - sixth;
+ int e3 = (left + right) >>> 1; // The midpoint
+ int e4 = e3 + sixth;
+ int e2 = e3 - sixth;
+
+ // Sort these elements in place using a 5-element sorting network
+ if (a[e1] > a[e2]) { int t = a[e1]; a[e1] = a[e2]; a[e2] = t; }
+ if (a[e4] > a[e5]) { int t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+ if (a[e1] > a[e3]) { int t = a[e1]; a[e1] = a[e3]; a[e3] = t; }
+ if (a[e2] > a[e3]) { int t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e1] > a[e4]) { int t = a[e1]; a[e1] = a[e4]; a[e4] = t; }
+ if (a[e3] > a[e4]) { int t = a[e3]; a[e3] = a[e4]; a[e4] = t; }
+ if (a[e2] > a[e5]) { int t = a[e2]; a[e2] = a[e5]; a[e5] = t; }
+ if (a[e2] > a[e3]) { int t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e4] > a[e5]) { int t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+
+ /*
+ * Use the second and fourth of the five sorted elements as pivots.
+ * These values are inexpensive approximations of the first and
+ * second terciles of the array. Note that pivot1 <= pivot2.
+ *
+ * The pivots are stored in local variables, and the first and
+ * the last of the sorted elements are moved to the locations
+ * formerly occupied by the pivots. When partitioning is complete,
+ * the pivots are swapped back into their final positions, and
+ * excluded from subsequent sorting.
+ */
+ int pivot1 = a[e2]; a[e2] = a[left];
+ int pivot2 = a[e4]; a[e4] = a[right];
+
+ /*
+ * Partitioning
+ *
+ * left part center part right part
+ * ------------------------------------------------------------
+ * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ]
+ * ------------------------------------------------------------
+ * ^ ^ ^
+ * | | |
+ * less k great
+ */
+
+ // Pointers
+ int less = left + 1; // The index of first element of center part
+ int great = right - 1; // The index before first element of right part
+
+ boolean pivotsDiffer = pivot1 != pivot2;
+
+ if (pivotsDiffer) {
+ /*
+ * Invariants:
+ * all in (left, less) < pivot1
+ * pivot1 <= all in [less, k) <= pivot2
+ * all in (great, right) > pivot2
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ int ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else if (ak > pivot2) {
+ while (a[great] > pivot2 && k < great) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ } else { // Pivots are equal
+ /*
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") partition:
+ *
+ * left part center part right part
+ * -------------------------------------------------
+ * [ < pivot | == pivot | ? | > pivot ]
+ * -------------------------------------------------
+ *
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (left, less) < pivot
+ * all in [less, k) == pivot
+ * all in (great, right) > pivot
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ int ak = a[k];
+
+ if (ak == pivot1) {
+ continue;
+ }
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else {
+ while (a[great] > pivot1) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ }
+
+ // Swap pivots into their final positions
+ a[left] = a[less - 1]; a[less - 1] = pivot1;
+ a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+ // Sort left and right parts recursively, excluding known pivot values
+ sort(a, left, less - 2);
+ sort(a, great + 2, right);
+
+ /*
+ * If pivot1 == pivot2, all elements from center
+ * part are equal and, therefore, already sorted
+ */
+ if (!pivotsDiffer) {
+ return;
+ }
+
+ /*
+ * If center part is too large (comprises > 5/6 of
+ * the array), swap internal pivot values to ends
+ */
+ if (less < e1 && e5 < great) {
+ while (a[less] == pivot1) {
+ less++;
+ }
+ for (int k = less + 1; k <= great; k++) {
+ if (a[k] == pivot1) {
+ a[k] = a[less];
+ a[less++] = pivot1;
+ }
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+ for (int k = great - 1; k >= less; k--) {
+ if (a[k] == pivot2) {
+ a[k] = a[great];
+ a[great--] = pivot2;
+ }
+ }
+ }
+
+ // Sort center part recursively, excluding known pivot values
+ sort(a, less, great);
+ }
+
+ /**
+ * Sorts the specified range of the array into ascending order.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ static void sort(long[] a, int left, int right) {
+ // Use insertion sort on tiny arrays
+ if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
+ for (int k = left + 1; k <= right; k++) {
+ long ak = a[k];
+ int j;
+
+ for (j = k - 1; j >= left && ak < a[j]; j--) {
+ a[j + 1] = a[j];
+ }
+ a[j + 1] = ak;
+ }
+ } else { // Use Dual-Pivot Quicksort on large arrays
+ dualPivotQuicksort(a, left, right);
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array into ascending order
+ * by Dual-Pivot Quicksort.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ private static void dualPivotQuicksort(long[] a, int left, int right) {
+ // Compute indices of five evenly spaced elements
+ int sixth = (right - left + 1) / 6;
+ int e1 = left + sixth;
+ int e5 = right - sixth;
+ int e3 = (left + right) >>> 1; // The midpoint
+ int e4 = e3 + sixth;
+ int e2 = e3 - sixth;
+
+ // Sort these elements in place using a 5-element sorting network
+ if (a[e1] > a[e2]) { long t = a[e1]; a[e1] = a[e2]; a[e2] = t; }
+ if (a[e4] > a[e5]) { long t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+ if (a[e1] > a[e3]) { long t = a[e1]; a[e1] = a[e3]; a[e3] = t; }
+ if (a[e2] > a[e3]) { long t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e1] > a[e4]) { long t = a[e1]; a[e1] = a[e4]; a[e4] = t; }
+ if (a[e3] > a[e4]) { long t = a[e3]; a[e3] = a[e4]; a[e4] = t; }
+ if (a[e2] > a[e5]) { long t = a[e2]; a[e2] = a[e5]; a[e5] = t; }
+ if (a[e2] > a[e3]) { long t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e4] > a[e5]) { long t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+
+ /*
+ * Use the second and fourth of the five sorted elements as pivots.
+ * These values are inexpensive approximations of the first and
+ * second terciles of the array. Note that pivot1 <= pivot2.
+ *
+ * The pivots are stored in local variables, and the first and
+ * the last of the sorted elements are moved to the locations
+ * formerly occupied by the pivots. When partitioning is complete,
+ * the pivots are swapped back into their final positions, and
+ * excluded from subsequent sorting.
+ */
+ long pivot1 = a[e2]; a[e2] = a[left];
+ long pivot2 = a[e4]; a[e4] = a[right];
+
+ /*
+ * Partitioning
+ *
+ * left part center part right part
+ * ------------------------------------------------------------
+ * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ]
+ * ------------------------------------------------------------
+ * ^ ^ ^
+ * | | |
+ * less k great
+ */
+
+ // Pointers
+ int less = left + 1; // The index of first element of center part
+ int great = right - 1; // The index before first element of right part
+
+ boolean pivotsDiffer = pivot1 != pivot2;
+
+ if (pivotsDiffer) {
+ /*
+ * Invariants:
+ * all in (left, less) < pivot1
+ * pivot1 <= all in [less, k) <= pivot2
+ * all in (great, right) > pivot2
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ long ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else if (ak > pivot2) {
+ while (a[great] > pivot2 && k < great) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ } else { // Pivots are equal
+ /*
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") partition:
+ *
+ * left part center part right part
+ * -------------------------------------------------
+ * [ < pivot | == pivot | ? | > pivot ]
+ * -------------------------------------------------
+ *
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (left, less) < pivot
+ * all in [less, k) == pivot
+ * all in (great, right) > pivot
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ long ak = a[k];
+
+ if (ak == pivot1) {
+ continue;
+ }
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else {
+ while (a[great] > pivot1) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ }
+
+ // Swap pivots into their final positions
+ a[left] = a[less - 1]; a[less - 1] = pivot1;
+ a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+ // Sort left and right parts recursively, excluding known pivot values
+ sort(a, left, less - 2);
+ sort(a, great + 2, right);
+
+ /*
+ * If pivot1 == pivot2, all elements from center
+ * part are equal and, therefore, already sorted
+ */
+ if (!pivotsDiffer) {
+ return;
+ }
+
+ /*
+ * If center part is too large (comprises > 5/6 of
+ * the array), swap internal pivot values to ends
+ */
+ if (less < e1 && e5 < great) {
+ while (a[less] == pivot1) {
+ less++;
+ }
+ for (int k = less + 1; k <= great; k++) {
+ if (a[k] == pivot1) {
+ a[k] = a[less];
+ a[less++] = pivot1;
+ }
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+ for (int k = great - 1; k >= less; k--) {
+ if (a[k] == pivot2) {
+ a[k] = a[great];
+ a[great--] = pivot2;
+ }
+ }
+ } else { // Use Dual-Pivot Quicksort on large arrays
+ dualPivotQuicksort(a, left, right);
+ }
+ }
+
+ /** The number of distinct short values */
+ private static final int NUM_SHORT_VALUES = 1 << 16;
+
+ /**
+ * Sorts the specified range of the array into ascending order.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ static void sort(short[] a, int left, int right) {
+ // Use insertion sort on tiny arrays
+ if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
+ for (int k = left + 1; k <= right; k++) {
+ short ak = a[k];
+ int j;
+
+ for (j = k - 1; j >= left && ak < a[j]; j--) {
+ a[j + 1] = a[j];
+ }
+ a[j + 1] = ak;
+ }
+ } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+ // Use counting sort on huge arrays
+ int[] count = new int[NUM_SHORT_VALUES];
+
+ for (int i = left; i <= right; i++) {
+ count[a[i] - Short.MIN_VALUE]++;
+ }
+ for (int i = 0, k = left; i < count.length && k < right; i++) {
+ short value = (short) (i + Short.MIN_VALUE);
+
+ for (int s = count[i]; s > 0; s--) {
+ a[k++] = value;
+ }
+ }
+ } else { // Use Dual-Pivot Quicksort on large arrays
+ dualPivotQuicksort(a, left, right);
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array into ascending order
+ * by Dual-Pivot Quicksort.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ private static void dualPivotQuicksort(short[] a, int left, int right) {
+ // Compute indices of five evenly spaced elements
+ int sixth = (right - left + 1) / 6;
+ int e1 = left + sixth;
+ int e5 = right - sixth;
+ int e3 = (left + right) >>> 1; // The midpoint
+ int e4 = e3 + sixth;
+ int e2 = e3 - sixth;
+
+ // Sort these elements in place using a 5-element sorting network
+ if (a[e1] > a[e2]) { short t = a[e1]; a[e1] = a[e2]; a[e2] = t; }
+ if (a[e4] > a[e5]) { short t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+ if (a[e1] > a[e3]) { short t = a[e1]; a[e1] = a[e3]; a[e3] = t; }
+ if (a[e2] > a[e3]) { short t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e1] > a[e4]) { short t = a[e1]; a[e1] = a[e4]; a[e4] = t; }
+ if (a[e3] > a[e4]) { short t = a[e3]; a[e3] = a[e4]; a[e4] = t; }
+ if (a[e2] > a[e5]) { short t = a[e2]; a[e2] = a[e5]; a[e5] = t; }
+ if (a[e2] > a[e3]) { short t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e4] > a[e5]) { short t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+
+ /*
+ * Use the second and fourth of the five sorted elements as pivots.
+ * These values are inexpensive approximations of the first and
+ * second terciles of the array. Note that pivot1 <= pivot2.
+ *
+ * The pivots are stored in local variables, and the first and
+ * the last of the sorted elements are moved to the locations
+ * formerly occupied by the pivots. When partitioning is complete,
+ * the pivots are swapped back into their final positions, and
+ * excluded from subsequent sorting.
+ */
+ short pivot1 = a[e2]; a[e2] = a[left];
+ short pivot2 = a[e4]; a[e4] = a[right];
+
+ /*
+ * Partitioning
+ *
+ * left part center part right part
+ * ------------------------------------------------------------
+ * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ]
+ * ------------------------------------------------------------
+ * ^ ^ ^
+ * | | |
+ * less k great
+ */
+
+ // Pointers
+ int less = left + 1; // The index of first element of center part
+ int great = right - 1; // The index before first element of right part
+
+ boolean pivotsDiffer = pivot1 != pivot2;
+
+ if (pivotsDiffer) {
+ /*
+ * Invariants:
+ * all in (left, less) < pivot1
+ * pivot1 <= all in [less, k) <= pivot2
+ * all in (great, right) > pivot2
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ short ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else if (ak > pivot2) {
+ while (a[great] > pivot2 && k < great) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ } else { // Pivots are equal
+ /*
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") partition:
+ *
+ * left part center part right part
+ * -------------------------------------------------
+ * [ < pivot | == pivot | ? | > pivot ]
+ * -------------------------------------------------
+ *
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (left, less) < pivot
+ * all in [less, k) == pivot
+ * all in (great, right) > pivot
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ short ak = a[k];
+
+ if (ak == pivot1) {
+ continue;
+ }
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else {
+ while (a[great] > pivot1) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ }
+
+ // Swap pivots into their final positions
+ a[left] = a[less - 1]; a[less - 1] = pivot1;
+ a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+ // Sort left and right parts recursively, excluding known pivot values
+ sort(a, left, less - 2);
+ sort(a, great + 2, right);
+
+ /*
+ * If pivot1 == pivot2, all elements from center
+ * part are equal and, therefore, already sorted
+ */
+ if (!pivotsDiffer) {
+ return;
+ }
+
+ /*
+ * If center part is too large (comprises > 5/6 of
+ * the array), swap internal pivot values to ends
+ */
+ if (less < e1 && e5 < great) {
+ while (a[less] == pivot1) {
+ less++;
+ }
+ for (int k = less + 1; k <= great; k++) {
+ if (a[k] == pivot1) {
+ a[k] = a[less];
+ a[less++] = pivot1;
+ }
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+ for (int k = great - 1; k >= less; k--) {
+ if (a[k] == pivot2) {
+ a[k] = a[great];
+ a[great--] = pivot2;
+ }
+ }
+ }
+
+ // Sort center part recursively, excluding known pivot values
+ sort(a, less, great);
+ }
+
+ /** The number of distinct byte values */
+ private static final int NUM_BYTE_VALUES = 1 << 8;
+
+ /**
+ * Sorts the specified range of the array into ascending order.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ static void sort(byte[] a, int left, int right) {
+ // Use insertion sort on tiny arrays
+ if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
+ for (int k = left + 1; k <= right; k++) {
+ byte ak = a[k];
+ int j;
+
+ for (j = k - 1; j >= left && ak < a[j]; j--) {
+ a[j + 1] = a[j];
+ }
+ a[j + 1] = ak;
+ }
+ } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
+ // Use counting sort on large arrays
+ int[] count = new int[NUM_BYTE_VALUES];
+
+ for (int i = left; i <= right; i++) {
+ count[a[i] - Byte.MIN_VALUE]++;
+ }
+ for (int i = 0, k = left; i < count.length && k < right; i++) {
+ byte value = (byte) (i + Byte.MIN_VALUE);
+
+ for (int s = count[i]; s > 0; s--) {
+ a[k++] = value;
+ }
+ }
+ } else { // Use Dual-Pivot Quicksort on large arrays
+ dualPivotQuicksort(a, left, right);
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array into ascending order
+ * by Dual-Pivot Quicksort.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ private static void dualPivotQuicksort(byte[] a, int left, int right) {
+ // Compute indices of five evenly spaced elements
+ int sixth = (right - left + 1) / 6;
+ int e1 = left + sixth;
+ int e5 = right - sixth;
+ int e3 = (left + right) >>> 1; // The midpoint
+ int e4 = e3 + sixth;
+ int e2 = e3 - sixth;
+
+ // Sort these elements in place using a 5-element sorting network
+ if (a[e1] > a[e2]) { byte t = a[e1]; a[e1] = a[e2]; a[e2] = t; }
+ if (a[e4] > a[e5]) { byte t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+ if (a[e1] > a[e3]) { byte t = a[e1]; a[e1] = a[e3]; a[e3] = t; }
+ if (a[e2] > a[e3]) { byte t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e1] > a[e4]) { byte t = a[e1]; a[e1] = a[e4]; a[e4] = t; }
+ if (a[e3] > a[e4]) { byte t = a[e3]; a[e3] = a[e4]; a[e4] = t; }
+ if (a[e2] > a[e5]) { byte t = a[e2]; a[e2] = a[e5]; a[e5] = t; }
+ if (a[e2] > a[e3]) { byte t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e4] > a[e5]) { byte t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+
+ /*
+ * Use the second and fourth of the five sorted elements as pivots.
+ * These values are inexpensive approximations of the first and
+ * second terciles of the array. Note that pivot1 <= pivot2.
+ *
+ * The pivots are stored in local variables, and the first and
+ * the last of the sorted elements are moved to the locations
+ * formerly occupied by the pivots. When partitioning is complete,
+ * the pivots are swapped back into their final positions, and
+ * excluded from subsequent sorting.
+ */
+ byte pivot1 = a[e2]; a[e2] = a[left];
+ byte pivot2 = a[e4]; a[e4] = a[right];
+
+ /*
+ * Partitioning
+ *
+ * left part center part right part
+ * ------------------------------------------------------------
+ * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ]
+ * ------------------------------------------------------------
+ * ^ ^ ^
+ * | | |
+ * less k great
+ */
+
+ // Pointers
+ int less = left + 1; // The index of first element of center part
+ int great = right - 1; // The index before first element of right part
+
+ boolean pivotsDiffer = pivot1 != pivot2;
+
+ if (pivotsDiffer) {
+ /*
+ * Invariants:
+ * all in (left, less) < pivot1
+ * pivot1 <= all in [less, k) <= pivot2
+ * all in (great, right) > pivot2
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ byte ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else if (ak > pivot2) {
+ while (a[great] > pivot2 && k < great) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ } else { // Pivots are equal
+ /*
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") partition:
+ *
+ * left part center part right part
+ * -------------------------------------------------
+ * [ < pivot | == pivot | ? | > pivot ]
+ * -------------------------------------------------
+ *
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (left, less) < pivot
+ * all in [less, k) == pivot
+ * all in (great, right) > pivot
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ byte ak = a[k];
+
+ if (ak == pivot1) {
+ continue;
+ }
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else {
+ while (a[great] > pivot1) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ }
+
+ // Swap pivots into their final positions
+ a[left] = a[less - 1]; a[less - 1] = pivot1;
+ a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+ // Sort left and right parts recursively, excluding known pivot values
+ sort(a, left, less - 2);
+ sort(a, great + 2, right);
+
+ /*
+ * If pivot1 == pivot2, all elements from center
+ * part are equal and, therefore, already sorted
+ */
+ if (!pivotsDiffer) {
+ return;
+ }
+
+ /*
+ * If center part is too large (comprises > 5/6 of
+ * the array), swap internal pivot values to ends
+ */
+ if (less < e1 && e5 < great) {
+ while (a[less] == pivot1) {
+ less++;
+ }
+ for (int k = less + 1; k <= great; k++) {
+ if (a[k] == pivot1) {
+ a[k] = a[less];
+ a[less++] = pivot1;
+ }
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+ for (int k = great - 1; k >= less; k--) {
+ if (a[k] == pivot2) {
+ a[k] = a[great];
+ a[great--] = pivot2;
+ }
+ }
+ }
+
+ // Sort center part recursively, excluding known pivot values
+ sort(a, less, great);
+ }
+
+ /** The number of distinct char values */
+ private static final int NUM_CHAR_VALUES = 1 << 16;
+
+ /**
+ * Sorts the specified range of the array into ascending order.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ static void sort(char[] a, int left, int right) {
+ // Use insertion sort on tiny arrays
+ if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
+ for (int k = left + 1; k <= right; k++) {
+ char ak = a[k];
+ int j;
+
+ for (j = k - 1; j >= left && ak < a[j]; j--) {
+ a[j + 1] = a[j];
+ }
+ a[j + 1] = ak;
+ }
+ } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+ // Use counting sort on huge arrays
+ int[] count = new int[NUM_CHAR_VALUES];
+
+ for (int i = left; i <= right; i++) {
+ count[a[i]]++;
+ }
+ for (int i = 0, k = left; i < count.length && k < right; i++) {
+ for (int s = count[i]; s > 0; s--) {
+ a[k++] = (char) i;
+ }
+ }
+ } else { // Use Dual-Pivot Quicksort on large arrays
+ dualPivotQuicksort(a, left, right);
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array into ascending order
+ * by Dual-Pivot Quicksort.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ private static void dualPivotQuicksort(char[] a, int left, int right) {
+ // Compute indices of five evenly spaced elements
+ int sixth = (right - left + 1) / 6;
+ int e1 = left + sixth;
+ int e5 = right - sixth;
+ int e3 = (left + right) >>> 1; // The midpoint
+ int e4 = e3 + sixth;
+ int e2 = e3 - sixth;
+
+ // Sort these elements in place using a 5-element sorting network
+ if (a[e1] > a[e2]) { char t = a[e1]; a[e1] = a[e2]; a[e2] = t; }
+ if (a[e4] > a[e5]) { char t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+ if (a[e1] > a[e3]) { char t = a[e1]; a[e1] = a[e3]; a[e3] = t; }
+ if (a[e2] > a[e3]) { char t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e1] > a[e4]) { char t = a[e1]; a[e1] = a[e4]; a[e4] = t; }
+ if (a[e3] > a[e4]) { char t = a[e3]; a[e3] = a[e4]; a[e4] = t; }
+ if (a[e2] > a[e5]) { char t = a[e2]; a[e2] = a[e5]; a[e5] = t; }
+ if (a[e2] > a[e3]) { char t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e4] > a[e5]) { char t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+
+ /*
+ * Use the second and fourth of the five sorted elements as pivots.
+ * These values are inexpensive approximations of the first and
+ * second terciles of the array. Note that pivot1 <= pivot2.
+ *
+ * The pivots are stored in local variables, and the first and
+ * the last of the sorted elements are moved to the locations
+ * formerly occupied by the pivots. When partitioning is complete,
+ * the pivots are swapped back into their final positions, and
+ * excluded from subsequent sorting.
+ */
+ char pivot1 = a[e2]; a[e2] = a[left];
+ char pivot2 = a[e4]; a[e4] = a[right];
+
+ /*
+ * Partitioning
+ *
+ * left part center part right part
+ * ------------------------------------------------------------
+ * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ]
+ * ------------------------------------------------------------
+ * ^ ^ ^
+ * | | |
+ * less k great
+ */
+
+ // Pointers
+ int less = left + 1; // The index of first element of center part
+ int great = right - 1; // The index before first element of right part
+
+ boolean pivotsDiffer = pivot1 != pivot2;
+
+ if (pivotsDiffer) {
+ /*
+ * Invariants:
+ * all in (left, less) < pivot1
+ * pivot1 <= all in [less, k) <= pivot2
+ * all in (great, right) > pivot2
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ char ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else if (ak > pivot2) {
+ while (a[great] > pivot2 && k < great) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ } else { // Pivots are equal
+ /*
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") partition:
+ *
+ * left part center part right part
+ * -------------------------------------------------
+ * [ < pivot | == pivot | ? | > pivot ]
+ * -------------------------------------------------
+ *
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (left, less) < pivot
+ * all in [less, k) == pivot
+ * all in (great, right) > pivot
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ char ak = a[k];
+
+ if (ak == pivot1) {
+ continue;
+ }
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else {
+ while (a[great] > pivot1) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ }
+
+ // Swap pivots into their final positions
+ a[left] = a[less - 1]; a[less - 1] = pivot1;
+ a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+ // Sort left and right parts recursively, excluding known pivot values
+ sort(a, left, less - 2);
+ sort(a, great + 2, right);
+
+ /*
+ * If pivot1 == pivot2, all elements from center
+ * part are equal and, therefore, already sorted
+ */
+ if (!pivotsDiffer) {
+ return;
+ }
+
+ /*
+ * If center part is too large (comprises > 5/6 of
+ * the array), swap internal pivot values to ends
+ */
+ if (less < e1 && e5 < great) {
+ while (a[less] == pivot1) {
+ less++;
+ }
+ for (int k = less + 1; k <= great; k++) {
+ if (a[k] == pivot1) {
+ a[k] = a[less];
+ a[less++] = pivot1;
+ }
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+ for (int k = great - 1; k >= less; k--) {
+ if (a[k] == pivot2) {
+ a[k] = a[great];
+ a[great--] = pivot2;
+ }
+ }
+ }
+
+ // Sort center part recursively, excluding known pivot values
+ sort(a, less, great);
+ }
+
+ /**
+ * Sorts the specified range of the array into ascending order.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ static void sort(float[] a, int left, int right) {
+ // Use insertion sort on tiny arrays
+ if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
+ for (int k = left + 1; k <= right; k++) {
+ float ak = a[k];
+ int j;
+
+ for (j = k - 1; j >= left && ak < a[j]; j--) {
+ a[j + 1] = a[j];
+ }
+ a[j + 1] = ak;
+ }
+ } else { // Use Dual-Pivot Quicksort on large arrays
+ dualPivotQuicksort(a, left, right);
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array into ascending order
+ * by Dual-Pivot Quicksort.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ private static void dualPivotQuicksort(float[] a, int left, int right) {
+ // Compute indices of five evenly spaced elements
+ int sixth = (right - left + 1) / 6;
+ int e1 = left + sixth;
+ int e5 = right - sixth;
+ int e3 = (left + right) >>> 1; // The midpoint
+ int e4 = e3 + sixth;
+ int e2 = e3 - sixth;
+
+ // Sort these elements in place using a 5-element sorting network
+ if (a[e1] > a[e2]) { float t = a[e1]; a[e1] = a[e2]; a[e2] = t; }
+ if (a[e4] > a[e5]) { float t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+ if (a[e1] > a[e3]) { float t = a[e1]; a[e1] = a[e3]; a[e3] = t; }
+ if (a[e2] > a[e3]) { float t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e1] > a[e4]) { float t = a[e1]; a[e1] = a[e4]; a[e4] = t; }
+ if (a[e3] > a[e4]) { float t = a[e3]; a[e3] = a[e4]; a[e4] = t; }
+ if (a[e2] > a[e5]) { float t = a[e2]; a[e2] = a[e5]; a[e5] = t; }
+ if (a[e2] > a[e3]) { float t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e4] > a[e5]) { float t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+
+ /*
+ * Use the second and fourth of the five sorted elements as pivots.
+ * These values are inexpensive approximations of the first and
+ * second terciles of the array. Note that pivot1 <= pivot2.
+ *
+ * The pivots are stored in local variables, and the first and
+ * the last of the sorted elements are moved to the locations
+ * formerly occupied by the pivots. When partitioning is complete,
+ * the pivots are swapped back into their final positions, and
+ * excluded from subsequent sorting.
+ */
+ float pivot1 = a[e2]; a[e2] = a[left];
+ float pivot2 = a[e4]; a[e4] = a[right];
+
+ /*
+ * Partitioning
+ *
+ * left part center part right part
+ * ------------------------------------------------------------
+ * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ]
+ * ------------------------------------------------------------
+ * ^ ^ ^
+ * | | |
+ * less k great
+ */
+
+ // Pointers
+ int less = left + 1; // The index of first element of center part
+ int great = right - 1; // The index before first element of right part
+
+ boolean pivotsDiffer = pivot1 != pivot2;
+
+ if (pivotsDiffer) {
+ /*
+ * Invariants:
+ * all in (left, less) < pivot1
+ * pivot1 <= all in [less, k) <= pivot2
+ * all in (great, right) > pivot2
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ float ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else if (ak > pivot2) {
+ while (a[great] > pivot2 && k < great) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ } else { // Pivots are equal
+ /*
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") partition:
+ *
+ * left part center part right part
+ * -------------------------------------------------
+ * [ < pivot | == pivot | ? | > pivot ]
+ * -------------------------------------------------
+ *
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (left, less) < pivot
+ * all in [less, k) == pivot
+ * all in (great, right) > pivot
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ float ak = a[k];
+
+ if (ak == pivot1) {
+ continue;
+ }
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else {
+ while (a[great] > pivot1) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ }
+
+ // Swap pivots into their final positions
+ a[left] = a[less - 1]; a[less - 1] = pivot1;
+ a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+ // Sort left and right parts recursively, excluding known pivot values
+ sort(a, left, less - 2);
+ sort(a, great + 2, right);
+
+ /*
+ * If pivot1 == pivot2, all elements from center
+ * part are equal and, therefore, already sorted
+ */
+ if (!pivotsDiffer) {
+ return;
+ }
+
+ /*
+ * If center part is too large (comprises > 5/6 of
+ * the array), swap internal pivot values to ends
+ */
+ if (less < e1 && e5 < great) {
+ while (a[less] == pivot1) {
+ less++;
+ }
+ for (int k = less + 1; k <= great; k++) {
+ if (a[k] == pivot1) {
+ a[k] = a[less];
+ a[less++] = pivot1;
+ }
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+ for (int k = great - 1; k >= less; k--) {
+ if (a[k] == pivot2) {
+ a[k] = a[great];
+ a[great--] = pivot2;
+ }
+ }
+ }
+
+ // Sort center part recursively, excluding known pivot values
+ sort(a, less, great);
+ }
+
+ /**
+ * Sorts the specified range of the array into ascending order.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ static void sort(double[] a, int left, int right) {
+ // Use insertion sort on tiny arrays
+ if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
+ for (int k = left + 1; k <= right; k++) {
+ double ak = a[k];
+ int j;
+
+ for (j = k - 1; j >= left && ak < a[j]; j--) {
+ a[j + 1] = a[j];
+ }
+ a[j + 1] = ak;
+ }
+ } else { // Use Dual-Pivot Quicksort on large arrays
+ dualPivotQuicksort(a, left, right);
+ }
+ }
+
+ /**
+ * Sorts the specified range of the array into ascending order
+ * by Dual-Pivot Quicksort.
+ *
+ * @param a the array to be sorted
+ * @param left the index of the first element, inclusively, to be sorted
+ * @param right the index of the last element, inclusively, to be sorted
+ */
+ private static void dualPivotQuicksort(double[] a, int left, int right) {
+ // Compute indices of five evenly spaced elements
+ int sixth = (right - left + 1) / 6;
+ int e1 = left + sixth;
+ int e5 = right - sixth;
+ int e3 = (left + right) >>> 1; // The midpoint
+ int e4 = e3 + sixth;
+ int e2 = e3 - sixth;
+
+ // Sort these elements in place using a 5-element sorting network
+ if (a[e1] > a[e2]) { double t = a[e1]; a[e1] = a[e2]; a[e2] = t; }
+ if (a[e4] > a[e5]) { double t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+ if (a[e1] > a[e3]) { double t = a[e1]; a[e1] = a[e3]; a[e3] = t; }
+ if (a[e2] > a[e3]) { double t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e1] > a[e4]) { double t = a[e1]; a[e1] = a[e4]; a[e4] = t; }
+ if (a[e3] > a[e4]) { double t = a[e3]; a[e3] = a[e4]; a[e4] = t; }
+ if (a[e2] > a[e5]) { double t = a[e2]; a[e2] = a[e5]; a[e5] = t; }
+ if (a[e2] > a[e3]) { double t = a[e2]; a[e2] = a[e3]; a[e3] = t; }
+ if (a[e4] > a[e5]) { double t = a[e4]; a[e4] = a[e5]; a[e5] = t; }
+
+ /*
+ * Use the second and fourth of the five sorted elements as pivots.
+ * These values are inexpensive approximations of the first and
+ * second terciles of the array. Note that pivot1 <= pivot2.
+ *
+ * The pivots are stored in local variables, and the first and
+ * the last of the sorted elements are moved to the locations
+ * formerly occupied by the pivots. When partitioning is complete,
+ * the pivots are swapped back into their final positions, and
+ * excluded from subsequent sorting.
+ */
+ double pivot1 = a[e2]; a[e2] = a[left];
+ double pivot2 = a[e4]; a[e4] = a[right];
+
+ /*
+ * Partitioning
+ *
+ * left part center part right part
+ * ------------------------------------------------------------
+ * [ < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 ]
+ * ------------------------------------------------------------
+ * ^ ^ ^
+ * | | |
+ * less k great
+ */
+
+ // Pointers
+ int less = left + 1; // The index of first element of center part
+ int great = right - 1; // The index before first element of right part
+
+ boolean pivotsDiffer = pivot1 != pivot2;
+
+ if (pivotsDiffer) {
+ /*
+ * Invariants:
+ * all in (left, less) < pivot1
+ * pivot1 <= all in [less, k) <= pivot2
+ * all in (great, right) > pivot2
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ double ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else if (ak > pivot2) {
+ while (a[great] > pivot2 && k < great) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ } else { // Pivots are equal
+ /*
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") partition:
+ *
+ * left part center part right part
+ * -------------------------------------------------
+ * [ < pivot | == pivot | ? | > pivot ]
+ * -------------------------------------------------
+ *
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (left, less) < pivot
+ * all in [less, k) == pivot
+ * all in (great, right) > pivot
+ *
+ * Pointer k is the first index of ?-part
+ */
+ for (int k = less; k <= great; k++) {
+ double ak = a[k];
+
+ if (ak == pivot1) {
+ continue;
+ }
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ } else {
+ while (a[great] > pivot1) {
+ great--;
+ }
+ a[k] = a[great];
+ a[great--] = ak;
+ ak = a[k];
+
+ if (ak < pivot1) {
+ a[k] = a[less];
+ a[less++] = ak;
+ }
+ }
+ }
+ }
+
+ // Swap pivots into their final positions
+ a[left] = a[less - 1]; a[less - 1] = pivot1;
+ a[right] = a[great + 1]; a[great + 1] = pivot2;
+
+ // Sort left and right parts recursively, excluding known pivot values
+ sort(a, left, less - 2);
+ sort(a, great + 2, right);
+
+ /*
+ * If pivot1 == pivot2, all elements from center
+ * part are equal and, therefore, already sorted
+ */
+ if (!pivotsDiffer) {
+ return;
+ }
+
+ /*
+ * If center part is too large (comprises > 5/6 of
+ * the array), swap internal pivot values to ends
+ */
+ if (less < e1 && e5 < great) {
+ while (a[less] == pivot1) {
+ less++;
+ }
+ for (int k = less + 1; k <= great; k++) {
+ if (a[k] == pivot1) {
+ a[k] = a[less];
+ a[less++] = pivot1;
+ }
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+ for (int k = great - 1; k >= less; k--) {
+ if (a[k] == pivot2) {
+ a[k] = a[great];
+ a[great--] = pivot2;
+ }
+ }
+ }
+
+ // Sort center part recursively, excluding known pivot values
+ sort(a, less, great);
+ }
+}
diff --git a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java
index f7a8591646a..adf2cd8ace1 100644
--- a/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java
+++ b/jdk/src/share/classes/sun/security/krb5/EncryptionKey.java
@@ -1,5 +1,5 @@
/*
- * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
+ * Portions Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -503,7 +503,19 @@ public class EncryptionKey
+ '\n'));
}
+ /**
+ * Find a key with given etype
+ */
public static EncryptionKey findKey(int etype, EncryptionKey[] keys)
+ throws KrbException {
+ return findKey(etype, null, keys);
+ }
+
+ /**
+ * Find a key with given etype and kvno
+ * @param kvno if null, return any (first?) key
+ */
+ public static EncryptionKey findKey(int etype, Integer kvno, EncryptionKey[] keys)
throws KrbException {
// check if encryption type is supported
@@ -516,7 +528,8 @@ public class EncryptionKey
for (int i = 0; i < keys.length; i++) {
ktype = keys[i].getEType();
if (EType.isSupported(ktype)) {
- if (etype == ktype) {
+ Integer kv = keys[i].getKeyVersionNumber();
+ if (etype == ktype && (kvno == null || kvno.equals(kv))) {
return keys[i];
}
}
@@ -528,8 +541,11 @@ public class EncryptionKey
for (int i = 0; i < keys.length; i++) {
ktype = keys[i].getEType();
if (ktype == EncryptedData.ETYPE_DES_CBC_CRC ||
- ktype == EncryptedData.ETYPE_DES_CBC_MD5) {
- return new EncryptionKey(etype, keys[i].getBytes());
+ ktype == EncryptedData.ETYPE_DES_CBC_MD5) {
+ Integer kv = keys[i].getKeyVersionNumber();
+ if (kvno == null || kvno.equals(kv)) {
+ return new EncryptionKey(etype, keys[i].getBytes());
+ }
}
}
}
diff --git a/jdk/src/share/classes/sun/security/krb5/KrbApReq.java b/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
index 696762b6cd0..e3c21af0d7f 100644
--- a/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
+++ b/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
@@ -268,7 +268,8 @@ public class KrbApReq {
private void authenticate(EncryptionKey[] keys, InetAddress initiator)
throws KrbException, IOException {
int encPartKeyType = apReqMessg.ticket.encPart.getEType();
- EncryptionKey dkey = EncryptionKey.findKey(encPartKeyType, keys);
+ Integer kvno = apReqMessg.ticket.encPart.getKeyVersionNumber();
+ EncryptionKey dkey = EncryptionKey.findKey(encPartKeyType, kvno, keys);
if (dkey == null) {
throw new KrbException(Krb5.API_INVALID_ARG,
diff --git a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java
index 388548b2eeb..edca23322a4 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java
@@ -395,6 +395,28 @@ public class KeyTab implements KeyTabConstants {
}
}
+ /**
+ * Only used by KDC test. This method can specify kvno and does not
+ * remove any old keys.
+ */
+ public void addEntry(PrincipalName service, char[] psswd, int kvno)
+ throws KrbException {
+
+ EncryptionKey[] encKeys = EncryptionKey.acquireSecretKeys(
+ psswd, service.getSalt());
+
+ for (int i = 0; encKeys != null && i < encKeys.length; i++) {
+ int keyType = encKeys[i].getEType();
+ byte[] keyValue = encKeys[i].getBytes();
+ KeyTabEntry newEntry = new KeyTabEntry(service,
+ service.getRealm(),
+ new KerberosTime(System.currentTimeMillis()),
+ kvno, keyType, keyValue);
+ if (entries == null)
+ entries = new Vector ();
+ entries.addElement(newEntry);
+ }
+ }
/**
* Retrieves the key table entry with the specified service name.
diff --git a/jdk/src/share/classes/sun/security/tools/JarSigner.java b/jdk/src/share/classes/sun/security/tools/JarSigner.java
index b373ebc23ef..005d8aa1bfd 100644
--- a/jdk/src/share/classes/sun/security/tools/JarSigner.java
+++ b/jdk/src/share/classes/sun/security/tools/JarSigner.java
@@ -1483,6 +1483,7 @@ public class JarSigner {
Timestamp timestamp = signer.getTimestamp();
if (timestamp != null) {
s.append(printTimestamp(tab, timestamp));
+ s.append('\n');
}
// display the certificate(s)
for (Certificate c : certs) {
diff --git a/jdk/src/share/classes/sun/security/tools/KeyTool.java b/jdk/src/share/classes/sun/security/tools/KeyTool.java
index 3ce402a65d0..b3b0f7365ab 100644
--- a/jdk/src/share/classes/sun/security/tools/KeyTool.java
+++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java
@@ -26,6 +26,7 @@
package sun.security.tools;
import java.io.*;
+import java.security.CodeSigner;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.MessageDigest;
@@ -34,6 +35,7 @@ import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;
+import java.security.Timestamp;
import java.security.UnrecoverableEntryException;
import java.security.UnrecoverableKeyException;
import java.security.Principal;
@@ -46,6 +48,8 @@ import java.security.cert.CertificateException;
import java.text.Collator;
import java.text.MessageFormat;
import java.util.*;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
@@ -130,6 +134,7 @@ public final class KeyTool {
private File ksfile = null;
private InputStream ksStream = null; // keystore stream
private String sslserver = null;
+ private String jarfile = null;
private KeyStore keyStore = null;
private boolean token = false;
private boolean nullStream = false;
@@ -206,7 +211,7 @@ public final class KeyTool {
"-providername", "-providerclass", "-providerarg",
"-providerpath", "-v", "-protected"),
PRINTCERT("Prints the content of a certificate",
- "-rfc", "-file", "-sslserver", "-v"),
+ "-rfc", "-file", "-sslserver", "-jarfile", "-v"),
PRINTCERTREQ("Prints the content of a certificate request",
"-file", "-v"),
SELFCERT("Generates a self-signed certificate",
@@ -266,6 +271,7 @@ public final class KeyTool {
{"-srcstorepass", "", "source keystore password"},
{"-srcstoretype", "", "source keystore type"},
{"-sslserver", "", "SSL server host and port"},
+ {"-jarfile", "", "signed jar file"},
{"-startdate", "", "certificate validity start date/time"},
{"-storepass", "", "keystore password"},
{"-storetype", "", "keystore type"},
@@ -453,6 +459,8 @@ public final class KeyTool {
outfilename = args[++i];
} else if (collator.compare(flags, "-sslserver") == 0) {
sslserver = args[++i];
+ } else if (collator.compare(flags, "-jarfile") == 0) {
+ jarfile = args[++i];
} else if (collator.compare(flags, "-srckeystore") == 0) {
srcksfname = args[++i];
} else if ((collator.compare(flags, "-provider") == 0) ||
@@ -2065,7 +2073,71 @@ public final class KeyTool {
}
private void doPrintCert(final PrintStream out) throws Exception {
- if (sslserver != null) {
+ if (jarfile != null) {
+ JarFile jf = new JarFile(jarfile, true);
+ Enumeration entries = jf.entries();
+ Set ss = new HashSet();
+ byte[] buffer = new byte[8192];
+ int pos = 0;
+ while (entries.hasMoreElements()) {
+ JarEntry je = entries.nextElement();
+ InputStream is = null;
+ try {
+ is = jf.getInputStream(je);
+ while (is.read(buffer) != -1) {
+ // we just read. this will throw a SecurityException
+ // if a signature/digest check fails. This also
+ // populate the signers
+ }
+ } finally {
+ if (is != null) {
+ is.close();
+ }
+ }
+ CodeSigner[] signers = je.getCodeSigners();
+ if (signers != null) {
+ for (CodeSigner signer: signers) {
+ if (!ss.contains(signer)) {
+ ss.add(signer);
+ out.printf(rb.getString("Signer #%d:"), ++pos);
+ out.println();
+ out.println();
+ out.println(rb.getString("Signature:"));
+ out.println();
+ for (Certificate cert: signer.getSignerCertPath().getCertificates()) {
+ X509Certificate x = (X509Certificate)cert;
+ if (rfc) {
+ out.println(rb.getString("Certificate owner: ") + x.getSubjectDN() + "\n");
+ dumpCert(x, out);
+ } else {
+ printX509Cert(x, out);
+ }
+ out.println();
+ }
+ Timestamp ts = signer.getTimestamp();
+ if (ts != null) {
+ out.println(rb.getString("Timestamp:"));
+ out.println();
+ for (Certificate cert: ts.getSignerCertPath().getCertificates()) {
+ X509Certificate x = (X509Certificate)cert;
+ if (rfc) {
+ out.println(rb.getString("Certificate owner: ") + x.getSubjectDN() + "\n");
+ dumpCert(x, out);
+ } else {
+ printX509Cert(x, out);
+ }
+ out.println();
+ }
+ }
+ }
+ }
+ }
+ }
+ jf.close();
+ if (ss.size() == 0) {
+ out.println(rb.getString("Not a signed jar file"));
+ }
+ } else if (sslserver != null) {
SSLContext sc = SSLContext.getInstance("SSL");
final boolean[] certPrinted = new boolean[1];
sc.init(null, new TrustManager[] {
diff --git a/jdk/src/share/classes/sun/security/util/Resources.java b/jdk/src/share/classes/sun/security/util/Resources.java
index 686e91469a8..3911b5479f8 100644
--- a/jdk/src/share/classes/sun/security/util/Resources.java
+++ b/jdk/src/share/classes/sun/security/util/Resources.java
@@ -162,6 +162,8 @@ public class Resources extends java.util.ListResourceBundle {
"source keystore type"}, //-srcstoretype
{"SSL server host and port",
"SSL server host and port"}, //-sslserver
+ {"signed jar file",
+ "signed jar file"}, //=jarfile
{"certificate validity start date/time",
"certificate validity start date/time"}, //-startdate
{"keystore password",
@@ -370,6 +372,13 @@ public class Resources extends java.util.ListResourceBundle {
{"***************** WARNING WARNING WARNING *****************",
"***************** WARNING WARNING WARNING *****************"},
+ {"Signer #%d:", "Signer #%d:"},
+ {"Timestamp:", "Timestamp:"},
+ {"Signature:", "Signature:"},
+ {"Certificate owner: ", "Certificate owner: "},
+ {"Not a signed jar file", "Not a signed jar file"},
+ {"No certificate from the SSL server",
+ "No certificate from the SSL server"},
// Translators of the following 5 pairs, ATTENTION:
// the next 5 string pairs are meant to be combined into 2 paragraphs,
diff --git a/jdk/test/sun/security/krb5/auto/KDC.java b/jdk/test/sun/security/krb5/auto/KDC.java
index 601eda50707..586d8b23e61 100644
--- a/jdk/test/sun/security/krb5/auto/KDC.java
+++ b/jdk/test/sun/security/krb5/auto/KDC.java
@@ -466,7 +466,17 @@ public class KDC {
// the krb5.conf config file would be loaded.
Method stringToKey = EncryptionKey.class.getDeclaredMethod("stringToKey", char[].class, String.class, byte[].class, Integer.TYPE);
stringToKey.setAccessible(true);
- return new EncryptionKey((byte[]) stringToKey.invoke(null, getPassword(p), getSalt(p), null, etype), etype, null);
+ Integer kvno = null;
+ // For service whose password ending with a number, use it as kvno
+ if (p.toString().indexOf('/') >= 0) {
+ char[] pass = getPassword(p);
+ if (Character.isDigit(pass[pass.length-1])) {
+ kvno = pass[pass.length-1] - '0';
+ }
+ }
+ return new EncryptionKey((byte[]) stringToKey.invoke(
+ null, getPassword(p), getSalt(p), null, etype),
+ etype, kvno);
} catch (InvocationTargetException ex) {
KrbException ke = (KrbException)ex.getCause();
throw ke;
diff --git a/jdk/test/sun/security/krb5/auto/MoreKvno.java b/jdk/test/sun/security/krb5/auto/MoreKvno.java
new file mode 100644
index 00000000000..66740a8b799
--- /dev/null
+++ b/jdk/test/sun/security/krb5/auto/MoreKvno.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6893158
+ * @summary AP_REQ check should use key version number
+ */
+
+import sun.security.jgss.GSSUtil;
+import sun.security.krb5.PrincipalName;
+import sun.security.krb5.internal.ktab.KeyTab;
+
+public class MoreKvno {
+
+ public static void main(String[] args)
+ throws Exception {
+
+ OneKDC kdc = new OneKDC(null);
+ kdc.writeJAASConf();
+
+ // Rewrite keytab, 3 set of keys with different kvno
+ KeyTab ktab = KeyTab.create(OneKDC.KTAB);
+ PrincipalName p = new PrincipalName(OneKDC.SERVER+"@"+OneKDC.REALM, PrincipalName.KRB_NT_SRV_HST);
+ ktab.addEntry(p, "pass0".toCharArray(), 0);
+ ktab.addEntry(p, "pass2".toCharArray(), 2);
+ ktab.addEntry(p, "pass1".toCharArray(), 1);
+ ktab.save();
+
+ kdc.addPrincipal(OneKDC.SERVER, "pass1".toCharArray());
+ go(OneKDC.SERVER, "com.sun.security.jgss.krb5.accept");
+ kdc.addPrincipal(OneKDC.SERVER, "pass2".toCharArray());
+ // "server" initiate also, check pass2 is used at authentication
+ go(OneKDC.SERVER, "server");
+ }
+
+ static void go(String server, String entry) throws Exception {
+ Context c, s;
+ c = Context.fromUserPass("dummy", "bogus".toCharArray(), false);
+ s = Context.fromJAAS(entry);
+
+ c.startAsClient(server, GSSUtil.GSS_KRB5_MECH_OID);
+ s.startAsServer(GSSUtil.GSS_KRB5_MECH_OID);
+
+ Context.handshake(c, s);
+
+ s.dispose();
+ c.dispose();
+ }
+}
diff --git a/jdk/test/sun/security/tools/keytool/readjar.sh b/jdk/test/sun/security/tools/keytool/readjar.sh
new file mode 100644
index 00000000000..e9ec824c32f
--- /dev/null
+++ b/jdk/test/sun/security/tools/keytool/readjar.sh
@@ -0,0 +1,56 @@
+#
+# Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 6890872
+# @summary keytool -printcert to recognize signed jar files
+#
+
+if [ "${TESTJAVA}" = "" ] ; then
+ JAVAC_CMD=`which javac`
+ TESTJAVA=`dirname $JAVAC_CMD`/..
+fi
+
+# set platform-dependent variables
+OS=`uname -s`
+case "$OS" in
+ Windows_* )
+ FS="\\"
+ ;;
+ * )
+ FS="/"
+ ;;
+esac
+
+KS=readjar.jks
+rm $KS
+$TESTJAVA${FS}bin${FS}keytool -storepass changeit -keypass changeit -keystore $KS \
+ -alias x -dname CN=X -genkeypair
+$TESTJAVA${FS}bin${FS}jar cvf readjar.jar $KS
+$TESTJAVA${FS}bin${FS}jarsigner -storepass changeit -keystore $KS readjar.jar x
+
+$TESTJAVA${FS}bin${FS}keytool -printcert -jarfile readjar.jar || exit 1
+$TESTJAVA${FS}bin${FS}keytool -printcert -jarfile readjar.jar -rfc || exit 1
+
+exit 0
+