From 05569f4eef4a8bad67c567ceafaf0bee6d71a446 Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Tue, 1 Apr 2014 16:42:02 +0400 Subject: [PATCH] TreeMap passes all tests from Apache Harmony --- .../teavm/classlib/java/util/TTreeMap.java | 123 +++++++++++++----- .../teavm/classlib/java/util/TreeMapTest.java | 2 +- 2 files changed, 92 insertions(+), 33 deletions(-) diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTreeMap.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTreeMap.java index 068914504..ffd9071c1 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTreeMap.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTreeMap.java @@ -246,9 +246,7 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS while (node != null) { @SuppressWarnings("unchecked") int cmp = comparator.compare((K)key, node.getKey()); - if (cmp == 0) { - break; - } else if (cmp < 0) { + if (cmp < 0) { lastLeftTurn = node; node = node.left; } else { @@ -266,9 +264,7 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS while (node != null) { @SuppressWarnings("unchecked") int cmp = comparator.compare((K)key, node.getKey()); - if (cmp == 0) { - break; - } else if (cmp < 0) { + if (cmp < 0) { path[depth++] = node; node = node.left; } else { @@ -296,6 +292,27 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS return lastRightTurn; } + TreeNode[] pathToExactOrPrev(Object key) { + @SuppressWarnings("unchecked") + TreeNode[] path = (TreeNode[])new TreeNode[height()]; + int depth = 0; + TreeNode 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.right; + } else { + node = node.left; + } + } + return TArrays.copyOf(path, depth); + } + TreeNode[] pathToFirst() { @SuppressWarnings("unchecked") TreeNode[] path = (TreeNode[])new TreeNode[height()]; @@ -314,9 +331,7 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS while (node != null) { @SuppressWarnings("unchecked") int cmp = comparator.compare((K)key, node.getKey()); - if (cmp == 0) { - return node; - } else if (cmp > 0) { + if (cmp > 0) { lastRightTurn = node; node = node.right; } else { @@ -326,6 +341,24 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS return lastRightTurn; } + TreeNode[] pathToPrev(Object key) { + @SuppressWarnings("unchecked") + TreeNode[] path = (TreeNode[])new TreeNode[height()]; + int depth = 0; + TreeNode node = root; + while (node != null) { + @SuppressWarnings("unchecked") + int cmp = comparator.compare((K)key, node.getKey()); + if (cmp > 0) { + path[depth++] = node; + node = node.right; + } else { + node = node.left; + } + } + return TArrays.copyOf(path, depth); + } + private TreeNode getOrCreateNode(TreeNode root, K key) { if (root == null) { return new TreeNode<>(key); @@ -407,7 +440,7 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS @Override public TSortedMap tailMap(K fromKey) { - return new SubMap<>(this, fromKey, false, true, null, false, false); + return new SubMap<>(this, fromKey, true, true, null, false, false); } @Override @@ -465,6 +498,7 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS } private static class EntrySet extends TAbstractSet> { + private int modCount = -1; private TTreeMap owner; private K from; private boolean fromIncluded; @@ -472,6 +506,7 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS private K to; private boolean toIncluded; private boolean toChecked; + private int cachedSize; public EntrySet(TTreeMap owner, K from, boolean fromIncluded, boolean fromChecked, K to, boolean toIncluded, boolean toChecked) { @@ -486,18 +521,29 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS @Override public int size() { - int size = owner.size(); - if (fromChecked) { - TreeNode node = fromIncluded ? owner.findPrev(from) : owner.findExactOrPrev(from); - if (node != null) { - size -= node.size; + int size = cachedSize; + if (modCount != owner.modCount) { + modCount = owner.modCount; + size = owner.size(); + if (fromChecked) { + TreeNode[] path = fromIncluded ? owner.pathToPrev(from) : owner.pathToExactOrPrev(from); + for (TreeNode node : path) { + if (node.left != null) { + size -= node.left.size; + } + } + size -= path.length; } - } - if (toChecked) { - TreeNode node = toIncluded ? owner.findNext(to) : owner.findExactOrNext(to); - if (node != null) { - size -= node.size; + if (toChecked) { + TreeNode path[] = toIncluded ? owner.pathToNext(to) : owner.pathToExactOrNext(to); + for (TreeNode node : path) { + if (node.right != null) { + size -= node.right.size; + } + } + size -= path.length; } + cachedSize = size; } return size; } @@ -546,7 +592,7 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS @Override public boolean isEmpty() { - return from == to; + return size() == 0; } } @@ -608,7 +654,9 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS } } - private static class SubMap extends TAbstractMap implements TSortedMap { + private static class SubMap extends TAbstractMap implements TSortedMap, TSerializable { + private int modCount = -1; + private int cachedSize; private TTreeMap owner; private K from; private boolean fromIncluded; @@ -679,18 +727,29 @@ public class TTreeMap extends TAbstractMap implements TCloneable, TS @Override public int size() { - int size = owner.size(); - if (fromChecked) { - TreeNode node = fromIncluded ? owner.findPrev(from) : owner.findExactOrPrev(from); - if (node != null) { - size -= node.size; + int size = cachedSize; + if (modCount != owner.modCount) { + modCount = owner.modCount; + size = owner.size(); + if (fromChecked) { + TreeNode[] path = fromIncluded ? owner.pathToPrev(from) : owner.pathToExactOrPrev(from); + for (TreeNode node : path) { + if (node.left != null) { + size -= node.left.size; + } + } + size -= path.length; } - } - if (toChecked) { - TreeNode node = toIncluded ? owner.findNext(to) : owner.findExactOrNext(to); - if (node != null) { - size -= node.size; + if (toChecked) { + TreeNode path[] = toIncluded ? owner.pathToNext(to) : owner.pathToExactOrNext(to); + for (TreeNode node : path) { + if (node.right != null) { + size -= node.right.size; + } + } + size -= path.length; } + cachedSize = size; } return size; } diff --git a/teavm-classlib/src/test/java/org/teavm/classlib/java/util/TreeMapTest.java b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/TreeMapTest.java index f8979caa1..62841e18f 100644 --- a/teavm-classlib/src/test/java/org/teavm/classlib/java/util/TreeMapTest.java +++ b/teavm-classlib/src/test/java/org/teavm/classlib/java/util/TreeMapTest.java @@ -471,7 +471,7 @@ public class TreeMapTest { // Regression for Harmony-1066 assertTrue(tail instanceof Serializable); - SortedMap intMap,sub; + SortedMap intMap,sub; int size = 16; intMap = new TreeMap<>(); for(int i=0; i