diff --git a/.hgtags b/.hgtags
index 43473804c908a2fe71357a272cf247f0386672ba..986d99166594134d8fea14099c0243817d5370d7 100644
--- a/.hgtags
+++ b/.hgtags
@@ -75,3 +75,5 @@ b1903d7528d33b521df42bc9291bdcdd2f444a29 jdk7-b97
82593186fa54ab12f17af31f86a7bf364efaf4df jdk7-b98
2587c9f0b60dc3146b4247b8674ada456a643d6f jdk7-b99
820b4e843d5168370a3bf166d19751a3271d8575 jdk7-b100
+d58354a69011f3d3354765fa3167567c4c4a9612 jdk7-b101
+13029a61b16bec06535d4f0aa98229b358684128 jdk7-b102
diff --git a/make/common/shared/Defs-javadoc.gmk b/make/common/shared/Defs-javadoc.gmk
new file mode 100644
index 0000000000000000000000000000000000000000..83b3b4aa7066453ebe54c9462e4179611aaa6749
--- /dev/null
+++ b/make/common/shared/Defs-javadoc.gmk
@@ -0,0 +1,93 @@
+#
+# Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation. Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# Copyright year for beginning of Java and some of the apis
+# (Needed when creating the javadocs)
+FIRST_COPYRIGHT_YEAR = 1993
+DOMAPI_FIRST_COPYRIGHT_YEAR = 2005
+MIRROR_FIRST_COPYRIGHT_YEAR = 2004
+DOCLETAPI_FIRST_COPYRIGHT_YEAR = 1993
+TAGLETAPI_FIRST_COPYRIGHT_YEAR = 1993
+JDI_FIRST_COPYRIGHT_YEAR = 1999
+JAAS_FIRST_COPYRIGHT_YEAR = 1998
+JGSS_FIRST_COPYRIGHT_YEAR = 2000
+SMARTCARDIO_FIRST_COPYRIGHT_YEAR = 2005
+HTTPSERVER_FIRST_COPYRIGHT_YEAR = 2005
+MGMT_FIRST_COPYRIGHT_YEAR = 2003
+ATTACH_FIRST_COPYRIGHT_YEAR = 2005
+JCONSOLE_FIRST_COPYRIGHT_YEAR = 2006
+SCTPAPI_FIRST_COPYRIGHT_YEAR = 2009
+TRACING_FIRST_COPYRIGHT_YEAR = 2008
+TREEAPI_FIRST_COPYRIGHT_YEAR = 2005
+JNLP_FIRST_COPYRIGHT_YEAR = 1998
+PLUGIN2_FIRST_COPYRIGHT_YEAR = 2007
+
+# Oracle name
+COMPANY_NAME = Oracle and/or its affiliates
+
+# Copyright address
+COMPANY_ADDRESS = 500 Oracle Parkway Redwood Shores, CA 94065 USA.
+
+# The trademark symbol
+TRADEMARK = ™
+
+# Common copyright lines used
+# The word "Copyright" might optionally be a link to the file cpyr.html.
+# The first year of copyright may vary or not be available.
+# The address to the company might be optional.
+COMMA:= ,
+EMPTY:=
+SPACE:=$(EMPTY) $(EMPTY)
+COPYRIGHT_SYMBOL = &\#x00a9;
+# Macros to handle the optional empty args.
+# (The GNU make 3.78.1 "if" conditional is broken, fixed in GNU make 3.81)
+define OptionalCopyrightUrl # url
+$(shell \
+ if [ "$1" != "" ] ; then \
+ printf "Copyright" "$1"; \
+ else \
+ printf "Copyright"; \
+ fi)
+endef
+define OptionalCopyrightFirstYear # year
+$(shell \
+ if [ "$1" != "" ] ; then \
+ printf "%s," "$1";\
+ fi)
+endef
+define OptionalCompanyAddress # address
+$(shell \
+ if [ "$1" != "" ] ; then \
+ printf "%s" "$1";\
+ fi)
+endef
+define CopyrightLine # optionalurl optionalfirstyear optionaladdress
+$(call OptionalCopyrightUrl,$1) $(COPYRIGHT_SYMBOL)\
+$(call OptionalCopyrightFirstYear,$2) $(COPYRIGHT_YEAR),\
+$(COMPANY_NAME).\
+$(call OptionalCompanyAddress,$3)\
+All rights reserved.
+endef
+
diff --git a/make/docs/Makefile b/make/docs/Makefile
index a000aae2551058bfc57b994eddbe663e8cfe9f37..20150c81a473ac3103c494978ed3a9c8d567b805 100644
--- a/make/docs/Makefile
+++ b/make/docs/Makefile
@@ -1,5 +1,4 @@
-#
-# Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -30,6 +29,41 @@ BUILDDIR=..
PRODUCT=docs
include $(BUILDDIR)/common/Defs.gmk
+# Get CopyrightLine macro and other shared variables
+include $(BUILDDIR)/common/shared/Defs-javadoc.gmk
+
+# Url to root of documents
+DOCSDIR_URL = {@docroot}/$(GET2DOCSDIR)
+
+# Url to copyright html file
+COPYRIGHT_URL-7 = $(DOCSDIR_URL)/legal/cpyr.html
+COPYRIGHT_URL = $(COPYRIGHT_URL-$(JDK_MINOR_VERSION))
+
+# Url to bug filing site
+BUG_SUBMIT_URL = http://bugs.sun.com/services/bugreport/index.jsp
+
+# Common line for how to submit a bug or rfe
+BUG_SUBMIT_LINE = Submit a bug or feature
+
+# Url to devdocs page
+# Was: http://java.sun.com/javase/6/webnotes/devdocs-vs-specs.html
+DEV_DOCS_URL-5 = http://java.sun.com/j2se/1.5.0/docs
+DEV_DOCS_URL-6 = http://download.oracle.com/docs/cd/E17409_01/javase/6/docs
+DEV_DOCS_URL-7 = http://download.oracle.com/docs/cd/E17409_01/javase/7/docs
+DEV_DOCS_URL = $(DEV_DOCS_URL-$(JDK_MINOR_VERSION))
+
+# Url to Java Language Spec
+JLS3_URL = http://java.sun.com/docs/books/jls/
+
+# Common Java trademark line
+JAVA_TRADEMARK_LINE = Java is a trademark or registered trademark of \
+$(COMPANY_NAME) in the US and other countries.
+
+#
+# Definitions for imported components
+#
+include $(BUILDDIR)/common/internal/ImportComponents.gmk
+
# We override whatever the max VM memory setting is here.
# NOTE: javadoc will not complete without these larger settings.
# WARNING: This could cause thrashing on low memory machines.
@@ -39,672 +73,1135 @@ else
MAX_VM_MEMORY = 512
endif
+# List of all possible directories for javadoc to look for sources
+# NOTE: Quotes are required around sourcepath argument only on Windows.
+# Otherwise, you get "No packages or classes specified." due
+# to $(CLASSPATH_SEPARATOR) being interpreted as an end of
+# command (newline or shell ; character)
+ALL_SOURCE_DIRS = $(SHARE_SRC)/classes \
+ $(IMPORTSRCDIR) \
+ $(GENSRCDIR) \
+ $(SHARE_SRC)/../solaris/classes \
+ $(SHARE_SRC)/../windows/classes \
+ $(SHARE_SRC)/doc/stub
+EMPTY:=
+SPACE:= $(EMPTY) $(EMPTY)
+RELEASEDOCS_SOURCEPATH = \
+ $(subst $(SPACE),$(CLASSPATH_SEPARATOR),$(strip $(ALL_SOURCE_DIRS)))
+
+# Prep for javadoc creation, assumes $@ is an index.html file
+define prep-javadoc
+@if [ -f "$@" -a "$?" != "" ] ; then \
+ $(ECHO) "# Dependencies have changed: $?"; \
+fi
+$(RM) -r $(@D)
+$(MKDIR) -p $(@D)
+endef
+
+# A cache of the directories in ALL_SOURCE_DIRS
+DIRECTORY_CACHE = $(DOCSTMPDIR)/directory.cache
+
+# Given a list of packages, return a list of files or dirs to be dependent on
+# (Currently only returning a list of directories)
+define PackageDependencies # packages
+$(shell \
+ if [ "$1" != "" -a -f $(DIRECTORY_CACHE) ] ; then \
+ for p in $1 ; do \
+ pd=`$(ECHO) $${p} | $(SED) -e 's@[.]@/@g'`; \
+ $(CAT) $(DIRECTORY_CACHE) | $(GREP) "/$${pd}/" ; \
+ done; \
+ fi \
+)
+endef
+
+# Given a list of packages, add packages that exist to $@, print summary
+define PackageFilter # packages
+@if [ "$1" != "" ] ; then \
+ for p in $1 ; do \
+ pd=`$(ECHO) $${p} | $(SED) -e 's@[.]@/@g'`; \
+ found="false"; \
+ for cp in $(ALL_SOURCE_DIRS) ; do \
+ if [ -d $${cp}/$${pd} ] ; then \
+ $(ECHO) "$${p}" >> $@; \
+ found="true"; \
+ break; \
+ fi; \
+ done; \
+ if [ "$${found}" = "false" ] ; then \
+ $(ECHO) "WARNING: Package not found: $${p}"; \
+ fi; \
+ done; \
+fi
+endef
+
+# Print out a summary of the javadoc command about to be run
+define JavadocSummary # optionsfile packagesfile
+@$(ECHO) "# Summary for $@";\
+ $(ECHO) "# Options (`$(BASENAME) $1`):"; $(SED) -e 's@^@# @' $1; \
+ $(ECHO) "# Packages (`$(BASENAME) $2`):";$(SED) -e 's@^@# @' $2
+endef
+
#
-# Variables used by docs target
+# Temporary directory for javadoc creation
#
-DOCSTMPDIR = $(TEMPDIR)/doctmp
+DOCSTMPDIR = $(TEMPDIR)/doctmp
+#
+# Different api directories created from root directory
+#
+COREAPI_DOCSDIR = $(DOCSDIR)/api
+JDK_API_DOCSDIR = $(DOCSDIR)/jdk/api
+JRE_API_DOCSDIR = $(DOCSDIR)/jre/api
+PLATFORM_DOCSDIR = $(DOCSDIR)/platform
+
+# The non-core api javadocs need to be able to access the root of the core
+# api directory, so for jdk/api or jre/api to get to the core api/
+# directory we would use this:
+JDKJRE2COREAPI = ../../api
+
+# Common bottom argument
+define CommonBottom # year
+
$(call CopyrightLine,,$1,)
+endef
+
+# Common trademark bottom argument (Not sure why this is used sometimes)
+define CommonTrademarkBottom # year
+\
+$(BUG_SUBMIT_LINE) $(JAVA_TRADEMARK_LINE) \
+$(call CopyrightLine,,$1,$(COMPANY_ADDRESS))\
+
+endef
+
+# Core api bottom argument (with special sauce)
+COREAPI_BOTTOM = $(BUG_SUBMIT_LINE)\
+ For further API reference and developer documentation, \
+see Java SE Documentation. \
+That documentation contains more detailed, developer-targeted descriptions, \
+with conceptual overviews, definitions of terms, workarounds, \
+and working code examples.
\
+Please note that the specifications and other information \
+contained herein are not final and are subject to change. \
+The information is being made available to you solely for purpose of \
+evaluation. \
+
+ endif
+endif
+
+#################################################################
+
+#
+# CORE_PKGS environment variable has been moved to the following file
+#
+include CORE_PKGS.gmk
+
+#
+# Load environment variables for API package names that are not part of
+# the Java SE platform
+#
+include NON_CORE_PKGS.gmk
+#################################################################
+
+#
+# Default target is same as docs target, create core api and all others it can
+#
+
+all docs: coredocs otherdocs
+
+#################################################################
+# Production Targets -- USE THESE TARGETS WHEN:
+# a) You're generating docs outside of release engineering's
+# standard control build.
+# b) The docs will be pushed to the web and/or included in
+# the downloaded doc bundle.
+#
+# See: Notes.html#releaseTargets
+# Note: Spaces precede ifdef/ifndef indents. Tabs precede target commands (!)
+#
+
+sanitycheckcoredocs:
+ @$(ECHO) ""
+ @$(ECHO) "Building core api docs with these values:"
+ @$(ECHO) " BUILD_NUMBER = $(BUILD_NUMBER)"
+ @$(ECHO) " MILESTONE = $(MILESTONE)"
+ @$(ECHO) ""
+ ifeq ($(BUILD_NUMBER), b00)
+ @$(ECHO) "ERROR: Build number must be defined"
+ @$(ECHO) "MILESTONE is set to $(MILESTONE)"
+ @$(ECHO) ""
+ exit 1
+ endif
+
+#############################################################
+#
+# coredocs
+#
+COREAPI_DOCTITLE = Java$(TRADEMARK) Platform, Standard Edition \
+$(JDK_MINOR_VERSION) API Specification
+COREAPI_WINDOWTITLE = Java Platform SE $(JDK_MINOR_VERSION)
+COREAPI_HEADER = \
+Java$(TRADEMARK) Platform Standard Ed. $(JDK_MINOR_VERSION)
+
+# Ignored tags
IGNORED_TAGS = beaninfo revised since.unbundled spec specdefault Note ToDo
-JLS3_URL = http://java.sun.com/docs/books/jls/
-JLS3_CITE = \
+# Java language specification cite
+JLS3_CITE = \
The Java Language Specification, Third Edition
TAG_JLS3 = -tag 'jls3:a:See $(JLS3_CITE):'
TAGS = $(IGNORED_TAGS:%=-tag %:X) $(TAG_JLS3)
-ifeq ($(MILESTONE), fcs)
- DOCTITLE_SWITCH = $(JAVADOCTITLE)
- WINDOWTITLE_SWITCH = $(JAVADOCWINDOWTITLE)
- HEADER_SWITCH = $(JAVADOCHEADER)
- TOPOPTION=
- JAVADOCBOTTOM_SWITCH= $(JAVADOCBOTTOM)
- OVERVIEW_OPTION = -overview $(JAVADOCOVERVIEW)
-else
- DOCTITLE_SWITCH = $(JAVADOCTITLE_EARLYACCESS)$(DRAFT)
- WINDOWTITLE_SWITCH = $(JAVADOCWINDOWTITLE)" $(BUILD_NUMBER)"
- HEADER_SWITCH = $(JAVADOCHEADER)$(DRAFT)
- JAVADOCBOTTOM_SWITCH= $(JAVADOCBOTTOM_EARLYACCESS)
- TOPOPTION= -top $(JAVADOCTOP_EARLYACCESS)
- OVERVIEW_OPTION =
+# Overview file for core apis
+COREAPI_OVERVIEW = $(SHARE_SRC)/classes/overview-core.html
+
+# The index.html, options, and packages files
+COREAPI_INDEX_FILE = $(COREAPI_DOCSDIR)/index.html
+COREAPI_OPTIONS_FILE = $(DOCSTMPDIR)/coredocs.options
+COREAPI_PACKAGES_FILE = $(DOCSTMPDIR)/coredocs.packages
+
+coredocs: $(COREAPI_INDEX_FILE)
+
+# Set relative location to core api document root
+$(COREAPI_INDEX_FILE): GET2DOCSDIR=..
+
+# Run javadoc if the index file is out of date or missing
+$(COREAPI_INDEX_FILE): $(COREAPI_OPTIONS_FILE) $(COREAPI_PACKAGES_FILE)
+ $(prep-javadoc)
+ $(call JavadocSummary,$(COREAPI_OPTIONS_FILE),$(COREAPI_PACKAGES_FILE))
+ $(JAVADOC_CMD) $(JAVADOC_VM_MEMORY_FLAGS) -d $(@D) \
+ @$(COREAPI_OPTIONS_FILE) @$(COREAPI_PACKAGES_FILE)
+
+# Create file with javadoc options in it
+$(COREAPI_OPTIONS_FILE): $(COREAPI_OVERVIEW)
+ $(prep-target)
+ @($(ECHO) "$(COMMON_JAVADOCFLAGS)" ; \
+ $(ECHO) "-sourcepath \"$(RELEASEDOCS_SOURCEPATH)\"" ; \
+ $(ECHO) "$(TAGS)" ; \
+ $(ECHO) "-encoding ISO-8859-1" ; \
+ $(ECHO) "-splitIndex" ; \
+ $(ECHO) "-overview $(COREAPI_OVERVIEW)" ; \
+ $(ECHO) "-doctitle '$(COREAPI_DOCTITLE)'" ; \
+ $(ECHO) "-windowtitle '$(COREAPI_WINDOWTITLE) $(DRAFT_WINTITLE)'";\
+ $(ECHO) "-header '$(COREAPI_HEADER)$(DRAFT_HEADER)'" ; \
+ $(ECHO) "-bottom '$(COREAPI_BOTTOM)$(DRAFT_BOTTOM)'" ; \
+ ) >> $@
+ifdef COREAPI_TOP_EARLYACCESS
+ @$(ECHO) "-top '$(COREAPI_TOP_EARLYACCESS)'" >> $@
endif
-JAVADOCTITLE = 'Java$(TRADEMARK) Platform, Standard Edition $(JDK_MINOR_VERSION) API Specification'
-JAVADOCWINDOWTITLE = 'Java Platform SE $(JDK_MINOR_VERSION)'
-JAVADOCHEADER = 'Java$(TRADEMARK) Platform Standard Ed. $(JDK_MINOR_VERSION)'
-JAVADOCBOTTOM = 'Submit a bug or feature For further API reference and developer documentation, see Java SE Developer Documentation. That documentation contains more detailed, developer-targeted descriptions, with conceptual overviews, definitions of terms, workarounds, and working code examples.
'
-JAVADOCOVERVIEW = $(SHARE_SRC)/classes/overview-core.html
+# Create a file with the package names in it
+$(COREAPI_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(CORE_PKGS))
+ $(prep-target)
+ $(call PackageFilter,$(CORE_PKGS))
+#############################################################
#
-# Early access top and bottom text (for snapshots, beta and rc)
+# mirrordocs
#
-JAVADOCTOP_EARLYACCESS = '
Please note that this documentation is not final and is subject to change.
- * Used in the contructors of the EventSetDescriptor,
- * PropertyDescriptor and the IndexedPropertyDescriptor.
- *
- * @param cls The Class object on which to retrieve the method.
- * @param methodName Name of the method.
- * @param argCount Number of arguments for the desired method.
- * @param args Array of argument types for the method.
- * @return the method or null if not found
- */
- static Method findMethod(Class cls, String methodName, int argCount,
- Class args[]) {
- if (methodName == null) {
+ static Method findInstanceMethod(Class> type, String name, Class>... args) {
+ try {
+ return MethodFinder.findInstanceMethod(type, name, args);
+ }
+ catch (NoSuchMethodException exception) {
return null;
}
- return internalFindMethod(cls, methodName, argCount, args);
}
/**
diff --git a/src/share/classes/java/beans/MethodDescriptor.java b/src/share/classes/java/beans/MethodDescriptor.java
index 998aa23b217894f7c64233c7c2680adaa26f47df..74a7a16782d704a73246ae1b667971eaf0082a45 100644
--- a/src/share/classes/java/beans/MethodDescriptor.java
+++ b/src/share/classes/java/beans/MethodDescriptor.java
@@ -82,21 +82,21 @@ public class MethodDescriptor extends FeatureDescriptor {
Method method = getMethod0();
if (method == null) {
Class cls = getClass0();
- if (cls != null) {
+ String name = getName();
+ if ((cls != null) && (name != null)) {
Class[] params = getParams();
if (params == null) {
for (int i = 0; i < 3; i++) {
// Find methods for up to 2 params. We are guessing here.
// This block should never execute unless the classloader
// that loaded the argument classes disappears.
- method = Introspector.findMethod(cls, getName(), i, null);
+ method = Introspector.findMethod(cls, name, i);
if (method != null) {
break;
}
}
} else {
- method = Introspector.findMethod(cls, getName(),
- params.length, params);
+ method = Statement.getMethod(cls, name, params);
}
setMethod(method);
}
diff --git a/src/share/classes/java/beans/PropertyDescriptor.java b/src/share/classes/java/beans/PropertyDescriptor.java
index a757530e5a82f86b4cbfea5480acc4bd8fa8dec4..c7524e3026fcdf354c3278b85aca30d27782fbb1 100644
--- a/src/share/classes/java/beans/PropertyDescriptor.java
+++ b/src/share/classes/java/beans/PropertyDescriptor.java
@@ -112,9 +112,7 @@ public class PropertyDescriptor extends FeatureDescriptor {
// If this class or one of its base classes allow PropertyChangeListener,
// then we assume that any properties we discover are "bound".
// See Introspector.getTargetPropertyInfo() method.
- String name = "addPropertyChangeListener";
- Class[] args = {PropertyChangeListener.class};
- this.bound = (null != Introspector.findMethod(beanClass, name, args.length, args));
+ this.bound = null != Introspector.findInstanceMethod(beanClass, "addPropertyChangeListener", PropertyChangeListener.class);
}
/**
@@ -225,10 +223,10 @@ public class PropertyDescriptor extends FeatureDescriptor {
// property type is. For booleans, there can be "is" and "get"
// methods. If an "is" method exists, this is the official
// reader method so look for this one first.
- readMethod = Introspector.findMethod(cls, readMethodName, 0);
+ readMethod = Introspector.findInstanceMethod(cls, readMethodName);
if (readMethod == null) {
readMethodName = Introspector.GET_PREFIX + getBaseName();
- readMethod = Introspector.findMethod(cls, readMethodName, 0);
+ readMethod = Introspector.findInstanceMethod(cls, readMethodName);
}
try {
setReadMethod(readMethod);
@@ -293,8 +291,7 @@ public class PropertyDescriptor extends FeatureDescriptor {
writeMethodName = Introspector.SET_PREFIX + getBaseName();
}
- writeMethod = Introspector.findMethod(cls, writeMethodName, 1,
- (type == null) ? null : new Class[] { type });
+ writeMethod = Introspector.findInstanceMethod(cls, writeMethodName, type);
if (writeMethod != null) {
if (!writeMethod.getReturnType().equals(void.class)) {
writeMethod = null;
diff --git a/src/share/classes/java/beans/PropertyEditorManager.java b/src/share/classes/java/beans/PropertyEditorManager.java
index 3dfbbca321b04402bb73bfec83b5aea606ac5c89..6bdfa95f41b786c49b76913b3a1865a653ec4dd2 100644
--- a/src/share/classes/java/beans/PropertyEditorManager.java
+++ b/src/share/classes/java/beans/PropertyEditorManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -81,10 +81,7 @@ public class PropertyEditorManager {
if (sm != null) {
sm.checkPropertiesAccess();
}
- PropertyEditorFinder finder = getFinder();
- synchronized (finder) {
- finder.register(targetType, editorClass);
- }
+ getFinder().register(targetType, editorClass);
}
/**
@@ -95,10 +92,7 @@ public class PropertyEditorManager {
* The result is null if no suitable editor can be found.
*/
public static PropertyEditor findEditor(Class> targetType) {
- PropertyEditorFinder finder = getFinder();
- synchronized (finder) {
- return finder.find(targetType);
- }
+ return getFinder().find(targetType);
}
/**
@@ -110,10 +104,7 @@ public class PropertyEditorManager {
* e.g. Sun implementation initially sets to {"sun.beans.editors"}.
*/
public static String[] getEditorSearchPath() {
- PropertyEditorFinder finder = getFinder();
- synchronized (finder) {
- return finder.getPackages();
- }
+ return getFinder().getPackages();
}
/**
@@ -134,10 +125,7 @@ public class PropertyEditorManager {
if (sm != null) {
sm.checkPropertiesAccess();
}
- PropertyEditorFinder finder = getFinder();
- synchronized (finder) {
- finder.setPackages(path);
- }
+ getFinder().setPackages(path);
}
private static PropertyEditorFinder getFinder() {
diff --git a/src/share/classes/java/beans/XMLDecoder.java b/src/share/classes/java/beans/XMLDecoder.java
index 4fd0f9dab77286f091d76fe6d5e90835b37f455a..a0d5aa04ff301630bd48e4c53eed8c0e78900f6d 100644
--- a/src/share/classes/java/beans/XMLDecoder.java
+++ b/src/share/classes/java/beans/XMLDecoder.java
@@ -60,7 +60,7 @@ import org.xml.sax.helpers.DefaultHandler;
*
* @author Philip Milne
*/
-public class XMLDecoder {
+public class XMLDecoder implements AutoCloseable {
private final DocumentHandler handler = new DocumentHandler();
private final InputSource input;
private Object owner;
diff --git a/src/share/classes/java/beans/XMLEncoder.java b/src/share/classes/java/beans/XMLEncoder.java
index d4b37da581c6ca474df2a873618b6b8c7f851f90..3866a630187f568a47f490a7d34e769493714392 100644
--- a/src/share/classes/java/beans/XMLEncoder.java
+++ b/src/share/classes/java/beans/XMLEncoder.java
@@ -204,7 +204,7 @@ import java.nio.charset.UnsupportedCharsetException;
*
* @author Philip Milne
*/
-public class XMLEncoder extends Encoder {
+public class XMLEncoder extends Encoder implements AutoCloseable {
private final CharsetEncoder encoder;
private final String charset;
diff --git a/src/share/classes/java/io/Bits.java b/src/share/classes/java/io/Bits.java
index 4b65d817b18e5103a3a471e4b4d4da873c6fade6..3554c4fe2684bd7214b8f5b8ae791363234a7f07 100644
--- a/src/share/classes/java/io/Bits.java
+++ b/src/share/classes/java/io/Bits.java
@@ -41,51 +41,39 @@ class Bits {
}
static char getChar(byte[] b, int off) {
- return (char) (((b[off + 1] & 0xFF) << 0) +
- ((b[off + 0]) << 8));
+ return (char) ((b[off + 1] & 0xFF) +
+ (b[off] << 8));
}
static short getShort(byte[] b, int off) {
- return (short) (((b[off + 1] & 0xFF) << 0) +
- ((b[off + 0]) << 8));
+ return (short) ((b[off + 1] & 0xFF) +
+ (b[off] << 8));
}
static int getInt(byte[] b, int off) {
- return ((b[off + 3] & 0xFF) << 0) +
- ((b[off + 2] & 0xFF) << 8) +
+ return ((b[off + 3] & 0xFF) ) +
+ ((b[off + 2] & 0xFF) << 8) +
((b[off + 1] & 0xFF) << 16) +
- ((b[off + 0]) << 24);
+ ((b[off ] ) << 24);
}
static float getFloat(byte[] b, int off) {
- int i = ((b[off + 3] & 0xFF) << 0) +
- ((b[off + 2] & 0xFF) << 8) +
- ((b[off + 1] & 0xFF) << 16) +
- ((b[off + 0]) << 24);
- return Float.intBitsToFloat(i);
+ return Float.intBitsToFloat(getInt(b, off));
}
static long getLong(byte[] b, int off) {
- return ((b[off + 7] & 0xFFL) << 0) +
- ((b[off + 6] & 0xFFL) << 8) +
+ return ((b[off + 7] & 0xFFL) ) +
+ ((b[off + 6] & 0xFFL) << 8) +
((b[off + 5] & 0xFFL) << 16) +
((b[off + 4] & 0xFFL) << 24) +
((b[off + 3] & 0xFFL) << 32) +
((b[off + 2] & 0xFFL) << 40) +
((b[off + 1] & 0xFFL) << 48) +
- (((long) b[off + 0]) << 56);
+ (((long) b[off]) << 56);
}
static double getDouble(byte[] b, int off) {
- long j = ((b[off + 7] & 0xFFL) << 0) +
- ((b[off + 6] & 0xFFL) << 8) +
- ((b[off + 5] & 0xFFL) << 16) +
- ((b[off + 4] & 0xFFL) << 24) +
- ((b[off + 3] & 0xFFL) << 32) +
- ((b[off + 2] & 0xFFL) << 40) +
- ((b[off + 1] & 0xFFL) << 48) +
- (((long) b[off + 0]) << 56);
- return Double.longBitsToDouble(j);
+ return Double.longBitsToDouble(getLong(b, off));
}
/*
@@ -98,50 +86,38 @@ class Bits {
}
static void putChar(byte[] b, int off, char val) {
- b[off + 1] = (byte) (val >>> 0);
- b[off + 0] = (byte) (val >>> 8);
+ b[off + 1] = (byte) (val );
+ b[off ] = (byte) (val >>> 8);
}
static void putShort(byte[] b, int off, short val) {
- b[off + 1] = (byte) (val >>> 0);
- b[off + 0] = (byte) (val >>> 8);
+ b[off + 1] = (byte) (val );
+ b[off ] = (byte) (val >>> 8);
}
static void putInt(byte[] b, int off, int val) {
- b[off + 3] = (byte) (val >>> 0);
- b[off + 2] = (byte) (val >>> 8);
+ b[off + 3] = (byte) (val );
+ b[off + 2] = (byte) (val >>> 8);
b[off + 1] = (byte) (val >>> 16);
- b[off + 0] = (byte) (val >>> 24);
+ b[off ] = (byte) (val >>> 24);
}
static void putFloat(byte[] b, int off, float val) {
- int i = Float.floatToIntBits(val);
- b[off + 3] = (byte) (i >>> 0);
- b[off + 2] = (byte) (i >>> 8);
- b[off + 1] = (byte) (i >>> 16);
- b[off + 0] = (byte) (i >>> 24);
+ putInt(b, off, Float.floatToIntBits(val));
}
static void putLong(byte[] b, int off, long val) {
- b[off + 7] = (byte) (val >>> 0);
- b[off + 6] = (byte) (val >>> 8);
+ b[off + 7] = (byte) (val );
+ b[off + 6] = (byte) (val >>> 8);
b[off + 5] = (byte) (val >>> 16);
b[off + 4] = (byte) (val >>> 24);
b[off + 3] = (byte) (val >>> 32);
b[off + 2] = (byte) (val >>> 40);
b[off + 1] = (byte) (val >>> 48);
- b[off + 0] = (byte) (val >>> 56);
+ b[off ] = (byte) (val >>> 56);
}
static void putDouble(byte[] b, int off, double val) {
- long j = Double.doubleToLongBits(val);
- b[off + 7] = (byte) (j >>> 0);
- b[off + 6] = (byte) (j >>> 8);
- b[off + 5] = (byte) (j >>> 16);
- b[off + 4] = (byte) (j >>> 24);
- b[off + 3] = (byte) (j >>> 32);
- b[off + 2] = (byte) (j >>> 40);
- b[off + 1] = (byte) (j >>> 48);
- b[off + 0] = (byte) (j >>> 56);
+ putLong(b, off, Double.doubleToLongBits(val));
}
}
diff --git a/src/share/classes/java/io/Closeable.java b/src/share/classes/java/io/Closeable.java
index e47e70d6cda8e0781b4f6c32c758b1db7d5002ad..0fbb1217cd029e6a619de959075d25521444ff03 100644
--- a/src/share/classes/java/io/Closeable.java
+++ b/src/share/classes/java/io/Closeable.java
@@ -28,14 +28,14 @@ package java.io;
import java.io.IOException;
/**
- * A Closeable is a source or destination of data that can be closed.
+ * A {@code Closeable} is a source or destination of data that can be closed.
* The close method is invoked to release resources that the object is
* holding (such as open files).
*
* @since 1.5
*/
-public interface Closeable {
+public interface Closeable extends AutoCloseable {
/**
* Closes this stream and releases any system resources associated
@@ -45,5 +45,4 @@ public interface Closeable {
* @throws IOException if an I/O error occurs
*/
public void close() throws IOException;
-
}
diff --git a/src/share/classes/java/io/ObjectInput.java b/src/share/classes/java/io/ObjectInput.java
index 179760b3d15b45fc0fe6ddd28cad10832fe99b61..3c72518205a993da0a645e00810b4815cf3d864f 100644
--- a/src/share/classes/java/io/ObjectInput.java
+++ b/src/share/classes/java/io/ObjectInput.java
@@ -36,7 +36,7 @@ package java.io;
* @see java.io.ObjectInputStream
* @since JDK1.1
*/
-public interface ObjectInput extends DataInput {
+public interface ObjectInput extends DataInput, AutoCloseable {
/**
* Read and return an object. The class that implements this interface
* defines where the object is "read" from.
diff --git a/src/share/classes/java/io/ObjectOutput.java b/src/share/classes/java/io/ObjectOutput.java
index 33426dd39f2f92426b0e676b0049a8efd6cd722f..bf55305f388ad45d7751cbad2f0fc4e588c0620f 100644
--- a/src/share/classes/java/io/ObjectOutput.java
+++ b/src/share/classes/java/io/ObjectOutput.java
@@ -36,7 +36,7 @@ package java.io;
* @see java.io.ObjectInputStream
* @since JDK1.1
*/
-public interface ObjectOutput extends DataOutput {
+public interface ObjectOutput extends DataOutput, AutoCloseable {
/**
* Write an object to the underlying storage or stream. The
* class that implements this interface defines how the object is
diff --git a/src/share/classes/java/lang/AbstractStringBuilder.java b/src/share/classes/java/lang/AbstractStringBuilder.java
index f83da439c98bfe909b74567e9f2e048e280a4ba9..fad8ad6da66d1a5de46421d1127ad5a5087d9667 100644
--- a/src/share/classes/java/lang/AbstractStringBuilder.java
+++ b/src/share/classes/java/lang/AbstractStringBuilder.java
@@ -721,19 +721,18 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* {@code codePoint} isn't a valid Unicode code point
*/
public AbstractStringBuilder appendCodePoint(int codePoint) {
- if (!Character.isValidCodePoint(codePoint)) {
- throw new IllegalArgumentException();
- }
- int n = 1;
- if (codePoint >= Character.MIN_SUPPLEMENTARY_CODE_POINT) {
- n++;
- }
- ensureCapacityInternal(count + n);
- if (n == 1) {
- value[count++] = (char) codePoint;
- } else {
+ final int count = this.count;
+
+ if (Character.isBmpCodePoint(codePoint)) {
+ ensureCapacityInternal(count + 1);
+ value[count] = (char) codePoint;
+ this.count = count + 1;
+ } else if (Character.isValidCodePoint(codePoint)) {
+ ensureCapacityInternal(count + 2);
Character.toSurrogates(codePoint, value, count);
- count += n;
+ this.count = count + 2;
+ } else {
+ throw new IllegalArgumentException();
}
return this;
}
diff --git a/src/share/classes/java/lang/AutoCloseable.java b/src/share/classes/java/lang/AutoCloseable.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f7ed8e0dd618d5212a42ad5ffce1e592a6011c7
--- /dev/null
+++ b/src/share/classes/java/lang/AutoCloseable.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * A resource that must be closed when it is no longer needed.
+ *
+ * @author Josh Bloch
+ * @since 1.7
+ */
+public interface AutoCloseable {
+ /**
+ * Close this resource, relinquishing any underlying resources.
+ * This method is invoked automatically by the automatic resource
+ * management block construct.
+ *
+ *
Classes implementing this method are strongly encouraged to
+ * be declared to throw more specific exceptions (or no exception
+ * at all, if the close cannot fail).
+ *
+ * @throws Exception if this resource cannot be closed
+ */
+ void close() throws Exception;
+}
diff --git a/src/share/classes/java/lang/Character.java b/src/share/classes/java/lang/Character.java
index 14fce55811de2f078ed757244b50d6f49ea42fa6..69134bda77f1235c264b16bc8be0228558a919ae 100644
--- a/src/share/classes/java/lang/Character.java
+++ b/src/share/classes/java/lang/Character.java
@@ -24,6 +24,7 @@
*/
package java.lang;
+
import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
@@ -67,17 +68,16 @@ import java.util.Locale;
* definition of the U+n notation in the Unicode
* standard.)
*
- *
The set of characters from U+0000 to U+FFFF is sometimes
- * referred to as the Basic Multilingual Plane (BMP). Characters whose code points are greater
+ *
The set of characters from U+0000 to U+FFFF is
+ * sometimes referred to as the Basic Multilingual Plane (BMP).
+ * Characters whose code points are greater
* than U+FFFF are called supplementary characters. The Java
- * 2 platform uses the UTF-16 representation in char
- * arrays and in the String and StringBuffer
- * classes. In this representation, supplementary characters are
- * represented as a pair of char values, the first from
- * the high-surrogates range, (\uD800-\uDBFF), the
- * second from the low-surrogates range
- * (\uDC00-\uDFFF).
+ * platform uses the UTF-16 representation in char arrays and
+ * in the String and StringBuffer classes. In
+ * this representation, supplementary characters are represented as a pair
+ * of char values, the first from the high-surrogates
+ * range, (\uD800-\uDBFF), the second from the
+ * low-surrogates range (\uDC00-\uDFFF).
*
*
A char value, therefore, represents Basic
* Multilingual Plane (BMP) code points, including the surrogate
@@ -115,10 +115,12 @@ import java.util.Locale;
* @author Lee Boynton
* @author Guy Steele
* @author Akira Tanaka
+ * @author Martin Buchholz
+ * @author Ulf Zibis
* @since 1.0
*/
public final
-class Character extends Object implements java.io.Serializable, Comparable {
+class Character implements java.io.Serializable, Comparable {
/**
* The minimum radix available for conversion to and from strings.
* The constant value of this field is the smallest value permitted
@@ -127,10 +129,10 @@ class Character extends Object implements java.io.Serializable, ComparabletoString method of class
* Integer.
*
- * @see java.lang.Character#digit(char, int)
- * @see java.lang.Character#forDigit(int, int)
- * @see java.lang.Integer#toString(int, int)
- * @see java.lang.Integer#valueOf(java.lang.String)
+ * @see Character#digit(char, int)
+ * @see Character#forDigit(int, int)
+ * @see Integer#toString(int, int)
+ * @see Integer#valueOf(String)
*/
public static final int MIN_RADIX = 2;
@@ -142,10 +144,10 @@ class Character extends Object implements java.io.Serializable, ComparabletoString method of class
* Integer.
*
- * @see java.lang.Character#digit(char, int)
- * @see java.lang.Character#forDigit(int, int)
- * @see java.lang.Integer#toString(int, int)
- * @see java.lang.Integer#valueOf(java.lang.String)
+ * @see Character#digit(char, int)
+ * @see Character#forDigit(int, int)
+ * @see Integer#toString(int, int)
+ * @see Integer#valueOf(String)
*/
public static final int MAX_RADIX = 36;
@@ -155,7 +157,7 @@ class Character extends Object implements java.io.Serializable, ComparableClass instance representing the primitive type
@@ -171,230 +173,201 @@ class Character extends Object implements java.io.Serializable, Comparable TYPE = Class.getPrimitiveClass("char");
- /*
- * Normative general types
- */
-
- /*
- * General character types
- */
-
- /**
- * General category "Cn" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- UNASSIGNED = 0;
-
- /**
- * General category "Lu" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- UPPERCASE_LETTER = 1;
-
- /**
- * General category "Ll" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- LOWERCASE_LETTER = 2;
-
- /**
- * General category "Lt" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- TITLECASE_LETTER = 3;
-
- /**
- * General category "Lm" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- MODIFIER_LETTER = 4;
-
- /**
- * General category "Lo" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- OTHER_LETTER = 5;
-
- /**
- * General category "Mn" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- NON_SPACING_MARK = 6;
-
- /**
- * General category "Me" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- ENCLOSING_MARK = 7;
-
- /**
- * General category "Mc" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- COMBINING_SPACING_MARK = 8;
-
- /**
- * General category "Nd" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- DECIMAL_DIGIT_NUMBER = 9;
-
- /**
- * General category "Nl" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- LETTER_NUMBER = 10;
-
- /**
- * General category "No" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- OTHER_NUMBER = 11;
-
- /**
- * General category "Zs" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- SPACE_SEPARATOR = 12;
-
- /**
- * General category "Zl" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- LINE_SEPARATOR = 13;
-
- /**
- * General category "Zp" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- PARAGRAPH_SEPARATOR = 14;
-
- /**
- * General category "Cc" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- CONTROL = 15;
-
- /**
- * General category "Cf" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- FORMAT = 16;
-
- /**
- * General category "Co" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- PRIVATE_USE = 18;
-
- /**
- * General category "Cs" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- SURROGATE = 19;
-
- /**
- * General category "Pd" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- DASH_PUNCTUATION = 20;
-
- /**
- * General category "Ps" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- START_PUNCTUATION = 21;
-
- /**
- * General category "Pe" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- END_PUNCTUATION = 22;
-
- /**
- * General category "Pc" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- CONNECTOR_PUNCTUATION = 23;
-
- /**
- * General category "Po" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- OTHER_PUNCTUATION = 24;
-
- /**
- * General category "Sm" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- MATH_SYMBOL = 25;
-
- /**
- * General category "Sc" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- CURRENCY_SYMBOL = 26;
-
- /**
- * General category "Sk" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- MODIFIER_SYMBOL = 27;
-
- /**
- * General category "So" in the Unicode specification.
- * @since 1.1
- */
- public static final byte
- OTHER_SYMBOL = 28;
-
- /**
- * General category "Pi" in the Unicode specification.
- * @since 1.4
- */
- public static final byte
- INITIAL_QUOTE_PUNCTUATION = 29;
-
- /**
- * General category "Pf" in the Unicode specification.
- * @since 1.4
- */
- public static final byte
- FINAL_QUOTE_PUNCTUATION = 30;
+ /*
+ * Normative general types
+ */
+
+ /*
+ * General character types
+ */
+
+ /**
+ * General category "Cn" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte UNASSIGNED = 0;
+
+ /**
+ * General category "Lu" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte UPPERCASE_LETTER = 1;
+
+ /**
+ * General category "Ll" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte LOWERCASE_LETTER = 2;
+
+ /**
+ * General category "Lt" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte TITLECASE_LETTER = 3;
+
+ /**
+ * General category "Lm" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte MODIFIER_LETTER = 4;
+
+ /**
+ * General category "Lo" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte OTHER_LETTER = 5;
+
+ /**
+ * General category "Mn" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte NON_SPACING_MARK = 6;
+
+ /**
+ * General category "Me" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte ENCLOSING_MARK = 7;
+
+ /**
+ * General category "Mc" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte COMBINING_SPACING_MARK = 8;
+
+ /**
+ * General category "Nd" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte DECIMAL_DIGIT_NUMBER = 9;
+
+ /**
+ * General category "Nl" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte LETTER_NUMBER = 10;
+
+ /**
+ * General category "No" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte OTHER_NUMBER = 11;
+
+ /**
+ * General category "Zs" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte SPACE_SEPARATOR = 12;
+
+ /**
+ * General category "Zl" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte LINE_SEPARATOR = 13;
+
+ /**
+ * General category "Zp" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte PARAGRAPH_SEPARATOR = 14;
+
+ /**
+ * General category "Cc" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte CONTROL = 15;
+
+ /**
+ * General category "Cf" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte FORMAT = 16;
+
+ /**
+ * General category "Co" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte PRIVATE_USE = 18;
+
+ /**
+ * General category "Cs" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte SURROGATE = 19;
+
+ /**
+ * General category "Pd" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte DASH_PUNCTUATION = 20;
+
+ /**
+ * General category "Ps" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte START_PUNCTUATION = 21;
+
+ /**
+ * General category "Pe" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte END_PUNCTUATION = 22;
+
+ /**
+ * General category "Pc" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte CONNECTOR_PUNCTUATION = 23;
+
+ /**
+ * General category "Po" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte OTHER_PUNCTUATION = 24;
+
+ /**
+ * General category "Sm" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte MATH_SYMBOL = 25;
+
+ /**
+ * General category "Sc" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte CURRENCY_SYMBOL = 26;
+
+ /**
+ * General category "Sk" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte MODIFIER_SYMBOL = 27;
+
+ /**
+ * General category "So" in the Unicode specification.
+ * @since 1.1
+ */
+ public static final byte OTHER_SYMBOL = 28;
+
+ /**
+ * General category "Pi" in the Unicode specification.
+ * @since 1.4
+ */
+ public static final byte INITIAL_QUOTE_PUNCTUATION = 29;
+
+ /**
+ * General category "Pf" in the Unicode specification.
+ * @since 1.4
+ */
+ public static final byte FINAL_QUOTE_PUNCTUATION = 30;
/**
* Error flag. Use int (code point) to avoid confusion with U+FFFF.
*/
- static final int ERROR = 0xFFFFFFFF;
+ static final int ERROR = 0xFFFFFFFF;
/**
@@ -402,7 +375,7 @@ class Character extends Object implements java.io.Serializable, ComparableCharacter class is {@link Character.UnicodeBlock
- * UnicodeBlock}. Other portions of the Java API may define other
- * subsets for their own purposes.
+ * Character class is {@link Character.UnicodeBlock}.
+ * Other portions of the Java API may define other subsets for their
+ * own purposes.
*
* @since 1.2
*/
@@ -624,6 +597,7 @@ class Character extends Object implements java.io.Serializable, Comparablenull
* @param name The name of this subset
+ * @exception NullPointerException if name is null
*/
protected Subset(String name) {
if (name == null) {
@@ -662,6 +636,9 @@ class Character extends Object implements java.io.Serializable, Comparable map
+ = new HashMap(256);
/**
- * Create a UnicodeBlock with the given identifier name.
+ * Creates a UnicodeBlock with the given identifier name.
* This name must be the same as the block identifier.
*/
private UnicodeBlock(String idName) {
super(idName);
- map.put(idName.toUpperCase(Locale.US), this);
+ map.put(idName, this);
}
/**
- * Create a UnicodeBlock with the given identifier name and
+ * Creates a UnicodeBlock with the given identifier name and
* alias name.
*/
private UnicodeBlock(String idName, String alias) {
this(idName);
- map.put(alias.toUpperCase(Locale.US), this);
+ map.put(alias, this);
}
/**
- * Create a UnicodeBlock with the given identifier name and
+ * Creates a UnicodeBlock with the given identifier name and
* alias names.
*/
- private UnicodeBlock(String idName, String[] aliasName) {
+ private UnicodeBlock(String idName, String... aliases) {
this(idName);
- if (aliasName != null) {
- for(int x=0; xnull if the character is not a
* member of a defined block.
*
- *
Note: This method cannot handle supplementary
- * characters. To support all Unicode characters,
- * including supplementary characters, use the {@link
- * #of(int)} method.
+ *
Note: This method cannot handle
+ * supplementary
+ * characters. To support all Unicode characters, including
+ * supplementary characters, use the {@link #of(int)} method.
*
* @param c The character in question
* @return The UnicodeBlock instance representing the
@@ -2462,22 +2556,21 @@ class Character extends Object implements java.io.Serializable, Comparablenull if the character is not a member of a
* defined block.
*
- * @param codePoint the character (Unicode code point) in question.
+ * @param codePoint the character (Unicode code point) in question.
* @return The UnicodeBlock instance representing the
* Unicode block of which this character is a member, or
* null if the character is not a member of any
* Unicode block
- * @exception IllegalArgumentException if the specified
- * codePoint is an invalid Unicode code point.
- * @see Character#isValidCodePoint(int)
- * @since 1.5
+ * @exception IllegalArgumentException if the specified
+ * codePoint is an invalid Unicode code point.
+ * @see Character#isValidCodePoint(int)
+ * @since 1.5
*/
public static UnicodeBlock of(int codePoint) {
if (!isValidCodePoint(codePoint)) {
@@ -2519,7 +2612,7 @@ class Character extends Object implements java.io.Serializable, ComparableThe text representation of each constant UnicodeBlock identifier.
* For example, this method will return the {@link #BASIC_LATIN} block if
* provided with the "BASIC_LATIN" name. This form replaces all spaces and
- * hyphens in the canonical name with underscores.
+ * hyphens in the canonical name with underscores.
*
* Finally, character case is ignored for all of the valid block name forms.
* For example, "BASIC_LATIN" and "basic_latin" are both valid block names.
@@ -2538,7 +2631,7 @@ class Character extends Object implements java.io.Serializable, Comparable aliases;
static {
- aliases = new HashMap();
+ aliases = new HashMap(128);
aliases.put("ARAB", ARABIC);
aliases.put("ARMI", IMPERIAL_ARAMAIC);
aliases.put("ARMN", ARMENIAN);
@@ -3809,7 +3902,7 @@ class Character extends Object implements java.io.Serializable, Comparable= MIN_CODE_POINT && codePoint <= MAX_CODE_POINT;
+ // Optimized form of:
+ // codePoint >= MIN_CODE_POINT && codePoint <= MAX_CODE_POINT
+ int plane = codePoint >>> 16;
+ return plane < ((MAX_CODE_POINT + 1) >>> 16);
+ }
+
+ /**
+ * Determines whether the specified character (Unicode code point)
+ * is in the Basic Multilingual Plane (BMP).
+ * Such code points can be represented using a single {@code char}.
+ *
+ * @param codePoint the character (Unicode code point) to be tested
+ * @return {@code true} if the specified code point is between
+ * {@link #MIN_VALUE} and {@link #MAX_VALUE} inclusive;
+ * {@code false} otherwise.
+ * @since 1.7
+ */
+ public static boolean isBmpCodePoint(int codePoint) {
+ return codePoint >>> 16 == 0;
+ // Optimized form of:
+ // codePoint >= MIN_VALUE && codePoint <= MAX_VALUE
+ // We consistently use logical shift (>>>) to facilitate
+ // additional runtime optimizations.
}
/**
@@ -3930,7 +4045,7 @@ class Character extends Object implements java.io.Serializable, Comparable= MIN_SUPPLEMENTARY_CODE_POINT
- && codePoint <= MAX_CODE_POINT;
+ && codePoint < MAX_CODE_POINT + 1;
}
/**
@@ -3949,12 +4064,13 @@ class Character extends Object implements java.io.Serializable, Comparable= MIN_HIGH_SURROGATE && ch <= MAX_HIGH_SURROGATE;
+ // Help VM constant-fold; MAX_HIGH_SURROGATE + 1 == MIN_LOW_SURROGATE
+ return ch >= MIN_HIGH_SURROGATE && ch < (MAX_HIGH_SURROGATE + 1);
}
/**
@@ -3973,11 +4089,11 @@ class Character extends Object implements java.io.Serializable, Comparable= MIN_LOW_SURROGATE && ch <= MAX_LOW_SURROGATE;
+ return ch >= MIN_LOW_SURROGATE && ch < (MAX_LOW_SURROGATE + 1);
}
/**
@@ -4001,7 +4117,7 @@ class Character extends Object implements java.io.Serializable, Comparable= MIN_SURROGATE && ch <= MAX_SURROGATE;
+ return ch >= MIN_SURROGATE && ch < (MAX_SURROGATE + 1);
}
/**
@@ -4039,11 +4155,11 @@ class Character extends Object implements java.io.Serializable, Comparable= MIN_SUPPLEMENTARY_CODE_POINT? 2 : 1;
+ return codePoint >= MIN_SUPPLEMENTARY_CODE_POINT ? 2 : 1;
}
/**
@@ -4160,6 +4276,7 @@ class Character extends Object implements java.io.Serializable, Comparable
+ * high surrogate code unit) of the
+ *
+ * surrogate pair
+ * representing the specified supplementary character (Unicode
+ * code point) in the UTF-16 encoding. If the specified character
+ * is not a
+ * supplementary character,
+ * an unspecified {@code char} is returned.
+ *
+ *
If
+ * {@link #isSupplementaryCodePoint isSupplementaryCodePoint(x)}
+ * is {@code true}, then
+ * {@link #isHighSurrogate isHighSurrogate}{@code (highSurrogate(x))} and
+ * {@link #toCodePoint toCodePoint}{@code (highSurrogate(x), }{@link #lowSurrogate lowSurrogate}{@code (x)) == x}
+ * are also always {@code true}.
+ *
+ * @param codePoint a supplementary character (Unicode code point)
+ * @return the leading surrogate code unit used to represent the
+ * character in the UTF-16 encoding
+ * @since 1.7
+ */
+ public static char highSurrogate(int codePoint) {
+ return (char) ((codePoint >>> 10)
+ + (MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10)));
+ }
+
+ /**
+ * Returns the trailing surrogate (a
+ *
+ * low surrogate code unit) of the
+ *
+ * surrogate pair
+ * representing the specified supplementary character (Unicode
+ * code point) in the UTF-16 encoding. If the specified character
+ * is not a
+ * supplementary character,
+ * an unspecified {@code char} is returned.
+ *
+ *
If
+ * {@link #isSupplementaryCodePoint isSupplementaryCodePoint(x)}
+ * is {@code true}, then
+ * {@link #isLowSurrogate isLowSurrogate}{@code (lowSurrogate(x))} and
+ * {@link #toCodePoint toCodePoint}{@code (}{@link #highSurrogate highSurrogate}{@code (x), lowSurrogate(x)) == x}
+ * are also always {@code true}.
+ *
+ * @param codePoint a supplementary character (Unicode code point)
+ * @return the trailing surrogate code unit used to represent the
+ * character in the UTF-16 encoding
+ * @since 1.7
+ */
+ public static char lowSurrogate(int codePoint) {
+ return (char) ((codePoint & 0x3ff) + MIN_LOW_SURROGATE);
+ }
+
/**
* Converts the specified character (Unicode code point) to its
* UTF-16 representation. If the specified code point is a BMP
@@ -4311,15 +4486,15 @@ class Character extends Object implements java.io.Serializable, Comparable MAX_CODE_POINT) {
- throw new IllegalArgumentException();
- }
- if (codePoint < MIN_SUPPLEMENTARY_CODE_POINT) {
+ if (isBmpCodePoint(codePoint)) {
dst[dstIndex] = (char) codePoint;
return 1;
+ } else if (isValidCodePoint(codePoint)) {
+ toSurrogates(codePoint, dst, dstIndex);
+ return 2;
+ } else {
+ throw new IllegalArgumentException();
}
- toSurrogates(codePoint, dst, dstIndex);
- return 2;
}
/**
@@ -4339,22 +4514,21 @@ class Character extends Object implements java.io.Serializable, Comparable MAX_CODE_POINT) {
+ if (isBmpCodePoint(codePoint)) {
+ return new char[] { (char) codePoint };
+ } else if (isValidCodePoint(codePoint)) {
+ char[] result = new char[2];
+ toSurrogates(codePoint, result, 0);
+ return result;
+ } else {
throw new IllegalArgumentException();
}
- if (codePoint < MIN_SUPPLEMENTARY_CODE_POINT) {
- return new char[] { (char) codePoint };
- }
- char[] result = new char[2];
- toSurrogates(codePoint, result, 0);
- return result;
}
static void toSurrogates(int codePoint, char[] dst, int index) {
// We write elements "backwards" to guarantee all-or-nothing
- dst[index+1] = (char)((codePoint & 0x3ff) + MIN_LOW_SURROGATE);
- dst[index] = (char)((codePoint >>> 10)
- + (MIN_HIGH_SURROGATE - (MIN_SUPPLEMENTARY_CODE_POINT >>> 10)));
+ dst[index+1] = lowSurrogate(codePoint);
+ dst[index] = highSurrogate(codePoint);
}
/**
@@ -4385,13 +4559,12 @@ class Character extends Object implements java.io.Serializable, Comparable length || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
- int n = 0;
+ int n = endIndex - beginIndex;
for (int i = beginIndex; i < endIndex; ) {
- n++;
- if (isHighSurrogate(seq.charAt(i++))) {
- if (i < endIndex && isLowSurrogate(seq.charAt(i))) {
- i++;
- }
+ if (isHighSurrogate(seq.charAt(i++)) && i < endIndex &&
+ isLowSurrogate(seq.charAt(i))) {
+ n--;
+ i++;
}
}
return n;
@@ -4425,13 +4598,12 @@ class Character extends Object implements java.io.Serializable, Comparable= 0) {
int i;
for (i = 0; x < length && i < codePointOffset; i++) {
- if (isHighSurrogate(seq.charAt(x++))) {
- if (x < length && isLowSurrogate(seq.charAt(x))) {
- x++;
- }
+ if (isHighSurrogate(seq.charAt(x++)) && x < length &&
+ isLowSurrogate(seq.charAt(x))) {
+ x++;
}
}
if (i < codePointOffset) {
@@ -4482,10 +4653,9 @@ class Character extends Object implements java.io.Serializable, Comparable 0 && i < 0; i++) {
- if (isLowSurrogate(seq.charAt(--x))) {
- if (x > 0 && isHighSurrogate(seq.charAt(x-1))) {
- x--;
- }
+ if (isLowSurrogate(seq.charAt(--x)) && x > 0 &&
+ isHighSurrogate(seq.charAt(x-1))) {
+ x--;
}
}
if (i < 0) {
@@ -4544,10 +4714,9 @@ class Character extends Object implements java.io.Serializable, Comparable start && i < 0; i++) {
- if (isLowSurrogate(a[--x])) {
- if (x > start && isHighSurrogate(a[x-1])) {
- x--;
- }
+ if (isLowSurrogate(a[--x]) && x > start &&
+ isHighSurrogate(a[x-1])) {
+ x--;
}
}
if (i < 0) {
@@ -4569,7 +4737,7 @@ class Character extends Object implements java.io.Serializable, Comparable
* A character is lowercase if its general category type, provided
@@ -4594,10 +4762,10 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is lowercase;
* false otherwise.
- * @see java.lang.Character#isLowerCase(char)
- * @see java.lang.Character#isTitleCase(char)
- * @see java.lang.Character#toLowerCase(char)
- * @see java.lang.Character#getType(char)
+ * @see Character#isLowerCase(char)
+ * @see Character#isTitleCase(char)
+ * @see Character#toLowerCase(char)
+ * @see Character#getType(char)
*/
public static boolean isLowerCase(char ch) {
return isLowerCase((int)ch);
@@ -4624,17 +4792,17 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is lowercase;
* false otherwise.
- * @see java.lang.Character#isLowerCase(int)
- * @see java.lang.Character#isTitleCase(int)
- * @see java.lang.Character#toLowerCase(int)
- * @see java.lang.Character#getType(int)
+ * @see Character#isLowerCase(int)
+ * @see Character#isTitleCase(int)
+ * @see Character#toLowerCase(int)
+ * @see Character#getType(int)
* @since 1.5
*/
public static boolean isLowerCase(int codePoint) {
return getType(codePoint) == Character.LOWERCASE_LETTER;
}
- /**
+ /**
* Determines if the specified character is an uppercase character.
*
* A character is uppercase if its general category type, provided by
@@ -4658,10 +4826,10 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is uppercase;
* false otherwise.
- * @see java.lang.Character#isLowerCase(char)
- * @see java.lang.Character#isTitleCase(char)
- * @see java.lang.Character#toUpperCase(char)
- * @see java.lang.Character#getType(char)
+ * @see Character#isLowerCase(char)
+ * @see Character#isTitleCase(char)
+ * @see Character#toUpperCase(char)
+ * @see Character#getType(char)
* @since 1.0
*/
public static boolean isUpperCase(char ch) {
@@ -4687,10 +4855,10 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is uppercase;
* false otherwise.
- * @see java.lang.Character#isLowerCase(int)
- * @see java.lang.Character#isTitleCase(int)
- * @see java.lang.Character#toUpperCase(int)
- * @see java.lang.Character#getType(int)
+ * @see Character#isLowerCase(int)
+ * @see Character#isTitleCase(int)
+ * @see Character#toUpperCase(int)
+ * @see Character#getType(int)
* @since 1.5
*/
public static boolean isUpperCase(int codePoint) {
@@ -4728,10 +4896,10 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is titlecase;
* false otherwise.
- * @see java.lang.Character#isLowerCase(char)
- * @see java.lang.Character#isUpperCase(char)
- * @see java.lang.Character#toTitleCase(char)
- * @see java.lang.Character#getType(char)
+ * @see Character#isLowerCase(char)
+ * @see Character#isUpperCase(char)
+ * @see Character#toTitleCase(char)
+ * @see Character#getType(char)
* @since 1.0.2
*/
public static boolean isTitleCase(char ch) {
@@ -4764,10 +4932,10 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is titlecase;
* false otherwise.
- * @see java.lang.Character#isLowerCase(int)
- * @see java.lang.Character#isUpperCase(int)
- * @see java.lang.Character#toTitleCase(int)
- * @see java.lang.Character#getType(int)
+ * @see Character#isLowerCase(int)
+ * @see Character#isUpperCase(int)
+ * @see Character#toTitleCase(int)
+ * @see Character#getType(int)
* @since 1.5
*/
public static boolean isTitleCase(int codePoint) {
@@ -4805,9 +4973,9 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is a digit;
* false otherwise.
- * @see java.lang.Character#digit(char, int)
- * @see java.lang.Character#forDigit(int, int)
- * @see java.lang.Character#getType(char)
+ * @see Character#digit(char, int)
+ * @see Character#forDigit(int, int)
+ * @see Character#getType(char)
*/
public static boolean isDigit(char ch) {
return isDigit((int)ch);
@@ -4839,8 +5007,8 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is a digit;
* false otherwise.
- * @see java.lang.Character#forDigit(int, int)
- * @see java.lang.Character#getType(int)
+ * @see Character#forDigit(int, int)
+ * @see Character#getType(int)
* @since 1.5
*/
public static boolean isDigit(int codePoint) {
@@ -4864,12 +5032,12 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character has a defined meaning
* in Unicode; false otherwise.
- * @see java.lang.Character#isDigit(char)
- * @see java.lang.Character#isLetter(char)
- * @see java.lang.Character#isLetterOrDigit(char)
- * @see java.lang.Character#isLowerCase(char)
- * @see java.lang.Character#isTitleCase(char)
- * @see java.lang.Character#isUpperCase(char)
+ * @see Character#isDigit(char)
+ * @see Character#isLetter(char)
+ * @see Character#isLetterOrDigit(char)
+ * @see Character#isLowerCase(char)
+ * @see Character#isTitleCase(char)
+ * @see Character#isUpperCase(char)
* @since 1.0.2
*/
public static boolean isDefined(char ch) {
@@ -4888,12 +5056,12 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character has a defined meaning
* in Unicode; false otherwise.
- * @see java.lang.Character#isDigit(int)
- * @see java.lang.Character#isLetter(int)
- * @see java.lang.Character#isLetterOrDigit(int)
- * @see java.lang.Character#isLowerCase(int)
- * @see java.lang.Character#isTitleCase(int)
- * @see java.lang.Character#isUpperCase(int)
+ * @see Character#isDigit(int)
+ * @see Character#isLetter(int)
+ * @see Character#isLetterOrDigit(int)
+ * @see Character#isLowerCase(int)
+ * @see Character#isTitleCase(int)
+ * @see Character#isUpperCase(int)
* @since 1.5
*/
public static boolean isDefined(int codePoint) {
@@ -4925,15 +5093,15 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is a letter;
* false otherwise.
- * @see java.lang.Character#isDigit(char)
- * @see java.lang.Character#isJavaIdentifierStart(char)
- * @see java.lang.Character#isJavaLetter(char)
- * @see java.lang.Character#isJavaLetterOrDigit(char)
- * @see java.lang.Character#isLetterOrDigit(char)
- * @see java.lang.Character#isLowerCase(char)
- * @see java.lang.Character#isTitleCase(char)
- * @see java.lang.Character#isUnicodeIdentifierStart(char)
- * @see java.lang.Character#isUpperCase(char)
+ * @see Character#isDigit(char)
+ * @see Character#isJavaIdentifierStart(char)
+ * @see Character#isJavaLetter(char)
+ * @see Character#isJavaLetterOrDigit(char)
+ * @see Character#isLetterOrDigit(char)
+ * @see Character#isLowerCase(char)
+ * @see Character#isTitleCase(char)
+ * @see Character#isUnicodeIdentifierStart(char)
+ * @see Character#isUpperCase(char)
*/
public static boolean isLetter(char ch) {
return isLetter((int)ch);
@@ -4959,13 +5127,13 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is a letter;
* false otherwise.
- * @see java.lang.Character#isDigit(int)
- * @see java.lang.Character#isJavaIdentifierStart(int)
- * @see java.lang.Character#isLetterOrDigit(int)
- * @see java.lang.Character#isLowerCase(int)
- * @see java.lang.Character#isTitleCase(int)
- * @see java.lang.Character#isUnicodeIdentifierStart(int)
- * @see java.lang.Character#isUpperCase(int)
+ * @see Character#isDigit(int)
+ * @see Character#isJavaIdentifierStart(int)
+ * @see Character#isLetterOrDigit(int)
+ * @see Character#isLowerCase(int)
+ * @see Character#isTitleCase(int)
+ * @see Character#isUnicodeIdentifierStart(int)
+ * @see Character#isUpperCase(int)
* @since 1.5
*/
public static boolean isLetter(int codePoint) {
@@ -4993,12 +5161,12 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is a letter or digit;
* false otherwise.
- * @see java.lang.Character#isDigit(char)
- * @see java.lang.Character#isJavaIdentifierPart(char)
- * @see java.lang.Character#isJavaLetter(char)
- * @see java.lang.Character#isJavaLetterOrDigit(char)
- * @see java.lang.Character#isLetter(char)
- * @see java.lang.Character#isUnicodeIdentifierPart(char)
+ * @see Character#isDigit(char)
+ * @see Character#isJavaIdentifierPart(char)
+ * @see Character#isJavaLetter(char)
+ * @see Character#isJavaLetterOrDigit(char)
+ * @see Character#isLetter(char)
+ * @see Character#isUnicodeIdentifierPart(char)
* @since 1.0.2
*/
public static boolean isLetterOrDigit(char ch) {
@@ -5016,10 +5184,10 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is a letter or digit;
* false otherwise.
- * @see java.lang.Character#isDigit(int)
- * @see java.lang.Character#isJavaIdentifierPart(int)
- * @see java.lang.Character#isLetter(int)
- * @see java.lang.Character#isUnicodeIdentifierPart(int)
+ * @see Character#isDigit(int)
+ * @see Character#isJavaIdentifierPart(int)
+ * @see Character#isLetter(int)
+ * @see Character#isUnicodeIdentifierPart(int)
* @since 1.5
*/
public static boolean isLetterOrDigit(int codePoint) {
@@ -5048,12 +5216,12 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character may start a Java
* identifier; false otherwise.
- * @see java.lang.Character#isJavaLetterOrDigit(char)
- * @see java.lang.Character#isJavaIdentifierStart(char)
- * @see java.lang.Character#isJavaIdentifierPart(char)
- * @see java.lang.Character#isLetter(char)
- * @see java.lang.Character#isLetterOrDigit(char)
- * @see java.lang.Character#isUnicodeIdentifierStart(char)
+ * @see Character#isJavaLetterOrDigit(char)
+ * @see Character#isJavaIdentifierStart(char)
+ * @see Character#isJavaIdentifierPart(char)
+ * @see Character#isLetter(char)
+ * @see Character#isLetterOrDigit(char)
+ * @see Character#isUnicodeIdentifierStart(char)
* @since 1.02
* @deprecated Replaced by isJavaIdentifierStart(char).
*/
@@ -5083,13 +5251,13 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character may be part of a
* Java identifier; false otherwise.
- * @see java.lang.Character#isJavaLetter(char)
- * @see java.lang.Character#isJavaIdentifierStart(char)
- * @see java.lang.Character#isJavaIdentifierPart(char)
- * @see java.lang.Character#isLetter(char)
- * @see java.lang.Character#isLetterOrDigit(char)
- * @see java.lang.Character#isUnicodeIdentifierPart(char)
- * @see java.lang.Character#isIdentifierIgnorable(char)
+ * @see Character#isJavaLetter(char)
+ * @see Character#isJavaIdentifierStart(char)
+ * @see Character#isJavaIdentifierPart(char)
+ * @see Character#isLetter(char)
+ * @see Character#isLetterOrDigit(char)
+ * @see Character#isUnicodeIdentifierPart(char)
+ * @see Character#isIdentifierIgnorable(char)
* @since 1.02
* @deprecated Replaced by isJavaIdentifierPart(char).
*/
@@ -5119,9 +5287,9 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character may start a Java identifier;
* false otherwise.
- * @see java.lang.Character#isJavaIdentifierPart(char)
- * @see java.lang.Character#isLetter(char)
- * @see java.lang.Character#isUnicodeIdentifierStart(char)
+ * @see Character#isJavaIdentifierPart(char)
+ * @see Character#isLetter(char)
+ * @see Character#isUnicodeIdentifierStart(char)
* @see javax.lang.model.SourceVersion#isIdentifier(CharSequence)
* @since 1.1
*/
@@ -5148,9 +5316,9 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character may start a Java identifier;
* false otherwise.
- * @see java.lang.Character#isJavaIdentifierPart(int)
- * @see java.lang.Character#isLetter(int)
- * @see java.lang.Character#isUnicodeIdentifierStart(int)
+ * @see Character#isJavaIdentifierPart(int)
+ * @see Character#isLetter(int)
+ * @see Character#isUnicodeIdentifierStart(int)
* @see javax.lang.model.SourceVersion#isIdentifier(CharSequence)
* @since 1.5
*/
@@ -5184,10 +5352,10 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character may be part of a
* Java identifier; false otherwise.
- * @see java.lang.Character#isIdentifierIgnorable(char)
- * @see java.lang.Character#isJavaIdentifierStart(char)
- * @see java.lang.Character#isLetterOrDigit(char)
- * @see java.lang.Character#isUnicodeIdentifierPart(char)
+ * @see Character#isIdentifierIgnorable(char)
+ * @see Character#isJavaIdentifierStart(char)
+ * @see Character#isLetterOrDigit(char)
+ * @see Character#isUnicodeIdentifierPart(char)
* @see javax.lang.model.SourceVersion#isIdentifier(CharSequence)
* @since 1.1
*/
@@ -5217,10 +5385,10 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character may be part of a
* Java identifier; false otherwise.
- * @see java.lang.Character#isIdentifierIgnorable(int)
- * @see java.lang.Character#isJavaIdentifierStart(int)
- * @see java.lang.Character#isLetterOrDigit(int)
- * @see java.lang.Character#isUnicodeIdentifierPart(int)
+ * @see Character#isIdentifierIgnorable(int)
+ * @see Character#isJavaIdentifierStart(int)
+ * @see Character#isLetterOrDigit(int)
+ * @see Character#isUnicodeIdentifierPart(int)
* @see javax.lang.model.SourceVersion#isIdentifier(CharSequence)
* @since 1.5
*/
@@ -5248,9 +5416,9 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character may start a Unicode
* identifier; false otherwise.
- * @see java.lang.Character#isJavaIdentifierStart(char)
- * @see java.lang.Character#isLetter(char)
- * @see java.lang.Character#isUnicodeIdentifierPart(char)
+ * @see Character#isJavaIdentifierStart(char)
+ * @see Character#isLetter(char)
+ * @see Character#isUnicodeIdentifierPart(char)
* @since 1.1
*/
public static boolean isUnicodeIdentifierStart(char ch) {
@@ -5272,9 +5440,9 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character may start a Unicode
* identifier; false otherwise.
- * @see java.lang.Character#isJavaIdentifierStart(int)
- * @see java.lang.Character#isLetter(int)
- * @see java.lang.Character#isUnicodeIdentifierPart(int)
+ * @see Character#isJavaIdentifierStart(int)
+ * @see Character#isLetter(int)
+ * @see Character#isUnicodeIdentifierPart(int)
* @since 1.5
*/
public static boolean isUnicodeIdentifierStart(int codePoint) {
@@ -5306,10 +5474,10 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character may be part of a
* Unicode identifier; false otherwise.
- * @see java.lang.Character#isIdentifierIgnorable(char)
- * @see java.lang.Character#isJavaIdentifierPart(char)
- * @see java.lang.Character#isLetterOrDigit(char)
- * @see java.lang.Character#isUnicodeIdentifierStart(char)
+ * @see Character#isIdentifierIgnorable(char)
+ * @see Character#isJavaIdentifierPart(char)
+ * @see Character#isLetterOrDigit(char)
+ * @see Character#isUnicodeIdentifierStart(char)
* @since 1.1
*/
public static boolean isUnicodeIdentifierPart(char ch) {
@@ -5335,10 +5503,10 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character may be part of a
* Unicode identifier; false otherwise.
- * @see java.lang.Character#isIdentifierIgnorable(int)
- * @see java.lang.Character#isJavaIdentifierPart(int)
- * @see java.lang.Character#isLetterOrDigit(int)
- * @see java.lang.Character#isUnicodeIdentifierStart(int)
+ * @see Character#isIdentifierIgnorable(int)
+ * @see Character#isJavaIdentifierPart(int)
+ * @see Character#isLetterOrDigit(int)
+ * @see Character#isUnicodeIdentifierStart(int)
* @since 1.5
*/
public static boolean isUnicodeIdentifierPart(int codePoint) {
@@ -5372,8 +5540,8 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is an ignorable control
* character that may be part of a Java or Unicode identifier;
* false otherwise.
- * @see java.lang.Character#isJavaIdentifierPart(char)
- * @see java.lang.Character#isUnicodeIdentifierPart(char)
+ * @see Character#isJavaIdentifierPart(char)
+ * @see Character#isUnicodeIdentifierPart(char)
* @since 1.1
*/
public static boolean isIdentifierIgnorable(char ch) {
@@ -5402,8 +5570,8 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is an ignorable control
* character that may be part of a Java or Unicode identifier;
* false otherwise.
- * @see java.lang.Character#isJavaIdentifierPart(int)
- * @see java.lang.Character#isUnicodeIdentifierPart(int)
+ * @see Character#isJavaIdentifierPart(int)
+ * @see Character#isUnicodeIdentifierPart(int)
* @since 1.5
*/
public static boolean isIdentifierIgnorable(int codePoint) {
@@ -5419,7 +5587,7 @@ class Character extends Object implements java.io.Serializable, Comparabletrue for some ranges of
* characters, particularly those that are symbols or ideographs.
*
- *
In general, {@link java.lang.String#toLowerCase()} should be used to map
+ *
In general, {@link String#toLowerCase()} should be used to map
* characters to lowercase. String case mapping methods
* have several benefits over Character case mapping methods.
* String case mapping methods can perform locale-sensitive
@@ -5434,8 +5602,8 @@ class Character extends Object implements java.io.Serializable, Comparabletrue for some ranges of
* characters, particularly those that are symbols or ideographs.
*
- *
In general, {@link java.lang.String#toLowerCase()} should be used to map
+ *
In general, {@link String#toLowerCase()} should be used to map
* characters to lowercase. String case mapping methods
* have several benefits over Character case mapping methods.
* String case mapping methods can perform locale-sensitive
@@ -5461,8 +5629,8 @@ class Character extends Object implements java.io.Serializable, Comparabletrue for some ranges of
* characters, particularly those that are symbols or ideographs.
*
- *
In general, {@link java.lang.String#toUpperCase()} should be used to map
+ *
In general, {@link String#toUpperCase()} should be used to map
* characters to uppercase. String case mapping methods
* have several benefits over Character case mapping methods.
* String case mapping methods can perform locale-sensitive
@@ -5494,8 +5662,8 @@ class Character extends Object implements java.io.Serializable, Comparabletrue for some ranges of
* characters, particularly those that are symbols or ideographs.
*
- *
In general, {@link java.lang.String#toUpperCase()} should be used to map
+ *
In general, {@link String#toUpperCase()} should be used to map
* characters to uppercase. String case mapping methods
* have several benefits over Character case mapping methods.
* String case mapping methods can perform locale-sensitive
@@ -5521,8 +5689,8 @@ class Character extends Object implements java.io.Serializable, Comparableint
* value; -2 if the character has a numeric value that is not a
* nonnegative integer; -1 if the character has no numeric value.
- * @see java.lang.Character#forDigit(int, int)
- * @see java.lang.Character#isDigit(char)
+ * @see Character#forDigit(int, int)
+ * @see Character#isDigit(char)
* @since 1.1
*/
public static int getNumericValue(char ch) {
@@ -5732,8 +5900,8 @@ class Character extends Object implements java.io.Serializable, Comparableint
* value; -2 if the character has a numeric value that is not a
* nonnegative integer; -1 if the character has no numeric value.
- * @see java.lang.Character#forDigit(int, int)
- * @see java.lang.Character#isDigit(int)
+ * @see Character#forDigit(int, int)
+ * @see Character#isDigit(int)
* @since 1.5
*/
public static int getNumericValue(int codePoint) {
@@ -5760,8 +5928,8 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is ISO-LATIN-1 white
* space; false otherwise.
- * @see java.lang.Character#isSpaceChar(char)
- * @see java.lang.Character#isWhitespace(char)
+ * @see Character#isSpaceChar(char)
+ * @see Character#isWhitespace(char)
* @deprecated Replaced by isWhitespace(char).
*/
@Deprecated
@@ -5795,7 +5963,7 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is a space character;
* false otherwise.
- * @see java.lang.Character#isWhitespace(char)
+ * @see Character#isWhitespace(char)
* @since 1.1
*/
public static boolean isSpaceChar(char ch) {
@@ -5818,7 +5986,7 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is a space character;
* false otherwise.
- * @see java.lang.Character#isWhitespace(int)
+ * @see Character#isWhitespace(int)
* @since 1.5
*/
public static boolean isSpaceChar(int codePoint) {
@@ -5856,7 +6024,7 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is a Java whitespace
* character; false otherwise.
- * @see java.lang.Character#isSpaceChar(char)
+ * @see Character#isSpaceChar(char)
* @since 1.1
*/
public static boolean isWhitespace(char ch) {
@@ -5888,7 +6056,7 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is a Java whitespace
* character; false otherwise.
- * @see java.lang.Character#isSpaceChar(int)
+ * @see Character#isSpaceChar(int)
* @since 1.5
*/
public static boolean isWhitespace(int codePoint) {
@@ -5911,8 +6079,8 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is an ISO control character;
* false otherwise.
*
- * @see java.lang.Character#isSpaceChar(char)
- * @see java.lang.Character#isWhitespace(char)
+ * @see Character#isSpaceChar(char)
+ * @see Character#isWhitespace(char)
* @since 1.1
*/
public static boolean isISOControl(char ch) {
@@ -5929,13 +6097,16 @@ class Character extends Object implements java.io.Serializable, Comparabletrue if the character is an ISO control character;
* false otherwise.
- * @see java.lang.Character#isSpaceChar(int)
- * @see java.lang.Character#isWhitespace(int)
+ * @see Character#isSpaceChar(int)
+ * @see Character#isWhitespace(int)
* @since 1.5
*/
public static boolean isISOControl(int codePoint) {
- return (codePoint >= 0x0000 && codePoint <= 0x001F) ||
- (codePoint >= 0x007F && codePoint <= 0x009F);
+ // Optimized form of:
+ // (codePoint >= 0x00 && codePoint <= 0x1F) ||
+ // (codePoint >= 0x7F && codePoint <= 0x9F);
+ return codePoint <= 0x9F &&
+ (codePoint >= 0x7F || (codePoint >>> 5 == 0));
}
/**
@@ -5949,36 +6120,36 @@ class Character extends Object implements java.io.Serializable, Comparableint representing the
* character's general category.
- * @see java.lang.Character#COMBINING_SPACING_MARK
- * @see java.lang.Character#CONNECTOR_PUNCTUATION
- * @see java.lang.Character#CONTROL
- * @see java.lang.Character#CURRENCY_SYMBOL
- * @see java.lang.Character#DASH_PUNCTUATION
- * @see java.lang.Character#DECIMAL_DIGIT_NUMBER
- * @see java.lang.Character#ENCLOSING_MARK
- * @see java.lang.Character#END_PUNCTUATION
- * @see java.lang.Character#FINAL_QUOTE_PUNCTUATION
- * @see java.lang.Character#FORMAT
- * @see java.lang.Character#INITIAL_QUOTE_PUNCTUATION
- * @see java.lang.Character#LETTER_NUMBER
- * @see java.lang.Character#LINE_SEPARATOR
- * @see java.lang.Character#LOWERCASE_LETTER
- * @see java.lang.Character#MATH_SYMBOL
- * @see java.lang.Character#MODIFIER_LETTER
- * @see java.lang.Character#MODIFIER_SYMBOL
- * @see java.lang.Character#NON_SPACING_MARK
- * @see java.lang.Character#OTHER_LETTER
- * @see java.lang.Character#OTHER_NUMBER
- * @see java.lang.Character#OTHER_PUNCTUATION
- * @see java.lang.Character#OTHER_SYMBOL
- * @see java.lang.Character#PARAGRAPH_SEPARATOR
- * @see java.lang.Character#PRIVATE_USE
- * @see java.lang.Character#SPACE_SEPARATOR
- * @see java.lang.Character#START_PUNCTUATION
- * @see java.lang.Character#SURROGATE
- * @see java.lang.Character#TITLECASE_LETTER
- * @see java.lang.Character#UNASSIGNED
- * @see java.lang.Character#UPPERCASE_LETTER
+ * @see Character#COMBINING_SPACING_MARK
+ * @see Character#CONNECTOR_PUNCTUATION
+ * @see Character#CONTROL
+ * @see Character#CURRENCY_SYMBOL
+ * @see Character#DASH_PUNCTUATION
+ * @see Character#DECIMAL_DIGIT_NUMBER
+ * @see Character#ENCLOSING_MARK
+ * @see Character#END_PUNCTUATION
+ * @see Character#FINAL_QUOTE_PUNCTUATION
+ * @see Character#FORMAT
+ * @see Character#INITIAL_QUOTE_PUNCTUATION
+ * @see Character#LETTER_NUMBER
+ * @see Character#LINE_SEPARATOR
+ * @see Character#LOWERCASE_LETTER
+ * @see Character#MATH_SYMBOL
+ * @see Character#MODIFIER_LETTER
+ * @see Character#MODIFIER_SYMBOL
+ * @see Character#NON_SPACING_MARK
+ * @see Character#OTHER_LETTER
+ * @see Character#OTHER_NUMBER
+ * @see Character#OTHER_PUNCTUATION
+ * @see Character#OTHER_SYMBOL
+ * @see Character#PARAGRAPH_SEPARATOR
+ * @see Character#PRIVATE_USE
+ * @see Character#SPACE_SEPARATOR
+ * @see Character#START_PUNCTUATION
+ * @see Character#SURROGATE
+ * @see Character#TITLECASE_LETTER
+ * @see Character#UNASSIGNED
+ * @see Character#UPPERCASE_LETTER
* @since 1.1
*/
public static int getType(char ch) {
@@ -6047,9 +6218,9 @@ class Character extends Object implements java.io.Serializable, Comparablechar representation of the specified digit
* in the specified radix.
- * @see java.lang.Character#MIN_RADIX
- * @see java.lang.Character#MAX_RADIX
- * @see java.lang.Character#digit(char, int)
+ * @see Character#MIN_RADIX
+ * @see Character#MAX_RADIX
+ * @see Character#digit(char, int)
*/
public static char forDigit(int digit, int radix) {
if ((digit >= radix) || (digit < 0)) {
@@ -6230,10 +6401,10 @@ class Character extends Object implements java.io.Serializable, ComparableCharacter.ERROR)
* that indicates that a 1:M char mapping exists.
- * @see java.lang.Character#isLowerCase(char)
- * @see java.lang.Character#isUpperCase(char)
- * @see java.lang.Character#toLowerCase(char)
- * @see java.lang.Character#toTitleCase(char)
+ * @see Character#isLowerCase(char)
+ * @see Character#isUpperCase(char)
+ * @see Character#toLowerCase(char)
+ * @see Character#toTitleCase(char)
* @since 1.4
*/
static int toUpperCaseEx(int codePoint) {
@@ -6254,8 +6425,7 @@ class Character extends Object implements java.io.Serializable, ComparableString class represents character strings. All
* string literals in Java programs, such as "abc", are
@@ -99,6 +98,8 @@ import java.util.regex.PatternSyntaxException;
*
* @author Lee Boynton
* @author Arthur van Hoff
+ * @author Martin Buchholz
+ * @author Ulf Zibis
* @see java.lang.Object#toString()
* @see java.lang.StringBuffer
* @see java.lang.StringBuilder
@@ -273,32 +274,32 @@ public final class String
throw new StringIndexOutOfBoundsException(offset + count);
}
+ final int end = offset + count;
+
// Pass 1: Compute precise size of char[]
- int n = 0;
- for (int i = offset; i < offset + count; i++) {
+ int n = count;
+ for (int i = offset; i < end; i++) {
int c = codePoints[i];
- if (c >= Character.MIN_CODE_POINT &&
- c < Character.MIN_SUPPLEMENTARY_CODE_POINT)
- n += 1;
- else if (Character.isSupplementaryCodePoint(c))
- n += 2;
+ if (Character.isBmpCodePoint(c))
+ continue;
+ else if (Character.isValidCodePoint(c))
+ n++;
else throw new IllegalArgumentException(Integer.toString(c));
}
// Pass 2: Allocate and fill in char[]
- char[] v = new char[n];
- for (int i = offset, j = 0; i < offset + count; i++) {
+ final char[] v = new char[n];
+
+ for (int i = offset, j = 0; i < end; i++, j++) {
int c = codePoints[i];
- if (c < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
- v[j++] = (char) c;
- } else {
- Character.toSurrogates(c, v, j);
- j += 2;
- }
+ if (Character.isBmpCodePoint(c))
+ v[j] = (char) c;
+ else
+ Character.toSurrogates(c, v, j++);
}
this.value = v;
- this.count = v.length;
+ this.count = n;
this.offset = 0;
}
@@ -1573,9 +1574,6 @@ public final class String
* if the character does not occur.
*/
public int indexOf(int ch, int fromIndex) {
- int max = offset + count;
- char v[] = value;
-
if (fromIndex < 0) {
fromIndex = 0;
} else if (fromIndex >= count) {
@@ -1583,29 +1581,36 @@ public final class String
return -1;
}
- int i = offset + fromIndex;
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
- for (; i < max ; i++) {
- if (v[i] == ch) {
+ final char[] value = this.value;
+ final int offset = this.offset;
+ final int max = offset + count;
+ for (int i = offset + fromIndex; i < max ; i++) {
+ if (value[i] == ch) {
return i - offset;
}
}
return -1;
+ } else {
+ return indexOfSupplementary(ch, fromIndex);
}
+ }
- if (ch <= Character.MAX_CODE_POINT) {
- // handle supplementary characters here
- char[] surrogates = Character.toChars(ch);
- for (; i < max; i++) {
- if (v[i] == surrogates[0]) {
- if (i + 1 == max) {
- break;
- }
- if (v[i+1] == surrogates[1]) {
- return i - offset;
- }
+ /**
+ * Handles (rare) calls of indexOf with a supplementary character.
+ */
+ private int indexOfSupplementary(int ch, int fromIndex) {
+ if (Character.isValidCodePoint(ch)) {
+ final char[] value = this.value;
+ final int offset = this.offset;
+ final char hi = Character.highSurrogate(ch);
+ final char lo = Character.lowSurrogate(ch);
+ final int max = offset + count - 1;
+ for (int i = offset + fromIndex; i < max; i++) {
+ if (value[i] == hi && value[i+1] == lo) {
+ return i - offset;
}
}
}
@@ -1674,34 +1679,36 @@ public final class String
* if the character does not occur before that point.
*/
public int lastIndexOf(int ch, int fromIndex) {
- int min = offset;
- char v[] = value;
-
- int i = offset + ((fromIndex >= count) ? count - 1 : fromIndex);
-
if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
// handle most cases here (ch is a BMP code point or a
// negative value (invalid code point))
- for (; i >= min ; i--) {
- if (v[i] == ch) {
+ final char[] value = this.value;
+ final int offset = this.offset;
+ int i = offset + Math.min(fromIndex, count - 1);
+ for (; i >= offset ; i--) {
+ if (value[i] == ch) {
return i - offset;
}
}
return -1;
+ } else {
+ return lastIndexOfSupplementary(ch, fromIndex);
}
+ }
- int max = offset + count;
- if (ch <= Character.MAX_CODE_POINT) {
- // handle supplementary characters here
- char[] surrogates = Character.toChars(ch);
- for (; i >= min; i--) {
- if (v[i] == surrogates[0]) {
- if (i + 1 == max) {
- break;
- }
- if (v[i+1] == surrogates[1]) {
- return i - offset;
- }
+ /**
+ * Handles (rare) calls of lastIndexOf with a supplementary character.
+ */
+ private int lastIndexOfSupplementary(int ch, int fromIndex) {
+ if (Character.isValidCodePoint(ch)) {
+ final char[] value = this.value;
+ final int offset = this.offset;
+ char hi = Character.highSurrogate(ch);
+ char lo = Character.lowSurrogate(ch);
+ int i = offset + Math.min(fromIndex, count - 2);
+ for (; i >= offset; i--) {
+ if (value[i] == hi && value[i+1] == lo) {
+ return i - offset;
}
}
}
@@ -1710,18 +1717,17 @@ public final class String
/**
* Returns the index within this string of the first occurrence of the
- * specified substring. The integer returned is the smallest value
- * k such that:
+ * specified substring.
+ *
+ *
The returned index is the smallest value k for which:
*
* this.startsWith(str, k)
*
- * is true.
+ * If no such value of k exists, then {@code -1} is returned.
*
- * @param str any string.
- * @return if the string argument occurs as a substring within this
- * object, then the index of the first character of the first
- * such substring is returned; if it does not occur as a
- * substring, -1 is returned.
+ * @param str the substring to search for.
+ * @return the index of the first occurrence of the specified substring,
+ * or {@code -1} if there is no such occurrence.
*/
public int indexOf(String str) {
return indexOf(str, 0);
@@ -1729,17 +1735,19 @@ public final class String
/**
* Returns the index within this string of the first occurrence of the
- * specified substring, starting at the specified index. The integer
- * returned is the smallest value k for which:
+ * specified substring, starting at the specified index.
+ *
+ *
The returned index is the smallest value k for which:
*
- * k >= Math.min(fromIndex, this.length()) && this.startsWith(str, k)
+ * k >= fromIndex && this.startsWith(str, k)
*
- * If no such value of k exists, then -1 is returned.
+ * If no such value of k exists, then {@code -1} is returned.
*
- * @param str the substring for which to search.
+ * @param str the substring to search for.
* @param fromIndex the index from which to start the search.
- * @return the index within this string of the first occurrence of the
- * specified substring, starting at the specified index.
+ * @return the index of the first occurrence of the specified substring,
+ * starting at the specified index,
+ * or {@code -1} if there is no such occurrence.
*/
public int indexOf(String str, int fromIndex) {
return indexOf(value, offset, count,
@@ -1798,20 +1806,19 @@ public final class String
}
/**
- * Returns the index within this string of the rightmost occurrence
- * of the specified substring. The rightmost empty string "" is
- * considered to occur at the index value this.length().
- * The returned index is the largest value k such that
+ * Returns the index within this string of the last occurrence of the
+ * specified substring. The last occurrence of the empty string ""
+ * is considered to occur at the index value {@code this.length()}.
+ *
+ *
The returned index is the largest value k for which:
*
- * is true.
+ * If no such value of k exists, then {@code -1} is returned.
*
* @param str the substring to search for.
- * @return if the string argument occurs one or more times as a substring
- * within this object, then the index of the first character of
- * the last such substring is returned. If it does not occur as
- * a substring, -1 is returned.
+ * @return the index of the last occurrence of the specified substring,
+ * or {@code -1} if there is no such occurrence.
*/
public int lastIndexOf(String str) {
return lastIndexOf(str, count);
@@ -1820,16 +1827,18 @@ public final class String
/**
* Returns the index within this string of the last occurrence of the
* specified substring, searching backward starting at the specified index.
- * The integer returned is the largest value k such that:
+ *
+ *
The returned index is the largest value k for which:
*
- * k <= Math.min(fromIndex, this.length()) && this.startsWith(str, k)
+ * k <= fromIndex && this.startsWith(str, k)
*
- * If no such value of k exists, then -1 is returned.
+ * If no such value of k exists, then {@code -1} is returned.
*
* @param str the substring to search for.
* @param fromIndex the index to start the search from.
- * @return the index within this string of the last occurrence of the
- * specified substring.
+ * @return the index of the last occurrence of the specified substring,
+ * searching backward from the specified index,
+ * or {@code -1} if there is no such occurrence.
*/
public int lastIndexOf(String str, int fromIndex) {
return lastIndexOf(value, offset, count,
diff --git a/src/share/classes/java/lang/System.java b/src/share/classes/java/lang/System.java
index a317dabc596e54bea16ac43c59c928973f566c5a..39c6a5888d16912f0814b6a705f0f14b81b0f6eb 100644
--- a/src/share/classes/java/lang/System.java
+++ b/src/share/classes/java/lang/System.java
@@ -69,7 +69,7 @@ public final class System {
* corresponds to keyboard input or another input source specified by
* the host environment or user.
*/
- public final static InputStream in = nullInputStream();
+ public final static InputStream in = null;
/**
* The "standard" output stream. This stream is already
@@ -96,7 +96,7 @@ public final class System {
* @see java.io.PrintStream#println(java.lang.Object)
* @see java.io.PrintStream#println(java.lang.String)
*/
- public final static PrintStream out = nullPrintStream();
+ public final static PrintStream out = null;
/**
* The "standard" error output stream. This stream is already
@@ -110,7 +110,7 @@ public final class System {
* variable out, has been redirected to a file or other
* destination that is typically not continuously monitored.
*/
- public final static PrintStream err = nullPrintStream();
+ public final static PrintStream err = null;
/* The security manager for the system.
*/
@@ -1092,26 +1092,6 @@ public final class System {
*/
public static native String mapLibraryName(String libname);
- /**
- * The following two methods exist because in, out, and err must be
- * initialized to null. The compiler, however, cannot be permitted to
- * inline access to them, since they are later set to more sensible values
- * by initializeSystemClass().
- */
- private static InputStream nullInputStream() throws NullPointerException {
- if (currentTimeMillis() > 0) {
- return null;
- }
- throw new NullPointerException();
- }
-
- private static PrintStream nullPrintStream() throws NullPointerException {
- if (currentTimeMillis() > 0) {
- return null;
- }
- throw new NullPointerException();
- }
-
/**
* Initialize the system class. Called after thread initialization.
*/
diff --git a/src/share/classes/java/lang/Throwable.java b/src/share/classes/java/lang/Throwable.java
index ba89aa67493707848e30a1e6a81fe9a6390524d4..58478f90af4a238782eb6de5e2bd9fbb0eab418c 100644
--- a/src/share/classes/java/lang/Throwable.java
+++ b/src/share/classes/java/lang/Throwable.java
@@ -25,6 +25,7 @@
package java.lang;
import java.io.*;
+import java.util.*;
/**
* The Throwable class is the superclass of all errors and
@@ -102,7 +103,7 @@ import java.io.*;
* lowLevelOp();
* } catch (LowLevelException le) {
* throw (HighLevelException)
- new HighLevelException().initCause(le); // Legacy constructor
+ * new HighLevelException().initCause(le); // Legacy constructor
* }
*
*
@@ -192,6 +193,24 @@ public class Throwable implements Serializable {
* nulled out when fillInStackTrace is called.
*/
+ /**
+ * The list of suppressed exceptions, as returned by
+ * {@link #getSuppressedExceptions()}.
+ *
+ * @serial
+ * @since 1.7
+ */
+ private List suppressedExceptions = Collections.emptyList();
+
+ /** Message for trying to suppress a null exception. */
+ private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception.";
+
+ /** Caption for labeling causative exception stack traces */
+ private static final String CAUSE_CAPTION = "Caused by: ";
+
+ /** Caption for labeling suppressed exception stack traces */
+ private static final String SUPPRESSED_CAPTION = "Suppressed: ";
+
/**
* Constructs a new throwable with null as its detail message.
* The cause is not initialized, and may subsequently be initialized by a
@@ -469,6 +488,52 @@ public class Throwable implements Serializable {
* class LowLevelException extends Exception {
* }
*
+ * As of release 7, the platform supports the notion of
+ * suppressed exceptions (in conjunction with automatic
+ * resource management blocks). Any exceptions that were
+ * suppressed in order to deliver an exception are printed out
+ * beneath the stack trace. The format of this information
+ * depends on the implementation, but the following example may be
+ * regarded as typical:
+ *
+ *
+ * Exception in thread "main" java.lang.Exception: Something happened
+ * at Foo.bar(Foo.java:10)
+ * at Foo.main(Foo.java:5)
+ * Suppressed: Resource$CloseFailException: Resource ID = 0
+ * at Resource.close(Resource.java:26)
+ * at Foo.bar(Foo.java:9)
+ * ... 1 more
+ *
+ * Note that the "... n more" notation is used on suppressed exceptions
+ * just at it is used on causes. Unlike causes, suppressed exceptions are
+ * indented beyond their "containing exceptions."
+ *
+ *
An exception can have both a cause and one or more suppressed
+ * exceptions:
+ *
+ * Exception in thread "main" java.lang.Exception: Main block
+ * at Foo3.main(Foo3.java:7)
+ * Suppressed: Resource$CloseFailException: Resource ID = 2
+ * at Resource.close(Resource.java:26)
+ * at Foo3.main(Foo3.java:5)
+ * Suppressed: Resource$CloseFailException: Resource ID = 1
+ * at Resource.close(Resource.java:26)
+ * at Foo3.main(Foo3.java:5)
+ * Caused by: java.lang.Exception: I did it
+ * at Foo3.main(Foo3.java:8)
+ *
+ * Likewise, a suppressed exception can have a cause:
+ *
+ * Exception in thread "main" java.lang.Exception: Main block
+ * at Foo4.main(Foo4.java:6)
+ * Suppressed: Resource2$CloseFailException: Resource ID = 1
+ * at Resource2.close(Resource2.java:20)
+ * at Foo4.main(Foo4.java:5)
+ * Caused by: java.lang.Exception: Rats, you caught me
+ * at Resource2$CloseFailException.(Resource2.java:45)
+ * ... 2 more
+ *
*/
public void printStackTrace() {
printStackTrace(System.err);
@@ -480,44 +545,71 @@ public class Throwable implements Serializable {
* @param s PrintStream to use for output
*/
public void printStackTrace(PrintStream s) {
- synchronized (s) {
+ printStackTrace(new WrappedPrintStream(s));
+ }
+
+ private void printStackTrace(PrintStreamOrWriter s) {
+ Set dejaVu = new HashSet();
+ dejaVu.add(this);
+
+ synchronized (s.lock()) {
+ // Print our stack trace
s.println(this);
StackTraceElement[] trace = getOurStackTrace();
- for (int i=0; i < trace.length; i++)
- s.println("\tat " + trace[i]);
+ for (StackTraceElement traceElement : trace)
+ s.println("\tat " + traceElement);
+
+ // Print suppressed exceptions, if any
+ for (Throwable se : suppressedExceptions)
+ se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
+ // Print cause, if any
Throwable ourCause = getCause();
if (ourCause != null)
- ourCause.printStackTraceAsCause(s, trace);
+ ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, "", dejaVu);
}
}
/**
- * Print our stack trace as a cause for the specified stack trace.
+ * Print our stack trace as an enclosed exception for the specified
+ * stack trace.
*/
- private void printStackTraceAsCause(PrintStream s,
- StackTraceElement[] causedTrace)
- {
- // assert Thread.holdsLock(s);
-
- // Compute number of frames in common between this and caused
- StackTraceElement[] trace = getOurStackTrace();
- int m = trace.length-1, n = causedTrace.length-1;
- while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
- m--; n--;
+ private void printEnclosedStackTrace(PrintStreamOrWriter s,
+ StackTraceElement[] enclosingTrace,
+ String caption,
+ String prefix,
+ Set dejaVu) {
+ assert Thread.holdsLock(s.lock());
+ if (dejaVu.contains(this)) {
+ s.println("\t[CIRCULAR REFERENCE:" + this + "]");
+ } else {
+ dejaVu.add(this);
+ // Compute number of frames in common between this and enclosing trace
+ StackTraceElement[] trace = getOurStackTrace();
+ int m = trace.length - 1;
+ int n = enclosingTrace.length - 1;
+ while (m >= 0 && n >=0 && trace[m].equals(enclosingTrace[n])) {
+ m--; n--;
+ }
+ int framesInCommon = trace.length - 1 - m;
+
+ // Print our stack trace
+ s.println(prefix + caption + this);
+ for (int i = 0; i <= m; i++)
+ s.println(prefix + "\tat " + trace[i]);
+ if (framesInCommon != 0)
+ s.println(prefix + "\t... " + framesInCommon + " more");
+
+ // Print suppressed exceptions, if any
+ for (Throwable se : suppressedExceptions)
+ se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
+ prefix +"\t", dejaVu);
+
+ // Print cause, if any
+ Throwable ourCause = getCause();
+ if (ourCause != null)
+ ourCause.printEnclosedStackTrace(s, trace, CAUSE_CAPTION, prefix, dejaVu);
}
- int framesInCommon = trace.length - 1 - m;
-
- s.println("Caused by: " + this);
- for (int i=0; i <= m; i++)
- s.println("\tat " + trace[i]);
- if (framesInCommon != 0)
- s.println("\t... " + framesInCommon + " more");
-
- // Recurse if we have a cause
- Throwable ourCause = getCause();
- if (ourCause != null)
- ourCause.printStackTraceAsCause(s, trace);
}
/**
@@ -528,44 +620,51 @@ public class Throwable implements Serializable {
* @since JDK1.1
*/
public void printStackTrace(PrintWriter s) {
- synchronized (s) {
- s.println(this);
- StackTraceElement[] trace = getOurStackTrace();
- for (int i=0; i < trace.length; i++)
- s.println("\tat " + trace[i]);
-
- Throwable ourCause = getCause();
- if (ourCause != null)
- ourCause.printStackTraceAsCause(s, trace);
- }
+ printStackTrace(new WrappedPrintWriter(s));
}
/**
- * Print our stack trace as a cause for the specified stack trace.
+ * Wrapper class for PrintStream and PrintWriter to enable a single
+ * implementation of printStackTrace.
*/
- private void printStackTraceAsCause(PrintWriter s,
- StackTraceElement[] causedTrace)
- {
- // assert Thread.holdsLock(s);
+ private abstract static class PrintStreamOrWriter {
+ /** Returns the object to be locked when using this StreamOrWriter */
+ abstract Object lock();
+
+ /** Prints the specified string as a line on this StreamOrWriter */
+ abstract void println(Object o);
+ }
+
+ private static class WrappedPrintStream extends PrintStreamOrWriter {
+ private final PrintStream printStream;
+
+ WrappedPrintStream(PrintStream printStream) {
+ this.printStream = printStream;
+ }
+
+ Object lock() {
+ return printStream;
+ }
+
+ void println(Object o) {
+ printStream.println(o);
+ }
+ }
+
+ private static class WrappedPrintWriter extends PrintStreamOrWriter {
+ private final PrintWriter printWriter;
+
+ WrappedPrintWriter(PrintWriter printWriter) {
+ this.printWriter = printWriter;
+ }
+
+ Object lock() {
+ return printWriter;
+ }
- // Compute number of frames in common between this and caused
- StackTraceElement[] trace = getOurStackTrace();
- int m = trace.length-1, n = causedTrace.length-1;
- while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) {
- m--; n--;
+ void println(Object o) {
+ printWriter.println(o);
}
- int framesInCommon = trace.length - 1 - m;
-
- s.println("Caused by: " + this);
- for (int i=0; i <= m; i++)
- s.println("\tat " + trace[i]);
- if (framesInCommon != 0)
- s.println("\t... " + framesInCommon + " more");
-
- // Recurse if we have a cause
- Throwable ourCause = getCause();
- if (ourCause != null)
- ourCause.printStackTraceAsCause(s, trace);
}
/**
@@ -667,10 +766,60 @@ public class Throwable implements Serializable {
*/
native StackTraceElement getStackTraceElement(int index);
- private synchronized void writeObject(java.io.ObjectOutputStream s)
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException {
+ s.defaultReadObject(); // read in all fields
+ List suppressed = Collections.emptyList();
+ if (suppressedExceptions != null &&
+ !suppressedExceptions.isEmpty()) { // Copy Throwables to new list
+ suppressed = new ArrayList();
+ for(Throwable t : suppressedExceptions) {
+ if (t == null)
+ throw new NullPointerException(NULL_CAUSE_MESSAGE);
+ suppressed.add(t);
+ }
+ }
+ suppressedExceptions = suppressed;
+ }
+
+ private synchronized void writeObject(ObjectOutputStream s)
throws IOException
{
getOurStackTrace(); // Ensure that stackTrace field is initialized.
s.defaultWriteObject();
}
+
+ /**
+ * Adds the specified exception to the list of exceptions that
+ * were suppressed, typically by the automatic resource management
+ * statement, in order to deliver this exception.
+ *
+ * @param exception the exception to be added to the list of
+ * suppressed exceptions
+ * @throws NullPointerException if {@code exception} is null
+ * @since 1.7
+ */
+ public synchronized void addSuppressedException(Throwable exception) {
+ if (exception == null)
+ throw new NullPointerException(NULL_CAUSE_MESSAGE);
+
+ if (suppressedExceptions.size() == 0)
+ suppressedExceptions = new ArrayList();
+ suppressedExceptions.add(exception);
+ }
+
+ private static final Throwable[] EMPTY_THROWABLE_ARRAY = new Throwable[0];
+
+ /**
+ * Returns an array containing all of the exceptions that were
+ * suppressed, typically by the automatic resource management
+ * statement, in order to deliver this exception.
+ *
+ * @return an array containing all of the exceptions that were
+ * suppressed to deliver this exception.
+ * @since 1.7
+ */
+ public Throwable[] getSuppressedExceptions() {
+ return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
+ }
}
diff --git a/src/share/classes/java/net/Inet6Address.java b/src/share/classes/java/net/Inet6Address.java
index 521dd499eac87f812502e4f2e37bd03a8d25147f..d2b25af8661764e2465df90c549404efb5d2d7bc 100644
--- a/src/share/classes/java/net/Inet6Address.java
+++ b/src/share/classes/java/net/Inet6Address.java
@@ -427,8 +427,9 @@ class Inet6Address extends InetAddress {
try {
scope_id = deriveNumericScope (scope_ifname);
} catch (UnknownHostException e) {
- // should not happen
- assert false;
+ // typically should not happen, but it may be that
+ // the machine being used for deserialization has
+ // the same interface name but without IPv6 configured.
}
}
} catch (SocketException e) {}
diff --git a/src/share/classes/java/nio/Bits.java b/src/share/classes/java/nio/Bits.java
index 274661a0a3b15f7ed9317fdaef850c4ca967ef62..4adf3e48066c663306f6d45a9bc2a1bdab48c5e4 100644
--- a/src/share/classes/java/nio/Bits.java
+++ b/src/share/classes/java/nio/Bits.java
@@ -41,25 +41,19 @@ class Bits { // package-private
// -- Swapping --
static short swap(short x) {
- return (short)((x << 8) |
- ((char)x >>> 8));
+ return Short.reverseBytes(x);
}
static char swap(char x) {
- return (char)((x << 8) |
- (x >>> 8));
+ return Character.reverseBytes(x);
}
static int swap(int x) {
- return ((x << 24) |
- ((x & 0x0000ff00) << 8) |
- ((x & 0x00ff0000) >>> 8) |
- (x >>> 24));
+ return Integer.reverseBytes(x);
}
static long swap(long x) {
- return (((long)swap((int)x) << 32) |
- ((long)swap((int)(x >>> 32)) & 0xffffffffL));
+ return Long.reverseBytes(x);
}
@@ -71,52 +65,52 @@ class Bits { // package-private
static char getCharL(ByteBuffer bb, int bi) {
return makeChar(bb._get(bi + 1),
- bb._get(bi + 0));
+ bb._get(bi ));
}
static char getCharL(long a) {
return makeChar(_get(a + 1),
- _get(a + 0));
+ _get(a ));
}
static char getCharB(ByteBuffer bb, int bi) {
- return makeChar(bb._get(bi + 0),
+ return makeChar(bb._get(bi ),
bb._get(bi + 1));
}
static char getCharB(long a) {
- return makeChar(_get(a + 0),
+ return makeChar(_get(a ),
_get(a + 1));
}
static char getChar(ByteBuffer bb, int bi, boolean bigEndian) {
- return (bigEndian ? getCharB(bb, bi) : getCharL(bb, bi));
+ return bigEndian ? getCharB(bb, bi) : getCharL(bb, bi);
}
static char getChar(long a, boolean bigEndian) {
- return (bigEndian ? getCharB(a) : getCharL(a));
+ return bigEndian ? getCharB(a) : getCharL(a);
}
private static byte char1(char x) { return (byte)(x >> 8); }
- private static byte char0(char x) { return (byte)(x >> 0); }
+ private static byte char0(char x) { return (byte)(x ); }
static void putCharL(ByteBuffer bb, int bi, char x) {
- bb._put(bi + 0, char0(x));
+ bb._put(bi , char0(x));
bb._put(bi + 1, char1(x));
}
static void putCharL(long a, char x) {
- _put(a + 0, char0(x));
+ _put(a , char0(x));
_put(a + 1, char1(x));
}
static void putCharB(ByteBuffer bb, int bi, char x) {
- bb._put(bi + 0, char1(x));
+ bb._put(bi , char1(x));
bb._put(bi + 1, char0(x));
}
static void putCharB(long a, char x) {
- _put(a + 0, char1(x));
+ _put(a , char1(x));
_put(a + 1, char0(x));
}
@@ -143,52 +137,52 @@ class Bits { // package-private
static short getShortL(ByteBuffer bb, int bi) {
return makeShort(bb._get(bi + 1),
- bb._get(bi + 0));
+ bb._get(bi ));
}
static short getShortL(long a) {
return makeShort(_get(a + 1),
- _get(a));
+ _get(a ));
}
static short getShortB(ByteBuffer bb, int bi) {
- return makeShort(bb._get(bi + 0),
+ return makeShort(bb._get(bi ),
bb._get(bi + 1));
}
static short getShortB(long a) {
- return makeShort(_get(a),
+ return makeShort(_get(a ),
_get(a + 1));
}
static short getShort(ByteBuffer bb, int bi, boolean bigEndian) {
- return (bigEndian ? getShortB(bb, bi) : getShortL(bb, bi));
+ return bigEndian ? getShortB(bb, bi) : getShortL(bb, bi);
}
static short getShort(long a, boolean bigEndian) {
- return (bigEndian ? getShortB(a) : getShortL(a));
+ return bigEndian ? getShortB(a) : getShortL(a);
}
private static byte short1(short x) { return (byte)(x >> 8); }
- private static byte short0(short x) { return (byte)(x >> 0); }
+ private static byte short0(short x) { return (byte)(x ); }
static void putShortL(ByteBuffer bb, int bi, short x) {
- bb._put(bi + 0, short0(x));
+ bb._put(bi , short0(x));
bb._put(bi + 1, short1(x));
}
static void putShortL(long a, short x) {
- _put(a, short0(x));
+ _put(a , short0(x));
_put(a + 1, short1(x));
}
static void putShortB(ByteBuffer bb, int bi, short x) {
- bb._put(bi + 0, short1(x));
+ bb._put(bi , short1(x));
bb._put(bi + 1, short0(x));
}
static void putShortB(long a, short x) {
- _put(a, short1(x));
+ _put(a , short1(x));
_put(a + 1, short0(x));
}
@@ -210,76 +204,76 @@ class Bits { // package-private
// -- get/put int --
static private int makeInt(byte b3, byte b2, byte b1, byte b0) {
- return (((b3 & 0xff) << 24) |
+ return (((b3 ) << 24) |
((b2 & 0xff) << 16) |
((b1 & 0xff) << 8) |
- ((b0 & 0xff) << 0));
+ ((b0 & 0xff) ));
}
static int getIntL(ByteBuffer bb, int bi) {
return makeInt(bb._get(bi + 3),
bb._get(bi + 2),
bb._get(bi + 1),
- bb._get(bi + 0));
+ bb._get(bi ));
}
static int getIntL(long a) {
return makeInt(_get(a + 3),
_get(a + 2),
_get(a + 1),
- _get(a + 0));
+ _get(a ));
}
static int getIntB(ByteBuffer bb, int bi) {
- return makeInt(bb._get(bi + 0),
+ return makeInt(bb._get(bi ),
bb._get(bi + 1),
bb._get(bi + 2),
bb._get(bi + 3));
}
static int getIntB(long a) {
- return makeInt(_get(a + 0),
+ return makeInt(_get(a ),
_get(a + 1),
_get(a + 2),
_get(a + 3));
}
static int getInt(ByteBuffer bb, int bi, boolean bigEndian) {
- return (bigEndian ? getIntB(bb, bi) : getIntL(bb, bi));
+ return bigEndian ? getIntB(bb, bi) : getIntL(bb, bi) ;
}
static int getInt(long a, boolean bigEndian) {
- return (bigEndian ? getIntB(a) : getIntL(a));
+ return bigEndian ? getIntB(a) : getIntL(a) ;
}
private static byte int3(int x) { return (byte)(x >> 24); }
private static byte int2(int x) { return (byte)(x >> 16); }
private static byte int1(int x) { return (byte)(x >> 8); }
- private static byte int0(int x) { return (byte)(x >> 0); }
+ private static byte int0(int x) { return (byte)(x ); }
static void putIntL(ByteBuffer bb, int bi, int x) {
bb._put(bi + 3, int3(x));
bb._put(bi + 2, int2(x));
bb._put(bi + 1, int1(x));
- bb._put(bi + 0, int0(x));
+ bb._put(bi , int0(x));
}
static void putIntL(long a, int x) {
_put(a + 3, int3(x));
_put(a + 2, int2(x));
_put(a + 1, int1(x));
- _put(a + 0, int0(x));
+ _put(a , int0(x));
}
static void putIntB(ByteBuffer bb, int bi, int x) {
- bb._put(bi + 0, int3(x));
+ bb._put(bi , int3(x));
bb._put(bi + 1, int2(x));
bb._put(bi + 2, int1(x));
bb._put(bi + 3, int0(x));
}
static void putIntB(long a, int x) {
- _put(a + 0, int3(x));
+ _put(a , int3(x));
_put(a + 1, int2(x));
_put(a + 2, int1(x));
_put(a + 3, int0(x));
@@ -305,14 +299,14 @@ class Bits { // package-private
static private long makeLong(byte b7, byte b6, byte b5, byte b4,
byte b3, byte b2, byte b1, byte b0)
{
- return ((((long)b7 & 0xff) << 56) |
+ return ((((long)b7 ) << 56) |
(((long)b6 & 0xff) << 48) |
(((long)b5 & 0xff) << 40) |
(((long)b4 & 0xff) << 32) |
(((long)b3 & 0xff) << 24) |
(((long)b2 & 0xff) << 16) |
(((long)b1 & 0xff) << 8) |
- (((long)b0 & 0xff) << 0));
+ (((long)b0 & 0xff) ));
}
static long getLongL(ByteBuffer bb, int bi) {
@@ -323,7 +317,7 @@ class Bits { // package-private
bb._get(bi + 3),
bb._get(bi + 2),
bb._get(bi + 1),
- bb._get(bi + 0));
+ bb._get(bi ));
}
static long getLongL(long a) {
@@ -334,11 +328,11 @@ class Bits { // package-private
_get(a + 3),
_get(a + 2),
_get(a + 1),
- _get(a + 0));
+ _get(a ));
}
static long getLongB(ByteBuffer bb, int bi) {
- return makeLong(bb._get(bi + 0),
+ return makeLong(bb._get(bi ),
bb._get(bi + 1),
bb._get(bi + 2),
bb._get(bi + 3),
@@ -349,7 +343,7 @@ class Bits { // package-private
}
static long getLongB(long a) {
- return makeLong(_get(a + 0),
+ return makeLong(_get(a ),
_get(a + 1),
_get(a + 2),
_get(a + 3),
@@ -360,11 +354,11 @@ class Bits { // package-private
}
static long getLong(ByteBuffer bb, int bi, boolean bigEndian) {
- return (bigEndian ? getLongB(bb, bi) : getLongL(bb, bi));
+ return bigEndian ? getLongB(bb, bi) : getLongL(bb, bi);
}
static long getLong(long a, boolean bigEndian) {
- return (bigEndian ? getLongB(a) : getLongL(a));
+ return bigEndian ? getLongB(a) : getLongL(a);
}
private static byte long7(long x) { return (byte)(x >> 56); }
@@ -374,7 +368,7 @@ class Bits { // package-private
private static byte long3(long x) { return (byte)(x >> 24); }
private static byte long2(long x) { return (byte)(x >> 16); }
private static byte long1(long x) { return (byte)(x >> 8); }
- private static byte long0(long x) { return (byte)(x >> 0); }
+ private static byte long0(long x) { return (byte)(x ); }
static void putLongL(ByteBuffer bb, int bi, long x) {
bb._put(bi + 7, long7(x));
@@ -384,7 +378,7 @@ class Bits { // package-private
bb._put(bi + 3, long3(x));
bb._put(bi + 2, long2(x));
bb._put(bi + 1, long1(x));
- bb._put(bi + 0, long0(x));
+ bb._put(bi , long0(x));
}
static void putLongL(long a, long x) {
@@ -395,11 +389,11 @@ class Bits { // package-private
_put(a + 3, long3(x));
_put(a + 2, long2(x));
_put(a + 1, long1(x));
- _put(a + 0, long0(x));
+ _put(a , long0(x));
}
static void putLongB(ByteBuffer bb, int bi, long x) {
- bb._put(bi + 0, long7(x));
+ bb._put(bi , long7(x));
bb._put(bi + 1, long6(x));
bb._put(bi + 2, long5(x));
bb._put(bi + 3, long4(x));
@@ -410,7 +404,7 @@ class Bits { // package-private
}
static void putLongB(long a, long x) {
- _put(a + 0, long7(x));
+ _put(a , long7(x));
_put(a + 1, long6(x));
_put(a + 2, long5(x));
_put(a + 3, long4(x));
@@ -454,11 +448,11 @@ class Bits { // package-private
}
static float getFloat(ByteBuffer bb, int bi, boolean bigEndian) {
- return (bigEndian ? getFloatB(bb, bi) : getFloatL(bb, bi));
+ return bigEndian ? getFloatB(bb, bi) : getFloatL(bb, bi);
}
static float getFloat(long a, boolean bigEndian) {
- return (bigEndian ? getFloatB(a) : getFloatL(a));
+ return bigEndian ? getFloatB(a) : getFloatL(a);
}
static void putFloatL(ByteBuffer bb, int bi, float x) {
@@ -511,11 +505,11 @@ class Bits { // package-private
}
static double getDouble(ByteBuffer bb, int bi, boolean bigEndian) {
- return (bigEndian ? getDoubleB(bb, bi) : getDoubleL(bb, bi));
+ return bigEndian ? getDoubleB(bb, bi) : getDoubleL(bb, bi);
}
static double getDouble(long a, boolean bigEndian) {
- return (bigEndian ? getDoubleB(a) : getDoubleL(a));
+ return bigEndian ? getDoubleB(a) : getDoubleL(a);
}
static void putDoubleL(ByteBuffer bb, int bi, double x) {
@@ -794,7 +788,7 @@ class Bits { // package-private
static native void copyFromIntArray(Object src, long srcPos, long dstAddr,
long length);
static native void copyToIntArray(long srcAddr, Object dst, long dstPos,
- long length);
+ long length);
static native void copyFromLongArray(Object src, long srcPos, long dstAddr,
long length);
diff --git a/src/share/classes/java/nio/channels/FileLock.java b/src/share/classes/java/nio/channels/FileLock.java
index af1adf510182b9f39162e98cf155f859b3239c40..9098a3317fdc2472f5445c149cb1e9802b6c20e3 100644
--- a/src/share/classes/java/nio/channels/FileLock.java
+++ b/src/share/classes/java/nio/channels/FileLock.java
@@ -116,7 +116,7 @@ import java.io.IOException;
* @since 1.4
*/
-public abstract class FileLock {
+public abstract class FileLock implements AutoCloseable {
private final Channel channel;
private final long position;
@@ -298,6 +298,17 @@ public abstract class FileLock {
*/
public abstract void release() throws IOException;
+ /**
+ * This method invokes the {@link #release} method. It was added
+ * to the class so that it could be used in conjunction with the
+ * automatic resource management block construct.
+ *
+ * @since 1.7
+ */
+ public final void close() throws IOException {
+ release();
+ }
+
/**
* Returns a string describing the range, type, and validity of this lock.
*
diff --git a/src/share/classes/java/util/DualPivotQuicksort.java b/src/share/classes/java/util/DualPivotQuicksort.java
index 168a47d9b5cf84d8a882a51308e7e68e702040e3..873230a2c7394533f9b27775f25e36ef0b01b981 100644
--- a/src/share/classes/java/util/DualPivotQuicksort.java
+++ b/src/share/classes/java/util/DualPivotQuicksort.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,7 +27,7 @@ package java.util;
/**
* This class implements the Dual-Pivot Quicksort algorithm by
- * Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. The algorithm
+ * Vladimir Yaroslavskiy, Jon Bentley, and Josh Bloch. The algorithm
* offers O(n log(n)) performance on many data sets that cause other
* quicksorts to degrade to quadratic performance, and is typically
* faster than traditional (one-pivot) Quicksort implementations.
@@ -36,7 +36,8 @@ package java.util;
* @author Jon Bentley
* @author Josh Bloch
*
- * @version 2009.11.29 m765.827.12i
+ * @version 2010.06.21 m765.827.12i:5\7
+ * @since 1.7
*/
final class DualPivotQuicksort {
@@ -68,7 +69,7 @@ final class DualPivotQuicksort {
private static final int COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR = 32768;
/*
- * Sorting methods for 7 primitive types.
+ * Sorting methods for seven primitive types.
*/
/**
@@ -77,7 +78,7 @@ final class DualPivotQuicksort {
* @param a the array to be sorted
*/
public static void sort(int[] a) {
- doSort(a, 0, a.length - 1);
+ sort(a, 0, a.length - 1, true);
}
/**
@@ -95,98 +96,132 @@ final class DualPivotQuicksort {
*/
public static void sort(int[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- doSort(a, fromIndex, toIndex - 1);
+ sort(a, fromIndex, toIndex - 1, true);
}
/**
- * Sorts the specified range of the array into ascending order. This
- * method differs from the public {@code sort} method in that the
- * {@code right} index is inclusive, and it does no range checking
- * on {@code left} or {@code right}.
+ * 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 doSort(int[] a, int left, int right) {
+ private static void sort(int[] a, int left, int right, boolean leftmost) {
+ int length = right - left + 1;
+
// Use insertion sort on tiny arrays
- if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
- for (int i = left + 1; i <= right; i++) {
- int ai = a[i];
- int j;
- for (j = i - 1; j >= left && ai < a[j]; j--) {
- a[j + 1] = a[j];
+ 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++) {
+ 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.
+ */
+ for (int i = left, j = i; i < right; j = ++i) {
+ int ai = a[i + 1];
+ while (ai < a[j]) {
+ a[j + 1] = a[j];
+ if (j-- == left) {
+ break;
+ }
+ }
+ a[j + 1] = ai;
}
- a[j + 1] = ai;
}
- } else { // Use Dual-Pivot Quicksort on large arrays
- dualPivotQuicksort(a, left, right);
+ return;
}
- }
- /**
- * Sorts the specified range of the array into ascending order by the
- * Dual-Pivot Quicksort algorithm.
- *
- * @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 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;
+ // Inexpensive approximation of length / 7
+ int seventh = (length >>> 3) + (length >>> 6) + 1;
- // Sort these elements using a 5-element sorting network
- int ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
+ /*
+ * 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;
- if (ae1 > ae2) { int t = ae1; ae1 = ae2; ae2 = t; }
- if (ae4 > ae5) { int t = ae4; ae4 = ae5; ae5 = t; }
- if (ae1 > ae3) { int t = ae1; ae1 = ae3; ae3 = t; }
- if (ae2 > ae3) { int t = ae2; ae2 = ae3; ae3 = t; }
- if (ae1 > ae4) { int t = ae1; ae1 = ae4; ae4 = t; }
- if (ae3 > ae4) { int t = ae3; ae3 = ae4; ae4 = t; }
- if (ae2 > ae5) { int t = ae2; ae2 = ae5; ae5 = t; }
- if (ae2 > ae3) { int t = ae2; ae2 = ae3; ae3 = t; }
- if (ae4 > ae5) { int t = ae4; ae4 = ae5; ae5 = t; }
+ // Sort these elements using insertion sort
+ if (a[e2] < a[e1]) { int t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
- a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
+ if (a[e3] < a[e2]) { int t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ if (a[e4] < a[e3]) { int t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+ if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ }
+ if (a[e5] < a[e4]) { int t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+ if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+ if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ }
+ }
/*
* 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 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.
*/
- int pivot1 = ae2; a[e2] = a[left];
- int pivot2 = ae4; a[e4] = a[right];
+ int pivot1 = a[e2];
+ int pivot2 = a[e4];
// 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
+ 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];
- boolean pivotsDiffer = (pivot1 != pivot2);
+ /*
+ * Skip elements, which are less or greater than pivot values.
+ */
+ while (a[++less] < pivot1);
+ while (a[--great] > pivot2);
- if (pivotsDiffer) {
/*
* Partitioning:
*
- * left part center part right part
- * +------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +--------------------------------------------------------------+
+ * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
+ * +--------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -194,16 +229,14 @@ final class DualPivotQuicksort {
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
outer:
for (int k = less; k <= great; k++) {
int ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
@@ -213,26 +246,107 @@ final class DualPivotQuicksort {
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ a[less] = a[great];
+ less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
- a[great--] = ak;
+ }
+ 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) {
+ /*
+ * Skip elements, which are equal to pivot values.
+ */
+ while (a[less] == pivot1) {
+ less++;
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+
+ /*
+ * Partitioning:
+ *
+ * left part center part right part
+ * +----------------------------------------------------------+
+ * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
+ * +----------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (*, less) == pivot1
+ * pivot1 < all in [less, k) < pivot2
+ * all in (great, *) == pivot2
+ *
+ * Pointer k is the first index of ?-part.
+ */
+ outer:
+ for (int k = less; k <= great; k++) {
+ int ak = a[k];
+ if (ak == pivot1) { // Move a[k] to left part
+ a[k] = a[less];
+ a[less] = ak;
+ less++;
+ } else if (ak == pivot2) { // Move a[k] to right part
+ while (a[great] == pivot2) {
+ if (great-- == k) {
+ break outer;
+ }
+ }
+ if (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--;
}
}
}
+
+ // Sort center part recursively
+ sort(a, less, great, false);
+
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way,
- * or "Dutch National Flag", partition:
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") schema:
*
- * left part center part right part
- * +----------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +----------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +-------------------------------------------------+
+ * | < pivot | == pivot | ? | > pivot |
+ * +-------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -240,20 +354,19 @@ final class DualPivotQuicksort {
* all in [less, k) == pivot
* all in (great, right) > pivot
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
- for (int k = less; k <= great; k++) {
- int ak = a[k];
- if (ak == pivot1) {
+ for (int k = left; k <= great; k++) {
+ if (a[k] == pivot1) {
continue;
}
+ int ak = a[k];
+
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
- } else { // (a[k] > pivot1) - Move a[k] to right part
+ } 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
@@ -261,92 +374,33 @@ final class DualPivotQuicksort {
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
+ // assert great > k;
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ 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;
- a[great--] = ak;
}
+ 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 pivot values
- doSort(a, left, less - 2);
- doSort(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 > 2/3 of the array),
- * swap internal pivot values to ends
- */
- if (less < e1 && great > e5) {
- while (a[less] == pivot1) {
- less++;
- }
- while (a[great] == pivot2) {
- great--;
- }
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part
- */
- outer:
- for (int k = less; k <= great; k++) {
- int ak = a[k];
- 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++] = pivot1;
- } else { // pivot1 < a[great] < pivot2
- a[k] = a[great];
- }
- a[great--] = pivot2;
- } else if (ak == pivot1) { // Move a[k] to left part
- a[k] = a[less];
- a[less++] = pivot1;
- }
- }
+ // Sort left and right parts recursively
+ sort(a, left, less - 1, leftmost);
+ sort(a, great + 1, right, false);
}
-
- // Sort center part recursively, excluding known pivot values
- doSort(a, less, great);
}
/**
@@ -355,7 +409,7 @@ final class DualPivotQuicksort {
* @param a the array to be sorted
*/
public static void sort(long[] a) {
- doSort(a, 0, a.length - 1);
+ sort(a, 0, a.length - 1, true);
}
/**
@@ -373,98 +427,132 @@ final class DualPivotQuicksort {
*/
public static void sort(long[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- doSort(a, fromIndex, toIndex - 1);
+ sort(a, fromIndex, toIndex - 1, true);
}
/**
- * Sorts the specified range of the array into ascending order. This
- * method differs from the public {@code sort} method in that the
- * {@code right} index is inclusive, and it does no range checking on
- * {@code left} or {@code right}.
+ * 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 doSort(long[] a, int left, int right) {
+ private static void sort(long[] a, int left, int right, boolean leftmost) {
+ int length = right - left + 1;
+
// Use insertion sort on tiny arrays
- if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
- for (int i = left + 1; i <= right; i++) {
- long ai = a[i];
- int j;
- for (j = i - 1; j >= left && ai < a[j]; j--) {
- a[j + 1] = a[j];
+ 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 {
+ /*
+ * 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) {
+ long ai = a[i + 1];
+ while (ai < a[j]) {
+ a[j + 1] = a[j];
+ if (j-- == left) {
+ break;
+ }
+ }
+ a[j + 1] = ai;
}
- a[j + 1] = ai;
}
- } else { // Use Dual-Pivot Quicksort on large arrays
- dualPivotQuicksort(a, left, right);
+ return;
}
- }
- /**
- * Sorts the specified range of the array into ascending order by the
- * Dual-Pivot Quicksort algorithm.
- *
- * @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 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;
+ // Inexpensive approximation of length / 7
+ int seventh = (length >>> 3) + (length >>> 6) + 1;
- // Sort these elements using a 5-element sorting network
- long ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
+ /*
+ * 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;
- if (ae1 > ae2) { long t = ae1; ae1 = ae2; ae2 = t; }
- if (ae4 > ae5) { long t = ae4; ae4 = ae5; ae5 = t; }
- if (ae1 > ae3) { long t = ae1; ae1 = ae3; ae3 = t; }
- if (ae2 > ae3) { long t = ae2; ae2 = ae3; ae3 = t; }
- if (ae1 > ae4) { long t = ae1; ae1 = ae4; ae4 = t; }
- if (ae3 > ae4) { long t = ae3; ae3 = ae4; ae4 = t; }
- if (ae2 > ae5) { long t = ae2; ae2 = ae5; ae5 = t; }
- if (ae2 > ae3) { long t = ae2; ae2 = ae3; ae3 = t; }
- if (ae4 > ae5) { long t = ae4; ae4 = ae5; ae5 = t; }
+ // Sort these elements using insertion sort
+ if (a[e2] < a[e1]) { long t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
- a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
+ 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.
- *
- * The pivots are stored in local variables, and the first and
- * the last of the 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.
*/
- long pivot1 = ae2; a[e2] = a[left];
- long pivot2 = ae4; a[e4] = a[right];
+ long pivot1 = a[e2];
+ long pivot2 = a[e4];
// 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
+ 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];
- boolean pivotsDiffer = (pivot1 != pivot2);
+ /*
+ * Skip elements, which are less or greater than pivot values.
+ */
+ while (a[++less] < pivot1);
+ while (a[--great] > pivot2);
- if (pivotsDiffer) {
/*
* Partitioning:
*
- * left part center part right part
- * +------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +--------------------------------------------------------------+
+ * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
+ * +--------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -472,16 +560,14 @@ final class DualPivotQuicksort {
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
- * Pointer k is the first index of ?-part
+ * 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
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
@@ -491,26 +577,107 @@ final class DualPivotQuicksort {
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ a[less] = a[great];
+ less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
- a[great--] = ak;
+ }
+ 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) {
+ /*
+ * Skip elements, which are equal to pivot values.
+ */
+ while (a[less] == pivot1) {
+ less++;
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+
+ /*
+ * Partitioning:
+ *
+ * left part center part right part
+ * +----------------------------------------------------------+
+ * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
+ * +----------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (*, less) == pivot1
+ * pivot1 < all in [less, k) < pivot2
+ * all in (great, *) == pivot2
+ *
+ * Pointer k is the first index of ?-part.
+ */
+ outer:
+ for (int k = less; 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--;
}
}
}
+
+ // Sort center part recursively
+ sort(a, less, great, false);
+
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way,
- * or "Dutch National Flag", partition:
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") schema:
*
- * left part center part right part
- * +----------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +----------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +-------------------------------------------------+
+ * | < pivot | == pivot | ? | > pivot |
+ * +-------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -518,20 +685,19 @@ final class DualPivotQuicksort {
* all in [less, k) == pivot
* all in (great, right) > pivot
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
- for (int k = less; k <= great; k++) {
- long ak = a[k];
- if (ak == pivot1) {
+ 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
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
- } else { // (a[k] > pivot1) - Move a[k] to right part
+ } 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
@@ -539,92 +705,33 @@ final class DualPivotQuicksort {
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
+ // assert great > k;
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ 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;
- a[great--] = ak;
}
+ 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 pivot values
- doSort(a, left, less - 2);
- doSort(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 > 2/3 of the array),
- * swap internal pivot values to ends
- */
- if (less < e1 && great > e5) {
- while (a[less] == pivot1) {
- less++;
- }
- while (a[great] == pivot2) {
- great--;
- }
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part
- */
- outer:
- for (int k = less; k <= great; k++) {
- long ak = a[k];
- 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++] = pivot1;
- } else { // pivot1 < a[great] < pivot2
- a[k] = a[great];
- }
- a[great--] = pivot2;
- } else if (ak == pivot1) { // Move a[k] to left part
- a[k] = a[less];
- a[less++] = pivot1;
- }
- }
+ // Sort left and right parts recursively
+ sort(a, left, less - 1, leftmost);
+ sort(a, great + 1, right, false);
}
-
- // Sort center part recursively, excluding known pivot values
- doSort(a, less, great);
}
/**
@@ -633,7 +740,11 @@ final class DualPivotQuicksort {
* @param a the array to be sorted
*/
public static void sort(short[] a) {
- doSort(a, 0, a.length - 1);
+ if (a.length > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+ countingSort(a, 0, a.length - 1);
+ } else {
+ sort(a, 0, a.length - 1, true);
+ }
}
/**
@@ -651,115 +762,166 @@ final class DualPivotQuicksort {
*/
public static void sort(short[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- doSort(a, fromIndex, toIndex - 1);
+
+ 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 into ascending order. This
- * method differs from the public {@code sort} method in that the
- * {@code right} index is inclusive, and it does no range checking on
- * {@code left} or {@code right}.
+ * 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 doSort(short[] a, int left, int right) {
- // Use insertion sort on tiny arrays
- if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
- for (int i = left + 1; i <= right; i++) {
- short ai = a[i];
- int j;
- for (j = i - 1; j >= left && ai < a[j]; j--) {
- a[j + 1] = a[j];
- }
- a[j + 1] = ai;
- }
- } 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];
+ 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 = 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--;
}
- for (int i = 0, k = left; i < count.length && k <= right; i++) {
- short value = (short) (i + Short.MIN_VALUE);
+ short value = (short) (i + Short.MIN_VALUE);
+ int s = count[i];
- for (int s = count[i]; s > 0; s--) {
- a[k++] = value;
- }
- }
- } else { // Use Dual-Pivot Quicksort on large arrays
- dualPivotQuicksort(a, left, right);
+ do {
+ a[k--] = value;
+ } while (--s > 0);
}
}
/**
* Sorts the specified range of the array into ascending order by the
- * Dual-Pivot Quicksort algorithm.
+ * 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 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;
+ 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];
+ }
+ a[j + 1] = ai;
+ }
+ } 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;
+ }
+ }
+ return;
+ }
+
+ // Inexpensive approximation of length / 7
+ int seventh = (length >>> 3) + (length >>> 6) + 1;
- // Sort these elements using a 5-element sorting network
- short ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
+ /*
+ * 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;
- if (ae1 > ae2) { short t = ae1; ae1 = ae2; ae2 = t; }
- if (ae4 > ae5) { short t = ae4; ae4 = ae5; ae5 = t; }
- if (ae1 > ae3) { short t = ae1; ae1 = ae3; ae3 = t; }
- if (ae2 > ae3) { short t = ae2; ae2 = ae3; ae3 = t; }
- if (ae1 > ae4) { short t = ae1; ae1 = ae4; ae4 = t; }
- if (ae3 > ae4) { short t = ae3; ae3 = ae4; ae4 = t; }
- if (ae2 > ae5) { short t = ae2; ae2 = ae5; ae5 = t; }
- if (ae2 > ae3) { short t = ae2; ae2 = ae3; ae3 = t; }
- if (ae4 > ae5) { short t = ae4; ae4 = ae5; ae5 = t; }
+ // Sort these elements using insertion sort
+ if (a[e2] < a[e1]) { short t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
- a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
+ 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]) { 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]) { 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; }
+ }
+ }
+ }
/*
* 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 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.
*/
- short pivot1 = ae2; a[e2] = a[left];
- short pivot2 = ae4; a[e4] = a[right];
+ short pivot1 = a[e2];
+ short pivot2 = a[e4];
// 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
+ int less = left; // The index of the first element of center part
+ int great = right; // The index before the first element of right part
- boolean pivotsDiffer = (pivot1 != pivot2);
+ 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);
- if (pivotsDiffer) {
/*
* Partitioning:
*
- * left part center part right part
- * +------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +--------------------------------------------------------------+
+ * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
+ * +--------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -767,16 +929,14 @@ final class DualPivotQuicksort {
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
outer:
for (int k = less; k <= great; k++) {
short ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
@@ -786,26 +946,107 @@ final class DualPivotQuicksort {
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ a[less] = a[great];
+ less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
- a[great--] = ak;
+ }
+ 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) {
+ /*
+ * Skip elements, which are equal to pivot values.
+ */
+ while (a[less] == pivot1) {
+ less++;
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+
+ /*
+ * Partitioning:
+ *
+ * left part center part right part
+ * +----------------------------------------------------------+
+ * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
+ * +----------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (*, less) == pivot1
+ * pivot1 < all in [less, k) < pivot2
+ * all in (great, *) == pivot2
+ *
+ * Pointer k is the first index of ?-part.
+ */
+ outer:
+ for (int k = less; k <= great; k++) {
+ short ak = a[k];
+ if (ak == pivot1) { // Move a[k] to left part
+ a[k] = a[less];
+ a[less] = ak;
+ less++;
+ } else if (ak == pivot2) { // Move a[k] to right part
+ while (a[great] == pivot2) {
+ if (great-- == k) {
+ break outer;
+ }
+ }
+ 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--;
}
}
}
+
+ // Sort center part recursively
+ sort(a, less, great, false);
+
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way,
- * or "Dutch National Flag", partition:
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") schema:
*
- * left part center part right part
- * +----------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +----------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +-------------------------------------------------+
+ * | < pivot | == pivot | ? | > pivot |
+ * +-------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -813,20 +1054,19 @@ final class DualPivotQuicksort {
* all in [less, k) == pivot
* all in (great, right) > pivot
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
- for (int k = less; k <= great; k++) {
- short ak = a[k];
- if (ak == pivot1) {
+ for (int k = left; k <= great; k++) {
+ if (a[k] == pivot1) {
continue;
}
+ short ak = a[k];
+
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
- } else { // (a[k] > pivot1) - Move a[k] to right part
+ } 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
@@ -834,92 +1074,33 @@ final class DualPivotQuicksort {
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
+ // assert great > k;
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ 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;
- a[great--] = ak;
}
+ 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 pivot values
- doSort(a, left, less - 2);
- doSort(a, great + 2, right);
-
- /*
- * If pivot1 == pivot2, all elements from center
- * part are equal and, therefore, already sorted
- */
- if (!pivotsDiffer) {
- return;
+ // Sort left and right parts recursively
+ sort(a, left, less - 1, leftmost);
+ sort(a, great + 1, right, false);
}
-
- /*
- * If center part is too large (comprises > 2/3 of the array),
- * swap internal pivot values to ends
- */
- if (less < e1 && great > e5) {
- while (a[less] == pivot1) {
- less++;
- }
- while (a[great] == pivot2) {
- great--;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part
- */
- outer:
- for (int k = less; k <= great; k++) {
- short ak = a[k];
- 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++] = pivot1;
- } else { // pivot1 < a[great] < pivot2
- a[k] = a[great];
- }
- a[great--] = pivot2;
- } else if (ak == pivot1) { // Move a[k] to left part
- a[k] = a[less];
- a[less++] = pivot1;
- }
- }
- }
-
- // Sort center part recursively, excluding known pivot values
- doSort(a, less, great);
}
/**
@@ -928,7 +1109,11 @@ final class DualPivotQuicksort {
* @param a the array to be sorted
*/
public static void sort(char[] a) {
- doSort(a, 0, a.length - 1);
+ if (a.length > COUNTING_SORT_THRESHOLD_FOR_SHORT_OR_CHAR) {
+ countingSort(a, 0, a.length - 1);
+ } else {
+ sort(a, 0, a.length - 1, true);
+ }
}
/**
@@ -946,113 +1131,166 @@ final class DualPivotQuicksort {
*/
public static void sort(char[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- doSort(a, fromIndex, toIndex - 1);
+
+ 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 char values. */
private static final int NUM_CHAR_VALUES = 1 << 16;
/**
- * Sorts the specified range of the array into ascending order. This
- * method differs from the public {@code sort} method in that the
- * {@code right} index is inclusive, and it does no range checking on
- * {@code left} or {@code right}.
+ * 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 doSort(char[] a, int left, int right) {
- // Use insertion sort on tiny arrays
- if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
- for (int i = left + 1; i <= right; i++) {
- char ai = a[i];
- int j;
- for (j = i - 1; j >= left && ai < a[j]; j--) {
- a[j + 1] = a[j];
- }
- a[j + 1] = ai;
- }
- } 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];
+ private static void countingSort(char[] a, int left, int right) {
+ 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;
- }
+ for (int i = left; i <= right; i++) {
+ count[a[i]]++;
+ }
+ for (int i = 0, k = left; k <= right; i++) {
+ while (count[i] == 0) {
+ i++;
}
- } else { // Use Dual-Pivot Quicksort on large arrays
- dualPivotQuicksort(a, left, right);
+ char value = (char) i;
+ 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.
+ * 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 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;
+ private static void sort(char[] a, int left, int right, boolean leftmost) {
+ int length = right - left + 1;
- // Sort these elements using a 5-element sorting network
- char ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
+ // 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++) {
+ 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 {
+ /*
+ * 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) {
+ char ai = a[i + 1];
+ while (ai < a[j]) {
+ a[j + 1] = a[j];
+ if (j-- == left) {
+ break;
+ }
+ }
+ 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;
- if (ae1 > ae2) { char t = ae1; ae1 = ae2; ae2 = t; }
- if (ae4 > ae5) { char t = ae4; ae4 = ae5; ae5 = t; }
- if (ae1 > ae3) { char t = ae1; ae1 = ae3; ae3 = t; }
- if (ae2 > ae3) { char t = ae2; ae2 = ae3; ae3 = t; }
- if (ae1 > ae4) { char t = ae1; ae1 = ae4; ae4 = t; }
- if (ae3 > ae4) { char t = ae3; ae3 = ae4; ae4 = t; }
- if (ae2 > ae5) { char t = ae2; ae2 = ae5; ae5 = t; }
- if (ae2 > ae3) { char t = ae2; ae2 = ae3; ae3 = t; }
- if (ae4 > ae5) { char t = ae4; ae4 = ae5; ae5 = t; }
+ // Sort these elements using insertion sort
+ if (a[e2] < a[e1]) { char t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
- a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
+ if (a[e3] < a[e2]) { char t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ if (a[e4] < a[e3]) { char t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+ if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ }
+ if (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; }
+ }
+ }
+ }
/*
* 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 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.
*/
- char pivot1 = ae2; a[e2] = a[left];
- char pivot2 = ae4; a[e4] = a[right];
+ char pivot1 = a[e2];
+ char pivot2 = a[e4];
// 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
+ 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];
- boolean pivotsDiffer = (pivot1 != pivot2);
+ /*
+ * Skip elements, which are less or greater than pivot values.
+ */
+ while (a[++less] < pivot1);
+ while (a[--great] > pivot2);
- if (pivotsDiffer) {
/*
* Partitioning:
*
- * left part center part right part
- * +------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +--------------------------------------------------------------+
+ * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
+ * +--------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -1060,16 +1298,14 @@ final class DualPivotQuicksort {
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
outer:
for (int k = less; k <= great; k++) {
char ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
@@ -1079,26 +1315,107 @@ final class DualPivotQuicksort {
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ a[less] = a[great];
+ less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
- a[great--] = ak;
}
+ 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) {
+ /*
+ * Skip elements, which are equal to pivot values.
+ */
+ while (a[less] == pivot1) {
+ less++;
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+
+ /*
+ * Partitioning:
+ *
+ * left part center part right part
+ * +----------------------------------------------------------+
+ * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
+ * +----------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (*, less) == pivot1
+ * pivot1 < all in [less, k) < pivot2
+ * all in (great, *) == pivot2
+ *
+ * Pointer k is the first index of ?-part.
+ */
+ outer:
+ for (int k = less; k <= great; k++) {
+ char ak = a[k];
+ if (ak == pivot1) { // Move a[k] to left part
+ a[k] = a[less];
+ a[less] = ak;
+ less++;
+ } else if (ak == pivot2) { // Move a[k] to right part
+ while (a[great] == pivot2) {
+ if (great-- == k) {
+ break outer;
+ }
+ }
+ 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--;
+ }
+ }
+ }
+
+ // Sort center part recursively
+ sort(a, less, great, false);
+
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way,
- * or "Dutch National Flag", partition:
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") schema:
*
- * left part center part right part
- * +----------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +----------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +-------------------------------------------------+
+ * | < pivot | == pivot | ? | > pivot |
+ * +-------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -1106,20 +1423,19 @@ final class DualPivotQuicksort {
* all in [less, k) == pivot
* all in (great, right) > pivot
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
- for (int k = less; k <= great; k++) {
- char ak = a[k];
- if (ak == pivot1) {
+ for (int k = left; k <= great; k++) {
+ if (a[k] == pivot1) {
continue;
}
+ char ak = a[k];
+
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
- } else { // (a[k] > pivot1) - Move a[k] to right part
+ } 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
@@ -1127,92 +1443,33 @@ final class DualPivotQuicksort {
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
+ // assert great > k;
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ 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;
- a[great--] = ak;
}
+ 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 pivot values
- doSort(a, left, less - 2);
- doSort(a, great + 2, right);
-
- /*
- * If pivot1 == pivot2, all elements from center
- * part are equal and, therefore, already sorted
- */
- if (!pivotsDiffer) {
- return;
+ // Sort left and right parts recursively
+ sort(a, left, less - 1, leftmost);
+ sort(a, great + 1, right, false);
}
-
- /*
- * If center part is too large (comprises > 2/3 of the array),
- * swap internal pivot values to ends
- */
- if (less < e1 && great > e5) {
- while (a[less] == pivot1) {
- less++;
- }
- while (a[great] == pivot2) {
- great--;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part
- */
- outer:
- for (int k = less; k <= great; k++) {
- char ak = a[k];
- 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++] = pivot1;
- } else { // pivot1 < a[great] < pivot2
- a[k] = a[great];
- }
- a[great--] = pivot2;
- } else if (ak == pivot1) { // Move a[k] to left part
- a[k] = a[less];
- a[less++] = pivot1;
- }
- }
- }
-
- // Sort center part recursively, excluding known pivot values
- doSort(a, less, great);
}
/**
@@ -1221,7 +1478,11 @@ final class DualPivotQuicksort {
* @param a the array to be sorted
*/
public static void sort(byte[] a) {
- doSort(a, 0, a.length - 1);
+ if (a.length > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
+ countingSort(a, 0, a.length - 1);
+ } else {
+ sort(a, 0, a.length - 1, true);
+ }
}
/**
@@ -1239,115 +1500,166 @@ final class DualPivotQuicksort {
*/
public static void sort(byte[] a, int fromIndex, int toIndex) {
rangeCheck(a.length, fromIndex, toIndex);
- doSort(a, fromIndex, toIndex - 1);
+
+ if (toIndex - fromIndex > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
+ countingSort(a, fromIndex, toIndex - 1);
+ } else {
+ sort(a, fromIndex, toIndex - 1, true);
+ }
}
/** 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. This
- * method differs from the public {@code sort} method in that the
- * {@code right} index is inclusive, and it does no range checking on
- * {@code left} or {@code right}.
+ * 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 doSort(byte[] a, int left, int right) {
- // Use insertion sort on tiny arrays
- if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
- for (int i = left + 1; i <= right; i++) {
- byte ai = a[i];
- int j;
- for (j = i - 1; j >= left && ai < a[j]; j--) {
- a[j + 1] = a[j];
- }
- a[j + 1] = ai;
- }
- } else if (right - left + 1 > COUNTING_SORT_THRESHOLD_FOR_BYTE) {
- // Use counting sort on huge arrays
- int[] count = new int[NUM_BYTE_VALUES];
+ private static void countingSort(byte[] a, int left, int right) {
+ int[] count = new int[NUM_BYTE_VALUES];
- for (int i = left; i <= right; i++) {
- count[a[i] - Byte.MIN_VALUE]++;
+ 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 = 0, k = left; i < count.length && k <= right; i++) {
- byte value = (byte) (i + Byte.MIN_VALUE);
+ byte value = (byte) (i + Byte.MIN_VALUE);
+ int s = count[i];
- for (int s = count[i]; s > 0; s--) {
- a[k++] = value;
- }
- }
- } else { // Use Dual-Pivot Quicksort on large arrays
- dualPivotQuicksort(a, left, right);
+ do {
+ a[k--] = value;
+ } while (--s > 0);
}
}
/**
* Sorts the specified range of the array into ascending order by the
- * Dual-Pivot Quicksort algorithm.
+ * 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 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;
+ private static void sort(byte[] a, int left, int right, boolean leftmost) {
+ int length = right - left + 1;
- // Sort these elements using a 5-element sorting network
- byte ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
+ // 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++) {
+ 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 {
+ /*
+ * 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) {
+ byte ai = a[i + 1];
+ while (ai < a[j]) {
+ a[j + 1] = a[j];
+ if (j-- == left) {
+ break;
+ }
+ }
+ 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;
- if (ae1 > ae2) { byte t = ae1; ae1 = ae2; ae2 = t; }
- if (ae4 > ae5) { byte t = ae4; ae4 = ae5; ae5 = t; }
- if (ae1 > ae3) { byte t = ae1; ae1 = ae3; ae3 = t; }
- if (ae2 > ae3) { byte t = ae2; ae2 = ae3; ae3 = t; }
- if (ae1 > ae4) { byte t = ae1; ae1 = ae4; ae4 = t; }
- if (ae3 > ae4) { byte t = ae3; ae3 = ae4; ae4 = t; }
- if (ae2 > ae5) { byte t = ae2; ae2 = ae5; ae5 = t; }
- if (ae2 > ae3) { byte t = ae2; ae2 = ae3; ae3 = t; }
- if (ae4 > ae5) { byte t = ae4; ae4 = ae5; ae5 = t; }
+ // Sort these elements using insertion sort
+ if (a[e2] < a[e1]) { byte t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
- a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
+ if (a[e3] < a[e2]) { byte 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 (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 (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.
- *
- * The pivots are stored in local variables, and the first and
- * the last of the 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.
*/
- byte pivot1 = ae2; a[e2] = a[left];
- byte pivot2 = ae4; a[e4] = a[right];
+ byte pivot1 = a[e2];
+ byte pivot2 = a[e4];
// 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
+ int less = left; // The index of the first element of center part
+ int great = right; // The index before the first element of right part
- boolean pivotsDiffer = (pivot1 != pivot2);
+ 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);
- if (pivotsDiffer) {
/*
* Partitioning:
*
- * left part center part right part
- * +------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +--------------------------------------------------------------+
+ * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
+ * +--------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -1355,16 +1667,14 @@ final class DualPivotQuicksort {
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
outer:
for (int k = less; k <= great; k++) {
byte ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
@@ -1374,26 +1684,107 @@ final class DualPivotQuicksort {
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ a[less] = a[great];
+ less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
- a[great--] = ak;
}
+ 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) {
+ /*
+ * Skip elements, which are equal to pivot values.
+ */
+ while (a[less] == pivot1) {
+ less++;
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+
+ /*
+ * Partitioning:
+ *
+ * left part center part right part
+ * +----------------------------------------------------------+
+ * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
+ * +----------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (*, less) == pivot1
+ * pivot1 < all in [less, k) < pivot2
+ * all in (great, *) == pivot2
+ *
+ * Pointer k is the first index of ?-part.
+ */
+ outer:
+ for (int k = less; k <= great; k++) {
+ byte 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--;
+ }
+ }
+ }
+
+ // Sort center part recursively
+ sort(a, less, great, false);
+
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way,
- * or "Dutch National Flag", partition:
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") schema:
*
- * left part center part right part
- * +----------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +----------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +-------------------------------------------------+
+ * | < pivot | == pivot | ? | > pivot |
+ * +-------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -1401,20 +1792,19 @@ final class DualPivotQuicksort {
* all in [less, k) == pivot
* all in (great, right) > pivot
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
- for (int k = less; k <= great; k++) {
- byte ak = a[k];
- if (ak == pivot1) {
+ for (int k = left; k <= great; k++) {
+ if (a[k] == pivot1) {
continue;
}
+ byte ak = a[k];
+
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
- } else { // (a[k] > pivot1) - Move a[k] to right part
+ } 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
@@ -1422,92 +1812,33 @@ final class DualPivotQuicksort {
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
+ // assert great > k;
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ 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;
- a[great--] = ak;
}
+ 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 pivot values
- doSort(a, left, less - 2);
- doSort(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 > 2/3 of the array),
- * swap internal pivot values to ends
- */
- if (less < e1 && great > e5) {
- while (a[less] == pivot1) {
- less++;
- }
- while (a[great] == pivot2) {
- great--;
- }
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part
- */
- outer:
- for (int k = less; k <= great; k++) {
- byte ak = a[k];
- 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++] = pivot1;
- } else { // pivot1 < a[great] < pivot2
- a[k] = a[great];
- }
- a[great--] = pivot2;
- } else if (ak == pivot1) { // Move a[k] to left part
- a[k] = a[less];
- a[less++] = pivot1;
- }
- }
+ // Sort left and right parts recursively
+ sort(a, left, less - 1, leftmost);
+ sort(a, great + 1, right, false);
}
-
- // Sort center part recursively, excluding known pivot values
- doSort(a, less, great);
}
/**
@@ -1531,7 +1862,7 @@ 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).
+ * 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 float
* values: {@code -0.0f == 0.0f} is {@code true} and a {@code Float.NaN}
@@ -1565,162 +1896,207 @@ final class DualPivotQuicksort {
*/
private static void sortNegZeroAndNaN(float[] a, int left, int right) {
/*
- * Phase 1: Count negative zeros and move NaNs to end of array
+ * Phase 1: Move NaNs to the end of the array.
*/
- final int NEGATIVE_ZERO = Float.floatToIntBits(-0.0f);
- int numNegativeZeros = 0;
- int n = right;
-
- for (int k = left; k <= n; k++) {
+ while (left <= right && Float.isNaN(a[right])) {
+ right--;
+ }
+ for (int k = right - 1; k >= left; k--) {
float ak = a[k];
- if (ak == 0.0f && NEGATIVE_ZERO == Float.floatToIntBits(ak)) {
- a[k] = 0.0f;
- numNegativeZeros++;
- } else if (ak != ak) { // i.e., ak is NaN
- a[k--] = a[n];
- a[n--] = Float.NaN;
+ if (ak != ak) { // a[k] is NaN
+ a[k] = a[right];
+ a[right] = ak;
+ right--;
}
}
/*
- * Phase 2: Sort everything except NaNs (which are already in place)
+ * Phase 2: Sort everything except NaNs (which are already in place).
*/
- doSort(a, left, n);
+ sort(a, left, right, true);
/*
- * Phase 3: Turn positive zeros back into negative zeros as appropriate
+ * Phase 3: Place negative zeros before positive zeros.
*/
- if (numNegativeZeros == 0) {
- return;
- }
+ int hi = right;
- // Find first zero element
- int zeroIndex = findAnyZero(a, left, n);
+ /*
+ * Search first zero, or first positive, or last negative element.
+ */
+ while (left < hi) {
+ int middle = (left + hi) >>> 1;
+ float middleValue = a[middle];
- for (int i = zeroIndex - 1; i >= left && a[i] == 0.0f; i--) {
- zeroIndex = i;
+ if (middleValue < 0.0f) {
+ left = middle + 1;
+ } else {
+ hi = middle;
+ }
}
- // Turn the right number of positive zeros back into negative zeros
- for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) {
- a[i] = -0.0f;
+ /*
+ * Skip the last negative value (if any) or all leading negative zeros.
+ */
+ while (left <= right && Float.floatToRawIntBits(a[left]) < 0) {
+ left++;
}
- }
-
- /**
- * Returns the index of some zero element in the specified range via
- * binary search. The range is assumed to be sorted, and must contain
- * at least one zero.
- *
- * @param a the array to be searched
- * @param low the index of the first element, inclusive, to be searched
- * @param high the index of the last element, inclusive, to be searched
- */
- private static int findAnyZero(float[] a, int low, int high) {
- while (true) {
- int middle = (low + high) >>> 1;
- float middleValue = a[middle];
- if (middleValue < 0.0f) {
- low = middle + 1;
- } else if (middleValue > 0.0f) {
- high = middle - 1;
- } else { // middleValue == 0.0f
- return middle;
+ /*
+ * Move negative zeros to the beginning of the sub-range.
+ *
+ * Partitioning:
+ *
+ * +---------------------------------------------------+
+ * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) |
+ * +---------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * left p k
+ *
+ * Invariants:
+ *
+ * all in (*, left) < 0.0
+ * all in [left, p) == -0.0
+ * all in [p, k) == 0.0
+ * all in [k, right] >= 0.0
+ *
+ * Pointer k is the first index of ?-part.
+ */
+ for (int k = left + 1, p = left; k <= right; k++) {
+ 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;
}
}
}
/**
- * Sorts the specified range of the array into ascending order. This
- * method differs from the public {@code sort} method in three ways:
- * {@code right} index is inclusive, it does no range checking on
- * {@code left} or {@code right}, and it does not handle negative
- * zeros or NaNs in the array.
+ * 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, which must not contain -0.0f or NaN
+ * @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 doSort(float[] a, int left, int right) {
+ private static void sort(float[] a, int left, int right,boolean leftmost) {
+ int length = right - left + 1;
+
// Use insertion sort on tiny arrays
- if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
- for (int i = left + 1; i <= right; i++) {
- float ai = a[i];
- int j;
- for (j = i - 1; j >= left && ai < a[j]; j--) {
- a[j + 1] = a[j];
+ 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 {
+ /*
+ * 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) {
+ float ai = a[i + 1];
+ while (ai < a[j]) {
+ a[j + 1] = a[j];
+ if (j-- == left) {
+ break;
+ }
+ }
+ a[j + 1] = ai;
}
- a[j + 1] = ai;
}
- } else { // Use Dual-Pivot Quicksort on large arrays
- dualPivotQuicksort(a, left, right);
+ return;
}
- }
- /**
- * Sorts the specified range of the array into ascending order by the
- * Dual-Pivot Quicksort algorithm.
- *
- * @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 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;
+ // Inexpensive approximation of length / 7
+ int seventh = (length >>> 3) + (length >>> 6) + 1;
- // Sort these elements using a 5-element sorting network
- float ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
+ /*
+ * 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;
- if (ae1 > ae2) { float t = ae1; ae1 = ae2; ae2 = t; }
- if (ae4 > ae5) { float t = ae4; ae4 = ae5; ae5 = t; }
- if (ae1 > ae3) { float t = ae1; ae1 = ae3; ae3 = t; }
- if (ae2 > ae3) { float t = ae2; ae2 = ae3; ae3 = t; }
- if (ae1 > ae4) { float t = ae1; ae1 = ae4; ae4 = t; }
- if (ae3 > ae4) { float t = ae3; ae3 = ae4; ae4 = t; }
- if (ae2 > ae5) { float t = ae2; ae2 = ae5; ae5 = t; }
- if (ae2 > ae3) { float t = ae2; ae2 = ae3; ae3 = t; }
- if (ae4 > ae5) { float t = ae4; ae4 = ae5; ae5 = t; }
+ // Sort these elements using insertion sort
+ if (a[e2] < a[e1]) { float t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
- a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
+ if (a[e3] < a[e2]) { float t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ if (a[e4] < a[e3]) { float t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+ if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ }
+ if (a[e5] < a[e4]) { float t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+ if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+ if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ }
+ }
/*
* 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 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.
*/
- float pivot1 = ae2; a[e2] = a[left];
- float pivot2 = ae4; a[e4] = a[right];
+ float pivot1 = a[e2];
+ float pivot2 = a[e4];
// 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
+ int less = left; // The index of the first element of center part
+ int great = right; // The index before the first element of right part
- boolean pivotsDiffer = (pivot1 != pivot2);
+ 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);
- if (pivotsDiffer) {
/*
* Partitioning:
*
- * left part center part right part
- * +------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +--------------------------------------------------------------+
+ * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
+ * +--------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -1728,16 +2104,14 @@ final class DualPivotQuicksort {
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
outer:
for (int k = less; k <= great; k++) {
float ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
@@ -1747,26 +2121,107 @@ final class DualPivotQuicksort {
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ a[less] = a[great];
+ less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
- a[great--] = ak;
}
+ 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) {
+ /*
+ * Skip elements, which are equal to pivot values.
+ */
+ while (a[less] == pivot1) {
+ less++;
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+
+ /*
+ * Partitioning:
+ *
+ * left part center part right part
+ * +----------------------------------------------------------+
+ * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
+ * +----------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (*, less) == pivot1
+ * pivot1 < all in [less, k) < pivot2
+ * all in (great, *) == pivot2
+ *
+ * Pointer k is the first index of ?-part.
+ */
+ outer:
+ for (int k = less; k <= great; k++) {
+ float ak = a[k];
+ if (ak == pivot1) { // Move a[k] to left part
+ a[k] = a[less];
+ a[less] = ak;
+ less++;
+ } else if (ak == pivot2) { // Move a[k] to right part
+ while (a[great] == pivot2) {
+ if (great-- == k) {
+ break outer;
+ }
+ }
+ 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] = a[great];
+ less++;
+ } else { // pivot1 < a[great] < pivot2
+ a[k] = a[great];
+ }
+ a[great] = ak;
+ great--;
+ }
+ }
+ }
+
+ // Sort center part recursively
+ sort(a, less, great, false);
+
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way,
- * or "Dutch National Flag", partition:
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") schema:
*
- * left part center part right part
- * +----------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +----------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +-------------------------------------------------+
+ * | < pivot | == pivot | ? | > pivot |
+ * +-------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -1774,20 +2229,19 @@ final class DualPivotQuicksort {
* all in [less, k) == pivot
* all in (great, right) > pivot
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
- for (int k = less; k <= great; k++) {
- float ak = a[k];
- if (ak == pivot1) {
+ for (int k = left; k <= great; k++) {
+ if (a[k] == pivot1) {
continue;
}
+ float ak = a[k];
+
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
- } else { // (a[k] > pivot1) - Move a[k] to right part
+ } 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
@@ -1795,92 +2249,33 @@ final class DualPivotQuicksort {
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
+ // assert great > k;
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ a[less] = a[great];
+ less++;
} else { // a[great] == pivot1
- a[k] = pivot1;
- a[great--] = 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
- doSort(a, left, less - 2);
- doSort(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 > 2/3 of the array),
- * swap internal pivot values to ends
- */
- if (less < e1 && great > e5) {
- while (a[less] == pivot1) {
- less++;
- }
- while (a[great] == pivot2) {
- great--;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part
- */
- outer:
- for (int k = less; k <= great; k++) {
- float ak = a[k];
- 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++] = pivot1;
- } else { // pivot1 < a[great] < pivot2
+ /*
+ * 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] = a[great];
}
- a[great--] = pivot2;
- } else if (ak == pivot1) { // Move a[k] to left part
- a[k] = a[less];
- a[less++] = pivot1;
+ a[great] = ak;
+ great--;
}
}
- }
- // Sort center part recursively, excluding known pivot values
- doSort(a, less, great);
+ // Sort left and right parts recursively
+ sort(a, left, less - 1, leftmost);
+ sort(a, great + 1, right, false);
+ }
}
/**
@@ -1938,162 +2333,207 @@ final class DualPivotQuicksort {
*/
private static void sortNegZeroAndNaN(double[] a, int left, int right) {
/*
- * Phase 1: Count negative zeros and move NaNs to end of array
+ * Phase 1: Move NaNs to the end of the array.
*/
- final long NEGATIVE_ZERO = Double.doubleToLongBits(-0.0d);
- int numNegativeZeros = 0;
- int n = right;
-
- for (int k = left; k <= n; k++) {
+ while (left <= right && Double.isNaN(a[right])) {
+ right--;
+ }
+ for (int k = right - 1; k >= left; k--) {
double ak = a[k];
- if (ak == 0.0d && NEGATIVE_ZERO == Double.doubleToLongBits(ak)) {
- a[k] = 0.0d;
- numNegativeZeros++;
- } else if (ak != ak) { // i.e., ak is NaN
- a[k--] = a[n];
- a[n--] = Double.NaN;
+ if (ak != ak) { // a[k] is NaN
+ a[k] = a[right];
+ a[right] = ak;
+ right--;
}
}
/*
- * Phase 2: Sort everything except NaNs (which are already in place)
+ * Phase 2: Sort everything except NaNs (which are already in place).
*/
- doSort(a, left, n);
+ sort(a, left, right, true);
/*
- * Phase 3: Turn positive zeros back into negative zeros as appropriate
+ * Phase 3: Place negative zeros before positive zeros.
*/
- if (numNegativeZeros == 0) {
- return;
- }
+ int hi = right;
- // Find first zero element
- int zeroIndex = findAnyZero(a, left, n);
+ /*
+ * Search first zero, or first positive, or last negative element.
+ */
+ while (left < hi) {
+ int middle = (left + hi) >>> 1;
+ double middleValue = a[middle];
- for (int i = zeroIndex - 1; i >= left && a[i] == 0.0d; i--) {
- zeroIndex = i;
+ if (middleValue < 0.0d) {
+ left = middle + 1;
+ } else {
+ hi = middle;
+ }
}
- // Turn the right number of positive zeros back into negative zeros
- for (int i = zeroIndex, m = zeroIndex + numNegativeZeros; i < m; i++) {
- a[i] = -0.0d;
+ /*
+ * Skip the last negative value (if any) or all leading negative zeros.
+ */
+ while (left <= right && Double.doubleToRawLongBits(a[left]) < 0) {
+ left++;
}
- }
-
- /**
- * Returns the index of some zero element in the specified range via
- * binary search. The range is assumed to be sorted, and must contain
- * at least one zero.
- *
- * @param a the array to be searched
- * @param low the index of the first element, inclusive, to be searched
- * @param high the index of the last element, inclusive, to be searched
- */
- private static int findAnyZero(double[] a, int low, int high) {
- while (true) {
- int middle = (low + high) >>> 1;
- double middleValue = a[middle];
- if (middleValue < 0.0d) {
- low = middle + 1;
- } else if (middleValue > 0.0d) {
- high = middle - 1;
- } else { // middleValue == 0.0d
- return middle;
+ /*
+ * Move negative zeros to the beginning of the sub-range.
+ *
+ * Partitioning:
+ *
+ * +---------------------------------------------------+
+ * | < 0.0 | -0.0 | 0.0 | ? ( >= 0.0 ) |
+ * +---------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * left p k
+ *
+ * Invariants:
+ *
+ * all in (*, left) < 0.0
+ * all in [left, p) == -0.0
+ * all in [p, k) == 0.0
+ * all in [k, right] >= 0.0
+ *
+ * Pointer k is the first index of ?-part.
+ */
+ for (int k = left + 1, p = left; k <= right; k++) {
+ 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;
}
}
}
/**
- * Sorts the specified range of the array into ascending order. This
- * method differs from the public {@code sort} method in three ways:
- * {@code right} index is inclusive, it does no range checking on
- * {@code left} or {@code right}, and it does not handle negative
- * zeros or NaNs in the array.
+ * 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, which must not contain -0.0d and NaN
+ * @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 doSort(double[] a, int left, int right) {
+ private static void sort(double[] a, int left,int right,boolean leftmost) {
+ int length = right - left + 1;
+
// Use insertion sort on tiny arrays
- if (right - left + 1 < INSERTION_SORT_THRESHOLD) {
- for (int i = left + 1; i <= right; i++) {
- double ai = a[i];
- int j;
- for (j = i - 1; j >= left && ai < a[j]; j--) {
- a[j + 1] = a[j];
+ 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 {
+ /*
+ * 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) {
+ double ai = a[i + 1];
+ while (ai < a[j]) {
+ a[j + 1] = a[j];
+ if (j-- == left) {
+ break;
+ }
+ }
+ a[j + 1] = ai;
}
- a[j + 1] = ai;
}
- } else { // Use Dual-Pivot Quicksort on large arrays
- dualPivotQuicksort(a, left, right);
+ return;
}
- }
- /**
- * Sorts the specified range of the array into ascending order by the
- * Dual-Pivot Quicksort algorithm.
- *
- * @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 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;
+ // Inexpensive approximation of length / 7
+ int seventh = (length >>> 3) + (length >>> 6) + 1;
- // Sort these elements using a 5-element sorting network
- double ae1 = a[e1], ae2 = a[e2], ae3 = a[e3], ae4 = a[e4], ae5 = a[e5];
+ /*
+ * 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;
- if (ae1 > ae2) { double t = ae1; ae1 = ae2; ae2 = t; }
- if (ae4 > ae5) { double t = ae4; ae4 = ae5; ae5 = t; }
- if (ae1 > ae3) { double t = ae1; ae1 = ae3; ae3 = t; }
- if (ae2 > ae3) { double t = ae2; ae2 = ae3; ae3 = t; }
- if (ae1 > ae4) { double t = ae1; ae1 = ae4; ae4 = t; }
- if (ae3 > ae4) { double t = ae3; ae3 = ae4; ae4 = t; }
- if (ae2 > ae5) { double t = ae2; ae2 = ae5; ae5 = t; }
- if (ae2 > ae3) { double t = ae2; ae2 = ae3; ae3 = t; }
- if (ae4 > ae5) { double t = ae4; ae4 = ae5; ae5 = t; }
+ // Sort these elements using insertion sort
+ if (a[e2] < a[e1]) { double t = a[e2]; a[e2] = a[e1]; a[e1] = t; }
- a[e1] = ae1; a[e3] = ae3; a[e5] = ae5;
+ if (a[e3] < a[e2]) { double t = a[e3]; a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ if (a[e4] < a[e3]) { double t = a[e4]; a[e4] = a[e3]; a[e3] = t;
+ if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ }
+ if (a[e5] < a[e4]) { double t = a[e5]; a[e5] = a[e4]; a[e4] = t;
+ if (t < a[e3]) { a[e4] = a[e3]; a[e3] = t;
+ if (t < a[e2]) { a[e3] = a[e2]; a[e2] = t;
+ if (t < a[e1]) { a[e2] = a[e1]; a[e1] = t; }
+ }
+ }
+ }
/*
* 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 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.
*/
- double pivot1 = ae2; a[e2] = a[left];
- double pivot2 = ae4; a[e4] = a[right];
+ double pivot1 = a[e2];
+ double pivot2 = a[e4];
// 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
+ int less = left; // The index of the first element of center part
+ int great = right; // The index before the first element of right part
- boolean pivotsDiffer = (pivot1 != pivot2);
+ 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);
- if (pivotsDiffer) {
/*
* Partitioning:
*
- * left part center part right part
- * +------------------------------------------------------------+
- * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
- * +------------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +--------------------------------------------------------------+
+ * | < pivot1 | pivot1 <= && <= pivot2 | ? | > pivot2 |
+ * +--------------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -2101,16 +2541,14 @@ final class DualPivotQuicksort {
* pivot1 <= all in [less, k) <= pivot2
* all in (great, right) > pivot2
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
outer:
for (int k = less; k <= great; k++) {
double ak = a[k];
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
} else if (ak > pivot2) { // Move a[k] to right part
while (a[great] > pivot2) {
@@ -2120,26 +2558,107 @@ final class DualPivotQuicksort {
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ a[less] = a[great];
+ less++;
} else { // pivot1 <= a[great] <= pivot2
a[k] = a[great];
- a[great--] = ak;
}
+ 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) {
+ /*
+ * Skip elements, which are equal to pivot values.
+ */
+ while (a[less] == pivot1) {
+ less++;
+ }
+ while (a[great] == pivot2) {
+ great--;
+ }
+
+ /*
+ * Partitioning:
+ *
+ * left part center part right part
+ * +----------------------------------------------------------+
+ * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
+ * +----------------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
+ *
+ * Invariants:
+ *
+ * all in (*, less) == pivot1
+ * pivot1 < all in [less, k) < pivot2
+ * all in (great, *) == pivot2
+ *
+ * Pointer k is the first index of ?-part.
+ */
+ outer:
+ for (int k = less; k <= great; k++) {
+ double ak = a[k];
+ if (ak == pivot1) { // Move a[k] to left part
+ a[k] = a[less];
+ a[less] = ak;
+ less++;
+ } else if (ak == pivot2) { // Move a[k] to right part
+ while (a[great] == pivot2) {
+ if (great-- == k) {
+ break outer;
+ }
+ }
+ if (a[great] == pivot1) {
+ a[k] = a[less];
+ /*
+ * Even though a[great] equals to pivot1, the
+ * assignment a[less] = pivot1 may be incorrect,
+ * if a[great] and pivot1 are floating-point zeros
+ * of different signs. Therefore in float and
+ * double sorting methods we have to use more
+ * accurate assignment a[less] = a[great].
+ */
+ a[less] = a[great];
+ less++;
+ } else { // pivot1 < a[great] < pivot2
+ a[k] = a[great];
+ }
+ a[great] = ak;
+ great--;
+ }
+ }
+ }
+
+ // Sort center part recursively
+ sort(a, less, great, false);
+
} else { // Pivots are equal
/*
- * Partition degenerates to the traditional 3-way,
- * or "Dutch National Flag", partition:
+ * Partition degenerates to the traditional 3-way
+ * (or "Dutch National Flag") schema:
*
- * left part center part right part
- * +----------------------------------------------+
- * | < pivot | == pivot | ? | > pivot |
- * +----------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
+ * left part center part right part
+ * +-------------------------------------------------+
+ * | < pivot | == pivot | ? | > pivot |
+ * +-------------------------------------------------+
+ * ^ ^ ^
+ * | | |
+ * less k great
*
* Invariants:
*
@@ -2147,20 +2666,19 @@ final class DualPivotQuicksort {
* all in [less, k) == pivot
* all in (great, right) > pivot
*
- * Pointer k is the first index of ?-part
+ * Pointer k is the first index of ?-part.
*/
- for (int k = less; k <= great; k++) {
- double ak = a[k];
- if (ak == pivot1) {
+ for (int k = left; k <= great; k++) {
+ if (a[k] == pivot1) {
continue;
}
+ double ak = a[k];
+
if (ak < pivot1) { // Move a[k] to left part
- if (k != less) {
- a[k] = a[less];
- a[less] = ak;
- }
+ a[k] = a[less];
+ a[less] = ak;
less++;
- } else { // (a[k] > pivot1) - Move a[k] to right part
+ } 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
@@ -2168,102 +2686,43 @@ final class DualPivotQuicksort {
* In other words, a[e3] acts as a sentinel for great.
*/
while (a[great] > pivot1) {
+ // assert great > k;
great--;
}
if (a[great] < pivot1) {
a[k] = a[less];
- a[less++] = a[great];
- a[great--] = ak;
+ a[less] = a[great];
+ less++;
} else { // a[great] == pivot1
- a[k] = pivot1;
- a[great--] = 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
- doSort(a, left, less - 2);
- doSort(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 > 2/3 of the array),
- * swap internal pivot values to ends
- */
- if (less < e1 && great > e5) {
- while (a[less] == pivot1) {
- less++;
- }
- while (a[great] == pivot2) {
- great--;
- }
-
- /*
- * Partitioning:
- *
- * left part center part right part
- * +----------------------------------------------------------+
- * | == pivot1 | pivot1 < && < pivot2 | ? | == pivot2 |
- * +----------------------------------------------------------+
- * ^ ^ ^
- * | | |
- * less k great
- *
- * Invariants:
- *
- * all in (*, less) == pivot1
- * pivot1 < all in [less, k) < pivot2
- * all in (great, *) == pivot2
- *
- * Pointer k is the first index of ?-part
- */
- outer:
- for (int k = less; k <= great; k++) {
- double ak = a[k];
- 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++] = pivot1;
- } else { // pivot1 < a[great] < pivot2
+ /*
+ * 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] = a[great];
}
- a[great--] = pivot2;
- } else if (ak == pivot1) { // Move a[k] to left part
- a[k] = a[less];
- a[less++] = pivot1;
+ a[great] = ak;
+ great--;
}
}
- }
- // Sort center part recursively, excluding known pivot values
- doSort(a, less, great);
+ // Sort left and right parts recursively
+ sort(a, left, less - 1, leftmost);
+ sort(a, great + 1, right, false);
+ }
}
/**
- * Checks that {@code fromIndex} and {@code toIndex} are in
- * the range and throws an appropriate exception, if they aren't.
+ * 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 + ")");
+ "fromIndex: " + fromIndex + " > toIndex: " + toIndex);
}
if (fromIndex < 0) {
throw new ArrayIndexOutOfBoundsException(fromIndex);
diff --git a/src/share/classes/java/util/Scanner.java b/src/share/classes/java/util/Scanner.java
index 96f6e5bba54dda847286737d8545254ed3d18348..615250ccc3ccea031551fa6362b4ebfbc1dcb51d 100644
--- a/src/share/classes/java/util/Scanner.java
+++ b/src/share/classes/java/util/Scanner.java
@@ -343,7 +343,7 @@ import sun.misc.LRUCache;
*
* @since 1.5
*/
-public final class Scanner implements Iterator {
+public final class Scanner implements Iterator, Closeable {
// Internal buffer used to hold input
private CharBuffer buf;
diff --git a/src/share/classes/java/util/logging/LogManager.java b/src/share/classes/java/util/logging/LogManager.java
index 70337cb9427fac330c6f7e1aca04bfda4675401a..00f2d7c5e2fe5aed99b61cbc3e273a6fa41c37be 100644
--- a/src/share/classes/java/util/logging/LogManager.java
+++ b/src/share/classes/java/util/logging/LogManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@ package java.util.logging;
import java.io.*;
import java.util.*;
import java.security.*;
+import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
@@ -154,10 +155,10 @@ public class LogManager {
= new PropertyChangeSupport(LogManager.class);
private final static Level defaultLevel = Level.INFO;
- // Table of known loggers. Maps names to Loggers.
- private Hashtable> loggers =
- new Hashtable>();
- // Tree of known loggers
+ // Table of named Loggers that maps names to Loggers.
+ private Hashtable namedLoggers =
+ new Hashtable();
+ // Tree of named Loggers
private LogNode root = new LogNode(null);
private Logger rootLogger;
@@ -417,6 +418,121 @@ public class LogManager {
}});
}
+
+ // loggerRefQueue holds LoggerWeakRef objects for Logger objects
+ // that have been GC'ed.
+ private final ReferenceQueue loggerRefQueue
+ = new ReferenceQueue();
+
+ // Package-level inner class.
+ // Helper class for managing WeakReferences to Logger objects.
+ //
+ // LogManager.namedLoggers
+ // - has weak references to all named Loggers
+ // - namedLoggers keeps the LoggerWeakRef objects for the named
+ // Loggers around until we can deal with the book keeping for
+ // the named Logger that is being GC'ed.
+ // LogManager.LogNode.loggerRef
+ // - has a weak reference to a named Logger
+ // - the LogNode will also keep the LoggerWeakRef objects for
+ // the named Loggers around; currently LogNodes never go away.
+ // Logger.kids
+ // - has a weak reference to each direct child Logger; this
+ // includes anonymous and named Loggers
+ // - anonymous Loggers are always children of the rootLogger
+ // which is a strong reference; rootLogger.kids keeps the
+ // LoggerWeakRef objects for the anonymous Loggers around
+ // until we can deal with the book keeping.
+ //
+ final class LoggerWeakRef extends WeakReference {
+ private String name; // for namedLoggers cleanup
+ private LogNode node; // for loggerRef cleanup
+ private WeakReference parentRef; // for kids cleanup
+
+ LoggerWeakRef(Logger logger) {
+ super(logger, loggerRefQueue);
+
+ name = logger.getName(); // save for namedLoggers cleanup
+ }
+
+ // dispose of this LoggerWeakRef object
+ void dispose() {
+ if (node != null) {
+ // if we have a LogNode, then we were a named Logger
+ // so clear namedLoggers weak ref to us
+ manager.namedLoggers.remove(name);
+ name = null; // clear our ref to the Logger's name
+
+ node.loggerRef = null; // clear LogNode's weak ref to us
+ node = null; // clear our ref to LogNode
+ }
+
+ if (parentRef != null) {
+ // this LoggerWeakRef has or had a parent Logger
+ Logger parent = parentRef.get();
+ if (parent != null) {
+ // the parent Logger is still there so clear the
+ // parent Logger's weak ref to us
+ parent.removeChildLogger(this);
+ }
+ parentRef = null; // clear our weak ref to the parent Logger
+ }
+ }
+
+ // set the node field to the specified value
+ void setNode(LogNode node) {
+ this.node = node;
+ }
+
+ // set the parentRef field to the specified value
+ void setParentRef(WeakReference parentRef) {
+ this.parentRef = parentRef;
+ }
+ }
+
+ // Package-level method.
+ // Drain some Logger objects that have been GC'ed.
+ //
+ // drainLoggerRefQueueBounded() is called by addLogger() below
+ // and by Logger.getAnonymousLogger(String) so we'll drain up to
+ // MAX_ITERATIONS GC'ed Loggers for every Logger we add.
+ //
+ // On a WinXP VMware client, a MAX_ITERATIONS value of 400 gives
+ // us about a 50/50 mix in increased weak ref counts versus
+ // decreased weak ref counts in the AnonLoggerWeakRefLeak test.
+ // Here are stats for cleaning up sets of 400 anonymous Loggers:
+ // - test duration 1 minute
+ // - sample size of 125 sets of 400
+ // - average: 1.99 ms
+ // - minimum: 0.57 ms
+ // - maximum: 25.3 ms
+ //
+ // The same config gives us a better decreased weak ref count
+ // than increased weak ref count in the LoggerWeakRefLeak test.
+ // Here are stats for cleaning up sets of 400 named Loggers:
+ // - test duration 2 minutes
+ // - sample size of 506 sets of 400
+ // - average: 0.57 ms
+ // - minimum: 0.02 ms
+ // - maximum: 10.9 ms
+ //
+ private final static int MAX_ITERATIONS = 400;
+ final synchronized void drainLoggerRefQueueBounded() {
+ for (int i = 0; i < MAX_ITERATIONS; i++) {
+ if (loggerRefQueue == null) {
+ // haven't finished loading LogManager yet
+ break;
+ }
+
+ LoggerWeakRef ref = (LoggerWeakRef) loggerRefQueue.poll();
+ if (ref == null) {
+ break;
+ }
+ // a Logger object has been GC'ed so clean it up
+ ref.dispose();
+ }
+ }
+
/**
* Add a named logger. This does nothing and returns false if a logger
* with the same name is already registered.
@@ -439,13 +555,16 @@ public class LogManager {
throw new NullPointerException();
}
- WeakReference ref = loggers.get(name);
+ // cleanup some Loggers that have been GC'ed
+ drainLoggerRefQueueBounded();
+
+ LoggerWeakRef ref = namedLoggers.get(name);
if (ref != null) {
if (ref.get() == null) {
- // Hashtable holds stale weak reference
- // to a logger which has been GC-ed.
- // Allow to register new one.
- loggers.remove(name);
+ // It's possible that the Logger was GC'ed after the
+ // drainLoggerRefQueueBounded() call above so allow
+ // a new one to be registered.
+ namedLoggers.remove(name);
} else {
// We already have a registered logger with the given name.
return false;
@@ -454,7 +573,8 @@ public class LogManager {
// We're adding a new logger.
// Note that we are creating a weak reference here.
- loggers.put(name, new WeakReference(logger));
+ ref = new LoggerWeakRef(logger);
+ namedLoggers.put(name, ref);
// Apply any initial level defined for the new logger.
Level level = getLevelProperty(name+".level", null);
@@ -469,11 +589,11 @@ public class LogManager {
// Find the new node and its parent.
LogNode node = findNode(name);
- node.loggerRef = new WeakReference(logger);
+ node.loggerRef = ref;
Logger parent = null;
LogNode nodep = node.parent;
while (nodep != null) {
- WeakReference nodeRef = nodep.loggerRef;
+ LoggerWeakRef nodeRef = nodep.loggerRef;
if (nodeRef != null) {
parent = nodeRef.get();
if (parent != null) {
@@ -489,6 +609,9 @@ public class LogManager {
// Walk over the children and tell them we are their new parent.
node.walkAndSetParent(logger);
+ // new LogNode is ready so tell the LoggerWeakRef about it
+ ref.setNode(node);
+
return true;
}
@@ -572,7 +695,7 @@ public class LogManager {
* @return matching logger or null if none is found
*/
public synchronized Logger getLogger(String name) {
- WeakReference ref = loggers.get(name);
+ LoggerWeakRef ref = namedLoggers.get(name);
if (ref == null) {
return null;
}
@@ -580,7 +703,7 @@ public class LogManager {
if (logger == null) {
// Hashtable holds stale weak reference
// to a logger which has been GC-ed.
- loggers.remove(name);
+ namedLoggers.remove(name);
}
return logger;
}
@@ -594,7 +717,7 @@ public class LogManager {
* @return enumeration of logger name strings
*/
public synchronized Enumeration getLoggerNames() {
- return loggers.keys();
+ return namedLoggers.keys();
}
/**
@@ -942,7 +1065,7 @@ public class LogManager {
// Nested class to represent a node in our tree of named loggers.
private static class LogNode {
HashMap children;
- WeakReference loggerRef;
+ LoggerWeakRef loggerRef;
LogNode parent;
LogNode(LogNode parent) {
@@ -958,7 +1081,7 @@ public class LogManager {
Iterator values = children.values().iterator();
while (values.hasNext()) {
LogNode node = values.next();
- WeakReference ref = node.loggerRef;
+ LoggerWeakRef ref = node.loggerRef;
Logger logger = (ref == null) ? null : ref.get();
if (logger == null) {
node.walkAndSetParent(parent);
diff --git a/src/share/classes/java/util/logging/Logger.java b/src/share/classes/java/util/logging/Logger.java
index 57aa65cf42146c3e178fb29fd340d13bf897e5c1..234c09c0a8c25c215ab628d83e1be6569d780d64 100644
--- a/src/share/classes/java/util/logging/Logger.java
+++ b/src/share/classes/java/util/logging/Logger.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -183,7 +183,7 @@ public class Logger {
// We keep weak references from parents to children, but strong
// references from children to parents.
private volatile Logger parent; // our nearest parent.
- private ArrayList> kids; // WeakReferences to loggers that have us as parent
+ private ArrayList kids; // WeakReferences to loggers that have us as parent
private volatile Level levelObject;
private volatile int levelValue; // current effective level value
@@ -366,13 +366,8 @@ public class Logger {
*
* @return a newly created private Logger
*/
- public static synchronized Logger getAnonymousLogger() {
- LogManager manager = LogManager.getLogManager();
- Logger result = new Logger(null, null);
- result.anonymous = true;
- Logger root = manager.getLogger("");
- result.doSetParent(root);
- return result;
+ public static Logger getAnonymousLogger() {
+ return getAnonymousLogger(null);
}
/**
@@ -401,6 +396,8 @@ public class Logger {
*/
public static synchronized Logger getAnonymousLogger(String resourceBundleName) {
LogManager manager = LogManager.getLogManager();
+ // cleanup some Loggers that have been GC'ed
+ manager.drainLoggerRefQueueBounded();
Logger result = new Logger(null, resourceBundleName);
result.anonymous = true;
Logger root = manager.getLogger("");
@@ -1380,14 +1377,18 @@ public class Logger {
synchronized (treeLock) {
// Remove ourself from any previous parent.
+ LogManager.LoggerWeakRef ref = null;
if (parent != null) {
// assert parent.kids != null;
- for (Iterator> iter = parent.kids.iterator(); iter.hasNext(); ) {
- WeakReference ref = iter.next();
+ for (Iterator iter = parent.kids.iterator(); iter.hasNext(); ) {
+ ref = iter.next();
Logger kid = ref.get();
if (kid == this) {
+ // ref is used down below to complete the reparenting
iter.remove();
break;
+ } else {
+ ref = null;
}
}
// We have now removed ourself from our parents' kids.
@@ -1396,9 +1397,14 @@ public class Logger {
// Set our new parent.
parent = newParent;
if (parent.kids == null) {
- parent.kids = new ArrayList>(2);
+ parent.kids = new ArrayList(2);
+ }
+ if (ref == null) {
+ // we didn't have a previous parent
+ ref = manager.new LoggerWeakRef(this);
}
- parent.kids.add(new WeakReference(this));
+ ref.setParentRef(new WeakReference(parent));
+ parent.kids.add(ref);
// As a result of the reparenting, the effective level
// may have changed for us and our children.
@@ -1407,6 +1413,21 @@ public class Logger {
}
}
+ // Package-level method.
+ // Remove the weak reference for the specified child Logger from the
+ // kid list. We should only be called from LoggerWeakRef.dispose().
+ final void removeChildLogger(LogManager.LoggerWeakRef child) {
+ synchronized (treeLock) {
+ for (Iterator iter = kids.iterator(); iter.hasNext(); ) {
+ LogManager.LoggerWeakRef ref = iter.next();
+ if (ref == child) {
+ iter.remove();
+ return;
+ }
+ }
+ }
+ }
+
// Recalculate the effective level for this node and
// recursively for our children.
@@ -1438,7 +1459,7 @@ public class Logger {
// Recursively update the level on each of our kids.
if (kids != null) {
for (int i = 0; i < kids.size(); i++) {
- WeakReference ref = kids.get(i);
+ LogManager.LoggerWeakRef ref = kids.get(i);
Logger kid = ref.get();
if (kid != null) {
kid.updateEffectiveLevel();
diff --git a/src/share/classes/javax/imageio/stream/ImageInputStream.java b/src/share/classes/javax/imageio/stream/ImageInputStream.java
index 3e026c374a996578740b1e60b992485f394c1799..2496c9b05fe46a0345a45280ed595feb83bf49c1 100644
--- a/src/share/classes/javax/imageio/stream/ImageInputStream.java
+++ b/src/share/classes/javax/imageio/stream/ImageInputStream.java
@@ -25,6 +25,7 @@
package javax.imageio.stream;
+import java.io.Closeable;
import java.io.DataInput;
import java.io.IOException;
import java.nio.ByteOrder;
@@ -42,7 +43,7 @@ import java.nio.ByteOrder;
* @see MemoryCacheImageInputStream
*
*/
-public interface ImageInputStream extends DataInput {
+public interface ImageInputStream extends DataInput, Closeable {
/**
* Sets the desired byte order for future reads of data values
diff --git a/src/share/classes/javax/sound/midi/MidiDevice.java b/src/share/classes/javax/sound/midi/MidiDevice.java
index 56e4a61d8928ec8cd71eea4ad87655b33c2ccb62..0a8fed47855384e7c6d0d834169d669cf661be78 100644
--- a/src/share/classes/javax/sound/midi/MidiDevice.java
+++ b/src/share/classes/javax/sound/midi/MidiDevice.java
@@ -107,7 +107,7 @@ import java.util.List;
* @author Florian Bomers
*/
-public interface MidiDevice {
+public interface MidiDevice extends AutoCloseable {
/**
diff --git a/src/share/classes/javax/sound/midi/Receiver.java b/src/share/classes/javax/sound/midi/Receiver.java
index ce6e5a1fdd04deea5f539d710ce469a87391123d..3ff16565c3c8f378755a44e64b4f1269a8f46aed 100644
--- a/src/share/classes/javax/sound/midi/Receiver.java
+++ b/src/share/classes/javax/sound/midi/Receiver.java
@@ -38,7 +38,7 @@ package javax.sound.midi;
*
* @author Kara Kytle
*/
-public interface Receiver {
+public interface Receiver extends AutoCloseable {
//$$fb 2002-04-12: fix for 4662090: Contradiction in Receiver specification
diff --git a/src/share/classes/javax/sound/midi/Transmitter.java b/src/share/classes/javax/sound/midi/Transmitter.java
index 93232f131ce48cc4b473952028af82a0fbe45b0f..c9b173894e2ca2756d68662bd7884e0fb38c4e13 100644
--- a/src/share/classes/javax/sound/midi/Transmitter.java
+++ b/src/share/classes/javax/sound/midi/Transmitter.java
@@ -35,7 +35,7 @@ package javax.sound.midi;
*
* @author Kara Kytle
*/
-public interface Transmitter {
+public interface Transmitter extends AutoCloseable {
/**
diff --git a/src/share/classes/javax/sound/sampled/Line.java b/src/share/classes/javax/sound/sampled/Line.java
index 9ed7c44a078a97a2119aceecf720ec22d9b3b52e..7d94243703ded42c56b38e67c86f9f0d32d2db70 100644
--- a/src/share/classes/javax/sound/sampled/Line.java
+++ b/src/share/classes/javax/sound/sampled/Line.java
@@ -70,7 +70,7 @@ package javax.sound.sampled;
* @see LineEvent
* @since 1.3
*/
-public interface Line {
+public interface Line extends AutoCloseable {
/**
* Obtains the Line.Info object describing this
diff --git a/src/share/classes/javax/swing/JSplitPane.java b/src/share/classes/javax/swing/JSplitPane.java
index 4ef14511cd1fd58fa38f5febf8b938fffbb6cb8f..b6956f9b498fa35dee379c3225c8e30330b8d9c0 100644
--- a/src/share/classes/javax/swing/JSplitPane.java
+++ b/src/share/classes/javax/swing/JSplitPane.java
@@ -242,19 +242,19 @@ public class JSplitPane extends JComponent implements Accessible
/**
* Creates a new JSplitPane configured to arrange the child
- * components side-by-side horizontally with no continuous
- * layout, using two buttons for the components.
+ * components side-by-side horizontally, using two buttons for the components.
*/
public JSplitPane() {
- this(JSplitPane.HORIZONTAL_SPLIT, false,
- new JButton(UIManager.getString("SplitPane.leftButtonText")),
- new JButton(UIManager.getString("SplitPane.rightButtonText")));
+ this(JSplitPane.HORIZONTAL_SPLIT,
+ UIManager.getBoolean("SplitPane.continuousLayout"),
+ new JButton(UIManager.getString("SplitPane.leftButtonText")),
+ new JButton(UIManager.getString("SplitPane.rightButtonText")));
}
/**
* Creates a new JSplitPane configured with the
- * specified orientation and no continuous layout.
+ * specified orientation.
*
* @param newOrientation JSplitPane.HORIZONTAL_SPLIT or
* JSplitPane.VERTICAL_SPLIT
@@ -263,7 +263,8 @@ public class JSplitPane extends JComponent implements Accessible
*/
@ConstructorProperties({"orientation"})
public JSplitPane(int newOrientation) {
- this(newOrientation, false);
+ this(newOrientation,
+ UIManager.getBoolean("SplitPane.continuousLayout"));
}
@@ -287,9 +288,7 @@ public class JSplitPane extends JComponent implements Accessible
/**
* Creates a new JSplitPane with the specified
- * orientation and
- * with the specified components that do not do continuous
- * redrawing.
+ * orientation and the specified components.
*
* @param newOrientation JSplitPane.HORIZONTAL_SPLIT or
* JSplitPane.VERTICAL_SPLIT
@@ -307,7 +306,9 @@ public class JSplitPane extends JComponent implements Accessible
public JSplitPane(int newOrientation,
Component newLeftComponent,
Component newRightComponent){
- this(newOrientation, false, newLeftComponent, newRightComponent);
+ this(newOrientation,
+ UIManager.getBoolean("SplitPane.continuousLayout"),
+ newLeftComponent, newRightComponent);
}
diff --git a/src/share/classes/javax/swing/JTable.java b/src/share/classes/javax/swing/JTable.java
index fd0e4eab69740dd868c69d108aa82b554577222e..8ca98bbe15ac77c459a5960c62046556adf622b8 100644
--- a/src/share/classes/javax/swing/JTable.java
+++ b/src/share/classes/javax/swing/JTable.java
@@ -1048,7 +1048,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable
/**
* Returns the horizontal and vertical space between cells.
- * The default spacing is (1, 1), which provides room to draw the grid.
+ * The default spacing is look and feel dependent.
*
* @return the horizontal and vertical spacing between cells
* @see #setIntercellSpacing
@@ -1155,7 +1155,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable
/**
* Returns true if the table draws horizontal lines between cells, false if it
- * doesn't. The default is true.
+ * doesn't. The default value is look and feel dependent.
*
* @return true if the table draws horizontal lines between cells, false if it
* doesn't
@@ -1167,7 +1167,7 @@ public class JTable extends JComponent implements TableModelListener, Scrollable
/**
* Returns true if the table draws vertical lines between cells, false if it
- * doesn't. The default is true.
+ * doesn't. The default value is look and feel dependent.
*
* @return true if the table draws vertical lines between cells, false if it
* doesn't
diff --git a/src/share/classes/javax/swing/JTree.java b/src/share/classes/javax/swing/JTree.java
index f90ab56a91dd1eee3b2e5bfeaf7073cc5961cba4..c99584ed341d632ddb6a0abb6defded27918c632 100644
--- a/src/share/classes/javax/swing/JTree.java
+++ b/src/share/classes/javax/swing/JTree.java
@@ -1986,20 +1986,17 @@ public class JTree extends JComponent implements Scrollable, Accessible
* true if all nodes in the path are expanded
*/
public boolean isExpanded(TreePath path) {
- if(path == null)
- return false;
-
- // Is this node expanded?
- Boolean value = expandedState.get(path);
- if(value == null || !value.booleanValue())
+ if(path == null)
return false;
+ Object value;
- // It is, make sure its parent is also expanded.
- TreePath parentPath = path.getParentPath();
+ do{
+ value = expandedState.get(path);
+ if(value == null || !((Boolean)value).booleanValue())
+ return false;
+ } while( (path=path.getParentPath())!=null );
- if(parentPath != null)
- return isExpanded(parentPath);
return true;
}
diff --git a/src/share/classes/javax/swing/border/TitledBorder.java b/src/share/classes/javax/swing/border/TitledBorder.java
index 5e382cbe832fa6985727632b269e70f86f6e6c36..3bf385e44c11958fabaeb385a6eab0133892bdc4 100644
--- a/src/share/classes/javax/swing/border/TitledBorder.java
+++ b/src/share/classes/javax/swing/border/TitledBorder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -24,22 +24,20 @@
*/
package javax.swing.border;
-import sun.swing.SwingUtilities2;
-
-import java.awt.Graphics;
-import java.awt.Insets;
-import java.awt.Rectangle;
import java.awt.Color;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Point;
-import java.awt.Toolkit;
import java.awt.Component;
import java.awt.Dimension;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Rectangle;
+import java.awt.geom.Path2D;
import java.beans.ConstructorProperties;
-
import javax.swing.JComponent;
+import javax.swing.JLabel;
import javax.swing.UIManager;
+import javax.swing.plaf.basic.BasicHTML;
/**
* A class which implements an arbitrary border
@@ -73,40 +71,40 @@ public class TitledBorder extends AbstractBorder
{
protected String title;
protected Border border;
- protected int titlePosition;
- protected int titleJustification;
- protected Font titleFont;
- protected Color titleColor;
+ protected int titlePosition;
+ protected int titleJustification;
+ protected Font titleFont;
+ protected Color titleColor;
- private Point textLoc = new Point();
+ private final JLabel label;
/**
* Use the default vertical orientation for the title text.
*/
static public final int DEFAULT_POSITION = 0;
/** Position the title above the border's top line. */
- static public final int ABOVE_TOP = 1;
+ static public final int ABOVE_TOP = 1;
/** Position the title in the middle of the border's top line. */
- static public final int TOP = 2;
+ static public final int TOP = 2;
/** Position the title below the border's top line. */
- static public final int BELOW_TOP = 3;
+ static public final int BELOW_TOP = 3;
/** Position the title above the border's bottom line. */
- static public final int ABOVE_BOTTOM = 4;
+ static public final int ABOVE_BOTTOM = 4;
/** Position the title in the middle of the border's bottom line. */
- static public final int BOTTOM = 5;
+ static public final int BOTTOM = 5;
/** Position the title below the border's bottom line. */
- static public final int BELOW_BOTTOM = 6;
+ static public final int BELOW_BOTTOM = 6;
/**
* Use the default justification for the title text.
*/
static public final int DEFAULT_JUSTIFICATION = 0;
/** Position title text at the left side of the border line. */
- static public final int LEFT = 1;
+ static public final int LEFT = 1;
/** Position title text in the center of the border line. */
- static public final int CENTER = 2;
+ static public final int CENTER = 2;
/** Position title text at the right side of the border line. */
- static public final int RIGHT = 3;
+ static public final int RIGHT = 3;
/** Position title text at the left side of the border line
* for left to right orientation, at the right side of the
* border line for right to left orientation.
@@ -132,7 +130,7 @@ public class TitledBorder extends AbstractBorder
*
* @param title the title the border should display
*/
- public TitledBorder(String title) {
+ public TitledBorder(String title) {
this(null, title, LEADING, DEFAULT_POSITION, null, null);
}
@@ -142,7 +140,7 @@ public class TitledBorder extends AbstractBorder
*
* @param border the border
*/
- public TitledBorder(Border border) {
+ public TitledBorder(Border border) {
this(border, "", LEADING, DEFAULT_POSITION, null, null);
}
@@ -167,9 +165,9 @@ public class TitledBorder extends AbstractBorder
* @param titlePosition the position for the title
*/
public TitledBorder(Border border,
- String title,
- int titleJustification,
- int titlePosition) {
+ String title,
+ int titleJustification,
+ int titlePosition) {
this(border, title, titleJustification,
titlePosition, null, null);
}
@@ -185,10 +183,10 @@ public class TitledBorder extends AbstractBorder
* @param titleFont the font for rendering the title
*/
public TitledBorder(Border border,
- String title,
- int titleJustification,
- int titlePosition,
- Font titleFont) {
+ String title,
+ int titleJustification,
+ int titlePosition,
+ Font titleFont) {
this(border, title, titleJustification,
titlePosition, titleFont, null);
}
@@ -207,11 +205,11 @@ public class TitledBorder extends AbstractBorder
*/
@ConstructorProperties({"border", "title", "titleJustification", "titlePosition", "titleFont", "titleColor"})
public TitledBorder(Border border,
- String title,
- int titleJustification,
- int titlePosition,
- Font titleFont,
- Color titleColor) {
+ String title,
+ int titleJustification,
+ int titlePosition,
+ Font titleFont,
+ Color titleColor) {
this.title = title;
this.border = border;
this.titleFont = titleFont;
@@ -219,6 +217,10 @@ public class TitledBorder extends AbstractBorder
setTitleJustification(titleJustification);
setTitlePosition(titlePosition);
+
+ this.label = new JLabel();
+ this.label.setOpaque(false);
+ this.label.putClientProperty(BasicHTML.propertyKey, null);
}
/**
@@ -232,178 +234,111 @@ public class TitledBorder extends AbstractBorder
* @param height the height of the painted border
*/
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
-
- Border border = getBorder();
-
- if (getTitle() == null || getTitle().equals("")) {
- if (border != null) {
- border.paintBorder(c, g, x, y, width, height);
+ Border border = getBorderUI();
+ String title = getTitle();
+ if ((title != null) && !title.isEmpty()) {
+ int edge = (border instanceof TitledBorder) ? 0 : EDGE_SPACING;
+ JLabel label = getLabel(c);
+ Dimension size = label.getPreferredSize();
+ Insets insets = (border != null)
+ ? border.getBorderInsets(c)
+ : new Insets(0, 0, 0, 0);
+
+ int borderX = x + edge;
+ int borderY = y + edge;
+ int borderW = width - edge - edge;
+ int borderH = height - edge - edge;
+
+ int labelY = y;
+ int labelH = size.height;
+ int position = getPosition();
+ switch (position) {
+ case ABOVE_TOP:
+ insets.left = 0;
+ insets.right = 0;
+ borderY += labelH - edge;
+ borderH -= labelH - edge;
+ break;
+ case TOP:
+ insets.top = edge + insets.top/2 - labelH/2;
+ if (insets.top < edge) {
+ borderY -= insets.top;
+ borderH += insets.top;
+ }
+ else {
+ labelY += insets.top;
+ }
+ break;
+ case BELOW_TOP:
+ labelY += insets.top + edge;
+ break;
+ case ABOVE_BOTTOM:
+ labelY += height - labelH - insets.bottom - edge;
+ break;
+ case BOTTOM:
+ labelY += height - labelH;
+ insets.bottom = edge + (insets.bottom - labelH) / 2;
+ if (insets.bottom < edge) {
+ borderH += insets.bottom;
+ }
+ else {
+ labelY -= insets.bottom;
+ }
+ break;
+ case BELOW_BOTTOM:
+ insets.left = 0;
+ insets.right = 0;
+ labelY += height - labelH;
+ borderH -= labelH - edge;
+ break;
}
- return;
- }
+ insets.left += edge + TEXT_INSET_H;
+ insets.right += edge + TEXT_INSET_H;
- Rectangle grooveRect = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING,
- width - (EDGE_SPACING * 2),
- height - (EDGE_SPACING * 2));
- Font font = g.getFont();
- Color color = g.getColor();
-
- g.setFont(getFont(c));
-
- JComponent jc = (c instanceof JComponent) ? (JComponent)c : null;
- FontMetrics fm = SwingUtilities2.getFontMetrics(jc, g);
- int fontHeight = fm.getHeight();
- int descent = fm.getDescent();
- int ascent = fm.getAscent();
- int diff;
- int stringWidth = SwingUtilities2.stringWidth(jc, fm,
- getTitle());
- Insets insets;
-
- if (border != null) {
- insets = border.getBorderInsets(c);
- } else {
- insets = new Insets(0, 0, 0, 0);
- }
-
- int titlePos = getTitlePosition();
- switch (titlePos) {
- case ABOVE_TOP:
- diff = ascent + descent + (Math.max(EDGE_SPACING,
- TEXT_SPACING*2) - EDGE_SPACING);
- grooveRect.y += diff;
- grooveRect.height -= diff;
- textLoc.y = grooveRect.y - (descent + TEXT_SPACING);
- break;
- case TOP:
- case DEFAULT_POSITION:
- diff = Math.max(0, ((ascent/2) + TEXT_SPACING) - EDGE_SPACING);
- grooveRect.y += diff;
- grooveRect.height -= diff;
- textLoc.y = (grooveRect.y - descent) +
- (insets.top + ascent + descent)/2;
- break;
- case BELOW_TOP:
- textLoc.y = grooveRect.y + insets.top + ascent + TEXT_SPACING;
- break;
- case ABOVE_BOTTOM:
- textLoc.y = (grooveRect.y + grooveRect.height) -
- (insets.bottom + descent + TEXT_SPACING);
- break;
- case BOTTOM:
- grooveRect.height -= fontHeight/2;
- textLoc.y = ((grooveRect.y + grooveRect.height) - descent) +
- ((ascent + descent) - insets.bottom)/2;
- break;
- case BELOW_BOTTOM:
- grooveRect.height -= fontHeight;
- textLoc.y = grooveRect.y + grooveRect.height + ascent +
- TEXT_SPACING;
- break;
- }
-
- int justification = getTitleJustification();
- if(isLeftToRight(c)) {
- if(justification==LEADING ||
- justification==DEFAULT_JUSTIFICATION) {
- justification = LEFT;
- }
- else if(justification==TRAILING) {
- justification = RIGHT;
- }
- }
- else {
- if(justification==LEADING ||
- justification==DEFAULT_JUSTIFICATION) {
- justification = RIGHT;
+ int labelX = x;
+ int labelW = width - insets.left - insets.right;
+ if (labelW > size.width) {
+ labelW = size.width;
}
- else if(justification==TRAILING) {
- justification = LEFT;
+ switch (getJustification(c)) {
+ case LEFT:
+ labelX += insets.left;
+ break;
+ case RIGHT:
+ labelX += width - insets.right - labelW;
+ break;
+ case CENTER:
+ labelX += (width - labelW) / 2;
+ break;
}
- }
-
- switch (justification) {
- case LEFT:
- textLoc.x = grooveRect.x + TEXT_INSET_H + insets.left;
- break;
- case RIGHT:
- textLoc.x = (grooveRect.x + grooveRect.width) -
- (stringWidth + TEXT_INSET_H + insets.right);
- break;
- case CENTER:
- textLoc.x = grooveRect.x +
- ((grooveRect.width - stringWidth) / 2);
- break;
- }
- // If title is positioned in middle of border AND its fontsize
- // is greater than the border's thickness, we'll need to paint
- // the border in sections to leave space for the component's background
- // to show through the title.
- //
- if (border != null) {
- if (((titlePos == TOP || titlePos == DEFAULT_POSITION) &&
- (grooveRect.y > textLoc.y - ascent)) ||
- (titlePos == BOTTOM &&
- (grooveRect.y + grooveRect.height < textLoc.y + descent))) {
-
- Rectangle clipRect = new Rectangle();
-
- // save original clip
- Rectangle saveClip = g.getClipBounds();
-
- // paint strip left of text
- clipRect.setBounds(saveClip);
- if (computeIntersection(clipRect, x, y, textLoc.x-1-x, height)) {
- g.setClip(clipRect);
- border.paintBorder(c, g, grooveRect.x, grooveRect.y,
- grooveRect.width, grooveRect.height);
- }
-
- // paint strip right of text
- clipRect.setBounds(saveClip);
- if (computeIntersection(clipRect, textLoc.x+stringWidth+1, y,
- x+width-(textLoc.x+stringWidth+1), height)) {
- g.setClip(clipRect);
- border.paintBorder(c, g, grooveRect.x, grooveRect.y,
- grooveRect.width, grooveRect.height);
+ if (border != null) {
+ if ((position != TOP) && (position != BOTTOM)) {
+ border.paintBorder(c, g, borderX, borderY, borderW, borderH);
}
-
- if (titlePos == TOP || titlePos == DEFAULT_POSITION) {
- // paint strip below text
- clipRect.setBounds(saveClip);
- if (computeIntersection(clipRect, textLoc.x-1, textLoc.y+descent,
- stringWidth+2, y+height-textLoc.y-descent)) {
- g.setClip(clipRect);
- border.paintBorder(c, g, grooveRect.x, grooveRect.y,
- grooveRect.width, grooveRect.height);
- }
-
- } else { // titlePos == BOTTOM
- // paint strip above text
- clipRect.setBounds(saveClip);
- if (computeIntersection(clipRect, textLoc.x-1, y,
- stringWidth+2, textLoc.y - ascent - y)) {
- g.setClip(clipRect);
- border.paintBorder(c, g, grooveRect.x, grooveRect.y,
- grooveRect.width, grooveRect.height);
+ else {
+ Graphics g2 = g.create();
+ if (g2 instanceof Graphics2D) {
+ Graphics2D g2d = (Graphics2D) g2;
+ Path2D path = new Path2D.Float();
+ path.append(new Rectangle(borderX, borderY, borderW, labelY - borderY), false);
+ path.append(new Rectangle(borderX, labelY, labelX - borderX - TEXT_SPACING, labelH), false);
+ path.append(new Rectangle(labelX + labelW + TEXT_SPACING, labelY, borderX - labelX + borderW - labelW - TEXT_SPACING, labelH), false);
+ path.append(new Rectangle(borderX, labelY + labelH, borderW, borderY - labelY + borderH - labelH), false);
+ g2d.clip(path);
}
+ border.paintBorder(c, g2, borderX, borderY, borderW, borderH);
+ g2.dispose();
}
-
- // restore clip
- g.setClip(saveClip);
-
- } else {
- border.paintBorder(c, g, grooveRect.x, grooveRect.y,
- grooveRect.width, grooveRect.height);
}
+ g.translate(labelX, labelY);
+ label.setSize(labelW, labelH);
+ label.paint(g);
+ g.translate(-labelX, -labelY);
+ }
+ else if (border != null) {
+ border.paintBorder(c, g, x, y, width, height);
}
-
- g.setColor(getTitleColor());
- SwingUtilities2.drawString(jc, g, getTitle(), textLoc.x, textLoc.y);
-
- g.setFont(font);
- g.setColor(color);
}
/**
@@ -412,69 +347,54 @@ public class TitledBorder extends AbstractBorder
* @param insets the object to be reinitialized
*/
public Insets getBorderInsets(Component c, Insets insets) {
- FontMetrics fm;
- int descent = 0;
- int ascent = 16;
- int height = 16;
-
- Border border = getBorder();
- if (border != null) {
- if (border instanceof AbstractBorder) {
- ((AbstractBorder)border).getBorderInsets(c, insets);
- } else {
- // Can't reuse border insets because the Border interface
- // can't be enhanced.
- Insets i = border.getBorderInsets(c);
- insets.top = i.top;
- insets.right = i.right;
- insets.bottom = i.bottom;
- insets.left = i.left;
- }
- } else {
- insets.left = insets.top = insets.right = insets.bottom = 0;
+ Border border = getBorderUI();
+ if (border == null) {
+ insets.set(0, 0, 0, 0);
}
-
- insets.left += EDGE_SPACING + TEXT_SPACING;
- insets.right += EDGE_SPACING + TEXT_SPACING;
- insets.top += EDGE_SPACING + TEXT_SPACING;
- insets.bottom += EDGE_SPACING + TEXT_SPACING;
-
- if(c == null || getTitle() == null || getTitle().equals("")) {
- return insets;
+ else if (border instanceof AbstractBorder) {
+ AbstractBorder ab = (AbstractBorder) border;
+ insets = ab.getBorderInsets(c, insets);
}
-
- Font font = getFont(c);
-
- fm = c.getFontMetrics(font);
-
- if(fm != null) {
- descent = fm.getDescent();
- ascent = fm.getAscent();
- height = fm.getHeight();
+ else {
+ Insets i = border.getBorderInsets(c);
+ insets.set(i.top, i.left, i.bottom, i.right);
}
-
- switch (getTitlePosition()) {
- case ABOVE_TOP:
- insets.top += ascent + descent
- + (Math.max(EDGE_SPACING, TEXT_SPACING*2)
- - EDGE_SPACING);
- break;
- case TOP:
- case DEFAULT_POSITION:
- insets.top += ascent + descent;
- break;
- case BELOW_TOP:
- insets.top += ascent + descent + TEXT_SPACING;
- break;
- case ABOVE_BOTTOM:
- insets.bottom += ascent + descent + TEXT_SPACING;
- break;
- case BOTTOM:
- insets.bottom += ascent + descent;
- break;
- case BELOW_BOTTOM:
- insets.bottom += height;
- break;
+ String title = getTitle();
+ if ((title != null) && !title.isEmpty()) {
+ int edge = (border instanceof TitledBorder) ? 0 : EDGE_SPACING;
+ JLabel label = getLabel(c);
+ Dimension size = label.getPreferredSize();
+
+ switch (getPosition()) {
+ case ABOVE_TOP:
+ insets.top += size.height - edge;
+ break;
+ case TOP: {
+ if (insets.top < size.height) {
+ insets.top = size.height - edge;
+ }
+ break;
+ }
+ case BELOW_TOP:
+ insets.top += size.height;
+ break;
+ case ABOVE_BOTTOM:
+ insets.bottom += size.height;
+ break;
+ case BOTTOM: {
+ if (insets.bottom < size.height) {
+ insets.bottom = size.height - edge;
+ }
+ break;
+ }
+ case BELOW_BOTTOM:
+ insets.bottom += size.height - edge;
+ break;
+ }
+ insets.top += edge + TEXT_SPACING;
+ insets.left += edge + TEXT_SPACING;
+ insets.right += edge + TEXT_SPACING;
+ insets.bottom += edge + TEXT_SPACING;
}
return insets;
}
@@ -492,41 +412,14 @@ public class TitledBorder extends AbstractBorder
/**
* Returns the border of the titled border.
*/
- public Border getBorder() {
- Border b = border;
- if (b == null)
- b = UIManager.getBorder("TitledBorder.border");
- return b;
+ public Border getBorder() {
+ return border;
}
/**
* Returns the title-position of the titled border.
*/
public int getTitlePosition() {
- if (titlePosition == DEFAULT_POSITION) {
- Object value = UIManager.get("TitledBorder.position");
- if (value instanceof String) {
- String s = (String)value;
- if ("ABOVE_TOP".equalsIgnoreCase(s)) {
- return ABOVE_TOP;
- } else if ("TOP".equalsIgnoreCase(s)) {
- return TOP;
- } else if ("BELOW_TOP".equalsIgnoreCase(s)) {
- return BELOW_TOP;
- } else if ("ABOVE_BOTTOM".equalsIgnoreCase(s)) {
- return ABOVE_BOTTOM;
- } else if ("BOTTOM".equalsIgnoreCase(s)) {
- return BOTTOM;
- } else if ("BELOW_BOTTOM".equalsIgnoreCase(s)) {
- return BELOW_BOTTOM;
- }
- } else if (value instanceof Integer) {
- int i = (Integer)value;
- if (i >= 0 && i <= 6) {
- return i;
- }
- }
- }
return titlePosition;
}
@@ -539,20 +432,14 @@ public class TitledBorder extends AbstractBorder
* Returns the title-font of the titled border.
*/
public Font getTitleFont() {
- Font f = titleFont;
- if (f == null)
- f = UIManager.getFont("TitledBorder.font");
- return f;
+ return titleFont;
}
/**
* Returns the title-color of the titled border.
*/
public Color getTitleColor() {
- Color c = titleColor;
- if (c == null)
- c = UIManager.getColor("TitledBorder.titleColor");
- return c;
+ return titleColor;
}
@@ -576,18 +463,18 @@ public class TitledBorder extends AbstractBorder
*/
public void setTitlePosition(int titlePosition) {
switch (titlePosition) {
- case ABOVE_TOP:
- case TOP:
- case BELOW_TOP:
- case ABOVE_BOTTOM:
- case BOTTOM:
- case BELOW_BOTTOM:
- case DEFAULT_POSITION:
+ case ABOVE_TOP:
+ case TOP:
+ case BELOW_TOP:
+ case ABOVE_BOTTOM:
+ case BOTTOM:
+ case BELOW_BOTTOM:
+ case DEFAULT_POSITION:
this.titlePosition = titlePosition;
break;
- default:
- throw new IllegalArgumentException(titlePosition +
- " is not a valid title position.");
+ default:
+ throw new IllegalArgumentException(titlePosition +
+ " is not a valid title position.");
}
}
@@ -624,7 +511,7 @@ public class TitledBorder extends AbstractBorder
* @param titleColor the color for the border title
*/
public void setTitleColor(Color titleColor) {
- this.titleColor = titleColor;
+ this.titleColor = titleColor;
}
/**
@@ -636,22 +523,18 @@ public class TitledBorder extends AbstractBorder
Insets insets = getBorderInsets(c);
Dimension minSize = new Dimension(insets.right+insets.left,
insets.top+insets.bottom);
- Font font = getFont(c);
- FontMetrics fm = c.getFontMetrics(font);
- JComponent jc = (c instanceof JComponent) ? (JComponent)c : null;
- switch (getTitlePosition()) {
- case ABOVE_TOP:
- case BELOW_BOTTOM:
- minSize.width = Math.max(SwingUtilities2.stringWidth(jc, fm,
- getTitle()), minSize.width);
- break;
- case BELOW_TOP:
- case ABOVE_BOTTOM:
- case TOP:
- case BOTTOM:
- case DEFAULT_POSITION:
- default:
- minSize.width += SwingUtilities2.stringWidth(jc, fm, getTitle());
+ String title = getTitle();
+ if ((title != null) && !title.isEmpty()) {
+ JLabel label = getLabel(c);
+ Dimension size = label.getPreferredSize();
+
+ int position = getPosition();
+ if ((position != ABOVE_TOP) && (position != BELOW_BOTTOM)) {
+ minSize.width += size.width;
+ }
+ else if (minSize.width < size.width) {
+ minSize.width += size.width;
+ }
}
return minSize;
}
@@ -674,48 +557,36 @@ public class TitledBorder extends AbstractBorder
if (height < 0) {
throw new IllegalArgumentException("Height must be >= 0");
}
+ Border border = getBorderUI();
String title = getTitle();
- if (title != null && !"".equals(title)) {
- Font font = getFont(c);
- Border border2 = getBorder();
- Insets borderInsets;
- if (border2 != null) {
- borderInsets = border2.getBorderInsets(c);
- }
- else {
- borderInsets = new Insets(0, 0, 0, 0);
- }
- FontMetrics fm = c.getFontMetrics(font);
- int fontHeight = fm.getHeight();
- int descent = fm.getDescent();
- int ascent = fm.getAscent();
- int y = EDGE_SPACING;
- int h = height - EDGE_SPACING * 2;
- int diff;
- switch (getTitlePosition()) {
- case ABOVE_TOP:
- diff = ascent + descent + (Math.max(EDGE_SPACING,
- TEXT_SPACING * 2) -
- EDGE_SPACING);
- return y + diff - (descent + TEXT_SPACING);
- case TOP:
- case DEFAULT_POSITION:
- diff = Math.max(0, ((ascent/2) + TEXT_SPACING) -
- EDGE_SPACING);
- return (y + diff - descent) +
- (borderInsets.top + ascent + descent)/2;
- case BELOW_TOP:
- return y + borderInsets.top + ascent + TEXT_SPACING;
- case ABOVE_BOTTOM:
- return (y + h) - (borderInsets.bottom + descent +
- TEXT_SPACING);
- case BOTTOM:
- h -= fontHeight / 2;
- return ((y + h) - descent) +
- ((ascent + descent) - borderInsets.bottom)/2;
- case BELOW_BOTTOM:
- h -= fontHeight;
- return y + h + ascent + TEXT_SPACING;
+ if ((title != null) && !title.isEmpty()) {
+ int edge = (border instanceof TitledBorder) ? 0 : EDGE_SPACING;
+ JLabel label = getLabel(c);
+ Dimension size = label.getPreferredSize();
+ Insets insets = (border != null)
+ ? border.getBorderInsets(c)
+ : new Insets(0, 0, 0, 0);
+
+ int baseline = label.getBaseline(size.width, size.height);
+ switch (getPosition()) {
+ case ABOVE_TOP:
+ return baseline;
+ case TOP:
+ insets.top = edge + (insets.top - size.height) / 2;
+ return (insets.top < edge)
+ ? baseline
+ : baseline + insets.top;
+ case BELOW_TOP:
+ return baseline + insets.top + edge;
+ case ABOVE_BOTTOM:
+ return baseline + height - size.height - insets.bottom - edge;
+ case BOTTOM:
+ insets.bottom = edge + (insets.bottom - size.height) / 2;
+ return (insets.bottom < edge)
+ ? baseline + height - size.height
+ : baseline + height - size.height + insets.bottom;
+ case BELOW_BOTTOM:
+ return baseline + height - size.height;
}
}
return -1;
@@ -732,44 +603,111 @@ public class TitledBorder extends AbstractBorder
public Component.BaselineResizeBehavior getBaselineResizeBehavior(
Component c) {
super.getBaselineResizeBehavior(c);
- switch(getTitlePosition()) {
- case TitledBorder.ABOVE_TOP:
- case TitledBorder.TOP:
- case TitledBorder.DEFAULT_POSITION:
- case TitledBorder.BELOW_TOP:
- return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
- case TitledBorder.ABOVE_BOTTOM:
- case TitledBorder.BOTTOM:
- case TitledBorder.BELOW_BOTTOM:
- return JComponent.BaselineResizeBehavior.CONSTANT_DESCENT;
+ switch (getPosition()) {
+ case TitledBorder.ABOVE_TOP:
+ case TitledBorder.TOP:
+ case TitledBorder.BELOW_TOP:
+ return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
+ case TitledBorder.ABOVE_BOTTOM:
+ case TitledBorder.BOTTOM:
+ case TitledBorder.BELOW_BOTTOM:
+ return JComponent.BaselineResizeBehavior.CONSTANT_DESCENT;
}
return Component.BaselineResizeBehavior.OTHER;
}
+ private Border getBorderUI() {
+ Border border = getBorder();
+ return border != null
+ ? border
+ : UIManager.getBorder("TitledBorder.border");
+ }
+
+ private int getPosition() {
+ int position = getTitlePosition();
+ if (position != DEFAULT_POSITION) {
+ return position;
+ }
+ Object value = UIManager.get("TitledBorder.position");
+ if (value instanceof Integer) {
+ int i = (Integer) value;
+ if ((0 < i) && (i <= 6)) {
+ return i;
+ }
+ }
+ else if (value instanceof String) {
+ String s = (String) value;
+ if (s.equalsIgnoreCase("ABOVE_TOP")) {
+ return ABOVE_TOP;
+ }
+ if (s.equalsIgnoreCase("TOP")) {
+ return TOP;
+ }
+ if (s.equalsIgnoreCase("BELOW_TOP")) {
+ return BELOW_TOP;
+ }
+ if (s.equalsIgnoreCase("ABOVE_BOTTOM")) {
+ return ABOVE_BOTTOM;
+ }
+ if (s.equalsIgnoreCase("BOTTOM")) {
+ return BOTTOM;
+ }
+ if (s.equalsIgnoreCase("BELOW_BOTTOM")) {
+ return BELOW_BOTTOM;
+ }
+ }
+ return TOP;
+ }
+
+ private int getJustification(Component c) {
+ int justification = getTitleJustification();
+ if ((justification == LEADING) || (justification == DEFAULT_JUSTIFICATION)) {
+ return c.getComponentOrientation().isLeftToRight() ? LEFT : RIGHT;
+ }
+ if (justification == TRAILING) {
+ return c.getComponentOrientation().isLeftToRight() ? RIGHT : LEFT;
+ }
+ return justification;
+ }
+
protected Font getFont(Component c) {
- Font font;
- if ((font = getTitleFont()) != null) {
+ Font font = getTitleFont();
+ if (font != null) {
return font;
- } else if (c != null && (font = c.getFont()) != null) {
+ }
+ font = UIManager.getFont("TitledBorder.font");
+ if (font != null) {
return font;
}
+ if (c != null) {
+ font = c.getFont();
+ if (font != null) {
+ return font;
+ }
+ }
return new Font(Font.DIALOG, Font.PLAIN, 12);
}
- private static boolean computeIntersection(Rectangle dest,
- int rx, int ry, int rw, int rh) {
- int x1 = Math.max(rx, dest.x);
- int x2 = Math.min(rx + rw, dest.x + dest.width);
- int y1 = Math.max(ry, dest.y);
- int y2 = Math.min(ry + rh, dest.y + dest.height);
- dest.x = x1;
- dest.y = y1;
- dest.width = x2 - x1;
- dest.height = y2 - y1;
-
- if (dest.width <= 0 || dest.height <= 0) {
- return false;
+ private Color getColor(Component c) {
+ Color color = getTitleColor();
+ if (color != null) {
+ return color;
+ }
+ color = UIManager.getColor("TitledBorder.titleColor");
+ if (color != null) {
+ return color;
}
- return true;
+ return (c != null)
+ ? c.getForeground()
+ : null;
+ }
+
+ private JLabel getLabel(Component c) {
+ this.label.setText(getTitle());
+ this.label.setFont(getFont(c));
+ this.label.setForeground(getColor(c));
+ this.label.setComponentOrientation(c.getComponentOrientation());
+ this.label.setEnabled(c.isEnabled());
+ return this.label;
}
}
diff --git a/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java b/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java
index fb7122a9cf76ab373cd6112f7b7fe32930e23247..cd7e15e7cac6abf9863bda71e8ce0e09af1ec206 100644
--- a/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java
+++ b/src/share/classes/javax/swing/plaf/basic/BasicButtonListener.java
@@ -195,9 +195,8 @@ public class BasicButtonListener implements MouseListener, MouseMotionListener,
}
ButtonModel model = b.getModel();
- model.setArmed(false);
model.setPressed(false);
-
+ model.setArmed(false);
b.repaint();
}
diff --git a/src/share/classes/javax/swing/plaf/basic/BasicTableHeaderUI.java b/src/share/classes/javax/swing/plaf/basic/BasicTableHeaderUI.java
index 1524c03ea71b898cb0e9beaefcbd329a21c9af7d..6241364b497482addf9d08d7ca0dc9cb85397121 100644
--- a/src/share/classes/javax/swing/plaf/basic/BasicTableHeaderUI.java
+++ b/src/share/classes/javax/swing/plaf/basic/BasicTableHeaderUI.java
@@ -876,7 +876,7 @@ public class BasicTableHeaderUI extends TableHeaderUI {
String name = getName();
if (TOGGLE_SORT_ORDER == name) {
JTable table = th.getTable();
- RowSorter sorter = table.getRowSorter();
+ RowSorter sorter = table == null ? null : table.getRowSorter();
if (sorter != null) {
int columnIndex = ui.getSelectedColumnIndex();
columnIndex = table.convertColumnIndexToModel(
diff --git a/src/share/classes/javax/swing/plaf/nimbus/skin.laf b/src/share/classes/javax/swing/plaf/nimbus/skin.laf
index 7e45c90e62adaa5720aba7abf36a9638f25ce199..236cfe3fabb26fb181a33047cc4a3627dd418464 100644
--- a/src/share/classes/javax/swing/plaf/nimbus/skin.laf
+++ b/src/share/classes/javax/swing/plaf/nimbus/skin.laf
@@ -21276,6 +21276,7 @@
+
diff --git a/src/share/classes/sun/awt/SunToolkit.java b/src/share/classes/sun/awt/SunToolkit.java
index 3985616d58dc3d66fa08ff0c917988940613fd06..984cb11cc69ded3c6b959abcf2ede1e2373e46cf 100644
--- a/src/share/classes/sun/awt/SunToolkit.java
+++ b/src/share/classes/sun/awt/SunToolkit.java
@@ -39,6 +39,7 @@ import java.net.URL;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import sun.util.logging.PlatformLogger;
import sun.misc.SoftCache;
@@ -592,7 +593,7 @@ public abstract class SunToolkit extends Toolkit
}
PostEventQueue postEventQueue =
(PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
- if(postEventQueue != null) {
+ if (postEventQueue != null) {
postEventQueue.postEvent(event);
}
}
@@ -610,16 +611,29 @@ public abstract class SunToolkit extends Toolkit
postEvent(targetToAppContext(e.getSource()), pe);
}
+ private static final Lock flushLock = new ReentrantLock();
+ private static boolean isFlushingPendingEvents = false;
+
/*
* Flush any pending events which haven't been posted to the AWT
* EventQueue yet.
*/
public static void flushPendingEvents() {
- AppContext appContext = AppContext.getAppContext();
- PostEventQueue postEventQueue =
- (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
- if(postEventQueue != null) {
- postEventQueue.flush();
+ flushLock.lock();
+ try {
+ // Don't call flushPendingEvents() recursively
+ if (!isFlushingPendingEvents) {
+ isFlushingPendingEvents = true;
+ AppContext appContext = AppContext.getAppContext();
+ PostEventQueue postEventQueue =
+ (PostEventQueue)appContext.get(POST_EVENT_QUEUE_KEY);
+ if (postEventQueue != null) {
+ postEventQueue.flush();
+ }
+ }
+ } finally {
+ isFlushingPendingEvents = false;
+ flushLock.unlock();
}
}
@@ -1930,6 +1944,25 @@ public abstract class SunToolkit extends Toolkit
return (Window)comp;
}
+ /**
+ * Returns the value of the system property indicated by the specified key.
+ */
+ public static String getSystemProperty(final String key) {
+ return (String)AccessController.doPrivileged(new PrivilegedAction() {
+ public Object run() {
+ return System.getProperty(key);
+ }
+ });
+ }
+
+ /**
+ * Returns the boolean value of the system property indicated by the specified key.
+ */
+ protected static Boolean getBooleanSystemProperty(String key) {
+ return Boolean.valueOf(AccessController.
+ doPrivileged(new GetBooleanAction(key)));
+ }
+
private static Boolean sunAwtDisableMixing = null;
/**
@@ -1938,9 +1971,7 @@ public abstract class SunToolkit extends Toolkit
*/
public synchronized static boolean getSunAwtDisableMixing() {
if (sunAwtDisableMixing == null) {
- sunAwtDisableMixing = Boolean.valueOf(
- AccessController.doPrivileged(
- new GetBooleanAction("sun.awt.disableMixing")));
+ sunAwtDisableMixing = getBooleanSystemProperty("sun.awt.disableMixing");
}
return sunAwtDisableMixing.booleanValue();
}
@@ -2079,12 +2110,14 @@ class PostEventQueue {
eventQueue = eq;
}
- public boolean noEvents() {
+ public synchronized boolean noEvents() {
return queueHead == null;
}
/*
- * Continually post pending AWTEvents to the Java EventQueue.
+ * Continually post pending AWTEvents to the Java EventQueue. The method
+ * is synchronized to ensure the flush is completed before a new event
+ * can be posted to this queue.
*/
public synchronized void flush() {
EventQueueItem tempQueue = queueHead;
diff --git a/src/share/classes/sun/io/CharToByteDBCS_ASCII.java b/src/share/classes/sun/io/CharToByteDBCS_ASCII.java
index 8bd39e3b5afe567a0e5ac8c9b5e5f493317d4b61..8d2ba119dae15bd1e8d777e708f495852c49abd0 100644
--- a/src/share/classes/sun/io/CharToByteDBCS_ASCII.java
+++ b/src/share/classes/sun/io/CharToByteDBCS_ASCII.java
@@ -24,7 +24,6 @@
*/
package sun.io;
-import sun.nio.cs.Surrogate;
import sun.nio.cs.ext.DoubleByte;
import static sun.nio.cs.CharsetMapping.*;
diff --git a/src/share/classes/sun/io/CharToByteDBCS_EBCDIC.java b/src/share/classes/sun/io/CharToByteDBCS_EBCDIC.java
index 1e601374e381430f3d09468e9216c870e8665582..b410076a7e6f5d27946130699c98d54f2a26753a 100644
--- a/src/share/classes/sun/io/CharToByteDBCS_EBCDIC.java
+++ b/src/share/classes/sun/io/CharToByteDBCS_EBCDIC.java
@@ -24,7 +24,6 @@
*/
package sun.io;
-import sun.nio.cs.Surrogate;
import sun.nio.cs.ext.DoubleByte;
import static sun.nio.cs.CharsetMapping.*;
diff --git a/src/share/classes/sun/launcher/LauncherHelper.java b/src/share/classes/sun/launcher/LauncherHelper.java
index dc89f23da71e357dd30420be1a103e1ff0d786c1..cba795968c69c0875894aed1da6f67ebe74ac60f 100644
--- a/src/share/classes/sun/launcher/LauncherHelper.java
+++ b/src/share/classes/sun/launcher/LauncherHelper.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -208,7 +208,7 @@ public enum LauncherHelper {
Method method = null;
try {
method = clazz.getMethod("main", String[].class);
- } catch (Exception e) {
+ } catch (NoSuchMethodException nsme) {
ostream.println(getLocalizedMessage("java.launcher.cls.error4",
classname));
throw new RuntimeException("Main method not found in " + classname);
@@ -225,8 +225,7 @@ public enum LauncherHelper {
throw new RuntimeException("Main method is not static in class " +
classname);
}
- Class> rType = method.getReturnType();
- if (!rType.isPrimitive() || !rType.getName().equals("void")) {
+ if (method.getReturnType() != java.lang.Void.TYPE) {
ostream.println(getLocalizedMessage("java.launcher.cls.error3",
classname));
throw new RuntimeException("Main method must return a value" +
diff --git a/src/share/classes/sun/net/httpserver/ExchangeImpl.java b/src/share/classes/sun/net/httpserver/ExchangeImpl.java
index 71fc997f8d834155a8b15bdb63e4ee6142889c0f..26453e6973ead4a4b3e6d8a5d73174ad3e7a4861 100644
--- a/src/share/classes/sun/net/httpserver/ExchangeImpl.java
+++ b/src/share/classes/sun/net/httpserver/ExchangeImpl.java
@@ -52,14 +52,16 @@ class ExchangeImpl {
boolean http10 = false;
/* for formatting the Date: header */
- static TimeZone tz;
- static DateFormat df;
- static {
- String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz";
- tz = TimeZone.getTimeZone ("GMT");
- df = new SimpleDateFormat (pattern, Locale.US);
- df.setTimeZone (tz);
- }
+ private static final String pattern = "EEE, dd MMM yyyy HH:mm:ss zzz";
+ private static final TimeZone gmtTZ = TimeZone.getTimeZone("GMT");
+ private static final ThreadLocal dateFormat =
+ new ThreadLocal() {
+ @Override protected DateFormat initialValue() {
+ DateFormat df = new SimpleDateFormat(pattern, Locale.US);
+ df.setTimeZone(gmtTZ);
+ return df;
+ }
+ };
private static final String HEAD = "HEAD";
@@ -206,7 +208,7 @@ class ExchangeImpl {
PlaceholderOutputStream o = getPlaceholderResponseBody();
tmpout.write (bytes(statusLine, 0), 0, statusLine.length());
boolean noContentToSend = false; // assume there is content
- rspHdrs.set ("Date", df.format (new Date()));
+ rspHdrs.set ("Date", dateFormat.get().format (new Date()));
/* check for response type that is not allowed to send a body */
diff --git a/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java b/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
index 1421c737d399bf3e8640440ad0bd611c332b6c7e..713c7d85c215fd6bab44ec3e87e961f3e173ad99 100644
--- a/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
+++ b/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
@@ -2331,7 +2331,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
* closed the connection to the web server.
*/
private void disconnectWeb() throws IOException {
- if (usingProxy()) {
+ if (usingProxy() && http.isKeepingAlive()) {
responseCode = -1;
// clean up, particularly, skip the content part
// of a 401 error response
diff --git a/src/share/classes/sun/nio/cs/Surrogate.java b/src/share/classes/sun/nio/cs/Surrogate.java
index 771b6e81e79e7c995610218cd34b4704092c3a24..8b2fcf6765f1cf20e6a78cc7b35f14aee2fa5ba8 100644
--- a/src/share/classes/sun/nio/cs/Surrogate.java
+++ b/src/share/classes/sun/nio/cs/Surrogate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,8 +34,9 @@ import java.nio.charset.UnmappableCharacterException;
* Utility class for dealing with surrogates.
*
* @author Mark Reinhold
+ * @author Martin Buchholz
+ * @author Ulf Zibis
*/
-
public class Surrogate {
private Surrogate() { }
@@ -74,17 +75,10 @@ public class Surrogate {
return (MIN <= c) && (c <= MAX);
}
- /**
- * Tells whether or not the given UCS-4 character is in the Basic
- * Multilingual Plane, and can be represented using a single char.
- */
- public static boolean isBMPCodePoint(int uc) {
- return uc >> 16 == 0;
- }
-
/**
* Tells whether or not the given UCS-4 character must be represented as a
* surrogate pair in UTF-16.
+ * Use of {@link Character#isSupplementaryCodePoint} is generally preferred.
*/
public static boolean neededFor(int uc) {
return Character.isSupplementaryCodePoint(uc);
@@ -92,24 +86,25 @@ public class Surrogate {
/**
* Returns the high UTF-16 surrogate for the given supplementary UCS-4 character.
+ * Use of {@link Character#highSurrogate} is generally preferred.
*/
public static char high(int uc) {
assert Character.isSupplementaryCodePoint(uc);
- return (char)((uc >> 10)
- + (Character.MIN_HIGH_SURROGATE
- - (Character.MIN_SUPPLEMENTARY_CODE_POINT >> 10)));
+ return Character.highSurrogate(uc);
}
/**
* Returns the low UTF-16 surrogate for the given supplementary UCS-4 character.
+ * Use of {@link Character#lowSurrogate} is generally preferred.
*/
public static char low(int uc) {
assert Character.isSupplementaryCodePoint(uc);
- return (char)((uc & 0x3ff) + Character.MIN_LOW_SURROGATE);
+ return Character.lowSurrogate(uc);
}
/**
* Converts the given surrogate pair into a 32-bit UCS-4 character.
+ * Use of {@link Character#toCodePoint} is generally preferred.
*/
public static int toUCS4(char c, char d) {
assert Character.isHighSurrogate(c) && Character.isLowSurrogate(d);
@@ -290,8 +285,9 @@ public class Surrogate {
* error() will return a descriptive result object
*/
public int generate(int uc, int len, CharBuffer dst) {
- if (Surrogate.isBMPCodePoint(uc)) {
- if (Surrogate.is(uc)) {
+ if (Character.isBmpCodePoint(uc)) {
+ char c = (char) uc;
+ if (Character.isSurrogate(c)) {
error = CoderResult.malformedForLength(len);
return -1;
}
@@ -299,16 +295,16 @@ public class Surrogate {
error = CoderResult.OVERFLOW;
return -1;
}
- dst.put((char)uc);
+ dst.put(c);
error = null;
return 1;
- } else if (Character.isSupplementaryCodePoint(uc)) {
+ } else if (Character.isValidCodePoint(uc)) {
if (dst.remaining() < 2) {
error = CoderResult.OVERFLOW;
return -1;
}
- dst.put(Surrogate.high(uc));
- dst.put(Surrogate.low(uc));
+ dst.put(Character.highSurrogate(uc));
+ dst.put(Character.lowSurrogate(uc));
error = null;
return 2;
} else {
@@ -334,8 +330,9 @@ public class Surrogate {
* error() will return a descriptive result object
*/
public int generate(int uc, int len, char[] da, int dp, int dl) {
- if (Surrogate.isBMPCodePoint(uc)) {
- if (Surrogate.is(uc)) {
+ if (Character.isBmpCodePoint(uc)) {
+ char c = (char) uc;
+ if (Character.isSurrogate(c)) {
error = CoderResult.malformedForLength(len);
return -1;
}
@@ -343,16 +340,16 @@ public class Surrogate {
error = CoderResult.OVERFLOW;
return -1;
}
- da[dp] = (char)uc;
+ da[dp] = c;
error = null;
return 1;
- } else if (Character.isSupplementaryCodePoint(uc)) {
+ } else if (Character.isValidCodePoint(uc)) {
if (dl - dp < 2) {
error = CoderResult.OVERFLOW;
return -1;
}
- da[dp] = Surrogate.high(uc);
- da[dp + 1] = Surrogate.low(uc);
+ da[dp] = Character.highSurrogate(uc);
+ da[dp + 1] = Character.lowSurrogate(uc);
error = null;
return 2;
} else {
diff --git a/src/share/classes/sun/nio/cs/UTF_32Coder.java b/src/share/classes/sun/nio/cs/UTF_32Coder.java
index be3e177fbce64c72f643c33cbe1bb73770df9658..53645a75b6011aa6224f6b932a478788dced6b43 100644
--- a/src/share/classes/sun/nio/cs/UTF_32Coder.java
+++ b/src/share/classes/sun/nio/cs/UTF_32Coder.java
@@ -86,22 +86,21 @@ class UTF_32Coder {
src.position(mark);
}
}
- while (src.remaining() > 3) {
+ while (src.remaining() >= 4) {
cp = getCP(src);
- if (cp < 0 || cp > Surrogate.UCS4_MAX) {
- return CoderResult.malformedForLength(4);
- }
- if (cp < Surrogate.UCS4_MIN) {
+ if (Character.isBmpCodePoint(cp)) {
if (!dst.hasRemaining())
return CoderResult.OVERFLOW;
mark += 4;
- dst.put((char)cp);
- } else {
+ dst.put((char) cp);
+ } else if (Character.isValidCodePoint(cp)) {
if (dst.remaining() < 2)
return CoderResult.OVERFLOW;
mark += 4;
- dst.put(Surrogate.high(cp));
- dst.put(Surrogate.low(cp));
+ dst.put(Character.highSurrogate(cp));
+ dst.put(Character.lowSurrogate(cp));
+ } else {
+ return CoderResult.malformedForLength(4);
}
}
return CoderResult.UNDERFLOW;
@@ -154,7 +153,12 @@ class UTF_32Coder {
try {
while (src.hasRemaining()) {
char c = src.get();
- if (Character.isHighSurrogate(c)) {
+ if (!Character.isSurrogate(c)) {
+ if (dst.remaining() < 4)
+ return CoderResult.OVERFLOW;
+ mark++;
+ put(c, dst);
+ } else if (Character.isHighSurrogate(c)) {
if (!src.hasRemaining())
return CoderResult.UNDERFLOW;
char low = src.get();
@@ -162,17 +166,13 @@ class UTF_32Coder {
if (dst.remaining() < 4)
return CoderResult.OVERFLOW;
mark += 2;
- put(Surrogate.toUCS4(c, low), dst);
+ put(Character.toCodePoint(c, low), dst);
} else {
return CoderResult.malformedForLength(1);
}
- } else if (Character.isLowSurrogate(c)) {
- return CoderResult.malformedForLength(1);
} else {
- if (dst.remaining() < 4)
- return CoderResult.OVERFLOW;
- mark++;
- put(c, dst);
+ // assert Character.isLowSurrogate(c);
+ return CoderResult.malformedForLength(1);
}
}
return CoderResult.UNDERFLOW;
diff --git a/src/share/classes/sun/nio/cs/UTF_8.java b/src/share/classes/sun/nio/cs/UTF_8.java
index 208ab077f818da3e5eaac4c63e05fb32d5899ae3..2b62e92f6c177d5f44066166b3e243e0bb85fcf6 100644
--- a/src/share/classes/sun/nio/cs/UTF_8.java
+++ b/src/share/classes/sun/nio/cs/UTF_8.java
@@ -102,7 +102,7 @@ class UTF_8 extends Unicode
// [F1..F3] [80..BF] [80..BF] [80..BF]
// [F4] [80..8F] [80..BF] [80..BF]
// only check 80-be range here, the [0xf0,0x80...] and [0xf4,0x90-...]
- // will be checked by Surrogate.neededFor(uc)
+ // will be checked by Character.isSupplementaryCodePoint(uc)
private static boolean isMalformed4(int b2, int b3, int b4) {
return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
(b4 & 0xc0) != 0x80;
@@ -207,15 +207,15 @@ class UTF_8 extends Unicode
// ASCII only loop
while (dp < dlASCII && sa[sp] >= 0)
- da[dp++] = (char)sa[sp++];
+ da[dp++] = (char) sa[sp++];
while (sp < sl) {
int b1 = sa[sp];
- if (b1 >= 0) {
+ if (b1 >= 0) {
// 1 byte, 7 bits: 0xxxxxxx
if (dp >= dl)
return xflow(src, sp, sl, dst, dp, 1);
- da[dp++] = (char)b1;
+ da[dp++] = (char) b1;
sp++;
} else if ((b1 >> 5) == -2) {
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
@@ -224,7 +224,10 @@ class UTF_8 extends Unicode
int b2 = sa[sp + 1];
if (isMalformed2(b1, b2))
return malformed(src, sp, dst, dp, 2);
- da[dp++] = (char) (((b1 << 6) ^ b2) ^ 0x0f80);
+ da[dp++] = (char) (((b1 << 6) ^ b2)
+ ^
+ (((byte) 0xC0 << 6) ^
+ ((byte) 0x80 << 0)));
sp += 2;
} else if ((b1 >> 4) == -2) {
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
@@ -234,7 +237,13 @@ class UTF_8 extends Unicode
int b3 = sa[sp + 2];
if (isMalformed3(b1, b2, b3))
return malformed(src, sp, dst, dp, 3);
- da[dp++] = (char) (((b1 << 12) ^ (b2 << 6) ^ b3) ^ 0x1f80);
+ da[dp++] = (char)
+ ((b1 << 12) ^
+ (b2 << 6) ^
+ (b3 ^
+ (((byte) 0xE0 << 12) ^
+ ((byte) 0x80 << 6) ^
+ ((byte) 0x80 << 0))));
sp += 3;
} else if ((b1 >> 3) == -2) {
// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
@@ -243,16 +252,21 @@ class UTF_8 extends Unicode
int b2 = sa[sp + 1];
int b3 = sa[sp + 2];
int b4 = sa[sp + 3];
- int uc = ((b1 & 0x07) << 18) |
- ((b2 & 0x3f) << 12) |
- ((b3 & 0x3f) << 06) |
- (b4 & 0x3f);
+ int uc = ((b1 << 18) ^
+ (b2 << 12) ^
+ (b3 << 6) ^
+ (b4 ^
+ (((byte) 0xF0 << 18) ^
+ ((byte) 0x80 << 12) ^
+ ((byte) 0x80 << 6) ^
+ ((byte) 0x80 << 0))));
if (isMalformed4(b2, b3, b4) ||
- !Surrogate.neededFor(uc)) {
+ // shortest form check
+ !Character.isSupplementaryCodePoint(uc)) {
return malformed(src, sp, dst, dp, 4);
}
- da[dp++] = Surrogate.high(uc);
- da[dp++] = Surrogate.low(uc);
+ da[dp++] = Character.highSurrogate(uc);
+ da[dp++] = Character.lowSurrogate(uc);
sp += 4;
} else
return malformed(src, sp, dst, dp, 1);
@@ -270,8 +284,8 @@ class UTF_8 extends Unicode
if (b1 >= 0) {
// 1 byte, 7 bits: 0xxxxxxx
if (dst.remaining() < 1)
- return xflow(src, mark, 1); //overflow
- dst.put((char)b1);
+ return xflow(src, mark, 1); // overflow
+ dst.put((char) b1);
mark++;
} else if ((b1 >> 5) == -2) {
// 2 bytes, 11 bits: 110xxxxx 10xxxxxx
@@ -280,7 +294,10 @@ class UTF_8 extends Unicode
int b2 = src.get();
if (isMalformed2(b1, b2))
return malformed(src, mark, 2);
- dst.put((char) (((b1 << 6) ^ b2) ^ 0x0f80));
+ dst.put((char) (((b1 << 6) ^ b2)
+ ^
+ (((byte) 0xC0 << 6) ^
+ ((byte) 0x80 << 0))));
mark += 2;
} else if ((b1 >> 4) == -2) {
// 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx
@@ -290,7 +307,13 @@ class UTF_8 extends Unicode
int b3 = src.get();
if (isMalformed3(b1, b2, b3))
return malformed(src, mark, 3);
- dst.put((char) (((b1 << 12) ^ (b2 << 6) ^ b3) ^ 0x1f80));
+ dst.put((char)
+ ((b1 << 12) ^
+ (b2 << 6) ^
+ (b3 ^
+ (((byte) 0xE0 << 12) ^
+ ((byte) 0x80 << 6) ^
+ ((byte) 0x80 << 0)))));
mark += 3;
} else if ((b1 >> 3) == -2) {
// 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
@@ -299,16 +322,21 @@ class UTF_8 extends Unicode
int b2 = src.get();
int b3 = src.get();
int b4 = src.get();
- int uc = ((b1 & 0x07) << 18) |
- ((b2 & 0x3f) << 12) |
- ((b3 & 0x3f) << 06) |
- (b4 & 0x3f);
+ int uc = ((b1 << 18) ^
+ (b2 << 12) ^
+ (b3 << 6) ^
+ (b4 ^
+ (((byte) 0xF0 << 18) ^
+ ((byte) 0x80 << 12) ^
+ ((byte) 0x80 << 6) ^
+ ((byte) 0x80 << 0))));
if (isMalformed4(b2, b3, b4) ||
- !Surrogate.neededFor(uc)) { // shortest form check
+ // shortest form check
+ !Character.isSupplementaryCodePoint(uc)) {
return malformed(src, mark, 4);
}
- dst.put(Surrogate.high(uc));
- dst.put(Surrogate.low(uc));
+ dst.put(Character.highSurrogate(uc));
+ dst.put(Character.lowSurrogate(uc));
mark += 4;
} else {
return malformed(src, mark, 1);
@@ -366,7 +394,7 @@ class UTF_8 extends Unicode
int dl = dst.arrayOffset() + dst.limit();
int dlASCII = dp + Math.min(sl - sp, dl - dp);
- //ASCII only loop
+ // ASCII only loop
while (dp < dlASCII && sa[sp] < '\u0080')
da[dp++] = (byte) sa[sp++];
while (sp < sl) {
@@ -380,7 +408,7 @@ class UTF_8 extends Unicode
// 2 bytes, 11 bits
if (dl - dp < 2)
return overflow(src, sp, dst, dp);
- da[dp++] = (byte)(0xc0 | ((c >> 06)));
+ da[dp++] = (byte)(0xc0 | (c >> 6));
da[dp++] = (byte)(0x80 | (c & 0x3f));
} else if (Character.isSurrogate(c)) {
// Have a surrogate pair
@@ -395,7 +423,7 @@ class UTF_8 extends Unicode
return overflow(src, sp, dst, dp);
da[dp++] = (byte)(0xf0 | ((uc >> 18)));
da[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
- da[dp++] = (byte)(0x80 | ((uc >> 06) & 0x3f));
+ da[dp++] = (byte)(0x80 | ((uc >> 6) & 0x3f));
da[dp++] = (byte)(0x80 | (uc & 0x3f));
sp++; // 2 chars
} else {
@@ -403,7 +431,7 @@ class UTF_8 extends Unicode
if (dl - dp < 3)
return overflow(src, sp, dst, dp);
da[dp++] = (byte)(0xe0 | ((c >> 12)));
- da[dp++] = (byte)(0x80 | ((c >> 06) & 0x3f));
+ da[dp++] = (byte)(0x80 | ((c >> 6) & 0x3f));
da[dp++] = (byte)(0x80 | (c & 0x3f));
}
sp++;
@@ -427,7 +455,7 @@ class UTF_8 extends Unicode
// 2 bytes, 11 bits
if (dst.remaining() < 2)
return overflow(src, mark);
- dst.put((byte)(0xc0 | ((c >> 06))));
+ dst.put((byte)(0xc0 | (c >> 6)));
dst.put((byte)(0x80 | (c & 0x3f)));
} else if (Character.isSurrogate(c)) {
// Have a surrogate pair
@@ -442,15 +470,15 @@ class UTF_8 extends Unicode
return overflow(src, mark);
dst.put((byte)(0xf0 | ((uc >> 18))));
dst.put((byte)(0x80 | ((uc >> 12) & 0x3f)));
- dst.put((byte)(0x80 | ((uc >> 06) & 0x3f)));
+ dst.put((byte)(0x80 | ((uc >> 6) & 0x3f)));
dst.put((byte)(0x80 | (uc & 0x3f)));
- mark++; //2 chars
+ mark++; // 2 chars
} else {
// 3 bytes, 16 bits
if (dst.remaining() < 3)
return overflow(src, mark);
dst.put((byte)(0xe0 | ((c >> 12))));
- dst.put((byte)(0x80 | ((c >> 06) & 0x3f)));
+ dst.put((byte)(0x80 | ((c >> 6) & 0x3f)));
dst.put((byte)(0x80 | (c & 0x3f)));
}
mark++;
diff --git a/src/share/classes/sun/nio/cs/UnicodeEncoder.java b/src/share/classes/sun/nio/cs/UnicodeEncoder.java
index 2fac5fa5b5cb0107b6aefc2edf38a0283c040464..cea0270c104b88ce81642a12ff764bc36f0bb5a6 100644
--- a/src/share/classes/sun/nio/cs/UnicodeEncoder.java
+++ b/src/share/classes/sun/nio/cs/UnicodeEncoder.java
@@ -93,8 +93,8 @@ public abstract class UnicodeEncoder extends CharsetEncoder {
if (dst.remaining() < 4)
return CoderResult.OVERFLOW;
mark += 2;
- put(Surrogate.high(d), dst);
- put(Surrogate.low(d), dst);
+ put(Character.highSurrogate(d), dst);
+ put(Character.lowSurrogate(d), dst);
}
return CoderResult.UNDERFLOW;
} finally {
diff --git a/src/share/classes/sun/nio/cs/ext/EUC_TW.java b/src/share/classes/sun/nio/cs/ext/EUC_TW.java
index a4ae8df6e98de04a71154f409ae257f2c461af55..28a2a97d9294dfa889cc1b78648caf4a44e0d993 100644
--- a/src/share/classes/sun/nio/cs/ext/EUC_TW.java
+++ b/src/share/classes/sun/nio/cs/ext/EUC_TW.java
@@ -34,7 +34,6 @@ import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.Arrays;
import sun.nio.cs.HistoricallyNamedCharset;
-import sun.nio.cs.Surrogate;
import static sun.nio.cs.CharsetMapping.*;
public class EUC_TW extends Charset implements HistoricallyNamedCharset
@@ -159,8 +158,8 @@ public class EUC_TW extends Charset implements HistoricallyNamedCharset
c1[0] = c;
return c1;
} else {
- c2[0] = Surrogate.high(0x20000 + c);
- c2[1] = Surrogate.low(0x20000 + c);
+ c2[0] = Character.highSurrogate(0x20000 + c);
+ c2[1] = Character.lowSurrogate(0x20000 + c);
return c2;
}
}
@@ -441,7 +440,7 @@ public class EUC_TW extends Charset implements HistoricallyNamedCharset
}
static int encode(char hi, char low, byte[] bb) {
- int c = Surrogate.toUCS4(hi, low);
+ int c = Character.toCodePoint(hi, low);
if ((c & 0xf0000) != 0x20000)
return -1;
c -= 0x20000;
diff --git a/src/share/classes/sun/nio/cs/ext/GB18030.java b/src/share/classes/sun/nio/cs/ext/GB18030.java
index acbe23a36d6c74f5e49c7f08baeb53720adc2dd5..59e3c4db851fddb2340d2415a92d27995104125a 100644
--- a/src/share/classes/sun/nio/cs/ext/GB18030.java
+++ b/src/share/classes/sun/nio/cs/ext/GB18030.java
@@ -12628,7 +12628,7 @@ public class GB18030
if (Character.isSurrogate(c)) {
if ((condensedKey=sgp.parse(c, sa, sp, sl)) < 0)
return sgp.error();
- // Surogate.toUCS4 looks like
+ // Character.toCodePoint looks like
// (((high & 0x3ff) << 10) | (low & 0x3ff)) + 0x10000;
// so we add (0x2e248 - 0x10000) to get the "key".
condensedKey += 0x1E248;
diff --git a/src/share/classes/sun/nio/cs/ext/IBM33722.java b/src/share/classes/sun/nio/cs/ext/IBM33722.java
index 58b610bf1636fba554e45d6e3054f8dd5cad14cc..dc1508278d22c63a337958eab84772e118f5a986 100644
--- a/src/share/classes/sun/nio/cs/ext/IBM33722.java
+++ b/src/share/classes/sun/nio/cs/ext/IBM33722.java
@@ -36,7 +36,6 @@ import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import sun.nio.cs.HistoricallyNamedCharset;
-import sun.nio.cs.Surrogate;
public class IBM33722
extends Charset
diff --git a/src/share/classes/sun/nio/cs/ext/IBM964.java b/src/share/classes/sun/nio/cs/ext/IBM964.java
index 9155ff58d009d2f756b439d483c3457797653f7d..b87e838714bf5cbe9037d0019b894edcf31204cb 100644
--- a/src/share/classes/sun/nio/cs/ext/IBM964.java
+++ b/src/share/classes/sun/nio/cs/ext/IBM964.java
@@ -36,7 +36,6 @@ import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import sun.nio.cs.HistoricallyNamedCharset;
-import sun.nio.cs.Surrogate;
public class IBM964
extends Charset
diff --git a/src/share/classes/sun/security/krb5/Credentials.java b/src/share/classes/sun/security/krb5/Credentials.java
index 4114efe2c17f910d5312c25182da0b5eba7e30f4..b7ae4aaee6593210fe04e41691ae3200efeb5d33 100644
--- a/src/share/classes/sun/security/krb5/Credentials.java
+++ b/src/share/classes/sun/security/krb5/Credentials.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -33,9 +33,7 @@ package sun.security.krb5;
import sun.security.krb5.internal.*;
import sun.security.krb5.internal.ccache.CredentialsCache;
-import sun.security.krb5.internal.ktab.*;
import sun.security.krb5.internal.crypto.EType;
-import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.net.InetAddress;
@@ -506,59 +504,6 @@ public class Credentials {
return result;
}
-
- /**
- * Gets service credential from key table. The credential is used to
- * decrypt the received client message
- * and authenticate the client by verifying the client's credential.
- *
- * @param serviceName the name of service, using format component@realm
- * @param keyTabFile the file of key table.
- * @return a KrbCreds object.
- */
- public static Credentials getServiceCreds(String serviceName,
- File keyTabFile) {
- EncryptionKey k = null;
- PrincipalName service = null;
- Credentials result = null;
- try {
- service = new PrincipalName(serviceName);
- if (service.getRealm() == null) {
- String realm = Config.getInstance().getDefaultRealm();
- if (realm == null) {
- return null;
- } else {
- service.setRealm(realm);
- }
- }
- } catch (RealmException e) {
- if (DEBUG) {
- e.printStackTrace();
- }
- return null;
- } catch (KrbException e) {
- if (DEBUG) {
- e.printStackTrace();
- }
- return null;
- }
- KeyTab kt;
- if (keyTabFile == null) {
- kt = KeyTab.getInstance();
- } else {
- kt = KeyTab.getInstance(keyTabFile);
- }
- if ((kt != null) && (kt.findServiceEntry(service))) {
- k = kt.readServiceKey(service);
- result = new Credentials(null, service, null, null, null,
- null, null, null, null, null);
- result.serviceKey = k;
- }
- return result;
- }
-
-
-
/**
* Acquires credentials for a specified service using initial credential.
* When the service has a different realm
diff --git a/src/share/classes/sun/security/krb5/EncryptedData.java b/src/share/classes/sun/security/krb5/EncryptedData.java
index d5d764315f464adceb404365afe50fb14cb3a3bb..f9907687e3034f474084b58cf07cc695465a15c6 100644
--- a/src/share/classes/sun/security/krb5/EncryptedData.java
+++ b/src/share/classes/sun/security/krb5/EncryptedData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -336,38 +336,29 @@ public class EncryptedData implements Cloneable {
}
/**
- * Reset data stream after decryption, remove redundant bytes.
+ * Reset asn.1 data stream after decryption, remove redundant bytes.
* @param data the decrypted data from decrypt().
- * @param encoded true if the encrypted data is ASN1 encoded data,
- * false if the encrypted data is not ASN1 encoded data.
* @return the reset byte array which holds exactly one asn1 datum
* including its tag and length.
*
*/
- public byte[] reset(byte[] data, boolean encoded) {
+ public byte[] reset(byte[] data) {
byte[] bytes = null;
- // if it is encoded data, we use length field to
+ // for asn.1 encoded data, we use length field to
// determine the data length and remove redundant paddings.
- if (encoded) {
- if ((data[1] & 0xFF) < 128) {
- bytes = new byte[data[1] + 2];
- System.arraycopy(data, 0, bytes, 0, data[1] + 2);
- } else
- if ((data[1] & 0xFF) > 128) {
- int len = data[1] & (byte)0x7F;
- int result = 0;
- for (int i = 0; i < len; i++) {
- result |= (data[i + 2] & 0xFF) << (8 * (len - i - 1));
- }
- bytes = new byte[result + len + 2];
- System.arraycopy(data, 0, bytes, 0, result + len + 2);
- }
+ if ((data[1] & 0xFF) < 128) {
+ bytes = new byte[data[1] + 2];
+ System.arraycopy(data, 0, bytes, 0, data[1] + 2);
} else {
- // if it is not encoded, which happens in GSS tokens,
- // we remove padding data according to padding pattern.
- bytes = new byte[data.length - data[data.length - 1]];
- System.arraycopy(data, 0, bytes, 0,
- data.length - data[data.length - 1]);
+ if ((data[1] & 0xFF) > 128) {
+ int len = data[1] & (byte)0x7F;
+ int result = 0;
+ for (int i = 0; i < len; i++) {
+ result |= (data[i + 2] & 0xFF) << (8 * (len - i - 1));
+ }
+ bytes = new byte[result + len + 2];
+ System.arraycopy(data, 0, bytes, 0, result + len + 2);
+ }
}
return bytes;
}
diff --git a/src/share/classes/sun/security/krb5/KrbApRep.java b/src/share/classes/sun/security/krb5/KrbApRep.java
index d011af79fc0c5fc8b311c8dc0eee8adb37318356..2b994f7ea3a805b79370d75ef9dffac6b2aa458d 100644
--- a/src/share/classes/sun/security/krb5/KrbApRep.java
+++ b/src/share/classes/sun/security/krb5/KrbApRep.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -130,7 +130,7 @@ public class KrbApRep {
byte[] temp = rep.encPart.decrypt(tgs_creds.key,
KeyUsage.KU_ENC_AP_REP_PART);
- byte[] enc_ap_rep_part = rep.encPart.reset(temp, true);
+ byte[] enc_ap_rep_part = rep.encPart.reset(temp);
encoding = new DerValue(enc_ap_rep_part);
encPart = new EncAPRepPart(encoding);
diff --git a/src/share/classes/sun/security/krb5/KrbApReq.java b/src/share/classes/sun/security/krb5/KrbApReq.java
index 09a32c6b0ec8e9d7c2b69ff120ea268d30524712..409ca4e8205d3951a2c4bc5f745f6e552d9c7c58 100644
--- a/src/share/classes/sun/security/krb5/KrbApReq.java
+++ b/src/share/classes/sun/security/krb5/KrbApReq.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -279,14 +279,14 @@ public class KrbApReq {
byte[] bytes = apReqMessg.ticket.encPart.decrypt(dkey,
KeyUsage.KU_TICKET);
- byte[] temp = apReqMessg.ticket.encPart.reset(bytes, true);
+ byte[] temp = apReqMessg.ticket.encPart.reset(bytes);
EncTicketPart enc_ticketPart = new EncTicketPart(temp);
checkPermittedEType(enc_ticketPart.key.getEType());
byte[] bytes2 = apReqMessg.authenticator.decrypt(enc_ticketPart.key,
KeyUsage.KU_AP_REQ_AUTHENTICATOR);
- byte[] temp2 = apReqMessg.authenticator.reset(bytes2, true);
+ byte[] temp2 = apReqMessg.authenticator.reset(bytes2);
authenticator = new Authenticator(temp2);
ctime = authenticator.ctime;
cusec = authenticator.cusec;
diff --git a/src/share/classes/sun/security/krb5/KrbAsRep.java b/src/share/classes/sun/security/krb5/KrbAsRep.java
index 0ce39ebd34d73fbcab999047dadd91ebfebf3131..709e4410a0acda90233e1a44c01c57cbf94a8129 100644
--- a/src/share/classes/sun/security/krb5/KrbAsRep.java
+++ b/src/share/classes/sun/security/krb5/KrbAsRep.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -95,7 +95,7 @@ public class KrbAsRep extends KrbKdcRep {
byte[] enc_as_rep_bytes = rep.encPart.decrypt(dkey,
KeyUsage.KU_ENC_AS_REP_PART);
- byte[] enc_as_rep_part = rep.encPart.reset(enc_as_rep_bytes, true);
+ byte[] enc_as_rep_part = rep.encPart.reset(enc_as_rep_bytes);
encoding = new DerValue(enc_as_rep_part);
EncASRepPart enc_part = new EncASRepPart(encoding);
diff --git a/src/share/classes/sun/security/krb5/KrbCred.java b/src/share/classes/sun/security/krb5/KrbCred.java
index 9b0757855af7119e71c3aa2df0fc267599e3b7b6..e263640e99e94de2fdfcab5c0da7a8770212af7d 100644
--- a/src/share/classes/sun/security/krb5/KrbCred.java
+++ b/src/share/classes/sun/security/krb5/KrbCred.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -130,7 +130,7 @@ public class KrbCred {
byte[] temp = credMessg.encPart.decrypt(key,
KeyUsage.KU_ENC_KRB_CRED_PART);
- byte[] plainText = credMessg.encPart.reset(temp, true);
+ byte[] plainText = credMessg.encPart.reset(temp);
DerValue encoding = new DerValue(plainText);
EncKrbCredPart encPart = new EncKrbCredPart(encoding);
diff --git a/src/share/classes/sun/security/krb5/KrbPriv.java b/src/share/classes/sun/security/krb5/KrbPriv.java
index 36abaef3ef4b2376a2b79f87721c58b1ca91bc02..bac278884e0706322d43378785150e6e01147c13 100644
--- a/src/share/classes/sun/security/krb5/KrbPriv.java
+++ b/src/share/classes/sun/security/krb5/KrbPriv.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@
package sun.security.krb5;
-import sun.security.krb5.EncryptionKey;
import sun.security.krb5.internal.*;
import sun.security.krb5.internal.crypto.*;
import sun.security.util.*;
@@ -159,7 +158,7 @@ class KrbPriv extends KrbAppMessage {
byte[] bytes = krb_priv.encPart.decrypt(key,
KeyUsage.KU_ENC_KRB_PRIV_PART);
- byte[] temp = krb_priv.encPart.reset(bytes, true);
+ byte[] temp = krb_priv.encPart.reset(bytes);
DerValue ref = new DerValue(temp);
EncKrbPrivPart enc_part = new EncKrbPrivPart(ref);
diff --git a/src/share/classes/sun/security/krb5/KrbTgsRep.java b/src/share/classes/sun/security/krb5/KrbTgsRep.java
index 16c622baf484c4e8d4b7369d5c58467fb1ff7f21..5812894de017bb486ad71a15f3cf44e5b7c2e7ef 100644
--- a/src/share/classes/sun/security/krb5/KrbTgsRep.java
+++ b/src/share/classes/sun/security/krb5/KrbTgsRep.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -79,7 +79,7 @@ public class KrbTgsRep extends KrbKdcRep {
tgsReq.usedSubkey() ? KeyUsage.KU_ENC_TGS_REP_PART_SUBKEY :
KeyUsage.KU_ENC_TGS_REP_PART_SESSKEY);
- byte[] enc_tgs_rep_part = rep.encPart.reset(enc_tgs_rep_bytes, true);
+ byte[] enc_tgs_rep_part = rep.encPart.reset(enc_tgs_rep_bytes);
ref = new DerValue(enc_tgs_rep_part);
EncTGSRepPart enc_part = new EncTGSRepPart(ref);
rep.ticket.sname.setRealm(rep.ticket.realm);
diff --git a/src/share/classes/sun/security/krb5/internal/crypto/EType.java b/src/share/classes/sun/security/krb5/internal/crypto/EType.java
index 31e998f0bcb29e616c1956bdfd86001dc93d4b89..90c0be67dae3be1d071b8a61635a5567ec2ff36b 100644
--- a/src/share/classes/sun/security/krb5/internal/crypto/EType.java
+++ b/src/share/classes/sun/security/krb5/internal/crypto/EType.java
@@ -185,20 +185,20 @@ public abstract class EType {
// is set to false.
private static final int[] BUILTIN_ETYPES = new int[] {
- EncryptedData.ETYPE_DES_CBC_MD5,
- EncryptedData.ETYPE_DES_CBC_CRC,
- EncryptedData.ETYPE_ARCFOUR_HMAC,
- EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
- EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96,
+ EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
+ EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
+ EncryptedData.ETYPE_ARCFOUR_HMAC,
+ EncryptedData.ETYPE_DES_CBC_CRC,
+ EncryptedData.ETYPE_DES_CBC_MD5,
};
private static final int[] BUILTIN_ETYPES_NOAES256 = new int[] {
- EncryptedData.ETYPE_DES_CBC_MD5,
- EncryptedData.ETYPE_DES_CBC_CRC,
- EncryptedData.ETYPE_ARCFOUR_HMAC,
- EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
EncryptedData.ETYPE_AES128_CTS_HMAC_SHA1_96,
+ EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD,
+ EncryptedData.ETYPE_ARCFOUR_HMAC,
+ EncryptedData.ETYPE_DES_CBC_CRC,
+ EncryptedData.ETYPE_DES_CBC_MD5,
};
@@ -217,8 +217,8 @@ public abstract class EType {
result = BUILTIN_ETYPES;
}
if (!ALLOW_WEAK_CRYPTO) {
- // The first 2 etypes are now weak ones
- return Arrays.copyOfRange(result, 2, result.length);
+ // The last 2 etypes are now weak ones
+ return Arrays.copyOfRange(result, 0, result.length - 2);
}
return result;
}
diff --git a/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java b/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java
index a798eebc1eb3740eb00ec17f7aac6486b15426e6..623d6252bcf40b1dfa8abc05b80f4e05dd08ac4c 100644
--- a/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java
+++ b/src/share/classes/sun/security/krb5/internal/ktab/KeyTab.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -227,37 +227,6 @@ public class KeyTab implements KeyTabConstants {
}
}
- /**
- * Reads the service key from the keytab file.
- * @param service the PrincipalName of the requested service.
- * @return the last service key in the keytab with the highest kvno
- */
- public EncryptionKey readServiceKey(PrincipalName service) {
- KeyTabEntry entry = null;
- EncryptionKey key = null;
- if (entries != null) {
- // Find latest entry for this service that has an etype
- // that has been configured for use
- for (int i = entries.size()-1; i >= 0; i--) {
- entry = entries.elementAt(i);
- if (entry.service.match(service)) {
- if (EType.isSupported(entry.keyType)) {
- if (key == null ||
- entry.keyVersion > key.getKeyVersionNumber()) {
- key = new EncryptionKey(entry.keyblock,
- entry.keyType,
- new Integer(entry.keyVersion));
- }
- } else if (DEBUG) {
- System.out.println("Found unsupported keytype (" +
- entry.keyType + ") for " + service);
- }
- }
- }
- }
- return key;
- }
-
/**
* Reads all keys for a service from the keytab file that have
* etypes that have been configured for use. If there are multiple
@@ -309,7 +278,7 @@ public class KeyTab implements KeyTabConstants {
Arrays.sort(retVal, new Comparator() {
@Override
public int compare(EncryptionKey o1, EncryptionKey o2) {
- if (etypes != null && etypes != EType.getBuiltInDefaults()) {
+ if (etypes != null) {
int o1EType = o1.getEType();
int o2EType = o2.getEType();
if (o1EType != o2EType) {
@@ -320,6 +289,9 @@ public class KeyTab implements KeyTabConstants {
return 1;
}
}
+ // Neither o1EType nor o2EType in default_tkt_enctypes,
+ // therefore won't be used in AS-REQ. We do not care
+ // about their order, use kvno is OK.
}
}
return o2.getKeyVersionNumber().intValue()
diff --git a/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
index 3f275c0eb8d3c72f5af0aeda03148c571158504b..777604473ca48cb649f21ec14e24b06091894ac8 100644
--- a/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
+++ b/src/share/classes/sun/security/pkcs12/PKCS12KeyStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -180,24 +180,15 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
String alias;
};
- private static class KeyId {
- byte[] keyId;
-
- KeyId(byte[] keyId) {
+ // A certificate with its PKCS #9 attributes
+ private static class CertEntry {
+ final X509Certificate cert;
+ final byte[] keyId;
+ final String alias;
+ CertEntry(X509Certificate cert, byte[] keyId, String alias) {
+ this.cert = cert;
this.keyId = keyId;
- }
- public int hashCode() {
- int hash = 0;
-
- for (int i = 0; i < keyId.length; i++)
- hash += keyId[i];
- return hash;
- }
- public boolean equals(Object obj) {
- if (!(obj instanceof KeyId))
- return false;
- KeyId that = (KeyId)obj;
- return (Arrays.equals(this.keyId, that.keyId));
+ this.alias = alias;
}
}
@@ -209,7 +200,9 @@ public final class PKCS12KeyStore extends KeyStoreSpi {
new Hashtable();
private ArrayList keyList = new ArrayList();
- private LinkedHashMap