summaryrefslogtreecommitdiff
path: root/java/util
diff options
context:
space:
mode:
Diffstat (limited to 'java/util')
-rw-r--r--java/util/Calendar.java33
-rw-r--r--java/util/Locale.java48
-rw-r--r--java/util/ResourceBundle.java134
-rw-r--r--java/util/Vector.java12
-rw-r--r--java/util/regex/Matcher.java26
-rw-r--r--java/util/zip/ZipFile.java109
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()