8151384: Improve String.CASE_INSENSITIVE_ORDER and remove sun.misc.ASCIICaseInsensitiveComparator
authorchegar
Tue, 08 Mar 2016 12:11:07 +0000
changeset 36411 f0cd8358b5ea
parent 36410 c2ef247d0b6f
child 36412 bf90c6348632
8151384: Improve String.CASE_INSENSITIVE_ORDER and remove sun.misc.ASCIICaseInsensitiveComparator Reviewed-by: shade, sherman
jdk/src/java.base/share/classes/java/lang/String.java
jdk/src/java.base/share/classes/java/lang/StringLatin1.java
jdk/src/java.base/share/classes/java/lang/StringUTF16.java
jdk/src/java.base/share/classes/java/nio/charset/Charset.java
jdk/src/java.base/share/classes/java/util/jar/Attributes.java
jdk/src/java.base/share/classes/sun/misc/ASCIICaseInsensitiveComparator.java
jdk/src/jdk.charsets/share/classes/sun/nio/cs/ext/AbstractCharsetProvider.java
--- a/jdk/src/java.base/share/classes/java/lang/String.java	Tue Mar 08 11:01:38 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/String.java	Tue Mar 08 12:11:07 2016 +0000
@@ -1222,30 +1222,12 @@
         public int compare(String s1, String s2) {
             byte v1[] = s1.value;
             byte v2[] = s2.value;
-            int n1 = s1.length();
-            int n2 = s2.length();
-            boolean s1IsLatin1 = s1.isLatin1();
-            boolean s2IsLatin1 = s2.isLatin1();
-            int min = Math.min(n1, n2);
-            for (int i = 0; i < min; i++) {
-                char c1 = s1IsLatin1 ? StringLatin1.getChar(v1, i)
-                                     : StringUTF16.getChar(v1, i);
-                char c2 = s2IsLatin1 ? StringLatin1.getChar(v2, i)
-                                     : StringUTF16.getChar(v2, i);
-                if (c1 != c2) {
-                    c1 = Character.toUpperCase(c1);
-                    c2 = Character.toUpperCase(c2);
-                    if (c1 != c2) {
-                        c1 = Character.toLowerCase(c1);
-                        c2 = Character.toLowerCase(c2);
-                        if (c1 != c2) {
-                            // No overflow because of numeric promotion
-                            return c1 - c2;
-                        }
-                    }
-                }
+            if (s1.coder() == s2.coder()) {
+                return s1.isLatin1() ? StringLatin1.compareToCI(v1, v2)
+                                     : StringUTF16.compareToCI(v1, v2);
             }
-            return n1 - n2;
+            return s1.isLatin1() ? StringLatin1.compareToCI_UTF16(v1, v2)
+                                 : StringUTF16.compareToCI_Latin1(v1, v2);
         }
 
         /** Replaces the de-serialized object. */
--- a/jdk/src/java.base/share/classes/java/lang/StringLatin1.java	Tue Mar 08 11:01:38 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/StringLatin1.java	Tue Mar 08 12:11:07 2016 +0000
@@ -128,6 +128,48 @@
         return len1 - len2;
     }
 
