edu.emory.mathcs.backport.java.util.TreeMap Maven / Gradle / Ivy
The newest version!
/*
* Written by Dawid Kurzyniec, on the basis of public specifications and
* public domain sources from JSR 166 and the Doug Lea's collections package,
* and released to the public domain,
* as explained at http://creativecommons.org/licenses/publicdomain.
*/
package edu.emory.mathcs.backport.java.util;
import java.util.Comparator;
import java.util.Map;
import java.util.AbstractSet;
import java.util.SortedSet;
import java.util.Set;
import java.util.Iterator;
import java.util.SortedMap;
import java.util.NoSuchElementException;
import java.util.ConcurrentModificationException;
import java.io.Serializable;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import edu.emory.mathcs.backport.java.util.TreeMap.AscendingSubMap;
/**
* Sorted map implementation based on a red-black tree and implementing
* all the methods from the NavigableMap interface.
*
* @author Dawid Kurzyniec
*/
public class TreeMap extends AbstractMap
implements NavigableMap, Serializable {
private static final long serialVersionUID = 919286545866124006L;
private final Comparator comparator;
private transient Entry root;
private transient int size = 0;
private transient int modCount = 0;
private transient EntrySet entrySet;
private transient KeySet navigableKeySet;
private transient NavigableMap descendingMap;
private transient Comparator reverseComparator;
public TreeMap() {
this.comparator = null;
}
public TreeMap(Comparator comparator) {
this.comparator = comparator;
}
public TreeMap(SortedMap map) {
this.comparator = map.comparator();
this.buildFromSorted(map.entrySet().iterator(), map.size());
}
public TreeMap(Map map) {
this.comparator = null;
putAll(map);
}
public int size() { return size; }
public void clear() {
root = null;
size = 0;
modCount++;
}
public Object clone() {
TreeMap clone;
try { clone = (TreeMap)super.clone(); }
catch (CloneNotSupportedException e) { throw new InternalError(); }
clone.root = null;
clone.size = 0;
clone.modCount = 0;
if (!isEmpty()) {
clone.buildFromSorted(this.entrySet().iterator(), this.size);
}
return clone;
}
public Object put(Object key, Object value) {
if (root == null) {
root = new Entry(key, value);
size++;
modCount++;
return null;
}
else {
Entry t = root;
for (;;) {
int diff = compare(key, t.getKey(), comparator);
if (diff == 0) return t.setValue(value);
else if (diff <= 0) {
if (t.left != null) t = t.left;
else {
size++;
modCount++;
Entry e = new Entry(key, value);
e.parent = t;
t.left = e;
fixAfterInsertion(e);
return null;
}
}
else {
if (t.right != null) t = t.right;
else {
size++;
modCount++;
Entry e = new Entry(key, value);
e.parent = t;
t.right = e;
fixAfterInsertion(e);
return null;
}
}
}
}
}
/**
* {@inheritDoc}
*/
public Object get(Object key) {
Entry entry = getEntry(key);
return (entry == null) ? null : entry.getValue();
}
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
public Set entrySet() {
if (entrySet == null) {
entrySet = new EntrySet();
}
return entrySet;
}
public static class Entry
implements Map.Entry, Cloneable, java.io.Serializable {
private static final boolean RED = false;
private static final boolean BLACK = true;
private Object key;
private Object element;
/**
* The node color (RED, BLACK)
*/
private boolean color;
/**
* Pointer to left child
*/
private Entry left;
/**
* Pointer to right child
*/
private Entry right;
/**
* Pointer to parent (null if root)
*/
private Entry parent;
/**
* Make a new node with given element, null links, and BLACK color.
* Normally only called to establish a new root.
*/
public Entry(Object key, Object element) {
this.key = key;
this.element = element;
this.color = BLACK;
}
/**
* Return a new Entry with same element and color as self,
* but with null links. (Since it is never OK to have
* multiple identical links in a RB tree.)
*/
protected Object clone() throws CloneNotSupportedException {
Entry t = new Entry(key, element);
t.color = color;
return t;
}
public final Object getKey() {
return key;
}
/**
* return the element value
*/
public final Object getValue() {
return element;
}
/**
* set the element value
*/
public final Object setValue(Object v) {
Object old = element;
element = v;
return old;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry)) return false;
Map.Entry e = (Map.Entry)o;
return eq(key, e.getKey()) && eq(element, e.getValue());
}
public int hashCode() {
return (key == null ? 0 : key.hashCode()) ^
(element == null ? 0 : element.hashCode());
}
public String toString() {
return key + "=" + element;
}
}
/**
* Return the inorder successor, or null if no such
*/
private static Entry successor(Entry e) {
if (e.right != null) {
for (e = e.right; e.left != null; e = e.left) {}
return e;
} else {
Entry p = e.parent;
while (p != null && e == p.right) {
e = p;
p = p.parent;
}
return p;
}
}
/**
* Return the inorder predecessor, or null if no such
*/
private static Entry predecessor(Entry e) {
if (e.left != null) {
for (e = e.left; e.right != null; e = e.right) {}
return e;
}
else {
Entry p = e.parent;
while (p != null && e == p.left) {
e = p;
p = p.parent;
}
return p;
}
}
private Entry getEntry(Object key) {
Entry t = root;
if (comparator != null) {
for (;;) {
if (t == null) return null;
int diff = comparator.compare(key, t.key);
if (diff == 0) return t;
t = (diff < 0) ? t.left : t.right;
}
}
else {
Comparable c = (Comparable)key;
for (;;) {
if (t == null) return null;
int diff = c.compareTo(t.key);
if (diff == 0) return t;
t = (diff < 0) ? t.left : t.right;
}
}
}
private Entry getHigherEntry(Object key) {
Entry t = root;
if (t == null) return null;
for (;;) {
int diff = compare(key, t.key, comparator);
if (diff < 0) {
if (t.left != null) t = t.left; else return t;
}
else {
if (t.right != null) {
t = t.right;
}
else {
Entry parent = t.parent;
while (parent != null && t == parent.right) {
t = parent;
parent = parent.parent;
}
return parent;
}
}
}
}
private Entry getFirstEntry() {
Entry e = root;
if (e == null) return null;
while (e.left != null) e = e.left;
return e;
}
private Entry getLastEntry() {
Entry e = root;
if (e == null) return null;
while (e.right != null) e = e.right;
return e;
}
private Entry getCeilingEntry(Object key) {
Entry e = root;
if (e == null) return null;
for (;;) {
int diff = compare(key, e.key, comparator);
if (diff < 0) {
if (e.left != null) e = e.left; else return e;
}
else if (diff > 0) {
if (e.right != null) {
e = e.right;
}
else {
Entry p = e.parent;
while (p != null && e == p.right) {
e = p;
p = p.parent;
}
return p;
}
}
else return e;
}
}
private Entry getLowerEntry(Object key) {
Entry e = root;
if (e == null) return null;
for (;;) {
int diff = compare(key, e.key, comparator);
if (diff > 0) {
if (e.right != null) e = e.right; else return e;
}
else {
if (e.left != null) {
e = e.left;
}
else {
Entry p = e.parent;
while (p != null && e == p.left) {
e = p;
p = p.parent;
}
return p;
}
}
}
}
private Entry getFloorEntry(Object key) {
Entry e = root;
if (e == null) return null;
for (;;) {
int diff = compare(key, e.key, comparator);
if (diff > 0) {
if (e.right != null) e = e.right; else return e;
}
else if (diff < 0) {
if (e.left != null) {
e = e.left;
}
else {
Entry p = e.parent;
while (p != null && e == p.left) {
e = p;
p = p.parent;
}
return p;
}
}
else return e;
}
}
void buildFromSorted(Iterator itr, int size) {
modCount++;
this.size = size;
// nodes at the bottom (unbalanced) level must be red
int bottom = 0;
for (int ssize = 1; ssize-1 < size; ssize <<= 1) bottom++;
this.root = createFromSorted(itr, size, 0, bottom);
}
private static Entry createFromSorted(Iterator itr, int size,
int level, int bottom) {
level++;
if (size == 0) return null;
int leftSize = (size-1) >> 1;
int rightSize = size-1-leftSize;
Entry left = createFromSorted(itr, leftSize, level, bottom);
Map.Entry orig = (Map.Entry)itr.next();
Entry right = createFromSorted(itr, rightSize, level, bottom);
Entry e = new Entry(orig.getKey(), orig.getValue());
if (left != null) {
e.left = left;
left.parent = e;
}
if (right != null) {
e.right = right;
right.parent = e;
}
if (level == bottom) e.color = Entry.RED;
return e;
}
/**
* Delete the current node, and then rebalance the tree it is in
* @param root the root of the current tree
* @return the new root of the current tree. (Rebalancing
* can change the root!)
*/
private void delete(Entry e) {
// handle case where we are only node
if (e.left == null && e.right == null && e.parent == null) {
root = null;
size = 0;
modCount++;
return;
}
// if strictly internal, swap places with a successor
if (e.left != null && e.right != null) {
Entry s = successor(e);
e.key = s.key;
e.element = s.element;
e = s;
}
// Start fixup at replacement node (normally a child).
// But if no children, fake it by using self
if (e.left == null && e.right == null) {
if (e.color == Entry.BLACK)
fixAfterDeletion(e);
// Unlink (Couldn't before since fixAfterDeletion needs parent ptr)
if (e.parent != null) {
if (e == e.parent.left)
e.parent.left = null;
else if (e == e.parent.right)
e.parent.right = null;
e.parent = null;
}
}
else {
Entry replacement = e.left;
if (replacement == null)
replacement = e.right;
// link replacement to parent
replacement.parent = e.parent;
if (e.parent == null)
root = replacement;
else if (e == e.parent.left)
e.parent.left = replacement;
else
e.parent.right = replacement;
e.left = null;
e.right = null;
e.parent = null;
// fix replacement
if (e.color == Entry.BLACK)
fixAfterDeletion(replacement);
}
size--;
modCount++;
}
/**
* Return color of node p, or BLACK if p is null
* (In the CLR version, they use
* a special dummy `nil' node for such purposes, but that doesn't
* work well here, since it could lead to creating one such special
* node per real node.)
*
*/
static boolean colorOf(Entry p) {
return (p == null) ? Entry.BLACK : p.color;
}
/**
* return parent of node p, or null if p is null
*/
static Entry parentOf(Entry p) {
return (p == null) ? null : p.parent;
}
/**
* Set the color of node p, or do nothing if p is null
*/
private static void setColor(Entry p, boolean c) {
if (p != null) p.color = c;
}
/**
* return left child of node p, or null if p is null
*/
private static Entry leftOf(Entry p) {
return (p == null) ? null : p.left;
}
/**
* return right child of node p, or null if p is null
*/
private static Entry rightOf(Entry p) {
return (p == null) ? null : p.right;
}
/** From CLR */
private final void rotateLeft(Entry e) {
Entry r = e.right;
e.right = r.left;
if (r.left != null)
r.left.parent = e;
r.parent = e.parent;
if (e.parent == null) root = r;
else if (e.parent.left == e)
e.parent.left = r;
else
e.parent.right = r;
r.left = e;
e.parent = r;
}
/** From CLR */
private final void rotateRight(Entry e) {
Entry l = e.left;
e.left = l.right;
if (l.right != null)
l.right.parent = e;
l.parent = e.parent;
if (e.parent == null) root = l;
else if (e.parent.right == e)
e.parent.right = l;
else
e.parent.left = l;
l.right = e;
e.parent = l;
}
/** From CLR */
private final void fixAfterInsertion(Entry e) {
e.color = Entry.RED;
Entry x = e;
while (x != null && x != root && x.parent.color == Entry.RED) {
if (parentOf(x) == leftOf(parentOf(parentOf(x)))) {
Entry y = rightOf(parentOf(parentOf(x)));
if (colorOf(y) == Entry.RED) {
setColor(parentOf(x), Entry.BLACK);
setColor(y, Entry.BLACK);
setColor(parentOf(parentOf(x)), Entry.RED);
x = parentOf(parentOf(x));
}
else {
if (x == rightOf(parentOf(x))) {
x = parentOf(x);
rotateLeft(x);
}
setColor(parentOf(x), Entry.BLACK);
setColor(parentOf(parentOf(x)), Entry.RED);
if (parentOf(parentOf(x)) != null)
rotateRight(parentOf(parentOf(x)));
}
}
else {
Entry y = leftOf(parentOf(parentOf(x)));
if (colorOf(y) == Entry.RED) {
setColor(parentOf(x), Entry.BLACK);
setColor(y, Entry.BLACK);
setColor(parentOf(parentOf(x)), Entry.RED);
x = parentOf(parentOf(x));
}
else {
if (x == leftOf(parentOf(x))) {
x = parentOf(x);
rotateRight(x);
}
setColor(parentOf(x), Entry.BLACK);
setColor(parentOf(parentOf(x)), Entry.RED);
if (parentOf(parentOf(x)) != null)
rotateLeft(parentOf(parentOf(x)));
}
}
}
root.color = Entry.BLACK;
}
/** From CLR */
private final Entry fixAfterDeletion(Entry e) {
Entry x = e;
while (x != root && colorOf(x) == Entry.BLACK) {
if (x == leftOf(parentOf(x))) {
Entry sib = rightOf(parentOf(x));
if (colorOf(sib) == Entry.RED) {
setColor(sib, Entry.BLACK);
setColor(parentOf(x), Entry.RED);
rotateLeft(parentOf(x));
sib = rightOf(parentOf(x));
}
if (colorOf(leftOf(sib)) == Entry.BLACK &&
colorOf(rightOf(sib)) == Entry.BLACK) {
setColor(sib, Entry.RED);
x = parentOf(x);
}
else {
if (colorOf(rightOf(sib)) == Entry.BLACK) {
setColor(leftOf(sib), Entry.BLACK);
setColor(sib, Entry.RED);
rotateRight(sib);
sib = rightOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), Entry.BLACK);
setColor(rightOf(sib), Entry.BLACK);
rotateLeft(parentOf(x));
x = root;
}
}
else {
Entry sib = leftOf(parentOf(x));
if (colorOf(sib) == Entry.RED) {
setColor(sib, Entry.BLACK);
setColor(parentOf(x), Entry.RED);
rotateRight(parentOf(x));
sib = leftOf(parentOf(x));
}
if (colorOf(rightOf(sib)) == Entry.BLACK &&
colorOf(leftOf(sib)) == Entry.BLACK) {
setColor(sib, Entry.RED);
x = parentOf(x);
}
else {
if (colorOf(leftOf(sib)) == Entry.BLACK) {
setColor(rightOf(sib), Entry.BLACK);
setColor(sib, Entry.RED);
rotateLeft(sib);
sib = leftOf(parentOf(x));
}
setColor(sib, colorOf(parentOf(x)));
setColor(parentOf(x), Entry.BLACK);
setColor(leftOf(sib), Entry.BLACK);
rotateRight(parentOf(x));
x = root;
}
}
}
setColor(x, Entry.BLACK);
return root;
}
private class BaseEntryIterator {
Entry cursor;
Entry lastRet;
int expectedModCount;
BaseEntryIterator(Entry cursor) {
this.cursor = cursor;
this.expectedModCount = modCount;
}
public boolean hasNext() {
return (cursor != null);
}
Entry nextEntry() {
Entry curr = cursor;
if (curr == null) throw new NoSuchElementException();
if (expectedModCount != modCount)
throw new ConcurrentModificationException();
cursor = successor(curr);
lastRet = curr;
return curr;
}
Entry prevEntry() {
Entry curr = cursor;
if (curr == null) throw new NoSuchElementException();
if (expectedModCount != modCount)
throw new ConcurrentModificationException();
cursor = predecessor(curr);
lastRet = curr;
return curr;
}
public void remove() {
if (lastRet == null) throw new IllegalStateException();
if (expectedModCount != modCount)
throw new ConcurrentModificationException();
// if removal strictly internal, it swaps places with a successor
if (lastRet.left != null && lastRet.right != null && cursor != null) cursor = lastRet;
delete(lastRet);
lastRet = null;
expectedModCount++;
}
}
class EntryIterator extends BaseEntryIterator implements Iterator {
EntryIterator(Entry cursor) { super(cursor); }
public Object next() { return nextEntry(); }
}
class KeyIterator extends BaseEntryIterator implements Iterator {
KeyIterator(Entry cursor) { super(cursor); }
public Object next() { return nextEntry().key; }
}
class ValueIterator extends BaseEntryIterator implements Iterator {
ValueIterator(Entry cursor) { super(cursor); }
public Object next() { return nextEntry().element; }
}
class DescendingEntryIterator extends BaseEntryIterator implements Iterator {
DescendingEntryIterator(Entry cursor) { super(cursor); }
public Object next() { return prevEntry(); }
}
class DescendingKeyIterator extends BaseEntryIterator implements Iterator {
DescendingKeyIterator(Entry cursor) { super(cursor); }
public Object next() { return prevEntry().key; }
}
class DescendingValueIterator extends BaseEntryIterator implements Iterator {
DescendingValueIterator(Entry cursor) { super(cursor); }
public Object next() { return prevEntry().element; }
}
private Entry getMatchingEntry(Object o) {
if (!(o instanceof Map.Entry)) return null;
Map.Entry e = (Map.Entry)o;
Entry found = TreeMap.this.getEntry(e.getKey());
return (found != null && eq(found.getValue(), e.getValue())) ? found : null;
}
class EntrySet extends AbstractSet {
public int size() { return TreeMap.this.size(); }
public boolean isEmpty() { return TreeMap.this.isEmpty(); }
public void clear() { TreeMap.this.clear(); }
public Iterator iterator() {
return new EntryIterator(getFirstEntry());
}
public boolean contains(Object o) {
return getMatchingEntry(o) != null;
}
public boolean remove(Object o) {
Entry e = getMatchingEntry(o);
if (e == null) return false;
delete(e);
return true;
}
}
class DescendingEntrySet extends EntrySet {
public Iterator iterator() {
return new DescendingEntryIterator(getLastEntry());
}
}
class ValueSet extends AbstractSet {
public int size() { return TreeMap.this.size(); }
public boolean isEmpty() { return TreeMap.this.isEmpty(); }
public void clear() { TreeMap.this.clear(); }
public boolean contains(Object o) {
for (Entry e = getFirstEntry(); e != null; e = successor(e)) {
if (eq(o, e.element)) return true;
}
return false;
}
public Iterator iterator() {
return new ValueIterator(getFirstEntry());
}
public boolean remove(Object o) {
for (Entry e = getFirstEntry(); e != null; e = successor(e)) {
if (eq(o, e.element)) {
delete(e);
return true;
}
}
return false;
}
}
abstract class KeySet extends AbstractSet implements NavigableSet {
public int size() { return TreeMap.this.size(); }
public boolean isEmpty() { return TreeMap.this.isEmpty(); }
public void clear() { TreeMap.this.clear(); }
public boolean contains(Object o) {
return getEntry(o) != null;
}
public boolean remove(Object o) {
Entry found = getEntry(o);
if (found == null) return false;
delete(found);
return true;
}
public SortedSet subSet(Object fromElement, Object toElement) {
return subSet(fromElement, true, toElement, false);
}
public SortedSet headSet(Object toElement) {
return headSet(toElement, false);
}
public SortedSet tailSet(Object fromElement) {
return tailSet(fromElement, true);
}
}
class AscendingKeySet extends KeySet {
public Iterator iterator() {
return new KeyIterator(getFirstEntry());
}
public Iterator descendingIterator() {
return new DescendingKeyIterator(getFirstEntry());
}
public Object lower(Object e) { return lowerKey(e); }
public Object floor(Object e) { return floorKey(e); }
public Object ceiling(Object e) { return ceilingKey(e); }
public Object higher(Object e) { return higherKey(e); }
public Object first() { return firstKey(); }
public Object last() { return lastKey(); }
public Comparator comparator() { return TreeMap.this.comparator(); }
public Object pollFirst() {
Map.Entry e = pollFirstEntry();
return e == null? null : e.getKey();
}
public Object pollLast() {
Map.Entry e = pollLastEntry();
return e == null? null : e.getKey();
}
public NavigableSet subSet(Object fromElement, boolean fromInclusive,
Object toElement, boolean toInclusive) {
return (NavigableSet)(subMap(fromElement, fromInclusive,
toElement, toInclusive)).keySet();
}
public NavigableSet headSet(Object toElement, boolean inclusive) {
return (NavigableSet)(headMap(toElement, inclusive)).keySet();
}
public NavigableSet tailSet(Object fromElement, boolean inclusive) {
return (NavigableSet)(tailMap(fromElement, inclusive)).keySet();
}
public NavigableSet descendingSet() {
return (NavigableSet)descendingMap().keySet();
}
}
class DescendingKeySet extends KeySet {
public Iterator iterator() {
return new DescendingKeyIterator(getLastEntry());
}
public Iterator descendingIterator() {
return new KeyIterator(getFirstEntry());
}
public Object lower(Object e) { return higherKey(e); }
public Object floor(Object e) { return ceilingKey(e); }
public Object ceiling(Object e) { return floorKey(e); }
public Object higher(Object e) { return lowerKey(e); }
public Object first() { return lastKey(); }
public Object last() { return firstKey(); }
public Comparator comparator() { return descendingMap().comparator(); }
public Object pollFirst() {
Map.Entry e = pollLastEntry();
return e == null? null : e.getKey();
}
public Object pollLast() {
Map.Entry e = pollFirstEntry();
return e == null? null : e.getKey();
}
public NavigableSet subSet(Object fromElement, boolean fromInclusive,
Object toElement, boolean toInclusive) {
return (NavigableSet)(descendingMap().subMap(fromElement, fromInclusive,
toElement, toInclusive)).keySet();
}
public NavigableSet headSet(Object toElement, boolean inclusive) {
return (NavigableSet)(descendingMap().headMap(toElement, inclusive)).keySet();
}
public NavigableSet tailSet(Object fromElement, boolean inclusive) {
return (NavigableSet)(descendingMap().tailMap(fromElement, inclusive)).keySet();
}
public NavigableSet descendingSet() {
return (NavigableSet)keySet();
}
}
private static boolean eq(Object o1, Object o2) {
return o1 == null ? o2 == null : o1.equals(o2);
}
private static int compare(Object o1, Object o2, Comparator cmp) {
return (cmp == null)
? ((Comparable)o1).compareTo(o2)
: cmp.compare(o1, o2);
}
/**
* @since 1.6
*/
public Map.Entry lowerEntry(Object key) {
Map.Entry e = getLowerEntry(key);
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
/**
* @since 1.6
*/
public Object lowerKey(Object key) {
Map.Entry e = getLowerEntry(key);
return (e == null) ? null : e.getKey();
}
/**
* @since 1.6
*/
public Map.Entry floorEntry(Object key) {
Entry e = getFloorEntry(key);
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
/**
* @since 1.6
*/
public Object floorKey(Object key) {
Entry e = getFloorEntry(key);
return (e == null) ? null : e.key;
}
/**
* @since 1.6
*/
public Map.Entry ceilingEntry(Object key) {
Entry e = getCeilingEntry(key);
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
/**
* @since 1.6
*/
public Object ceilingKey(Object key) {
Entry e = getCeilingEntry(key);
return (e == null) ? null : e.key;
}
/**
* @since 1.6
*/
public Map.Entry higherEntry(Object key) {
Entry e = getHigherEntry(key);
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
/**
* @since 1.6
*/
public Object higherKey(Object key) {
Entry e = getHigherEntry(key);
return (e == null) ? null : e.key;
}
/**
* @since 1.6
*/
public Map.Entry firstEntry() {
Entry e = getFirstEntry();
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
/**
* @since 1.6
*/
public Map.Entry lastEntry() {
Entry e = getLastEntry();
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
/**
* @since 1.6
*/
public Map.Entry pollFirstEntry() {
Entry e = getFirstEntry();
if (e == null) return null;
Map.Entry res = new AbstractMap.SimpleImmutableEntry(e);
delete(e);
return res;
}
/**
* @since 1.6
*/
public Map.Entry pollLastEntry() {
Entry e = getLastEntry();
if (e == null) return null;
Map.Entry res = new AbstractMap.SimpleImmutableEntry(e);
delete(e);
return res;
}
/**
* @since 1.6
*/
public NavigableMap descendingMap() {
NavigableMap map = descendingMap;
if (map == null) {
descendingMap = map = new DescendingSubMap(true, null, true,
true, null, true);
}
return map;
}
public NavigableSet descendingKeySet() {
return descendingMap().navigableKeySet();
}
public SortedMap subMap(Object fromKey, Object toKey) {
return subMap(fromKey, true, toKey, false);
}
public SortedMap headMap(Object toKey) {
return headMap(toKey, false);
}
public SortedMap tailMap(Object fromKey) {
return tailMap(fromKey, true);
}
public NavigableMap subMap(Object fromKey, boolean fromInclusive,
Object toKey, boolean toInclusive) {
return new AscendingSubMap(false, fromKey, fromInclusive,
false, toKey, toInclusive);
}
public NavigableMap headMap(Object toKey, boolean toInclusive) {
return new AscendingSubMap(true, null, true,
false, toKey, toInclusive);
}
public NavigableMap tailMap(Object fromKey, boolean fromInclusive) {
return new AscendingSubMap(false, fromKey, fromInclusive,
true, null, true);
}
public Comparator comparator() {
return comparator;
}
final Comparator reverseComparator() {
if (reverseComparator == null) {
reverseComparator = Collections.reverseOrder(comparator);
}
return reverseComparator;
}
public Object firstKey() {
Entry e = getFirstEntry();
if (e == null) throw new NoSuchElementException();
return e.key;
}
public Object lastKey() {
Entry e = getLastEntry();
if (e == null) throw new NoSuchElementException();
return e.key;
}
public boolean isEmpty() {
return size == 0;
}
public boolean containsValue(Object value) {
if (root == null) return false;
return (value == null) ? containsNull(root) : containsValue(root, value);
}
private static boolean containsNull(Entry e) {
if (e.element == null) return true;
if (e.left != null && containsNull(e.left)) return true;
if (e.right != null && containsNull(e.right)) return true;
return false;
}
private static boolean containsValue(Entry e, Object val) {
if (val.equals(e.element)) return true;
if (e.left != null && containsValue(e.left, val)) return true;
if (e.right != null && containsValue(e.right, val)) return true;
return false;
}
public Object remove(Object key) {
Entry e = getEntry(key);
if (e == null) return null;
Object old = e.getValue();
delete(e);
return old;
}
public void putAll(Map map) {
if (map instanceof SortedMap) {
SortedMap smap = (SortedMap)map;
if (eq(this.comparator, smap.comparator())) {
this.buildFromSorted(smap.entrySet().iterator(), map.size());
return;
}
}
// not a sorted map, or comparator mismatch
super.putAll(map);
}
public Set keySet() {
return navigableKeySet();
}
public NavigableSet navigableKeySet() {
if (navigableKeySet == null) {
navigableKeySet = new AscendingKeySet();
}
return navigableKeySet;
}
// public Collection values() {
// if (valueSet == null) {
// valueSet = new ValueSet();
// }
// return valueSet;
// }
//
private abstract class NavigableSubMap extends AbstractMap
implements NavigableMap, Serializable {
private static final long serialVersionUID = -6520786458950516097L;
final Object fromKey, toKey;
final boolean fromStart, toEnd;
final boolean fromInclusive, toInclusive;
transient int cachedSize = -1, cacheVersion;
transient SubEntrySet entrySet;
transient NavigableMap descendingMap;
transient NavigableSet navigableKeySet;
NavigableSubMap(boolean fromStart, Object fromKey, boolean fromInclusive,
boolean toEnd, Object toKey, boolean toInclusive) {
if (!fromStart && !toEnd) {
if (compare(fromKey, toKey, comparator) > 0) {
throw new IllegalArgumentException("fromKey > toKey");
}
}
else {
if (!fromStart) compare(fromKey, fromKey, comparator);
if (!toEnd) compare(toKey, toKey, comparator);
}
this.fromStart = fromStart;
this.toEnd = toEnd;
this.fromKey = fromKey;
this.toKey = toKey;
this.fromInclusive = fromInclusive;
this.toInclusive = toInclusive;
}
final TreeMap.Entry checkLoRange(TreeMap.Entry e) {
return (e == null || absTooLow(e.key)) ? null : e;
}
final TreeMap.Entry checkHiRange(TreeMap.Entry e) {
return (e == null || absTooHigh(e.key)) ? null : e;
}
final boolean inRange(Object key) {
return !absTooLow(key) && !absTooHigh(key);
}
final boolean inRangeExclusive(Object key) {
return (fromStart || compare(key, fromKey, comparator) >= 0)
&& (toEnd || compare(toKey, key, comparator) >= 0);
}
final boolean inRange(Object key, boolean inclusive) {
return inclusive ? inRange(key) : inRangeExclusive(key);
}
private boolean absTooHigh(Object key) {
if (toEnd) return false;
int c = compare(key, toKey, comparator);
return (c > 0 || (c == 0 && !toInclusive));
}
private boolean absTooLow(Object key) {
if (fromStart) return false;
int c = compare(key, fromKey, comparator);
return (c < 0 || (c == 0 && !fromInclusive));
}
protected abstract TreeMap.Entry first();
protected abstract TreeMap.Entry last();
protected abstract TreeMap.Entry lower(Object key);
protected abstract TreeMap.Entry floor(Object key);
protected abstract TreeMap.Entry ceiling(Object key);
protected abstract TreeMap.Entry higher(Object key);
protected abstract TreeMap.Entry uncheckedHigher(TreeMap.Entry e);
// absolute comparisons, for use by subclasses
final TreeMap.Entry absLowest() {
return checkHiRange((fromStart) ? getFirstEntry() :
fromInclusive ? getCeilingEntry(fromKey) : getHigherEntry(fromKey));
}
final TreeMap.Entry absHighest() {
return checkLoRange((toEnd) ? getLastEntry() :
toInclusive ? getFloorEntry(toKey) : getLowerEntry(toKey));
}
final TreeMap.Entry absLower(Object key) {
return absTooHigh(key) ? absHighest() : checkLoRange(getLowerEntry(key));
}
final TreeMap.Entry absFloor(Object key) {
return absTooHigh(key) ? absHighest() : checkLoRange(getFloorEntry(key));
}
final TreeMap.Entry absCeiling(Object key) {
return absTooLow(key) ? absLowest() : checkHiRange(getCeilingEntry(key));
}
final TreeMap.Entry absHigher(Object key) {
return absTooLow(key) ? absLowest() : checkHiRange(getHigherEntry(key));
}
// navigable implementations, using subclass-defined comparisons
public Map.Entry firstEntry() {
TreeMap.Entry e = first();
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
public Object firstKey() {
TreeMap.Entry e = first();
if (e == null) throw new NoSuchElementException();
return e.key;
}
public Map.Entry lastEntry() {
TreeMap.Entry e = last();
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
public Object lastKey() {
TreeMap.Entry e = last();
if (e == null) throw new NoSuchElementException();
return e.key;
}
public Map.Entry pollFirstEntry() {
TreeMap.Entry e = first();
if (e == null) return null;
Map.Entry result = new SimpleImmutableEntry(e);
delete(e);
return result;
}
public java.util.Map.Entry pollLastEntry() {
TreeMap.Entry e = last();
if (e == null) return null;
Map.Entry result = new SimpleImmutableEntry(e);
delete(e);
return result;
}
public Map.Entry lowerEntry(Object key) {
TreeMap.Entry e = lower(key);
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
public Object lowerKey(Object key) {
TreeMap.Entry e = lower(key);
return (e == null) ? null : e.key;
}
public Map.Entry floorEntry(Object key) {
TreeMap.Entry e = floor(key);
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
public Object floorKey(Object key) {
TreeMap.Entry e = floor(key);
return (e == null) ? null : e.key;
}
public Map.Entry ceilingEntry(Object key) {
TreeMap.Entry e = ceiling(key);
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
public Object ceilingKey(Object key) {
TreeMap.Entry e = ceiling(key);
return (e == null) ? null : e.key;
}
public Map.Entry higherEntry(Object key) {
TreeMap.Entry e = higher(key);
return (e == null) ? null : new AbstractMap.SimpleImmutableEntry(e);
}
public Object higherKey(Object key) {
TreeMap.Entry e = higher(key);
return (e == null) ? null : e.key;
}
public NavigableSet descendingKeySet() {
return descendingMap().navigableKeySet();
}
public SortedMap subMap(Object fromKey, Object toKey) {
return subMap(fromKey, true, toKey, false);
}
public SortedMap headMap(Object toKey) {
return headMap(toKey, false);
}
public SortedMap tailMap(Object fromKey) {
return tailMap(fromKey, true);
}
public int size() {
if (cachedSize < 0 || cacheVersion != modCount) {
cachedSize = recalculateSize();
cacheVersion = modCount;
}
return cachedSize;
}
private int recalculateSize() {
TreeMap.Entry terminator = absHighest();
Object terminalKey = terminator != null ? terminator.key : null;
int size = 0;
for (TreeMap.Entry e = absLowest(); e != null;
e = (e.key == terminalKey) ? null : successor(e)) {
size++;
}
return size;
}
public boolean isEmpty() {
return absLowest() == null;
}
public boolean containsKey(Object key) {
return (inRange(key) && TreeMap.this.containsKey(key));
}
public Object get(Object key) {
if (!inRange(key)) return null;
else return TreeMap.this.get(key);
}
public Object put(Object key, Object value) {
if (!inRange(key))
throw new IllegalArgumentException("Key out of range");
return TreeMap.this.put(key, value);
}
public Object remove(Object key) {
if (!inRange(key)) return null;
return TreeMap.this.remove(key);
}
public Set entrySet() {
if (entrySet == null) {
entrySet = new SubEntrySet();
}
return entrySet;
}
public Set keySet() {
return navigableKeySet();
}
public NavigableSet navigableKeySet() {
if (navigableKeySet == null) {
navigableKeySet = new SubKeySet();
}
return navigableKeySet;
}
private TreeMap.Entry getMatchingSubEntry(Object o) {
if (!(o instanceof Map.Entry)) return null;
Map.Entry e = (Map.Entry)o;
Object key = e.getKey();
if (!inRange(key)) return null;
TreeMap.Entry found = getEntry(key);
return (found != null && eq(found.getValue(), e.getValue())) ? found : null;
}
class SubEntrySet extends AbstractSet {
public int size() { return NavigableSubMap.this.size(); }
public boolean isEmpty() { return NavigableSubMap.this.isEmpty(); }
public boolean contains(Object o) {
return getMatchingSubEntry(o) != null;
}
public boolean remove(Object o) {
TreeMap.Entry e = getMatchingSubEntry(o);
if (e == null) return false;
delete(e);
return true;
}
public Iterator iterator() {
return new SubEntryIterator();
}
}
class SubKeySet extends AbstractSet implements NavigableSet {
public int size() { return NavigableSubMap.this.size(); }
public boolean isEmpty() { return NavigableSubMap.this.isEmpty(); }
public void clear() { NavigableSubMap.this.clear(); }
public boolean contains(Object o) {
return getEntry(o) != null;
}
public boolean remove(Object o) {
if (!inRange(o)) return false;
TreeMap.Entry found = getEntry(o);
if (found == null) return false;
delete(found);
return true;
}
public SortedSet subSet(Object fromElement, Object toElement) {
return subSet(fromElement, true, toElement, false);
}
public SortedSet headSet(Object toElement) {
return headSet(toElement, false);
}
public SortedSet tailSet(Object fromElement) {
return tailSet(fromElement, true);
}
public Iterator iterator() {
return new SubKeyIterator(NavigableSubMap.this.entrySet().iterator());
}
public Iterator descendingIterator() {
return new SubKeyIterator(NavigableSubMap.this.descendingMap().entrySet().iterator());
}
public Object lower(Object e) { return NavigableSubMap.this.lowerKey(e); }
public Object floor(Object e) { return NavigableSubMap.this.floorKey(e); }
public Object ceiling(Object e) { return NavigableSubMap.this.ceilingKey(e); }
public Object higher(Object e) { return NavigableSubMap.this.higherKey(e); }
public Object first() { return NavigableSubMap.this.firstKey(); }
public Object last() { return NavigableSubMap.this.lastKey(); }
public Comparator comparator() { return NavigableSubMap.this.comparator(); }
public Object pollFirst() {
Map.Entry e = NavigableSubMap.this.pollFirstEntry();
return e == null? null : e.getKey();
}
public Object pollLast() {
Map.Entry e = NavigableSubMap.this.pollLastEntry();
return e == null? null : e.getKey();
}
public NavigableSet subSet(Object fromElement, boolean fromInclusive,
Object toElement, boolean toInclusive) {
return (NavigableSet)(NavigableSubMap.this.subMap(fromElement, fromInclusive,
toElement, toInclusive)).keySet();
}
public NavigableSet headSet(Object toElement, boolean inclusive) {
return (NavigableSet)(NavigableSubMap.this.headMap(toElement, inclusive)).keySet();
}
public NavigableSet tailSet(Object fromElement, boolean inclusive) {
return (NavigableSet)(NavigableSubMap.this.tailMap(fromElement, inclusive)).keySet();
}
public NavigableSet descendingSet() {
return (NavigableSet)NavigableSubMap.this.descendingMap().keySet();
}
}
class SubEntryIterator extends BaseEntryIterator implements Iterator {
final Object terminalKey;
SubEntryIterator() {
super(first());
TreeMap.Entry terminator = last();
this.terminalKey = terminator == null ? null : terminator.key;
}
public boolean hasNext() {
return cursor != null;
}
public Object next() {
TreeMap.Entry curr = cursor;
if (curr == null) throw new NoSuchElementException();
if (expectedModCount != modCount)
throw new ConcurrentModificationException();
cursor = (curr.key == terminalKey) ? null : uncheckedHigher(curr);
lastRet = curr;
return curr;
}
}
class SubKeyIterator implements Iterator {
final Iterator itr;
SubKeyIterator(Iterator itr) { this.itr = itr; }
public boolean hasNext() { return itr.hasNext(); }
public Object next() { return ((Map.Entry)itr.next()).getKey(); }
public void remove() { itr.remove(); }
}
}
class AscendingSubMap extends NavigableSubMap {
AscendingSubMap(boolean fromStart, Object fromKey, boolean fromInclusive,
boolean toEnd, Object toKey, boolean toInclusive) {
super(fromStart, fromKey, fromInclusive, toEnd, toKey, toInclusive);
}
public Comparator comparator() {
return comparator;
}
protected TreeMap.Entry first() { return absLowest(); }
protected TreeMap.Entry last() { return absHighest(); }
protected TreeMap.Entry lower(Object key) { return absLower(key); }
protected TreeMap.Entry floor(Object key) { return absFloor(key); }
protected TreeMap.Entry ceiling(Object key) { return absCeiling(key); }
protected TreeMap.Entry higher(Object key) { return absHigher(key); }
protected TreeMap.Entry uncheckedHigher(TreeMap.Entry e) {
return successor(e);
}
public NavigableMap subMap(Object fromKey, boolean fromInclusive,
Object toKey, boolean toInclusive) {
if (!inRange(fromKey, fromInclusive)) {
throw new IllegalArgumentException("fromKey out of range");
}
if (!inRange(toKey, toInclusive)) {
throw new IllegalArgumentException("toKey out of range");
}
return new AscendingSubMap(false, fromKey, fromInclusive,
false, toKey, toInclusive);
}
public NavigableMap headMap(Object toKey, boolean toInclusive) {
if (!inRange(toKey, toInclusive)) {
throw new IllegalArgumentException("toKey out of range");
}
return new AscendingSubMap(fromStart, fromKey, fromInclusive,
false, toKey, toInclusive);
}
public NavigableMap tailMap(Object fromKey, boolean fromInclusive) {
if (!inRange(fromKey, fromInclusive)) {
throw new IllegalArgumentException("fromKey out of range");
}
return new AscendingSubMap(false, fromKey, fromInclusive,
toEnd, toKey, toInclusive);
}
public NavigableMap descendingMap() {
if (descendingMap == null) {
descendingMap =
new DescendingSubMap(fromStart, fromKey, fromInclusive,
toEnd, toKey, toInclusive);
}
return descendingMap;
}
}
class DescendingSubMap extends NavigableSubMap {
DescendingSubMap(boolean fromStart, Object fromKey, boolean fromInclusive,
boolean toEnd, Object toKey, boolean toInclusive) {
super(fromStart, fromKey, fromInclusive, toEnd, toKey, toInclusive);
}
public Comparator comparator() { return TreeMap.this.reverseComparator(); }
protected TreeMap.Entry first() { return absHighest(); }
protected TreeMap.Entry last() { return absLowest(); }
protected TreeMap.Entry lower(Object key) { return absHigher(key); }
protected TreeMap.Entry floor(Object key) { return absCeiling(key); }
protected TreeMap.Entry ceiling(Object key) { return absFloor(key); }
protected TreeMap.Entry higher(Object key) { return absLower(key); }
protected TreeMap.Entry uncheckedHigher(TreeMap.Entry e) {
return predecessor(e);
}
public NavigableMap subMap(Object fromKey, boolean fromInclusive,
Object toKey, boolean toInclusive) {
if (!inRange(fromKey, fromInclusive)) {
throw new IllegalArgumentException("fromKey out of range");
}
if (!inRange(toKey, toInclusive)) {
throw new IllegalArgumentException("toKey out of range");
}
return new DescendingSubMap(false, toKey, toInclusive,
false, fromKey, fromInclusive);
}
public NavigableMap headMap(Object toKey, boolean toInclusive) {
if (!inRange(toKey, toInclusive)) {
throw new IllegalArgumentException("toKey out of range");
}
return new DescendingSubMap(false, toKey, toInclusive,
this.toEnd, this.toKey, this.toInclusive);
}
public NavigableMap tailMap(Object fromKey, boolean fromInclusive) {
if (!inRange(fromKey, fromInclusive)) {
throw new IllegalArgumentException("fromKey out of range");
}
return new DescendingSubMap(this.fromStart, this.fromKey, this.fromInclusive,
false, fromKey, fromInclusive);
}
public NavigableMap descendingMap() {
if (descendingMap == null) {
descendingMap =
new AscendingSubMap(fromStart, fromKey, fromInclusive,
toEnd, toKey, toInclusive);
}
return descendingMap;
}
}
// serialization
static class IteratorIOException extends RuntimeException {
IteratorIOException(java.io.IOException e) {
super(e);
}
java.io.IOException getException() {
return (java.io.IOException)getCause();
}
}
static class IteratorNoClassException extends RuntimeException {
IteratorNoClassException(ClassNotFoundException e) {
super(e);
}
ClassNotFoundException getException() {
return (ClassNotFoundException)getCause();
}
}
static class IOIterator implements Iterator {
final java.io.ObjectInputStream ois;
int remaining;
IOIterator(java.io.ObjectInputStream ois, int remaining) {
this.ois = ois;
this.remaining = remaining;
}
public boolean hasNext() {
return remaining > 0;
}
public Object next() {
if (remaining <= 0) throw new NoSuchElementException();
remaining--;
try {
return new AbstractMap.SimpleImmutableEntry(ois.readObject(),
ois.readObject());
}
catch (java.io.IOException e) { throw new IteratorIOException(e); }
catch (ClassNotFoundException e) { throw new IteratorNoClassException(e); }
}
public void remove() { throw new UnsupportedOperationException(); }
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeInt(size);
for (Entry e = getFirstEntry(); e != null; e = successor(e)) {
out.writeObject(e.key);
out.writeObject(e.element);
}
}
private void readObject(ObjectInputStream in)
throws java.io.IOException, ClassNotFoundException
{
in.defaultReadObject();
int size = in.readInt();
try {
buildFromSorted(new IOIterator(in, size), size);
}
catch (IteratorIOException e) {
throw e.getException();
}
catch (IteratorNoClassException e) {
throw e.getException();
}
}
private class SubMap extends AbstractMap implements Serializable, NavigableMap {
private static final long serialVersionUID = -6520786458950516097L;
final Object fromKey, toKey;
SubMap() { fromKey = toKey = null; }
private Object readResolve() {
return new AscendingSubMap(fromKey == null, fromKey, true,
toKey == null, toKey, false);
}
public Map.Entry lowerEntry(Object key) { throw new Error(); }
public Object lowerKey(Object key) { throw new Error(); }
public Map.Entry floorEntry(Object key) { throw new Error(); }
public Object floorKey(Object key) { throw new Error(); }
public Map.Entry ceilingEntry(Object key) { throw new Error(); }
public Object ceilingKey(Object key) { throw new Error(); }
public Map.Entry higherEntry(Object key) { throw new Error(); }
public Object higherKey(Object key) { throw new Error(); }
public Map.Entry firstEntry() { throw new Error(); }
public Map.Entry lastEntry() { throw new Error(); }
public Map.Entry pollFirstEntry() { throw new Error(); }
public Map.Entry pollLastEntry() { throw new Error(); }
public NavigableMap descendingMap() { throw new Error(); }
public NavigableSet navigableKeySet() { throw new Error(); }
public NavigableSet descendingKeySet() { throw new Error(); }
public Set entrySet() { throw new Error(); }
public NavigableMap subMap(Object fromKey, boolean fromInclusive,
Object toKey, boolean toInclusive) {
throw new Error();
}
public NavigableMap headMap(Object toKey, boolean inclusive) {
throw new Error();
}
public NavigableMap tailMap(Object fromKey, boolean inclusive) {
throw new Error();
}
public SortedMap subMap(Object fromKey, Object toKey) {
throw new Error();
}
public SortedMap headMap(Object toKey) { throw new Error(); }
public SortedMap tailMap(Object fromKey) { throw new Error(); }
public Comparator comparator() { throw new Error(); }
public Object firstKey() { throw new Error(); }
public Object lastKey() { throw new Error(); }
}
}