package net.sharenav.util; /* * ShareNav - Copyright (c) 2008 Kai Krueger apm at users dot sourceforge dot net * See Copying */ /** * This class implements a simple map using * a primitive int as its key. Needed to reimplement * this, as all the standard Java libraries seem to * require an object as a key, waisting a lot of * overhead in creating and storing "primitive objects" * * This class only accepts positive keys * * @author Kai Krueger * (c) 2008 * see Copying * */ public class IntTree { /** * Initial capacity of the tree and the amount by which it is extended. */ private static final int capacityInc = 20; /** * keys are stored in ascending order. Empty entries are filled with Integer.MinValue * therefore the array grows from the end downwards */ private int [] keys; private Object[] values; /** * points to the first empty key. i.e, if tree grows, treeSize * reduces in value, as the array is grown from the end. * */ private short treeSize = 0; // /** * Cache the last looked up key value in case we rerequest it. * This could save a binary search in the array. Not sure if this * is worth the effort though. */ private int keyCache; private Object valueCache; public IntTree() { removeAll(); } private void clearCache() { keyCache = Integer.MIN_VALUE; valueCache = null; } /** * Bisection search of the key array. * @param key * @return returns the position in the array at which the key was found. * If no key is found, returns the position at which it would be if it were in the array * */ private int bisect(int key) { int rangeLow = 0; int rangeHigh = keys.length - 1; int pivot = 1; while (rangeLow <= rangeHigh) { pivot = rangeLow + ((rangeHigh - rangeLow)/2); if (keys[pivot] == key) { return pivot; } else if (keys[pivot] < key) { rangeLow = pivot + 1; } else { rangeHigh = pivot -1; } } if (keys[pivot] > key) pivot--; return -1 * pivot; } public synchronized Object get(int key) { if (size() == 0) return null; if (key == keyCache) return valueCache; int idx = bisect(key); if (idx >= 0) { keyCache = key; valueCache = values[idx]; return values[idx]; } return null; } public synchronized Object getValueIdx(int idx) { if (idx < 0 || idx >= size()) { return null; } return values[treeSize + idx + 1]; } public synchronized int getKeyIdx(int idx) { if (idx < 0 || idx >= size()) { return 0; } return keys[treeSize + idx + 1]; } public synchronized void put (int key, Object value) { clearCache(); int idx = bisect(key); if (idx >= 0) { // key already in array. Overwrite values[idx] = value; } else { idx *= -1; // indicates position it should be stored if ((treeSize - 1) > 0) { //Still space left in array if (treeSize < keys.length -1) { /* * Copy the elements before idx one position down to make * space to insert the new value; */ System.arraycopy(keys, treeSize+1, keys, treeSize, idx - treeSize); System.arraycopy(values, treeSize+1, values, treeSize, idx - treeSize); } treeSize--; } else { //Need to grow array //Create a new array of capacityInc more elements int [] keys2 = new int[keys.length + capacityInc]; Object[] values2 = new Object[keys.length + capacityInc]; for (int i = 0; i < capacityInc + treeSize; i++) keys2[i] = Integer.MIN_VALUE; System.arraycopy(keys, treeSize + 1, keys2, treeSize + capacityInc, idx - treeSize); System.arraycopy(values, treeSize + 1, values2, treeSize + capacityInc, idx - treeSize); System.arraycopy(keys, idx + 1, keys2, idx + capacityInc + 1, keys.length - idx - 1); System.arraycopy(values, idx + 1, values2, idx + capacityInc + 1, keys.length - idx - 1); keys = keys2; values = values2; idx += capacityInc; treeSize+= capacityInc - 1; } keys[idx] = key; values[idx] = value; } } public synchronized int popFirstKey() { if (treeSize == keys.length - 1) return -1; int key = keys[++treeSize]; keys[treeSize] = Integer.MIN_VALUE; values[treeSize] = null; return key; } public synchronized void remove(int key) { clearCache(); if (size() == 0) return; int idx = bisect(key); if (idx >= 0) { System.arraycopy(keys, treeSize, keys, treeSize+1, idx - treeSize); System.arraycopy(values, treeSize, values, treeSize+1, idx - treeSize); values[treeSize] = null; keys[treeSize] = Integer.MIN_VALUE; treeSize++; } } public synchronized void removeAll() { int size = capacityInc; keys = new int[size]; values = new Object[size]; for (int i = 0; i < size; i++) { keys[i] = Integer.MIN_VALUE; } treeSize = (short)(keys.length - 1); clearCache(); } public int size() { return keys.length - treeSize - 1; } public int capacity() { return keys.length; } public synchronized void clone(IntTree clone) { synchronized (clone) { int size = clone.keys.length; keys = new int[size]; values = new Object[size]; System.arraycopy(clone.keys, 0, keys , 0, size); System.arraycopy(clone.values, 0, values , 0, size); treeSize = clone.treeSize; clearCache(); } } public String toString() { String res = "Length: " + size() + " "; for (int i = treeSize; i < keys.length; i++) { res += " (" + keys[i] + "|" + values[i] + ") "; } return res; } }