sclass DoubleKeyedMap {
new Map> map1;
new Map> map2;
Map getA(A a) { ret map1.get(a); }
Map getB(B b) { ret map2.get(b); }
Cl valuesForA(A a) { ret values(getA(a)); }
Cl valuesForB(B b) { ret values(getB(b)); }
Set bsForA(A a) { ret keys(getA(a)); }
Set asForB(B b) { ret keys(getB(b)); }
C get(A a, B b) { ret mapGet(map1.get(a), b); }
C get(Pair p) { ret p == null ? null : get(p.a, p.b); }
C put(A a, B b, C c) {
mapGetOrCreateHashMap(map1, a).put(b, c);
ret mapGetOrCreateHashMap(map2, b).put(a, c);
}
C put(Pair p, C c) {
ret put(p.a, p.b, c);
}
C remove(A a, B b) {
nestedMapRemove(map1, a, b);
ret nestedMapRemove(map2, b, a);
}
Set aKeys() { ret keys(map1); }
Set bKeys() { ret keys(map2); }
void removeAllA(Iterable l) { fOr (A a : l) removeA(a); }
void removeA(A a) {
fOr (B b : cloneList(bsForA(a))) remove(a, b);
}
}