- Lazy init hashCache to avoid clinit calls
- Made hashCode run faster; since only 32 chars can contribute to the final value, it seemed silly to read more than 32; I spread those characters out evenly over the string for hopefully better hashing
- Optimized valueOf() impls
- String(x) is the generally accepted syntax for coercing to a String primitive
- Made some param names more consistent
Review by: knorton
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1208 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/super/com/google/gwt/emul/java/lang/String.java b/user/super/com/google/gwt/emul/java/lang/String.java
index e1cecdc..ec1bf34 100644
--- a/user/super/com/google/gwt/emul/java/lang/String.java
+++ b/user/super/com/google/gwt/emul/java/lang/String.java
@@ -35,7 +35,7 @@
* accesses need to be prefixed with ':' to prevent conflict with built-in JavaScript properties.
* @skip
*/
- private static JavaScriptObject hashCache;
+ static JavaScriptObject hashCache;
public static native String valueOf(boolean x) /*-{ return x ? "true" : "false"; }-*/;
@@ -64,13 +64,13 @@
return valueOf(x, 0, x.length);
}
- public static native String valueOf(double x) /*-{ return x.toString(); }-*/;
+ public static native String valueOf(double x) /*-{ return "" + x; }-*/;
- public static native String valueOf(float x) /*-{ return x.toString(); }-*/;
+ public static native String valueOf(float x) /*-{ return "" + x; }-*/;
- public static native String valueOf(int x) /*-{ return x.toString(); }-*/;
+ public static native String valueOf(int x) /*-{ return "" + x; }-*/;
- public static native String valueOf(long x) /*-{ return x.toString(); }-*/;
+ public static native String valueOf(long x) /*-{ return "" + x; }-*/;
public static String valueOf(Object x) {
return x != null ? x.toString() : "null";
@@ -128,29 +128,7 @@
private static native boolean __equals(String me, Object other) /*-{
// Coerce me to a primitive string to force string comparison
- return me.toString() == other;
- }-*/;
-
- // Prefix needed to prevent conflict with built-in JavaScript properties.
- private static native int __hashCode(String me) /*-{
- var hashCode = @java.lang.String::hashCache[':' + me];
- if (hashCode) {
- return hashCode;
- }
-
- hashCode = 0;
- var len = me.length;
- var i = len;
- while (--i >= 0) {
- hashCode <<= 1;
- hashCode += me.charCodeAt(i);
- }
- @java.lang.String::hashCache[':' + me] = hashCode;
- return hashCode;
- }-*/;
-
- private static native void __initHashCache() /*-{
- @java.lang.String::hashCache = {};
+ return String(me) == other;
}-*/;
public String() {
@@ -183,21 +161,26 @@
}
public int compareTo(String other) {
- int length = Math.min(this.length(), other.length());
+ int thisLength = this.length();
+ int otherLength = other.length();
+ int length = Math.min(thisLength, otherLength);
for (int i = 0; i < length; i++) {
- if (this.charAt(i) != other.charAt(i)) {
- return this.charAt(i) - other.charAt(i);
+ char thisChar = this.charAt(i);
+ char otherChar = other.charAt(i);
+ if (thisChar != otherChar) {
+ return thisChar - otherChar;
}
}
- return this.length() - other.length();
+ return thisLength - otherLength;
}
- public native String concat(String other) /*-{
- return this+other;
+ public native String concat(String str) /*-{
+ return this + str;
}-*/;
public native boolean endsWith(String suffix) /*-{
- return this.lastIndexOf(suffix) != -1 && (this.lastIndexOf(suffix) == (this.length - suffix.length));
+ return (this.lastIndexOf(suffix) != -1)
+ && (this.lastIndexOf(suffix) == (this.length - suffix.length));
}-*/;
public boolean equals(Object other) {
@@ -212,9 +195,36 @@
return (this == other) || (this.toLowerCase() == other.toLowerCase());
}-*/;
- public int hashCode() {
- return __hashCode(this);
- }
+ public native int hashCode() /*-{
+ var hashCache = @java.lang.String::hashCache;
+ if (!hashCache) {
+ hashCache = @java.lang.String::hashCache = {};
+ }
+
+ // Prefix needed to prevent conflict with built-in JavaScript properties.
+ var key = ':' + this;
+ var hashCode = hashCache[key];
+ // Must check null/undefined because 0 is a legal hashCode
+ if (hashCode == null) {
+ hashCode = 0;
+ var n = this.length;
+ // In our hash code calculation, only 32 characters will actually affect
+ // the final value, so there's no need to sample more than 32 characters.
+ // To get a better hash code, we'd like to evenly distribute these
+ // characters throughout the string. That means that for lengths between
+ // 0 and 63 (inclusive), we increment by 1. For 64-95, 2; 96-127, 3; and
+ // so on. The complicated formula below computes just that. The "| 0"
+ // operation is a fast way to coerce the division result to an integer.
+ var inc = (n < 64) ? 1 : ((n / 32) | 0);
+ for (var i = 0; i < n; i += inc) {
+ hashCode <<= 1;
+ hashCode += this.charCodeAt(i);
+ }
+ hashCode |= 0; // force to 32-bits
+ hashCache[key] = hashCode
+ }
+ return hashCode;
+ }-*/;
public native int indexOf(int ch) /*-{
return this.indexOf(String.fromCharCode(ch));
@@ -228,8 +238,8 @@
return this.indexOf(str);
}-*/;
- public native int indexOf(String other, int startIndex) /*-{
- return this.indexOf(other, startIndex);
+ public native int indexOf(String str, int startIndex) /*-{
+ return this.indexOf(str, startIndex);
}-*/;
public native int lastIndexOf(int ch) /*-{
@@ -410,9 +420,5 @@
return r2;
}-*/;
- static {
- String.__initHashCache();
- }
-
// CHECKSTYLE_ON
}