mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2025-01-08 07:54:11 -08:00
Rewritten TreeMap passes most of tests
This commit is contained in:
parent
4be4c4a843
commit
161c4c76b7
|
@ -16,11 +16,9 @@
|
|||
package org.teavm.classlib.java.util;
|
||||
|
||||
import org.teavm.classlib.java.io.TSerializable;
|
||||
import org.teavm.classlib.java.lang.ObjectNativeGenerator;
|
||||
import org.teavm.classlib.java.lang.TCloneNotSupportedException;
|
||||
import org.teavm.classlib.java.lang.TObject;
|
||||
import org.teavm.classlib.java.lang.TUnsupportedOperationException;
|
||||
import org.teavm.dependency.PluggableDependency;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -266,7 +264,6 @@ public abstract class TAbstractMap<K, V> extends TObject implements TMap<K, V> {
|
|||
}
|
||||
|
||||
@Override
|
||||
@PluggableDependency(ObjectNativeGenerator.class)
|
||||
protected Object clone() throws TCloneNotSupportedException {
|
||||
TAbstractMap<?, ?> copy = (TAbstractMap<?, ?>)super.clone();
|
||||
copy.cachedKeySet = null;
|
||||
|
|
|
@ -13,58 +13,23 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
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> {
|
||||
class TreeNode implements Entry<K, V> {
|
||||
K key;
|
||||
V value;
|
||||
TreeNode left;
|
||||
TreeNode right;
|
||||
static class TreeNode<K, V> extends SimpleEntry<K, V> {
|
||||
TreeNode<K, V> left;
|
||||
TreeNode<K, V> right;
|
||||
int height = 1;
|
||||
int size = 1;
|
||||
|
||||
public TreeNode(K key) {
|
||||
this.key = key;
|
||||
super(key, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V setValue(V value) {
|
||||
V old = this.value;
|
||||
this.value = value;
|
||||
return old;
|
||||
}
|
||||
|
||||
public TreeNode balance() {
|
||||
public TreeNode<K, V> balance() {
|
||||
int factor = factor();
|
||||
if (factor == 2) {
|
||||
if (right.factor() < 0) {
|
||||
|
@ -85,8 +50,8 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
return (right != null ? right.height : 0) - (left != null ? left.height : 0);
|
||||
}
|
||||
|
||||
public TreeNode rotateRight() {
|
||||
TreeNode left = this.left;
|
||||
public TreeNode<K, V> rotateRight() {
|
||||
TreeNode<K, V> left = this.left;
|
||||
this.left = left.right;
|
||||
left.right = this;
|
||||
fix();
|
||||
|
@ -94,8 +59,8 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
return left;
|
||||
}
|
||||
|
||||
public TreeNode rotateLeft() {
|
||||
TreeNode right = this.right;
|
||||
public TreeNode<K, V> rotateLeft() {
|
||||
TreeNode<K, V> right = this.right;
|
||||
this.right = right.left;
|
||||
right.left = this;
|
||||
fix();
|
||||
|
@ -115,10 +80,15 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
}
|
||||
}
|
||||
|
||||
TreeNode root;
|
||||
TreeNode<K, V> root;
|
||||
private TComparator<? super K> comparator;
|
||||
private TComparator<? super K> originalComparator;
|
||||
private int modCount = 0;
|
||||
private EntrySet<K, V> cachedEntrySet;
|
||||
|
||||
public TTreeMap() {
|
||||
this((TComparator<? super K>)null);
|
||||
}
|
||||
|
||||
public TTreeMap(TComparator<? super K> comparator) {
|
||||
this.originalComparator = comparator;
|
||||
|
@ -133,31 +103,70 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
public TTreeMap(TMap<? extends K, ? extends V> m) {
|
||||
this((TComparator<? super K>)null);
|
||||
@SuppressWarnings("unchecked")
|
||||
Entry<K, V>[] entries = (Entry<K, V>[])new Entry<?, ?>[m.size()];
|
||||
entries = m.entrySet().toArray(entries);
|
||||
TArrays.sort(entries, new TComparator<Entry<K, V>>() {
|
||||
@Override public int compare(Entry<K, V> o1, Entry<K, V> o2) {
|
||||
return comparator.compare(o1.getKey(), o2.getKey());
|
||||
}
|
||||
});
|
||||
fillMap(entries);
|
||||
}
|
||||
|
||||
public TTreeMap(TSortedMap<K, ? extends V> m) {
|
||||
this(m.comparator());
|
||||
@SuppressWarnings("unchecked")
|
||||
Entry<K, V>[] entries = (Entry<K, V>[])new Entry<?, ?>[m.size()];
|
||||
entries = m.entrySet().toArray(entries);
|
||||
fillMap(entries);
|
||||
}
|
||||
|
||||
private void fillMap(Entry<? extends K, ? extends V>[] entries) {
|
||||
root = createNode(entries, 0, entries.length - 1);
|
||||
}
|
||||
|
||||
private TreeNode<K, V> createNode(Entry<? extends K, ? extends V>[] entries, int l, int u) {
|
||||
if (l > u) {
|
||||
return null;
|
||||
}
|
||||
int mid = (l + u) / 2;
|
||||
Entry<? extends K, ? extends V> entry = entries[mid];
|
||||
TreeNode<K, V> node = new TreeNode<K, V>(entry.getKey());
|
||||
node.setValue(entry.getValue());
|
||||
node.left = createNode(entries, l, mid - 1);
|
||||
node.right = createNode(entries, mid + 1, u);
|
||||
node.fix();
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
TreeNode node = findNode(key);
|
||||
return node != null ? node.value : null;
|
||||
TreeNode<?, V> node = findExact(key);
|
||||
return node != null ? node.getValue() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
root = getOrCreateNode(root, key);
|
||||
TreeNode node = findNode(key);
|
||||
V old = node.value;
|
||||
node.value = value;
|
||||
TreeNode<?, V> node = findExact(key);
|
||||
V old = node.setValue(value);
|
||||
node.setValue(value);
|
||||
modCount++;
|
||||
return old;
|
||||
}
|
||||
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
TreeNode node = findNode(key);
|
||||
TreeNode<?, V> node = findExact(key);
|
||||
if (node == null) {
|
||||
return null;
|
||||
}
|
||||
root = deleteNode(root, key);
|
||||
modCount++;
|
||||
return node.value;
|
||||
return node.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -173,14 +182,14 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return findNode(key) != null;
|
||||
return findExact(key) != null;
|
||||
}
|
||||
|
||||
TreeNode findNode(Object key) {
|
||||
TreeNode node = root;
|
||||
TreeNode<?, V> findExact(Object key) {
|
||||
TreeNode<K, V> node = root;
|
||||
while (node != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = comparator.compare((K)key, node.key);
|
||||
int cmp = comparator.compare((K)key, node.getKey());
|
||||
if (cmp == 0) {
|
||||
return node;
|
||||
} else if (cmp < 0) {
|
||||
|
@ -192,11 +201,136 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
return null;
|
||||
}
|
||||
|
||||
private TreeNode getOrCreateNode(TreeNode root, K key) {
|
||||
if (root == null) {
|
||||
return new TreeNode(key);
|
||||
TreeNode<K, V> findExactOrNext(Object key) {
|
||||
TreeNode<K, V> node = root;
|
||||
TreeNode<K, V> lastLeftTurn = null;
|
||||
while (node != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = comparator.compare((K)key, node.getKey());
|
||||
if (cmp == 0) {
|
||||
return node;
|
||||
} else if (cmp < 0) {
|
||||
lastLeftTurn = node;
|
||||
node = node.left;
|
||||
} else {
|
||||
node = node.right;
|
||||
}
|
||||
}
|
||||
int cmp = comparator.compare(key, root.key);
|
||||
return lastLeftTurn;
|
||||
}
|
||||
|
||||
TreeNode<K, V>[] pathToExactOrNext(Object key) {
|
||||
@SuppressWarnings("unchecked")
|
||||
TreeNode<K, V>[] path = (TreeNode<K, V>[])new TreeNode<?, ?>[height()];
|
||||
int depth = 0;
|
||||
TreeNode<K, V> node = root;
|
||||
while (node != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = comparator.compare((K)key, node.getKey());
|
||||
if (cmp == 0) {
|
||||
path[depth++] = node;
|
||||
break;
|
||||
} else if (cmp < 0) {
|
||||
path[depth++] = node;
|
||||
node = node.left;
|
||||
} else {
|
||||
node = node.right;
|
||||
}
|
||||
}
|
||||
return TArrays.copyOf(path, depth);
|
||||
}
|
||||
|
||||
TreeNode<K, V> findNext(Object key) {
|
||||
TreeNode<K, V> node = root;
|
||||
TreeNode<K, V> lastLeftTurn = null;
|
||||
while (node != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = comparator.compare((K)key, node.getKey());
|
||||
if (cmp == 0) {
|
||||
break;
|
||||
} else if (cmp < 0) {
|
||||
lastLeftTurn = node;
|
||||
node = node.left;
|
||||
} else {
|
||||
node = node.right;
|
||||
}
|
||||
}
|
||||
return lastLeftTurn;
|
||||
}
|
||||
|
||||
TreeNode<K, V>[] pathToNext(Object key) {
|
||||
@SuppressWarnings("unchecked")
|
||||
TreeNode<K, V>[] path = (TreeNode<K, V>[])new TreeNode<?, ?>[height()];
|
||||
int depth = 0;
|
||||
TreeNode<K, V> node = root;
|
||||
while (node != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = comparator.compare((K)key, node.getKey());
|
||||
if (cmp == 0) {
|
||||
break;
|
||||
} else if (cmp < 0) {
|
||||
path[depth++] = node;
|
||||
node = node.left;
|
||||
} else {
|
||||
node = node.right;
|
||||
}
|
||||
}
|
||||
return TArrays.copyOf(path, depth);
|
||||
}
|
||||
|
||||
TreeNode<K, V> findExactOrPrev(Object key) {
|
||||
TreeNode<K, V> node = root;
|
||||
TreeNode<K, V> lastRightTurn = null;
|
||||
while (node != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = comparator.compare((K)key, node.getKey());
|
||||
if (cmp == 0) {
|
||||
return node;
|
||||
} else if (cmp > 0) {
|
||||
lastRightTurn = node;
|
||||
node = node.right;
|
||||
} else {
|
||||
node = node.left;
|
||||
}
|
||||
}
|
||||
return lastRightTurn;
|
||||
}
|
||||
|
||||
TreeNode<K, V>[] pathToFirst() {
|
||||
@SuppressWarnings("unchecked")
|
||||
TreeNode<K, V>[] path = (TreeNode<K, V>[])new TreeNode<?, ?>[height()];
|
||||
int depth = 0;
|
||||
TreeNode<K, V> node = root;
|
||||
while (node != null) {
|
||||
path[depth++] = node;
|
||||
node = node.left;
|
||||
}
|
||||
return TArrays.copyOf(path, depth);
|
||||
}
|
||||
|
||||
TreeNode<K, V> findPrev(Object key) {
|
||||
TreeNode<K, V> node = root;
|
||||
TreeNode<K, V> lastRightTurn = null;
|
||||
while (node != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = comparator.compare((K)key, node.getKey());
|
||||
if (cmp == 0) {
|
||||
return node;
|
||||
} else if (cmp > 0) {
|
||||
lastRightTurn = node;
|
||||
node = node.right;
|
||||
} else {
|
||||
node = node.left;
|
||||
}
|
||||
}
|
||||
return lastRightTurn;
|
||||
}
|
||||
|
||||
private TreeNode<K, V> getOrCreateNode(TreeNode<K, V> root, K key) {
|
||||
if (root == null) {
|
||||
return new TreeNode<>(key);
|
||||
}
|
||||
int cmp = comparator.compare(key, root.getKey());
|
||||
if (cmp == 0) {
|
||||
return root;
|
||||
} else if (cmp < 0) {
|
||||
|
@ -204,15 +338,16 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
} else {
|
||||
root.right = getOrCreateNode(root.right, key);
|
||||
}
|
||||
root.fix();
|
||||
return root.balance();
|
||||
}
|
||||
|
||||
private TreeNode deleteNode(TreeNode root, Object key) {
|
||||
private TreeNode<K, V> deleteNode(TreeNode<K, V> root, Object key) {
|
||||
if (root == null) {
|
||||
return null;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = comparator.compare((K)key, root.key);
|
||||
int cmp = comparator.compare((K)key, root.getKey());
|
||||
if (cmp < 0) {
|
||||
root.left = deleteNode(root.left, key);
|
||||
} else if (cmp > 0) {
|
||||
|
@ -220,19 +355,19 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
} else if (root.right == null) {
|
||||
return root.left;
|
||||
} else {
|
||||
TreeNode left = root.left;
|
||||
TreeNode right = root.right;
|
||||
TreeNode min = right;
|
||||
Object[] pathToMin = new Object[right.height];
|
||||
TreeNode<K, V> left = root.left;
|
||||
TreeNode<K, V> right = root.right;
|
||||
TreeNode<K, V> min = right;
|
||||
@SuppressWarnings("unchecked")
|
||||
TreeNode<K, V>[] pathToMin = (TreeNode<K, V>[])new TreeNode<?, ?>[right.height];
|
||||
int minDepth = 0;
|
||||
while (min.left != null) {
|
||||
pathToMin[minDepth++] = min;
|
||||
min = min.left;
|
||||
}
|
||||
right = min.right;
|
||||
while (minDepth >= 0) {
|
||||
@SuppressWarnings("unchecked")
|
||||
TreeNode node = (TreeNode)pathToMin[--minDepth];
|
||||
while (minDepth > 0) {
|
||||
TreeNode<K, V> node = pathToMin[--minDepth];
|
||||
node.left = right;
|
||||
right = node;
|
||||
node.balance();
|
||||
|
@ -246,7 +381,10 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
|
||||
@Override
|
||||
public TSet<Entry<K, V>> entrySet() {
|
||||
return new EntrySet(new Object[0], null);
|
||||
if (cachedEntrySet == null) {
|
||||
cachedEntrySet = new EntrySet<>(this, null, true, false, null, true, false);
|
||||
}
|
||||
return cachedEntrySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -256,49 +394,58 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
|
||||
@Override
|
||||
public TSortedMap<K, V> subMap(K fromKey, K toKey) {
|
||||
return null;
|
||||
if (comparator.compare(fromKey, toKey) > 0) {
|
||||
throw new TIllegalArgumentException();
|
||||
}
|
||||
return new SubMap<>(this, fromKey, true, true, toKey, false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TSortedMap<K, V> headMap(K toKey) {
|
||||
return null;
|
||||
return new SubMap<>(this, null, true, false, toKey, false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TSortedMap<K, V> tailMap(K fromKey) {
|
||||
return null;
|
||||
return new SubMap<>(this, fromKey, false, true, null, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K firstKey() {
|
||||
return firstEntry().key;
|
||||
TreeNode<K, V> node = firstNode();
|
||||
if (node == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
return node.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K lastKey() {
|
||||
return lastEntry().key;
|
||||
}
|
||||
|
||||
private TreeNode firstEntry() {
|
||||
if (isEmpty()) {
|
||||
TreeNode<K, V> node = lastNode();
|
||||
if (node == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
TreeNode node = root;
|
||||
while (node.left != null) {
|
||||
node = node.left;
|
||||
}
|
||||
return node;
|
||||
return node.getKey();
|
||||
}
|
||||
|
||||
private TreeNode lastEntry() {
|
||||
if (isEmpty()) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
TreeNode node = root;
|
||||
while (node.left != null) {
|
||||
private TreeNode<K, V> firstNode() {
|
||||
TreeNode<K, V> node = root;
|
||||
TreeNode<K, V> prev = null;
|
||||
while (node != null) {
|
||||
prev = node;
|
||||
node = node.left;
|
||||
}
|
||||
return node;
|
||||
return prev;
|
||||
}
|
||||
|
||||
private TreeNode<K, V> lastNode() {
|
||||
TreeNode<K, V> node = root;
|
||||
TreeNode<K, V> prev = null;
|
||||
while (node != null) {
|
||||
prev = node;
|
||||
node = node.right;
|
||||
}
|
||||
return prev;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -306,28 +453,50 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
return root != null ? root.size : 0;
|
||||
}
|
||||
|
||||
private class EntrySet extends TAbstractSet<Entry<K, V>> {
|
||||
private Object[] path;
|
||||
private TreeNode from;
|
||||
private TreeNode to;
|
||||
int height() {
|
||||
return root != null ? root.height : 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public EntrySet(Object[] path, TreeNode to) {
|
||||
this.path = path;
|
||||
this.from = this.path.length > 0 ? (TreeNode)this.path[this.path.length - 1] : null;
|
||||
@Override
|
||||
public Object clone() {
|
||||
TTreeMap<?, ?> copy = (TTreeMap<?, ?>)super.clone();
|
||||
copy.cachedEntrySet = null;
|
||||
return copy;
|
||||
}
|
||||
|
||||
private static class EntrySet<K, V> extends TAbstractSet<Entry<K, V>> {
|
||||
private TTreeMap<K, V> owner;
|
||||
private K from;
|
||||
private boolean fromIncluded;
|
||||
private boolean fromChecked;
|
||||
private K to;
|
||||
private boolean toIncluded;
|
||||
private boolean toChecked;
|
||||
|
||||
public EntrySet(TTreeMap<K, V> owner, K from, boolean fromIncluded, boolean fromChecked,
|
||||
K to, boolean toIncluded, boolean toChecked) {
|
||||
this.owner = owner;
|
||||
this.from = from;
|
||||
this.fromIncluded = fromIncluded;
|
||||
this.fromChecked = fromChecked;
|
||||
this.to = to;
|
||||
this.toIncluded = toIncluded;
|
||||
this.toChecked = toChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
int size = TTreeMap.this.size();
|
||||
if (from != null && from.left != null) {
|
||||
size -= from.left.size;
|
||||
int size = owner.size();
|
||||
if (fromChecked) {
|
||||
TreeNode<K, V> node = fromIncluded ? owner.findPrev(from) : owner.findExactOrPrev(from);
|
||||
if (node != null) {
|
||||
size -= node.size;
|
||||
}
|
||||
}
|
||||
if (to != null) {
|
||||
size -= 1;
|
||||
if (to.right != null) {
|
||||
size -= to.right.size;
|
||||
if (toChecked) {
|
||||
TreeNode<K, V> node = toIncluded ? owner.findNext(to) : owner.findExactOrNext(to);
|
||||
if (node != null) {
|
||||
size -= node.size;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
|
@ -335,50 +504,283 @@ public class TTreeMap<K, V> extends TAbstractMap<K, V> implements TCloneable, TS
|
|||
|
||||
@Override
|
||||
public TIterator<Entry<K, V>> iterator() {
|
||||
return null;
|
||||
TreeNode<K, V>[] fromPath;
|
||||
if (fromChecked) {
|
||||
fromPath = fromIncluded ? owner.pathToExactOrNext(from) : owner.pathToNext(from);
|
||||
} else {
|
||||
fromPath = owner.pathToFirst();
|
||||
}
|
||||
TreeNode<K, V> toEntry;
|
||||
if (toChecked) {
|
||||
toEntry = toIncluded ? owner.findExactOrPrev(to) : owner.findPrev(to);
|
||||
} else {
|
||||
toEntry = owner.lastNode();
|
||||
}
|
||||
return new EntryIterator<>(owner, fromPath, toEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (!(o instanceof Entry)) {
|
||||
return false;
|
||||
}
|
||||
Entry<?, ?> entry = (Entry<?, ?>)o;
|
||||
Object key = entry.getKey();
|
||||
if (from != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = owner.comparator.compare((K)key, from);
|
||||
if (fromIncluded ? cmp < 0 : cmp <= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (to != null) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = owner.comparator.compare((K)key, to);
|
||||
if (toIncluded ? cmp > 0 : cmp >= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TreeNode<?, V> node = owner.findExact(key);
|
||||
return node != null && node.equals(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return from == to;
|
||||
}
|
||||
}
|
||||
|
||||
private class EntryIterator implements TIterator<Entry<K, V>> {
|
||||
private int modCount = TTreeMap.this.modCount;
|
||||
private Object[] path = new Object[root != null ? root.height : 0];
|
||||
private TreeNode last;
|
||||
private TreeNode to;
|
||||
private int pathLength;
|
||||
public EntryIterator(Object[] path, TreeNode to) {
|
||||
TreeNode node = root;
|
||||
while (node != null) {
|
||||
path[pathLength++] = node;
|
||||
node = node.left;
|
||||
}
|
||||
private static class EntryIterator<K, V> implements TIterator<Entry<K, V>> {
|
||||
private int modCount;
|
||||
private TTreeMap<K, V> owner;
|
||||
private TreeNode<K, V>[] path;
|
||||
private TreeNode<K, V> last;
|
||||
private TreeNode<K, V> to;
|
||||
private int depth;
|
||||
|
||||
public EntryIterator(TTreeMap<K, V> owner, TreeNode<K, V>[] path, TreeNode<K, V> to) {
|
||||
this.owner = owner;
|
||||
modCount = owner.modCount;
|
||||
this.path = TArrays.copyOf(path, owner.root.height);
|
||||
depth = path.length;
|
||||
this.to = to;
|
||||
}
|
||||
@Override public boolean hasNext() {
|
||||
return pathLength > 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return depth > 0;
|
||||
}
|
||||
@SuppressWarnings("unchecked") @Override public Entry<K, V> next() {
|
||||
if (modCount != TTreeMap.this.modCount) {
|
||||
|
||||
@Override
|
||||
public Entry<K, V> next() {
|
||||
if (modCount != owner.modCount) {
|
||||
throw new TConcurrentModificationException();
|
||||
}
|
||||
if (pathLength == 0) {
|
||||
if (depth == 0) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
TreeNode node = (TreeNode)path[--pathLength];
|
||||
TreeNode<K, V> node = path[--depth];
|
||||
last = node;
|
||||
if (node.right != null) {
|
||||
node = node.right;
|
||||
while (node != null) {
|
||||
path[pathLength++] = node;
|
||||
path[depth++] = node;
|
||||
node = node.left;
|
||||
}
|
||||
}
|
||||
if (last == to) {
|
||||
depth = 0;
|
||||
}
|
||||
return last;
|
||||
}
|
||||
@Override public void remove() {
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
if (modCount != owner.modCount) {
|
||||
throw new TConcurrentModificationException();
|
||||
}
|
||||
if (last == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
deleteNode(root, last);
|
||||
owner.root = owner.deleteNode(owner.root, last.getKey());
|
||||
modCount = ++owner.modCount;
|
||||
last = null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SubMap<K, V> extends TAbstractMap<K, V> implements TSortedMap<K, V> {
|
||||
private TTreeMap<K, V> owner;
|
||||
private K from;
|
||||
private boolean fromIncluded;
|
||||
private boolean fromChecked;
|
||||
private K to;
|
||||
private boolean toIncluded;
|
||||
private boolean toChecked;
|
||||
private EntrySet<K, V> entrySetCache;
|
||||
|
||||
public SubMap(TTreeMap<K, V> owner, K from, boolean fromIncluded, boolean fromChecked,
|
||||
K to, boolean toIncluded, boolean toChecked) {
|
||||
this.owner = owner;
|
||||
this.from = from;
|
||||
this.fromIncluded = fromIncluded;
|
||||
this.fromChecked = fromChecked;
|
||||
this.to = to;
|
||||
this.toIncluded = toIncluded;
|
||||
this.toChecked = toChecked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TSet<Entry<K, V>> entrySet() {
|
||||
if (entrySetCache == null) {
|
||||
entrySetCache = new EntrySet<>(owner, from, fromIncluded, fromChecked, to, toIncluded, toChecked);
|
||||
}
|
||||
return entrySetCache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TComparator<? super K> comparator() {
|
||||
return owner.originalComparator;
|
||||
}
|
||||
|
||||
private void checkKey(K key) {
|
||||
if (fromChecked) {
|
||||
int cmp = owner.comparator.compare(key, from);
|
||||
if (fromIncluded ? cmp < 0 : cmp <= 0) {
|
||||
throw new TIllegalArgumentException();
|
||||
}
|
||||
}
|
||||
if (toChecked) {
|
||||
int cmp = owner.comparator.compare(key, to);
|
||||
if (fromIncluded ? cmp > 0 : cmp >= 0) {
|
||||
throw new TIllegalArgumentException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
checkKey((K)key);
|
||||
return owner.get(key);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
checkKey((K)key);
|
||||
return owner.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
checkKey(key);
|
||||
return owner.put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
int size = owner.size();
|
||||
if (fromChecked) {
|
||||
TreeNode<K, V> node = fromIncluded ? owner.findPrev(from) : owner.findExactOrPrev(from);
|
||||
if (node != null) {
|
||||
size -= node.size;
|
||||
}
|
||||
}
|
||||
if (toChecked) {
|
||||
TreeNode<K, V> node = toIncluded ? owner.findNext(to) : owner.findExactOrNext(to);
|
||||
if (node != null) {
|
||||
size -= node.size;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
if (fromChecked) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = owner.comparator.compare((K)key, from);
|
||||
if (fromIncluded ? cmp < 0 : cmp <= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (toChecked) {
|
||||
@SuppressWarnings("unchecked")
|
||||
int cmp = owner.comparator.compare((K)key, to);
|
||||
if (fromIncluded ? cmp > 0 : cmp >= 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return owner.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TSortedMap<K, V> subMap(K fromKey, K toKey) {
|
||||
checkKey(fromKey);
|
||||
checkKey(toKey);
|
||||
return new SubMap<>(owner, fromKey, true, true, toKey, false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TSortedMap<K, V> headMap(K toKey) {
|
||||
checkKey(toKey);
|
||||
return new SubMap<>(owner, from, fromIncluded, fromChecked, toKey, false, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TSortedMap<K, V> tailMap(K fromKey) {
|
||||
checkKey(fromKey);
|
||||
return new SubMap<>(owner, fromKey, true, true, to, toIncluded, toChecked);
|
||||
}
|
||||
|
||||
@Override
|
||||
public K firstKey() {
|
||||
TreeNode<K, V> node = firstNode();
|
||||
if (node == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
return node.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K lastKey() {
|
||||
TreeNode<K, V> node = lastNode();
|
||||
if (node == null) {
|
||||
throw new TNoSuchElementException();
|
||||
}
|
||||
return node.getKey();
|
||||
}
|
||||
|
||||
private TreeNode<K, V> firstNode() {
|
||||
TreeNode<K, V> node;
|
||||
if (fromChecked) {
|
||||
node = fromIncluded ? owner.findExactOrNext(from) : owner.findNext(from);
|
||||
} else {
|
||||
node = owner.firstNode();
|
||||
}
|
||||
if (toChecked) {
|
||||
int cmp = owner.comparator.compare(node.getKey(), to);
|
||||
if (toIncluded ? cmp > 0 : cmp >= 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
private TreeNode<K, V> lastNode() {
|
||||
TreeNode<K, V> node;
|
||||
if (toChecked) {
|
||||
node = toIncluded ? owner.findExactOrPrev(to) : owner.findPrev(to);
|
||||
} else {
|
||||
node = owner.lastNode();
|
||||
}
|
||||
if (fromChecked) {
|
||||
int cmp = owner.comparator.compare(node.getKey(), from);
|
||||
if (fromIncluded ? cmp < 0 : cmp <= 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -441,22 +441,16 @@ public class TreeMapTest {
|
|||
Map<String, String> subMap = map.subMap("", "test");
|
||||
assertEquals(3, subMap.size());
|
||||
|
||||
Set<Map.Entry<String, String>> entrySet = subMap.entrySet();
|
||||
Iterator<Map.Entry<String, String>> iter = entrySet.iterator();
|
||||
int size = 0;
|
||||
while (iter.hasNext()) {
|
||||
Map.Entry<String, String> entry = iter.next();
|
||||
for (Map.Entry<String, String> entry : subMap.entrySet()) {
|
||||
assertTrue(map.containsKey(entry.getKey()));
|
||||
assertTrue(map.containsValue(entry.getValue()));
|
||||
size++;
|
||||
}
|
||||
assertEquals(map.size(), size);
|
||||
|
||||
Set<String> keySet = subMap.keySet();
|
||||
Iterator<String> keyIter = keySet.iterator();
|
||||
size = 0;
|
||||
while (keyIter.hasNext()) {
|
||||
String key = keyIter.next();
|
||||
for (String key : subMap.keySet()) {
|
||||
assertTrue(map.containsKey(key));
|
||||
size++;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user