package org.basex.util.hash;
import java.util.Arrays;
/**
* This is an efficient hash set, storing keys in a simple integer array.
* The {@link IntMap} class extends it to a hash map.
*
* @author BaseX Team 2005-12, BSD License
* @author Christian Gruen
*/
public class IntSet {
/** Initial hash capacity. */
static final int CAP = 1 << 3;
/** Hash entries. Actual hash size is {@code size - 1}. */
int size = 1;
/** Hash keys. */
int[] keys;
/** Pointers to the next token. */
private int[] next;
/** Hash table buckets. */
private int[] bucket;
/**
* Constructor.
*/
public IntSet() {
keys = new int[CAP];
next = new int[CAP];
bucket = new int[CAP];
}
/**
* Indexes the specified key and returns the offset of the added key.
* If the key already exists, a negative offset is returned.
* @param key key
* @return offset of added key, negative offset otherwise
*/
public final int add(final int key) {
if(size == next.length) rehash();
final int p = key & bucket.length - 1;
for(int id = bucket[p]; id != 0; id = next[id]) {
if(key == keys[id]) return -id;
}
next[size] = bucket[p];
keys[size] = key;
bucket[p] = size;
return size++;
}
/**
* Returns the id of the specified key or -1 if key was not found.
* @param key key to be found
* @return id or 0 if nothing was found
*/
final int id(final int key) {
final int p = key & bucket.length - 1;
for(int id = bucket[p]; id != 0; id = next[id]) {
if(key == keys[id]) return id;
}
return 0;
}
/**
* Returns the specified key.
* @param i key index
* @return key
*/
public final int key(final int i) {
return keys[i];
}
/**
* Returns number of entries.
* @return number of entries
*/
public final int size() {
return size - 1;
}
/**
* Resizes the hash table.
*/
void rehash() {
final int s = size << 1;
final int[] tmp = new int[s];
final int l = bucket.length;
for(int i = 0; i != l; ++i) {
int id = bucket[i];
while(id != 0) {
final int p = keys[id] & s - 1;
final int nx = next[id];
next[id] = tmp[p];
tmp[p] = id;
id = nx;
}
}
bucket = tmp;
next = Arrays.copyOf(next, s);
final int[] k = new int[s];
System.arraycopy(keys, 0, k, 0, size);
keys = k;
}
/**
* Deletes the specified key.
* @param key key
* @return deleted key or 0
*/
public final int delete(final int key) {
final int p = key & bucket.length - 1;
for(int id = bucket[p]; id != 0; id = next[id]) {
if(key == keys[id]) {
if(bucket[p] == id) bucket[p] = next[id];
else next[id] = next[next[id]];
keys[id] = 0;
return id;
}
}
return 0;
}
}