diff options
Diffstat (limited to 'libjava/classpath/java/util/TreeMap.java')
-rw-r--r-- | libjava/classpath/java/util/TreeMap.java | 3322 |
1 files changed, 3322 insertions, 0 deletions
diff --git a/libjava/classpath/java/util/TreeMap.java b/libjava/classpath/java/util/TreeMap.java new file mode 100644 index 000000000..87c532fc1 --- /dev/null +++ b/libjava/classpath/java/util/TreeMap.java @@ -0,0 +1,3322 @@ +/* TreeMap.java -- a class providing a basic Red-Black Tree data structure, + mapping Object --> Object + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006 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; + +import gnu.java.lang.CPStringBuilder; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * This class provides a red-black tree implementation of the SortedMap + * interface. Elements in the Map will be sorted by either a user-provided + * Comparator object, or by the natural ordering of the keys. + * + * The algorithms are adopted from Corman, Leiserson, and Rivest's + * <i>Introduction to Algorithms.</i> TreeMap guarantees O(log n) + * insertion and deletion of elements. That being said, there is a large + * enough constant coefficient in front of that "log n" (overhead involved + * in keeping the tree balanced), that TreeMap may not be the best choice + * for small collections. If something is already sorted, you may want to + * just use a LinkedHashMap to maintain the order while providing O(1) access. + * + * TreeMap is a part of the JDK1.2 Collections API. Null keys are allowed + * only if a Comparator is used which can deal with them; natural ordering + * cannot cope with null. Null values are always allowed. Note that the + * ordering must be <i>consistent with equals</i> to correctly implement + * the Map interface. If this condition is violated, the map is still + * well-behaved, but you may have suprising results when comparing it to + * other maps.<p> + * + * This implementation is not synchronized. If you need to share this between + * multiple threads, do something like:<br> + * <code>SortedMap m + * = Collections.synchronizedSortedMap(new TreeMap(...));</code><p> + * + * The iterators are <i>fail-fast</i>, meaning that any structural + * modification, except for <code>remove()</code> called on the iterator + * itself, cause the iterator to throw a + * <code>ConcurrentModificationException</code> rather than exhibit + * non-deterministic behavior. + * + * @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 + * @see LinkedHashMap + * @see Comparable + * @see Comparator + * @see Collection + * @see Collections#synchronizedSortedMap(SortedMap) + * @since 1.2 + * @status updated to 1.6 + */ +public class TreeMap<K, V> extends AbstractMap<K, V> + implements NavigableMap<K, V>, Cloneable, Serializable +{ + // Implementation note: + // A red-black tree is a binary search tree with the additional properties + // that all paths to a leaf node visit the same number of black nodes, + // and no red node has red children. To avoid some null-pointer checks, + // we use the special node nil which is always black, has no relatives, + // and has key and value of null (but is not equal to a mapping of null). + + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = 919286545866124006L; + + /** + * Color status of a node. Package visible for use by nested classes. + */ + static final int RED = -1, + BLACK = 1; + + /** + * Sentinal node, used to avoid null checks for corner cases and make the + * delete rebalance code simpler. The rebalance code must never assign + * the parent, left, or right of nil, but may safely reassign the color + * to be black. This object must never be used as a key in a TreeMap, or + * it will break bounds checking of a SubMap. + */ + static final Node nil = new Node(null, null, BLACK); + static + { + // Nil is self-referential, so we must initialize it after creation. + nil.parent = nil; + nil.left = nil; + nil.right = nil; + } + + /** + * The root node of this TreeMap. + */ + private transient Node root; + + /** + * The size of this TreeMap. Package visible for use by nested classes. + */ + transient int size; + + /** + * The cache for {@link #entrySet()}. + */ + 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. + */ + transient int modCount; + + /** + * This TreeMap's comparator, or null for natural ordering. + * Package visible for use by nested classes. + * @serial the comparator ordering this tree, or null + */ + final Comparator<? super K> comparator; + + /** + * Class to represent an entry in the tree. Holds a single key-value pair, + * plus pointers to parent and child nodes. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private static final class Node<K, V> extends AbstractMap.SimpleEntry<K, V> + { + // All fields package visible for use by nested classes. + /** The color of this node. */ + int color; + + /** The left child node. */ + Node<K, V> left = nil; + /** The right child node. */ + Node<K, V> right = nil; + /** The parent node. */ + Node<K, V> parent = nil; + + /** + * Simple constructor. + * @param key the key + * @param value the value + */ + Node(K key, V value, int color) + { + super(key, value); + this.color = color; + } + } + + /** + * Instantiate a new TreeMap with no elements, using the keys' natural + * ordering to sort. All entries in the map must have a key which implements + * Comparable, and which are <i>mutually comparable</i>, otherwise map + * operations may throw a {@link ClassCastException}. Attempts to use + * a null key will throw a {@link NullPointerException}. + * + * @see Comparable + */ + public TreeMap() + { + this((Comparator) null); + } + + /** + * Instantiate a new TreeMap with no elements, using the provided comparator + * to sort. All entries in the map must have keys which are mutually + * comparable by the Comparator, otherwise map operations may throw a + * {@link ClassCastException}. + * + * @param c the sort order for the keys of this map, or null + * for the natural order + */ + public TreeMap(Comparator<? super K> c) + { + comparator = c; + fabricateTree(0); + } + + /** + * Instantiate a new TreeMap, initializing it with all of the elements in + * the provided Map. The elements will be sorted using the natural + * ordering of the keys. This algorithm runs in n*log(n) time. All entries + * in the map must have keys which implement Comparable and are mutually + * comparable, otherwise map operations may throw a + * {@link ClassCastException}. + * + * @param map a Map, whose entries will be put into this TreeMap + * @throws ClassCastException if the keys in the provided Map are not + * comparable + * @throws NullPointerException if map is null + * @see Comparable + */ + public TreeMap(Map<? extends K, ? extends V> map) + { + this((Comparator) null); + putAll(map); + } + + /** + * Instantiate a new TreeMap, initializing it with all of the elements in + * the provided SortedMap. The elements will be sorted using the same + * comparator as in the provided SortedMap. This runs in linear time. + * + * @param sm a SortedMap, whose entries will be put into this TreeMap + * @throws NullPointerException if sm is null + */ + public TreeMap(SortedMap<K, ? extends V> sm) + { + this(sm.comparator()); + int pos = sm.size(); + Iterator itr = sm.entrySet().iterator(); + + fabricateTree(pos); + Node node = firstNode(); + + while (--pos >= 0) + { + Map.Entry me = (Map.Entry) itr.next(); + node.key = me.getKey(); + node.value = me.getValue(); + node = successor(node); + } + } + + /** + * Clears the Map so it has no keys. This is O(1). + */ + public void clear() + { + if (size > 0) + { + modCount++; + root = nil; + size = 0; + } + } + + /** + * Returns a shallow clone of this TreeMap. The Map itself is cloned, + * but its contents are not. + * + * @return the clone + */ + public Object clone() + { + TreeMap copy = null; + try + { + copy = (TreeMap) super.clone(); + } + catch (CloneNotSupportedException x) + { + } + copy.entries = null; + copy.fabricateTree(size); + + Node node = firstNode(); + Node cnode = copy.firstNode(); + + while (node != nil) + { + cnode.key = node.key; + cnode.value = node.value; + node = successor(node); + cnode = copy.successor(cnode); + } + return copy; + } + + /** + * Return the comparator used to sort this map, or null if it is by + * natural order. + * + * @return the map's comparator + */ + public Comparator<? super K> comparator() + { + return comparator; + } + + /** + * Returns true if the map contains a mapping for the given key. + * + * @param key the key to look for + * @return true if the key has a mapping + * @throws ClassCastException if key is not comparable to map elements + * @throws NullPointerException if key is null and the comparator is not + * tolerant of nulls + */ + public boolean containsKey(Object key) + { + return getNode((K) key) != nil; + } + + /** + * Returns true if the map contains at least one mapping to the given value. + * This requires linear time. + * + * @param value the value to look for + * @return true if the value appears in a mapping + */ + public boolean containsValue(Object value) + { + Node node = firstNode(); + while (node != nil) + { + if (equals(value, node.value)) + return true; + node = successor(node); + } + return false; + } + + /** + * Returns a "set view" of this TreeMap's entries. The set is backed by + * the TreeMap, so changes in one show up in the other. The set supports + * element removal, but not element addition.<p> + * + * Note that the iterators for all three views, from keySet(), entrySet(), + * and values(), traverse the TreeMap in sorted sequence. + * + * @return a set view of the entries + * @see #keySet() + * @see #values() + * @see Map.Entry + */ + 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 NavigableEntrySet(); + return entries; + } + + /** + * Returns the first (lowest) key in the map. + * + * @return the first key + * @throws NoSuchElementException if the map is empty + */ + public K firstKey() + { + if (root == nil) + throw new NoSuchElementException(); + return firstNode().key; + } + + /** + * Return the value in this TreeMap associated with the supplied key, + * or <code>null</code> if the key maps to nothing. NOTE: Since the value + * could also be null, you must use containsKey to see if this key + * actually maps to something. + * + * @param key the key for which to fetch an associated value + * @return what the key maps to, if present + * @throws ClassCastException if key is not comparable to elements in the map + * @throws NullPointerException if key is null but the comparator does not + * tolerate nulls + * @see #put(Object, Object) + * @see #containsKey(Object) + */ + public V get(Object key) + { + // Exploit fact that nil.value == null. + return getNode((K) key).value; + } + + /** + * Returns a view of this Map including all entries with keys less than + * <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. The returned map does not include + * 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 + * @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 SortedMap<K, V> headMap(K 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); + } + + /** + * Returns a "set view" of this TreeMap's keys. The set is backed by the + * TreeMap, so changes in one show up in the other. The set supports + * element removal, but not element addition. + * + * @return a set view of the keys + * @see #values() + * @see #entrySet() + */ + public Set<K> keySet() + { + if (keys == null) + // Create an AbstractSet with custom implementations of those methods + // that can be overriden easily and efficiently. + keys = new KeySet(); + return keys; + } + + /** + * Returns the last (highest) key in the map. + * + * @return the last key + * @throws NoSuchElementException if the map is empty + */ + public K lastKey() + { + if (root == nil) + throw new NoSuchElementException("empty"); + return lastNode().key; + } + + /** + * Puts the supplied value into the Map, mapped by the supplied key. + * The value may be retrieved by any object which <code>equals()</code> + * this key. NOTE: Since the prior value could also be null, you must + * first use containsKey if you want to see if you are replacing the + * key's mapping. + * + * @param key the key used to locate the value + * @param value the value to be stored in the Map + * @return the prior mapping of the key, or null if there was none + * @throws ClassCastException if key is not comparable to current map keys + * @throws NullPointerException if key is null, but the comparator does + * not tolerate nulls + * @see #get(Object) + * @see Object#equals(Object) + */ + public V put(K key, V value) + { + Node<K,V> current = root; + Node<K,V> parent = nil; + int comparison = 0; + + // Find new node's parent. + while (current != nil) + { + parent = current; + comparison = compare(key, current.key); + if (comparison > 0) + current = current.right; + else if (comparison < 0) + current = current.left; + else // Key already in tree. + return current.setValue(value); + } + + // Set up new node. + Node n = new Node(key, value, RED); + n.parent = parent; + + // Insert node in tree. + modCount++; + size++; + if (parent == nil) + { + // Special case inserting into an empty tree. + root = n; + return null; + } + if (comparison > 0) + parent.right = n; + else + parent.left = n; + + // Rebalance after insert. + insertFixup(n); + return null; + } + + /** + * Copies all elements of the given map into this TreeMap. If this map + * already has a mapping for a key, the new mapping replaces the current + * one. + * + * @param m the map to be added + * @throws ClassCastException if a key in m is not comparable with keys + * in the map + * @throws NullPointerException if a key in m is null, and the comparator + * does not tolerate nulls + */ + public void putAll(Map<? extends K, ? extends V> m) + { + Iterator itr = m.entrySet().iterator(); + int pos = m.size(); + while (--pos >= 0) + { + Map.Entry<K,V> e = (Map.Entry<K,V>) itr.next(); + put(e.getKey(), e.getValue()); + } + } + + /** + * Removes from the TreeMap and returns the value which is mapped by the + * supplied key. If the key maps to nothing, then the TreeMap remains + * unchanged, and <code>null</code> is returned. NOTE: Since the value + * could also be null, you must use containsKey to see if you are + * actually removing a mapping. + * + * @param key the key used to locate the value to remove + * @return whatever the key mapped to, if present + * @throws ClassCastException if key is not comparable to current map keys + * @throws NullPointerException if key is null, but the comparator does + * not tolerate nulls + */ + public V remove(Object key) + { + Node<K, V> n = getNode((K)key); + if (n == nil) + return null; + // Note: removeNode can alter the contents of n, so save value now. + V result = n.value; + removeNode(n); + return result; + } + + /** + * Returns the number of key-value mappings currently in this Map. + * + * @return the size + */ + public int size() + { + return size; + } + + /** + * Returns a view of this Map including all entries with keys greater or + * equal to <code>fromKey</code> and less than <code>toKey</code> (a + * half-open interval). 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. 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 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 + * @return a view of the map between the cutoffs + * @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 SortedMap<K, V> subMap(K fromKey, K 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); + } + + /** + * 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. + * 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 + * @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 SortedMap<K, V> tailMap(K fromKey) + { + 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); + } + + /** + * Returns a "collection view" (or "bag view") of this TreeMap's values. + * The collection is backed by the TreeMap, so changes in one show up + * in the other. The collection supports element removal, but not element + * addition. + * + * @return a bag view of the values + * @see #keySet() + * @see #entrySet() + */ + public Collection<V> values() + { + if (values == null) + // We don't bother overriding many of the optional methods, as doing so + // wouldn't provide any significant performance advantage. + values = new AbstractCollection<V>() + { + public int size() + { + return size; + } + + public Iterator<V> iterator() + { + return new TreeIterator(VALUES); + } + + public void clear() + { + TreeMap.this.clear(); + } + }; + return values; + } + + /** + * Compares two elements by the set comparator, or by natural ordering. + * Package visible for use by nested classes. + * + * @param o1 the first object + * @param o2 the second object + * @throws ClassCastException if o1 and o2 are not mutually comparable, + * or are not Comparable with natural ordering + * @throws NullPointerException if o1 or o2 is null with natural ordering + */ + final int compare(K o1, K o2) + { + return (comparator == null + ? ((Comparable) o1).compareTo(o2) + : comparator.compare(o1, o2)); + } + + /** + * Maintain red-black balance after deleting a node. + * + * @param node the child of the node just deleted, possibly nil + * @param parent the parent of the node just deleted, never nil + */ + private void deleteFixup(Node<K,V> node, Node<K,V> parent) + { + // if (parent == nil) + // throw new InternalError(); + // If a black node has been removed, we need to rebalance to avoid + // violating the "same number of black nodes on any path" rule. If + // node is red, we can simply recolor it black and all is well. + while (node != root && node.color == BLACK) + { + if (node == parent.left) + { + // Rebalance left side. + Node<K,V> sibling = parent.right; + // if (sibling == nil) + // throw new InternalError(); + if (sibling.color == RED) + { + // Case 1: Sibling is red. + // Recolor sibling and parent, and rotate parent left. + sibling.color = BLACK; + parent.color = RED; + rotateLeft(parent); + sibling = parent.right; + } + + if (sibling.left.color == BLACK && sibling.right.color == BLACK) + { + // Case 2: Sibling has no red children. + // Recolor sibling, and move to parent. + sibling.color = RED; + node = parent; + parent = parent.parent; + } + else + { + if (sibling.right.color == BLACK) + { + // Case 3: Sibling has red left child. + // Recolor sibling and left child, rotate sibling right. + sibling.left.color = BLACK; + sibling.color = RED; + rotateRight(sibling); + sibling = parent.right; + } + // Case 4: Sibling has red right child. Recolor sibling, + // right child, and parent, and rotate parent left. + sibling.color = parent.color; + parent.color = BLACK; + sibling.right.color = BLACK; + rotateLeft(parent); + node = root; // Finished. + } + } + else + { + // Symmetric "mirror" of left-side case. + Node<K,V> sibling = parent.left; + // if (sibling == nil) + // throw new InternalError(); + if (sibling.color == RED) + { + // Case 1: Sibling is red. + // Recolor sibling and parent, and rotate parent right. + sibling.color = BLACK; + parent.color = RED; + rotateRight(parent); + sibling = parent.left; + } + + if (sibling.right.color == BLACK && sibling.left.color == BLACK) + { + // Case 2: Sibling has no red children. + // Recolor sibling, and move to parent. + sibling.color = RED; + node = parent; + parent = parent.parent; + } + else + { + if (sibling.left.color == BLACK) + { + // Case 3: Sibling has red right child. + // Recolor sibling and right child, rotate sibling left. + sibling.right.color = BLACK; + sibling.color = RED; + rotateLeft(sibling); + sibling = parent.left; + } + // Case 4: Sibling has red left child. Recolor sibling, + // left child, and parent, and rotate parent right. + sibling.color = parent.color; + parent.color = BLACK; + sibling.left.color = BLACK; + rotateRight(parent); + node = root; // Finished. + } + } + } + node.color = BLACK; + } + + /** + * Construct a perfectly balanced tree consisting of n "blank" nodes. This + * permits a tree to be generated from pre-sorted input in linear time. + * + * @param count the number of blank nodes, non-negative + */ + private void fabricateTree(final int count) + { + if (count == 0) + { + root = nil; + size = 0; + return; + } + + // We color every row of nodes black, except for the overflow nodes. + // I believe that this is the optimal arrangement. We construct the tree + // in place by temporarily linking each node to the next node in the row, + // then updating those links to the children when working on the next row. + + // Make the root node. + root = new Node(null, null, BLACK); + size = count; + Node row = root; + int rowsize; + + // Fill each row that is completely full of nodes. + for (rowsize = 2; rowsize + rowsize <= count; rowsize <<= 1) + { + Node parent = row; + Node last = null; + for (int i = 0; i < rowsize; i += 2) + { + Node left = new Node(null, null, BLACK); + Node right = new Node(null, null, BLACK); + left.parent = parent; + left.right = right; + right.parent = parent; + parent.left = left; + Node next = parent.right; + parent.right = right; + parent = next; + if (last != null) + last.right = left; + last = right; + } + row = row.left; + } + + // Now do the partial final row in red. + int overflow = count - rowsize; + Node parent = row; + int i; + for (i = 0; i < overflow; i += 2) + { + Node left = new Node(null, null, RED); + Node right = new Node(null, null, RED); + left.parent = parent; + right.parent = parent; + parent.left = left; + Node next = parent.right; + parent.right = right; + parent = next; + } + // Add a lone left node if necessary. + if (i - overflow == 0) + { + Node left = new Node(null, null, RED); + left.parent = parent; + parent.left = left; + parent = parent.right; + left.parent.right = nil; + } + // Unlink the remaining nodes of the previous row. + while (parent != nil) + { + Node next = parent.right; + parent.right = nil; + parent = next; + } + } + + /** + * Returns the first sorted node in the map, or nil if empty. Package + * visible for use by nested classes. + * + * @return the first node + */ + final Node<K, V> firstNode() + { + // Exploit fact that nil.left == nil. + Node node = root; + while (node.left != nil) + node = node.left; + return node; + } + + /** + * Return the TreeMap.Node associated with key, or the nil node if no such + * node exists in the tree. Package visible for use by nested classes. + * + * @param key the key to search for + * @return the node where the key is found, or nil + */ + final Node<K, V> getNode(K key) + { + Node<K,V> current = root; + while (current != nil) + { + int comparison = compare(key, current.key); + if (comparison > 0) + current = current.right; + else if (comparison < 0) + current = current.left; + else + return current; + } + return current; + } + + /** + * Find the "highest" node which is < key. If key is nil, return last + * node. Package visible for use by nested classes. + * + * @param key the upper bound, exclusive + * @return the previous node + */ + 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(); + + Node<K,V> last = nil; + Node<K,V> current = root; + int comparison = 0; + + while (current != nil) + { + last = current; + comparison = compare(key, current.key); + if (comparison > 0) + current = current.right; + else if (comparison < 0) + current = current.left; + else // Exact match. + return (equal ? last : predecessor(last)); + } + return comparison < 0 ? predecessor(last) : last; + } + + /** + * Maintain red-black balance after inserting a new node. + * + * @param n the newly inserted node + */ + private void insertFixup(Node<K,V> n) + { + // Only need to rebalance when parent is a RED node, and while at least + // 2 levels deep into the tree (ie: node has a grandparent). Remember + // that nil.color == BLACK. + while (n.parent.color == RED && n.parent.parent != nil) + { + if (n.parent == n.parent.parent.left) + { + Node uncle = n.parent.parent.right; + // Uncle may be nil, in which case it is BLACK. + if (uncle.color == RED) + { + // Case 1. Uncle is RED: Change colors of parent, uncle, + // and grandparent, and move n to grandparent. + n.parent.color = BLACK; + uncle.color = BLACK; + uncle.parent.color = RED; + n = uncle.parent; + } + else + { + if (n == n.parent.right) + { + // Case 2. Uncle is BLACK and x is right child. + // Move n to parent, and rotate n left. + n = n.parent; + rotateLeft(n); + } + // Case 3. Uncle is BLACK and x is left child. + // Recolor parent, grandparent, and rotate grandparent right. + n.parent.color = BLACK; + n.parent.parent.color = RED; + rotateRight(n.parent.parent); + } + } + else + { + // Mirror image of above code. + Node uncle = n.parent.parent.left; + // Uncle may be nil, in which case it is BLACK. + if (uncle.color == RED) + { + // Case 1. Uncle is RED: Change colors of parent, uncle, + // and grandparent, and move n to grandparent. + n.parent.color = BLACK; + uncle.color = BLACK; + uncle.parent.color = RED; + n = uncle.parent; + } + else + { + if (n == n.parent.left) + { + // Case 2. Uncle is BLACK and x is left child. + // Move n to parent, and rotate n right. + n = n.parent; + rotateRight(n); + } + // Case 3. Uncle is BLACK and x is right child. + // Recolor parent, grandparent, and rotate grandparent left. + n.parent.color = BLACK; + n.parent.parent.color = RED; + rotateLeft(n.parent.parent); + } + } + } + root.color = BLACK; + } + + /** + * Returns the last sorted node in the map, or nil if empty. + * + * @return the last node + */ + private Node<K,V> lastNode() + { + // Exploit fact that nil.right == nil. + Node node = root; + while (node.right != nil) + node = node.right; + return node; + } + + /** + * 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. + * + * @param key the lower bound, inclusive + * @param first true to return the first element instead of nil for nil key + * @return the next node + */ + 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; + + Node<K,V> last = nil; + Node<K,V> current = root; + int comparison = 0; + + while (current != nil) + { + last = current; + comparison = compare(key, current.key); + if (comparison > 0) + current = current.right; + else if (comparison < 0) + current = current.left; + else + return (equal ? current : successor(current)); + } + return comparison > 0 ? successor(last) : last; + } + + /** + * Return the node preceding the given one, or nil if there isn't one. + * + * @param node the current node, not nil + * @return the prior node in sorted order + */ + private Node<K,V> predecessor(Node<K,V> node) + { + if (node.left != nil) + { + node = node.left; + while (node.right != nil) + node = node.right; + return node; + } + + Node parent = node.parent; + // Exploit fact that nil.left == nil and node is non-nil. + while (node == parent.left) + { + node = parent; + parent = node.parent; + } + return parent; + } + + /** + * Construct a tree from sorted keys in linear time. Package visible for + * use by TreeSet. + * + * @param s the stream to read from + * @param count the number of keys to read + * @param readValues true to read values, false to insert "" as the value + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @see #readObject(ObjectInputStream) + * @see TreeSet#readObject(ObjectInputStream) + */ + final void putFromObjStream(ObjectInputStream s, int count, + boolean readValues) + throws IOException, ClassNotFoundException + { + fabricateTree(count); + Node node = firstNode(); + + while (--count >= 0) + { + node.key = s.readObject(); + node.value = readValues ? s.readObject() : ""; + node = successor(node); + } + } + + /** + * Construct a tree from sorted keys in linear time, with values of "". + * Package visible for use by TreeSet, which uses a value type of String. + * + * @param keys the iterator over the sorted keys + * @param count the number of nodes to insert + * @see TreeSet#TreeSet(SortedSet) + */ + final void putKeysLinear(Iterator<K> keys, int count) + { + fabricateTree(count); + Node<K,V> node = firstNode(); + + while (--count >= 0) + { + node.key = keys.next(); + node.value = (V) ""; + node = successor(node); + } + } + + /** + * Deserializes this object from the given stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @serialData the <i>size</i> (int), followed by key (Object) and value + * (Object) pairs in sorted order + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + int size = s.readInt(); + putFromObjStream(s, size, true); + } + + /** + * Remove node from tree. This will increment modCount and decrement size. + * Node must exist in the tree. Package visible for use by nested classes. + * + * @param node the node to remove + */ + final void removeNode(Node<K,V> node) + { + Node<K,V> splice; + Node<K,V> child; + + modCount++; + size--; + + // Find splice, the node at the position to actually remove from the tree. + if (node.left == nil) + { + // Node to be deleted has 0 or 1 children. + splice = node; + child = node.right; + } + else if (node.right == nil) + { + // Node to be deleted has 1 child. + splice = node; + child = node.left; + } + else + { + // Node has 2 children. Splice is node's predecessor, and we swap + // its contents into node. + splice = node.left; + while (splice.right != nil) + splice = splice.right; + child = splice.left; + node.key = splice.key; + node.value = splice.value; + } + + // Unlink splice from the tree. + Node parent = splice.parent; + if (child != nil) + child.parent = parent; + if (parent == nil) + { + // Special case for 0 or 1 node remaining. + root = child; + return; + } + if (splice == parent.left) + parent.left = child; + else + parent.right = child; + + if (splice.color == BLACK) + deleteFixup(child, parent); + } + + /** + * Rotate node n to the left. + * + * @param node the node to rotate + */ + private void rotateLeft(Node<K,V> node) + { + Node child = node.right; + // if (node == nil || child == nil) + // throw new InternalError(); + + // Establish node.right link. + node.right = child.left; + if (child.left != nil) + child.left.parent = node; + + // Establish child->parent link. + child.parent = node.parent; + if (node.parent != nil) + { + if (node == node.parent.left) + node.parent.left = child; + else + node.parent.right = child; + } + else + root = child; + + // Link n and child. + child.left = node; + node.parent = child; + } + + /** + * Rotate node n to the right. + * + * @param node the node to rotate + */ + private void rotateRight(Node<K,V> node) + { + Node child = node.left; + // if (node == nil || child == nil) + // throw new InternalError(); + + // Establish node.left link. + node.left = child.right; + if (child.right != nil) + child.right.parent = node; + + // Establish child->parent link. + child.parent = node.parent; + if (node.parent != nil) + { + if (node == node.parent.right) + node.parent.right = child; + else + node.parent.left = child; + } + else + root = child; + + // Link n and child. + child.right = node; + node.parent = child; + } + + /** + * Return the node following the given one, or nil if there isn't one. + * Package visible for use by nested classes. + * + * @param node the current node, not nil + * @return the next node in sorted order + */ + final Node<K,V> successor(Node<K,V> node) + { + if (node.right != nil) + { + node = node.right; + while (node.left != nil) + node = node.left; + return node; + } + + Node<K,V> parent = node.parent; + // Exploit fact that nil.right == nil and node is non-nil. + while (node == parent.right) + { + node = parent; + parent = parent.parent; + } + return parent; + } + + /** + * Serializes this object to the given stream. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + * @serialData the <i>size</i> (int), followed by key (Object) and value + * (Object) pairs in sorted order + */ + private void writeObject(ObjectOutputStream s) throws IOException + { + s.defaultWriteObject(); + + Node node = firstNode(); + s.writeInt(size); + while (node != nil) + { + s.writeObject(node.key); + s.writeObject(node.value); + node = successor(node); + } + } + + /** + * Iterate over TreeMap's entries. This implementation is parameterized + * to give a sequential view of keys, values, or entries. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + private final class TreeIterator implements Iterator + { + /** + * The type of this Iterator: {@link #KEYS}, {@link #VALUES}, + * or {@link #ENTRIES}. + */ + private final int type; + /** The number of modifications to the backing Map that we know about. */ + private int knownMod = modCount; + /** The last Entry returned by a next() call. */ + private Node last; + /** The next entry that should be returned by next(). */ + private Node next; + /** + * The last node visible to this iterator. This is used when iterating + * on a SubMap. + */ + private final Node max; + + /** + * Construct a new TreeIterator with the supplied type. + * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + */ + TreeIterator(int type) + { + this(type, firstNode(), nil); + } + + /** + * Construct a new TreeIterator with the supplied type. Iteration will + * be from "first" (inclusive) to "max" (exclusive). + * + * @param type {@link #KEYS}, {@link #VALUES}, or {@link #ENTRIES} + * @param first where to start iteration, nil for empty iterator + * @param max the cutoff for iteration, nil for all remaining nodes + */ + TreeIterator(int type, Node first, Node max) + { + this.type = type; + this.next = first; + this.max = max; + } + + /** + * Returns true if the Iterator has more elements. + * @return true if there are more elements + */ + public boolean hasNext() + { + return next != max; + } + + /** + * Returns the next element in the Iterator's sequential view. + * @return the next element + * @throws ConcurrentModificationException if the TreeMap was modified + * @throws NoSuchElementException if there is none + */ + public Object next() + { + if (knownMod != modCount) + throw new ConcurrentModificationException(); + if (next == max) + throw new NoSuchElementException(); + last = next; + next = successor(last); + + if (type == VALUES) + return last.value; + else if (type == KEYS) + return last.key; + return last; + } + + /** + * Removes from the backing TreeMap the last element which was fetched + * with the <code>next()</code> method. + * @throws ConcurrentModificationException if the TreeMap was modified + * @throws IllegalStateException if called when there is no last element + */ + public void remove() + { + if (last == null) + throw new IllegalStateException(); + if (knownMod != modCount) + throw new ConcurrentModificationException(); + + removeNode(last); + last = null; + knownMod++; + } + } // class TreeIterator + + /** + * Implementation of {@link #subMap(Object, Object)} and other map + * ranges. This class provides a view of a portion of the original backing + * map, and throws {@link IllegalArgumentException} for attempts to + * access beyond that range. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ + 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 K minKey; + + /** + * The upper range of this view, exclusive, or nil for unbounded. + * Package visible for use by nested classes. + */ + final K maxKey; + + /** + * The cache for {@link #entrySet()}. + */ + 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) + * and maxKey (exclusive). If minKey is nil, SubMap has no lower bound + * (headMap). If maxKey is nil, the SubMap has no upper bound (tailMap). + * + * @param minKey the lower bound + * @param maxKey the upper bound + * @throws IllegalArgumentException if minKey > maxKey + */ + SubMap(K minKey, K maxKey) + { + if (minKey != nil && maxKey != nil && compare(minKey, maxKey) > 0) + throw new IllegalArgumentException("fromKey > toKey"); + this.minKey = minKey; + this.maxKey = maxKey; + } + + /** + * Check if "key" is in within the range bounds for this SubMap. The + * lower ("from") SubMap range is inclusive, and the upper ("to") bound + * is exclusive. Package visible for use by nested classes. + * + * @param key the key to check + * @return true if the key is in range + */ + boolean keyInRange(K key) + { + 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); + Node max = lowestGreaterThan(maxKey, false); + while (next != max) + { + Node current = next; + next = successor(current); + removeNode(current); + } + } + + public Comparator<? super K> comparator() + { + return comparator; + } + + public boolean containsKey(Object key) + { + return keyInRange((K) key) && TreeMap.this.containsKey(key); + } + + public boolean containsValue(Object value) + { + Node node = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + while (node != max) + { + if (equals(value, node.getValue())) + return true; + node = successor(node); + } + return false; + } + + 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 SubMap.NavigableEntrySet(); + return entries; + } + + public Entry<K,V> firstEntry() + { + 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 e.getKey(); + } + + public Entry<K,V> floorEntry(K key) + { + Entry<K,V> n = TreeMap.this.floorEntry(key); + if (n != null && keyInRange(n.getKey())) + return n; + return null; + } + + public K floorKey(K key) + { + 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 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 SubMap.KeySet(); + return this.keys; + } + + 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 K higherKey(K key) + { + K found = TreeMap.this.higherKey(key); + if (keyInRange(found)) + return found; + else + return null; + } + + public Entry<K,V> lastEntry() + { + return lowerEntry(maxKey); + } + + public K lastKey() + { + Entry<K,V> e = lastEntry(); + if (e == null) + throw new NoSuchElementException(); + 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 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 TreeMap.this.put(key, value); + } + + public V remove(Object key) + { + if (keyInRange((K)key)) + return TreeMap.this.remove(key); + return null; + } + + public int size() + { + Node node = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + int count = 0; + while (node != max) + { + count++; + node = successor(node); + } + return count; + } + + 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(fromInclusive ? fromKey : successor(getNode(fromKey)).key, + toInclusive ? successor(getNode(toKey)).key : toKey); + } + + 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(inclusive ? fromKey : successor(getNode(fromKey)).key, + maxKey); + } + + public Collection<V> values() + { + if (this.values == null) + // Create an AbstractCollection with custom implementations of those + // methods that can be overriden easily and efficiently. + this.values = new AbstractCollection() + { + public int size() + { + return SubMap.this.size(); + } + + public Iterator<V> iterator() + { + Node first = lowestGreaterThan(minKey, true); + Node max = lowestGreaterThan(maxKey, false); + return new TreeIterator(VALUES, first, max); + } + + public void clear() + { + SubMap.this.clear(); + } + }; + return this.values; + } + + 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() + { + CPStringBuilder r = new CPStringBuilder("{"); + 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 DescendingMap.this.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() + { + DescendingMap.this.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() + { + CPStringBuilder r = new CPStringBuilder("["); + 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 |