diff --git a/make/java/java/FILES_java.gmk b/make/java/java/FILES_java.gmk
index fcb61e1beb6aebb94de43cf883b482531294d2d3..f9fdea5cf069d74c50e08d8ea907879eb4679fc8 100644
--- a/make/java/java/FILES_java.gmk
+++ b/make/java/java/FILES_java.gmk
@@ -465,14 +465,11 @@ JAVA_JAVA_java = \
java/security/ProtectionDomain.java \
java/net/URLClassLoader.java \
java/net/URLConnection.java \
+ sun/misc/BootClassLoaderHook.java \
sun/misc/Launcher.java \
sun/misc/MetaIndex.java \
sun/misc/URLClassPath.java \
sun/misc/Version.java \
- sun/net/www/protocol/jar/Handler.java \
- sun/net/www/protocol/jar/JarURLConnection.java \
- sun/net/www/protocol/file/Handler.java \
- sun/net/www/protocol/file/FileURLConnection.java \
sun/misc/FileURLMapper.java \
sun/misc/MessageUtils.java \
sun/misc/GC.java \
@@ -482,6 +479,10 @@ JAVA_JAVA_java = \
sun/misc/JavaIOFileDescriptorAccess.java \
sun/misc/JavaNioAccess.java \
sun/misc/Perf.java \
- sun/misc/PerfCounter.java
+ sun/misc/PerfCounter.java \
+ sun/net/www/protocol/jar/Handler.java \
+ sun/net/www/protocol/jar/JarURLConnection.java \
+ sun/net/www/protocol/file/Handler.java \
+ sun/net/www/protocol/file/FileURLConnection.java
FILES_java = $(JAVA_JAVA_java)
diff --git a/src/share/classes/com/sun/java/util/jar/pack/Attribute.java b/src/share/classes/com/sun/java/util/jar/pack/Attribute.java
index 0c1b09543001609f9d5a8e44cac56e36ff2e55e3..b662ebb9683ddfd1e5e4c6ccb8f3c29744fd32b1 100644
--- a/src/share/classes/com/sun/java/util/jar/pack/Attribute.java
+++ b/src/share/classes/com/sun/java/util/jar/pack/Attribute.java
@@ -654,8 +654,8 @@ class Attribute implements Comparable, Constants {
String layout;
public FormatException(String message,
int ctype, String name, String layout) {
- super(ATTR_CONTEXT_NAME[ctype]+"."+name
- +(message == null? "": (": "+message)));
+ super(ATTR_CONTEXT_NAME[ctype]+ " attribute \"" + name + "\"" +
+ (message == null? "" : (": " + message)));
this.ctype = ctype;
this.name = name;
this.layout = layout;
diff --git a/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java b/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java
index a14bf350a6f5410952576ee933c2063b0f896045..fd28171a75b7c95eff0997d6f678c96c732ccb44 100644
--- a/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java
+++ b/src/share/classes/com/sun/java/util/jar/pack/ClassReader.java
@@ -30,6 +30,7 @@ import java.util.*;
import com.sun.java.util.jar.pack.Package.Class;
import com.sun.java.util.jar.pack.Package.InnerClass;
import com.sun.java.util.jar.pack.ConstantPool.*;
+import com.sun.tools.classfile.AttributeException;
/**
* Reader for a class file that is being incorporated into a package.
@@ -246,7 +247,9 @@ class ClassReader implements Constants {
fixups[fptr++] = in.readUnsignedShort();
break;
default:
- throw new IOException("Bad constant pool tag "+tag);
+ throw new ClassFormatException("Bad constant pool tag " +
+ tag + " in File: " + cls.file.nameString +
+ " at pos: " + inPos);
}
}
@@ -403,7 +406,7 @@ class ClassReader implements Constants {
skip(length, "unknown "+name+" attribute in "+h);
continue;
} else {
- String message = "unknown in "+h;
+ String message = " is unknown attribute in class " + h;
throw new Attribute.FormatException(message, ctype, name,
unknownAttrCommand);
}
@@ -415,7 +418,12 @@ class ClassReader implements Constants {
if (a.name() == "Code") {
Class.Method m = (Class.Method) h;
m.code = new Code(m);
- readCode(m.code);
+ try {
+ readCode(m.code);
+ } catch (Instruction.FormatException iie) {
+ String message = iie.getMessage() + " in " + h;
+ throw new ClassReader.ClassFormatException(message);
+ }
} else {
assert(h == cls);
readInnerClasses(cls);
@@ -427,6 +435,10 @@ class ClassReader implements Constants {
in.readFully(bytes);
a = a.addContent(bytes);
}
+ if (a.size() == 0 && !a.layout().isEmpty()) {
+ throw new ClassFormatException(name +
+ ": attribute length cannot be zero, in " + h);
+ }
h.addAttribute(a);
if (verbose > 2)
Utils.log.fine("read "+a);
@@ -438,6 +450,7 @@ class ClassReader implements Constants {
code.max_locals = readUnsignedShort();
code.bytes = new byte[readInt()];
in.readFully(code.bytes);
+ Instruction.opcodeChecker(code.bytes);
int nh = readUnsignedShort();
code.setHandlerCount(nh);
for (int i = 0; i < nh; i++) {
@@ -463,4 +476,10 @@ class ClassReader implements Constants {
cls.innerClasses = ics; // set directly; do not use setInnerClasses.
// (Later, ics may be transferred to the pkg.)
}
+
+ class ClassFormatException extends IOException {
+ public ClassFormatException(String message) {
+ super(message);
+ }
+ }
}
diff --git a/src/share/classes/com/sun/java/util/jar/pack/Instruction.java b/src/share/classes/com/sun/java/util/jar/pack/Instruction.java
index bef43fd0f03af11866d1f9b03cdfab7b26ccd535..2eb4604ec08642c29ea9731a347a1433c4971d90 100644
--- a/src/share/classes/com/sun/java/util/jar/pack/Instruction.java
+++ b/src/share/classes/com/sun/java/util/jar/pack/Instruction.java
@@ -25,6 +25,8 @@
package com.sun.java.util.jar.pack;
+import java.io.IOException;
+
/**
* A parsed bytecode instruction.
* Provides accessors to various relevant bits.
@@ -628,4 +630,21 @@ class Instruction implements Constants {
}
}
}
+
+ public static void opcodeChecker(byte[] code) throws FormatException {
+ Instruction i = at(code, 0);
+ while (i != null) {
+ int opcode = i.getBC();
+ if (opcode == _xxxunusedxxx || opcode < _nop || opcode > _jsr_w) {
+ String message = "illegal opcode: " + opcode + " " + i;
+ throw new FormatException(message);
+ }
+ i = i.next();
+ }
+ }
+ static class FormatException extends IOException {
+ FormatException(String message) {
+ super(message);
+ }
+ }
}
diff --git a/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java b/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java
index 449bbbeb5b1a5376d0440f1cdebf8a1fcecb6570..a45a4bcba094a4bf207784c789e40fac5ffbb6a7 100644
--- a/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java
+++ b/src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java
@@ -496,15 +496,29 @@ public class PackerImpl extends TLGlobals implements Pack200.Packer {
reader.unknownAttrCommand = unknownAttrCommand;
try {
reader.read();
- } catch (Attribute.FormatException ee) {
- // He passed up the category to us in layout.
- if (ee.layout.equals(Pack200.Packer.PASS)) {
- Utils.log.warning("Passing class file uncompressed due to unrecognized attribute: "+fname);
- Utils.log.info(ee.toString());
- return null;
+ } catch (IOException ioe) {
+ String message = "Passing class file uncompressed due to";
+ if (ioe instanceof Attribute.FormatException) {
+ Attribute.FormatException ee = (Attribute.FormatException) ioe;
+ // He passed up the category to us in layout.
+ if (ee.layout.equals(Pack200.Packer.PASS)) {
+ Utils.log.info(ee.toString());
+ Utils.log.warning(message + " unrecognized attribute: " +
+ fname);
+ return null;
+ }
+ } else if (ioe instanceof ClassReader.ClassFormatException) {
+ ClassReader.ClassFormatException ce = (ClassReader.ClassFormatException) ioe;
+ // %% TODO: Do we invent a new property for this or reuse %%
+ if (unknownAttrCommand.equals(Pack200.Packer.PASS)) {
+ Utils.log.info(ce.toString());
+ Utils.log.warning(message + " unknown class format: " +
+ fname);
+ return null;
+ }
}
// Otherwise, it must be an error.
- throw ee;
+ throw ioe;
}
pkg.addClass(cls);
return cls.file;
diff --git a/src/share/classes/com/sun/java/util/jar/pack/Utils.java b/src/share/classes/com/sun/java/util/jar/pack/Utils.java
index 2dc47c414642bf4f32a4323f8ba30d8a97a1c7bb..84f65ac2ccfcbbbc769f769e95b43eeef2c6b8da 100644
--- a/src/share/classes/com/sun/java/util/jar/pack/Utils.java
+++ b/src/share/classes/com/sun/java/util/jar/pack/Utils.java
@@ -182,11 +182,8 @@ class Utils {
}
public void warning(String msg, Object param) {
- int verbose = currentPropMap().getInteger(DEBUG_VERBOSE);
- if (verbose > 0) {
getLogger().warning(msg, param);
}
- }
public void warning(String msg) {
warning(msg, null);
@@ -216,7 +213,9 @@ class Utils {
// Returns the Max Version String of this implementation
static String getVersionString() {
- return "Pack200, Vendor: Sun Microsystems, Version: " +
+ return "Pack200, Vendor: " +
+ System.getProperty("java.vendor") +
+ ", Version: " +
Constants.JAVA6_PACKAGE_MAJOR_VERSION + "." +
Constants.JAVA6_PACKAGE_MINOR_VERSION;
}
diff --git a/src/share/classes/com/sun/jndi/dns/DnsContextFactory.java b/src/share/classes/com/sun/jndi/dns/DnsContextFactory.java
index c006ebdb5b95743510edd86d6556ae1109c3b26d..2ce289e7d4dee431d938244bc3f67d66db573bcb 100644
--- a/src/share/classes/com/sun/jndi/dns/DnsContextFactory.java
+++ b/src/share/classes/com/sun/jndi/dns/DnsContextFactory.java
@@ -54,6 +54,7 @@ import sun.net.dns.ResolverConfiguration; // available since 1.4.1
public class DnsContextFactory implements InitialContextFactory {
private static final String DEFAULT_URL = "dns:";
+ private static final int DEFAULT_PORT = 53;
public Context getInitialContext(Hashtable,?> env) throws NamingException {
@@ -89,7 +90,9 @@ public class DnsContextFactory implements InitialContextFactory {
* Public for use by product test suite.
*/
public static boolean platformServersAvailable() {
- return !ResolverConfiguration.open().nameservers().isEmpty();
+ return !filterNameServers(
+ ResolverConfiguration.open().nameservers(), true
+ ).isEmpty();
}
private static Context urlToContext(String url, Hashtable env)
@@ -142,8 +145,8 @@ public class DnsContextFactory implements InitialContextFactory {
// No server or port given, so look to underlying platform.
// ResolverConfiguration does some limited caching, so the
// following is reasonably efficient even if called rapid-fire.
- List
+ * In environments in which the delegation model is not strictly
+ * hierarchical, class loaders need to be parallel capable, otherwise class
* loading can lead to deadlocks because the loader lock is held for the
* duration of the class loading process (see {@link #loadClass
* loadClass} methods).
@@ -1218,14 +1221,14 @@ public abstract class ClassLoader {
private static native Class extends ClassLoader> getCaller(int index);
/**
- * Registers the caller class loader as parallel capable.
- * In order for the registration to succeed, all super classes
- * of the caller class loader must also be registered as
- * parallel capable when this method is called.
LinkageError indicate that a class has
+ * Subclasses of {@code LinkageError} indicate that a class has
* some dependency on another class; however, the latter class has
* incompatibly changed after the compilation of the former class.
*
@@ -39,14 +39,14 @@ class LinkageError extends Error {
private static final long serialVersionUID = 3579600108157160122L;
/**
- * Constructs a LinkageError with no detail message.
+ * Constructs a {@code LinkageError} with no detail message.
*/
public LinkageError() {
super();
}
/**
- * Constructs a LinkageError with the specified detail
+ * Constructs a {@code LinkageError} with the specified detail
* message.
*
* @param s the detail message.
@@ -54,4 +54,16 @@ class LinkageError extends Error {
public LinkageError(String s) {
super(s);
}
+
+ /**
+ * Constructs a {@code LinkageError} with the specified detail
+ * message and cause.
+ *
+ * @param s the detail message.
+ * @param cause the cause, may be {@code null}
+ * @since 1.7
+ */
+ public LinkageError(String s, Throwable cause) {
+ super(s, cause);
+ }
}
diff --git a/src/share/classes/java/lang/System.java b/src/share/classes/java/lang/System.java
index 42431865f255584552b584efcff567bd5b851616..6df4af6950507ad1597bc839a3e19f858f1e778f 100644
--- a/src/share/classes/java/lang/System.java
+++ b/src/share/classes/java/lang/System.java
@@ -53,7 +53,13 @@ import sun.reflect.annotation.AnnotationType;
*/
public final class System {
- /* First thing---register the natives */
+ /* register the natives via the static initializer.
+ *
+ * VM will invoke the initializeSystemClass method to complete
+ * the initialization for this class separated from clinit.
+ * Note that to use properties set by the VM, see the constraints
+ * described in the initializeSystemClass method.
+ */
private static native void registerNatives();
static {
registerNatives();
@@ -1096,17 +1102,21 @@ public final class System {
* Initialize the system class. Called after thread initialization.
*/
private static void initializeSystemClass() {
- props = new Properties();
- initProperties(props);
+ // There are certain system configurations that may be controlled by
+ // VM options such as the maximum amount of direct memory and
+ // Integer cache size used to support the object identity semantics
+ // of autoboxing. Typically, the library will obtain these values
+ // from the properties set by the VM. If the properties are for
+ // internal implementation use only, these properties should be
+ // removed from the system properties.
+ //
+ // See java.lang.Integer.IntegerCache and the
+ // sun.misc.VM.saveAndRemoveProperties method for example.
+ props = initSystemProperties();
+
lineSeparator = props.getProperty("line.separator");
sun.misc.Version.init();
- // Gets and removes system properties that configure the Integer
- // cache used to support the object identity semantics of autoboxing.
- // At this time, the size of the cache may be controlled by the
- // vm option -XX:AutoBoxCacheMax=checkConnect
* method is called for each InetAddress. Only InetAddresses where
* the checkConnect doesn't throw a SecurityException
- * will be returned in the Enumeration.
+ * will be returned in the Enumeration. However, if the caller has the
+ * {@link NetPermission}("getNetworkInformation") permission, then all
+ * InetAddresses are returned.
* @return an Enumeration object with all or a subset of the InetAddresses
* bound to this network interface
*/
@@ -99,11 +101,19 @@ public final class NetworkInterface {
checkedAddresses() {
local_addrs = new InetAddress[addrs.length];
+ boolean trusted = true;
SecurityManager sec = System.getSecurityManager();
+ if (sec != null) {
+ try {
+ sec.checkPermission(new NetPermission("getNetworkInformation"));
+ } catch (SecurityException e) {
+ trusted = false;
+ }
+ }
for (int j=0; jnull if
- * the address doesn't exist or is not accessible.
* @exception SocketException if an I/O error occurs.
* @since 1.6
*/
public byte[] getHardwareAddress() throws SocketException {
+ SecurityManager sec = System.getSecurityManager();
+ if (sec != null) {
+ try {
+ sec.checkPermission(new NetPermission("getNetworkInformation"));
+ } catch (SecurityException e) {
+ if (!getInetAddresses().hasMoreElements()) {
+ // don't have connect permission to any local address
+ return null;
+ }
+ }
+ }
for (InetAddress addr : addrs) {
if (addr instanceof Inet4Address) {
return getMacAddr0(((Inet4Address)addr).getAddress(), name, index);
@@ -523,11 +549,10 @@ public final class NetworkInterface {
}
public int hashCode() {
- int count = 0;
- if (addrs != null) {
- for (int i = 0; i < addrs.length; i++) {
- count += addrs[i].hashCode();
- }
+ int count = name == null? 0: name.hashCode();
+ EnumerationX500Principal that represents the name of the
+ * authority that signed the certificate's revocation status information
*/
private final X500Principal authority;
@@ -79,8 +79,9 @@ public class CertificateRevokedException extends CertificateException {
* @param extensions a map of X.509 Extensions. Each key is an OID String
* that maps to the corresponding Extension. The map is copied to
* prevent subsequent modification.
- * @param authority the name of the authority that signed the certificate's
- * revocation status information
+ * @param authority the X500Principal that represents the name
+ * of the authority that signed the certificate's revocation status
+ * information
* @throws NullPointerException if revocationDate,
* reason, authority, or
* extensions is null
@@ -121,8 +122,8 @@ public class CertificateRevokedException extends CertificateException {
* Returns the name of the authority that signed the certificate's
* revocation status information.
*
- * @return the name of the authority that signed the certificate's
- * revocation status information
+ * @return the X500Principal that represents the name of the
+ * authority that signed the certificate's revocation status information
*/
public X500Principal getAuthorityName() {
return authority;
diff --git a/src/share/classes/java/util/Arrays.java b/src/share/classes/java/util/Arrays.java
index 54abbb27c8dacd15f3913c737b3f1358a5413e4e..b4951e14f111d41d2d3bc0d114ae3d62c59a2acf 100644
--- a/src/share/classes/java/util/Arrays.java
+++ b/src/share/classes/java/util/Arrays.java
@@ -97,7 +97,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(int[] a, int fromIndex, int toIndex) {
- DualPivotQuicksort.sort(a, fromIndex, toIndex);
+ rangeCheck(a.length, fromIndex, toIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
@@ -136,7 +137,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(long[] a, int fromIndex, int toIndex) {
- DualPivotQuicksort.sort(a, fromIndex, toIndex);
+ rangeCheck(a.length, fromIndex, toIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
@@ -175,7 +177,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(short[] a, int fromIndex, int toIndex) {
- DualPivotQuicksort.sort(a, fromIndex, toIndex);
+ rangeCheck(a.length, fromIndex, toIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
@@ -214,7 +217,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(char[] a, int fromIndex, int toIndex) {
- DualPivotQuicksort.sort(a, fromIndex, toIndex);
+ rangeCheck(a.length, fromIndex, toIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
@@ -253,7 +257,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(byte[] a, int fromIndex, int toIndex) {
- DualPivotQuicksort.sort(a, fromIndex, toIndex);
+ rangeCheck(a.length, fromIndex, toIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
@@ -308,7 +313,8 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(float[] a, int fromIndex, int toIndex) {
- DualPivotQuicksort.sort(a, fromIndex, toIndex);
+ rangeCheck(a.length, fromIndex, toIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/**
@@ -363,12 +369,12 @@ public class Arrays {
* if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
public static void sort(double[] a, int fromIndex, int toIndex) {
- DualPivotQuicksort.sort(a, fromIndex, toIndex);
+ rangeCheck(a.length, fromIndex, toIndex);
+ DualPivotQuicksort.sort(a, fromIndex, toIndex - 1);
}
/*
* Sorting of complex type arrays.
- *
*/
/**
diff --git a/src/share/classes/java/util/DualPivotQuicksort.java b/src/share/classes/java/util/DualPivotQuicksort.java
index 873230a2c7394533f9b27775f25e36ef0b01b981..616ee2e2fe2ae30a877bfc7b9c377f316f90c780 100644
--- a/src/share/classes/java/util/DualPivotQuicksort.java
+++ b/src/share/classes/java/util/DualPivotQuicksort.java
@@ -36,7 +36,7 @@ package java.util;
* @author Jon Bentley
* @author Josh Bloch
*
- * @version 2010.06.21 m765.827.12i:5\7
+ * @version 2010.10.13 m765.827.12i:5\7p
* @since 1.7
*/
final class DualPivotQuicksort {
@@ -54,26 +54,26 @@ final class DualPivotQuicksort {
* 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;
+ private static final int INSERTION_SORT_THRESHOLD = 47;
/**
- * If the length of a byte array to be sorted is greater than
- * this constant, counting sort is used in preference to Quicksort.
+ * If the length of a byte array to be sorted is greater than this
+ * constant, counting sort is used in preference to insertion sort.
*/
- private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 128;
+ private static final int COUNTING_SORT_THRESHOLD_FOR_BYTE = 29;
/**
* 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;
+ private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 3200;
/*
* Sorting methods for seven primitive types.
*/
/**
- * Sorts the specified array into ascending numerical order.
+ * Sorts the specified array.
*
* @param a the array to be sorted
*/
@@ -82,58 +82,34 @@ final class DualPivotQuicksort {
}
/**
- * Sorts the specified range of the array into ascending order. The range
- * to be sorted extends from the index {@code fromIndex}, inclusive, to
- * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
- * the range to be sorted is empty (and the call is a no-op).
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
- * @param fromIndex the index of the first element, inclusive, to be sorted
- * @param toIndex the index of the last element, exclusive, to be sorted
- * @throws IllegalArgumentException if {@code fromIndex > toIndex}
- * @throws ArrayIndexOutOfBoundsException
- * if {@code fromIndex < 0} or {@code toIndex > a.length}
+ * @param left the index of the first element, inclusive, to be sorted
+ * @param right the index of the last element, inclusive, to be sorted
*/
- public static void sort(int[] a, int fromIndex, int toIndex) {
- rangeCheck(a.length, fromIndex, toIndex);
- sort(a, fromIndex, toIndex - 1, true);
+ public static void sort(int[] a, int left, int right) {
+ sort(a, left, right, true);
}
/**
- * Sorts the specified range of the array into ascending order by the
- * Dual-Pivot Quicksort algorithm. This method differs from the public
- * {@code sort} method in that the {@code right} index is inclusive,
- * it does no range checking on {@code left} or {@code right}, and has
- * boolean flag whether insertion sort with sentinel is used or not.
+ * Sorts the specified range of the array by Dual-Pivot Quicksort.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if the part is the most left in the range
+ * @param leftmost indicates if this part is the leftmost in the range
*/
private static void sort(int[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
- // Use insertion sort on tiny arrays
+ // Use insertion sort on small arrays
if (length < INSERTION_SORT_THRESHOLD) {
- if (!leftmost) {
+ if (leftmost) {
/*
- * Every element in adjoining part plays the role
- * of sentinel, therefore this allows us to avoid
- * the j >= left check on each iteration.
- */
- for (int j, i = left + 1; i <= right; i++) {
- int ai = a[i];
- for (j = i - 1; ai < a[j]; j--) {
- // assert j >= left;
- a[j + 1] = a[j];
- }
- a[j + 1] = ai;
- }
- } else {
- /*
- * For case of leftmost part traditional (without a sentinel)
- * insertion sort, optimized for server JVM, is used.
+ * Traditional (without sentinel) insertion sort,
+ * optimized for server VM, is used in case of
+ * the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
int ai = a[i + 1];
@@ -145,12 +121,54 @@ final class DualPivotQuicksort {
}
a[j + 1] = ai;
}
+ } else {
+ /*
+ * Skip the longest ascending sequence.
+ */
+ do {
+ if (left++ >= right) {
+ return;
+ }
+ } while (a[left - 1] <= a[left]);
+
+ /*
+ * Every element from adjoining part plays the role
+ * of sentinel, therefore this allows us to avoid the
+ * left range check on each iteration. Moreover, we use
+ * the best improved algorithm, so called pair insertion
+ * sort, which is faster than traditional implementation
+ * in the context of Dual-Pivot Quicksort.
+ */
+ for (int k = left--; (left += 2) <= right; ) {
+ int a1, a2; k = left - 1;
+
+ if (a[k] < a[left]) {
+ a2 = a[k]; a1 = a[left];
+ } else {
+ a1 = a[k]; a2 = a[left];
+ }
+ while (a1 < a[--k]) {
+ a[k + 2] = a[k];
+ }
+ a[++k + 1] = a1;
+
+ while (a2 < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = a2;
+ }
+ int last = a[right];
+
+ while (last < a[--right]) {
+ a[right + 1] = a[right];
+ }
+ a[right + 1] = last;
}
return;
}
// Inexpensive approximation of length / 7
- int seventh = (length >>> 3) + (length >>> 6) + 1;
+ int seventh = (length >> 3) + (length >> 6) + 1;
/*
* Sort five evenly spaced elements around (and including) the
@@ -232,10 +250,14 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
int ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
+ /*
+ * Here and below we use "a[i] = b; i++;" instead
+ * of "a[i++] = b;" due to performance issue.
+ */
a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
@@ -244,13 +266,17 @@ final class DualPivotQuicksort {
break outer;
}
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
}
+ /*
+ * Here and below we use "a[i] = b; i--;" instead
+ * of "a[i--] = b;" due to performance issue.
+ */
a[great] = ak;
great--;
}
@@ -265,7 +291,7 @@ final class DualPivotQuicksort {
sort(a, great + 2, right, false);
/*
- * If center part is too large (comprises > 5/7 of the array),
+ * If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends.
*/
if (less < e1 && e5 < great) {
@@ -299,7 +325,7 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
+ for (int k = less - 1; ++k <= great; ) {
int ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
@@ -311,7 +337,7 @@ final class DualPivotQuicksort {
break outer;
}
}
- if (a[great] == pivot1) {
+ if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
@@ -337,7 +363,7 @@ final class DualPivotQuicksort {
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way
+ * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
@@ -356,28 +382,20 @@ final class DualPivotQuicksort {
*
* Pointer k is the first index of ?-part.
*/
- for (int k = left; k <= great; k++) {
+ for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) {
continue;
}
int ak = a[k];
-
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
less++;
} else { // a[k] > pivot1 - Move a[k] to right part
- /*
- * We know that pivot1 == a[e3] == pivot2. Thus, we know
- * that great will still be >= k when the following loop
- * terminates, even though we don't test for it explicitly.
- * In other words, a[e3] acts as a sentinel for great.
- */
while (a[great] > pivot1) {
- // assert great > k;
great--;
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less];
a[less] = a[great];
less++;
@@ -397,14 +415,18 @@ final class DualPivotQuicksort {
}
}
- // Sort left and right parts recursively
+ /*
+ * Sort left and right parts recursively.
+ * All elements from center part are equal
+ * and, therefore, already sorted.
+ */
sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false);
}
}
/**
- * Sorts the specified array into ascending numerical order.
+ * Sorts the specified array.
*
* @param a the array to be sorted
*/
@@ -413,58 +435,34 @@ final class DualPivotQuicksort {
}
/**
- * Sorts the specified range of the array into ascending order. The range
- * to be sorted extends from the index {@code fromIndex}, inclusive, to
- * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
- * the range to be sorted is empty (and the call is a no-op).
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
- * @param fromIndex the index of the first element, inclusive, to be sorted
- * @param toIndex the index of the last element, exclusive, to be sorted
- * @throws IllegalArgumentException if {@code fromIndex > toIndex}
- * @throws ArrayIndexOutOfBoundsException
- * if {@code fromIndex < 0} or {@code toIndex > a.length}
+ * @param left the index of the first element, inclusive, to be sorted
+ * @param right the index of the last element, inclusive, to be sorted
*/
- public static void sort(long[] a, int fromIndex, int toIndex) {
- rangeCheck(a.length, fromIndex, toIndex);
- sort(a, fromIndex, toIndex - 1, true);
+ public static void sort(long[] a, int left, int right) {
+ sort(a, left, right, true);
}
/**
- * Sorts the specified range of the array into ascending order by the
- * Dual-Pivot Quicksort algorithm. This method differs from the public
- * {@code sort} method in that the {@code right} index is inclusive,
- * it does no range checking on {@code left} or {@code right}, and has
- * boolean flag whether insertion sort with sentinel is used or not.
+ * Sorts the specified range of the array by Dual-Pivot Quicksort.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if the part is the most left in the range
+ * @param leftmost indicates if this part is the leftmost in the range
*/
private static void sort(long[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
- // Use insertion sort on tiny arrays
+ // Use insertion sort on small arrays
if (length < INSERTION_SORT_THRESHOLD) {
- if (!leftmost) {
- /*
- * Every element in adjoining part plays the role
- * of sentinel, therefore this allows us to avoid
- * the j >= left check on each iteration.
- */
- for (int j, i = left + 1; i <= right; i++) {
- long ai = a[i];
- for (j = i - 1; ai < a[j]; j--) {
- // assert j >= left;
- a[j + 1] = a[j];
- }
- a[j + 1] = ai;
- }
- } else {
+ if (leftmost) {
/*
- * For case of leftmost part traditional (without a sentinel)
- * insertion sort, optimized for server JVM, is used.
+ * Traditional (without sentinel) insertion sort,
+ * optimized for server VM, is used in case of
+ * the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
long ai = a[i + 1];
@@ -476,381 +474,54 @@ final class DualPivotQuicksort {
}
a[j + 1] = ai;
}
- }
- return;
- }
-
- // Inexpensive approximation of length / 7
- int seventh = (length >>> 3) + (length >>> 6) + 1;
-
- /*
- * Sort five evenly spaced elements around (and including) the
- * center element in the range. These elements will be used for
- * pivot selection as described below. The choice for spacing
- * these elements was empirically determined to work well on
- * a wide variety of inputs.
- */
- int e3 = (left + right) >>> 1; // The midpoint
- int e2 = e3 - seventh;
- int e1 = e2 - seventh;
- int e4 = e3 + seventh;
- int e5 = e4 + seventh;
-
- // Sort these elements using insertion sort
- if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
-
- if (a[e3] < a[e2]) { long t = a[e3]; a[e3] = a[e2]; a[e2] = t;
- if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
- }
- if (a[e4] < a[e3]) { long t = a[e4]; a[e4] = a[e3]; a[e3] = t;
- if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
- if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
- }
- }
- if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t;
- if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
- if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
- if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
- }
- }
- }
-
- /*
- * 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.
- */
- long pivot1 = a[e2];
- long pivot2 = a[e4];
-
- // Pointers
- int less = left; // The index of the first element of center part
- int great = right; // The index before the first element of right part
-
- if (pivot1 != pivot2) {
- /*
- * The first and the last elements to be sorted are moved to the
- * locations formerly occupied by the pivots. When partitioning
- * is complete, the pivots are swapped back into their final
- * positions, and excluded from subsequent sorting.
- */
- a[e2] = a[left];
- a[e4] = a[right];
-
- /*
- * Skip elements, which are less or greater than pivot values.
- */
- while (a[++less] < pivot1);
- while (a[--great] > pivot2);
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +--------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +--------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (left, less) < pivot1
- * pivot1 <= all in [less, k) <= pivot2
- * all in (great, right) > pivot2
- *
- * Pointer k is the first index of ?-part.
- */
- outer:
- for (int k = less; k <= great; k++) {
- long ak = a[k];
- if (ak < pivot1) { // Move a[k] to left part
- a[k] = a[less];
- a[less] = ak;
- less++;
- } else if (ak > pivot2) { // Move a[k] to right part
- while (a[great] > pivot2) {
- if (great-- == k) {
- break outer;
- }
- }
- if (a[great] < pivot1) {
- a[k] = a[less];
- a[less] = a[great];
- less++;
- } else { // pivot1 <= a[great] <= pivot2
- a[k] = a[great];
- }
- a[great] = ak;
- great--;
- }
- }
-
- // Swap pivots into their final positions
- a[left] = a[less - 1]; a[less - 1] = pivot1;
- a[right] = a[great + 1]; a[great + 1] = pivot2;
-
- // Sort left and right parts recursively, excluding known pivots
- sort(a, left, less - 2, leftmost);
- sort(a, great + 2, right, false);
-
- /*
- * If center part is too large (comprises > 5/7 of the array),
- * swap internal pivot values to ends.
- */
- if (less < e1 && e5 < great) {
+ } else {
/*
- * Skip elements, which are equal to pivot values.
+ * Skip the longest ascending sequence.
*/
- while (a[less] == pivot1) {
- less++;
- }
- while (a[great] == pivot2) {
- great--;
- }
+ do {
+ if (left++ >= right) {
+ return;
+ }
+ } while (a[left - 1] <= a[left]);
/*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part.
+ * Every element from adjoining part plays the role
+ * of sentinel, therefore this allows us to avoid the
+ * left range check on each iteration. Moreover, we use
+ * the best improved algorithm, so called pair insertion
+ * sort, which is faster than traditional implementation
+ * in the context of Dual-Pivot Quicksort.
*/
- outer:
- for (int k = less; k <= great; k++) {
- long ak = a[k];
- if (ak == pivot1) { // Move a[k] to left part
- a[k] = a[less];
- a[less] = ak;
- less++;
- } else if (ak == pivot2) { // Move a[k] to right part
- while (a[great] == pivot2) {
- if (great-- == k) {
- break outer;
- }
- }
- if (a[great] == pivot1) {
- a[k] = a[less];
- /*
- * Even though a[great] equals to pivot1, the
- * assignment a[less] = pivot1 may be incorrect,
- * if a[great] and pivot1 are floating-point zeros
- * of different signs. Therefore in float and
- * double sorting methods we have to use more
- * accurate assignment a[less] = a[great].
- */
- a[less] = pivot1;
- less++;
- } else { // pivot1 < a[great] < pivot2
- a[k] = a[great];
- }
- a[great] = ak;
- great--;
- }
- }
- }
+ for (int k = left--; (left += 2) <= right; ) {
+ long a1, a2; k = left - 1;
- // Sort center part recursively
- sort(a, less, great, false);
-
- } else { // Pivots are equal
- /*
- * Partition degenerates to the traditional 3-way
- * (or "Dutch National Flag") schema:
- *
- * left part center part right part
- * +-------------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +-------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (left, less) < pivot
- * all in [less, k) == pivot
- * all in (great, right) > pivot
- *
- * Pointer k is the first index of ?-part.
- */
- for (int k = left; k <= great; k++) {
- if (a[k] == pivot1) {
- continue;
- }
- long ak = a[k];
-
- if (ak < pivot1) { // Move a[k] to left part
- a[k] = a[less];
- a[less] = ak;
- less++;
- } else { // a[k] > pivot1 - Move a[k] to right part
- /*
- * We know that pivot1 == a[e3] == pivot2. Thus, we know
- * that great will still be >= k when the following loop
- * terminates, even though we don't test for it explicitly.
- * In other words, a[e3] acts as a sentinel for great.
- */
- while (a[great] > pivot1) {
- // assert great > k;
- great--;
+ if (a[k] < a[left]) {
+ a2 = a[k]; a1 = a[left];
+ } else {
+ a1 = a[k]; a2 = a[left];
}
- if (a[great] < pivot1) {
- a[k] = a[less];
- a[less] = a[great];
- less++;
- } else { // a[great] == pivot1
- /*
- * Even though a[great] equals to pivot1, the
- * assignment a[k] = pivot1 may be incorrect,
- * if a[great] and pivot1 are floating-point
- * zeros of different signs. Therefore in float
- * and double sorting methods we have to use
- * more accurate assignment a[k] = a[great].
- */
- a[k] = pivot1;
+ while (a1 < a[--k]) {
+ a[k + 2] = a[k];
}
- a[great] = ak;
- great--;
- }
- }
-
- // Sort left and right parts recursively
- sort(a, left, less - 1, leftmost);
- sort(a, great + 1, right, false);
- }
- }
+ a[++k + 1] = a1;
- /**
- * Sorts the specified array into ascending numerical order.
- *
- * @param a the array to be sorted
- */
- public static void sort(short[] a) {
- if (a.length > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
- countingSort(a, 0, a.length - 1);
- } else {
- sort(a, 0, a.length - 1, true);
- }
- }
-
- /**
- * Sorts the specified range of the array into ascending order. The range
- * to be sorted extends from the index {@code fromIndex}, inclusive, to
- * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
- * the range to be sorted is empty (and the call is a no-op).
- *
- * @param a the array to be sorted
- * @param fromIndex the index of the first element, inclusive, to be sorted
- * @param toIndex the index of the last element, exclusive, to be sorted
- * @throws IllegalArgumentException if {@code fromIndex > toIndex}
- * @throws ArrayIndexOutOfBoundsException
- * if {@code fromIndex < 0} or {@code toIndex > a.length}
- */
- public static void sort(short[] a, int fromIndex, int toIndex) {
- rangeCheck(a.length, fromIndex, toIndex);
-
- if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
- countingSort(a, fromIndex, toIndex - 1);
- } else {
- sort(a, fromIndex, toIndex - 1, true);
- }
- }
-
- /** The number of distinct short values. */
- private static final int NUM_SHORT_VALUES = 1 << 16;
-
- /**
- * Sorts the specified range of the array by counting sort.
- *
- * @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- */
- private static void countingSort(short[] a, int left, int right) {
- int[] count = new int[NUM_SHORT_VALUES];
-
- for (int i = left; i <= right; i++) {
- count[a[i] - Short.MIN_VALUE]++;
- }
- for (int i = NUM_SHORT_VALUES - 1, k = right; k >= left; i--) {
- while (count[i] == 0) {
- i--;
- }
- short value = (short) (i + Short.MIN_VALUE);
- int s = count[i];
-
- do {
- a[k--] = value;
- } while (--s > 0);
- }
- }
-
- /**
- * Sorts the specified range of the array into ascending order by the
- * Dual-Pivot Quicksort algorithm. This method differs from the public
- * {@code sort} method in that the {@code right} index is inclusive,
- * it does no range checking on {@code left} or {@code right}, and has
- * boolean flag whether insertion sort with sentinel is used or not.
- *
- * @param a the array to be sorted
- * @param left the index of the first element, inclusive, to be sorted
- * @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if the part is the most left in the range
- */
- private static void sort(short[] a, int left, int right,boolean leftmost) {
- int length = right - left + 1;
-
- // Use insertion sort on tiny arrays
- if (length < INSERTION_SORT_THRESHOLD) {
- if (!leftmost) {
- /*
- * Every element in adjoining part plays the role
- * of sentinel, therefore this allows us to avoid
- * the j >= left check on each iteration.
- */
- for (int j, i = left + 1; i <= right; i++) {
- short ai = a[i];
- for (j = i - 1; ai < a[j]; j--) {
- // assert j >= left;
- a[j + 1] = a[j];
+ while (a2 < a[--k]) {
+ a[k + 1] = a[k];
}
- a[j + 1] = ai;
+ a[k + 1] = a2;
}
- } else {
- /*
- * For case of leftmost part traditional (without a sentinel)
- * insertion sort, optimized for server JVM, is used.
- */
- for (int i = left, j = i; i < right; j = ++i) {
- short ai = a[i + 1];
- while (ai < a[j]) {
- a[j + 1] = a[j];
- if (j-- == left) {
- break;
- }
- }
- a[j + 1] = ai;
+ long last = a[right];
+
+ while (last < a[--right]) {
+ a[right + 1] = a[right];
}
+ a[right + 1] = last;
}
return;
}
// Inexpensive approximation of length / 7
- int seventh = (length >>> 3) + (length >>> 6) + 1;
+ int seventh = (length >> 3) + (length >> 6) + 1;
/*
* Sort five evenly spaced elements around (and including) the
@@ -866,17 +537,17 @@ final class DualPivotQuicksort {
int e5 = e4 + seventh;
// Sort these elements using insertion sort
- if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+ if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
- if (a[e3] < a[e2]) { short t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+ if (a[e3] < a[e2]) { long t = a[e3]; a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
}
- if (a[e4] < a[e3]) { short t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+ if (a[e4] < a[e3]) { long t = a[e4]; a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
}
}
- if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+ if (a[e5] < a[e4]) { long t = a[e5]; a[e5] = a[e4]; a[e4] = t;
if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
@@ -889,8 +560,8 @@ final class DualPivotQuicksort {
* These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2.
*/
- short pivot1 = a[e2];
- short pivot2 = a[e4];
+ long pivot1 = a[e2];
+ long pivot2 = a[e4];
// Pointers
int less = left; // The index of the first element of center part
@@ -932,10 +603,14 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
- short ak = a[k];
+ for (int k = less - 1; ++k <= great; ) {
+ long ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
+ /*
+ * Here and below we use "a[i] = b; i++;" instead
+ * of "a[i++] = b;" due to performance issue.
+ */
a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
@@ -944,13 +619,17 @@ final class DualPivotQuicksort {
break outer;
}
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
}
+ /*
+ * Here and below we use "a[i] = b; i--;" instead
+ * of "a[i--] = b;" due to performance issue.
+ */
a[great] = ak;
great--;
}
@@ -965,7 +644,7 @@ final class DualPivotQuicksort {
sort(a, great + 2, right, false);
/*
- * If center part is too large (comprises > 5/7 of the array),
+ * If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends.
*/
if (less < e1 && e5 < great) {
@@ -999,8 +678,8 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
- short ak = a[k];
+ for (int k = less - 1; ++k <= great; ) {
+ long ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
@@ -1011,7 +690,7 @@ final class DualPivotQuicksort {
break outer;
}
}
- if (a[great] == pivot1) {
+ if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
@@ -1037,7 +716,7 @@ final class DualPivotQuicksort {
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way
+ * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
@@ -1056,28 +735,20 @@ final class DualPivotQuicksort {
*
* Pointer k is the first index of ?-part.
*/
- for (int k = left; k <= great; k++) {
+ for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) {
continue;
}
- short ak = a[k];
-
+ long ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
less++;
} else { // a[k] > pivot1 - Move a[k] to right part
- /*
- * We know that pivot1 == a[e3] == pivot2. Thus, we know
- * that great will still be >= k when the following loop
- * terminates, even though we don't test for it explicitly.
- * In other words, a[e3] acts as a sentinel for great.
- */
while (a[great] > pivot1) {
- // assert great > k;
great--;
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less];
a[less] = a[great];
less++;
@@ -1097,115 +768,78 @@ final class DualPivotQuicksort {
}
}
- // Sort left and right parts recursively
+ /*
+ * Sort left and right parts recursively.
+ * All elements from center part are equal
+ * and, therefore, already sorted.
+ */
sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false);
}
}
/**
- * Sorts the specified array into ascending numerical order.
- *
- * @param a the array to be sorted
- */
- public static void sort(char[] a) {
- if (a.length > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
- countingSort(a, 0, a.length - 1);
- } else {
- sort(a, 0, a.length - 1, true);
- }
- }
-
- /**
- * Sorts the specified range of the array into ascending order. The range
- * to be sorted extends from the index {@code fromIndex}, inclusive, to
- * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
- * the range to be sorted is empty (and the call is a no-op).
+ * Sorts the specified array.
*
* @param a the array to be sorted
- * @param fromIndex the index of the first element, inclusive, to be sorted
- * @param toIndex the index of the last element, exclusive, to be sorted
- * @throws IllegalArgumentException if {@code fromIndex > toIndex}
- * @throws ArrayIndexOutOfBoundsException
- * if {@code fromIndex < 0} or {@code toIndex > a.length}
*/
- public static void sort(char[] a, int fromIndex, int toIndex) {
- rangeCheck(a.length, fromIndex, toIndex);
-
- if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
- countingSort(a, fromIndex, toIndex - 1);
- } else {
- sort(a, fromIndex, toIndex - 1, true);
- }
+ public static void sort(short[] a) {
+ sort(a, 0, a.length - 1);
}
- /** The number of distinct char values. */
- private static final int NUM_CHAR_VALUES = 1 << 16;
-
/**
- * Sorts the specified range of the array by counting sort.
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
*/
- private static void countingSort(char[] a, int left, int right) {
- int[] count = new int[NUM_CHAR_VALUES];
+ public static void sort(short[] a, int left, int right) {
+ // Use counting sort on large arrays
+ if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+ int[] count = new int[NUM_SHORT_VALUES];
- for (int i = left; i <= right; i++) {
- count[a[i]]++;
- }
- for (int i = 0, k = left; k <= right; i++) {
- while (count[i] == 0) {
- i++;
+ for (int i = left - 1; ++i <= right; ) {
+ count[a[i] - Short.MIN_VALUE]++;
}
- char value = (char) i;
- int s = count[i];
-
- do {
- a[k++] = value;
- } while (--s > 0);
+ for (int i = NUM_SHORT_VALUES, k = right + 1; k > left; ) {
+ while (count[--i] == 0);
+ short value = (short) (i + Short.MIN_VALUE);
+ int s = count[i];
+
+ do {
+ a[--k] = value;
+ } while (--s > 0);
+ }
+ } else { // Use Dual-Pivot Quicksort on small arrays
+ sort(a, left, right, true);
}
}
+ /** 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 by the
- * Dual-Pivot Quicksort algorithm. This method differs from the public
- * {@code sort} method in that the {@code right} index is inclusive,
- * it does no range checking on {@code left} or {@code right}, and has
- * boolean flag whether insertion sort with sentinel is used or not.
+ * Sorts the specified range of the array by Dual-Pivot Quicksort.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if the part is the most left in the range
+ * @param leftmost indicates if this part is the leftmost in the range
*/
- private static void sort(char[] a, int left, int right, boolean leftmost) {
+ private static void sort(short[] a, int left, int right,boolean leftmost) {
int length = right - left + 1;
- // Use insertion sort on tiny arrays
+ // Use insertion sort on small arrays
if (length < INSERTION_SORT_THRESHOLD) {
- if (!leftmost) {
- /*
- * Every element in adjoining part plays the role
- * of sentinel, therefore this allows us to avoid
- * the j >= left check on each iteration.
- */
- for (int j, i = left + 1; i <= right; i++) {
- char ai = a[i];
- for (j = i - 1; ai < a[j]; j--) {
- // assert j >= left;
- a[j + 1] = a[j];
- }
- a[j + 1] = ai;
- }
- } else {
+ if (leftmost) {
/*
- * For case of leftmost part traditional (without a sentinel)
- * insertion sort, optimized for server JVM, is used.
+ * Traditional (without sentinel) insertion sort,
+ * optimized for server VM, is used in case of
+ * the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
- char ai = a[i + 1];
+ short ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
if (j-- == left) {
@@ -1214,12 +848,54 @@ final class DualPivotQuicksort {
}
a[j + 1] = ai;
}
+ } else {
+ /*
+ * Skip the longest ascending sequence.
+ */
+ do {
+ if (left++ >= right) {
+ return;
+ }
+ } while (a[left - 1] <= a[left]);
+
+ /*
+ * Every element from adjoining part plays the role
+ * of sentinel, therefore this allows us to avoid the
+ * left range check on each iteration. Moreover, we use
+ * the best improved algorithm, so called pair insertion
+ * sort, which is faster than traditional implementation
+ * in the context of Dual-Pivot Quicksort.
+ */
+ for (int k = left--; (left += 2) <= right; ) {
+ short a1, a2; k = left - 1;
+
+ if (a[k] < a[left]) {
+ a2 = a[k]; a1 = a[left];
+ } else {
+ a1 = a[k]; a2 = a[left];
+ }
+ while (a1 < a[--k]) {
+ a[k + 2] = a[k];
+ }
+ a[++k + 1] = a1;
+
+ while (a2 < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = a2;
+ }
+ short last = a[right];
+
+ while (last < a[--right]) {
+ a[right + 1] = a[right];
+ }
+ a[right + 1] = last;
}
return;
}
// Inexpensive approximation of length / 7
- int seventh = (length >>> 3) + (length >>> 6) + 1;
+ int seventh = (length >> 3) + (length >> 6) + 1;
/*
* Sort five evenly spaced elements around (and including) the
@@ -1235,17 +911,17 @@ final class DualPivotQuicksort {
int e5 = e4 + seventh;
// Sort these elements using insertion sort
- if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+ if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
- if (a[e3] < a[e2]) { char t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+ if (a[e3] < a[e2]) { short t = a[e3]; a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
}
- if (a[e4] < a[e3]) { char t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+ if (a[e4] < a[e3]) { short t = a[e4]; a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
}
}
- if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+ if (a[e5] < a[e4]) { short t = a[e5]; a[e5] = a[e4]; a[e4] = t;
if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
@@ -1258,8 +934,8 @@ final class DualPivotQuicksort {
* These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2.
*/
- char pivot1 = a[e2];
- char pivot2 = a[e4];
+ short pivot1 = a[e2];
+ short pivot2 = a[e4];
// Pointers
int less = left; // The index of the first element of center part
@@ -1301,10 +977,14 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
- char ak = a[k];
+ for (int k = less - 1; ++k <= great; ) {
+ short ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
+ /*
+ * Here and below we use "a[i] = b; i++;" instead
+ * of "a[i++] = b;" due to performance issue.
+ */
a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
@@ -1313,13 +993,17 @@ final class DualPivotQuicksort {
break outer;
}
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
}
+ /*
+ * Here and below we use "a[i] = b; i--;" instead
+ * of "a[i--] = b;" due to performance issue.
+ */
a[great] = ak;
great--;
}
@@ -1334,7 +1018,7 @@ final class DualPivotQuicksort {
sort(a, great + 2, right, false);
/*
- * If center part is too large (comprises > 5/7 of the array),
+ * If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends.
*/
if (less < e1 && e5 < great) {
@@ -1368,8 +1052,8 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
- char ak = a[k];
+ for (int k = less - 1; ++k <= great; ) {
+ short ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
@@ -1380,7 +1064,7 @@ final class DualPivotQuicksort {
break outer;
}
}
- if (a[great] == pivot1) {
+ if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
@@ -1406,7 +1090,7 @@ final class DualPivotQuicksort {
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way
+ * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
@@ -1425,28 +1109,20 @@ final class DualPivotQuicksort {
*
* Pointer k is the first index of ?-part.
*/
- for (int k = left; k <= great; k++) {
+ for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) {
continue;
}
- char ak = a[k];
-
+ short ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
less++;
} else { // a[k] > pivot1 - Move a[k] to right part
- /*
- * We know that pivot1 == a[e3] == pivot2. Thus, we know
- * that great will still be >= k when the following loop
- * terminates, even though we don't test for it explicitly.
- * In other words, a[e3] acts as a sentinel for great.
- */
while (a[great] > pivot1) {
- // assert great > k;
great--;
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less];
a[less] = a[great];
less++;
@@ -1466,115 +1142,78 @@ final class DualPivotQuicksort {
}
}
- // Sort left and right parts recursively
+ /*
+ * Sort left and right parts recursively.
+ * All elements from center part are equal
+ * and, therefore, already sorted.
+ */
sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false);
}
}
/**
- * Sorts the specified array into ascending numerical order.
+ * Sorts the specified array.
*
* @param a the array to be sorted
*/
- public static void sort(byte[] a) {
- if (a.length > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
- countingSort(a, 0, a.length - 1);
- } else {
- sort(a, 0, a.length - 1, true);
- }
- }
-
- /**
- * Sorts the specified range of the array into ascending order. The range
- * to be sorted extends from the index {@code fromIndex}, inclusive, to
- * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex},
- * the range to be sorted is empty (and the call is a no-op).
- *
- * @param a the array to be sorted
- * @param fromIndex the index of the first element, inclusive, to be sorted
- * @param toIndex the index of the last element, exclusive, to be sorted
- * @throws IllegalArgumentException if {@code fromIndex > toIndex}
- * @throws ArrayIndexOutOfBoundsException
- * if {@code fromIndex < 0} or {@code toIndex > a.length}
- */
- public static void sort(byte[] a, int fromIndex, int toIndex) {
- rangeCheck(a.length, fromIndex, toIndex);
-
- if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
- countingSort(a, fromIndex, toIndex - 1);
- } else {
- sort(a, fromIndex, toIndex - 1, true);
- }
+ public static void sort(char[] a) {
+ sort(a, 0, a.length - 1);
}
- /** The number of distinct byte values. */
- private static final int NUM_BYTE_VALUES = 1 << 8;
-
/**
- * Sorts the specified range of the array by counting sort.
+ * Sorts the specified range of the array.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
*/
- private static void countingSort(byte[] a, int left, int right) {
- int[] count = new int[NUM_BYTE_VALUES];
+ public static void sort(char[] a, int left, int right) {
+ // Use counting sort on large arrays
+ if (right - left > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+ int[] count = new int[NUM_CHAR_VALUES];
- for (int i = left; i <= right; i++) {
- count[a[i] - Byte.MIN_VALUE]++;
- }
- for (int i = NUM_BYTE_VALUES - 1, k = right; k >= left; i--) {
- while (count[i] == 0) {
- i--;
+ for (int i = left - 1; ++i <= right; ) {
+ count[a[i]]++;
}
- byte value = (byte) (i + Byte.MIN_VALUE);
- int s = count[i];
-
- do {
- a[k--] = value;
- } while (--s > 0);
+ for (int i = NUM_CHAR_VALUES, k = right + 1; k > left; ) {
+ while (count[--i] == 0);
+ char value = (char) i;
+ int s = count[i];
+
+ do {
+ a[--k] = value;
+ } while (--s > 0);
+ }
+ } else { // Use Dual-Pivot Quicksort on small arrays
+ sort(a, left, right, true);
}
}
+ /** 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 by the
- * Dual-Pivot Quicksort algorithm. This method differs from the public
- * {@code sort} method in that the {@code right} index is inclusive,
- * it does no range checking on {@code left} or {@code right}, and has
- * boolean flag whether insertion sort with sentinel is used or not.
+ * Sorts the specified range of the array by Dual-Pivot Quicksort.
*
* @param a the array to be sorted
* @param left the index of the first element, inclusive, to be sorted
* @param right the index of the last element, inclusive, to be sorted
- * @param leftmost indicates if the part is the most left in the range
+ * @param leftmost indicates if this part is the leftmost in the range
*/
- private static void sort(byte[] a, int left, int right, boolean leftmost) {
+ private static void sort(char[] a, int left, int right, boolean leftmost) {
int length = right - left + 1;
- // Use insertion sort on tiny arrays
+ // Use insertion sort on small arrays
if (length < INSERTION_SORT_THRESHOLD) {
- if (!leftmost) {
- /*
- * Every element in adjoining part plays the role
- * of sentinel, therefore this allows us to avoid
- * the j >= left check on each iteration.
- */
- for (int j, i = left + 1; i <= right; i++) {
- byte ai = a[i];
- for (j = i - 1; ai < a[j]; j--) {
- // assert j >= left;
- a[j + 1] = a[j];
- }
- a[j + 1] = ai;
- }
- } else {
+ if (leftmost) {
/*
- * For case of leftmost part traditional (without a sentinel)
- * insertion sort, optimized for server JVM, is used.
+ * Traditional (without sentinel) insertion sort,
+ * optimized for server VM, is used in case of
+ * the leftmost part.
*/
for (int i = left, j = i; i < right; j = ++i) {
- byte ai = a[i + 1];
+ char ai = a[i + 1];
while (ai < a[j]) {
a[j + 1] = a[j];
if (j-- == left) {
@@ -1583,12 +1222,54 @@ final class DualPivotQuicksort {
}
a[j + 1] = ai;
}
+ } else {
+ /*
+ * Skip the longest ascending sequence.
+ */
+ do {
+ if (left++ >= right) {
+ return;
+ }
+ } while (a[left - 1] <= a[left]);
+
+ /*
+ * Every element from adjoining part plays the role
+ * of sentinel, therefore this allows us to avoid the
+ * left range check on each iteration. Moreover, we use
+ * the best improved algorithm, so called pair insertion
+ * sort, which is faster than traditional implementation
+ * in the context of Dual-Pivot Quicksort.
+ */
+ for (int k = left--; (left += 2) <= right; ) {
+ char a1, a2; k = left - 1;
+
+ if (a[k] < a[left]) {
+ a2 = a[k]; a1 = a[left];
+ } else {
+ a1 = a[k]; a2 = a[left];
+ }
+ while (a1 < a[--k]) {
+ a[k + 2] = a[k];
+ }
+ a[++k + 1] = a1;
+
+ while (a2 < a[--k]) {
+ a[k + 1] = a[k];
+ }
+ a[k + 1] = a2;
+ }
+ char last = a[right];
+
+ while (last < a[--right]) {
+ a[right + 1] = a[right];
+ }
+ a[right + 1] = last;
}
return;
}
// Inexpensive approximation of length / 7
- int seventh = (length >>> 3) + (length >>> 6) + 1;
+ int seventh = (length >> 3) + (length >> 6) + 1;
/*
* Sort five evenly spaced elements around (and including) the
@@ -1604,17 +1285,17 @@ final class DualPivotQuicksort {
int e5 = e4 + seventh;
// Sort these elements using insertion sort
- if (a[e2] < a[e1]) { byte t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
+ if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
- if (a[e3] < a[e2]) { byte t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+ if (a[e3] < a[e2]) { char t = a[e3]; a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
}
- if (a[e4] < a[e3]) { byte t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+ if (a[e4] < a[e3]) { char t = a[e4]; a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
}
}
- if (a[e5] < a[e4]) { byte t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+ if (a[e5] < a[e4]) { char t = a[e5]; a[e5] = a[e4]; a[e4] = t;
if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
@@ -1627,8 +1308,8 @@ final class DualPivotQuicksort {
* These values are inexpensive approximations of the first and
* second terciles of the array. Note that pivot1 <= pivot2.
*/
- byte pivot1 = a[e2];
- byte pivot2 = a[e4];
+ char pivot1 = a[e2];
+ char pivot2 = a[e4];
// Pointers
int less = left; // The index of the first element of center part
@@ -1670,10 +1351,14 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
- byte ak = a[k];
+ for (int k = less - 1; ++k <= great; ) {
+ char ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
+ /*
+ * Here and below we use "a[i] = b; i++;" instead
+ * of "a[i++] = b;" due to performance issue.
+ */
a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
@@ -1682,13 +1367,17 @@ final class DualPivotQuicksort {
break outer;
}
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot2
a[k] = a[less];
a[less] = a[great];
less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
}
+ /*
+ * Here and below we use "a[i] = b; i--;" instead
+ * of "a[i--] = b;" due to performance issue.
+ */
a[great] = ak;
great--;
}
@@ -1703,7 +1392,7 @@ final class DualPivotQuicksort {
sort(a, great + 2, right, false);
/*
- * If center part is too large (comprises > 5/7 of the array),
+ * If center part is too large (comprises > 4/7 of the array),
* swap internal pivot values to ends.
*/
if (less < e1 && e5 < great) {
@@ -1737,8 +1426,8 @@ final class DualPivotQuicksort {
* Pointer k is the first index of ?-part.
*/
outer:
- for (int k = less; k <= great; k++) {
- byte ak = a[k];
+ for (int k = less - 1; ++k <= great; ) {
+ char ak = a[k];
if (ak == pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
@@ -1749,7 +1438,7 @@ final class DualPivotQuicksort {
break outer;
}
}
- if (a[great] == pivot1) {
+ if (a[great] == pivot1) { // a[great] < pivot2
a[k] = a[less];
/*
* Even though a[great] equals to pivot1, the
@@ -1775,7 +1464,7 @@ final class DualPivotQuicksort {
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way
+ * Partitioning degenerates to the traditional 3-way
* (or "Dutch National Flag") schema:
*
* left part center part right part
@@ -1794,28 +1483,20 @@ final class DualPivotQuicksort {
*
* Pointer k is the first index of ?-part.
*/
- for (int k = left; k <= great; k++) {
+ for (int k = less; k <= great; ++k) {
if (a[k] == pivot1) {
continue;
}
- byte ak = a[k];
-
+ char ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
a[k] = a[less];
a[less] = ak;
less++;
} else { // a[k] > pivot1 - Move a[k] to right part
- /*
- * We know that pivot1 == a[e3] == pivot2. Thus, we know
- * that great will still be >= k when the following loop
- * terminates, even though we don't test for it explicitly.
- * In other words, a[e3] acts as a sentinel for great.
- */
while (a[great] > pivot1) {
- // assert great > k;
great--;
}
- if (a[great] < pivot1) {
+ if (a[great] < pivot1) { // a[great] <= pivot1
a[k] = a[less];
a[less] = a[great];
less++;
@@ -1835,73 +1516,90 @@ final class DualPivotQuicksort {
}
}
- // Sort left and right parts recursively
+ /*
+ * Sort left and right parts recursively.
+ * All elements from center part are equal
+ * and, therefore, already sorted.
+ */
sort(a, left, less - 1, leftmost);
sort(a, great + 1, right, false);
}
}
+ /** The number of distinct byte values. */
+ private static final int NUM_BYTE_VALUES = 1 << 8;
+
/**
- * Sorts the specified array into ascending numerical order.
- *
- * The {@code <} relation does not provide a total order on all float - * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Float#compareTo}: {@code -0.0f} is treated as less than value - * {@code 0.0f} and {@code Float.NaN} is considered greater than any - * other value and all {@code Float.NaN} values are considered equal. + * Sorts the specified array. * * @param a the array to be sorted */ - public static void sort(float[] a) { - sortNegZeroAndNaN(a, 0, a.length - 1); + public static void sort(byte[] a) { + sort(a, 0, a.length - 1); } /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty (and the call is a no-op). + * Sorts the specified range of the array. * - *
The {@code <} relation does not provide a total order on all float - * values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Float#compareTo}: {@code -0.0f} is treated as less than value - * {@code 0.0f} and {@code Float.NaN} is considered greater than any - * other value and all {@code Float.NaN} values are considered equal. + * @param a the array to be sorted + * @param left the index of the first element, inclusive, to be sorted + * @param right the index of the last element, inclusive, to be sorted + */ + public static void sort(byte[] a, int left, int right) { + // Use counting sort on large arrays + if (right - left > COUNTING_SORT_THRESHOLD_FOR_BYTE) { + int[] count = new int[NUM_BYTE_VALUES]; + + for (int i = left - 1; ++i <= right; ) { + count[a[i] - Byte.MIN_VALUE]++; + } + for (int i = NUM_BYTE_VALUES, k = right + 1; k > left; ) { + while (count[--i] == 0); + byte value = (byte) (i + Byte.MIN_VALUE); + int s = count[i]; + + do { + a[--k] = value; + } while (--s > 0); + } + } else { // Use insertion sort on small arrays + for (int i = left, j = i; i < right; j = ++i) { + byte ai = a[i + 1]; + while (ai < a[j]) { + a[j + 1] = a[j]; + if (j-- == left) { + break; + } + } + a[j + 1] = ai; + } + } + } + + /** + * Sorts the specified array. * * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} */ - public static void sort(float[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sortNegZeroAndNaN(a, fromIndex, toIndex - 1); + public static void sort(float[] a) { + sort(a, 0, a.length - 1); } /** - * Sorts the specified range of the array into ascending order. The - * sort is done in three phases to avoid expensive comparisons in the - * inner loop. The comparisons would be expensive due to anomalies - * associated with negative zero {@code -0.0f} and {@code Float.NaN}. + * Sorts the specified range of the array. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted */ - private static void sortNegZeroAndNaN(float[] a, int left, int right) { + public static void sort(float[] a, int left, int right) { /* * Phase 1: Move NaNs to the end of the array. */ while (left <= right && Float.isNaN(a[right])) { right--; } - for (int k = right - 1; k >= left; k--) { + for (int k = right; --k >= left; ) { float ak = a[k]; if (ak != ak) { // a[k] is NaN a[k] = a[right]; @@ -1921,7 +1619,7 @@ final class DualPivotQuicksort { int hi = right; /* - * Search first zero, or first positive, or last negative element. + * Find the first zero, or first positive, or last negative element. */ while (left < hi) { int middle = (left + hi) >>> 1; @@ -1946,12 +1644,12 @@ final class DualPivotQuicksort { * * Partitioning: * - * +---------------------------------------------------+ - * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) | - * +---------------------------------------------------+ - * ^ ^ ^ - * | | | - * left p k + * +----------------------------------------------------+ + * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) | + * +----------------------------------------------------+ + * ^ ^ ^ + * | | | + * left p k * * Invariants: * @@ -1962,53 +1660,36 @@ final class DualPivotQuicksort { * * Pointer k is the first index of ?-part. */ - for (int k = left + 1, p = left; k <= right; k++) { + for (int k = left, p = left - 1; ++k <= right; ) { float ak = a[k]; if (ak != 0.0f) { break; } if (Float.floatToRawIntBits(ak) < 0) { // ak is -0.0f a[k] = 0.0f; - a[p++] = -0.0f; + a[++p] = -0.0f; } } } /** - * Sorts the specified range of the array into ascending order by the - * Dual-Pivot Quicksort algorithm. This method differs from the public - * {@code sort} method in that the {@code right} index is inclusive, - * it does no range checking on {@code left} or {@code right}, and has - * boolean flag whether insertion sort with sentinel is used or not. + * Sorts the specified range of the array by Dual-Pivot Quicksort. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted - * @param leftmost indicates if the part is the most left in the range + * @param leftmost indicates if this part is the leftmost in the range */ private static void sort(float[] a, int left, int right,boolean leftmost) { int length = right - left + 1; - // Use insertion sort on tiny arrays + // Use insertion sort on small arrays if (length < INSERTION_SORT_THRESHOLD) { - if (!leftmost) { - /* - * Every element in adjoining part plays the role - * of sentinel, therefore this allows us to avoid - * the j >= left check on each iteration. - */ - for (int j, i = left + 1; i <= right; i++) { - float ai = a[i]; - for (j = i - 1; ai < a[j]; j--) { - // assert j >= left; - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } else { + if (leftmost) { /* - * For case of leftmost part traditional (without a sentinel) - * insertion sort, optimized for server JVM, is used. + * Traditional (without sentinel) insertion sort, + * optimized for server VM, is used in case of + * the leftmost part. */ for (int i = left, j = i; i < right; j = ++i) { float ai = a[i + 1]; @@ -2020,12 +1701,54 @@ final class DualPivotQuicksort { } a[j + 1] = ai; } + } else { + /* + * Skip the longest ascending sequence. + */ + do { + if (left++ >= right) { + return; + } + } while (a[left - 1] <= a[left]); + + /* + * Every element from adjoining part plays the role + * of sentinel, therefore this allows us to avoid the + * left range check on each iteration. Moreover, we use + * the best improved algorithm, so called pair insertion + * sort, which is faster than traditional implementation + * in the context of Dual-Pivot Quicksort. + */ + for (int k = left--; (left += 2) <= right; ) { + float a1, a2; k = left - 1; + + if (a[k] < a[left]) { + a2 = a[k]; a1 = a[left]; + } else { + a1 = a[k]; a2 = a[left]; + } + while (a1 < a[--k]) { + a[k + 2] = a[k]; + } + a[++k + 1] = a1; + + while (a2 < a[--k]) { + a[k + 1] = a[k]; + } + a[k + 1] = a2; + } + float last = a[right]; + + while (last < a[--right]) { + a[right + 1] = a[right]; + } + a[right + 1] = last; } return; } // Inexpensive approximation of length / 7 - int seventh = (length >>> 3) + (length >>> 6) + 1; + int seventh = (length >> 3) + (length >> 6) + 1; /* * Sort five evenly spaced elements around (and including) the @@ -2107,10 +1830,14 @@ final class DualPivotQuicksort { * Pointer k is the first index of ?-part. */ outer: - for (int k = less; k <= great; k++) { + for (int k = less - 1; ++k <= great; ) { float ak = a[k]; if (ak < pivot1) { // Move a[k] to left part a[k] = a[less]; + /* + * Here and below we use "a[i] = b; i++;" instead + * of "a[i++] = b;" due to performance issue. + */ a[less] = ak; less++; } else if (ak > pivot2) { // Move a[k] to right part @@ -2119,13 +1846,17 @@ final class DualPivotQuicksort { break outer; } } - if (a[great] < pivot1) { + if (a[great] < pivot1) { // a[great] <= pivot2 a[k] = a[less]; a[less] = a[great]; less++; } else { // pivot1 <= a[great] <= pivot2 a[k] = a[great]; } + /* + * Here and below we use "a[i] = b; i--;" instead + * of "a[i--] = b;" due to performance issue. + */ a[great] = ak; great--; } @@ -2140,7 +1871,7 @@ final class DualPivotQuicksort { sort(a, great + 2, right, false); /* - * If center part is too large (comprises > 5/7 of the array), + * If center part is too large (comprises > 4/7 of the array), * swap internal pivot values to ends. */ if (less < e1 && e5 < great) { @@ -2174,7 +1905,7 @@ final class DualPivotQuicksort { * Pointer k is the first index of ?-part. */ outer: - for (int k = less; k <= great; k++) { + for (int k = less - 1; ++k <= great; ) { float ak = a[k]; if (ak == pivot1) { // Move a[k] to left part a[k] = a[less]; @@ -2186,7 +1917,7 @@ final class DualPivotQuicksort { break outer; } } - if (a[great] == pivot1) { + if (a[great] == pivot1) { // a[great] < pivot2 a[k] = a[less]; /* * Even though a[great] equals to pivot1, the @@ -2212,7 +1943,7 @@ final class DualPivotQuicksort { } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way + * Partitioning degenerates to the traditional 3-way * (or "Dutch National Flag") schema: * * left part center part right part @@ -2231,28 +1962,20 @@ final class DualPivotQuicksort { * * Pointer k is the first index of ?-part. */ - for (int k = left; k <= great; k++) { + for (int k = less; k <= great; ++k) { if (a[k] == pivot1) { continue; } float ak = a[k]; - if (ak < pivot1) { // Move a[k] to left part a[k] = a[less]; a[less] = ak; less++; } else { // a[k] > pivot1 - Move a[k] to right part - /* - * We know that pivot1 == a[e3] == pivot2. Thus, we know - * that great will still be >= k when the following loop - * terminates, even though we don't test for it explicitly. - * In other words, a[e3] acts as a sentinel for great. - */ while (a[great] > pivot1) { - // assert great > k; great--; } - if (a[great] < pivot1) { + if (a[great] < pivot1) { // a[great] <= pivot1 a[k] = a[less]; a[less] = a[great]; less++; @@ -2272,73 +1995,40 @@ final class DualPivotQuicksort { } } - // Sort left and right parts recursively + /* + * Sort left and right parts recursively. + * All elements from center part are equal + * and, therefore, already sorted. + */ sort(a, left, less - 1, leftmost); sort(a, great + 1, right, false); } } /** - * Sorts the specified array into ascending numerical order. - * - *
The {@code <} relation does not provide a total order on all double - * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Double#compareTo}: {@code -0.0d} is treated as less than value - * {@code 0.0d} and {@code Double.NaN} is considered greater than any - * other value and all {@code Double.NaN} values are considered equal. + * Sorts the specified array. * * @param a the array to be sorted */ public static void sort(double[] a) { - sortNegZeroAndNaN(a, 0, a.length - 1); - } - - /** - * Sorts the specified range of the array into ascending order. The range - * to be sorted extends from the index {@code fromIndex}, inclusive, to - * the index {@code toIndex}, exclusive. If {@code fromIndex == toIndex}, - * the range to be sorted is empty (and the call is a no-op). - * - *
The {@code <} relation does not provide a total order on all double - * values: {@code -0.0d == 0.0d} is {@code true} and a {@code Double.NaN} - * value compares neither less than, greater than, nor equal to any value, - * even itself. This method uses the total order imposed by the method - * {@link Double#compareTo}: {@code -0.0d} is treated as less than value - * {@code 0.0d} and {@code Double.NaN} is considered greater than any - * other value and all {@code Double.NaN} values are considered equal. - * - * @param a the array to be sorted - * @param fromIndex the index of the first element, inclusive, to be sorted - * @param toIndex the index of the last element, exclusive, to be sorted - * @throws IllegalArgumentException if {@code fromIndex > toIndex} - * @throws ArrayIndexOutOfBoundsException - * if {@code fromIndex < 0} or {@code toIndex > a.length} - */ - public static void sort(double[] a, int fromIndex, int toIndex) { - rangeCheck(a.length, fromIndex, toIndex); - sortNegZeroAndNaN(a, fromIndex, toIndex - 1); + sort(a, 0, a.length - 1); } /** - * Sorts the specified range of the array into ascending order. The - * sort is done in three phases to avoid expensive comparisons in the - * inner loop. The comparisons would be expensive due to anomalies - * associated with negative zero {@code -0.0d} and {@code Double.NaN}. + * Sorts the specified range of the array. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted */ - private static void sortNegZeroAndNaN(double[] a, int left, int right) { + public static void sort(double[] a, int left, int right) { /* * Phase 1: Move NaNs to the end of the array. */ while (left <= right && Double.isNaN(a[right])) { right--; } - for (int k = right - 1; k >= left; k--) { + for (int k = right; --k >= left; ) { double ak = a[k]; if (ak != ak) { // a[k] is NaN a[k] = a[right]; @@ -2358,7 +2048,7 @@ final class DualPivotQuicksort { int hi = right; /* - * Search first zero, or first positive, or last negative element. + * Find the first zero, or first positive, or last negative element. */ while (left < hi) { int middle = (left + hi) >>> 1; @@ -2383,12 +2073,12 @@ final class DualPivotQuicksort { * * Partitioning: * - * +---------------------------------------------------+ - * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) | - * +---------------------------------------------------+ - * ^ ^ ^ - * | | | - * left p k + * +----------------------------------------------------+ + * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) | + * +----------------------------------------------------+ + * ^ ^ ^ + * | | | + * left p k * * Invariants: * @@ -2399,53 +2089,36 @@ final class DualPivotQuicksort { * * Pointer k is the first index of ?-part. */ - for (int k = left + 1, p = left; k <= right; k++) { + for (int k = left, p = left - 1; ++k <= right; ) { double ak = a[k]; if (ak != 0.0d) { break; } if (Double.doubleToRawLongBits(ak) < 0) { // ak is -0.0d a[k] = 0.0d; - a[p++] = -0.0d; + a[++p] = -0.0d; } } } /** - * Sorts the specified range of the array into ascending order by the - * Dual-Pivot Quicksort algorithm. This method differs from the public - * {@code sort} method in that the {@code right} index is inclusive, - * it does no range checking on {@code left} or {@code right}, and has - * boolean flag whether insertion sort with sentinel is used or not. + * Sorts the specified range of the array by Dual-Pivot Quicksort. * * @param a the array to be sorted * @param left the index of the first element, inclusive, to be sorted * @param right the index of the last element, inclusive, to be sorted - * @param leftmost indicates if the part is the most left in the range + * @param leftmost indicates if this part is the leftmost in the range */ private static void sort(double[] a, int left,int right,boolean leftmost) { int length = right - left + 1; - // Use insertion sort on tiny arrays + // Use insertion sort on small arrays if (length < INSERTION_SORT_THRESHOLD) { - if (!leftmost) { - /* - * Every element in adjoining part plays the role - * of sentinel, therefore this allows us to avoid - * the j >= left check on each iteration. - */ - for (int j, i = left + 1; i <= right; i++) { - double ai = a[i]; - for (j = i - 1; ai < a[j]; j--) { - // assert j >= left; - a[j + 1] = a[j]; - } - a[j + 1] = ai; - } - } else { + if (leftmost) { /* - * For case of leftmost part traditional (without a sentinel) - * insertion sort, optimized for server JVM, is used. + * Traditional (without sentinel) insertion sort, + * optimized for server VM, is used in case of + * the leftmost part. */ for (int i = left, j = i; i < right; j = ++i) { double ai = a[i + 1]; @@ -2457,12 +2130,54 @@ final class DualPivotQuicksort { } a[j + 1] = ai; } + } else { + /* + * Skip the longest ascending sequence. + */ + do { + if (left++ >= right) { + return; + } + } while (a[left - 1] <= a[left]); + + /* + * Every element from adjoining part plays the role + * of sentinel, therefore this allows us to avoid the + * left range check on each iteration. Moreover, we use + * the best improved algorithm, so called pair insertion + * sort, which is faster than traditional implementation + * in the context of Dual-Pivot Quicksort. + */ + for (int k = left--; (left += 2) <= right; ) { + double a1, a2; k = left - 1; + + if (a[k] < a[left]) { + a2 = a[k]; a1 = a[left]; + } else { + a1 = a[k]; a2 = a[left]; + } + while (a1 < a[--k]) { + a[k + 2] = a[k]; + } + a[++k + 1] = a1; + + while (a2 < a[--k]) { + a[k + 1] = a[k]; + } + a[k + 1] = a2; + } + double last = a[right]; + + while (last < a[--right]) { + a[right + 1] = a[right]; + } + a[right + 1] = last; } return; } // Inexpensive approximation of length / 7 - int seventh = (length >>> 3) + (length >>> 6) + 1; + int seventh = (length >> 3) + (length >> 6) + 1; /* * Sort five evenly spaced elements around (and including) the @@ -2544,10 +2259,14 @@ final class DualPivotQuicksort { * Pointer k is the first index of ?-part. */ outer: - for (int k = less; k <= great; k++) { + for (int k = less - 1; ++k <= great; ) { double ak = a[k]; if (ak < pivot1) { // Move a[k] to left part a[k] = a[less]; + /* + * Here and below we use "a[i] = b; i++;" instead + * of "a[i++] = b;" due to performance issue. + */ a[less] = ak; less++; } else if (ak > pivot2) { // Move a[k] to right part @@ -2556,13 +2275,17 @@ final class DualPivotQuicksort { break outer; } } - if (a[great] < pivot1) { + if (a[great] < pivot1) { // a[great] <= pivot2 a[k] = a[less]; a[less] = a[great]; less++; } else { // pivot1 <= a[great] <= pivot2 a[k] = a[great]; } + /* + * Here and below we use "a[i] = b; i--;" instead + * of "a[i--] = b;" due to performance issue. + */ a[great] = ak; great--; } @@ -2577,7 +2300,7 @@ final class DualPivotQuicksort { sort(a, great + 2, right, false); /* - * If center part is too large (comprises > 5/7 of the array), + * If center part is too large (comprises > 4/7 of the array), * swap internal pivot values to ends. */ if (less < e1 && e5 < great) { @@ -2611,7 +2334,7 @@ final class DualPivotQuicksort { * Pointer k is the first index of ?-part. */ outer: - for (int k = less; k <= great; k++) { + for (int k = less - 1; ++k <= great; ) { double ak = a[k]; if (ak == pivot1) { // Move a[k] to left part a[k] = a[less]; @@ -2623,7 +2346,7 @@ final class DualPivotQuicksort { break outer; } } - if (a[great] == pivot1) { + if (a[great] == pivot1) { // a[great] < pivot2 a[k] = a[less]; /* * Even though a[great] equals to pivot1, the @@ -2649,7 +2372,7 @@ final class DualPivotQuicksort { } else { // Pivots are equal /* - * Partition degenerates to the traditional 3-way + * Partitioning degenerates to the traditional 3-way * (or "Dutch National Flag") schema: * * left part center part right part @@ -2668,28 +2391,20 @@ final class DualPivotQuicksort { * * Pointer k is the first index of ?-part. */ - for (int k = left; k <= great; k++) { + for (int k = less; k <= great; ++k) { if (a[k] == pivot1) { continue; } double ak = a[k]; - if (ak < pivot1) { // Move a[k] to left part a[k] = a[less]; a[less] = ak; less++; } else { // a[k] > pivot1 - Move a[k] to right part - /* - * We know that pivot1 == a[e3] == pivot2. Thus, we know - * that great will still be >= k when the following loop - * terminates, even though we don't test for it explicitly. - * In other words, a[e3] acts as a sentinel for great. - */ while (a[great] > pivot1) { - // assert great > k; great--; } - if (a[great] < pivot1) { + if (a[great] < pivot1) { // a[great] <= pivot1 a[k] = a[less]; a[less] = a[great]; less++; @@ -2709,26 +2424,13 @@ final class DualPivotQuicksort { } } - // Sort left and right parts recursively + /* + * Sort left and right parts recursively. + * All elements from center part are equal + * and, therefore, already sorted. + */ sort(a, left, less - 1, leftmost); sort(a, great + 1, right, false); } } - - /** - * Checks that {@code fromIndex} and {@code toIndex} are in the range, - * otherwise throws an appropriate exception. - */ - 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 > length) { - throw new ArrayIndexOutOfBoundsException(toIndex); - } - } } diff --git a/src/share/classes/java/util/Properties.java b/src/share/classes/java/util/Properties.java index 6f9c562e4f8b7729f69946b2a0bccb369475a3e1..ee6d17c4e4da421954719c53ba8efd8ebdb295eb 100644 --- a/src/share/classes/java/util/Properties.java +++ b/src/share/classes/java/util/Properties.java @@ -705,7 +705,7 @@ class Properties extends Hashtable