static class MultiMap {
Map> data = new HashMap>();
MultiMap() {}
MultiMap(bool useTreeMap) { if (useTreeMap) data = new TreeMap; }
MultiMap(MultiMap map) { putAll(map); }
synchronized void put(A key, B value) {
List list = data.get(key);
if (list == null)
data.put(key, list = new ArrayList());
list.add(value);
}
synchronized void addAll(A key, Collection values) {
putAll(key, values);
}
synchronized void addAllIfNotThere(A key, Collection values) {
for (B value : values)
setPut(key, value);
}
synchronized void setPut(A key, B value) {
if (!containsPair(key, value))
put(key, value);
}
synchronized boolean containsPair(A key, B value) {
ret get(key).contains(value);
}
synchronized void putAll(A key, Collection values) {
for (B value : values)
put(key, value);
}
synchronized void removeAll(A key, Collection values) {
for (B value : values)
remove(key, value);
}
synchronized List get(A key) {
List list = data.get(key);
return list == null ? Collections. emptyList() : list;
}
// returns actual mutable live list
// creates the list if not there
synchronized List getActual(A key) {
List list = data.get(key);
if (list == null)
data.put(key, list = litlist());
ret list;
}
synchronized void clean(A key) {
L list = data.get(key);
if (list != null && list.isEmpty())
data.remove(key);
}
synchronized Set keySet() {
return data.keySet();
}
synchronized Set keys() {
return data.keySet();
}
synchronized void remove(A key) {
data.remove(key);
}
synchronized void remove(A key, B value) {
List list = data.get(key);
if (list != null) {
list.remove(value);
if (list.isEmpty())
data.remove(key);
}
}
synchronized void clear() {
data.clear();
}
synchronized boolean containsKey(A key) {
return data.containsKey(key);
}
synchronized B getFirst(A key) {
List list = get(key);
return list.isEmpty() ? null : list.get(0);
}
synchronized void putAll(MultiMap map) {
for (A key : map.keySet())
putAll(key, map.get(key));
}
// note: expensive operation
synchronized int size() {
int n = 0;
for (L l : data.values())
n += l(l);
ret n;
}
// expensive operation
synchronized L reverseGet(B b) {
new L l;
for (A key : data.keySet())
if (data.get(key).contains(b))
l.add(key);
ret l;
}
synchronized Map> asMap() {
ret cloneMap(data);
}
bool isEmpty() { ret data.isEmpty(); }
}