package org.quaere.alias;
import java.lang.ref.WeakReference;
public class WeakIdentityHashMap<K, V> {
private int mask, len, size, deletedCount, level;
private int maxSize, minSize, maxDeleted;
private static final int MAX_LOAD = 90;
private static final WeakReference DELETED_KEY = new WeakReference(null);
private WeakReference<K>[] keys;
private V[] values;
public WeakIdentityHashMap() {
reset(2);
}
public int size() {
return size;
}
private void checkSizePut() {
if (deletedCount > size) {
rehash(level);
}
if (size + deletedCount >= maxSize) {
rehash(level + 1);
}
}
private void checkSizeRemove() {
if (size < minSize && level > 0) {
rehash(level - 1);
} else if (deletedCount > maxDeleted) {
rehash(level);
}
}
private int getIndex(Object key) {
return System.identityHashCode(key) & mask;
}
private void reset(int newLevel) {
minSize = size * 3 / 4;
size = 0;
level = newLevel;
len = 2 << level;
mask = len - 1;
maxSize = (int) (len * MAX_LOAD / 100L);
deletedCount = 0;
maxDeleted = 20 + len / 2;
keys = new WeakReference[len];
values = (V[]) new Object[len];
}
public void put(K key, V value) {
checkSizePut();
int index = getIndex(key);
int plus = 1;
int deleted = -1;
do {
WeakReference k = keys[index];
if (k == null) {
// found an empty record
if (deleted >= 0) {
index = deleted;
deletedCount--;
}
size++;
keys[index] = new WeakReference(key);
values[index] = value;
return;
} else if (k == DELETED_KEY) {
if (deleted < 0) {
// found the first deleted record
deleted = index;
}
} else {
Object r = k.get();
if (r == null) {
delete(index);
} else if (r == key) {
// update existing
values[index] = value;
return;
}
}
index = (index + plus++) & mask;
} while(plus <= len);
throw new Error("hashmap is full");
}
public void remove(Object key) {
checkSizeRemove();
int index = getIndex(key);
int plus = 1;
do {
WeakReference k = keys[index];
if (k == null) {
// found an empty record
return;
} else if (k == DELETED_KEY) {
// continue
} else {
Object r = k.get();
if (r == null) {
delete(index);
} else if (r == key) {
// found the record
delete(index);
return;
}
}
index = (index + plus++) & mask;
k = keys[index];
} while(plus <= len);
// not found
}
private void delete(int index) {
keys[index] = DELETED_KEY;
values[index] = null;
deletedCount++;
size--;
}
private void rehash(int newLevel) {
WeakReference[] oldKeys = keys;
V[] oldValues = values;
reset(newLevel);
for (int i = 0; i < oldKeys.length; i++) {
WeakReference<K> k = oldKeys[i];
if (k != null && k != DELETED_KEY) {
K key = k.get();
if (key != null) {
put(key, oldValues[i]);
}
}
}
}
public V get(K key) {
int index = getIndex(key);
int plus = 1;
do {
WeakReference k = keys[index];
if (k == null) {
return null;
} else if (k == DELETED_KEY) {
// continue
} else {
Object r = k.get();
if (r == null) {
delete(index);
} else if (r == key) {
return values[index];
}
}
index = (index + plus++) & mask;
} while(plus <= len);
return null;
}
}