Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.jnthnclt.os.lab.collections.bah.BAHash Maven / Gradle / Ivy
package com.github.jnthnclt.os.lab.collections.bah;
import com.github.jnthnclt.os.lab.collections.KeyValueStream;
import java.util.concurrent.Semaphore;
/**
* @author jonathan.colt
*/
public class BAHash implements BAH {
private final BAHasher hasher;
private final BAHEqualer equaler;
private volatile BAHState state;
public BAHash(BAHState state, BAHasher hasher, BAHEqualer equaler) {
this.hasher = hasher;
this.equaler = equaler;
this.state = state;
}
@Override
public long size() {
return state.size();
}
@Override
public void clear() {
state = state.allocate(0);
}
private long hash(BAHState state, long keyShuffle) {
keyShuffle += keyShuffle >> 8; // shuffle bits to avoid worst case clustering
if (keyShuffle < 0) {
keyShuffle = -keyShuffle;
}
return keyShuffle % state.capacity();
}
V firstValue() {
BAHState s = state;
byte[] skipped = s.skipped();
long i = s.first();
if (i != -1) {
byte[] key;
key = s.key(i);
if (key != null && key != skipped) {
return s.value(i);
}
}
return null;
}
V removeFirstValue() {
BAHState s = state;
byte[] skipped = s.skipped();
long i = s.first();
if (i != -1) {
byte[] key;
key = s.key(i);
if (key != null && key != skipped) {
V v = s.value(i);
remove(key, 0, key.length);
return v;
}
}
return null;
}
@Override
public V get(byte[] key, int keyOffset, int keyLength) {
return get(hasher.hashCode(key, keyOffset, keyLength), key, keyOffset, keyLength);
}
@Override
public V get(long hashCode, byte[] key, int keyOffset, int keyLength) {
BAHState s = state;
byte[] skipped = s.skipped();
if (key == null || key == skipped) {
return null;
}
if (s.size() == 0) {
return null;
}
long capacity = s.capacity();
long start = hash(s, hashCode);
for (long i = start, j = 0, k = capacity; // stack vars for efficiency
j < k; // max search for key
i = (++i) % k, j++) { // wraps around table
byte[] storedKey = s.key(i);
if (storedKey == skipped) {
continue;
}
if (storedKey == null) {
return null;
}
if (equaler.equals(storedKey, key, keyOffset, keyLength)) {
return s.value(i);
}
}
return null;
}
@Override
public void remove(byte[] key, int keyOffset, int keyLength) {
remove(hasher.hashCode(key, keyOffset, keyLength), key, keyOffset, keyLength);
}
@SuppressWarnings("unchecked")
@Override
public void remove(long hashCode, byte[] key, int keyOffset, int keyLength) {
BAHState s = state;
byte[] skipped = s.skipped();
if (key == null || key == skipped) {
return;
}
if (s.size() == 0) {
return;
}
long capacity = s.capacity();
long start = hash(s, hashCode);
for (long i = start, j = 0, k = capacity; // stack vars for efficiency
j < k; // max search for key
i = (++i) % k, j++) { // wraps around table
byte[] storedKey = s.key(i);
if (storedKey == skipped) {
continue;
}
if (storedKey == null) {
return;
}
if (equaler.equals(storedKey, key, keyOffset, keyLength)) {
s.remove(i, skipped, null);
long next = (i + 1) % k;
if (s.key(next) == null) {
for (long z = i, y = 0; y < capacity; z = (z + capacity - 1) % k, y++) {
if (s.key(z) != skipped) {
break;
}
s.clear(z);
}
}
return;
}
}
}
@Override
public void put(byte[] key, V value) {
put(hasher.hashCode(key, 0, key.length), key, value);
}
@SuppressWarnings("unchecked")
@Override
public void put(long hashCode, byte[] key, V value) {
BAHState s = state;
long capacity = s.capacity();
if (s.size() * 2 >= capacity) {
BAHState to = s.allocate(capacity * 2);
rehash(s, to);
state = to;
s = to;
}
internalPut(s, hashCode, key, value);
}
private void internalPut(BAHState s, long hashCode, byte[] key, V value) {
long capacity = s.capacity();
long start = hash(s, hashCode);
byte[] skipped = s.skipped();
for (long i = start, j = 0, k = capacity; // stack vars for efficiency
j < k; // max search for available slot
i = (++i) % k, j++) {
// wraps around table
byte[] storedKey = s.key(i);
if (storedKey == key) {
s.update(i, key, value);
return;
}
if (storedKey == null || storedKey == skipped) {
s.link(i, key, value);
return;
}
if (equaler.equals(storedKey, key, 0, key.length)) {
s.update(i, key, value);
return;
}
}
}
private void rehash(BAHState from, BAHState to) {
long i = from.first();
byte[] skipped = to.skipped();
while (i != -1) {
byte[] storedKey = from.key(i);
if (storedKey != null && storedKey != skipped) {
long hash = hasher.hashCode(storedKey, 0, storedKey.length);
internalPut(to, hash, storedKey, from.value(i));
}
i = from.next(i);
}
}
@Override
public boolean stream(Semaphore semaphore, KeyValueStream stream) throws Exception {
BAHState s = state;
long c = s.capacity();
if (c <= 0) {
return true;
}
byte[] skipped = s.skipped();
long i = s.first();
while (i != -1) {
byte[] key;
V value = null;
semaphore.acquire();
try {
key = s.key(i);
if (key != null && key != skipped) {
value = s.value(i);
}
} finally {
semaphore.release();
}
if (key != null && key != skipped) {
if (!stream.keyValue(key, value)) {
return false;
}
}
i = s.next(i);
}
return true;
}
@Override
public String toString() {
return "BAHash{" + "hasher=" + hasher + ", equaler=" + equaler + ", state=" + state + '}';
}
}