diff options
Diffstat (limited to 'java/util')
-rw-r--r-- | java/util/Calendar.java | 33 | ||||
-rw-r--r-- | java/util/Locale.java | 48 | ||||
-rw-r--r-- | java/util/ResourceBundle.java | 134 | ||||
-rw-r--r-- | java/util/Vector.java | 12 | ||||
-rw-r--r-- | java/util/regex/Matcher.java | 26 | ||||
-rw-r--r-- | java/util/zip/ZipFile.java | 109 |
6 files changed, 232 insertions, 130 deletions
diff --git a/java/util/Calendar.java b/java/util/Calendar.java index 6865230c8..8c46c0193 100644 --- a/java/util/Calendar.java +++ b/java/util/Calendar.java @@ -1,5 +1,6 @@ /* Calendar.java -- - Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, + Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -484,6 +485,8 @@ public abstract class Calendar /** * Creates a calendar representing the actual time, using the default * time zone and locale. + * + * @return The new calendar. */ public static synchronized Calendar getInstance() { @@ -493,7 +496,12 @@ public abstract class Calendar /** * Creates a calendar representing the actual time, using the given * time zone and the default locale. - * @param zone a time zone. + * + * @param zone a time zone (<code>null</code> not permitted). + * + * @return The new calendar. + * + * @throws NullPointerException if <code>zone</code> is <code>null</code>. */ public static synchronized Calendar getInstance(TimeZone zone) { @@ -503,7 +511,12 @@ public abstract class Calendar /** * Creates a calendar representing the actual time, using the default * time zone and the given locale. - * @param locale a locale. + * + * @param locale a locale (<code>null</code> not permitted). + * + * @return The new calendar. + * + * @throws NullPointerException if <code>locale</code> is <code>null</code>. */ public static synchronized Calendar getInstance(Locale locale) { @@ -525,8 +538,14 @@ public abstract class Calendar /** * Creates a calendar representing the actual time, using the given * time zone and locale. - * @param zone a time zone. - * @param locale a locale. + * + * @param zone a time zone (<code>null</code> not permitted). + * @param locale a locale (<code>null</code> not permitted). + * + * @return The new calendar. + * + * @throws NullPointerException if <code>zone</code> or <code>locale</code> + * is <code>null</code>. */ public static synchronized Calendar getInstance(TimeZone zone, Locale locale) { @@ -618,6 +637,10 @@ public abstract class Calendar /** * Sets this Calendar's time to the given Date. All time fields * are invalidated by this method. + * + * @param date the date (<code>null</code> not permitted). + * + * @throws NullPointerException if <code>date</code> is <code>null</code>. */ public final void setTime(Date date) { diff --git a/java/util/Locale.java b/java/util/Locale.java index d2aead43c..001c7afde 100644 --- a/java/util/Locale.java +++ b/java/util/Locale.java @@ -188,11 +188,17 @@ public final class Locale implements Serializable, Cloneable private String variant; /** - * This is the cached hashcode. When writing to stream, we write -1. + * This is where the JDK caches its hashcode. This is is only here + * for serialization purposes. The actual cache is hashcodeCache * * @serial should be -1 in serial streams */ - private transient int hashcode; + private int hashcode = -1; + + /** + * This is the cached hashcode. + */ + private transient int hashcodeCache; /** * Array storing all available locales. @@ -324,7 +330,7 @@ public final class Locale implements Serializable, Cloneable this.language = language; this.country = country; this.variant = variant; - hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); + hashcodeCache = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); } /** @@ -899,7 +905,7 @@ public final class Locale implements Serializable, Cloneable */ public int hashCode() { - return hashcode; + return hashcodeCache; } /** @@ -917,32 +923,12 @@ public final class Locale implements Serializable, Cloneable return false; Locale l = (Locale) obj; - return (language == l.language - && country == l.country + return (language == l.language + && country == l.country && variant == l.variant); } /** - * Write the locale to an object stream. - * - * @param s the stream to write to - * @throws IOException if the write fails - * @serialData The first three fields are Strings representing language, - * country, and variant. The fourth field is a placeholder for - * the cached hashcode, but this is always written as -1, and - * recomputed when reading it back. - */ - private void writeObject(ObjectOutputStream s) - throws IOException - { - s.writeObject(language); - s.writeObject(country); - s.writeObject(variant); - // Hashcode field is always written as -1. - s.writeInt(-1); - } - - /** * Reads a locale from the input stream. * * @param s the stream to read from @@ -953,10 +939,10 @@ public final class Locale implements Serializable, Cloneable private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { - language = ((String) s.readObject()).intern(); - country = ((String) s.readObject()).intern(); - variant = ((String) s.readObject()).intern(); - // Recompute hashcode. - hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); + s.defaultReadObject(); + language = language.intern(); + country = country.intern(); + variant = variant.intern(); + hashcodeCache = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); } } // class Locale diff --git a/java/util/ResourceBundle.java b/java/util/ResourceBundle.java index 751d380b2..9b82bc801 100644 --- a/java/util/ResourceBundle.java +++ b/java/util/ResourceBundle.java @@ -91,6 +91,14 @@ baseName</pre> public abstract class ResourceBundle { /** + * Maximum size of our cache of <code>ResourceBundle</code>s keyed by + * {@link BundleKey} instances. + * + * @see BundleKey + */ + private static final int CACHE_SIZE = 100; + + /** * The parent bundle. This is consulted when you call getObject and there * is no such resource in the current bundle. This field may be null. */ @@ -104,21 +112,22 @@ public abstract class ResourceBundle private Locale locale; /** - * The resource bundle cache. - */ - private static Map bundleCache; - - /** - * The last default Locale we saw. If this ever changes then we have to - * reset our caches. - */ - private static Locale lastDefaultLocale; - - /** - * The `empty' locale is created once in order to optimize - * tryBundle(). + * A VM-wide cache of resource bundles already fetched. + * <p> + * This {@link Map} is a Least Recently Used (LRU) cache, of the last + * {@link #CACHE_SIZE} accessed <code>ResourceBundle</code>s keyed by the + * tuple: default locale, resource-bundle name, resource-bundle locale, and + * classloader. + * + * @see BundleKey */ - private static final Locale emptyLocale = new Locale(""); + private static Map bundleCache = new LinkedHashMap(CACHE_SIZE + 1, 0.75F, true) + { + public boolean removeEldestEntry(Map.Entry entry) + { + return size() > CACHE_SIZE; + } + }; /** * The constructor. It does nothing special. @@ -246,6 +255,7 @@ public abstract class ResourceBundle by the combination of bundle name, locale, and class loader. */ private static class BundleKey { + Locale defaultLocale; String baseName; Locale locale; ClassLoader classLoader; @@ -253,18 +263,19 @@ public abstract class ResourceBundle BundleKey() {} - BundleKey(String s, Locale l, ClassLoader cl) + BundleKey(Locale dl, String s, Locale l, ClassLoader cl) { - set(s, l, cl); + set(dl, s, l, cl); } - void set(String s, Locale l, ClassLoader cl) + void set(Locale dl, String s, Locale l, ClassLoader cl) { + defaultLocale = dl; baseName = s; locale = l; classLoader = cl; - hashcode = baseName.hashCode() ^ locale.hashCode() ^ - classLoader.hashCode(); + hashcode = defaultLocale.hashCode() ^ baseName.hashCode() + ^ locale.hashCode() ^ classLoader.hashCode(); } public int hashCode() @@ -277,10 +288,11 @@ public abstract class ResourceBundle if (! (o instanceof BundleKey)) return false; BundleKey key = (BundleKey) o; - return hashcode == key.hashcode && - baseName.equals(key.baseName) && - locale.equals(key.locale) && - classLoader.equals(key.classLoader); + return hashcode == key.hashcode + && defaultLocale.equals(key.defaultLocale) + && baseName.equals(key.baseName) + && locale.equals(key.locale) + && classLoader.equals(key.classLoader); } } @@ -370,61 +382,39 @@ public abstract class ResourceBundle public static synchronized ResourceBundle getBundle (String baseName, Locale locale, ClassLoader classLoader) { - // If the default locale changed since the last time we were called, - // all cache entries are invalidated. Locale defaultLocale = Locale.getDefault(); - if (defaultLocale != lastDefaultLocale) - { - bundleCache = new HashMap(); - lastDefaultLocale = defaultLocale; - } - // This will throw NullPointerException if any arguments are null. - lookupKey.set(baseName, locale, classLoader); - + lookupKey.set(defaultLocale, baseName, locale, classLoader); Object obj = bundleCache.get(lookupKey); - ResourceBundle rb = null; - if (obj instanceof ResourceBundle) + return (ResourceBundle) obj; + + if (obj == nullEntry) + throw new MissingResourceException("Bundle " + baseName + + " not found for locale " + locale + + " by classloader " + classLoader, + baseName, ""); + // First, look for a bundle for the specified locale. We don't want + // the base bundle this time. + boolean wantBase = locale.equals(defaultLocale); + ResourceBundle bundle = tryBundle(baseName, locale, classLoader, wantBase); + // Try the default locale if neccessary. + if (bundle == null && ! wantBase) + bundle = tryBundle(baseName, defaultLocale, classLoader, true); + + BundleKey key = new BundleKey(defaultLocale, baseName, locale, classLoader); + if (bundle == null) { - return (ResourceBundle) obj; - } - else if (obj == nullEntry) - { - // Lookup has failed previously. Fall through. + // Cache the fact that this lookup has previously failed. + bundleCache.put(key, nullEntry); + throw new MissingResourceException("Bundle " + baseName + + " not found for locale " + locale + + " by classloader " + classLoader, + baseName, ""); } - else - { - // First, look for a bundle for the specified locale. We don't want - // the base bundle this time. - boolean wantBase = locale.equals(defaultLocale); - ResourceBundle bundle = tryBundle(baseName, locale, classLoader, - wantBase); - - // Try the default locale if neccessary. - if (bundle == null && !locale.equals(defaultLocale)) - bundle = tryBundle(baseName, defaultLocale, classLoader, true); - - BundleKey key = new BundleKey(baseName, locale, classLoader); - if (bundle == null) - { - // Cache the fact that this lookup has previously failed. - bundleCache.put(key, nullEntry); - } - else - { - // Cache the result and return it. - bundleCache.put(key, bundle); - return bundle; - } - } - - throw new MissingResourceException("Bundle " + baseName - + " not found for locale " - + locale - + " by classloader " - + classLoader, - baseName, ""); + // Cache the result and return it. + bundleCache.put(key, bundle); + return bundle; } /** diff --git a/java/util/Vector.java b/java/util/Vector.java index 02eb1539a..ea29ce093 100644 --- a/java/util/Vector.java +++ b/java/util/Vector.java @@ -720,8 +720,10 @@ public class Vector<T> extends AbstractList<T> */ public synchronized boolean removeAll(Collection<?> c) { - if (c == null) - throw new NullPointerException(); + // The NullPointerException is thrown implicitly when the Vector + // is not empty and c is null. The RI allows null arguments when + // the vector is empty. See Mauve test: + // gnu/testlet/java/util/Vector/removeAll.java int i; int j; @@ -749,8 +751,10 @@ public class Vector<T> extends AbstractList<T> */ public synchronized boolean retainAll(Collection<?> c) { - if (c == null) - throw new NullPointerException(); + // The NullPointerException is thrown implicitly when the Vector + // is not empty and c is null. The RI allows null arguments when + // the vector is empty. See Mauve test: + // gnu/testlet/java/util/Vector/retainAll.java int i; int j; diff --git a/java/util/regex/Matcher.java b/java/util/regex/Matcher.java index 25e73810e..3ddd42547 100644 --- a/java/util/regex/Matcher.java +++ b/java/util/regex/Matcher.java @@ -218,7 +218,7 @@ public final class Matcher implements MatchResult public boolean lookingAt () { - match = pattern.getRE().getMatch(inputCharIndexed, 0); + match = pattern.getRE().getMatch(inputCharIndexed, 0, RE.REG_FIX_STARTING_POSITION, null); if (match != null) { if (match.getStartIndex() == 0) @@ -243,7 +243,7 @@ public final class Matcher implements MatchResult */ public boolean matches () { - match = pattern.getRE().getMatch(inputCharIndexed, 0, RE.REG_TRY_ENTIRE_MATCH); + match = pattern.getRE().getMatch(inputCharIndexed, 0, RE.REG_TRY_ENTIRE_MATCH|RE.REG_FIX_STARTING_POSITION, null); if (match != null) { if (match.getStartIndex() == 0) @@ -309,6 +309,28 @@ public final class Matcher implements MatchResult return match.getStartIndex(group); } + /** + * @return True if and only if the matcher hit the end of input. + */ + public boolean hitEnd() + { + return inputCharIndexed.hitEnd(); + } + + /** + * @return A string expression of this matcher. + */ + public String toString() + { + StringBuilder sb = new StringBuilder(); + sb.append(this.getClass().getName()) + .append("[pattern=").append(pattern.pattern()) + .append(" region=").append("0").append(",").append(input.length()) + .append(" lastmatch=").append(match == null ? "" : match.toString()) + .append("]"); + return sb.toString(); + } + private void assertMatchOp() { if (match == null) throw new IllegalStateException(); diff --git a/java/util/zip/ZipFile.java b/java/util/zip/ZipFile.java index 00ba19b15..3b34bd1f5 100644 --- a/java/util/zip/ZipFile.java +++ b/java/util/zip/ZipFile.java @@ -48,6 +48,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedHashMap; @@ -516,6 +519,16 @@ public class ZipFile implements ZipConstants private static final class PartialInputStream extends InputStream { + /** + * The UTF-8 charset use for decoding the filenames. + */ + private static final Charset UTF8CHARSET = Charset.forName("UTF-8"); + + /** + * The actual UTF-8 decoder. Created on demand. + */ + private CharsetDecoder utf8Decoder; + private final RandomAccessFile raf; private final byte[] buffer; private long bufferOffset; @@ -652,23 +665,86 @@ public class ZipFile implements ZipConstants int readLeShort() throws IOException { - int b0 = read(); - int b1 = read(); - if (b1 == -1) - throw new EOFException(); - return (b0 & 0xff) | (b1 & 0xff) << 8; + int result; + if(pos + 1 < buffer.length) + { + result = ((buffer[pos + 0] & 0xff) | (buffer[pos + 1] & 0xff) << 8); + pos += 2; + } + else + { + int b0 = read(); + int b1 = read(); + if (b1 == -1) + throw new EOFException(); + result = (b0 & 0xff) | (b1 & 0xff) << 8; + } + return result; } int readLeInt() throws IOException { - int b0 = read(); - int b1 = read(); - int b2 = read(); - int b3 = read(); - if (b3 == -1) - throw new EOFException(); - return ((b0 & 0xff) | (b1 & 0xff) << 8) - | ((b2 & 0xff) | (b3 & 0xff) << 8) << 16; + int result; + if(pos + 3 < buffer.length) + { + result = (((buffer[pos + 0] & 0xff) | (buffer[pos + 1] & 0xff) << 8) + | ((buffer[pos + 2] & 0xff) + | (buffer[pos + 3] & 0xff) << 8) << 16); + pos += 4; + } + else + { + int b0 = read(); + int b1 = read(); + int b2 = read(); + int b3 = read(); + if (b3 == -1) + throw new EOFException(); + result = (((b0 & 0xff) | (b1 & 0xff) << 8) | ((b2 & 0xff) + | (b3 & 0xff) << 8) << 16); + } + return result; + } + + /** + * Decode chars from byte buffer using UTF8 encoding. This + * operation is performance-critical since a jar file contains a + * large number of strings for the name of each file in the + * archive. This routine therefore avoids using the expensive + * utf8Decoder when decoding is straightforward. + * + * @param buffer the buffer that contains the encoded character + * data + * @param pos the index in buffer of the first byte of the encoded + * data + * @param length the length of the encoded data in number of + * bytes. + * + * @return a String that contains the decoded characters. + */ + private String decodeChars(byte[] buffer, int pos, int length) + throws IOException + { + String result; + int i=length - 1; + while ((i >= 0) && (buffer[i] <= 0x7f)) + { + i--; + } + if (i < 0) + { + result = new String(buffer, 0, pos, length); + } + else + { + ByteBuffer bufferBuffer = ByteBuffer.wrap(buffer, pos, length); + if (utf8Decoder == null) + utf8Decoder = UTF8CHARSET.newDecoder(); + utf8Decoder.reset(); + char [] characters = utf8Decoder.decode(bufferBuffer).array(); + result = String.valueOf(characters); + } + return result; } String readString(int length) throws IOException @@ -676,25 +752,26 @@ public class ZipFile implements ZipConstants if (length > end - (bufferOffset + pos)) throw new EOFException(); + String result = null; try { if (buffer.length - pos >= length) { - String s = new String(buffer, pos, length, "UTF-8"); + result = decodeChars(buffer, pos, length); pos += length; - return s; } else { byte[] b = new byte[length]; readFully(b); - return new String(b, 0, length, "UTF-8"); + result = decodeChars(b, 0, length); } } catch (UnsupportedEncodingException uee) { throw new AssertionError(uee); } + return result; } public void addDummyByte() |