diff options
Diffstat (limited to 'libjava/classpath/java/util')
31 files changed, 4782 insertions, 400 deletions
diff --git a/libjava/classpath/java/util/AbstractMap.java b/libjava/classpath/java/util/AbstractMap.java index 29249e1..2f58121 100644 --- a/libjava/classpath/java/util/AbstractMap.java +++ b/libjava/classpath/java/util/AbstractMap.java @@ -69,10 +69,23 @@ import java.io.Serializable; */ public abstract class AbstractMap<K, V> implements Map<K, V> { - /** @since 1.6 */ + /** + * A class containing an immutable key and value. The + * implementation of {@link Entry#setValue(V)} for this class + * simply throws an {@link UnsupportedOperationException}, + * thus preventing changes being made. This is useful when + * a static thread-safe view of a map is required. + * + * @since 1.6 + */ public static class SimpleImmutableEntry<K, V> implements Entry<K, V>, Serializable { + /** + * Compatible with JDK 1.6 + */ + private static final long serialVersionUID = 7138329143949025153L; + K key; V value; @@ -670,6 +683,12 @@ public abstract class AbstractMap<K, V> implements Map<K, V> */ public static class SimpleEntry<K, V> implements Entry<K, V>, Serializable { + + /** + * Compatible with JDK 1.6 + */ + private static final long serialVersionUID = -8499721149061103585L; + /** * The key. Package visible for direct manipulation. */ @@ -730,7 +749,7 @@ public abstract class AbstractMap<K, V> implements Map<K, V> * * @return the key */ - public final K getKey() + public K getKey() { return key; } @@ -741,7 +760,7 @@ public abstract class AbstractMap<K, V> implements Map<K, V> * * @return the value */ - public final V getValue() + public V getValue() { return value; } @@ -755,7 +774,7 @@ public abstract class AbstractMap<K, V> implements Map<K, V> * * @return the hash code */ - public final int hashCode() + public int hashCode() { return (AbstractMap.hashCode(key) ^ AbstractMap.hashCode(value)); } @@ -788,7 +807,7 @@ public abstract class AbstractMap<K, V> implements Map<K, V> * * @return the string representation */ - public final String toString() + public String toString() { return key + "=" + value; } diff --git a/libjava/classpath/java/util/Arrays.java b/libjava/classpath/java/util/Arrays.java index 41e8045..9443ced 100644 --- a/libjava/classpath/java/util/Arrays.java +++ b/libjava/classpath/java/util/Arrays.java @@ -92,8 +92,38 @@ public class Arrays */ public static int binarySearch(byte[] a, byte key) { - int low = 0; - int hi = a.length - 1; + if (a.length == 0) + return -1; + return binarySearch(a, 0, a.length - 1, key); + } + + /** + * Perform a binary search of a range of a byte array for a key. The range + * must be sorted (as by the <code>sort(byte[], int, int)</code> method) - + * if it is not, the behaviour of this method is undefined, and may be an + * infinite loop. If the array contains the key more than once, any one of + * them may be found. Note: although the specification allows for an infinite + * loop if the array is unsorted, it will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param low the lowest index to search from. + * @param hi the highest index to search to. + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @throws IllegalArgumentException if <code>low > hi</code> + * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or + * <code>hi > a.length</code>. + */ + public static int binarySearch(byte[] a, int low, int hi, byte key) + { + if (low > hi) + throw new IllegalArgumentException("The start index is higher than " + + "the finish index."); + if (low < 0 || hi > a.length) + throw new ArrayIndexOutOfBoundsException("One of the indices is out " + + "of bounds."); int mid = 0; while (low <= hi) { @@ -126,8 +156,38 @@ public class Arrays */ public static int binarySearch(char[] a, char key) { - int low = 0; - int hi = a.length - 1; + if (a.length == 0) + return -1; + return binarySearch(a, 0, a.length - 1, key); + } + + /** + * Perform a binary search of a range of a char array for a key. The range + * must be sorted (as by the <code>sort(char[], int, int)</code> method) - + * if it is not, the behaviour of this method is undefined, and may be an + * infinite loop. If the array contains the key more than once, any one of + * them may be found. Note: although the specification allows for an infinite + * loop if the array is unsorted, it will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param low the lowest index to search from. + * @param hi the highest index to search to. + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @throws IllegalArgumentException if <code>low > hi</code> + * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or + * <code>hi > a.length</code>. + */ + public static int binarySearch(char[] a, int low, int hi, char key) + { + if (low > hi) + throw new IllegalArgumentException("The start index is higher than " + + "the finish index."); + if (low < 0 || hi > a.length) + throw new ArrayIndexOutOfBoundsException("One of the indices is out " + + "of bounds."); int mid = 0; while (low <= hi) { @@ -160,8 +220,38 @@ public class Arrays */ public static int binarySearch(short[] a, short key) { - int low = 0; - int hi = a.length - 1; + if (a.length == 0) + return -1; + return binarySearch(a, 0, a.length - 1, key); + } + + /** + * Perform a binary search of a range of a short array for a key. The range + * must be sorted (as by the <code>sort(short[], int, int)</code> method) - + * if it is not, the behaviour of this method is undefined, and may be an + * infinite loop. If the array contains the key more than once, any one of + * them may be found. Note: although the specification allows for an infinite + * loop if the array is unsorted, it will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param low the lowest index to search from. + * @param hi the highest index to search to. + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @throws IllegalArgumentException if <code>low > hi</code> + * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or + * <code>hi > a.length</code>. + */ + public static int binarySearch(short[] a, int low, int hi, short key) + { + if (low > hi) + throw new IllegalArgumentException("The start index is higher than " + + "the finish index."); + if (low < 0 || hi > a.length) + throw new ArrayIndexOutOfBoundsException("One of the indices is out " + + "of bounds."); int mid = 0; while (low <= hi) { @@ -194,8 +284,38 @@ public class Arrays */ public static int binarySearch(int[] a, int key) { - int low = 0; - int hi = a.length - 1; + if (a.length == 0) + return -1; + return binarySearch(a, 0, a.length - 1, key); + } + + /** + * Perform a binary search of a range of an integer array for a key. The range + * must be sorted (as by the <code>sort(int[], int, int)</code> method) - + * if it is not, the behaviour of this method is undefined, and may be an + * infinite loop. If the array contains the key more than once, any one of + * them may be found. Note: although the specification allows for an infinite + * loop if the array is unsorted, it will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param low the lowest index to search from. + * @param hi the highest index to search to. + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @throws IllegalArgumentException if <code>low > hi</code> + * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or + * <code>hi > a.length</code>. + */ + public static int binarySearch(int[] a, int low, int hi, int key) + { + if (low > hi) + throw new IllegalArgumentException("The start index is higher than " + + "the finish index."); + if (low < 0 || hi > a.length) + throw new ArrayIndexOutOfBoundsException("One of the indices is out " + + "of bounds."); int mid = 0; while (low <= hi) { @@ -228,8 +348,38 @@ public class Arrays */ public static int binarySearch(long[] a, long key) { - int low = 0; - int hi = a.length - 1; + if (a.length == 0) + return -1; + return binarySearch(a, 0, a.length - 1, key); + } + + /** + * Perform a binary search of a range of a long array for a key. The range + * must be sorted (as by the <code>sort(long[], int, int)</code> method) - + * if it is not, the behaviour of this method is undefined, and may be an + * infinite loop. If the array contains the key more than once, any one of + * them may be found. Note: although the specification allows for an infinite + * loop if the array is unsorted, it will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param low the lowest index to search from. + * @param hi the highest index to search to. + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @throws IllegalArgumentException if <code>low > hi</code> + * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or + * <code>hi > a.length</code>. + */ + public static int binarySearch(long[] a, int low, int hi, long key) + { + if (low > hi) + throw new IllegalArgumentException("The start index is higher than " + + "the finish index."); + if (low < 0 || hi > a.length) + throw new ArrayIndexOutOfBoundsException("One of the indices is out " + + "of bounds."); int mid = 0; while (low <= hi) { @@ -262,9 +412,39 @@ public class Arrays */ public static int binarySearch(float[] a, float key) { + if (a.length == 0) + return -1; + return binarySearch(a, 0, a.length - 1, key); + } + + /** + * Perform a binary search of a range of a float array for a key. The range + * must be sorted (as by the <code>sort(float[], int, int)</code> method) - + * if it is not, the behaviour of this method is undefined, and may be an + * infinite loop. If the array contains the key more than once, any one of + * them may be found. Note: although the specification allows for an infinite + * loop if the array is unsorted, it will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param low the lowest index to search from. + * @param hi the highest index to search to. + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @throws IllegalArgumentException if <code>low > hi</code> + * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or + * <code>hi > a.length</code>. + */ + public static int binarySearch(float[] a, int low, int hi, float key) + { + if (low > hi) + throw new IllegalArgumentException("The start index is higher than " + + "the finish index."); + if (low < 0 || hi > a.length) + throw new ArrayIndexOutOfBoundsException("One of the indices is out " + + "of bounds."); // Must use Float.compare to take into account NaN, +-0. - int low = 0; - int hi = a.length - 1; int mid = 0; while (low <= hi) { @@ -297,9 +477,39 @@ public class Arrays */ public static int binarySearch(double[] a, double key) { + if (a.length == 0) + return -1; + return binarySearch(a, 0, a.length - 1, key); + } + + /** + * Perform a binary search of a range of a double array for a key. The range + * must be sorted (as by the <code>sort(double[], int, int)</code> method) - + * if it is not, the behaviour of this method is undefined, and may be an + * infinite loop. If the array contains the key more than once, any one of + * them may be found. Note: although the specification allows for an infinite + * loop if the array is unsorted, it will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param low the lowest index to search from. + * @param hi the highest index to search to. + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @throws IllegalArgumentException if <code>low > hi</code> + * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or + * <code>hi > a.length</code>. + */ + public static int binarySearch(double[] a, int low, int hi, double key) + { + if (low > hi) + throw new IllegalArgumentException("The start index is higher than " + + "the finish index."); + if (low < 0 || hi > a.length) + throw new ArrayIndexOutOfBoundsException("One of the indices is out " + + "of bounds."); // Must use Double.compare to take into account NaN, +-0. - int low = 0; - int hi = a.length - 1; int mid = 0; while (low <= hi) { @@ -337,10 +547,33 @@ public class Arrays */ public static int binarySearch(Object[] a, Object key) { + if (a.length == 0) + return -1; return binarySearch(a, key, null); } /** + * Perform a binary search of a range of an Object array for a key. The range + * must be sorted (as by the <code>sort(Object[], int, int)</code> method) - + * if it is not, the behaviour of this method is undefined, and may be an + * infinite loop. If the array contains the key more than once, any one of + * them may be found. Note: although the specification allows for an infinite + * loop if the array is unsorted, it will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param low the lowest index to search from. + * @param hi the highest index to search to. + * @param key the value to search for + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + */ + public static int binarySearch(Object[] a, int low, int hi, Object key) + { + return binarySearch(a, low, hi, key, null); + } + + /** * Perform a binary search of an Object array for a key, using a supplied * Comparator. The array must be sorted (as by the sort() method with the * same Comparator) - if it is not, the behaviour of this method is @@ -364,8 +597,44 @@ public class Arrays */ public static <T> int binarySearch(T[] a, T key, Comparator<? super T> c) { - int low = 0; - int hi = a.length - 1; + if (a.length == 0) + return -1; + return binarySearch(a, 0, a.length - 1, key, c); + } + + /** + * Perform a binary search of a range of an Object array for a key using + * a {@link Comparator}. The range must be sorted (as by the + * <code>sort(Object[], int, int)</code> method) - if it is not, the + * behaviour of this method is undefined, and may be an infinite loop. If + * the array contains the key more than once, any one of them may be found. + * Note: although the specification allows for an infinite loop if the array + * is unsorted, it will not happen in this implementation. + * + * @param a the array to search (must be sorted) + * @param low the lowest index to search from. + * @param hi the highest index to search to. + * @param key the value to search for + * @param c the comparator by which the array is sorted; or null to + * use the elements' natural order + * @return the index at which the key was found, or -n-1 if it was not + * found, where n is the index of the first value higher than key or + * a.length if there is no such value. + * @throws ClassCastException if key could not be compared with one of the + * elements of a + * @throws IllegalArgumentException if <code>low > hi</code> + * @throws ArrayIndexOutOfBoundsException if <code>low < 0</code> or + * <code>hi > a.length</code>. + */ + public static <T> int binarySearch(T[] a, int low, int hi, T key, + Comparator<? super T> c) + { + if (low > hi) + throw new IllegalArgumentException("The start index is higher than " + + "the finish index."); + if (low < 0 || hi > a.length) + throw new ArrayIndexOutOfBoundsException("One of the indices is out " + + "of bounds."); int mid = 0; while (low <= hi) { @@ -3062,4 +3331,701 @@ public class Arrays return array; } } + + /** + * Returns a copy of the supplied array, truncating or padding as + * necessary with <code>false</code> to obtain the specified length. + * Indices that are valid for both arrays will return the same value. + * Indices that only exist in the returned array (due to the new length + * being greater than the original length) will return <code>false</code>. + * This is equivalent to calling + * <code>copyOfRange(original, 0, newLength)</code>. + * + * @param original the original array to be copied. + * @param newLength the length of the returned array. + * @return a copy of the original array, truncated or padded with + * <code>false</code> to obtain the required length. + * @throws NegativeArraySizeException if <code>newLength</code> is negative. + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOfRange(boolean[],int,int) + */ + public static boolean[] copyOf(boolean[] original, int newLength) + { + if (newLength < 0) + throw new NegativeArraySizeException("The array size is negative."); + return copyOfRange(original, 0, newLength); + } + + /** + * Copies the specified range of the supplied array to a new + * array, padding as necessary with <code>false</code> + * if <code>to</code> is greater than the length of the original + * array. <code>from</code> must be in the range zero to + * <code>original.length</code> and can not be greater than + * <code>to</code>. The initial element of the + * returned array will be equal to <code>original[from]</code>, + * except where <code>from</code> is equal to <code>to</code> + * (where a zero-length array will be returned) or <code> + * <code>from</code> is equal to <code>original.length</code> + * (where an array padded with <code>false</code> will be + * returned). The returned array is always of length + * <code>to - from</code>. + * + * @param original the array from which to copy. + * @param from the initial index of the range, inclusive. + * @param to the final index of the range, exclusive. + * @return a copy of the specified range, with padding to + * obtain the required length. + * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code> + * or <code>from > original.length</code> + * @throws IllegalArgumentException if <code>from > to</code> + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOf(boolean[],int) + */ + public static boolean[] copyOfRange(boolean[] original, int from, int to) + { + if (from > to) + throw new IllegalArgumentException("The initial index is after " + + "the final index."); + boolean[] newArray = new boolean[to - from]; + if (to > original.length) + { + System.arraycopy(original, from, newArray, 0, + original.length - from); + fill(newArray, original.length, newArray.length, false); + } + else + System.arraycopy(original, from, newArray, 0, to - from); + return newArray; + } + + /** + * Returns a copy of the supplied array, truncating or padding as + * necessary with <code>(byte)0</code> to obtain the specified length. + * Indices that are valid for both arrays will return the same value. + * Indices that only exist in the returned array (due to the new length + * being greater than the original length) will return <code>(byte)0</code>. + * This is equivalent to calling + * <code>copyOfRange(original, 0, newLength)</code>. + * + * @param original the original array to be copied. + * @param newLength the length of the returned array. + * @return a copy of the original array, truncated or padded with + * <code>(byte)0</code> to obtain the required length. + * @throws NegativeArraySizeException if <code>newLength</code> is negative. + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOfRange(byte[],int,int) + */ + public static byte[] copyOf(byte[] original, int newLength) + { + if (newLength < 0) + throw new NegativeArraySizeException("The array size is negative."); + return copyOfRange(original, 0, newLength); + } + + /** + * Copies the specified range of the supplied array to a new + * array, padding as necessary with <code>(byte)0</code> + * if <code>to</code> is greater than the length of the original + * array. <code>from</code> must be in the range zero to + * <code>original.length</code> and can not be greater than + * <code>to</code>. The initial element of the + * returned array will be equal to <code>original[from]</code>, + * except where <code>from</code> is equal to <code>to</code> + * (where a zero-length array will be returned) or <code> + * <code>from</code> is equal to <code>original.length</code> + * (where an array padded with <code>(byte)0</code> will be + * returned). The returned array is always of length + * <code>to - from</code>. + * + * @param original the array from which to copy. + * @param from the initial index of the range, inclusive. + * @param to the final index of the range, exclusive. + * @return a copy of the specified range, with padding to + * obtain the required length. + * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code> + * or <code>from > original.length</code> + * @throws IllegalArgumentException if <code>from > to</code> + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOf(byte[],int) + */ + public static byte[] copyOfRange(byte[] original, int from, int to) + { + if (from > to) + throw new IllegalArgumentException("The initial index is after " + + "the final index."); + byte[] newArray = new byte[to - from]; + if (to > original.length) + { + System.arraycopy(original, from, newArray, 0, + original.length - from); + fill(newArray, original.length, newArray.length, (byte)0); + } + else + System.arraycopy(original, from, newArray, 0, to - from); + return newArray; + } + + /** + * Returns a copy of the supplied array, truncating or padding as + * necessary with <code>'\0'</code> to obtain the specified length. + * Indices that are valid for both arrays will return the same value. + * Indices that only exist in the returned array (due to the new length + * being greater than the original length) will return <code>'\0'</code>. + * This is equivalent to calling + * <code>copyOfRange(original, 0, newLength)</code>. + * + * @param original the original array to be copied. + * @param newLength the length of the returned array. + * @return a copy of the original array, truncated or padded with + * <code>'\0'</code> to obtain the required length. + * @throws NegativeArraySizeException if <code>newLength</code> is negative. + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOfRange(char[],int,int) + */ + public static char[] copyOf(char[] original, int newLength) + { + if (newLength < 0) + throw new NegativeArraySizeException("The array size is negative."); + return copyOfRange(original, 0, newLength); + } + + /** + * Copies the specified range of the supplied array to a new + * array, padding as necessary with <code>'\0'</code> + * if <code>to</code> is greater than the length of the original + * array. <code>from</code> must be in the range zero to + * <code>original.length</code> and can not be greater than + * <code>to</code>. The initial element of the + * returned array will be equal to <code>original[from]</code>, + * except where <code>from</code> is equal to <code>to</code> + * (where a zero-length array will be returned) or <code> + * <code>from</code> is equal to <code>original.length</code> + * (where an array padded with <code>'\0'</code> will be + * returned). The returned array is always of length + * <code>to - from</code>. + * + * @param original the array from which to copy. + * @param from the initial index of the range, inclusive. + * @param to the final index of the range, exclusive. + * @return a copy of the specified range, with padding to + * obtain the required length. + * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code> + * or <code>from > original.length</code> + * @throws IllegalArgumentException if <code>from > to</code> + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOf(char[],int) + */ + public static char[] copyOfRange(char[] original, int from, int to) + { + if (from > to) + throw new IllegalArgumentException("The initial index is after " + + "the final index."); + char[] newArray = new char[to - from]; + if (to > original.length) + { + System.arraycopy(original, from, newArray, 0, + original.length - from); + fill(newArray, original.length, newArray.length, '\0'); + } + else + System.arraycopy(original, from, newArray, 0, to - from); + return newArray; + } + + /** + * Returns a copy of the supplied array, truncating or padding as + * necessary with <code>0d</code> to obtain the specified length. + * Indices that are valid for both arrays will return the same value. + * Indices that only exist in the returned array (due to the new length + * being greater than the original length) will return <code>0d</code>. + * This is equivalent to calling + * <code>copyOfRange(original, 0, newLength)</code>. + * + * @param original the original array to be copied. + * @param newLength the length of the returned array. + * @return a copy of the original array, truncated or padded with + * <code>0d</code> to obtain the required length. + * @throws NegativeArraySizeException if <code>newLength</code> is negative. + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOfRange(double[],int,int) + */ + public static double[] copyOf(double[] original, int newLength) + { + if (newLength < 0) + throw new NegativeArraySizeException("The array size is negative."); + return copyOfRange(original, 0, newLength); + } + + /** + * Copies the specified range of the supplied array to a new + * array, padding as necessary with <code>0d</code> + * if <code>to</code> is greater than the length of the original + * array. <code>from</code> must be in the range zero to + * <code>original.length</code> and can not be greater than + * <code>to</code>. The initial element of the + * returned array will be equal to <code>original[from]</code>, + * except where <code>from</code> is equal to <code>to</code> + * (where a zero-length array will be returned) or <code> + * <code>from</code> is equal to <code>original.length</code> + * (where an array padded with <code>0d</code> will be + * returned). The returned array is always of length + * <code>to - from</code>. + * + * @param original the array from which to copy. + * @param from the initial index of the range, inclusive. + * @param to the final index of the range, exclusive. + * @return a copy of the specified range, with padding to + * obtain the required length. + * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code> + * or <code>from > original.length</code> + * @throws IllegalArgumentException if <code>from > to</code> + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOf(double[],int) + */ + public static double[] copyOfRange(double[] original, int from, int to) + { + if (from > to) + throw new IllegalArgumentException("The initial index is after " + + "the final index."); + double[] newArray = new double[to - from]; + if (to > original.length) + { + System.arraycopy(original, from, newArray, 0, + original.length - from); + fill(newArray, original.length, newArray.length, 0d); + } + else + System.arraycopy(original, from, newArray, 0, to - from); + return newArray; + } + + /** + * Returns a copy of the supplied array, truncating or padding as + * necessary with <code>0f</code> to obtain the specified length. + * Indices that are valid for both arrays will return the same value. + * Indices that only exist in the returned array (due to the new length + * being greater than the original length) will return <code>0f</code>. + * This is equivalent to calling + * <code>copyOfRange(original, 0, newLength)</code>. + * + * @param original the original array to be copied. + * @param newLength the length of the returned array. + * @return a copy of the original array, truncated or padded with + * <code>0f</code> to obtain the required length. + * @throws NegativeArraySizeException if <code>newLength</code> is negative. + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOfRange(float[],int,int) + */ + public static float[] copyOf(float[] original, int newLength) + { + if (newLength < 0) + throw new NegativeArraySizeException("The array size is negative."); + return copyOfRange(original, 0, newLength); + } + + /** + * Copies the specified range of the supplied array to a new + * array, padding as necessary with <code>0f</code> + * if <code>to</code> is greater than the length of the original + * array. <code>from</code> must be in the range zero to + * <code>original.length</code> and can not be greater than + * <code>to</code>. The initial element of the + * returned array will be equal to <code>original[from]</code>, + * except where <code>from</code> is equal to <code>to</code> + * (where a zero-length array will be returned) or <code> + * <code>from</code> is equal to <code>original.length</code> + * (where an array padded with <code>0f</code> will be + * returned). The returned array is always of length + * <code>to - from</code>. + * + * @param original the array from which to copy. + * @param from the initial index of the range, inclusive. + * @param to the final index of the range, exclusive. + * @return a copy of the specified range, with padding to + * obtain the required length. + * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code> + * or <code>from > original.length</code> + * @throws IllegalArgumentException if <code>from > to</code> + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOf(float[],int) + */ + public static float[] copyOfRange(float[] original, int from, int to) + { + if (from > to) + throw new IllegalArgumentException("The initial index is after " + + "the final index."); + float[] newArray = new float[to - from]; + if (to > original.length) + { + System.arraycopy(original, from, newArray, 0, + original.length - from); + fill(newArray, original.length, newArray.length, 0f); + } + else + System.arraycopy(original, from, newArray, 0, to - from); + return newArray; + } + + /** + * Returns a copy of the supplied array, truncating or padding as + * necessary with <code>0</code> to obtain the specified length. + * Indices that are valid for both arrays will return the same value. + * Indices that only exist in the returned array (due to the new length + * being greater than the original length) will return <code>0</code>. + * This is equivalent to calling + * <code>copyOfRange(original, 0, newLength)</code>. + * + * @param original the original array to be copied. + * @param newLength the length of the returned array. + * @return a copy of the original array, truncated or padded with + * <code>0</code> to obtain the required length. + * @throws NegativeArraySizeException if <code>newLength</code> is negative. + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOfRange(int[],int,int) + */ + public static int[] copyOf(int[] original, int newLength) + { + if (newLength < 0) + throw new NegativeArraySizeException("The array size is negative."); + return copyOfRange(original, 0, newLength); + } + + /** + * Copies the specified range of the supplied array to a new + * array, padding as necessary with <code>0</code> + * if <code>to</code> is greater than the length of the original + * array. <code>from</code> must be in the range zero to + * <code>original.length</code> and can not be greater than + * <code>to</code>. The initial element of the + * returned array will be equal to <code>original[from]</code>, + * except where <code>from</code> is equal to <code>to</code> + * (where a zero-length array will be returned) or <code> + * <code>from</code> is equal to <code>original.length</code> + * (where an array padded with <code>0</code> will be + * returned). The returned array is always of length + * <code>to - from</code>. + * + * @param original the array from which to copy. + * @param from the initial index of the range, inclusive. + * @param to the final index of the range, exclusive. + * @return a copy of the specified range, with padding to + * obtain the required length. + * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code> + * or <code>from > original.length</code> + * @throws IllegalArgumentException if <code>from > to</code> + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOf(int[],int) + */ + public static int[] copyOfRange(int[] original, int from, int to) + { + if (from > to) + throw new IllegalArgumentException("The initial index is after " + + "the final index."); + int[] newArray = new int[to - from]; + if (to > original.length) + { + System.arraycopy(original, from, newArray, 0, + original.length - from); + fill(newArray, original.length, newArray.length, 0); + } + else + System.arraycopy(original, from, newArray, 0, to - from); + return newArray; + } + + /** + * Returns a copy of the supplied array, truncating or padding as + * necessary with <code>0L</code> to obtain the specified length. + * Indices that are valid for both arrays will return the same value. + * Indices that only exist in the returned array (due to the new length + * being greater than the original length) will return <code>0L</code>. + * This is equivalent to calling + * <code>copyOfRange(original, 0, newLength)</code>. + * + * @param original the original array to be copied. + * @param newLength the length of the returned array. + * @return a copy of the original array, truncated or padded with + * <code>0L</code> to obtain the required length. + * @throws NegativeArraySizeException if <code>newLength</code> is negative. + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOfRange(long[],int,int) + */ + public static long[] copyOf(long[] original, int newLength) + { + if (newLength < 0) + throw new NegativeArraySizeException("The array size is negative."); + return copyOfRange(original, 0, newLength); + } + + /** + * Copies the specified range of the supplied array to a new + * array, padding as necessary with <code>0L</code> + * if <code>to</code> is greater than the length of the original + * array. <code>from</code> must be in the range zero to + * <code>original.length</code> and can not be greater than + * <code>to</code>. The initial element of the + * returned array will be equal to <code>original[from]</code>, + * except where <code>from</code> is equal to <code>to</code> + * (where a zero-length array will be returned) or <code> + * <code>from</code> is equal to <code>original.length</code> + * (where an array padded with <code>0L</code> will be + * returned). The returned array is always of length + * <code>to - from</code>. + * + * @param original the array from which to copy. + * @param from the initial index of the range, inclusive. + * @param to the final index of the range, exclusive. + * @return a copy of the specified range, with padding to + * obtain the required length. + * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code> + * or <code>from > original.length</code> + * @throws IllegalArgumentException if <code>from > to</code> + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOf(long[],int) + */ + public static long[] copyOfRange(long[] original, int from, int to) + { + if (from > to) + throw new IllegalArgumentException("The initial index is after " + + "the final index."); + long[] newArray = new long[to - from]; + if (to > original.length) + { + System.arraycopy(original, from, newArray, 0, + original.length - from); + fill(newArray, original.length, newArray.length, 0L); + } + else + System.arraycopy(original, from, newArray, 0, to - from); + return newArray; + } + + /** + * Returns a copy of the supplied array, truncating or padding as + * necessary with <code>(short)0</code> to obtain the specified length. + * Indices that are valid for both arrays will return the same value. + * Indices that only exist in the returned array (due to the new length + * being greater than the original length) will return <code>(short)0</code>. + * This is equivalent to calling + * <code>copyOfRange(original, 0, newLength)</code>. + * + * @param original the original array to be copied. + * @param newLength the length of the returned array. + * @return a copy of the original array, truncated or padded with + * <code>(short)0</code> to obtain the required length. + * @throws NegativeArraySizeException if <code>newLength</code> is negative. + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOfRange(short[],int,int) + */ + public static short[] copyOf(short[] original, int newLength) + { + if (newLength < 0) + throw new NegativeArraySizeException("The array size is negative."); + return copyOfRange(original, 0, newLength); + } + + /** + * Copies the specified range of the supplied array to a new + * array, padding as necessary with <code>(short)0</code> + * if <code>to</code> is greater than the length of the original + * array. <code>from</code> must be in the range zero to + * <code>original.length</code> and can not be greater than + * <code>to</code>. The initial element of the + * returned array will be equal to <code>original[from]</code>, + * except where <code>from</code> is equal to <code>to</code> + * (where a zero-length array will be returned) or <code> + * <code>from</code> is equal to <code>original.length</code> + * (where an array padded with <code>(short)0</code> will be + * returned). The returned array is always of length + * <code>to - from</code>. + * + * @param original the array from which to copy. + * @param from the initial index of the range, inclusive. + * @param to the final index of the range, exclusive. + * @return a copy of the specified range, with padding to + * obtain the required length. + * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code> + * or <code>from > original.length</code> + * @throws IllegalArgumentException if <code>from > to</code> + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOf(short[],int) + */ + public static short[] copyOfRange(short[] original, int from, int to) + { + if (from > to) + throw new IllegalArgumentException("The initial index is after " + + "the final index."); + short[] newArray = new short[to - from]; + if (to > original.length) + { + System.arraycopy(original, from, newArray, 0, + original.length - from); + fill(newArray, original.length, newArray.length, (short)0); + } + else + System.arraycopy(original, from, newArray, 0, to - from); + return newArray; + } + + /** + * Returns a copy of the supplied array, truncating or padding as + * necessary with <code>null</code> to obtain the specified length. + * Indices that are valid for both arrays will return the same value. + * Indices that only exist in the returned array (due to the new length + * being greater than the original length) will return <code>null</code>. + * This is equivalent to calling + * <code>copyOfRange(original, 0, newLength)</code>. + * + * @param original the original array to be copied. + * @param newLength the length of the returned array. + * @return a copy of the original array, truncated or padded with + * <code>null</code> to obtain the required length. + * @throws NegativeArraySizeException if <code>newLength</code> is negative. + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOfRange(T[],int,int) + */ + public static <T> T[] copyOf(T[] original, int newLength) + { + if (newLength < 0) + throw new NegativeArraySizeException("The array size is negative."); + return copyOfRange(original, 0, newLength); + } + + /** + * Copies the specified range of the supplied array to a new + * array, padding as necessary with <code>null</code> + * if <code>to</code> is greater than the length of the original + * array. <code>from</code> must be in the range zero to + * <code>original.length</code> and can not be greater than + * <code>to</code>. The initial element of the + * returned array will be equal to <code>original[from]</code>, + * except where <code>from</code> is equal to <code>to</code> + * (where a zero-length array will be returned) or <code> + * <code>from</code> is equal to <code>original.length</code> + * (where an array padded with <code>null</code> will be + * returned). The returned array is always of length + * <code>to - from</code>. + * + * @param original the array from which to copy. + * @param from the initial index of the range, inclusive. + * @param to the final index of the range, exclusive. + * @return a copy of the specified range, with padding to + * obtain the required length. + * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code> + * or <code>from > original.length</code> + * @throws IllegalArgumentException if <code>from > to</code> + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOf(T[],int) + */ + public static <T> T[] copyOfRange(T[] original, int from, int to) + { + if (from > to) + throw new IllegalArgumentException("The initial index is after " + + "the final index."); + T[] newArray = (T[]) new Object[to - from]; + if (to > original.length) + { + System.arraycopy(original, from, newArray, 0, + original.length - from); + fill(newArray, original.length, newArray.length, null); + } + else + System.arraycopy(original, from, newArray, 0, to - from); + return newArray; + } + + /** + * Returns a copy of the supplied array, truncating or padding as + * necessary with <code>null</code> to obtain the specified length. + * Indices that are valid for both arrays will return the same value. + * Indices that only exist in the returned array (due to the new length + * being greater than the original length) will return <code>null</code>. + * This is equivalent to calling + * <code>copyOfRange(original, 0, newLength, newType)</code>. The returned + * array will be of the specified type, <code>newType</code>. + * + * @param original the original array to be copied. + * @param newLength the length of the returned array. + * @param newType the type of the returned array. + * @return a copy of the original array, truncated or padded with + * <code>null</code> to obtain the required length. + * @throws NegativeArraySizeException if <code>newLength</code> is negative. + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOfRange(U[],int,int,Class) + */ + public static <T,U> T[] copyOf(U[] original, int newLength, + Class<? extends T[]> newType) + { + if (newLength < 0) + throw new NegativeArraySizeException("The array size is negative."); + return copyOfRange(original, 0, newLength, newType); + } + + /** + * Copies the specified range of the supplied array to a new + * array, padding as necessary with <code>null</code> + * if <code>to</code> is greater than the length of the original + * array. <code>from</code> must be in the range zero to + * <code>original.length</code> and can not be greater than + * <code>to</code>. The initial element of the + * returned array will be equal to <code>original[from]</code>, + * except where <code>from</code> is equal to <code>to</code> + * (where a zero-length array will be returned) or <code> + * <code>from</code> is equal to <code>original.length</code> + * (where an array padded with <code>null</code> will be + * returned). The returned array is always of length + * <code>to - from</code> and will be of the specified type, + * <code>newType</code>. + * + * @param original the array from which to copy. + * @param from the initial index of the range, inclusive. + * @param to the final index of the range, exclusive. + * @param newType the type of the returned array. + * @return a copy of the specified range, with padding to + * obtain the required length. + * @throws ArrayIndexOutOfBoundsException if <code>from < 0</code> + * or <code>from > original.length</code> + * @throws IllegalArgumentException if <code>from > to</code> + * @throws NullPointerException if <code>original</code> is <code>null</code>. + * @since 1.6 + * @see #copyOf(T[],int) + */ + public static <T,U> T[] copyOfRange(U[] original, int from, int to, + Class<? extends T[]> newType) + { + if (from > to) + throw new IllegalArgumentException("The initial index is after " + + "the final index."); + T[] newArray = (T[]) Array.newInstance(newType.getComponentType(), + to - from); + if (to > original.length) + { + System.arraycopy(original, from, newArray, 0, + original.length - from); + fill(newArray, original.length, newArray.length, null); + } + else + System.arraycopy(original, from, newArray, 0, to - from); + return newArray; + } } diff --git a/libjava/classpath/java/util/Calendar.java b/libjava/classpath/java/util/Calendar.java index 8c46c01..2b385b1 100644 --- a/libjava/classpath/java/util/Calendar.java +++ b/libjava/classpath/java/util/Calendar.java @@ -43,9 +43,12 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; + import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.text.DateFormatSymbols; + /** * This class is an abstract base class for Calendars, which can be * used to convert between <code>Date</code> objects and a set of @@ -99,6 +102,20 @@ day_of_week + week_of_year</pre> * specific field by one, propagating overflows), or * <code>add</code>ing/substracting a fixed amount to a field. * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Jochen Hoenicke (Jochen.Hoenicke@Informatik.Uni-Oldenburg.de) + * @author Warren Levy (warrenl@cygnus.com) + * @author Jeff Sturm (jsturm@one-point.com) + * @author Tom Tromey (tromey@redhat.com) + * @author Bryce McKinlay (mckinlay@redhat.com) + * @author Ingo Proetel (proetel@aicas.com) + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Jeroen Frijters (jeroen@frijters.net) + * @author Noa Resare (noa@resare.com) + * @author Sven de Marothy (sven@physto.se) + * @author David Gilbert (david.gilbert@object-refinery.com) + * @author Olivier Jolly (olivier.jolly@pcedev.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) * @see Date * @see GregorianCalendar * @see TimeZone @@ -326,6 +343,34 @@ public abstract class Calendar public static final int PM = 1; /** + * A style specifier for {@link #getDisplayNames(int,int,Locale)} + * stating that names should be returned in both long and short variants. + * + * @since 1.6 + * @see #SHORT + * @see #LONG + */ + public static final int ALL_STYLES = 0; + + /** + * A style specifier for {@link #getDisplayName(int,int,Locale)} + * and {@link #getDisplayNames(int,int,Locale)} stating that names + * should be returned in their short variant if applicable. + * + * @since 1.6 + */ + public static final int SHORT = 1; + + /** + * A style specifier for {@link #getDisplayName(int,int,Locale)} + * and {@link #getDisplayNames(int,int,Locale)} stating that names + * should be returned in their long variant if applicable. + * + * @since 1.6 + */ + public static final int LONG = 2; + + /** * The time fields. The array is indexed by the constants YEAR to * DST_OFFSET. * @serial @@ -527,7 +572,7 @@ public abstract class Calendar * Cache of locale->calendar-class mappings. This avoids having to do a ResourceBundle * lookup for every getInstance call. */ - private static HashMap cache = new HashMap(); + private static HashMap<Locale,Class> cache = new HashMap<Locale,Class>(); /** Preset argument types for calendar-class constructor lookup. */ private static Class[] ctorArgTypes = new Class[] @@ -549,7 +594,7 @@ public abstract class Calendar */ public static synchronized Calendar getInstance(TimeZone zone, Locale locale) { - Class calendarClass = (Class) cache.get(locale); + Class calendarClass = cache.get(locale); Throwable exception = null; try @@ -1343,4 +1388,205 @@ public abstract class Calendar areFieldsSet = false; } } + + /** + * Returns a localised textual representation of the current value + * of the given field using the specified style. If there is no + * applicable textual representation (e.g. the field has a numeric + * value), then <code>null</code> is returned. If one does exist, + * then the value is obtained from {@link #get(int)} and converted + * appropriately. For example, if the <code>MONTH</code> field is + * requested, then <code>get(MONTH)</code> is called. This is then + * converted to a textual representation based on its value and + * the style requested; if the <code>LONG</code> style is requested + * and the returned value is <code>11</code> from a + * {@link GregorianCalendar} implementation, then <code>"December"</code> + * is returned. By default, a textual representation is available + * for all fields which have an applicable value obtainable from + * {@link java.text.DateFormatSymbols}. + * + * @param field the calendar field whose textual representation should + * be obtained. + * @param style the style to use; either {@link #LONG} or {@link #SHORT}. + * @param locale the locale to use for translation. + * @return the textual representation of the given field in the specified + * style, or <code>null</code> if none is applicable. + * @throws IllegalArgumentException if <code>field</code> or <code>style</code> + * or invalid, or the calendar is non-lenient + * and has invalid values. + * @throws NullPointerException if <code>locale</code> is <code>null</code>. + * @since 1.6 + */ + public String getDisplayName(int field, int style, Locale locale) + { + if (field < 0 || field >= FIELD_COUNT) + throw new IllegalArgumentException("The field value, " + field + + ", is invalid."); + if (style != SHORT && style != LONG) + throw new IllegalArgumentException("The style must be either " + + "short or long."); + if (field == YEAR || field == WEEK_OF_YEAR || + field == WEEK_OF_MONTH || field == DAY_OF_MONTH || + field == DAY_OF_YEAR || field == DAY_OF_WEEK_IN_MONTH || + field == HOUR || field == HOUR_OF_DAY || field == MINUTE || + field == SECOND || field == MILLISECOND) + return null; + + int value = get(field); + DateFormatSymbols syms = DateFormatSymbols.getInstance(locale); + if (field == ERA) + return syms.getEras()[value]; + if (field == MONTH) + if (style == LONG) + return syms.getMonths()[value]; + else + return syms.getShortMonths()[value]; + if (field == DAY_OF_WEEK) + if (style == LONG) + return syms.getWeekdays()[value]; + else + return syms.getShortWeekdays()[value]; + if (field == AM_PM) + return syms.getAmPmStrings()[value]; + if (field == ZONE_OFFSET) + if (style == LONG) + return syms.getZoneStrings()[value][1]; + else + return syms.getZoneStrings()[value][2]; + if (field == DST_OFFSET) + if (style == LONG) + return syms.getZoneStrings()[value][3]; + else + return syms.getZoneStrings()[value][4]; + + throw new InternalError("Failed to resolve field " + field + + " with style " + style + " for locale " + + locale); + } + + /** + * Returns a map linking all specified textual representations + * of the given field to their numerical values. The textual + * representations included are determined by the specified + * style and locale. For example, if the style <code>LONG</code> + * is specified and the German locale, then the map will + * contain "Montag" to {@link #MONDAY}, "Dienstag" to + * {@link #TUESDAY}, "Mittwoch" to {@link #WEDNESDAY} and + * so on. The default implementation uses the values returned + * by {@link DateFormatSymbols} so, for example, the style + * {@link #ALL_STYLES} and the field {@link #MONTH} will return + * a map filled with the values returned from + * {@link DateFormatSymbols#getMonths()} and + * {@link DateFormatSymbols#getShortMonths()}. If there are + * no textual representations for a given field (usually because + * it is purely numeric, such as the year in the + * {@link GregorianCalendar}), <code>null</code> is returned. + * + * @param field the calendar field whose textual representation should + * be obtained. + * @param style the style to use; either {@link #LONG}, {@link #SHORT} + * or {@link ALL_STYLES}. + * @param locale the locale to use for translation. + * @return a map of the textual representations of the given field in the + * specified style to their numeric values, or <code>null</code> + * if none is applicable. + * @throws IllegalArgumentException if <code>field</code> or <code>style</code> + * or invalid, or the calendar is non-lenient + * and has invalid values. + * @throws NullPointerException if <code>locale</code> is <code>null</code>. + * @since 1.6 + */ + public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) + { + if (field < 0 || field >= FIELD_COUNT) + throw new IllegalArgumentException("The field value, " + field + + ", is invalid."); + if (style != SHORT && style != LONG && style != ALL_STYLES) + throw new IllegalArgumentException("The style must be either " + + "short, long or all styles."); + if (field == YEAR || field == WEEK_OF_YEAR || + field == WEEK_OF_MONTH || field == DAY_OF_MONTH || + field == DAY_OF_YEAR || field == DAY_OF_WEEK_IN_MONTH || + field == HOUR || field == HOUR_OF_DAY || field == MINUTE || + field == SECOND || field == MILLISECOND) + return null; + + DateFormatSymbols syms = DateFormatSymbols.getInstance(locale); + Map<String,Integer> map = new HashMap<String,Integer>(); + if (field == ERA) + { + String[] eras = syms.getEras(); + for (int a = 0; a < eras.length; ++a) + map.put(eras[a], a); + return map; + } + if (field == MONTH) + { + if (style == LONG || style == ALL_STYLES) + { + String[] months = syms.getMonths(); + for (int a = 0; a < months.length; ++a) + map.put(months[a], a); + } + if (style == SHORT || style == ALL_STYLES) + { + String[] months = syms.getShortMonths(); + for (int a = 0; a < months.length; ++a) + map.put(months[a], a); + } + return map; + } + if (field == DAY_OF_WEEK) + { + if (style == LONG || style == ALL_STYLES) + { + String[] weekdays = syms.getWeekdays(); + for (int a = SUNDAY; a < weekdays.length; ++a) + map.put(weekdays[a], a); + } + if (style == SHORT || style == ALL_STYLES) + { + String[] weekdays = syms.getShortWeekdays(); + for (int a = SUNDAY; a < weekdays.length; ++a) + map.put(weekdays[a], a); + } + return map; + } + if (field == AM_PM) + { + String[] ampms = syms.getAmPmStrings(); + for (int a = 0; a < ampms.length; ++a) + map.put(ampms[a], a); + return map; + } + if (field == ZONE_OFFSET) + { + String[][] zones = syms.getZoneStrings(); + for (int a = 0; a < zones.length; ++a) + { + if (style == LONG || style == ALL_STYLES) + map.put(zones[a][1], a); + if (style == SHORT || style == ALL_STYLES) + map.put(zones[a][2], a); + } + return map; + } + if (field == DST_OFFSET) + { + String[][] zones = syms.getZoneStrings(); + for (int a = 0; a < zones.length; ++a) + { + if (style == LONG || style == ALL_STYLES) + map.put(zones[a][3], a); + if (style == SHORT || style == ALL_STYLES) + map.put(zones[a][4], a); + } + return map; + } + + throw new InternalError("Failed to resolve field " + field + + " with style " + style + " for locale " + + locale); + } + } diff --git a/libjava/classpath/java/util/Collections.java b/libjava/classpath/java/util/Collections.java index 77ff6ed..fd802fe 100644 --- a/libjava/classpath/java/util/Collections.java +++ b/libjava/classpath/java/util/Collections.java @@ -706,14 +706,16 @@ public class Collections { if (!forward) itr.next(); // Changing direction first. - for ( ; i != pos; i++, o = itr.next()); + for ( ; i != pos; i++, o = itr.next()) + ; forward = true; } else { if (forward) itr.previous(); // Changing direction first. - for ( ; i != pos; i--, o = itr.previous()); + for ( ; i != pos; i--, o = itr.previous()) + ; forward = false; } final int d = compare(o, key, c); @@ -1460,8 +1462,10 @@ public class Collections public static int frequency (Collection<?> c, Object o) { int result = 0; - for (Object v : c) + final Iterator<?> it = c.iterator(); + while (it.hasNext()) { + Object v = it.next(); if (AbstractCollection.equals(o, v)) ++result; } @@ -1522,8 +1526,9 @@ public class Collections public static boolean disjoint(Collection<?> c1, Collection<?> c2) { Collection<Object> oc1 = (Collection<Object>) c1; - for (Object o : oc1) - if (c2.contains(o)) + final Iterator<Object> it = oc1.iterator(); + while (it.hasNext()) + if (c2.contains(it.next())) return false; return true; } @@ -5113,7 +5118,7 @@ public class Collections // The array returned is an array of UnmodifiableMapEntry instead of // Map.Entry - public Map.Entry<K,V>[] toArray() + public Object[] toArray() { Object[] mapEntryResult = super.toArray(); UnmodifiableMapEntry<K,V> result[] = null; @@ -5127,7 +5132,7 @@ public class Collections } return result; } - + // The array returned is an array of UnmodifiableMapEntry instead of // Map.Entry public <S> S[] toArray(S[] array) @@ -5825,8 +5830,10 @@ public class Collections public boolean addAll(Collection<? extends E> coll) { Collection<E> typedColl = (Collection<E>) c; - for (E element : typedColl) + final Iterator<E> it = typedColl.iterator(); + while (it.hasNext()) { + final E element = it.next(); if (!type.isInstance(element)) throw new ClassCastException("A member of the collection is not of the correct type."); } @@ -6167,9 +6174,10 @@ public class Collections public boolean addAll(int index, Collection<? extends E> coll) { Collection<E> typedColl = (Collection<E>) coll; - for (E element : typedColl) + final Iterator<E> it = typedColl.iterator(); + while (it.hasNext()) { - if (!type.isInstance(element)) + if (!type.isInstance(it.next())) throw new ClassCastException("A member of the collection is not of the correct type."); } return list.addAll(index, coll); @@ -6870,8 +6878,10 @@ public class Collections public void putAll(Map<? extends K, ? extends V> map) { Map<K,V> typedMap = (Map<K,V>) map; - for (Map.Entry<K,V> entry : typedMap.entrySet()) + final Iterator<Map.Entry<K,V>> it = typedMap.entrySet().iterator(); + while (it.hasNext()) { + final Map.Entry<K,V> entry = it.next(); if (!keyType.isInstance(entry.getKey())) throw new ClassCastException("A key is of the wrong type."); if (!valueType.isInstance(entry.getValue())) @@ -7423,4 +7433,189 @@ public class Collections } } // class CheckedSortedSet + /** + * Returns a view of a {@link Deque} as a stack or LIFO (Last-In-First-Out) + * {@link Queue}. Each call to the LIFO queue corresponds to one + * equivalent method call to the underlying deque, with the exception + * of {@link Collection#addAll(Collection)}, which is emulated by a series + * of {@link Deque#push(E)} calls. + * + * @param deque the deque to convert to a LIFO queue. + * @return a LIFO queue. + * @since 1.6 + */ + public static <T> Queue<T> asLifoQueue(Deque<T> deque) + { + return new LIFOQueue<T>(deque); + } + + /** + * Returns a set backed by the supplied map. The resulting set + * has the same performance, concurrency and ordering characteristics + * as the original map. The supplied map must be empty and should not + * be used after the set is created. Each call to the set corresponds + * to one equivalent method call to the underlying map, with the exception + * of {@link Set#addAll(Collection)} which is emulated by a series of + * calls to <code>put</code>. + * + * @param map the map to convert to a set. + * @return a set backed by the supplied map. + * @throws IllegalArgumentException if the map is not empty. + * @since 1.6 + */ + public static <E> Set<E> newSetFromMap(Map<E,Boolean> map) + { + return new MapSet<E>(map); + } + + /** + * The implementation of {@link #asLIFOQueue(Deque)}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ + private static class LIFOQueue<T> + extends AbstractQueue<T> + { + + /** + * The backing deque. + */ + private Deque<T> deque; + + /** + * Constructs a new {@link LIFOQueue} with the specified + * backing {@link Deque}. + * + * @param deque the backing deque. + */ + public LIFOQueue(Deque<T> deque) + { + this.deque = deque; + } + + public boolean add(T e) + { + return deque.offerFirst(e); + } + + public boolean addAll(Collection<? extends T> c) + { + boolean result = false; + final Iterator<? extends T> it = c.iterator(); + while (it.hasNext()) + result |= deque.offerFirst(it.next()); + return result; + } + + public void clear() + { + deque.clear(); + } + + public boolean isEmpty() + { + return deque.isEmpty(); + } + + public Iterator<T> iterator() + { + return deque.iterator(); + } + + public boolean offer(T e) + { + return deque.offerFirst(e); + } + + public T peek() + { + return deque.peek(); + } + + public T poll() + { + return deque.poll(); + } + + public int size() + { + return deque.size(); + } + } // class LIFOQueue + + /** + * The implementation of {@link #newSetFromMap(Map)}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ + private static class MapSet<E> + extends AbstractSet<E> + { + + /** + * The backing map. + */ + private Map<E,Boolean> map; + + /** + * Constructs a new {@link MapSet} using the specified + * backing {@link Map}. + * + * @param map the backing map. + * @throws IllegalArgumentException if the map is not empty. + */ + public MapSet(Map<E,Boolean> map) + { + if (!map.isEmpty()) + throw new IllegalArgumentException("The map must be empty."); + this.map = map; + } + + public boolean add(E e) + { + return map.put(e, true) == null; + } + + public boolean addAll(Collection<? extends E> c) + { + boolean result = false; + final Iterator<? extends E> it = c.iterator(); + while (it.hasNext()) + result |= (map.put(it.next(), true) == null); + return result; + } + + public void clear() + { + map.clear(); + } + + public boolean contains(Object o) + { + return map.containsKey(o); + } + + public boolean isEmpty() + { + return map.isEmpty(); + } + + public Iterator<E> iterator() + { + return map.keySet().iterator(); + } + + public boolean remove(Object o) + { + return map.remove(o) != null; + } + + public int size() + { + return map.size(); + } + } // class MapSet + } // class Collections diff --git a/libjava/classpath/java/util/Currency.java b/libjava/classpath/java/util/Currency.java index 32ea753..a0933ec 100644 --- a/libjava/classpath/java/util/Currency.java +++ b/libjava/classpath/java/util/Currency.java @@ -44,6 +44,8 @@ import java.io.IOException; import java.io.ObjectStreamException; import java.io.Serializable; +import java.util.spi.CurrencyNameProvider; + /** * Representation of a currency for a particular locale. Each currency * is identified by its ISO 4217 code, and only one instance of this @@ -402,8 +404,35 @@ public final class Currency */ public String getSymbol(Locale locale) { - return LocaleHelper.getLocalizedString(locale, currencyCode, - "currenciesSymbol", false, true); + String property = "currenciesSymbol." + currencyCode; + try + { + return ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + locale).getString(property); + } + catch (MissingResourceException exception) + { + /* This means runtime support for the locale + * is not available, so we check providers. */ + } + for (CurrencyNameProvider p : + ServiceLoader.load(CurrencyNameProvider.class)) + { + for (Locale loc : p.getAvailableLocales()) + { + if (loc.equals(locale)) + { + String localizedString = p.getSymbol(currencyCode, + locale); + if (localizedString != null) + return localizedString; + break; + } + } + } + if (locale.equals(Locale.ROOT)) // Base case + return currencyCode; + return getSymbol(LocaleHelper.getFallbackLocale(locale)); } /** diff --git a/libjava/classpath/java/util/Date.java b/libjava/classpath/java/util/Date.java index f481753..1ad128e 100644 --- a/libjava/classpath/java/util/Date.java +++ b/libjava/classpath/java/util/Date.java @@ -856,7 +856,7 @@ public class Date hour += 12; } else if (parseDayOfWeek(tok)) - ; // Ignore it; throw the token away. + { /* Ignore it; throw the token away. */ } else if (tok.equals("UT") || tok.equals("UTC") || tok.equals("GMT")) localTimezone = false; else if (tok.startsWith("UT") || tok.startsWith("GMT")) diff --git a/libjava/classpath/java/util/GregorianCalendar.java b/libjava/classpath/java/util/GregorianCalendar.java index 83ac00e..6eb7ce8 100644 --- a/libjava/classpath/java/util/GregorianCalendar.java +++ b/libjava/classpath/java/util/GregorianCalendar.java @@ -1,5 +1,5 @@ /* java.util.GregorianCalendar - Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004 + Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -223,7 +223,6 @@ public class GregorianCalendar extends Calendar { this(zone, locale, false); setTimeInMillis(System.currentTimeMillis()); - complete(); } /** @@ -842,13 +841,24 @@ public class GregorianCalendar extends Calendar // which day of the week are we (0..6), relative to getFirstDayOfWeek int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7; - fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] - relativeWeekday + 12) / 7; + // which day of the week is the first of this month? + // nb 35 is the smallest multiple of 7 that ensures that + // the left hand side of the modulo operator is positive. + int relativeWeekdayOfFirst = (relativeWeekday - fields[DAY_OF_MONTH] + + 1 + 35) % 7; + + // which week of the month is the first of this month in? + int minDays = getMinimalDaysInFirstWeek(); + int weekOfFirst = ((7 - relativeWeekdayOfFirst) >= minDays) ? 1 : 0; + + // which week of the month is this day in? + fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] + + relativeWeekdayOfFirst - 1) / 7 + weekOfFirst; int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7; // Do the Correction: getMinimalDaysInFirstWeek() is always in the // first week. - int minDays = getMinimalDaysInFirstWeek(); int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays) - getFirstDayOfWeek()) % 7; if (minDays - firstWeekday < 1) diff --git a/libjava/classpath/java/util/HashMap.java b/libjava/classpath/java/util/HashMap.java index 92022a7..eca3ad6 100644 --- a/libjava/classpath/java/util/HashMap.java +++ b/libjava/classpath/java/util/HashMap.java @@ -380,11 +380,11 @@ public class HashMap<K, V> extends AbstractMap<K, V> */ public void putAll(Map<? extends K, ? extends V> m) { - Map<K,V> addMap; - - addMap = (Map<K,V>) m; - for (Map.Entry<K,V> e : addMap.entrySet()) + final Map<K,V> addMap = (Map<K,V>) m; + final Iterator<Map.Entry<K,V>> it = addMap.entrySet().iterator(); + while (it.hasNext()) { + final Map.Entry<K,V> e = it.next(); // Optimize in case the Entry is one of our own. if (e instanceof AbstractMap.SimpleEntry) { @@ -710,12 +710,12 @@ public class HashMap<K, V> extends AbstractMap<K, V> */ void putAllInternal(Map<? extends K, ? extends V> m) { - Map<K,V> addMap; - - addMap = (Map<K,V>) m; + final Map<K,V> addMap = (Map<K,V>) m; + final Iterator<Map.Entry<K,V>> it = addMap.entrySet().iterator(); size = 0; - for (Map.Entry<K,V> e : addMap.entrySet()) + while (it.hasNext()) { + final Map.Entry<K,V> e = it.next(); size++; K key = e.getKey(); int idx = hash(key); diff --git a/libjava/classpath/java/util/Hashtable.java b/libjava/classpath/java/util/Hashtable.java index 2e265a4..a8567463 100644 --- a/libjava/classpath/java/util/Hashtable.java +++ b/libjava/classpath/java/util/Hashtable.java @@ -505,12 +505,11 @@ public class Hashtable<K, V> extends Dictionary<K, V> */ public synchronized void putAll(Map<? extends K, ? extends V> m) { - Map<K,V> addMap; - - addMap = (Map<K,V>) m; - - for (Map.Entry<K,V> e : addMap.entrySet()) + final Map<K,V> addMap = (Map<K,V>) m; + final Iterator<Map.Entry<K,V>> it = addMap.entrySet().iterator(); + while (it.hasNext()) { + final Map.Entry<K,V> e = it.next(); // Optimize in case the Entry is one of our own. if (e instanceof AbstractMap.SimpleEntry) { @@ -857,13 +856,12 @@ public class Hashtable<K, V> extends Dictionary<K, V> */ void putAllInternal(Map<? extends K, ? extends V> m) { - Map<K,V> addMap; - - addMap = (Map<K,V>) m; + final Map<K,V> addMap = (Map<K,V>) m; + final Iterator<Map.Entry<K,V>> it = addMap.entrySet().iterator(); size = 0; - - for (Map.Entry<K,V> e : addMap.entrySet()) + while (it.hasNext()) { + final Map.Entry<K,V> e = it.next(); size++; K key = e.getKey(); int idx = hash(key); diff --git a/libjava/classpath/java/util/LinkedList.java b/libjava/classpath/java/util/LinkedList.java index 2d78573..3f8b2ad 100644 --- a/libjava/classpath/java/util/LinkedList.java +++ b/libjava/classpath/java/util/LinkedList.java @@ -1,5 +1,5 @@ /* LinkedList.java -- Linked list implementation of the List interface - 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. @@ -64,15 +64,17 @@ import java.lang.reflect.Array; * @author Original author unknown * @author Bryce McKinlay * @author Eric Blake (ebb9@email.byu.edu) + * @author Tom Tromey (tromey@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) * @see List * @see ArrayList * @see Vector * @see Collections#synchronizedList(List) * @since 1.2 - * @status missing javadoc, but complete to 1.4 + * @status Complete to 1.6 */ public class LinkedList<T> extends AbstractSequentialList<T> - implements List<T>, Queue<T>, Cloneable, Serializable + implements List<T>, Deque<T>, Cloneable, Serializable { /** * Compatible with JDK 1.2. @@ -708,6 +710,10 @@ public class LinkedList<T> extends AbstractSequentialList<T> } /** + * Adds the specified element to the end of the list. + * + * @param value the value to add. + * @return true. * @since 1.5 */ public boolean offer(T value) @@ -716,6 +722,11 @@ public class LinkedList<T> extends AbstractSequentialList<T> } /** + * Returns the first element of the list without removing + * it. + * + * @return the first element of the list. + * @throws NoSuchElementException if the list is empty. * @since 1.5 */ public T element() @@ -724,6 +735,11 @@ public class LinkedList<T> extends AbstractSequentialList<T> } /** + * Returns the first element of the list without removing + * it. + * + * @return the first element of the list, or <code>null</code> + * if the list is empty. * @since 1.5 */ public T peek() @@ -734,6 +750,10 @@ public class LinkedList<T> extends AbstractSequentialList<T> } /** + * Removes and returns the first element of the list. + * + * @return the first element of the list, or <code>null</code> + * if the list is empty. * @since 1.5 */ public T poll() @@ -744,6 +764,10 @@ public class LinkedList<T> extends AbstractSequentialList<T> } /** + * Removes and returns the first element of the list. + * + * @return the first element of the list. + * @throws NoSuchElementException if the list is empty. * @since 1.5 */ public T remove() @@ -992,4 +1016,245 @@ public class LinkedList<T> extends AbstractSequentialList<T> lastReturned.data = o; } } // class LinkedListItr + + /** + * Obtain an Iterator over this list in reverse sequential order. + * + * @return an Iterator over the elements of the list in + * reverse order. + * @since 1.6 + */ + public Iterator<T> descendingIterator() + { + return new Iterator<T>() + { + /** Number of modifications we know about. */ + private int knownMod = modCount; + + /** Entry that will be returned by next(). */ + private Entry<T> next = last; + + /** Entry that will be affected by remove() or set(). */ + private Entry<T> lastReturned; + + /** Index of `next'. */ + private int position = size() - 1; + + // This will get inlined, since it is private. + /** + * Checks for modifications made to the list from + * elsewhere while iteration is in progress. + * + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + private void checkMod() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + } + + /** + * Tests to see if there are any more objects to + * return. + * + * @return true if the start of the list has not yet been + * reached. + */ + public boolean hasNext() + { + return next != null; + } + + /** + * Retrieves the next object from the list. + * + * @return The next object. + * @throws NoSuchElementException if there are + * no more objects to retrieve. + * @throws ConcurrentModificationException if the + * list has been modified elsewhere. + */ + public T next() + { + checkMod(); + if (next == null) + throw new NoSuchElementException(); + --position; + lastReturned = next; + next = lastReturned.previous; + return lastReturned.data; + } + + /** + * Removes the last object retrieved by <code>next()</code> + * from the list, if the list supports object removal. + * + * @throws ConcurrentModificationException if the list + * has been modified elsewhere. + * @throws IllegalStateException if the iterator is positioned + * before the start of the list or the last object has already + * been removed. + */ + public void remove() + { + checkMod(); + if (lastReturned == null) + throw new IllegalStateException(); + removeEntry(lastReturned); + lastReturned = null; + ++knownMod; + } + }; + } + + /** + * Inserts the specified element at the front of the list. + * + * @param value the element to insert. + * @return true. + * @since 1.6 + */ + public boolean offerFirst(T value) + { + addFirst(value); + return true; + } + + /** + * Inserts the specified element at the end of the list. + * + * @param value the element to insert. + * @return true. + * @since 1.6 + */ + public boolean offerLast(T value) + { + return add(value); + } + + /** + * Returns the first element of the list without removing + * it. + * + * @return the first element of the list, or <code>null</code> + * if the list is empty. + * @since 1.6 + */ + public T peekFirst() + { + return peek(); + } + + /** + * Returns the last element of the list without removing + * it. + * + * @return the last element of the list, or <code>null</code> + * if the list is empty. + * @since 1.6 + */ + public T peekLast() + { + if (size == 0) + return null; + return getLast(); + } + + /** + * Removes and returns the first element of the list. + * + * @return the first element of the list, or <code>null</code> + * if the list is empty. + * @since 1.6 + */ + public T pollFirst() + { + return poll(); + } + + /** + * Removes and returns the last element of the list. + * + * @return the last element of the list, or <code>null</code> + * if the list is empty. + * @since 1.6 + */ + public T pollLast() + { + if (size == 0) + return null; + return removeLast(); + } + + /** + * Pops an element from the stack by removing and returning + * the first element in the list. This is equivalent to + * calling {@link #removeFirst()}. + * + * @return the top of the stack, which is the first element + * of the list. + * @throws NoSuchElementException if the list is empty. + * @since 1.6 + * @see #removeFirst() + */ + public T pop() + { + return removeFirst(); + } + + /** + * Pushes an element on to the stack by adding it to the + * front of the list. This is equivalent to calling + * {@link #addFirst(T)}. + * + * @param value the element to push on to the stack. + * @throws NoSuchElementException if the list is empty. + * @since 1.6 + * @see #addFirst(T) + */ + public void push(T value) + { + addFirst(value); + } + + /** + * Removes the first occurrence of the specified element + * from the list, when traversing the list from head to + * tail. The list is unchanged if the element is not found. + * This is equivalent to calling {@link #remove(Object)}. + * + * @param o the element to remove. + * @return true if an instance of the object was removed. + * @since 1.6 + */ + public boolean removeFirstOccurrence(Object o) + { + return remove(o); + } + + /** + * Removes the last occurrence of the specified element + * from the list, when traversing the list from head to + * tail. The list is unchanged if the element is not found. + * + * @param o the element to remove. + * @return true if an instance of the object was removed. + * @since 1.6 + */ + public boolean removeLastOccurrence(Object o) + { + Entry<T> e = last; + while (e != null) + { + if (equals(o, e.data)) + { + removeEntry(e); + return true; + } + e = e.previous; + } + return false; + } + } diff --git a/libjava/classpath/java/util/Locale.java b/libjava/classpath/java/util/Locale.java index 4c91eeb..846ae7b 100644 --- a/libjava/classpath/java/util/Locale.java +++ b/libjava/classpath/java/util/Locale.java @@ -46,6 +46,8 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; +import java.util.spi.LocaleNameProvider; + /** * Locales represent a specific country and culture. Classes which can be * passed a Locale object tailor their information for a given locale. For @@ -161,6 +163,11 @@ public final class Locale implements Serializable, Cloneable /** Locale which represents the French speaking portion of Canada. */ public static final Locale CANADA_FRENCH = getLocale("fr", "CA"); + /** The root locale, used as the base case in lookups by + * locale-sensitive operations. + */ + public static final Locale ROOT = new Locale("","",""); + /** * Compatible with JDK 1.1+. */ @@ -674,6 +681,8 @@ public final class Locale implements Serializable, Cloneable */ public String getDisplayLanguage(Locale inLocale) { + if (language.isEmpty()) + return ""; try { ResourceBundle res = @@ -685,8 +694,27 @@ public final class Locale implements Serializable, Cloneable } catch (MissingResourceException e) { - return language; + /* This means runtime support for the locale + * is not available, so we check providers. */ } + for (LocaleNameProvider p : + ServiceLoader.load(LocaleNameProvider.class)) + { + for (Locale loc : p.getAvailableLocales()) + { + if (loc.equals(inLocale)) + { + String locLang = p.getDisplayLanguage(language, + inLocale); + if (locLang != null) + return locLang; + break; + } + } + } + if (inLocale.equals(Locale.ROOT)) // Base case + return language; + return getDisplayLanguage(LocaleHelper.getFallbackLocale(inLocale)); } /** @@ -732,6 +760,8 @@ public final class Locale implements Serializable, Cloneable */ public String getDisplayCountry(Locale inLocale) { + if (country.isEmpty()) + return ""; try { ResourceBundle res = @@ -743,8 +773,27 @@ public final class Locale implements Serializable, Cloneable } catch (MissingResourceException e) { - return country; + /* This means runtime support for the locale + * is not available, so we check providers. */ } + for (LocaleNameProvider p : + ServiceLoader.load(LocaleNameProvider.class)) + { + for (Locale loc : p.getAvailableLocales()) + { + if (loc.equals(inLocale)) + { + String locCountry = p.getDisplayCountry(country, + inLocale); + if (locCountry != null) + return locCountry; + break; + } + } + } + if (inLocale.equals(Locale.ROOT)) // Base case + return country; + return getDisplayCountry(LocaleHelper.getFallbackLocale(inLocale)); } /** @@ -791,6 +840,8 @@ public final class Locale implements Serializable, Cloneable */ public String getDisplayVariant(Locale inLocale) { + if (variant.isEmpty()) + return ""; try { ResourceBundle res = @@ -802,8 +853,27 @@ public final class Locale implements Serializable, Cloneable } catch (MissingResourceException e) { - return variant; + /* This means runtime support for the locale + * is not available, so we check providers. */ + } + for (LocaleNameProvider p : + ServiceLoader.load(LocaleNameProvider.class)) + { + for (Locale loc : p.getAvailableLocales()) + { + if (loc.equals(inLocale)) + { + String locVar = p.getDisplayVariant(variant, + inLocale); + if (locVar != null) + return locVar; + break; + } + } } + if (inLocale.equals(Locale.ROOT)) // Base case + return country; + return getDisplayVariant(LocaleHelper.getFallbackLocale(inLocale)); } /** diff --git a/libjava/classpath/java/util/PriorityQueue.java b/libjava/classpath/java/util/PriorityQueue.java index c9cfd8b..9e738d6 100644 --- a/libjava/classpath/java/util/PriorityQueue.java +++ b/libjava/classpath/java/util/PriorityQueue.java @@ -164,6 +164,7 @@ public class PriorityQueue<E> extends AbstractQueue<E> implements Serializable { while (storage[++index] == null) ; + ++count; return storage[index]; } diff --git a/libjava/classpath/java/util/ServiceConfigurationError.java b/libjava/classpath/java/util/ServiceConfigurationError.java new file mode 100644 index 0000000..1d006c8 --- /dev/null +++ b/libjava/classpath/java/util/ServiceConfigurationError.java @@ -0,0 +1,94 @@ +/* ServiceConfigurationError.java -- An error on service loading. + Copyright (C) 2007 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util; + +/** + * <p> + * An error thrown when a problem occurs during the loading + * of a service provider by a {@link ServiceLoader}. Such + * an error can occur for a number of reasons: + * </p> + * <ul> + * <li>An I/O error occurs</li> + * <li>The configuration file doesn't meet the specifications</li> + * <li>A listed class can not be found</li> + * <li>A listed class does not implement the service</li> + * <li>A listed class can not be instantiated</li> + * </ul> + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ +public class ServiceConfigurationError + extends Error +{ + + /** + * Compatible with JDK 1.6 + */ + private static final long serialVersionUID = 74132770414881L; + + /** + * Constructs a new {@link ServiceConfigurationError} + * with the specified message. + * + * @param message a message describing the error, or + * <code>null</code> if none is required. + */ + public ServiceConfigurationError(String message) + { + super(message); + } + + /** + * Constructs a new {@link ServiceConfigurationError} + * with the specified message and cause. + * + * @param message a message describing the error, or + * <code>null</code> if none is required. + * @param cause the cause of the error, or + * <code>null</code> if this is unknown + * or inappropriate. + */ + public ServiceConfigurationError(String message, + Throwable cause) + { + super(message,cause); + } + +} diff --git a/libjava/classpath/java/util/ServiceLoader.java b/libjava/classpath/java/util/ServiceLoader.java new file mode 100644 index 0000000..9935416 --- /dev/null +++ b/libjava/classpath/java/util/ServiceLoader.java @@ -0,0 +1,274 @@ +/* ServiceLoader.java -- Allows loading of plug-in services. + Copyright (C) 2006, 2007 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util; + +import gnu.classpath.ServiceFactory; + +/** + * <p> + * Facilities for loading service providers. A service is + * defined by a set of interfaces or abstract classes, and + * a service provider gives a concrete implementation of this. + * Service providers may be installed as part of the runtime + * environment using JAR files in the extension directories, + * or may be simply supplied on the classpath. + * </p> + * <p> + * In terms of loading a service, the service is defined by + * a single interface or abstract class which the provider + * implements. This may not constitute the entire service, + * but is simply a mechanism by which a provider of the + * service can be loaded and its capabilities determined. + * The variety of possible services means that no more + * requirements are made of the service provider other than + * that it must have an accessible zero argument constructor + * in order to allow an instance to be created. + * </p> + * <p> + * Service providers are listed in a file named after the + * service type in the directory <code>META-INF/services</code>. + * The file contains a list of classes, and must be encoded + * using UTF-8. Whitespace is ignored. Comments can be + * included by using a <code>'#'</code> prefix; anything occurring + * on the same line after this symbol is ignored. Duplicate classes + * are ignored. + * </p> + * <p> + * The classes are loaded using the same classloader that was + * queried in order to locate the configuration file. As a result, + * the providers do not need to reside in the same JAR file as the + * resource; they merely have to be accessible to this classloader, + * which may differ from the one that loaded the file itself. + * </p> + * <p> + * Providers are located and instantiated lazily, as calls to the + * {@link #iterator()} are made. Providers are cached, and those in + * the cache are returned first. The cache may be cleared by calling + * {@link #reload()}. Service loaders always execute in the security + * context of the caller, so ideally calls should be made from a trusted + * source. + * </p> + * <p> + * Note that this class is not thread-safe, and that strange errors may + * occur as the result of the use of remote URLs occurring on the classpath, + * which lead to erroneous web pages. + * </p> + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ +public final class ServiceLoader<S> + implements Iterable<S> +{ + + /** + * The class of the service provider. + */ + private Class<S> spi; + + /** + * The class loader for the service provider. + */ + private ClassLoader loader; + + /** + * The cache of service providers. + */ + private List<S> cache; + + /** + * The {@link gnu.classpath.ServiceFactory} iterator + * from which providers are obtained. + */ + private Iterator<S> serviceIt; + + /** + * Constructs a new {@link ServiceLoader} with + * the specified provider and class loader. + * + * @param spi the service to load. + * @param loader the class loader to use. + */ + private ServiceLoader(Class<S> spi, ClassLoader loader) + { + this.spi = spi; + this.loader = loader; + cache = new ArrayList<S>(); + } + + /** + * Lazily loads the available providers. The iterator first returns + * providers from the cache, in instantiation order, followed by any + * remaining providers, which are added to the cache after loading. + * The actual loading and parsing of the configuration file takes + * place in the {@link Iterator#hasNext()} and {@link Iterator#next()} + * methods, which means that they may result in a + * {@link ServiceConfigurationError} being thrown. If such an error + * does occur, subsequent invocations will attempt to recover. + * The {@link remove()} method is not supported and instead throws + * an {@link UnsupportedOperationException}. + * + * @return an iterator that lazily loads service providers. + */ + public Iterator<S> iterator() + { + return new Iterator<S>() + { + /** + * The cache iterator. + */ + private Iterator<S> cacheIt = cache.iterator(); + + public boolean hasNext() + { + if (cacheIt.hasNext()) + return true; + if (serviceIt == null) + serviceIt = + ServiceFactory.lookupProviders(spi, loader, true); + return serviceIt.hasNext(); + } + + public S next() + { + if (cacheIt.hasNext()) + return cacheIt.next(); + if (serviceIt == null) + serviceIt = + ServiceFactory.lookupProviders(spi, loader, true); + S nextService = serviceIt.next(); + cache.add(nextService); + return nextService; + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } + + /** + * Creates a new service loader for the given service, + * using the context class loader of the current thread. + * This is equivalent to calling <code>ServiceLoader.load(service, + * Thread.currentThread().getContextClassLoader())</code>. + * + * @param service the interface or abstract class that represents + * the service. + * @return a new {@link ServiceLoader} instance. + */ + public static <S> ServiceLoader<S> load(Class<S> service) + { + return load(service, + Thread.currentThread().getContextClassLoader()); + } + + /** + * Creates a new service loader for the given service, + * using the specified class loader. The class loader is + * used to access the configuration file and the service + * provider instances themselves. If the loader is + * <code>null</code>, the system class loader (or, if + * this is also <code>null</code>, the bootstrap class + * loader). + * + * @param service the interface or abstract class that represents + * the service. + * @param loader the class loader used to load the configuration + * file and service providers. + * @return a new {@link ServiceLoader} instance. + */ + public static <S> ServiceLoader<S> load(Class<S> service, + ClassLoader loader) + { + if (loader == null) + loader = ClassLoader.getSystemClassLoader(); + return new ServiceLoader(service, loader); + } + + /** + * Creates a new service loader for the given service, + * using the extension class loader. If the extension + * class loader can not be found, the system class loader + * is used (or, if this is <code>null</code>, the + * bootstrap class loader). The primary use of this method + * is to only obtain installed services, ignoring any which + * may appear on the classpath. This is equivalent to calling + * <code>load(service, extClassLoader)</code> where + * <code>extClassLoader</code> is the extension class loader + * (or <code>null</code> if this is unavailable). + * + * @param service the interface or abstract class that represents + * the service. + * @return a new {@link ServiceLoader} instance. + */ + public static <S> ServiceLoader<S> loadInstalled(Class<S> service) + { + /* We expect the extension class loader to be the parent + * of the system class loader, as in + * ClassLoader.getDefaultSystemClassLoader() */ + return load(service, + ClassLoader.getSystemClassLoader().getParent()); + } + + /** + * Clears the cache of the provider, so that all providers + * are again read from the configuration file and instantiated. + */ + public void reload() + { + cache.clear(); + } + + /** + * Returns a textual representation of this + * {@link ServiceLoader}. + * + * @return a textual representation of the + * service loader. + */ + public String toString() + { + return getClass().getName() + + "[spi=" + spi + + ",loader=" + loader + + "]"; + } + +} diff --git a/libjava/classpath/java/util/StringTokenizer.java b/libjava/classpath/java/util/StringTokenizer.java index 0b59abe..b230c73 100644 --- a/libjava/classpath/java/util/StringTokenizer.java +++ b/libjava/classpath/java/util/StringTokenizer.java @@ -181,13 +181,15 @@ public class StringTokenizer implements Enumeration<Object> { if (retDelims) return str.substring(pos, ++pos); - while (++pos < len && delim.indexOf(str.charAt(pos)) >= 0); + while (++pos < len && delim.indexOf(str.charAt(pos)) >= 0) + ; } if (pos < len) { int start = pos; - while (++pos < len && delim.indexOf(str.charAt(pos)) < 0); - + while (++pos < len && delim.indexOf(str.charAt(pos)) < 0) + ; + return str.substring(start, pos); } throw new NoSuchElementException(); diff --git a/libjava/classpath/java/util/TreeMap.java b/libjava/classpath/java/util/TreeMap.java index 88abce1..f54cbc3 100644 --- a/libjava/classpath/java/util/TreeMap.java +++ b/libjava/classpath/java/util/TreeMap.java @@ -1,6 +1,6 @@ /* TreeMap.java -- a class providing a basic Red-Black Tree data structure, mapping Object --> Object - 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. @@ -79,6 +79,7 @@ import java.io.Serializable; * @author Jon Zeppieri * @author Bryce McKinlay * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) * @see Map * @see HashMap * @see Hashtable @@ -88,10 +89,10 @@ import java.io.Serializable; * @see Collection * @see Collections#synchronizedSortedMap(SortedMap) * @since 1.2 - * @status updated to 1.4 + * @status updated to 1.6 */ public class TreeMap<K, V> extends AbstractMap<K, V> - implements SortedMap<K, V>, Cloneable, Serializable + implements NavigableMap<K, V>, Cloneable, Serializable { // Implementation note: // A red-black tree is a binary search tree with the additional properties @@ -143,6 +144,16 @@ public class TreeMap<K, V> extends AbstractMap<K, V> private transient Set<Map.Entry<K,V>> entries; /** + * The cache for {@link #descendingMap()}. + */ + private transient NavigableMap<K,V> descendingMap; + + /** + * The cache for {@link #navigableKeySet()}. + */ + private transient NavigableSet<K> nKeys; + + /** * Counts the number of modifications this TreeMap has undergone, used * by Iterators to know when to throw ConcurrentModificationExceptions. * Package visible for use by nested classes. @@ -369,46 +380,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V> if (entries == null) // Create an AbstractSet with custom implementations of those methods // that can be overriden easily and efficiently. - entries = new AbstractSet<Map.Entry<K,V>>() - { - public int size() - { - return size; - } - - public Iterator<Map.Entry<K,V>> iterator() - { - return new TreeIterator(ENTRIES); - } - - public void clear() - { - TreeMap.this.clear(); - } - - public boolean contains(Object o) - { - if (! (o instanceof Map.Entry)) - return false; - Map.Entry<K,V> me = (Map.Entry<K,V>) o; - Node<K,V> n = getNode(me.getKey()); - return n != nil && AbstractSet.equals(me.getValue(), n.value); - } - - public boolean remove(Object o) - { - if (! (o instanceof Map.Entry)) - return false; - Map.Entry<K,V> me = (Map.Entry<K,V>) o; - Node<K,V> n = getNode(me.getKey()); - if (n != nil && AbstractSet.equals(me.getValue(), n.value)) - { - removeNode(n); - return true; - } - return false; - } - }; + entries = new NavigableEntrySet(); return entries; } @@ -451,7 +423,9 @@ public class TreeMap<K, V> extends AbstractMap<K, V> * in one appear in the other. The submap will throw an * {@link IllegalArgumentException} for any attempt to access or add an * element beyond the specified cutoff. The returned map does not include - * the endpoint; if you want inclusion, pass the successor element. + * the endpoint; if you want inclusion, pass the successor element + * or call <code>headMap(toKey, true)</code>. This is equivalent to + * calling <code>headMap(toKey, false)</code>. * * @param toKey the (exclusive) cutoff point * @return a view of the map less than the cutoff @@ -462,7 +436,29 @@ public class TreeMap<K, V> extends AbstractMap<K, V> */ public SortedMap<K, V> headMap(K toKey) { - return new SubMap((K)(Object)nil, toKey); + return headMap(toKey, false); + } + + /** + * Returns a view of this Map including all entries with keys less than + * (or equal to, if <code>inclusive</code> is true) <code>toKey</code>. + * The returned map is backed by the original, so changes in one appear + * in the other. The submap will throw an {@link IllegalArgumentException} + * for any attempt to access or add an element beyond the specified cutoff. + * + * @param toKey the cutoff point + * @param inclusive true if the cutoff point should be included. + * @return a view of the map less than (or equal to, if <code>inclusive</code> + * is true) the cutoff. + * @throws ClassCastException if <code>toKey</code> is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if toKey is null, but the comparator does not + * tolerate null elements + */ + public NavigableMap<K, V> headMap(K toKey, boolean inclusive) + { + return new SubMap((K)(Object)nil, inclusive + ? successor(getNode(toKey)).key : toKey); } /** @@ -479,37 +475,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V> if (keys == null) // Create an AbstractSet with custom implementations of those methods // that can be overriden easily and efficiently. - keys = new AbstractSet<K>() - { - public int size() - { - return size; - } - - public Iterator<K> iterator() - { - return new TreeIterator(KEYS); - } - - public void clear() - { - TreeMap.this.clear(); - } - - public boolean contains(Object o) - { - return containsKey(o); - } - - public boolean remove(Object key) - { - Node<K,V> n = getNode((K) key); - if (n == nil) - return false; - removeNode(n); - return true; - } - }; + keys = new KeySet(); return keys; } @@ -648,7 +614,9 @@ public class TreeMap<K, V> extends AbstractMap<K, V> * {@link IllegalArgumentException} for any attempt to access or add an * element beyond the specified cutoffs. The returned map includes the low * endpoint but not the high; if you want to reverse this behavior on - * either end, pass in the successor element. + * either end, pass in the successor element or call + * {@link #subMap(K,boolean,K,boolean)}. This call is equivalent to + * <code>subMap(fromKey, true, toKey, false)</code>. * * @param fromKey the (inclusive) low cutoff point * @param toKey the (exclusive) high cutoff point @@ -661,7 +629,34 @@ public class TreeMap<K, V> extends AbstractMap<K, V> */ public SortedMap<K, V> subMap(K fromKey, K toKey) { - return new SubMap(fromKey, toKey); + return subMap(fromKey, true, toKey, false); + } + + /** + * Returns a view of this Map including all entries with keys greater (or + * equal to, if <code>fromInclusive</code> is true) <code>fromKey</code> and + * less than (or equal to, if <code>toInclusive</code> is true) + * <code>toKey</code>. The returned map is backed by the original, so + * changes in one appear in the other. The submap will throw an + * {@link IllegalArgumentException} for any attempt to access or add an + * element beyond the specified cutoffs. + * + * @param fromKey the low cutoff point + * @param fromInclusive true if the low cutoff point should be included. + * @param toKey the high cutoff point + * @param toInclusive true if the high cutoff point should be included. + * @return a view of the map for the specified range. + * @throws ClassCastException if either cutoff is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if fromKey or toKey is null, but the + * comparator does not tolerate null elements + * @throws IllegalArgumentException if fromKey is greater than toKey + */ + public NavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive) + { + return new SubMap(fromInclusive ? fromKey : successor(getNode(fromKey)).key, + toInclusive ? successor(getNode(toKey)).key : toKey); } /** @@ -671,6 +666,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V> * {@link IllegalArgumentException} for any attempt to access or add an * element beyond the specified cutoff. The returned map includes the * endpoint; if you want to exclude it, pass in the successor element. + * This is equivalent to calling <code>tailMap(fromKey, true)</code>. * * @param fromKey the (inclusive) low cutoff point * @return a view of the map above the cutoff @@ -681,7 +677,29 @@ public class TreeMap<K, V> extends AbstractMap<K, V> */ public SortedMap<K, V> tailMap(K fromKey) { - return new SubMap(fromKey, (K)(Object)nil); + return tailMap(fromKey, true); + } + + /** + * Returns a view of this Map including all entries with keys greater or + * equal to <code>fromKey</code>. The returned map is backed by the + * original, so changes in one appear in the other. The submap will throw an + * {@link IllegalArgumentException} for any attempt to access or add an + * element beyond the specified cutoff. The returned map includes the + * endpoint; if you want to exclude it, pass in the successor element. + * + * @param fromKey the low cutoff point + * @param inclusive true if the cutoff point should be included. + * @return a view of the map above the cutoff + * @throws ClassCastException if <code>fromKey</code> is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if fromKey is null, but the comparator + * does not tolerate null elements + */ + public NavigableMap<K, V> tailMap(K fromKey, boolean inclusive) + { + return new SubMap(inclusive ? fromKey : successor(getNode(fromKey)).key, + (K)(Object)nil); } /** @@ -972,6 +990,21 @@ public class TreeMap<K, V> extends AbstractMap<K, V> */ final Node<K,V> highestLessThan(K key) { + return highestLessThan(key, false); + } + + /** + * Find the "highest" node which is < (or equal to, + * if <code>equal</code> is true) key. If key is nil, + * return last node. Package visible for use by nested + * classes. + * + * @param key the upper bound, exclusive + * @param equal true if the key should be returned if found. + * @return the previous node + */ + final Node<K,V> highestLessThan(K key, boolean equal) + { if (key == nil) return lastNode(); @@ -988,9 +1021,9 @@ public class TreeMap<K, V> extends AbstractMap<K, V> else if (comparison < 0) current = current.left; else // Exact match. - return predecessor(last); + return (equal ? last : predecessor(last)); } - return comparison <= 0 ? predecessor(last) : last; + return comparison < 0 ? predecessor(last) : last; } /** @@ -1084,8 +1117,8 @@ public class TreeMap<K, V> extends AbstractMap<K, V> /** * Find the "lowest" node which is >= key. If key is nil, return either - * nil or the first node, depending on the parameter first. - * Package visible for use by nested classes. + * nil or the first node, depending on the parameter first. Package visible + * for use by nested classes. * * @param key the lower bound, inclusive * @param first true to return the first element instead of nil for nil key @@ -1093,6 +1126,21 @@ public class TreeMap<K, V> extends AbstractMap<K, V> */ final Node<K,V> lowestGreaterThan(K key, boolean first) { + return lowestGreaterThan(key, first, true); + } + + /** + * Find the "lowest" node which is > (or equal to, if <code>equal</code> + * is true) key. If key is nil, return either nil or the first node, depending + * on the parameter first. Package visible for use by nested classes. + * + * @param key the lower bound, inclusive + * @param first true to return the first element instead of nil for nil key + * @param equal true if the key should be returned if found. + * @return the next node + */ + final Node<K,V> lowestGreaterThan(K key, boolean first, boolean equal) + { if (key == nil) return first ? firstNode() : nil; @@ -1109,7 +1157,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V> else if (comparison < 0) current = current.left; else - return current; + return (equal ? current : successor(current)); } return comparison > 0 ? successor(last) : last; } @@ -1409,11 +1457,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V> */ TreeIterator(int type) { - // FIXME gcj cannot handle this. Bug java/4695 - // this(type, firstNode(), nil); - this.type = type; - this.next = firstNode(); - this.max = nil; + this(type, firstNode(), nil); } /** @@ -1489,26 +1533,36 @@ public class TreeMap<K, V> extends AbstractMap<K, V> * * @author Eric Blake (ebb9@email.byu.edu) */ - private final class SubMap<SK extends K,SV extends V> - extends AbstractMap<SK,SV> - implements SortedMap<SK,SV> + private final class SubMap + extends AbstractMap<K,V> + implements NavigableMap<K,V> { /** * The lower range of this view, inclusive, or nil for unbounded. * Package visible for use by nested classes. */ - final SK minKey; + final K minKey; /** * The upper range of this view, exclusive, or nil for unbounded. * Package visible for use by nested classes. */ - final SK maxKey; + final K maxKey; /** * The cache for {@link #entrySet()}. */ - private Set<Map.Entry<SK,SV>> entries; + private Set<Map.Entry<K,V>> entries; + + /** + * The cache for {@link #descendingMap()}. + */ + private NavigableMap<K,V> descendingMap; + + /** + * The cache for {@link #navigableKeySet()}. + */ + private NavigableSet<K> nKeys; /** * Create a SubMap representing the elements between minKey (inclusive) @@ -1519,9 +1573,9 @@ public class TreeMap<K, V> extends AbstractMap<K, V> * @param maxKey the upper bound * @throws IllegalArgumentException if minKey > maxKey */ - SubMap(SK minKey, SK maxKey) + SubMap(K minKey, K maxKey) { - if (minKey != nil && maxKey != nil && compare((K) minKey, (K) maxKey) > 0) + if (minKey != nil && maxKey != nil && compare(minKey, maxKey) > 0) throw new IllegalArgumentException("fromKey > toKey"); this.minKey = minKey; this.maxKey = maxKey; @@ -1535,12 +1589,41 @@ public class TreeMap<K, V> extends AbstractMap<K, V> * @param key the key to check * @return true if the key is in range */ - boolean keyInRange(SK key) + boolean keyInRange(K key) { - return ((minKey == nil || compare((K) key, (K) minKey) >= 0) - && (maxKey == nil || compare((K) key, (K) maxKey) < 0)); + return ((minKey == nil || compare(key, minKey) >= 0) + && (maxKey == nil || compare(key, maxKey) < 0)); } + public Entry<K,V> ceilingEntry(K key) + { + Entry<K,V> n = TreeMap.this.ceilingEntry(key); + if (n != null && keyInRange(n.getKey())) + return n; + return null; + } + + public K ceilingKey(K key) + { + K found = TreeMap.this.ceilingKey(key); + if (keyInRange(found)) + return found; + else + return null; + } + + public NavigableSet<K> descendingKeySet() + { + return descendingMap().navigableKeySet(); + } + + public NavigableMap<K,V> descendingMap() + { + if (descendingMap == null) + descendingMap = new DescendingMap(this); + return descendingMap; + } + public void clear() { Node next = lowestGreaterThan(minKey, true); @@ -1553,14 +1636,14 @@ public class TreeMap<K, V> extends AbstractMap<K, V> } } - public Comparator<? super SK> comparator() + public Comparator<? super K> comparator() { return comparator; } public boolean containsKey(Object key) { - return keyInRange((SK) key) && TreeMap.this.containsKey(key); + return keyInRange((K) key) && TreeMap.this.containsKey(key); } public boolean containsValue(Object value) @@ -1576,150 +1659,160 @@ public class TreeMap<K, V> extends AbstractMap<K, V> return false; } - public Set<Map.Entry<SK,SV>> entrySet() + public Set<Map.Entry<K,V>> entrySet() { if (entries == null) // Create an AbstractSet with custom implementations of those methods // that can be overriden easily and efficiently. - entries = new AbstractSet<Map.Entry<SK,SV>>() - { - public int size() - { - return SubMap.this.size(); - } - - public Iterator<Map.Entry<SK,SV>> iterator() - { - Node first = lowestGreaterThan(minKey, true); - Node max = lowestGreaterThan(maxKey, false); - return new TreeIterator(ENTRIES, first, max); - } - - public void clear() - { - SubMap.this.clear(); - } - - public boolean contains(Object o) - { - if (! (o instanceof Map.Entry)) - return false; - Map.Entry<SK,SV> me = (Map.Entry<SK,SV>) o; - SK key = me.getKey(); - if (! keyInRange(key)) - return false; - Node<K,V> n = getNode((K) key); - return n != nil && AbstractSet.equals(me.getValue(), n.value); - } - - public boolean remove(Object o) - { - if (! (o instanceof Map.Entry)) - return false; - Map.Entry<SK,SV> me = (Map.Entry<SK,SV>) o; - SK key = me.getKey(); - if (! keyInRange(key)) - return false; - Node<K,V> n = getNode((K) key); - if (n != nil && AbstractSet.equals(me.getValue(), n.value)) - { - removeNode(n); - return true; - } - return false; - } - }; + entries = new SubMap.NavigableEntrySet(); return entries; } - public SK firstKey() + public Entry<K,V> firstEntry() { - Node<SK,SV> node = (Node<SK,SV>) lowestGreaterThan(minKey, true); + Node<K,V> node = lowestGreaterThan(minKey, true); if (node == nil || ! keyInRange(node.key)) + return null; + return node; + } + + public K firstKey() + { + Entry<K,V> e = firstEntry(); + if (e == null) throw new NoSuchElementException(); - return node.key; + return e.getKey(); } - public SV get(Object key) + public Entry<K,V> floorEntry(K key) { - if (keyInRange((SK) key)) - return (SV) TreeMap.this.get(key); + Entry<K,V> n = TreeMap.this.floorEntry(key); + if (n != null && keyInRange(n.getKey())) + return n; return null; } - public SortedMap<SK,SV> headMap(SK toKey) + public K floorKey(K key) { - if (! keyInRange(toKey)) - throw new IllegalArgumentException("key outside range"); - return new SubMap(minKey, toKey); + K found = TreeMap.this.floorKey(key); + if (keyInRange(found)) + return found; + else + return null; + } + + public V get(Object key) + { + if (keyInRange((K) key)) + return TreeMap.this.get(key); + return null; } - public Set<SK> keySet() + public SortedMap<K,V> headMap(K toKey) + { + return headMap(toKey, false); + } + + public NavigableMap<K,V> headMap(K toKey, boolean inclusive) + { + if (!keyInRange(toKey)) + throw new IllegalArgumentException("Key outside submap range"); + return new SubMap(minKey, (inclusive ? + successor(getNode(toKey)).key : toKey)); + } + + public Set<K> keySet() { if (this.keys == null) // Create an AbstractSet with custom implementations of those methods // that can be overriden easily and efficiently. - this.keys = new AbstractSet() - { - public int size() - { - return SubMap.this.size(); - } - - public Iterator<SK> iterator() - { - Node first = lowestGreaterThan(minKey, true); - Node max = lowestGreaterThan(maxKey, false); - return new TreeIterator(KEYS, first, max); - } + this.keys = new SubMap.KeySet(); + return this.keys; + } - public void clear() - { - SubMap.this.clear(); - } + public Entry<K,V> higherEntry(K key) + { + Entry<K,V> n = TreeMap.this.higherEntry(key); + if (n != null && keyInRange(n.getKey())) + return n; + return null; + } - public boolean contains(Object o) - { - if (! keyInRange((SK) o)) - return false; - return getNode((K) o) != nil; - } + public K higherKey(K key) + { + K found = TreeMap.this.higherKey(key); + if (keyInRange(found)) + return found; + else + return null; + } - public boolean remove(Object o) - { - if (! keyInRange((SK) o)) - return false; - Node n = getNode((K) o); - if (n != nil) - { - removeNode(n); - return true; - } - return false; - } - }; - return this.keys; + public Entry<K,V> lastEntry() + { + return lowerEntry(maxKey); } - public SK lastKey() + public K lastKey() { - Node<SK,SV> node = (Node<SK,SV>) highestLessThan(maxKey); - if (node == nil || ! keyInRange(node.key)) + Entry<K,V> e = lastEntry(); + if (e == null) throw new NoSuchElementException(); - return (SK) node.key; + return e.getKey(); + } + + public Entry<K,V> lowerEntry(K key) + { + Entry<K,V> n = TreeMap.this.lowerEntry(key); + if (n != null && keyInRange(n.getKey())) + return n; + return null; + } + + public K lowerKey(K key) + { + K found = TreeMap.this.lowerKey(key); + if (keyInRange(found)) + return found; + else + return null; + } + + public NavigableSet<K> navigableKeySet() + { + if (this.nKeys == null) + // Create an AbstractSet with custom implementations of those methods + // that can be overriden easily and efficiently. + this.nKeys = new SubMap.NavigableKeySet(); + return this.nKeys; + } + + public Entry<K,V> pollFirstEntry() + { + Entry<K,V> e = firstEntry(); + if (e != null) + removeNode((Node<K,V>) e); + return e; } - public SV put(SK key, SV value) + public Entry<K,V> pollLastEntry() + { + Entry<K,V> e = lastEntry(); + if (e != null) + removeNode((Node<K,V>) e); + return e; + } + + public V put(K key, V value) { if (! keyInRange(key)) throw new IllegalArgumentException("Key outside range"); - return (SV) TreeMap.this.put(key, value); + return TreeMap.this.put(key, value); } - public SV remove(Object key) + public V remove(Object key) { - if (keyInRange((SK)key)) - return (SV) TreeMap.this.remove(key); + if (keyInRange((K)key)) + return TreeMap.this.remove(key); return null; } @@ -1736,21 +1829,34 @@ public class TreeMap<K, V> extends AbstractMap<K, V> return count; } - public SortedMap<SK, SV> subMap(SK fromKey, SK toKey) + public SortedMap<K,V> subMap(K fromKey, K toKey) + { + return subMap(fromKey, true, toKey, false); + } + + public NavigableMap<K,V> subMap(K fromKey, boolean fromInclusive, + K toKey, boolean toInclusive) { if (! keyInRange(fromKey) || ! keyInRange(toKey)) throw new IllegalArgumentException("key outside range"); - return new SubMap(fromKey, toKey); + return new SubMap(fromInclusive ? fromKey : successor(getNode(fromKey)).key, + toInclusive ? successor(getNode(toKey)).key : toKey); } - public SortedMap<SK, SV> tailMap(SK fromKey) + public SortedMap<K, V> tailMap(K fromKey) + { + return tailMap(fromKey, true); + } + + public NavigableMap<K,V> tailMap(K fromKey, boolean inclusive) { if (! keyInRange(fromKey)) throw new IllegalArgumentException("key outside range"); - return new SubMap(fromKey, maxKey); + return new SubMap(inclusive ? fromKey : successor(getNode(fromKey)).key, + maxKey); } - public Collection<SV> values() + public Collection<V> values() { if (this.values == null) // Create an AbstractCollection with custom implementations of those @@ -1762,7 +1868,7 @@ public class TreeMap<K, V> extends AbstractMap<K, V> return SubMap.this.size(); } - public Iterator<SV> iterator() + public Iterator<V> iterator() { Node first = lowestGreaterThan(minKey, true); Node max = lowestGreaterThan(maxKey, false); @@ -1776,5 +1882,1439 @@ public class TreeMap<K, V> extends AbstractMap<K, V> }; return this.values; } - } // class SubMap + + private class KeySet + extends AbstractSet<K> + { + public int size() + { + return SubMap.this.size(); + } + + public Iterator<K> iterator() + { + Node first = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + return new TreeIterator(KEYS, first, max); + } + + public void clear() + { + SubMap.this.clear(); + } + + public boolean contains(Object o) + { + if (! keyInRange((K) o)) + return false; + return getNode((K) o) != nil; + } + + public boolean remove(Object o) + { + if (! keyInRange((K) o)) + return false; + Node n = getNode((K) o); + if (n != nil) + { + removeNode(n); + return true; + } + return false; + } + + } // class SubMap.KeySet + + private final class NavigableKeySet + extends KeySet + implements NavigableSet<K> + { + + public K ceiling(K k) + { + return SubMap.this.ceilingKey(k); + } + + public Comparator<? super K> comparator() + { + return comparator; + } + + public Iterator<K> descendingIterator() + { + return descendingSet().iterator(); + } + + public NavigableSet<K> descendingSet() + { + return new DescendingSet(this); + } + + public K first() + { + return SubMap.this.firstKey(); + } + + public K floor(K k) + { + return SubMap.this.floorKey(k); + } + + public SortedSet<K> headSet(K to) + { + return headSet(to, false); + } + + public NavigableSet<K> headSet(K to, boolean inclusive) + { + return SubMap.this.headMap(to, inclusive).navigableKeySet(); + } + + public K higher(K k) + { + return SubMap.this.higherKey(k); + } + + public K last() + { + return SubMap.this.lastKey(); + } + + public K lower(K k) + { + return SubMap.this.lowerKey(k); + } + + public K pollFirst() + { + return SubMap.this.pollFirstEntry().getKey(); + } + + public K pollLast() + { + return SubMap.this.pollLastEntry().getKey(); + } + + public SortedSet<K> subSet(K from, K to) + { + return subSet(from, true, to, false); + } + + public NavigableSet<K> subSet(K from, boolean fromInclusive, + K to, boolean toInclusive) + { + return SubMap.this.subMap(from, fromInclusive, + to, toInclusive).navigableKeySet(); + } + + public SortedSet<K> tailSet(K from) + { + return tailSet(from, true); + } + + public NavigableSet<K> tailSet(K from, boolean inclusive) + { + return SubMap.this.tailMap(from, inclusive).navigableKeySet(); + } + + } // class SubMap.NavigableKeySet + + /** + * Implementation of {@link #entrySet()}. + */ + private class EntrySet + extends AbstractSet<Entry<K,V>> + { + + public int size() + { + return SubMap.this.size(); + } + + public Iterator<Map.Entry<K,V>> iterator() + { + Node first = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + return new TreeIterator(ENTRIES, first, max); + } + + public void clear() + { + SubMap.this.clear(); + } + + public boolean contains(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + Map.Entry<K,V> me = (Map.Entry<K,V>) o; + K key = me.getKey(); + if (! keyInRange(key)) + return false; + Node<K,V> n = getNode(key); + return n != nil && AbstractSet.equals(me.getValue(), n.value); + } + + public boolean remove(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + Map.Entry<K,V> me = (Map.Entry<K,V>) o; + K key = me.getKey(); + if (! keyInRange(key)) + return false; + Node<K,V> n = getNode(key); + if (n != nil && AbstractSet.equals(me.getValue(), n.value)) + { + removeNode(n); + return true; + } + return false; + } + } // class SubMap.EntrySet + + private final class NavigableEntrySet + extends EntrySet + implements NavigableSet<Entry<K,V>> + { + + public Entry<K,V> ceiling(Entry<K,V> e) + { + return SubMap.this.ceilingEntry(e.getKey()); + } + + public Comparator<? super Entry<K,V>> comparator() + { + return new Comparator<Entry<K,V>>() + { + public int compare(Entry<K,V> t1, Entry<K,V> t2) + { + return comparator.compare(t1.getKey(), t2.getKey()); + } + }; + } + + public Iterator<Entry<K,V>> descendingIterator() + { + return descendingSet().iterator(); + } + + public NavigableSet<Entry<K,V>> descendingSet() + { + return new DescendingSet(this); + } + + public Entry<K,V> first() + { + return SubMap.this.firstEntry(); + } + + public Entry<K,V> floor(Entry<K,V> e) + { + return SubMap.this.floorEntry(e.getKey()); + } + + public SortedSet<Entry<K,V>> headSet(Entry<K,V> to) + { + return headSet(to, false); + } + + public NavigableSet<Entry<K,V>> headSet(Entry<K,V> to, boolean inclusive) + { + return (NavigableSet<Entry<K,V>>) + SubMap.this.headMap(to.getKey(), inclusive).entrySet(); + } + + public Entry<K,V> higher(Entry<K,V> e) + { + return SubMap.this.higherEntry(e.getKey()); + } + + public Entry<K,V> last() + { + return SubMap.this.lastEntry(); + } + + public Entry<K,V> lower(Entry<K,V> e) + { + return SubMap.this.lowerEntry(e.getKey()); + } + + public Entry<K,V> pollFirst() + { + return SubMap.this.pollFirstEntry(); + } + + public Entry<K,V> pollLast() + { + return SubMap.this.pollLastEntry(); + } + + public SortedSet<Entry<K,V>> subSet(Entry<K,V> from, Entry<K,V> to) + { + return subSet(from, true, to, false); + } + + public NavigableSet<Entry<K,V>> subSet(Entry<K,V> from, boolean fromInclusive, + Entry<K,V> to, boolean toInclusive) + { + return (NavigableSet<Entry<K,V>>) + SubMap.this.subMap(from.getKey(), fromInclusive, + to.getKey(), toInclusive).entrySet(); + } + + public SortedSet<Entry<K,V>> tailSet(Entry<K,V> from) + { + return tailSet(from, true); + } + + public NavigableSet<Entry<K,V>> tailSet(Entry<K,V> from, boolean inclusive) + { + return (NavigableSet<Entry<K,V>>) + SubMap.this.tailMap(from.getKey(), inclusive).navigableKeySet(); + } + + } // class SubMap.NavigableEntrySet + +} // class SubMap + + /** + * Returns the entry associated with the least or lowest key + * that is greater than or equal to the specified key, or + * <code>null</code> if there is no such key. + * + * @param key the key relative to the returned entry. + * @return the entry with the least key greater than or equal + * to the given key, or <code>null</code> if there is + * no such key. + * @throws ClassCastException if the specified key can not + * be compared with those in the map. + * @throws NullPointerException if the key is <code>null</code> + * and this map either uses natural + * ordering or a comparator that does + * not permit null keys. + * @since 1.6 + */ + public Entry<K,V> ceilingEntry(K key) + { + Node<K,V> n = lowestGreaterThan(key, false); + return (n == nil) ? null : n; + } + + /** + * Returns the the least or lowest key that is greater than + * or equal to the specified key, or <code>null</code> if + * there is no such key. + * + * @param key the key relative to the returned entry. + * @return the least key greater than or equal to the given key, + * or <code>null</code> if there is no such key. + * @throws ClassCastException if the specified key can not + * be compared with those in the map. + * @throws NullPointerException if the key is <code>null</code> + * and this map either uses natural + * ordering or a comparator that does + * not permit null keys. + * @since 1.6 + */ + public K ceilingKey(K key) + { + Entry<K,V> e = ceilingEntry(key); + return (e == null) ? null : e.getKey(); + } + + /** + * Returns a reverse ordered {@link NavigableSet} view of this + * map's keys. The set is backed by the {@link TreeMap}, so changes + * in one show up in the other. The set supports element removal, + * but not element addition. + * + * @return a reverse ordered set view of the keys. + * @since 1.6 + * @see #descendingMap() + */ + public NavigableSet<K> descendingKeySet() + { + return descendingMap().navigableKeySet(); + } + + /** + * Returns a view of the map in reverse order. The descending map + * is backed by the original map, so that changes affect both maps. + * Any changes occurring to either map while an iteration is taking + * place (with the exception of a {@link Iterator#remove()} operation) + * result in undefined behaviour from the iteration. The ordering + * of the descending map is the same as for a map with a + * {@link Comparator} given by {@link Collections#reverseOrder()}, + * and calling {@link #descendingMap()} on the descending map itself + * results in a view equivalent to the original map. + * + * @return a reverse order view of the map. + * @since 1.6 + */ + public NavigableMap<K,V> descendingMap() + { + if (descendingMap == null) + descendingMap = new DescendingMap<K,V>(this); + return descendingMap; + } + + /** + * Returns the entry associated with the least or lowest key + * in the map, or <code>null</code> if the map is empty. + * + * @return the lowest entry, or <code>null</code> if the map + * is empty. + * @since 1.6 + */ + public Entry<K,V> firstEntry() + { + Node<K,V> n = firstNode(); + return (n == nil) ? null : n; + } + + /** + * Returns the entry associated with the greatest or highest key + * that is less than or equal to the specified key, or + * <code>null</code> if there is no such key. + * + * @param key the key relative to the returned entry. + * @return the entry with the greatest key less than or equal + * to the given key, or <code>null</code> if there is + * no such key. + * @throws ClassCastException if the specified key can not + * be compared with those in the map. + * @throws NullPointerException if the key is <code>null</code> + * and this map either uses natural + * ordering or a comparator that does + * not permit null keys. + * @since 1.6 + */ + public Entry<K,V> floorEntry(K key) + { + Node<K,V> n = highestLessThan(key, true); + return (n == nil) ? null : n; + } + + /** + * Returns the the greatest or highest key that is less than + * or equal to the specified key, or <code>null</code> if + * there is no such key. + * + * @param key the key relative to the returned entry. + * @return the greatest key less than or equal to the given key, + * or <code>null</code> if there is no such key. + * @throws ClassCastException if the specified key can not + * be compared with those in the map. + * @throws NullPointerException if the key is <code>null</code> + * and this map either uses natural + * ordering or a comparator that does + * not permit null keys. + * @since 1.6 + */ + public K floorKey(K key) + { + Entry<K,V> e = floorEntry(key); + return (e == null) ? null : e.getKey(); + } + + /** + * Returns the entry associated with the least or lowest key + * that is strictly greater than the specified key, or + * <code>null</code> if there is no such key. + * + * @param key the key relative to the returned entry. + * @return the entry with the least key greater than + * the given key, or <code>null</code> if there is + * no such key. + * @throws ClassCastException if the specified key can not + * be compared with those in the map. + * @throws NullPointerException if the key is <code>null</code> + * and this map either uses natural + * ordering or a comparator that does + * not permit null keys. + * @since 1.6 + */ + public Entry<K,V> higherEntry(K key) + { + Node<K,V> n = lowestGreaterThan(key, false, false); + return (n == nil) ? null : n; + } + + /** + * Returns the the least or lowest key that is strictly + * greater than the specified key, or <code>null</code> if + * there is no such key. + * + * @param key the key relative to the returned entry. + * @return the least key greater than the given key, + * or <code>null</code> if there is no such key. + * @throws ClassCastException if the specified key can not + * be compared with those in the map. + * @throws NullPointerException if the key is <code>null</code> + * and this map either uses natural + * ordering or a comparator that does + * not permit null keys. + * @since 1.6 + */ + public K higherKey(K key) + { + Entry<K,V> e = higherEntry(key); + return (e == null) ? null : e.getKey(); + } + + /** + * Returns the entry associated with the greatest or highest key + * in the map, or <code>null</code> if the map is empty. + * + * @return the highest entry, or <code>null</code> if the map + * is empty. + * @since 1.6 + */ + public Entry<K,V> lastEntry() + { + Node<K,V> n = lastNode(); + return (n == nil) ? null : n; + } + + /** + * Returns the entry associated with the greatest or highest key + * that is strictly less than the specified key, or + * <code>null</code> if there is no such key. + * + * @param key the key relative to the returned entry. + * @return the entry with the greatest key less than + * the given key, or <code>null</code> if there is + * no such key. + * @throws ClassCastException if the specified key can not + * be compared with those in the map. + * @throws NullPointerException if the key is <code>null</code> + * and this map either uses natural + * ordering or a comparator that does + * not permit null keys. + * @since 1.6 + */ + public Entry<K,V> lowerEntry(K key) + { + Node<K,V> n = highestLessThan(key); + return (n == nil) ? null : n; + } + + /** + * Returns the the greatest or highest key that is strictly + * less than the specified key, or <code>null</code> if + * there is no such key. + * + * @param key the key relative to the returned entry. + * @return the greatest key less than the given key, + * or <code>null</code> if there is no such key. + * @throws ClassCastException if the specified key can not + * be compared with those in the map. + * @throws NullPointerException if the key is <code>null</code> + * and this map either uses natural + * ordering or a comparator that does + * not permit null keys. + * @since 1.6 + */ + public K lowerKey(K key) + { + Entry<K,V> e = lowerEntry(key); + return (e == null) ? null : e.getKey(); + } + + /** + * Returns a {@link NavigableSet} view of this map's keys. The set is + * backed by the {@link TreeMap}, so changes in one show up in the other. + * Any changes occurring to either while an iteration is taking + * place (with the exception of a {@link Iterator#remove()} operation) + * result in undefined behaviour from the iteration. The ordering + * The set supports element removal, but not element addition. + * + * @return a {@link NavigableSet} view of the keys. + * @since 1.6 + */ + public NavigableSet<K> navigableKeySet() + { + if (nKeys == null) + nKeys = new NavigableKeySet(); + return nKeys; + } + + /** + * Removes and returns the entry associated with the least + * or lowest key in the map, or <code>null</code> if the map + * is empty. + * + * @return the removed first entry, or <code>null</code> if the + * map is empty. + * @since 1.6 + */ + public Entry<K,V> pollFirstEntry() + { + Entry<K,V> e = firstEntry(); + if (e != null) + removeNode((Node<K,V>)e); + return e; + } + + /** + * Removes and returns the entry associated with the greatest + * or highest key in the map, or <code>null</code> if the map + * is empty. + * + * @return the removed last entry, or <code>null</code> if the + * map is empty. + * @since 1.6 + */ + public Entry<K,V> pollLastEntry() + { + Entry<K,V> e = lastEntry(); + if (e != null) + removeNode((Node<K,V>)e); + return e; + } + + /** + * Implementation of {@link #descendingMap()} and associated + * derivatives. This class provides a view of the + * original backing map in reverse order, and throws + * {@link IllegalArgumentException} for attempts to + * access beyond that range. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private static final class DescendingMap<DK,DV> + implements NavigableMap<DK,DV> + { + + /** + * The cache for {@link #entrySet()}. + */ + private Set<Map.Entry<DK,DV>> entries; + + /** + * The cache for {@link #keySet()}. + */ + private Set<DK> keys; + + /** + * The cache for {@link #navigableKeySet()}. + */ + private NavigableSet<DK> nKeys; + + /** + * The cache for {@link #values()}. + */ + private Collection<DV> values; + + /** + * The backing {@link NavigableMap}. + */ + private NavigableMap<DK,DV> map; + + /** + * Create a {@link DescendingMap} around the specified + * map. + * + * @param map the map to wrap. + */ + public DescendingMap(NavigableMap<DK,DV> map) + { + this.map = map; + } + + public Map.Entry<DK,DV> ceilingEntry(DK key) + { + return map.floorEntry(key); + } + + public DK ceilingKey(DK key) + { + return map.floorKey(key); + } + + public void clear() + { + map.clear(); + } + + public Comparator<? super DK> comparator() + { + return Collections.reverseOrder(map.comparator()); + } + + public boolean containsKey(Object o) + { + return map.containsKey(o); + } + + public boolean containsValue(Object o) + { + return map.containsValue(o); + } + + public NavigableSet<DK> descendingKeySet() + { + return descendingMap().navigableKeySet(); + } + + public NavigableMap<DK,DV> descendingMap() + { + return map; + } + + public Set<Entry<DK,DV>> entrySet() + { + if (entries == null) + entries = + new DescendingSet<Entry<DK,DV>>((NavigableSet<Entry<DK,DV>>) + map.entrySet()); + return entries; + } + + public boolean equals(Object o) + { + return map.equals(o); + } + + public Entry<DK,DV> firstEntry() + { + return map.lastEntry(); + } + + public DK firstKey() + { + return map.lastKey(); + } + + public Entry<DK,DV> floorEntry(DK key) + { + return map.ceilingEntry(key); + } + + public DK floorKey(DK key) + { + return map.ceilingKey(key); + } + + public DV get(Object key) + { + return map.get(key); + } + + public int hashCode() + { + return map.hashCode(); + } + + public SortedMap<DK,DV> headMap(DK toKey) + { + return headMap(toKey, false); + } + + public NavigableMap<DK,DV> headMap(DK toKey, boolean inclusive) + { + return new DescendingMap(map.tailMap(toKey, inclusive)); + } + + public Entry<DK,DV> higherEntry(DK key) + { + return map.lowerEntry(key); + } + + public DK higherKey(DK key) + { + return map.lowerKey(key); + } + + public Set<DK> keySet() + { + if (keys == null) + keys = new DescendingSet<DK>(map.navigableKeySet()); + return keys; + } + + public boolean isEmpty() + { + return map.isEmpty(); + } + + public Entry<DK,DV> lastEntry() + { + return map.firstEntry(); + } + + public DK lastKey() + { + return map.firstKey(); + } + + public Entry<DK,DV> lowerEntry(DK key) + { + return map.higherEntry(key); + } + + public DK lowerKey(DK key) + { + return map.higherKey(key); + } + + public NavigableSet<DK> navigableKeySet() + { + if (nKeys == null) + nKeys = new DescendingSet<DK>(map.navigableKeySet()); + return nKeys; + } + + public Entry<DK,DV> pollFirstEntry() + { + return pollLastEntry(); + } + + public Entry<DK,DV> pollLastEntry() + { + return pollFirstEntry(); + } + + public DV put(DK key, DV value) + { + return map.put(key, value); + } + + public void putAll(Map<? extends DK, ? extends DV> m) + { + map.putAll(m); + } + + public DV remove(Object key) + { + return map.remove(key); + } + + public int size() + { + return map.size(); + } + + public SortedMap<DK,DV> subMap(DK fromKey, DK toKey) + { + return subMap(fromKey, true, toKey, false); + } + + public NavigableMap<DK,DV> subMap(DK fromKey, boolean fromInclusive, + DK toKey, boolean toInclusive) + { + return new DescendingMap(map.subMap(fromKey, fromInclusive, + toKey, toInclusive)); + } + + public SortedMap<DK,DV> tailMap(DK fromKey) + { + return tailMap(fromKey, true); + } + + public NavigableMap<DK,DV> tailMap(DK fromKey, boolean inclusive) + { + return new DescendingMap(map.headMap(fromKey, inclusive)); + } + + public String toString() + { + StringBuilder r = new StringBuilder("{"); + final Iterator<Entry<DK,DV>> it = entrySet().iterator(); + while (it.hasNext()) + { + final Entry<DK,DV> e = it.next(); + r.append(e.getKey()); + r.append('='); + r.append(e.getValue()); + r.append(", "); + } + r.replace(r.length() - 2, r.length(), "}"); + return r.toString(); + } + + public Collection<DV> values() + { + if (values == null) + // Create an AbstractCollection with custom implementations of those + // methods that can be overriden easily and efficiently. + values = new AbstractCollection() + { + public int size() + { + return size(); + } + + public Iterator<DV> iterator() + { + return new Iterator<DV>() + { + /** The last Entry returned by a next() call. */ + private Entry<DK,DV> last; + + /** The next entry that should be returned by next(). */ + private Entry<DK,DV> next = firstEntry(); + + public boolean hasNext() + { + return next != null; + } + + public DV next() + { + if (next == null) + throw new NoSuchElementException(); + last = next; + next = higherEntry(last.getKey()); + + return last.getValue(); + } + + public void remove() + { + if (last == null) + throw new IllegalStateException(); + + DescendingMap.this.remove(last.getKey()); + last = null; + } + }; + } + + public void clear() + { + clear(); + } + }; + return values; + } + + } // class DescendingMap + + /** + * Implementation of {@link #keySet()}. + */ + private class KeySet + extends AbstractSet<K> + { + + public int size() + { + return size; + } + + public Iterator<K> iterator() + { + return new TreeIterator(KEYS); + } + + public void clear() + { + TreeMap.this.clear(); + } + + public boolean contains(Object o) + { + return containsKey(o); + } + + public boolean remove(Object key) + { + Node<K,V> n = getNode((K) key); + if (n == nil) + return false; + removeNode(n); + return true; + } + } // class KeySet + + /** + * Implementation of {@link #navigableKeySet()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private final class NavigableKeySet + extends KeySet + implements NavigableSet<K> + { + + public K ceiling(K k) + { + return ceilingKey(k); + } + + public Comparator<? super K> comparator() + { + return comparator; + } + + public Iterator<K> descendingIterator() + { + return descendingSet().iterator(); + } + + public NavigableSet<K> descendingSet() + { + return new DescendingSet<K>(this); + } + + public K first() + { + return firstKey(); + } + + public K floor(K k) + { + return floorKey(k); + } + + public SortedSet<K> headSet(K to) + { + return headSet(to, false); + } + + public NavigableSet<K> headSet(K to, boolean inclusive) + { + return headMap(to, inclusive).navigableKeySet(); + } + + public K higher(K k) + { + return higherKey(k); + } + + public K last() + { + return lastKey(); + } + + public K lower(K k) + { + return lowerKey(k); + } + + public K pollFirst() + { + return pollFirstEntry().getKey(); + } + + public K pollLast() + { + return pollLastEntry().getKey(); + } + + public SortedSet<K> subSet(K from, K to) + { + return subSet(from, true, to, false); + } + + public NavigableSet<K> subSet(K from, boolean fromInclusive, + K to, boolean toInclusive) + { + return subMap(from, fromInclusive, + to, toInclusive).navigableKeySet(); + } + + public SortedSet<K> tailSet(K from) + { + return tailSet(from, true); + } + + public NavigableSet<K> tailSet(K from, boolean inclusive) + { + return tailMap(from, inclusive).navigableKeySet(); + } + + + } // class NavigableKeySet + + /** + * Implementation of {@link #descendingSet()} and associated + * derivatives. This class provides a view of the + * original backing set in reverse order, and throws + * {@link IllegalArgumentException} for attempts to + * access beyond that range. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private static final class DescendingSet<D> + implements NavigableSet<D> + { + + /** + * The backing {@link NavigableSet}. + */ + private NavigableSet<D> set; + + /** + * Create a {@link DescendingSet} around the specified + * set. + * + * @param map the set to wrap. + */ + public DescendingSet(NavigableSet<D> set) + { + this.set = set; + } + + public boolean add(D e) + { + return set.add(e); + } + + public boolean addAll(Collection<? extends D> c) + { + return set.addAll(c); + } + + public D ceiling(D e) + { + return set.floor(e); + } + + public void clear() + { + set.clear(); + } + + public Comparator<? super D> comparator() + { + return Collections.reverseOrder(set.comparator()); + } + + public boolean contains(Object o) + { + return set.contains(o); + } + + public boolean containsAll(Collection<?> c) + { + return set.containsAll(c); + } + + public Iterator<D> descendingIterator() + { + return descendingSet().iterator(); + } + + public NavigableSet<D> descendingSet() + { + return set; + } + + public boolean equals(Object o) + { + return set.equals(o); + } + + public D first() + { + return set.last(); + } + + public D floor(D e) + { + return set.ceiling(e); + } + + public int hashCode() + { + return set.hashCode(); + } + + public SortedSet<D> headSet(D to) + { + return headSet(to, false); + } + + public NavigableSet<D> headSet(D to, boolean inclusive) + { + return new DescendingSet(set.tailSet(to, inclusive)); + } + + public D higher(D e) + { + return set.lower(e); + } + + public boolean isEmpty() + { + return set.isEmpty(); + } + + public Iterator<D> iterator() + { + return new Iterator<D>() + { + + /** The last element returned by a next() call. */ + private D last; + + /** The next element that should be returned by next(). */ + private D next = first(); + + public boolean hasNext() + { + return next != null; + } + + public D next() + { + if (next == null) + throw new NoSuchElementException(); + last = next; + next = higher(last); + + return last; + } + + public void remove() + { + if (last == null) + throw new IllegalStateException(); + + DescendingSet.this.remove(last); + last = null; + } + }; + } + + public D last() + { + return set.first(); + } + + public D lower(D e) + { + return set.higher(e); + } + + public D pollFirst() + { + return set.pollLast(); + } + + public D pollLast() + { + return set.pollFirst(); + } + + public boolean remove(Object o) + { + return set.remove(o); + } + + public boolean removeAll(Collection<?> c) + { + return set.removeAll(c); + } + + public boolean retainAll(Collection<?> c) + { + return set.retainAll(c); + } + + public int size() + { + return set.size(); + } + + public SortedSet<D> subSet(D from, D to) + { + return subSet(from, true, to, false); + } + + public NavigableSet<D> subSet(D from, boolean fromInclusive, + D to, boolean toInclusive) + { + return new DescendingSet(set.subSet(from, fromInclusive, + to, toInclusive)); + } + + public SortedSet<D> tailSet(D from) + { + return tailSet(from, true); + } + + public NavigableSet<D> tailSet(D from, boolean inclusive) + { + return new DescendingSet(set.headSet(from, inclusive)); + } + + public Object[] toArray() + { + D[] array = (D[]) set.toArray(); + Arrays.sort(array, comparator()); + return array; + } + + public <T> T[] toArray(T[] a) + { + T[] array = set.toArray(a); + Arrays.sort(array, (Comparator<? super T>) comparator()); + return array; + } + + public String toString() + { + StringBuilder r = new StringBuilder("["); + final Iterator<D> it = iterator(); + while (it.hasNext()) + { + final D o = it.next(); + if (o == this) + r.append("<this>"); + else + r.append(o); + r.append(", "); + } + r.replace(r.length() - 2, r.length(), "]"); + return r.toString(); + } + + } // class DescendingSet + + private class EntrySet + extends AbstractSet<Entry<K,V>> + { + public int size() + { + return size; + } + + public Iterator<Map.Entry<K,V>> iterator() + { + return new TreeIterator(ENTRIES); + } + + public void clear() + { + TreeMap.this.clear(); + } + + public boolean contains(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + Map.Entry<K,V> me = (Map.Entry<K,V>) o; + Node<K,V> n = getNode(me.getKey()); + return n != nil && AbstractSet.equals(me.getValue(), n.value); + } + + public boolean remove(Object o) + { + if (! (o instanceof Map.Entry)) + return false; + Map.Entry<K,V> me = (Map.Entry<K,V>) o; + Node<K,V> n = getNode(me.getKey()); + if (n != nil && AbstractSet.equals(me.getValue(), n.value)) + { + removeNode(n); + return true; + } + return false; + } + } + + private final class NavigableEntrySet + extends EntrySet + implements NavigableSet<Entry<K,V>> + { + + public Entry<K,V> ceiling(Entry<K,V> e) + { + return ceilingEntry(e.getKey()); + } + + public Comparator<? super Entry<K,V>> comparator() + { + return new Comparator<Entry<K,V>>() + { + public int compare(Entry<K,V> t1, Entry<K,V> t2) + { + return comparator.compare(t1.getKey(), t2.getKey()); + } + }; + } + + public Iterator<Entry<K,V>> descendingIterator() + { + return descendingSet().iterator(); + } + + public NavigableSet<Entry<K,V>> descendingSet() + { + return new DescendingSet(this); + } + + public Entry<K,V> first() + { + return firstEntry(); + } + + public Entry<K,V> floor(Entry<K,V> e) + { + return floorEntry(e.getKey()); + } + + public SortedSet<Entry<K,V>> headSet(Entry<K,V> to) + { + return headSet(to, false); + } + + public NavigableSet<Entry<K,V>> headSet(Entry<K,V> to, boolean inclusive) + { + return (NavigableSet<Entry<K,V>>) headMap(to.getKey(), inclusive).entrySet(); + } + + public Entry<K,V> higher(Entry<K,V> e) + { + return higherEntry(e.getKey()); + } + + public Entry<K,V> last() + { + return lastEntry(); + } + + public Entry<K,V> lower(Entry<K,V> e) + { + return lowerEntry(e.getKey()); + } + + public Entry<K,V> pollFirst() + { + return pollFirstEntry(); + } + + public Entry<K,V> pollLast() + { + return pollLastEntry(); + } + + public SortedSet<Entry<K,V>> subSet(Entry<K,V> from, Entry<K,V> to) + { + return subSet(from, true, to, false); + } + + public NavigableSet<Entry<K,V>> subSet(Entry<K,V> from, boolean fromInclusive, + Entry<K,V> to, boolean toInclusive) + { + return (NavigableSet<Entry<K,V>>) subMap(from.getKey(), fromInclusive, + to.getKey(), toInclusive).entrySet(); + } + + public SortedSet<Entry<K,V>> tailSet(Entry<K,V> from) + { + return tailSet(from, true); + } + + public NavigableSet<Entry<K,V>> tailSet(Entry<K,V> from, boolean inclusive) + { + return (NavigableSet<Entry<K,V>>) tailMap(from.getKey(), inclusive).navigableKeySet(); + } + + } // class NavigableEntrySet + } // class TreeMap diff --git a/libjava/classpath/java/util/TreeSet.java b/libjava/classpath/java/util/TreeSet.java index 2851e4a..572cda6 100644 --- a/libjava/classpath/java/util/TreeSet.java +++ b/libjava/classpath/java/util/TreeSet.java @@ -79,10 +79,10 @@ import java.io.Serializable; * @see Collections#synchronizedSortedSet(SortedSet) * @see TreeMap * @since 1.2 - * @status updated to 1.4 + * @status updated to 1.6 */ public class TreeSet<T> extends AbstractSet<T> - implements SortedSet<T>, Cloneable, Serializable + implements NavigableSet<T>, Cloneable, Serializable { /** * Compatible with JDK 1.2. @@ -90,11 +90,11 @@ public class TreeSet<T> extends AbstractSet<T> private static final long serialVersionUID = -2479143000061671589L; /** - * The SortedMap which backs this Set. + * The NavigableMap which backs this Set. */ // Not final because of readObject. This will always be one of TreeMap or // TreeMap.SubMap, which both extend AbstractMap. - private transient SortedMap<T, String> map; + private transient NavigableMap<T, String> map; /** * Construct a new TreeSet whose backing TreeMap using the "natural" @@ -163,7 +163,7 @@ public class TreeSet<T> extends AbstractSet<T> * * @param backingMap the submap */ - private TreeSet(SortedMap<T,String> backingMap) + private TreeSet(NavigableMap<T,String> backingMap) { map = backingMap; } @@ -220,7 +220,7 @@ public class TreeSet<T> extends AbstractSet<T> { copy = (TreeSet<T>) super.clone(); // Map may be either TreeMap or TreeMap.SubMap, hence the ugly casts. - copy.map = (SortedMap<T, String>) ((AbstractMap<T, String>) map).clone(); + copy.map = (NavigableMap<T, String>) ((AbstractMap<T, String>) map).clone(); } catch (CloneNotSupportedException x) { @@ -269,7 +269,9 @@ public class TreeSet<T> extends AbstractSet<T> * in one appear in the other. The subset will throw an * {@link IllegalArgumentException} for any attempt to access or add an * element beyond the specified cutoff. The returned set does not include - * the endpoint; if you want inclusion, pass the successor element. + * the endpoint; if you want inclusion, pass the successor element or + * call {@link #headSet(T,boolean)}. This call is equivalent to + * <code>headSet(to, false)</code>. * * @param to the (exclusive) cutoff point * @return a view of the set less than the cutoff @@ -280,7 +282,28 @@ public class TreeSet<T> extends AbstractSet<T> */ public SortedSet<T> headSet(T to) { - return new TreeSet<T>(map.headMap(to)); + return headSet(to, false); + } + + /** + * Returns a view of this Set including all elements less than + * (or equal to, if <code>inclusive</code> is true) <code>to</code>. + * The returned set is backed by the original, so changes + * in one appear in the other. The subset will throw an + * {@link IllegalArgumentException} for any attempt to access or add an + * element beyond the specified cutoff. + * + * @param to the cutoff point + * @param inclusive true if <code>to</code> should be included. + * @return a view of the set for the specified range. + * @throws ClassCastException if <code>to</code> is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if to is null, but the comparator does not + * tolerate null elements + */ + public NavigableSet<T> headSet(T to, boolean inclusive) + { + return new TreeSet<T>(map.headMap(to, inclusive)); } /** @@ -345,7 +368,9 @@ public class TreeSet<T> extends AbstractSet<T> * the other. The subset will throw an {@link IllegalArgumentException} * for any attempt to access or add an element beyond the specified cutoffs. * The returned set includes the low endpoint but not the high; if you want - * to reverse this behavior on either end, pass in the successor element. + * to reverse this behavior on either end, pass in the successor element + * or call {@link #subSet(T,boolean,T,boolean)}. This is equivalent to + * calling <code>subSet(from,true,to,false)</code>. * * @param from the (inclusive) low cutoff point * @param to the (exclusive) high cutoff point @@ -358,7 +383,33 @@ public class TreeSet<T> extends AbstractSet<T> */ public SortedSet<T> subSet(T from, T to) { - return new TreeSet<T>(map.subMap(from, to)); + return subSet(from, true, to, false); + } + + /** + * Returns a view of this Set including all elements greater than (or equal to, + * if <code>fromInclusive</code> is true</code> <code>from</code> and less than + * (or equal to, if <code>toInclusive</code> is true) <code>to</code>. + * The returned set is backed by the original, so changes in one appear in + * the other. The subset will throw an {@link IllegalArgumentException} + * for any attempt to access or add an element beyond the specified cutoffs. + * + * @param from the low cutoff point + * @param fromInclusive true if <code>from</code> should be included. + * @param to the high cutoff point + * @param toInclusive true if <code>to</code> should be included. + * @return a view of the set for the specified range. + * @throws ClassCastException if either cutoff is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if from or to is null, but the comparator + * does not tolerate null elements + * @throws IllegalArgumentException if from is greater than to + */ + public NavigableSet<T> subSet(T from, boolean fromInclusive, + T to, boolean toInclusive) + { + return new TreeSet<T>(map.subMap(from, fromInclusive, + to, toInclusive)); } /** @@ -367,7 +418,9 @@ public class TreeSet<T> extends AbstractSet<T> * changes in one appear in the other. The subset will throw an * {@link IllegalArgumentException} for any attempt to access or add an * element beyond the specified cutoff. The returned set includes the - * endpoint; if you want to exclude it, pass in the successor element. + * endpoint; if you want to exclude it, pass in the successor element + * or call {@link #tailSet(T,boolean)}. This is equivalent to calling + * <code>tailSet(from, true)</code>. * * @param from the (inclusive) low cutoff point * @return a view of the set above the cutoff @@ -378,7 +431,27 @@ public class TreeSet<T> extends AbstractSet<T> */ public SortedSet<T> tailSet(T from) { - return new TreeSet<T>(map.tailMap(from)); + return tailSet(from, true); + } + + /** + * Returns a view of this Set including all elements greater (or equal to, + * if <code>inclusive</code> is true) <code>from</code>. The returned set + * is backed by the original, so changes in one appear in the other. The + * subset will throw an {@link IllegalArgumentException} for any attempt + * to access or add an element beyond the specified cutoff. + * + * @param from the low cutoff point. + * @param inclusive true if <code>from</code> should be included. + * @return a view of the set for the specified range. + * @throws ClassCastException if <code>from</code> is not compatible with + * the comparator (or is not Comparable, for natural ordering) + * @throws NullPointerException if from is null, but the comparator + * does not tolerate null elements + */ + public NavigableSet<T> tailSet(T from, boolean inclusive) + { + return new TreeSet<T>(map.tailMap(from, inclusive)); } /** @@ -418,4 +491,151 @@ public class TreeSet<T> extends AbstractSet<T> map = new TreeMap<T, String>(comparator); ((TreeMap<T, String>) map).putFromObjStream(s, size, false); } + + /** + * Returns the least or lowest element in the set greater than or + * equal to the given element, or <code>null</code> if there is + * no such element. + * + * @param e the element relative to the returned element. + * @return the least element greater than or equal + * to the given element, or <code>null</code> if there is + * no such element. + * @throws ClassCastException if the specified element can not + * be compared with those in the map. + * @throws NullPointerException if the element is <code>null</code> + * and this set either uses natural + * ordering or a comparator that does + * not permit null elements. + * @since 1.6 + */ + public T ceiling(T e) + { + return map.ceilingKey(e); + } + + /** + * Returns an iterator over the elements of this set in descending + * order. This is equivalent to calling + * <code>descendingSet().iterator()</code>. + * + * @return an iterator over the elements in descending order. + * @since 1.6 + */ + public Iterator<T> descendingIterator() + { + return descendingSet().iterator(); + } + + /** + * Returns a view of the set in reverse order. The descending set + * is backed by the original set, so that changes affect both sets. + * Any changes occurring to either set while an iteration is taking + * place (with the exception of a {@link Iterator#remove()} operation) + * result in undefined behaviour from the iteration. The ordering + * of the descending set is the same as for a set with a + * {@link Comparator} given by {@link Collections#reverseOrder()}, + * and calling {@link #descendingSet()} on the descending set itself + * results in a view equivalent to the original set. + * + * @return a reverse order view of the set. + * @since 1.6 + */ + public NavigableSet<T> descendingSet() + { + return map.descendingKeySet(); + } + + /** + * Returns the greatest or highest element in the set less than or + * equal to the given element, or <code>null</code> if there is + * no such element. + * + * @param e the element relative to the returned element. + * @return the greatest element less than or equal + * to the given element, or <code>null</code> if there is + * no such element. + * @throws ClassCastException if the specified element can not + * be compared with those in the map. + * @throws NullPointerException if the element is <code>null</code> + * and this set either uses natural + * ordering or a comparator that does + * not permit null elements. + * @since 1.6 + */ + public T floor(T e) + { + return map.floorKey(e); + } + + /** + * Returns the least or lowest element in the set strictly greater + * than the given element, or <code>null</code> if there is + * no such element. + * + * @param e the element relative to the returned element. + * @return the least element greater than + * the given element, or <code>null</code> if there is + * no such element. + * @throws ClassCastException if the specified element can not + * be compared with those in the map. + * @throws NullPointerException if the element is <code>null</code> + * and this set either uses natural + * ordering or a comparator that does + * not permit null elements. + * @since 1.6 + */ + public T higher(T e) + { + return map.higherKey(e); + } + + /** + * Returns the greatest or highest element in the set strictly less + * than the given element, or <code>null</code> if there is + * no such element. + * + * @param e the element relative to the returned element. + * @return the greatest element less than + * the given element, or <code>null</code> if there is + * no such element. + * @throws ClassCastException if the specified element can not + * be compared with those in the map. + * @throws NullPointerException if the element is <code>null</code> + * and this set either uses natural + * ordering or a comparator that does + * not permit null elements. + * @since 1.6 + */ + public T lower(T e) + { + return map.lowerKey(e); + } + + /** + * Removes and returns the least or lowest element in the set, + * or <code>null</code> if the map is empty. + * + * @return the removed first element, or <code>null</code> if the + * map is empty. + * @since 1.6 + */ + public T pollFirst() + { + return map.pollFirstEntry().getKey(); + } + + /** + * Removes and returns the greatest or highest element in the set, + * or <code>null</code> if the map is empty. + * + * @return the removed last element, or <code>null</code> if the + * map is empty. + * @since 1.6 + */ + public T pollLast() + { + return map.pollLastEntry().getKey(); + } + } diff --git a/libjava/classpath/java/util/class-dependencies.conf b/libjava/classpath/java/util/class-dependencies.conf deleted file mode 100644 index 39f9606..0000000 --- a/libjava/classpath/java/util/class-dependencies.conf +++ /dev/null @@ -1,78 +0,0 @@ -# This property file contains dependencies of classes, methods, and -# field on other methods or classes. -# -# Syntax: -# -# <used>: <needed 1> [... <needed N>] -# -# means that when <used> is included, <needed 1> (... <needed N>) must -# be included as well. -# -# <needed X> and <used> are of the form -# -# <class.methodOrField(signature)> -# -# or just -# -# <class> -# -# Within dependencies, variables can be used. A variable is defined as -# follows: -# -# {variable}: value1 value2 ... value<n> -# -# variables can be used on the right side of dependencies as follows: -# -# <used>: com.bla.blu.{variable}.Class.m()V -# -# The use of the variable will expand to <n> dependencies of the form -# -# <used>: com.bla.blu.value1.Class.m()V -# <used>: com.bla.blu.value2.Class.m()V -# ... -# <used>: com.bla.blu.value<n>.Class.m()V -# -# Variables can be redefined when building a system to select the -# required support for features like encodings, protocols, etc. -# -# Hints: -# -# - For methods and fields, the signature is mandatory. For -# specification, please see the Java Virtual Machine Specification by -# SUN. Unlike in the spec, field signatures (types) are in brackets. -# -# - Package names must be separated by '/' (and not '.'). E.g., -# java/lang/Class (this is necessary, because the '.' is used to -# separate method or field names from classes) -# -# - In case <needed> refers to a class, only the class itself will be -# included in the resulting binary, NOT necessarily all its methods -# and fields. If you want to refer to all methods and fields, you can -# write class.* as an abbreviation. -# -# - Abbreviations for packages are also possible: my/package/* means all -# methods and fields of all classes in my/package. -# -# - A line with a trailing '\' continues in the next line. - - -# All calendars supported are loaded via java/util/Calendar.getBundle or -# java/util/GregorianCalendar.getBundle from class -# gnu/java/locale/Calendar_{locale_id} -# -# This introduces a dependency for the localized calendars. To allow an easy -# selection and addition of locales, the library variable {calendar_locales} -# can be set to the set of supported calendar locales. -# - -{calendar_locales}: de en nl - -java/util/Calendar.getBundle(Ljava/util/Locale;)Ljava/util/ResourceBundle;: \ - gnu/java/locale/Calendar.* \ - gnu/java/locale/Calendar_{calendar_locales}.* - -java/util/GregorianCalendar.getBundle(Ljava/util/Locale;)Ljava/util/ResourceBundle;: \ - gnu/java/locale/Calendar.* \ - gnu/java/locale/Calendar_{calendar_locales}.* - -# end of file diff --git a/libjava/classpath/java/util/concurrent/CopyOnWriteArrayList.java b/libjava/classpath/java/util/concurrent/CopyOnWriteArrayList.java index 5ef37d9..48c017f 100644 --- a/libjava/classpath/java/util/concurrent/CopyOnWriteArrayList.java +++ b/libjava/classpath/java/util/concurrent/CopyOnWriteArrayList.java @@ -349,7 +349,8 @@ public class CopyOnWriteArrayList<E> extends AbstractList<E> implements { E[] data = this.data; E[] newData = (E[]) new Object[data.length - 1]; - System.arraycopy(data, 0, newData, 0, index - 1); + if (index > 0) + System.arraycopy(data, 0, newData, 0, index - 1); System.arraycopy(data, index + 1, newData, index, data.length - index - 1); E r = data[index]; diff --git a/libjava/classpath/java/util/logging/LogManager.java b/libjava/classpath/java/util/logging/LogManager.java index fbc0fe7..6daf3db 100644 --- a/libjava/classpath/java/util/logging/LogManager.java +++ b/libjava/classpath/java/util/logging/LogManager.java @@ -1,6 +1,6 @@ /* LogManager.java -- a class for maintaining Loggers and managing configuration properties - Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc. + Copyright (C) 2002, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -446,8 +446,8 @@ public class LogManager Iterator<WeakReference<Logger>> iter = loggers.values().iterator(); while (iter.hasNext()) - for (WeakReference<Logger> ref : loggers.values()) { + WeakReference<Logger> ref; Logger logger; ref = iter.next(); @@ -559,13 +559,21 @@ public class LogManager if ("handlers".equals(key)) { - StringTokenizer tokenizer = new StringTokenizer(value); + // In Java 5 and earlier this was specified to be + // whitespace-separated, but in reality it also accepted + // commas (tomcat relied on this), and in Java 6 the + // documentation was updated to fit the implementation. + StringTokenizer tokenizer = new StringTokenizer(value, + " \t\n\r\f,"); while (tokenizer.hasMoreTokens()) { String handlerName = tokenizer.nextToken(); Handler handler = (Handler) createInstance(handlerName, Handler.class, key); - Logger.root.addHandler(handler); + // Tomcat also relies on the implementation ignoring + // items in 'handlers' which are not class names. + if (handler != null) + Logger.root.addHandler(handler); } } diff --git a/libjava/classpath/java/util/logging/Logger.java b/libjava/classpath/java/util/logging/Logger.java index 46588e5..01ef8f5 100644 --- a/libjava/classpath/java/util/logging/Logger.java +++ b/libjava/classpath/java/util/logging/Logger.java @@ -1,5 +1,5 @@ /* Logger.java -- a class for logging messages - Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2006, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -276,8 +276,8 @@ public class Logger LogManager lm = LogManager.getLogManager(); Logger result; - /* Throw NullPointerException if name is null. */ - name.getClass(); + if (name == null) + throw new NullPointerException(); /* Without synchronized(lm), it could happen that another thread * would create a logger between our calls to getLogger and @@ -1013,8 +1013,8 @@ public class Logger public synchronized void addHandler(Handler handler) throws SecurityException { - /* Throw a new NullPointerException if handler is null. */ - handler.getClass(); + if (handler == null) + throw new NullPointerException(); /* An application is allowed to control an anonymous logger * without having the permission to control the logging @@ -1057,8 +1057,8 @@ public class Logger if (!anonymous) LogManager.getLogManager().checkAccess(); - /* Throw a new NullPointerException if handler is null. */ - handler.getClass(); + if (handler == null) + throw new NullPointerException(); handlerList.remove(handler); handlers = getHandlers(); @@ -1166,8 +1166,8 @@ public class Logger */ public synchronized void setParent(Logger parent) { - /* Throw a new NullPointerException if parent is null. */ - parent.getClass(); + if (parent == null) + throw new NullPointerException(); if (this == root) throw new IllegalArgumentException( diff --git a/libjava/classpath/java/util/prefs/AbstractPreferences.java b/libjava/classpath/java/util/prefs/AbstractPreferences.java index e676dc3..f3a62e6 100644 --- a/libjava/classpath/java/util/prefs/AbstractPreferences.java +++ b/libjava/classpath/java/util/prefs/AbstractPreferences.java @@ -45,6 +45,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.TreeSet; @@ -97,17 +98,18 @@ public abstract class AbstractPreferences extends Preferences { * accessed by earlier <code>getChild()</code> or <code>childSpi()</code> * invocations and that have not been removed. */ - private HashMap childCache = new HashMap(); + private HashMap<String, AbstractPreferences> childCache + = new HashMap<String, AbstractPreferences>(); /** * A list of all the registered NodeChangeListener objects. */ - private ArrayList nodeListeners; + private ArrayList<NodeChangeListener> nodeListeners; /** * A list of all the registered PreferenceChangeListener objects. */ - private ArrayList preferenceListeners; + private ArrayList<PreferenceChangeListener> preferenceListeners; // constructor @@ -202,7 +204,8 @@ public abstract class AbstractPreferences extends Preferences { */ protected final AbstractPreferences[] cachedChildren() { - return (AbstractPreferences[]) childCache.values().toArray(); + Collection<AbstractPreferences> vals = childCache.values(); + return vals.toArray(new AbstractPreferences[vals.size()]); } /** @@ -228,7 +231,7 @@ public abstract class AbstractPreferences extends Preferences { if (isRemoved()) throw new IllegalStateException("Node removed"); - TreeSet childrenNames = new TreeSet(); + TreeSet<String> childrenNames = new TreeSet<String>(); // First get all cached node names childrenNames.addAll(childCache.keySet()); @@ -1165,7 +1168,7 @@ public abstract class AbstractPreferences extends Preferences { if (listener == null) throw new NullPointerException("listener is null"); if (nodeListeners == null) - nodeListeners = new ArrayList(); + nodeListeners = new ArrayList<NodeChangeListener>(); nodeListeners.add(listener); } } @@ -1184,7 +1187,7 @@ public abstract class AbstractPreferences extends Preferences { if (listener == null) throw new NullPointerException("listener is null"); if (preferenceListeners == null) - preferenceListeners = new ArrayList(); + preferenceListeners = new ArrayList<PreferenceChangeListener>(); preferenceListeners.add(listener); } } diff --git a/libjava/classpath/java/util/prefs/Preferences.java b/libjava/classpath/java/util/prefs/Preferences.java index e53e4fc..e8cdda8 100644 --- a/libjava/classpath/java/util/prefs/Preferences.java +++ b/libjava/classpath/java/util/prefs/Preferences.java @@ -183,9 +183,9 @@ public abstract class Preferences { // Get the factory if (factory == null) { // Caller might not have enough permissions - factory = (PreferencesFactory) AccessController.doPrivileged( - new PrivilegedAction() { - public Object run() { + factory = AccessController.doPrivileged( + new PrivilegedAction<PreferencesFactory>() { + public PreferencesFactory run() { PreferencesFactory pf = null; String className = System.getProperty ("java.util.prefs.PreferencesFactory"); diff --git a/libjava/classpath/java/util/regex/Pattern.java b/libjava/classpath/java/util/regex/Pattern.java index d716fa4..217ce08 100644 --- a/libjava/classpath/java/util/regex/Pattern.java +++ b/libjava/classpath/java/util/regex/Pattern.java @@ -1,5 +1,5 @@ /* Pattern.java -- Compiled regular expression ready to be applied. - Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -246,7 +246,7 @@ public final class Pattern implements Serializable { String t = input.subSequence(start, input.length()).toString(); if ("".equals(t) && limit == 0) - ; // Don't add. + { /* Don't add. */ } else list.add(t); } @@ -260,4 +260,14 @@ public final class Pattern implements Serializable { return regex; } + + /** + * Return the regular expression used to construct this object. + * @specnote Prior to JDK 1.5 this method had a different behavior + * @since 1.5 + */ + public String toString() + { + return regex; + } } diff --git a/libjava/classpath/java/util/spi/CurrencyNameProvider.java b/libjava/classpath/java/util/spi/CurrencyNameProvider.java new file mode 100644 index 0000000..14fae4d --- /dev/null +++ b/libjava/classpath/java/util/spi/CurrencyNameProvider.java @@ -0,0 +1,100 @@ +/* CurrencyNameProvider.java -- Providers of localized currency symbols + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.spi; + +import java.util.Locale; + +/** + * A {@link CurrencyNameProvider} provides localized + * versions of the symbols that represent a particular + * currency. Note that currency symbols are regarded + * as names, and thus a <code>null</code> value may + * be returned, which should be treated as a lack of + * support for the specified {@link Locale}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ +public abstract class CurrencyNameProvider + extends LocaleServiceProvider +{ + + /** + * Constructs a new {@link CurrencyNameProvider}. + * Provided for implicit invocation by subclasses. + */ + protected CurrencyNameProvider() + { + } + + /** + * <p> + * This method returns the symbol which precedes or follows a + * value in this particular currency. The returned value is + * the symbol used to denote the currency in the specified locale. + * </p> + * <p> + * For example, a supplied locale may specify a different symbol + * for the currency, due to conflicts with its own currency. + * This would be the case with the American currency, the dollar. + * Locales that also use a dollar-based currency (e.g. Canada, Australia) + * need to differentiate the American dollar using 'US$' rather than '$'. + * So, supplying one of these locales to <code>getSymbol()</code> would + * return this value, rather than the standard '$'. + * </p> + * <p> + * In cases where there is no such symbol for a particular currency, + * <code>null</code> should be returned. + * </p> + * + * @param currencyCode the ISO 4217 currency code, consisting + * of three uppercase letters from 'A' to 'Z' + * @param locale the locale to express the symbol in. + * @return the currency symbol, or <code>null</code> if one is + * unavailable. + * @throws NullPointerException if the locale is null. + * @throws IllegalArgumentException if the currency code is + * not in the correct format + * or the locale is not one + * returned by + * {@link getAvailableLocales()} + * @see java.util.Currency#getSymbol(java.util.Locale) + */ + public abstract String getSymbol(String currencyCode, Locale locale); + +} diff --git a/libjava/classpath/java/util/spi/LocaleNameProvider.java b/libjava/classpath/java/util/spi/LocaleNameProvider.java new file mode 100644 index 0000000..dfd2e4c --- /dev/null +++ b/libjava/classpath/java/util/spi/LocaleNameProvider.java @@ -0,0 +1,135 @@ +/* LocaleNameProvider.java -- Providers of localized locale names + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.spi; + +import java.util.Locale; + +/** + * A {@link LocaleNameProvider} provides localized + * versions of the names that represent a particular + * locale. Note that a <code>null</code> value may + * be returned, which should be treated as a lack of + * support for the specified {@link Locale}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ +public abstract class LocaleNameProvider + extends LocaleServiceProvider +{ + + /** + * Constructs a new {@link LocaleNameProvider}. + * Provided for implicit invocation by subclasses. + */ + protected LocaleNameProvider() + { + } + + /** + * Returns the localized name for the specified ISO 3166 + * country in the supplied {@link java.util.Locale}. + * For example, if the country code is <code>"DE"</code>, + * this method will return <code>"Germany"</code> for + * {@link Locale.ENGLISH} but <code>"Deutschland"</code> + * for {@link Locale.GERMANY}. If the name of the country + * in the given locale is not supported, <code>null</code> + * is returned. + * + * @param countryCode the ISO 3166 country code, consisting + * of two uppercase letters from 'A' to 'Z' + * @param locale the locale to express the country in. + * @return the country name, or <code>null</code> if one is + * not available. + * @throws NullPointerException if the locale is null. + * @throws IllegalArgumentException if the country code is + * not in the correct format + * or the locale is not one + * returned by + * {@link getAvailableLocales()} + * @see java.util.Locale#getDisplayCountry(java.util.Locale) + */ + public abstract String getDisplayCountry(String countryCode, + Locale locale); + + /** + * Returns the localized name for the specified ISO 639 + * language in the supplied {@link java.util.Locale}. + * For example, if the language code is <code>"de"</code>, + * this method will return <code>"German"</code> for + * {@link Locale.ENGLISH} but <code>"Deutsch"</code> + * for {@link Locale.GERMANY}. If the name of the language + * in the given locale is not supported, <code>null</code> + * is returned. + * + * @param langCode the ISO 639 language code, consisting + * of two lowercase letters from 'a' to 'z' + * @param locale the locale to express the language in. + * @return the country name, or <code>null</code> if one is + * not available. + * @throws NullPointerException if the locale is null. + * @throws IllegalArgumentException if the language code is + * not in the correct format + * or the locale is not one + * returned by + * {@link getAvailableLocales()} + * @see java.util.Locale#getDisplayLanguage(java.util.Locale) + */ + public abstract String getDisplayLanguage(String langCode, + Locale locale); + + /** + * Returns the localized name for the specified variant + * in the supplied {@link java.util.Locale}. If the name + * of the variant in the given locale is not supported, + * <code>null</code> is returned. + * + * @param variant the variant. + * @param locale the locale to express the variant in. + * @return the localized variant, or <code>null</code> if one is + * not available. + * @throws NullPointerException if the locale is null. + * @throws IllegalArgumentException if the locale is not one + * returned by + * {@link getAvailableLocales()} + * @see java.util.Locale#getDisplayVariant(java.util.Locale) + */ + public abstract String getDisplayVariant(String variant, + Locale locale); + +} diff --git a/libjava/classpath/java/util/spi/LocaleServiceProvider.java b/libjava/classpath/java/util/spi/LocaleServiceProvider.java new file mode 100644 index 0000000..bb5b685 --- /dev/null +++ b/libjava/classpath/java/util/spi/LocaleServiceProvider.java @@ -0,0 +1,125 @@ +/* LocaleServiceProvider.java -- Superclass of locale SPIs + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.spi; + +import java.util.Locale; + +/** + * <p> + * This is the superclass of all the {@link Locale} service + * provider interfaces or SPIs. The locale SPIs are used + * to allow for the provision of additional support for + * locale-specific data. The runtime environment has its + * own collection of locale data, but these interfaces allow + * this to be extended by external classes. + * </p> + * <p> + * Service providers are created as concrete implementations + * of these interfaces, and accessed using the extension + * mechanism, realised by {@link ServiceLoader}. When a factory + * method of one of the locale-specific classes (such as + * {@link java.text.DateFormatSymbols} or {@link java.util.Currency}) + * is called, the runtime environment is first asked to + * provide data for the specified locale. If the runtime + * environment fails to provide this, then the offer is + * made to service providers which implement the appropriate + * interface. + * </p> + * <p> + * Each provider implements the method specified by this + * class, {@link #getAvailableLocales()}. This method is + * called first to determine whether the provider will be of + * any use in providing data for the specified locale. If + * a provider is found to be capable, then a more specific + * method appropriate to the class requiring the data will + * be called. In the case of {@link java.text.DateFormatSymbols}, + * this would be + * {@link java.text.spi.DateFormatSymbols#getInstance(Locale)}. + * </p> + * <p> + * If neither a service provider nor the runtime environment + * itself can fulfill the request, a fallback procedure is + * engaged. The locale is modified by applying the first + * applicable rule: + * </p> + * <ol> + * <li>If the variant contains a <code>'_'</code>, then + * this and everything following it is trimmed.</li> + * <li>If the variant is non-empty, it is converted to + * an empty string.</li> + * <li>If the country is non-empty, it is converted to + * an empty string.</li> + * <li>If the language is non-empty, it is converted to + * an empty string.</li> + * </ol> + * <p> + * The modified locale is then used to start the same + * process again. The root locale (@link java.util.Locale#ROOT} + * must be supported by the runtime environment in order + * to terminate this cycle. + * </p> + * <p> + * Note that any names returned by the providers may + * be <code>null</code>. Returning a <code>null</code> + * name is considered equivalent to not supporting a + * particular locale. + * </p> + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ +public abstract class LocaleServiceProvider +{ + + /** + * Constructs a new {@link LocaleServiceProvider}. + * Provided for implicit invocation by subclasses. + */ + protected LocaleServiceProvider() + { + } + + /** + * Returns an array of {@link Locale} instances, + * for which the provider can supply localized data. + * + * @return an array of supported locales. + */ + public abstract Locale[] getAvailableLocales(); + +} diff --git a/libjava/classpath/java/util/spi/TimeZoneNameProvider.java b/libjava/classpath/java/util/spi/TimeZoneNameProvider.java new file mode 100644 index 0000000..2815670 --- /dev/null +++ b/libjava/classpath/java/util/spi/TimeZoneNameProvider.java @@ -0,0 +1,97 @@ +/* TimeZoneNameProvider.java -- Providers of localized currency symbols + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.spi; + +import java.util.Locale; + +/** + * A {@link TimeZoneNameProvider} provides localized + * versions of the names that represent a particular + * timezone. A <code>null</code> value may + * be returned, which should be treated as a lack of + * support for the specified {@link Locale}. The names + * from this class are also used by + * {@link DateFormatSymbols#getZoneStrings()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ +public abstract class TimeZoneNameProvider + extends LocaleServiceProvider +{ + + /** + * Constructs a new {@link TimeZoneNameProvider}. + * Provided for implicit invocation by subclasses. + */ + protected TimeZoneNameProvider() + { + } + + /** + * Returns a name for the specified time zone identifier + * localized to the supplied {@link java.util.Locale}. + * The time zone identifier is either <code>"GMT"</code> + * or one of the identifiers from the public domain "tz + * database" found at <a href="ftp://elsie.nci.nih.gov/pub/"> + * ftp://elsie.nci.nih.gov/pub</a>. Note that a translated + * name for the daylight savings time variant should be returned, + * even if the timezone has not observed daylight savings + * time in the past. If the name of the timezone + * in the given locale is not supported, <code>null</code> + * is returned. + * + * @param id a time zone identifier. + * @param daylight true if the daylight savings time variant + * should be returned. + * @param style either {@link java.util.TimeZone.LONG} or + * {@link java.util.TimeZone.SHORT} + * @param locale the locale to express the timezone in. + * @return the localized time zone name, or <code>null</code> + * if one is not available. + * @throws NullPointerException if the identifer or locale is null. + * @throws IllegalArgumentException if the style is invalid + * or the locale is not one + * returned by + * {@link getAvailableLocales()} + * @see java.util.TimeZone#getDisplayName(boolean,int,java.util.Locale) + */ + public abstract String getDisplayName(String id, boolean daylight, + int style, Locale locale); + +} diff --git a/libjava/classpath/java/util/spi/package.html b/libjava/classpath/java/util/spi/package.html new file mode 100644 index 0000000..1abdeb8 --- /dev/null +++ b/libjava/classpath/java/util/spi/package.html @@ -0,0 +1,50 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in java.util.spi package. + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath 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 for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. --> + +<html> +<head><title>GNU Classpath - java.util.spi</title></head> + +<body> + +<p> +A series of service provider interfaces for use by the +classes in <code>java.util</code>. +</p> +<p><span style="font-weight: bold;">Since</span>: 1.6</p> +</body> +</html> diff --git a/libjava/classpath/java/util/zip/DeflaterEngine.java b/libjava/classpath/java/util/zip/DeflaterEngine.java index 5158716..38a82d8 100644 --- a/libjava/classpath/java/util/zip/DeflaterEngine.java +++ b/libjava/classpath/java/util/zip/DeflaterEngine.java @@ -377,7 +377,8 @@ class DeflaterEngine implements DeflaterConstants && window[++scan] == window[++match] && window[++scan] == window[++match] && window[++scan] == window[++match] - && scan < strend); + && scan < strend) + ; if (scan > best_end) { // if (DeflaterConstants.DEBUGGING && ins_h == 0) diff --git a/libjava/classpath/java/util/zip/ZipInputStream.java b/libjava/classpath/java/util/zip/ZipInputStream.java index 4539828..df44bb3 100644 --- a/libjava/classpath/java/util/zip/ZipInputStream.java +++ b/libjava/classpath/java/util/zip/ZipInputStream.java @@ -238,6 +238,7 @@ public class ZipInputStream extends InflaterInputStream implements ZipConstants byte[] tmp = new byte[2048]; while (read(tmp) > 0) ; + /* read will close this entry */ return; } |