From 7270451f1955f9b853ec4f57649a315e8a96c516 Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Sun, 30 Mar 2003 06:43:45 +0000 Subject: [PATCH] natString.cc (hashCode): Use cachedHashCode. 2003-03-29 Eric Blake Tom Tromey * java/lang/natString.cc (hashCode): Use cachedHashCode. (init()): Removed. (charAt): Put index in exception. (contentEquals): New method. Include StringBuffer.h. * java/lang/String.java (cachedHashCode): New field. (String()): Follow classpath implementation. (init()): Removed. (contentEquals): Declare. (subSequence): Don't declare IndexOutIfBoundsException in throws clause. (matches, replaceFirst, replaceAll, split): New methods from Classpath. Co-Authored-By: Tom Tromey From-SVN: r65037 --- libjava/ChangeLog | 17 ++++ libjava/java/lang/String.java | 146 ++++++++++++++++++++++++++++++++- libjava/java/lang/natString.cc | 36 +++++--- 3 files changed, 184 insertions(+), 15 deletions(-) diff --git a/libjava/ChangeLog b/libjava/ChangeLog index d93cdd3f5d2..ae9c68c0fce 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,20 @@ +2003-03-29 Eric Blake + Tom Tromey + + * java/lang/natString.cc (hashCode): Use cachedHashCode. + (init()): Removed. + (charAt): Put index in exception. + (contentEquals): New method. + Include StringBuffer.h. + * java/lang/String.java (cachedHashCode): New field. + (String()): Follow classpath implementation. + (init()): Removed. + (contentEquals): Declare. + (subSequence): Don't declare IndexOutIfBoundsException in throws + clause. + (matches, replaceFirst, replaceAll, split): New methods from + Classpath. + 2003-03-29 Tom Tromey * java/lang/String.java: Reordered to follow Classpath; merged in diff --git a/libjava/java/lang/String.java b/libjava/java/lang/String.java index e10e7dd1814..29b9c45d44d 100644 --- a/libjava/java/lang/String.java +++ b/libjava/java/lang/String.java @@ -44,6 +44,8 @@ import java.io.Serializable; import java.lang.Comparable; import java.util.Comparator; import java.util.Locale; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; /** * Strings represent an immutable set of characters. All String literals @@ -86,6 +88,12 @@ public final class String implements Serializable, Comparable, CharSequence private int boffset; // Note this is a byte offset - don't use in Java code! int count; + /** + * Caches the result of hashCode(). If this value is zero, the hashcode + * is considered uncached (even if 0 is the correct hash value). + */ + private int cachedHashCode; + /** * An implementation for {@link CASE_INSENSITIVE_ORDER}. * This must be {@link Serializable}. The class name is dictated by @@ -137,9 +145,11 @@ public final class String implements Serializable, Comparable, CharSequence * Creates an empty String (length 0). Unless you really need a new object, * consider using "" instead. */ - public String () + public String() { - init(); + data = "".data; + boffset = 0; + count = 0; } /** @@ -154,6 +164,7 @@ public final class String implements Serializable, Comparable, CharSequence data = str.data; boffset = str.boffset; count = str.count; + cachedHashCode = str.cachedHashCode; } /** @@ -510,6 +521,17 @@ public final class String implements Serializable, Comparable, CharSequence */ public native boolean equals (Object anObject); + /** + * Compares the given StringBuffer to this String. This is true if the + * StringBuffer has the same content as this String at this moment. + * + * @param buffer the StringBuffer to compare to + * @return true if StringBuffer has the same character sequence + * @throws NullPointerException if the given StringBuffer is null + * @since 1.4 + */ + public native boolean contentEquals(StringBuffer buffer); + /** * Compares a String to this String, ignoring case. This does not handle * multi-character capitalization exceptions; instead the comparison is @@ -815,7 +837,6 @@ public final class String implements Serializable, Comparable, CharSequence * @since 1.4 */ public CharSequence subSequence(int beginIndex, int endIndex) - throws IndexOutOfBoundsException { return substring(beginIndex, endIndex); } @@ -840,6 +861,124 @@ public final class String implements Serializable, Comparable, CharSequence */ public native String replace (char oldChar, char newChar); + /** + * Test if this String matches a regular expression. This is shorthand for + * {@link Pattern}.matches(regex, this). + * + * @param regex the pattern to match + * @return true if the pattern matches + * @throws NullPointerException if regex is null + * @throws PatternSyntaxException if regex is invalid + * @see Pattern#matches(String, CharSequence) + * @since 1.4 + */ + public boolean matches(String regex) + { + return Pattern.matches(regex, this); + } + + /** + * Replaces the first substring match of the regular expression with a + * given replacement. This is shorthand for {@link Pattern} + * .compile(regex).matcher(this).replaceFirst(replacement). + * + * @param regex the pattern to match + * @param replacement the replacement string + * @return the modified string + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #replaceAll(String, String) + * @see Pattern#compile(String) + * @see Pattern#matcher(CharSequence) + * @see Matcher#replaceFirst(String) + * @since 1.4 + */ + public String replaceFirst(String regex, String replacement) + { + return Pattern.compile(regex).matcher(this).replaceFirst(replacement); + } + + /** + * Replaces all matching substrings of the regular expression with a + * given replacement. This is shorthand for {@link Pattern} + * .compile(regex).matcher(this).replaceAll(replacement). + * + * @param regex the pattern to match + * @param replacement the replacement string + * @return the modified string + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #replaceFirst(String, String) + * @see Pattern#compile(String) + * @see Pattern#matcher(CharSequence) + * @see Matcher#replaceAll(String) + * @since 1.4 + */ + public String replaceAll(String regex, String replacement) + { + return Pattern.compile(regex).matcher(this).replaceAll(replacement); + } + + /** + * Split this string around the matches of a regular expression. Each + * element of the returned array is the largest block of characters not + * terminated by the regular expression, in the order the matches are found. + * + *

The limit affects the length of the array. If it is positive, the + * array will contain at most n elements (n - 1 pattern matches). If + * negative, the array length is unlimited, but there can be trailing empty + * entries. if 0, the array length is unlimited, and trailing empty entries + * are discarded. + * + *

For example, splitting "boo:and:foo" yields:
+ * + * + * + * + * + * + * + * + *
Regex Limit Result
":" 2 { "boo", "and:foo" }
":" t { "boo", "and", "foo" }
":" -2 { "boo", "and", "foo" }
"o" 5 { "b", "", ":and:f", "", "" }
"o" -2 { "b", "", ":and:f", "", "" }
"o" 0 { "b", "", ":and:f" }
+ * + *

This is shorthand for + * {@link Pattern}.compile(regex).split(this, limit). + * + * @param regex the pattern to match + * @param limit the limit threshold + * @return the array of split strings + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see Pattern#compile(String) + * @see Pattern#split(CharSequence, int) + * @since 1.4 + */ + public String[] split(String regex, int limit) + { + return Pattern.compile(regex).split(this, limit); + } + + /** + * Split this string around the matches of a regular expression. Each + * element of the returned array is the largest block of characters not + * terminated by the regular expression, in the order the matches are found. + * The array length is unlimited, and trailing empty entries are discarded, + * as though calling split(regex, 0). + * + * @param regex the pattern to match + * @return the array of split strings + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #split(String, int) + * @see Pattern#compile(String) + * @see Pattern#split(CharSequence, int) + * @since 1.4 + */ + public String[] split(String regex) + { + return Pattern.compile(regex).split(this, 0); + } + /** * Lowercases this String according to a particular locale. This uses * Unicode's special case mappings, as applied to the given Locale, so the @@ -1088,7 +1227,6 @@ public final class String implements Serializable, Comparable, CharSequence public native String intern (); - private native void init (); private native void init (char[] chars, int offset, int count, boolean dont_copy); private native void init (byte[] chars, int hibyte, int offset, int count); diff --git a/libjava/java/lang/natString.cc b/libjava/java/lang/natString.cc index 0d30a35af51..6514d816a02 100644 --- a/libjava/java/lang/natString.cc +++ b/libjava/java/lang/natString.cc @@ -1,6 +1,6 @@ // natString.cc - Implementation of java.lang.String native methods. -/* Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation This file is part of libgcj. @@ -20,6 +20,7 @@ details. */ #include #include #include +#include #include #include #include @@ -102,7 +103,9 @@ hashChars (jchar* ptr, jint length) jint java::lang::String::hashCode() { - return hashChars(JvGetStringChars(this), length()); + if (cachedHashCode == 0) + cachedHashCode = hashChars(JvGetStringChars(this), length()); + return cachedHashCode; } jstring* @@ -428,14 +431,6 @@ _Jv_NewStringLatin1(const char *bytes, jsize len) return str; } -void -java::lang::String::init () -{ - count = 0; - boffset = sizeof(java::lang::String); - data = this; -} - void java::lang::String::init(jcharArray chars, jint offset, jint count, jboolean dont_copy) @@ -552,11 +547,30 @@ java::lang::String::equals(jobject anObject) return true; } +jboolean +java::lang::String::contentEquals(java::lang::StringBuffer* buffer) +{ + if (buffer == NULL) + throw new NullPointerException; + JvSynchronize sync(buffer); + if (count != buffer->count) + return false; + if (data == buffer->value) + return true; // Possible if shared. + jint i = count; + jchar *xptr = JvGetStringChars(this); + jchar *yptr = elements(buffer->value); + while (--i >= 0) + if (*xptr++ != *yptr++) + return false; + return true; +} + jchar java::lang::String::charAt(jint i) { if (i < 0 || i >= count) - throw new java::lang::StringIndexOutOfBoundsException; + throw new java::lang::StringIndexOutOfBoundsException(i); return JvGetStringChars(this)[i]; }