sclass ExpiringMap2 extends AbstractMap {
Map> byKey = new HashMap; // key -> pair(expiry sys time, value)
new PriorityBlockingQueue> queue; // queue(pair(expiry sys time, key))
long standardExpiryTime; // ms
bool renewOnOverwrite = true, renewOnGet;
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(Pair(p.a, a));
byKey.put(a, pair(timeout, b));
if (p == null || renewOnOverwrite)
queue.add(Pair(timeout, a));
change();
ret pairB(p);
}
public B remove(O a) {
clean();
Pair p = byKey.get(a);
if (p == null) null;
queue.remove(Pair(p.a, a));
byKey.remove(a);
change();
ret p.b;
}
public B get(O a) {
clean();
Pair p = byKey.get(a);
if (renewOnGet && p != null) {
queue.remove(Pair(p.a, a));
long timeout = sysTime()+standardExpiryTime;
byKey.put((A) a, pair(timeout, p.b));
queue.add(Pair(timeout, a));
}
ret pairB(p);
}
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();
}
void setStandardExpiryTime(long ms) { standardExpiryTime = ms; }
ExpiringMap2 setMap(Map innerMap) {
byKey = innerMap;
this;
}
}