IntIntHash.java 5.25 KB
package is2.data;

import java.util.Arrays;

final public class IntIntHash {

	protected int _size;
	protected int _free;
	protected float _loadFactor;
	public int _maxSize;
	protected int _autoCompactRemovesRemaining;
	protected float _autoCompactionFactor;
	public int _set[];
	private int _values[];

	public IntIntHash() {
		this(102877, 0.5F);
	}

	public IntIntHash(int initialCapacity, float loadFactor) {
		_loadFactor = loadFactor;
		_autoCompactionFactor = loadFactor;
		setUp((int) Math.ceil(initialCapacity / loadFactor));
	}

	public int size() {
		return _size;
	}

	public void ensureCapacity(int desiredCapacity) {

		if (desiredCapacity > _maxSize - size()) {
			rehash(PrimeFinder.nextPrime((int) Math.ceil((desiredCapacity + size()) / _loadFactor) + 1));
			computeMaxSize(capacity());
		}
	}

	public void compact() {
		rehash(PrimeFinder.nextPrime((int) Math.ceil(size() / _loadFactor) + 1));
		computeMaxSize(capacity());
		if (_autoCompactionFactor != 0.0F)
			computeNextAutoCompactionAmount(size());
	}

	public void setAutoCompactionFactor(float factor) {
		if (factor < 0.0F) {
			throw new IllegalArgumentException(
					(new StringBuilder()).append("Factor must be >= 0: ").append(factor).toString());
		} else {
			_autoCompactionFactor = factor;
			return;
		}
	}

	public float getAutoCompactionFactor() {
		return _autoCompactionFactor;
	}

	private void computeMaxSize(int capacity) {
		_maxSize = Math.min(capacity - 1, (int) Math.floor(capacity * _loadFactor));
		_free = capacity - _size;
	}

	private void computeNextAutoCompactionAmount(int size) {
		if (_autoCompactionFactor != 0.0F)
			_autoCompactRemovesRemaining = Math.round(size * _autoCompactionFactor);
	}

	protected final void postInsertHook(boolean usedFreeSlot) {
		if (usedFreeSlot)
			_free--;
		if (++_size > _maxSize || _free == 0) {
			int newCapacity = _size <= _maxSize ? capacity() : PrimeFinder.nextPrime(capacity() << 1);
			rehash(newCapacity);
			computeMaxSize(capacity());
		}
	}

	protected int calculateGrownCapacity() {
		return capacity() << 1;
	}

	protected int capacity() {
		return _values.length;
	}

	public boolean contains(int val) {
		return index(val) >= 0;
	}

	private int index(int v) {

		int length = _set.length;
		int index = Math.abs((computeHashCode(v) /* & 2147483647 */ ) % length);

		while (true) {
			// first
			long l = _set[index];
			if (l == 0) {
				// good++;
				return -1;
			}
			// second
			if (l == v) {
				return index;
			}
			if (--index < 0)
				index += length;
		}
		// return -1;
	}

	protected int insertionIndex(long val) {
		int length = _set.length;
		int index = Math.abs((computeHashCode(val) /* & 2147483647 */ ) % length);
		while (true) {
			if (_set[index] == 0)
				return index;
			if (_set[index] == val)
				return -index - 1;
			if (--index < 0)
				index += length;

		}
	}

	public int computeHashCode(long value) {
		return (int) ((value ^ (value & 0xffffffff00000000L) >>> 32) * 31);// 0x811c9dc5
																			// ^
																			// //
																			// 29
	}

	protected int setUp(int initialCapacity) {
		int capacity = PrimeFinder.nextPrime(initialCapacity);
		computeMaxSize(capacity);
		computeNextAutoCompactionAmount(initialCapacity);
		_set = new int[capacity];
		_values = new int[capacity];
		return capacity;
	}

	public void put(int key, int value) {
		int index = insertionIndex(key);
		doPut(key, value, index);
	}

	private void doPut(int key, int value, int index) {
		boolean isNewMapping = true;
		if (index < 0) {
			index = -index - 1;
			isNewMapping = false;
		}
		_set[index] = key;
		_values[index] = value;
		if (isNewMapping)
			postInsertHook(true);

	}

	protected void rehash(int newCapacity) {
		int oldCapacity = _set.length;
		int oldKeys[] = _set;
		int oldVals[] = _values;
		_set = new int[newCapacity];
		_values = new int[newCapacity];
		int i = oldCapacity;

		while (true) {
			if (i-- <= 0)
				break;
			if (oldVals[i] != 0) {
				int o = oldKeys[i];
				int index = insertionIndex(o);
				_set[index] = o;
				_values[index] = oldVals[i];
			}
		}
	}

	int index = 0;

	public int get(int key) {
		int index = index(key);
		return index >= 0 ? _values[index] : 0;
	}

	public void clear() {
		_size = 0;
		_free = capacity();
		Arrays.fill(_set, 0, _set.length, 0);
		// Arrays.fill(_values, 0, _values.length, 0);
	}

	public int remove(int key) {
		int prev = 0;
		int index = index(key);
		if (index >= 0) {
			prev = _values[index];
			_values[index] = 0;
			_set[index] = 0;
			_size--;
			if (_autoCompactionFactor != 0.0F) {
				_autoCompactRemovesRemaining--;
				if (_autoCompactRemovesRemaining <= 0)
					compact();
			}
		}
		return prev;
	}

	public int[] getValues() {
		int vals[] = new int[size()];
		int v[] = _values;
		int i = v.length;
		int j = 0;
		do {
			if (i-- <= 0)
				break;
			if (v[i] != 0)
				vals[j++] = v[i];
		} while (true);
		return vals;
	}

	public int[] keys() {
		int keys[] = new int[size()];
		int k[] = _set;
		// byte states[] = _states;
		int i = k.length;
		int j = 0;
		do {
			if (i-- <= 0)
				break;
			if (k[i] != 0)
				keys[j++] = k[i];
		} while (true);
		return keys;
	}

	/**
	 * @param index2
	 * @param i
	 * @return
	 */
	public boolean adjustValue(int key, int i) {
		int index = index(key);
		if (index >= 0) {
			_values[index] += i;
			return true;
		}
		return false;
	}

}