package arkref.ext.fig.basic;
import static arkref.ext.fig.basic.LogInfo.*;
import java.io.*;
import java.util.*;
import arkref.ext.fig.basic.*;
/**
* Maps (object, object) pairs to objects.
* Based on T2VMap.
* It's useful when the number of second objects for a fixed first string
* is small.
* Most of the operations in this class parallel that of T2VMap<T>,
* but just applied to two keys. The implementation is essentially dispatching
* down to T2VMap<T>.
* Typical usage: conditional probability table.
*/
public class T2VMap<S, T, V> extends AbstractT2Map implements Iterable<Map.Entry<S, TVMap<T, V>>>, Serializable {
protected static final long serialVersionUID = 42;
public T2VMap() {
this.keyFunc = AbstractTMap.defaultFunctionality;
this.valueFunc = AbstractTMap.defaultFunctionality;
}
public T2VMap(AbstractTMap.Functionality<T> keyFunc, AbstractTMap.Functionality<V> valueFunc) {
this.keyFunc = keyFunc;
this.valueFunc = valueFunc;
}
public void initKeys(AbstractT2Map map) {
this.locked = map.locked;
// HACK: BAD dependencies
if(map instanceof T2DoubleMap) {
for(Map.Entry<S, TDoubleMap<T>> e : (T2DoubleMap<S, T>)map)
put(e.getKey(), new TVMap<T, V>(e.getValue(), valueFunc));
}
else if(map instanceof T2VMap) { // Not exactly right: need to check type of V
for(Map.Entry<S, TVMap<T, V>> e : ((T2VMap<S, T, V>)map))
put(e.getKey(), new TVMap<T, V>(e.getValue(), valueFunc));
}
else
throw new RuntimeException("");
}
// Main operations
public boolean containsKey(S key1, T key2) {
TVMap<T, V> map = getMap(key1, false);
return map != null && map.containsKey(key2);
}
public V get(S key1, T key2, V defaultValue) {
TVMap<T, V> map = getMap(key1, false);
return map == null ? defaultValue : map.get(key2, defaultValue);
}
public V getWithErrorMsg(S key1, T key2, V defaultValue) {
TVMap<T, V> map = getMap(key1, false);
if(map == null) errors("(%s, %s) not in map, using %f", key1, key2, defaultValue);
return map == null ? defaultValue : map.get(key2, defaultValue);
}
public V getSure(S key1, T key2) {
// Throw exception if key doesn't exist.
TVMap<T, V> map = getMap(key1, false);
if(map == null) throw new RuntimeException("Missing key: " + key1);
return map.getSure(key2);
}
public void put(S key1, TVMap<T, V> map) { // Risky
if(locked)
throw new RuntimeException("Cannot make new entry for " + key1 + ", because map is locked");
maps.put(key1, map);
}
public void put(S key1, T key2, V value) {
TVMap<T, V> map = getMap(key1, true);
map.put(key2, value);
}
public int size() { return maps.size(); }
// Return number of entries
public int totalSize() {
int n = 0;
for(TVMap<T, V> map : maps.values())
n += map.size();
return n;
}
public void gut() {
for(TVMap<T, V> map : maps.values())
map.gut();
}
public Iterator<Map.Entry<S, TVMap<T, V>>> iterator() {
return maps.entrySet().iterator();
}
public Set<Map.Entry<S, TVMap<T, V>>> entrySet() { return maps.entrySet(); }
public Set<S> keySet() { return maps.keySet(); }
public Collection<TVMap<T, V>> values() { return maps.values(); }
// If keys are locked, we can share the same keys.
public T2VMap<S, T, V> copy() {
return copy(newMap());
}
public T2VMap<S, T, V> copy(T2VMap<S, T, V> newMap) {
newMap.locked = locked;
for(Map.Entry<S, TVMap<T, V>> e : maps.entrySet())
newMap.maps.put(e.getKey(), e.getValue().copy());
return newMap;
}
public T2VMap<S, T, V> restrict(Set<S> set1, Set<T> set2) {
return restrict(newMap(), set1, set2);
}
public T2VMap<S, T, V> restrict(T2VMap<S, T, V> newMap, Set<S> set1, Set<T> set2) {
newMap.locked = locked;
for(Map.Entry<S, TVMap<T, V>> e : maps.entrySet())
if(set1.contains(e.getKey()))
newMap.maps.put(e.getKey(), e.getValue().restrict(set2));
return newMap;
}
public T2VMap<T, S, V> reverse(T2VMap<T, S, V> newMap) { // Return a map with (key2, key1) pairs
for(Map.Entry<S, TVMap<T, V>> e1 : maps.entrySet()) {
S key1 = e1.getKey();
TVMap<T, V> map = e1.getValue();
for(TVMap<T, V>.Entry e2 : map) {
T key2 = e2.getKey();
V value = e2.getValue();
newMap.put(key2, key1, value);
}
}
return newMap;
}
public void lock() {
for(TVMap<T, V> map : maps.values())
map.lock();
}
public void switchToSortedList() {
for(TVMap<T, V> map : maps.values())
map.switchToSortedList();
}
public void switchToHashTable() {
for(TVMap<T, V> map : maps.values())
map.switchToHashTable();
}
protected T2VMap<S, T, V> newMap() { return new T2VMap<S, T, V>(keyFunc, valueFunc); }
////////////////////////////////////////////////////////////
public TVMap<T, V> getMap(S key1, boolean modify) {
if(key1 == lastKey) return lastMap;
TVMap<T, V> map = maps.get(key1);
if(map != null) return map;
if(modify) {
if(locked)
throw new RuntimeException("Cannot make new entry for " + key1 + ", because map is locked");
maps.put(key1, map = new TVMap<T, V>(keyFunc, valueFunc));
lastKey = key1;
lastMap = map;
return map;
}
else
return null;
}
////////////////////////////////////////////////////////////
private Map<S, TVMap<T, V>> maps = new HashMap<S, TVMap<T, V>>();
private S lastKey; // Cache last access
private TVMap<T, V> lastMap; // Cache last access
protected TVMap.Functionality<V> valueFunc;
}