Adds partial support of NavigableMap into TreeMap

This commit is contained in:
konsoletyper 2014-04-02 17:25:11 +04:00
parent 3dc42b95f5
commit 1c50bb9d0b
2 changed files with 358 additions and 31 deletions

View File

@ -18,7 +18,7 @@ package org.teavm.classlib.java.util;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.*;
public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TSerializable, TSortedMap<K, V> {
public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TSerializable, TNavigableMap<K, V> {
static class TreeNode<K, V> extends SimpleEntry<K, V> {
TreeNode<K, V> left;
TreeNode<K, V> right;
@ -392,12 +392,12 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
}
@Override
public TSortedMap<K, V> headMap(K toKey) {
public TNavigableMap<K, V> headMap(K toKey) {
return new MapView<>(this, null, true, false, toKey, false, true, false);
}
@Override
public TSortedMap<K, V> tailMap(K fromKey) {
public TNavigableMap<K, V> tailMap(K fromKey) {
return new MapView<>(this, fromKey, true, true, null, false, false, false);
}
@ -419,6 +419,104 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
return node.getKey();
}
@Override
public Entry<K, V> lowerEntry(K key) {
return null;
}
@Override
public K lowerKey(K key) {
return null;
}
@Override
public Entry<K, V> floorEntry(K key) {
return null;
}
@Override
public K floorKey(K key) {
return null;
}
@Override
public Entry<K, V> ceilingEntry(K key) {
return null;
}
@Override
public K ceilingKey(K key) {
return null;
}
@Override
public Entry<K, V> higherEntry(K key) {
return null;
}
@Override
public K higherKey(K key) {
return null;
}
@Override
public Entry<K, V> firstEntry() {
return firstNode(false);
}
@Override
public Entry<K, V> lastEntry() {
return firstNode(true);
}
@Override
public Entry<K, V> pollFirstEntry() {
TreeNode<K, V> node = firstNode(false);
if (node != null) {
deleteNode(root, node.getKey());
}
return node;
}
@Override
public Entry<K, V> pollLastEntry() {
TreeNode<K, V> node = firstNode(true);
if (node != null) {
deleteNode(root, node.getKey());
}
return node;
}
@Override
public TNavigableMap<K, V> descendingMap() {
return new MapView<>(this, null, false, false, null, false, false, true);
}
@Override
public TNavigableSet<K> navigableKeySet() {
return null;
}
@Override
public TNavigableSet<K> descendingKeySet() {
return null;
}
@Override
public TNavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
return new MapView<>(this, fromKey, fromInclusive, true, toKey, toInclusive, true, false);
}
@Override
public TNavigableMap<K, V> headMap(K toKey, boolean inclusive) {
return new MapView<>(this, null, false, false, toKey, inclusive, true, false);
}
@Override
public TNavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
return new MapView<>(this, fromKey, inclusive, true, null, false, false, false);
}
private TreeNode<K, V> firstNode(boolean reverse) {
TreeNode<K, V> node = root;
TreeNode<K, V> prev = null;
@ -502,21 +600,39 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
@Override
public TIterator<Entry<K, V>> iterator() {
return !reverse ? ascendingIterator() : descendingIterator();
}
private TIterator<Entry<K, V>> ascendingIterator() {
TreeNode<K, V>[] fromPath;
K from = !reverse ? this.from : this.to;
K to = !reverse ? this.to : this.from;
if (fromChecked) {
fromPath = fromIncluded ? owner.pathToExactOrNext(from, reverse) : owner.pathToNext(from, reverse);
fromPath = fromIncluded ? owner.pathToExactOrNext(from, false) : owner.pathToNext(from, false);
} else {
fromPath = owner.pathToFirst(reverse);
fromPath = owner.pathToFirst(false);
}
TreeNode<K, V> toEntry;
if (toChecked) {
toEntry = toIncluded ? owner.findExactOrNext(to, !reverse) : owner.findNext(to, !reverse);
toEntry = toIncluded ? owner.findExactOrNext(to, true) : owner.findNext(to, true);
} else {
toEntry = owner.firstNode(!reverse);
toEntry = owner.firstNode(true);
}
return new EntryIterator<>(owner, fromPath, toEntry, reverse);
return new EntryIterator<>(owner, fromPath, toEntry, false);
}
private TIterator<Entry<K, V>> descendingIterator() {
TreeNode<K, V>[] toPath;
if (toChecked) {
toPath = toIncluded ? owner.pathToExactOrNext(to, true) : owner.pathToNext(to, true);
} else {
toPath = owner.pathToFirst(true);
}
TreeNode<K, V> fromEntry;
if (fromChecked) {
fromEntry = fromIncluded ? owner.findExactOrNext(to, false) : owner.findNext(to, false);
} else {
fromEntry = owner.firstNode(false);
}
return new EntryIterator<>(owner, toPath, fromEntry, true);
}
@Override
@ -611,7 +727,7 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
}
}
private static class MapView<K, V> extends TAbstractMap<K, V> implements TSortedMap<K, V>, TSerializable {
private static class MapView<K, V> extends TAbstractMap<K, V> implements TNavigableMap<K, V>, TSerializable {
private int modCount = -1;
private int cachedSize;
private TTreeMap<K, V> owner;
@ -656,31 +772,42 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
}
private void checkKey(K key) {
if (!keyInRange(key)) {
throw new TIllegalArgumentException();
}
}
private boolean keyInRange(K key) {
if (fromChecked) {
int cmp = owner.comparator.compare(key, from);
if (fromIncluded ? cmp < 0 : cmp <= 0) {
throw new TIllegalArgumentException();
return false;
}
}
if (toChecked) {
int cmp = owner.comparator.compare(key, to);
if (fromIncluded ? cmp > 0 : cmp >= 0) {
throw new TIllegalArgumentException();
return false;
}
}
return true;
}
@SuppressWarnings("unchecked")
@Override
public V get(Object key) {
checkKey((K)key);
if (!keyInRange((K)key)) {
return null;
}
return owner.get(key);
}
@SuppressWarnings("unchecked")
@Override
public V remove(Object key) {
checkKey((K)key);
if (!keyInRange((K)key)) {
return null;
}
return owner.remove(key);
}
@ -690,6 +817,15 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
return owner.put(key, value);
}
@Override
public void clear() {
if (!fromChecked && !toChecked) {
owner.clear();
} else {
super.clear();
}
}
@Override
public int size() {
int size = cachedSize;
@ -742,29 +878,17 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
@Override
public TSortedMap<K, V> subMap(K fromKey, K toKey) {
checkKey(fromKey);
checkKey(toKey);
return new MapView<>(owner, fromKey, true, true, toKey, false, true, reverse);
return subMap(fromKey, true, toKey, false);
}
@Override
public TSortedMap<K, V> headMap(K toKey) {
checkKey(toKey);
if (!reverse) {
return new MapView<>(owner, from, fromIncluded, fromChecked, toKey, false, true, false);
} else {
return new MapView<>(owner, toKey, false, true, to, toIncluded, toChecked, true);
}
return headMap(toKey, false);
}
@Override
public TSortedMap<K, V> tailMap(K fromKey) {
checkKey(fromKey);
if (!reverse) {
return new MapView<>(owner, fromKey, true, true, to, toIncluded, toChecked, false);
} else {
return new MapView<>(owner, from, fromIncluded, toChecked, fromKey, true, true, true);
}
return tailMap(fromKey, true);
}
@Override
@ -816,5 +940,135 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
}
return node;
}
@Override
public Entry<K, V> lowerEntry(K key) {
// TODO: implement
return null;
}
@Override
public K lowerKey(K key) {
// TODO: implement
return null;
}
@Override
public Entry<K, V> floorEntry(K key) {
// TODO: implement
return null;
}
@Override
public K floorKey(K key) {
// TODO: implement
return null;
}
@Override
public Entry<K, V> ceilingEntry(K key) {
// TODO: implement
return null;
}
@Override
public K ceilingKey(K key) {
// TODO: implement
return null;
}
@Override
public Entry<K, V> higherEntry(K key) {
// TODO: implement
return null;
}
@Override
public K higherKey(K key) {
// TODO: implement
return null;
}
@Override
public Entry<K, V> firstEntry() {
return !reverse ? firstNode() : lastNode();
}
@Override
public Entry<K, V> lastEntry() {
return !reverse ? lastNode() : firstNode();
}
@Override
public Entry<K, V> pollFirstEntry() {
TreeNode<K, V> node = !reverse ? firstNode() : lastNode();
if (node != null) {
owner.deleteNode(owner.root, node.getKey());
}
return node;
}
@Override
public Entry<K, V> pollLastEntry() {
TreeNode<K, V> node = !reverse ? lastNode() : firstNode();
if (node != null) {
owner.deleteNode(owner.root, node.getKey());
}
return node;
}
@Override
public TNavigableMap<K, V> descendingMap() {
return new MapView<>(owner, from, fromIncluded, fromChecked, to, toIncluded, toChecked, !reverse);
}
@Override
public TNavigableSet<K> navigableKeySet() {
// TODO: implement
return null;
}
@Override
public TNavigableSet<K> descendingKeySet() {
// TODO: implement
return null;
}
@Override
public TNavigableMap<K, V> subMap(K fromKey, boolean fromInclusive, K toKey, boolean toInclusive) {
checkKey(fromKey);
checkKey(toKey);
if (!reverse) {
if (owner.comparator.compare(fromKey, toKey) > 0) {
throw new IllegalArgumentException();
}
return new MapView<>(owner, fromKey, fromInclusive, true, toKey, toInclusive, true, false);
} else {
if (owner.comparator.compare(fromKey, toKey) < 0) {
throw new IllegalArgumentException();
}
return new MapView<>(owner, toKey, toInclusive, true, fromKey, fromInclusive, true, true);
}
}
@Override
public TNavigableMap<K, V> headMap(K toKey, boolean inclusive) {
checkKey(toKey);
if (!reverse) {
return new MapView<>(owner, from, fromIncluded, fromChecked, toKey, inclusive, true, false);
} else {
return new MapView<>(owner, toKey, inclusive, true, to, toIncluded, toChecked, true);
}
}
@Override
public TNavigableMap<K, V> tailMap(K fromKey, boolean inclusive) {
checkKey(fromKey);
if (!reverse) {
return new MapView<>(owner, fromKey, inclusive, true, to, toIncluded, toChecked, false);
} else {
return new MapView<>(owner, from, fromIncluded, toChecked, fromKey, inclusive, true, true);
}
}
}
}

