blob: 3ba42bc50a78f89f9d02ffd2f9636af1bacc1c16 [file] [log] [blame]
/*
* 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.apache.uima.internal.util.rb_trees;
import java.util.NoSuchElementException;
import org.apache.uima.internal.util.IntKeyValueIterator;
import org.apache.uima.internal.util.IntListIterator;
/**
* A map<int, int>
*
* uses IntArrayRBTcommon
*
* Int to Int Map, based on IntArrayRBT, used in no-duplicates mode
*
* Implements Map - like interface:
* keys and values are ints
* Entry set not (yet) impl
*
* no keySet()
* no values()
*
*/
public class Int2IntRBT extends IntArrayRBTcommon {
private class KeyValueIterator implements IntKeyValueIterator {
private int currentNode;
private KeyValueIterator() {
moveToFirst();
}
/**
* @see org.apache.uima.internal.util.IntPointerIterator#dec()
*/
public void dec() {
this.currentNode = previousNode(this.currentNode);
}
/**
* @see org.apache.uima.internal.util.IntPointerIterator#get()
*/
public int get() {
if (!isValid()) {
throw new NoSuchElementException();
}
return Int2IntRBT.this.getKeyForNode(this.currentNode);
}
public int getValue() {
if (!isValid()) {
throw new NoSuchElementException();
}
return Int2IntRBT.this.getValue(this.currentNode);
}
/**
* @see org.apache.uima.internal.util.IntPointerIterator#inc()
*/
public void inc() {
this.currentNode = nextNode(this.currentNode);
}
/**
* @see org.apache.uima.internal.util.IntPointerIterator#isValid()
*/
public boolean isValid() {
return (this.currentNode != NIL);
}
/**
* @see org.apache.uima.internal.util.IntPointerIterator#moveToFirst()
*/
public void moveToFirst() {
this.currentNode = getFirstNode();
}
/**
* @see org.apache.uima.internal.util.IntPointerIterator#moveToLast()
*/
public void moveToLast() {
this.currentNode = Int2IntRBT.this.greatestNode;
}
/**
* @see org.apache.uima.internal.util.IntPointerIterator#copy()
*/
public Object copy() {
KeyValueIterator it = new KeyValueIterator();
it.currentNode = this.currentNode;
return it;
}
/**
* @see org.apache.uima.internal.util.IntPointerIterator#moveTo(int)
*/
public void moveTo(int i) {
this.currentNode = findInsertionPointNoDups(i);
}
}
private class KeyIterator implements IntListIterator {
private int currentNode;
private KeyIterator() {
super();
this.currentNode = NIL;
}
public final boolean hasNext() {
return (this.currentNode != Int2IntRBT.this.greatestNode);
}
public final int next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
this.currentNode = (this.currentNode == NIL) ? getFirstNode() : nextNode(this.currentNode);
return Int2IntRBT.this.getKeyForNode(this.currentNode);
}
/**
* @see org.apache.uima.internal.util.IntListIterator#hasPrevious()
*/
public boolean hasPrevious() {
return (this.currentNode != NIL);
}
/**
* @see org.apache.uima.internal.util.IntListIterator#previous()
*/
public int previous() {
if (!hasPrevious()) {
throw new NoSuchElementException();
}
final int currentKey = Int2IntRBT.this.getKeyForNode(this.currentNode);
if (this.currentNode == getFirstNode()) {
this.currentNode = NIL;
} else {
this.currentNode = previousNode(this.currentNode);
}
return currentKey;
}
/**
* @see org.apache.uima.internal.util.IntListIterator#moveToEnd()
*/
public void moveToEnd() {
this.currentNode = Int2IntRBT.this.greatestNode;
}
/**
* @see org.apache.uima.internal.util.IntListIterator#moveToStart()
*/
public void moveToStart() {
this.currentNode = NIL;
}
}
protected int[] values;
private int getValue(int node) {
return values[node];
}
private int prevValue;
private int lastNodeGotten; // a speed up, maybe
/**
* Constructor for IntArrayRBT.
*/
public Int2IntRBT() {
super(default_size);
}
public Int2IntRBT(int initialSize) {
super(initialSize);
}
protected void setupArrays() {
super.setupArrays();
this.values = new int[initialSize];
}
public Int2IntRBT copy() {
Int2IntRBT c = new Int2IntRBT();
c.klrp = klrp.clone();
c.klrp1 = (klrp1 != null) ? klrp1.clone() : null;
c.klrp2 = (klrp2 != null) ? klrp2.clone() : null;
c.klrp3 = (klrp3 != null) ? klrp3.clone() : null;
c.color = color.clone();
c.values = values.clone();
c.root = root;
c.greatestNode = greatestNode;
c.next = next;
c.size = size;
return c;
}
public void clear() {
flush();
}
public void flush() {
super.flush();
lastNodeGotten = NIL;
}
@Override
protected void ensureCapacityKlrp(int requiredSize) {
super.ensureCapacityKlrp(requiredSize);
this.values = ensureArrayCapacity(this.values, requiredSize);
}
/**
*
* @param k the key to insert
* @param v the value to insert (or replace, if key already present)
* @return negative index if key is found
*/
private int treeInsert(final int k, final int v) {
if ((this.greatestNode != NIL) && (getKeyForNode(this.greatestNode) < k)) {
final int y = this.greatestNode;
final int z = newNode(k);
values[z] = v; // addition
this.greatestNode = z;
setRight(y, z);
setParent(z, y);
return z;
}
int x = this.root;
int y = NIL;
while (x != NIL) {
y = x;
final int xKey = getKeyForNode(x);
if (k == xKey) {
// key found
prevValue = values[x]; // addition
values[x] = v; // addition
return -x;
}
x = (k < xKey) ? getLeft(x) : getRight(x);
}
// The key was not found, so we create a new node, inserting the
// key.
final int z = newNode(k);
values[z] = v;
if (y == NIL) {
setAsRoot(z);
this.greatestNode = z;
setParent(z, NIL);
} else {
setParent(z, y);
if (k < getKeyForNode(y)) {
setLeft(y, z);
} else {
setRight(y, z);
}
}
return z;
}
/**
* Get the value for a given key
* @param k -
* @return the value
*/
public int get(final int k) {
final int node = findKey(k);
if (node == NIL) {
return 0;
}
return values[node];
}
public int getMostlyClose(final int k) {
final int node = findKeyFast(k);
if (node == NIL) {
return 0;
}
return values[node];
}
/**
* adds a k, v pair.
* if k already present, replaces v.
* returns previous value, or 0 if no prev value
* @param k -
* @param v -
* @return previous value or 0 if key not previously present
*/
public int put(final int k, final int v) {
if (this.root == NIL) {
final int x = newNode(k);
values[x] = v;
setAsRoot(x);
this.color[this.root] = black;
this.greatestNode = x;
return 0;
}
int x = treeInsert(k, v);
if (x < NIL) {
return prevValue;
}
// inserted a new key, no previous value
this.color[x] = red;
while ((x != this.root) && (this.color[getParent(x)] == red)) {
final int parent_x = getParent(x);
final int parent_parent_x = getParent(parent_x);
if (parent_x == getLeft(parent_parent_x)) {
final int y = getRight(parent_parent_x);
if (this.color[y] == red) {
this.color[parent_x] = black;
this.color[y] = black;
this.color[parent_parent_x] = red;
x = parent_parent_x;
} else {
if (x == getRight(parent_x)) {
x = parent_x;
leftRotate(x);
}
final int parent2_x = getParent(x);
this.color[parent2_x] = black;
final int parent2_parent2_x = getParent(parent2_x);
this.color[parent2_parent2_x] = red;
rightRotate(parent2_parent2_x);
}
} else {
final int y = getLeft(parent_parent_x);
if (this.color[y] == red) {
this.color[parent_x] = black;
this.color[y] = black;
this.color[parent_parent_x] = red;
x = parent_parent_x;
} else {
if (x == getLeft(parent_x)) {
x = parent_x;
rightRotate(x);
}
final int parent2_x = getParent(x);
this.color[parent2_x] = black;
final int parent2_parent2_x = getParent(parent2_x);
this.color[parent2_parent2_x] = red;
leftRotate(parent2_parent2_x);
}
}
}
this.color[this.root] = black;
return 0;
}
// private final boolean isNewNode(int node) {
// return (node == (next - 1));
// }
/**
* Fast version of findKey
* Keeps the last node referenced
* *** NOT THREAD SAFE ***
*
* Tries to shorten the search path, conditionally
* @param k -
* @return -
*/
protected int findKeyFast(final int k) {
final int node;
if (lastNodeGotten == NIL) {
node = findKey(k);
} else {
final int distanceToTop = Math.abs(k - getKeyForNode(this.root));
final int distanceToLast = Math.abs(k - getKeyForNode(this.lastNodeGotten));
node = (distanceToTop < distanceToLast) ? findKey(k) : findKeyFromLast(k);
}
if (node != NIL) {
lastNodeGotten = node;
}
return node;
}
private int findKeyFromLast(final int k) {
int node = lastNodeGotten;
int keyNode = getKeyForNode(node);
int prevNode;
if (k < keyNode) {
do {
prevNode = node;
node = getParent(node);
if (node == NIL) {
break;
}
keyNode = getKeyForNode(node);
} while (k < keyNode);
if (keyNode == k) {
return node;
}
return findKeyDown(k, prevNode);
}
if (k > keyNode) {
do {
prevNode = node;
node = getParent(node);
if (node == NIL) {
break;
}
keyNode = getKeyForNode(node);
} while (k > keyNode);
if (keyNode == k) {
return node;
}
return findKeyDown(k, prevNode);
}
return node;
}
// /**
// * Find the node such that key[node] >= k and key[previous(node)] < k.
// */
// private int findInsertionPoint(final int k) {
// int node = this.root;
// int found = node;
// while (node != NIL) {
// found = node;
// final int keyNode = getKeyForNode(node);
// if (k < keyNode) {
// node = getLeft(node);
// } else if (k == keyNode) {
// // In the presence of duplicates, we have to check if there are
// // identical
// // keys to the left of us.
// while (true) {
// final int left_node = getLeft(node);
// if ((left_node == NIL) ||
// (getKeyForNode(left_node) != keyNode)) {
// break;
// }
// node = left_node;
// }
//// while ((getLeft(node) != NIL) && (getKeyForNode(getLeft(node)) == keyNode)) {
//// node = getLeft(node);
//// }
// return node;
// } else {
// node = getRight(node);
// }
// }
// // node == NIL
// return found;
// }
// private final boolean isLeftDtr(int node) {
// return ((node != this.root) && (node == getLeft(getParent(node))));
// }
// private final boolean isRightDtr(int node) {
// return ((node != root) && (node == right[parent[node]]));
// }
public IntListIterator keyIterator() {
return new KeyIterator();
}
public IntListIterator keyIterator(int aKey) {
KeyIterator it = new KeyIterator();
it.currentNode = this.findKey(aKey);
return it;
}
public IntKeyValueIterator keyValueIterator() {
return new KeyValueIterator();
}
public IntKeyValueIterator keyValueIterator(int aKey) {
KeyValueIterator it = new KeyValueIterator();
it.currentNode = this.findKey(aKey);
return it;
}
}