package org.aksw.sparqlify.database; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.aksw.commons.util.Pair; import com.google.common.collect.HashMultimap; import com.google.common.collect.Multimap; public class IndirectEquiMap<K, V> { private Map<K, Integer> keyToToken = new HashMap<K, Integer>(); private Multimap<Integer, K> tokenToKeys = HashMultimap.create(); private Map<Integer, V> tokenToValue = new HashMap<Integer, V>(); private int nextToken = 0; public Set<K> keySet() { return keyToToken.keySet(); } public Multimap<Integer, K> getEquivalences() { return tokenToKeys; } public Collection<K> getEquivalences(K key) { return tokenToKeys.get(keyToToken.get(key)); } private void putKeyToken(K key, int token) { keyToToken.put(key, token); tokenToKeys.put(token, key); } public void stateEqual(K a, K b, V value) { stateEqual(a, b, value, true); } public Pair<V, V> stateEqual(K a, K b) { return stateEqual(a, b, null, false); } /* public Collection<> stateEqual(Collection<K> keys) { }*/ public void stateEqual(Collection<K> keys, V value) { int newToken = ++nextToken; for(K key : keys) { Integer oldToken = keyToToken.get(key); if(oldToken != null) { tokenToValue.remove(oldToken); tokenToKeys.putAll(newToken, tokenToKeys.get(oldToken)); tokenToKeys.removeAll(oldToken); } putKeyToken(key, newToken); } tokenToValue.put(newToken, value); } /** * States an equality between keys. * * if overwrite is true, conflicts can not occur as they are overwritten with value. Return value is always null. * if overwrite is false, in case of conflict the pair of conflicting values is returned * * Conflicts can be resolved using stateEqual(a, b, value) * * * @param a * @param b */ private Pair<V, V> stateEqual(K a, K b, V value, boolean overwrite) { Integer ta = keyToToken.get(a); Integer tb = keyToToken.get(b); if(ta == null) { if(tb == null) { int token = ++nextToken; putKeyToken(a, token); putKeyToken(b, token); } else { putKeyToken(a, tb); } } else { if(tb == null) { putKeyToken(b, ta); } else { V va = tokenToValue.get(ta); V vb = tokenToValue.get(tb); if(va != null && vb != null && !va.equals(vb)) { // Conflict: Equality stated, but two distinct values if(overwrite) { va = value; } else { return Pair.create(va, vb); } } if(va == null) { va = vb; } // Copy to avoid ConcurrentModificationException Collection<K> ka = new ArrayList<K>(tokenToKeys.get(ta)); Collection<K> kb = new ArrayList<K>(tokenToKeys.get(tb)); Collection<K> tmp; int tt; if(kb.size() > ka.size()) { tmp = ka; ka = kb; kb = tmp; tt = ta; ta = tb; tb = tt; } for(K k : kb) { tokenToKeys.remove(tb, k); putKeyToken(k, ta); } if(va != null) { tokenToValue.put(ta, va); } } } return null; } /** * Puts a new value, overwrites existing ones. * * * @param key * @param value */ public void put(K key, V value) { Integer token = keyToToken.get(key); if(token == null) { token = ++nextToken; keyToToken.put(key, token); } tokenToValue.put(token, value); tokenToKeys.put(token, key); } public V get(K key) { Integer token = keyToToken.get(key); if(token == null) { return null; } return tokenToValue.get(token); } public boolean isEqual(K a, K b) { Integer ta = keyToToken.get(a); return ta != null && ta.equals(keyToToken.get(b)); } @Override public String toString() { String result = "["; boolean isFirst = true; for(Entry<Integer, Collection<K>> entry : tokenToKeys.asMap().entrySet()) { if(!isFirst) { result += ", "; } result += entry.getValue() + ": " + tokenToValue.get(entry.getKey()); } result += "]"; return result; } }