+    public static int compareToCI(byte[] value, byte[] other) {
+        int len1 = value.length;
+        int len2 = other.length;
+        int lim = Math.min(len1, len2);
+        for (int k = 0; k < lim; k++) {
+            if (value[k] != other[k]) {
+                char c1 = (char) CharacterDataLatin1.instance.toUpperCase(getChar(value, k));
+                char c2 = (char) CharacterDataLatin1.instance.toUpperCase(getChar(other, k));
+                if (c1 != c2) {
+                    c1 = (char) CharacterDataLatin1.instance.toLowerCase(c1);
+                    c2 = (char) CharacterDataLatin1.instance.toLowerCase(c2);
+                    if (c1 != c2) {
+                        return c1 - c2;
+                    }
+                }
+            }
+        }
+        return len1 - len2;
+    }
+
+    public static int compareToCI_UTF16(byte[] value, byte[] other) {
+        int len1 = length(value);
+        int len2 = StringUTF16.length(other);
+        int lim = Math.min(len1, len2);
+        for (int k = 0; k < lim; k++) {
+            char c1 = getChar(value, k);
+            char c2 = StringUTF16.getChar(other, k);
+            if (c1 != c2) {
+                c1 = Character.toUpperCase(c1);
+                c2 = Character.toUpperCase(c2);
+                if (c1 != c2) {
+                    c1 = Character.toLowerCase(c1);
+                    c2 = Character.toLowerCase(c2);
+                    if (c1 != c2) {
+                        return c1 - c2;
+                    }
+                }
+            }
+        }
+        return len1 - len2;
+    }
+
     public static int hashCode(byte[] value) {
         int h = 0;
         for (byte v : value) {
--- a/jdk/src/java.base/share/classes/java/lang/StringUTF16.java	Tue Mar 08 11:01:38 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/StringUTF16.java	Tue Mar 08 12:11:07 2016 +0000
@@ -270,6 +270,50 @@
         return len1 - len2;
     }
 
+    public static int compareToCI(byte[] value, byte[] other) {
+        int len1 = length(value);
+        int len2 = length(other);
+        int lim = Math.min(len1, len2);
+        for (int k = 0; k < lim; k++) {
+            char c1 = getChar(value, k);
+            char c2 = getChar(other, k);
+            if (c1 != c2) {
+                c1 = Character.toUpperCase(c1);
+                c2 = Character.toUpperCase(c2);
+                if (c1 != c2) {
+                    c1 = Character.toLowerCase(c1);
+                    c2 = Character.toLowerCase(c2);
+                    if (c1 != c2) {
+                        return c1 - c2;
+                    }
+                }
+            }
+        }
+        return len1 - len2;
+    }
+
+    public static int compareToCI_Latin1(byte[] value, byte[] other) {
+        int len1 = length(value);
+        int len2 = StringLatin1.length(other);
+        int lim = Math.min(len1, len2);
+        for (int k = 0; k < lim; k++) {
+            char c1 = getChar(value, k);
+            char c2 = StringLatin1.getChar(other, k);
+            if (c1 != c2) {
+                c1 = Character.toUpperCase(c1);
+                c2 = Character.toUpperCase(c2);
+                if (c1 != c2) {
+                    c1 = Character.toLowerCase(c1);
+                    c2 = Character.toLowerCase(c2);
+                    if (c1 != c2) {
+                        return c1 - c2;
+                    }
+                }
+            }
+        }
+        return len1 - len2;
+    }
+
     public static int hashCode(byte[] value) {
         int h = 0;
         int length = value.length >> 1;
--- a/jdk/src/java.base/share/classes/java/nio/charset/Charset.java	Tue Mar 08 11:01:38 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/nio/charset/Charset.java	Tue Mar 08 12:11:07 2016 +0000
@@ -44,7 +44,6 @@
 import java.util.SortedMap;
 import java.util.TreeMap;
 import jdk.internal.misc.VM;
-import sun.misc.ASCIICaseInsensitiveComparator;
 import sun.nio.cs.StandardCharsets;
 import sun.nio.cs.ThreadLocalCoders;
 import sun.security.action.GetPropertyAction;
@@ -579,7 +578,7 @@
                 public SortedMap<String,Charset> run() {
                     TreeMap<String,Charset> m =
                         new TreeMap<>(
-                            ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
+                            String.CASE_INSENSITIVE_ORDER);
                     put(standardProvider.charsets(), m);
                     CharsetProvider[] ecps = ExtendedProviderHolder.extendedProviders;
                     for (CharsetProvider ecp :ecps) {
--- a/jdk/src/java.base/share/classes/java/util/jar/Attributes.java	Tue Mar 08 11:01:38 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/util/jar/Attributes.java	Tue Mar 08 12:11:07 2016 +0000
@@ -34,9 +34,9 @@
 import java.util.Collection;
 import java.util.AbstractSet;
 import java.util.Iterator;
+import java.util.Locale;
 import sun.util.logging.PlatformLogger;
 import java.util.Comparator;
-import sun.misc.ASCIICaseInsensitiveComparator;
 
 /**
  * The Attributes class maps Manifest attribute names to associated string
@@ -501,7 +501,7 @@
          */
         public boolean equals(Object o) {
             if (o instanceof Name) {
-                Comparator<String> c = ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER;
+                Comparator<String> c = String.CASE_INSENSITIVE_ORDER;
                 return c.compare(name, ((Name)o).name) == 0;
             } else {
                 return false;
@@ -513,7 +513,7 @@
          */
         public int hashCode() {
             if (hashCode == -1) {
-                hashCode = ASCIICaseInsensitiveComparator.lowerCaseHashCode(name);
+                hashCode = name.toLowerCase(Locale.ROOT).hashCode();
             }
             return hashCode;
         }
--- a/jdk/src/java.base/share/classes/sun/misc/ASCIICaseInsensitiveComparator.java	Tue Mar 08 11:01:38 2016 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2002, 2004, 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 sun.misc;
-
-import java.util.Comparator;
-
-/** Implements a locale and case insensitive comparator suitable for
-    strings that are known to only contain ASCII characters. Some
-    tables internal to the JDK contain only ASCII data and are using
-    the "generalized" java.lang.String case-insensitive comparator
-    which converts each character to both upper and lower case. */
-
-public class ASCIICaseInsensitiveComparator implements Comparator<String> {
-    public static final Comparator<String> CASE_INSENSITIVE_ORDER =
-        new ASCIICaseInsensitiveComparator();
-
-    public int compare(String s1, String s2) {
-        int n1=s1.length(), n2=s2.length();
-        int minLen = n1 < n2 ? n1 : n2;
-        for (int i=0; i < minLen; i++) {
-            char c1 = s1.charAt(i);
-            char c2 = s2.charAt(i);
-            assert c1 <= '\u007F' && c2 <= '\u007F';
-            if (c1 != c2) {
-                c1 = (char)toLower(c1);
-                c2 = (char)toLower(c2);
-                if (c1 != c2) {
-                    return c1 - c2;
-                }
-            }
-        }
-        return n1 - n2;
-    }
-
-    /**
-     * A case insensitive hash code method to go with the case insensitive
-     * compare() method.
-     *
-     * Returns a hash code for this ASCII string as if it were lower case.
-     *
-     * returns same answer as:<p>
-     * <code>s.toLowerCase(Locale.US).hashCode();</code><p>
-     * but does not allocate memory (it does NOT have the special
-     * case Turkish rules).
-     *
-     * @param s a String to compute the hashcode on.
-     * @return  a hash code value for this object.
-     */
-    public static int lowerCaseHashCode(String s) {
-        int h = 0;
-        int len = s.length();
-
-        for (int i = 0; i < len; i++) {
-            h = 31*h + toLower(s.charAt(i));
-        }
-
-        return h;
-    }
-
-    /* If java.util.regex.ASCII ever becomes public or sun.*, use its code instead:*/
-    static boolean isLower(int ch) {
-        return ((ch-'a')|('z'-ch)) >= 0;
-    }
-
-    static boolean isUpper(int ch) {
-        return ((ch-'A')|('Z'-ch)) >= 0;
-    }
-
-    static int toLower(int ch) {
-        return isUpper(ch) ? (ch + 0x20) : ch;
-    }
-
-    static int toUpper(int ch) {
-        return isLower(ch) ? (ch - 0x20) : ch;
-    }
-}
--- a/jdk/src/jdk.charsets/share/classes/sun/nio/cs/ext/AbstractCharsetProvider.java	Tue Mar 08 11:01:38 2016 +0000
+++ b/jdk/src/jdk.charsets/share/classes/sun/nio/cs/ext/AbstractCharsetProvider.java	Tue Mar 08 12:11:07 2016 +0000
@@ -33,7 +33,6 @@
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.Map;
-import sun.misc.ASCIICaseInsensitiveComparator;
 
 
 /**
@@ -49,22 +48,22 @@
     /* Maps canonical names to class names
      */
     private Map<String,String> classMap
-        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
+        = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 
     /* Maps alias names to canonical names
      */
     private Map<String,String> aliasMap
-        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
+        = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 
     /* Maps canonical names to alias-name arrays
      */
     private Map<String,String[]> aliasNameMap
-        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
+        = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 
     /* Maps canonical names to soft references that hold cached instances
      */
     private Map<String,SoftReference<Charset>> cache
-        = new TreeMap<>(ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
+        = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 
     private String packagePrefix;