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;
}
}
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;
}
}