entry : entries) {
+ if (entry.getKey().equals(key))
+ return i;
+ i++;
+ }
+ return -1;
+ }
}
diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java
deleted file mode 100644
index 46b3ab9c195..00000000000
--- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/HashTreePMap.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package kotlin.reflect.jvm.internal.pcollections;
-
-import java.util.Map;
-import java.util.Map.Entry;
-
-
-
-
-/**
- *
- * A static convenience class for creating efficient persistent maps.
- *
- * This class simply creates HashPMaps backed by IntTreePMaps.
- *
- * @author harold
- */
-public final class HashTreePMap {
- // not instantiable (or subclassable):
- private HashTreePMap() {}
-
- private static final HashPMap EMPTY
- = HashPMap.empty(IntTreePMap.>>empty());
-
- /**
- * @param
- * @param
- * @return an empty map
- */
- @SuppressWarnings("unchecked")
- public static HashPMap empty() {
- return (HashPMap)EMPTY; }
-
- /**
- * @param
- * @param
- * @param key
- * @param value
- * @return empty().plus(key, value)
- */
- public static HashPMap singleton(final K key, final V value) {
- return HashTreePMap.empty().plus(key, value); }
-
- /**
- * @param
- * @param
- * @param map
- * @return empty().plusAll(map)
- */
- public static HashPMap from(final Map extends K, ? extends V> map) {
- return HashTreePMap.empty().plusAll(map); }
-}
diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java
index d5a1ea7b2bb..5d3fcd44160 100644
--- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java
+++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTree.java
@@ -1,309 +1,248 @@
package kotlin.reflect.jvm.internal.pcollections;
-import java.util.Iterator;
-import java.util.Map.Entry;
-
-
-
-
/**
- *
* A non-public utility class for persistent balanced tree maps with integer keys.
- *
+ *
* To allow for efficiently increasing all keys above a certain value or decreasing
* all keys below a certain value, the keys values are stored relative to their parent.
* This makes this map a good backing for fast insertion and removal of indices in a
* vector.
- *
+ *
* This implementation is thread-safe except for its iterators.
- *
+ *
* Other than that, this tree is based on the Glasgow Haskell Compiler's Data.Map implementation,
* which in turn is based on "size balanced binary trees" as described by:
- *
+ *
* Stephen Adams, "Efficient sets: a balancing act",
* Journal of Functional Programming 3(4):553-562, October 1993,
* http://www.swiss.ai.mit.edu/~adams/BB/.
- *
+ *
* J. Nievergelt and E.M. Reingold, "Binary search trees of bounded balance",
* SIAM journal of computing 2(1), March 1973.
- *
- * @author harold
*
- * @param
+ * @author harold
*/
-class IntTree {
- // marker value:
- static final IntTree EMPTYNODE = new IntTree();
-
- private final long key; // we use longs so relative keys can express all ints
- // (e.g. if this has key -10 and right has 'absolute' key MAXINT,
- // then its relative key is MAXINT+10 which overflows)
- // there might be some way to deal with this based on left-verse-right logic,
- // but that sounds like a mess.
- private final V value; // null value means this is empty node
- private final IntTree left, right;
- private final int size;
- private IntTree() {
- if(EMPTYNODE!=null)
- throw new RuntimeException("empty constructor should only be used once");
- size = 0;
-
- key=0; value=null; left=null; right=null;
- }
- private IntTree(final long key, final V value, final IntTree left, final IntTree right) {
- this.key = key; this.value = value;
- this.left = left; this.right = right;
- size = 1 + left.size + right.size;
- }
-
- private IntTree withKey(final long newKey) {
- if(size==0 || newKey==key) return this;
- return new IntTree(newKey, value, left, right); }
-
- Iterator> iterator() {
- return new EntryIterator(this); }
-
- int size() {
- return size; }
+final class IntTree {
+ // marker value:
+ static final IntTree EMPTYNODE = new IntTree();
- boolean containsKey(final long key) {
- if(size==0)
- return false;
- if(key < this.key)
- return left.containsKey(key-this.key);
- if(key > this.key)
- return right.containsKey(key-this.key);
- // otherwise key==this.key:
- return true;
- }
-
- V get(final long key) {
- if(size==0)
- return null;
- if(key < this.key)
- return left.get(key-this.key);
- if(key > this.key)
- return right.get(key-this.key);
- // otherwise key==this.key:
- return value;
- }
+ // we use longs so relative keys can express all ints
+ // (e.g. if this has key -10 and right has 'absolute' key MAXINT,
+ // then its relative key is MAXINT+10 which overflows)
+ // there might be some way to deal with this based on left-verse-right logic,
+ // but that sounds like a mess.
+ private final long key;
+ private final V value; // null value means this is empty node
+ private final IntTree left, right;
+ private final int size;
- IntTree plus(final long key, final V value) {
- if(size==0)
- return new IntTree(key, value, this, this);
- if(key < this.key)
- return rebalanced(left.plus(key-this.key, value), right);
- if(key > this.key)
- return rebalanced(left, right.plus(key-this.key, value));
- // otherwise key==this.key, so we simply replace this, with no effect on balance:
- if(value==this.value)
- return this;
- return new IntTree(key, value, left, right);
- }
+ private IntTree() {
+ size = 0;
+ key = 0;
+ value = null;
+ left = null;
+ right = null;
+ }
- IntTree minus(final long key) {
- if(size==0)
- return this;
- if(key < this.key)
- return rebalanced(left.minus(key-this.key), right);
- if(key > this.key)
- return rebalanced(left, right.minus(key-this.key));
+ private IntTree(long key, V value, IntTree left, IntTree right) {
+ this.key = key;
+ this.value = value;
+ this.left = left;
+ this.right = right;
+ size = 1 + left.size + right.size;
+ }
- // otherwise key==this.key, so we are killing this node:
+ private IntTree withKey(long newKey) {
+ if (size == 0 || newKey == key) return this;
+ return new IntTree(newKey, value, left, right);
+ }
- if(left.size==0) // we can just become right node
- // make key 'absolute':
- return right.withKey(right.key+this.key);
- if(right.size==0) // we can just become left node
- return left.withKey(left.key+this.key);
+ boolean containsKey(long key) {
+ if (size == 0)
+ return false;
+ if (key < this.key)
+ return left.containsKey(key - this.key);
+ if (key > this.key)
+ return right.containsKey(key - this.key);
+ // otherwise key==this.key:
+ return true;
+ }
- // otherwise replace this with the next key (i.e. the smallest key to the right):
-
- // TODO have minNode() instead of minKey to avoid having to call get()
- // TODO get node from larger subtree, i.e. if left.size>right.size use left.maxNode()
- // TODO have faster minusMin() instead of just using minus()
-
- long newKey = right.minKey() + this.key;
- //(right.minKey() is relative to this; adding this.key makes it 'absolute'
- // where 'absolute' really means relative to the parent of this)
+ V get(long key) {
+ if (size == 0)
+ return null;
+ if (key < this.key)
+ return left.get(key - this.key);
+ if (key > this.key)
+ return right.get(key - this.key);
+ // otherwise key==this.key:
+ return value;
+ }
- V newValue = right.get(newKey-this.key);
- // now that we've got the new stuff, take it out of the right subtree:
- IntTree newRight = right.minus(newKey-this.key);
+ IntTree plus(long key, V value) {
+ if (size == 0)
+ return new IntTree(key, value, this, this);
+ if (key < this.key)
+ return rebalanced(left.plus(key - this.key, value), right);
+ if (key > this.key)
+ return rebalanced(left, right.plus(key - this.key, value));
+ // otherwise key==this.key, so we simply replace this, with no effect on balance:
+ if (value == this.value)
+ return this;
+ return new IntTree(key, value, left, right);
+ }
- // lastly, make the subtree keys relative to newKey (currently they are relative to this.key):
- newRight = newRight.withKey( (newRight.key+this.key) - newKey );
- // left is definitely not empty:
- IntTree newLeft = left.withKey( (left.key+this.key) - newKey );
-
- return rebalanced(newKey, newValue, newLeft, newRight);
- }
-
- /**
- * Changes every key k>=key to k+delta.
- *
- * This method will create an _invalid_ tree if delta<0
- * and the distance between the smallest k>=key in this
- * and the largest j changeKeysAbove(final long key, final int delta) {
- if(size==0 || delta==0)
- return this;
+ IntTree minus(long key) {
+ if (size == 0)
+ return this;
+ if (key < this.key)
+ return rebalanced(left.minus(key - this.key), right);
+ if (key > this.key)
+ return rebalanced(left, right.minus(key - this.key));
- if(this.key>=key)
- // adding delta to this.key changes the keys of _all_ children of this,
- // so we now need to un-change the children of this smaller than key,
- // all of which are to the left. note that we still use the 'old' relative key...:
- return new IntTree(this.key+delta, value, left.changeKeysBelow(key-this.key, -delta), right);
+ // otherwise key==this.key, so we are killing this node:
- // otherwise, doesn't apply yet, look to the right:
- IntTree newRight = right.changeKeysAbove(key-this.key, delta);
- if(newRight==right) return this;
- return new IntTree(this.key, value, left, newRight);
- }
-
- /**
- * Changes every key k0
- * and the distance between the largest k=key in this is delta or less.
- *
- * In other words, this method must not result in any overlap or change
- * in the order of the keys in this, since the tree _structure_ is
- * not being changed at all.
- */
- IntTree changeKeysBelow(final long key, final int delta) {
- if(size==0 || delta==0)
- return this;
+ if (left.size == 0) // we can just become right node
+ // make key 'absolute':
+ return right.withKey(right.key + this.key);
+ if (right.size == 0) // we can just become left node
+ return left.withKey(left.key + this.key);
- if(this.key(this.key+delta, value, left, right.changeKeysAbove(key-this.key, -delta));
+ // otherwise replace this with the next key (i.e. the smallest key to the right):
- // otherwise, doesn't apply yet, look to the left:
- IntTree newLeft = left.changeKeysBelow(key-this.key, delta);
- if(newLeft==left) return this;
- return new IntTree(this.key, value, newLeft, right);
- }
-
- // min key in this:
- private long minKey() {
- if(left.size==0)
- return key;
- // make key 'absolute' (i.e. relative to the parent of this):
- return left.minKey() + this.key;
- }
+ // TODO have minNode() instead of minKey to avoid having to call get()
+ // TODO get node from larger subtree, i.e. if left.size>right.size use left.maxNode()
+ // TODO have faster minusMin() instead of just using minus()
- private IntTree rebalanced(final IntTree newLeft, final IntTree newRight) {
- if(newLeft==left && newRight==right)
- return this; // already balanced
- return rebalanced(key, value, newLeft, newRight);
- }
+ long newKey = right.minKey() + this.key;
+ //(right.minKey() is relative to this; adding this.key makes it 'absolute'
+ // where 'absolute' really means relative to the parent of this)
- private static final int OMEGA = 5;
- private static final int ALPHA = 2;
- // rebalance a tree that is off-balance by at most 1:
- private static IntTree rebalanced(final long key, final V value,
- final IntTree left, final IntTree right) {
- if(left.size + right.size > 1) {
- if(left.size >= OMEGA*right.size) { // rotate to the right
- IntTree ll = left.left, lr = left.right;
- if(lr.size < ALPHA*ll.size) // single rotation
- return new IntTree(left.key+key, left.value,
- ll,
- new IntTree(-left.key, value,
- lr.withKey(lr.key+left.key),
- right));
- else { // double rotation:
- IntTree lrl = lr.left, lrr = lr.right;
- return new IntTree(lr.key+left.key+key, lr.value,
- new IntTree(-lr.key, left.value,
- ll,
- lrl.withKey(lrl.key+lr.key)),
- new IntTree(-left.key-lr.key, value,
- lrr.withKey(lrr.key+lr.key+left.key),
- right));
- }
- }
- else if(right.size >= OMEGA*left.size) { // rotate to the left
- IntTree rl = right.left, rr = right.right;
- if(rl.size < ALPHA*rr.size) // single rotation
- return new IntTree(right.key+key, right.value,
- new IntTree(-right.key, value,
- left,
- rl.withKey(rl.key+right.key)),
- rr);
- else { // double rotation:
- IntTree rll = rl.left, rlr = rl.right;
- return new IntTree(rl.key+right.key+key, rl.value,
- new IntTree(-right.key-rl.key, value,
- left,
- rll.withKey(rll.key+rl.key+right.key)),
- new IntTree(-rl.key, right.value,
- rlr.withKey(rlr.key+rl.key),
- rr));
- }
- }
- }
- // otherwise already balanced enough:
- return new IntTree(key, value, left, right);
- }
+ V newValue = right.get(newKey - this.key);
+ // now that we've got the new stuff, take it out of the right subtree:
+ IntTree newRight = right.minus(newKey - this.key);
-
-////entrySet().iterator() IMPLEMENTATION ////
- // TODO make this a ListIterator?
- private static final class EntryIterator implements Iterator> {
- private PStack> stack = ConsPStack.empty(); //path of nonempty nodes
- private int key = 0; // note we use _int_ here since this is a truly absolute key
-
- EntryIterator(final IntTree root) {
- gotoMinOf(root); }
-
- public boolean hasNext() {
- return stack.size()>0; }
-
- public Entry next() {
- IntTree node = stack.get(0);
- final Entry result = new SimpleImmutableEntry(key, node.value);
-
- // find next node.
- // we've already done everything smaller,
- // so try least larger node:
-
- if(node.right.size>0) // we can descend to the right
- gotoMinOf(node.right);
-
- else // can't descend to the right -- try ascending to the right
- while (true) { // find current node's least larger ancestor, if any
- key -= node.key; // revert to parent's key
- stack = stack.subList(1); // climb up to parent
- // if parent was larger than child or there was no parent, we're done:
- if(node.key<0 || stack.size()==0)
- break;
- // otherwise parent was smaller -- try its parent:
- node = stack.get(0);
- }
-
- return result;
- }
+ // lastly, make the subtree keys relative to newKey (currently they are relative to this.key):
+ newRight = newRight.withKey((newRight.key + this.key) - newKey);
+ // left is definitely not empty:
+ IntTree newLeft = left.withKey((left.key + this.key) - newKey);
- public void remove() {
- throw new UnsupportedOperationException(); }
+ return rebalanced(newKey, newValue, newLeft, newRight);
+ }
- // extend the stack to its least non-empty node:
- private void gotoMinOf(IntTree node) {
- while(node.size>0) {
- stack = stack.plus(node);
- key += node.key;
- node = node.left;
- }
- }
- }
+ /**
+ * Changes every key k>=key to k+delta.
+ *
+ * This method will create an _invalid_ tree if delta<0
+ * and the distance between the smallest k>=key in this
+ * and the largest j
+ * In other words, this method must not result in any change
+ * in the order of the keys in this, since the tree structure is
+ * not being changed at all.
+ */
+ IntTree changeKeysAbove(long key, int delta) {
+ if (size == 0 || delta == 0)
+ return this;
+
+ if (this.key >= key)
+ // adding delta to this.key changes the keys of _all_ children of this,
+ // so we now need to un-change the children of this smaller than key,
+ // all of which are to the left. note that we still use the 'old' relative key...:
+ return new IntTree(this.key + delta, value, left.changeKeysBelow(key - this.key, -delta), right);
+
+ // otherwise, doesn't apply yet, look to the right:
+ IntTree newRight = right.changeKeysAbove(key - this.key, delta);
+ if (newRight == right) return this;
+ return new IntTree(this.key, value, left, newRight);
+ }
+
+ /**
+ * Changes every key k
+ * This method will create an _invalid_ tree if delta>0
+ * and the distance between the largest k=key in this is delta or less.
+ *
+ * In other words, this method must not result in any overlap or change
+ * in the order of the keys in this, since the tree _structure_ is
+ * not being changed at all.
+ */
+ IntTree changeKeysBelow(long key, int delta) {
+ if (size == 0 || delta == 0)
+ return this;
+
+ if (this.key < key)
+ // adding delta to this.key changes the keys of _all_ children of this,
+ // so we now need to un-change the children of this larger than key,
+ // all of which are to the right. note that we still use the 'old' relative key...:
+ return new IntTree(this.key + delta, value, left, right.changeKeysAbove(key - this.key, -delta));
+
+ // otherwise, doesn't apply yet, look to the left:
+ IntTree newLeft = left.changeKeysBelow(key - this.key, delta);
+ if (newLeft == left) return this;
+ return new IntTree(this.key, value, newLeft, right);
+ }
+
+ // min key in this:
+ private long minKey() {
+ if (left.size == 0)
+ return key;
+ // make key 'absolute' (i.e. relative to the parent of this):
+ return left.minKey() + this.key;
+ }
+
+ private IntTree rebalanced(IntTree newLeft, IntTree newRight) {
+ if (newLeft == left && newRight == right)
+ return this; // already balanced
+ return rebalanced(key, value, newLeft, newRight);
+ }
+
+ private static final int OMEGA = 5;
+ private static final int ALPHA = 2;
+
+ // rebalance a tree that is off-balance by at most 1:
+ private static IntTree rebalanced(long key, V value, IntTree left, IntTree right) {
+ if (left.size + right.size > 1) {
+ if (left.size >= OMEGA * right.size) { // rotate to the right
+ IntTree ll = left.left, lr = left.right;
+ if (lr.size < ALPHA * ll.size) // single rotation
+ return new IntTree(left.key + key, left.value,
+ ll,
+ new IntTree(-left.key, value,
+ lr.withKey(lr.key + left.key),
+ right));
+ else { // double rotation:
+ IntTree lrl = lr.left, lrr = lr.right;
+ return new IntTree(lr.key + left.key + key, lr.value,
+ new IntTree(-lr.key, left.value,
+ ll,
+ lrl.withKey(lrl.key + lr.key)),
+ new IntTree(-left.key - lr.key, value,
+ lrr.withKey(lrr.key + lr.key + left.key),
+ right));
+ }
+ } else if (right.size >= OMEGA * left.size) { // rotate to the left
+ IntTree rl = right.left, rr = right.right;
+ if (rl.size < ALPHA * rr.size) // single rotation
+ return new IntTree(right.key + key, right.value,
+ new IntTree(-right.key, value,
+ left,
+ rl.withKey(rl.key + right.key)),
+ rr);
+ else { // double rotation:
+ IntTree rll = rl.left, rlr = rl.right;
+ return new IntTree(rl.key + right.key + key, rl.value,
+ new IntTree(-right.key - rl.key, value,
+ left,
+ rll.withKey(rll.key + rl.key + right.key)),
+ new IntTree(-rl.key, right.value,
+ rlr.withKey(rlr.key + rl.key),
+ rr));
+ }
+ }
+ }
+ // otherwise already balanced enough:
+ return new IntTree(key, value, left, right);
+ }
}
diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java
index 4c144faf378..169409aee9b 100644
--- a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java
+++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/pcollections/IntTreePMap.java
@@ -1,163 +1,52 @@
package kotlin.reflect.jvm.internal.pcollections;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-
-
-
/**
- *
* An efficient persistent map from integer keys to non-null values.
- *