View File

@ -563,7 +563,80 @@ public class TreeMapTest {
master.put("null", "0");
entry = master.entrySet().toArray();
assertFalse("Null-valued entry should not equal non-null-valued entry",
test_map.entrySet().contains(entry[0]));
test_map.entrySet().contains(entry[0]));
}
@Test
public void mapReversed() {
NavigableMap<Integer, String> map = createMapOfEvenNumbers();
NavigableMap<Integer, String> reversedMap = map.descendingMap();
assertEquals("The first key of reverse map is wrong", Integer.valueOf(998), reversedMap.firstKey());
assertEquals("The last key of reverse map is wrong", Integer.valueOf(0), reversedMap.lastKey());
assertTrue("Reversed map does not contain element from original map", reversedMap.containsKey(256));
assertEquals("Reversed map is of a wrong size", 500, reversedMap.size());
assertNull(reversedMap.get(1000));
Iterator<Integer> keys = reversedMap.keySet().iterator();
assertEquals("Wrong first element got from iterator", Integer.valueOf(998), keys.next());
assertEquals("Wrong second element got from iterator", Integer.valueOf(996), keys.next());
assertEquals("Wrong third element got from iterator", Integer.valueOf(994), keys.next());
}
@Test
public void submapReversed() {
NavigableMap<Integer, String> map = createMapOfEvenNumbers();
NavigableMap<Integer, String> reversedMap = map.subMap(100, true, 201, true).descendingMap();
assertEquals("The first key of map is wrong", Integer.valueOf(200), reversedMap.firstKey());
assertEquals("The last key of map is wrong", Integer.valueOf(100), reversedMap.lastKey());
assertTrue("Reversed map does not contain element from original map", reversedMap.containsKey(104));
assertEquals("Reversed map is of a wrong size", 51, reversedMap.size());
assertNull(reversedMap.get(103));
assertNull(reversedMap.get(256));
Iterator<Integer> keys = reversedMap.keySet().iterator();
assertEquals("Wrong first element got from iterator", Integer.valueOf(200), keys.next());
assertEquals("Wrong second element got from iterator", Integer.valueOf(198), keys.next());
assertEquals("Wrong third element got from iterator", Integer.valueOf(196), keys.next());
}
@Test
public void submapOfReverseSubmapObtained() {
NavigableMap<Integer, String> map = createMapOfEvenNumbers();
NavigableMap<Integer, String> reversedMap = map.subMap(100, true, 901, true).descendingMap()
.subMap(800, false, 201, false);
assertEquals("The first key of map is wrong", Integer.valueOf(798), reversedMap.firstKey());
assertEquals("The last key of map is wrong", Integer.valueOf(202), reversedMap.lastKey());
assertTrue("Reversed map does not contain element from original map", reversedMap.containsKey(244));
assertEquals("Reversed map is of a wrong size", 299, reversedMap.size());
assertNull(reversedMap.get(225));
assertNull(reversedMap.get(100));
Iterator<Integer> keys = reversedMap.keySet().iterator();
assertEquals("Wrong first element got from iterator", Integer.valueOf(798), keys.next());
assertEquals("Wrong second element got from iterator", Integer.valueOf(796), keys.next());
assertEquals("Wrong third element got from iterator", Integer.valueOf(794), keys.next());
}
@Test
public void tailOfReverseSubmapObtained() {
NavigableMap<Integer, String> map = createMapOfEvenNumbers();
NavigableMap<Integer, String> reversedMap = map.subMap(100, true, 901, true).descendingMap()
.tailMap(800, false);
assertEquals("The first key of map is wrong", Integer.valueOf(798), reversedMap.firstKey());
assertEquals("The last key of map is wrong", Integer.valueOf(100), reversedMap.lastKey());
assertTrue("Reversed map does not contain element from original map", reversedMap.containsKey(144));
assertEquals("Reversed map is of a wrong size", 350, reversedMap.size());
assertNull(reversedMap.get(225));
assertNull(reversedMap.get(94));
assertNull(reversedMap.get(908));
Iterator<Integer> keys = reversedMap.keySet().iterator();
assertEquals("Wrong first element got from iterator", Integer.valueOf(798), keys.next());
assertEquals("Wrong second element got from iterator", Integer.valueOf(796), keys.next());
assertEquals("Wrong third element got from iterator", Integer.valueOf(794), keys.next());
}
private TreeMap<Integer, String> createMapOfEvenNumbers() {
TreeMap<Integer, String> treeMap = new TreeMap<>();
for (int i = 0; i < 1000; i += 2) {
treeMap.put(i, String.valueOf(i));
}
return treeMap;
}
}