sclass ExpiringMap2 extends AbstractMap {
Map> byKey = new HashMap;
new PriorityBlockingQueue> queue;
long standardExpiryTime; // ms
bool renewOnOverwrite = true;
O onChange;
// new RestartableCountdown countdown; // TODO
*() {}
*(long *standardExpiryTime) {}
*(long *standardExpiryTime, O *onChange) {}
bool clean() {
bool changes = false;
Pair p;
while ((p = queue.peek()) != null && sysTime() >= p.a) {
p = queue.poll();
ifdef ExpiringMap2_debug
print("ExpiringMap: retiring key " + p.b);
endifdef
Pair v = byKey.get(p.b);
if (v != null /*&& v.a == p.a*/) {
ifdef ExpiringMap2_debug
print("ExpiringMap: retired key " + p.b);
endifdef
byKey.remove(p.b);
changes = true;
change();
}
}
ret changes;
}
void change() { callF(onChange); }
public B put(A a, B b) {
clean();
long timeout = sysTime()+standardExpiryTime;
Pair p = byKey.get(a);
if (p != null && renewOnOverwrite)
queue.remove(PairComparedByA(p.a, a));
byKey.put(a, pair(timeout, b));
change();
if (p == null || renewOnOverwrite)
queue.add(PairComparedByA(timeout, a));
ret pairB(p);
}
public B remove(O a) {
clean();
Pair p = byKey.get(a);
if (p == null) null;
queue.remove(PairComparedByA(p.a, a));
byKey.remove(a);
change();
ret p.b;
}
public B get(O a) {
clean();
ret pairB(byKey.get(a));
}
public Set> entrySet() {
clean();
// TODO: mutex
ret mapValues(f pairB, byKey).entrySet();
}
public Set keySet() {
clean();
ret byKey.keySet();
}
public int size() {
clean();
ret byKey.size();
}
}