edu.stanford.nlp.util.DeltaCollectionValuedMap Maven / Gradle / Ivy
package edu.stanford.nlp.util;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
/**
* Implementation of CollectionValuedMap that appears to store an "original"
* map and changes to that map. No one currently uses it. See {@link DeltaMap}.
*
* @author Teg Grenager ([email protected])
* Date: Jan 14, 2004
* Time: 10:40:57 AM
*/
public class DeltaCollectionValuedMap extends CollectionValuedMap {
private static final long serialVersionUID = 1L;
private CollectionValuedMap originalMap;
private Map> deltaMap;
private static Object removedValue = new Object();
// private CollectionFactory cf; //this was just hiding a field in CollectionValuedMap
static class SimpleEntry implements Map.Entry {
K key;
V value;
public SimpleEntry(K key, V value) {
this.key = key;
this.value = value;
}
public SimpleEntry(Map.Entry e) {
this.key = e.getKey();
this.value = e.getValue();
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public V setValue(V value) {
V oldValue = this.value;
this.value = value;
return oldValue;
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object o) {
if (!(o instanceof Map.Entry)) {
return false;
}
Map.Entry e = ErasureUtils.uncheckedCast(o);
return eq(key, e.getKey()) && eq(value, e.getValue());
}
@Override
public int hashCode() {
return ((key == null) ? 0 : key.hashCode()) ^ ((value == null) ? 0 : value.hashCode());
}
@Override
public String toString() {
return key + "=" + value;
}
private static boolean eq(Object o1, Object o2) {
return (o1 == null ? o2 == null : o1.equals(o2));
}
}
@Override
public Collection get(Object key) {
// key could be not in original or in deltaMap
// key could be not in original but in deltaMap
// key could be in original but removed from deltaMap
// key could be in original but mapped to something else in deltaMap
Collection deltaResult = deltaMap.get(key);
if (deltaResult == null) {
return originalMap.get(key);
}
if (deltaResult == removedValue) {
return cf.newEmptyCollection();
}
return deltaResult;
}
// Modification Operations
@Override
public Collection put(K key, Collection value) {
throw new UnsupportedOperationException();
}
@Override
public void putAll(Map extends K, ? extends Collection> m) {
throw new UnsupportedOperationException();
}
@Override
public void add(K key, V value) {
Collection deltaC = deltaMap.get(key);
if (deltaC == null) {
deltaC = cf.newCollection();
Collection originalC = originalMap.get(key);
if (originalC != null) {
deltaC.addAll(originalC);
}
deltaMap.put(key, deltaC);
}
deltaC.add(value);
}
/**
* Adds all of the mappings in m to this CollectionValuedMap.
* If m is a CollectionValuedMap, it will behave strangely. Use the constructor instead.
*
*/
@Override
public void addAll(Map m) {
for (Map.Entry e : m.entrySet()) {
add(e.getKey(), e.getValue());
}
}
@Override
public Collection remove(Object key) {
Collection result = get(key);
deltaMap.put(ErasureUtils.uncheckedCast(key), ErasureUtils.>uncheckedCast(removedValue));
return result;
}
@Override
public void removeMapping(K key, V value) {
Collection deltaC = deltaMap.get(key);
if (deltaC == null) {
Collection originalC = originalMap.get(key);
if (originalC != null && originalC.contains(value)) {
deltaC = cf.newCollection();
deltaC.addAll(originalC);
deltaMap.put(key, deltaC);
}
}
if (deltaC != null) {
deltaC.remove(value);
}
}
@Override
public boolean containsKey(Object key) {
// key could be not in original or in deltaMap
// key could be not in original but in deltaMap
// key could be in original but removed from deltaMap
// key could be in original but mapped to something else in deltaMap
Object value = deltaMap.get(key);
if (value == null) {
return originalMap.containsKey(key);
}
if (value == removedValue) {
return false;
}
return true;
}
@Override
public boolean containsValue(Object value) {
throw new UnsupportedOperationException();
}
// Bulk Operations
/**
* This is more expensive than normal.
*/
@Override
public void clear() {
// iterate over all keys in originalMap and set them to null in deltaMap
for (K key : originalMap.keySet()) {
deltaMap.put(key, ErasureUtils.>uncheckedCast(removedValue));
}
}
@Override
public boolean isEmpty() {
return size() == 0;
}
@Override
public int size() {
return entrySet().size();
}
@Override
public Collection> values() {
throw new UnsupportedOperationException();
}
// Views
/**
* This is cheap.
*
* @return a set view of the mappings contained in this map.
*/
@Override
public Set>> entrySet() {
return new AbstractSet>>() {
@Override
public Iterator>> iterator() {
Predicate>> filter1 = new Predicate>>() {
private static final long serialVersionUID = -3257173354412718639L;
// only accepts stuff not overwritten by deltaMap
public boolean test(Map.Entry> e) {
K key = e.getKey();
if (deltaMap.containsKey(key)) {
return false;
}
return true;
}
};
Iterator>> iter1 = new FilteredIterator<>(originalMap.entrySet().iterator(), filter1);
Predicate>> filter2 = new Predicate>>() {
private static final long serialVersionUID = 1L;
// only accepts stuff not overwritten by deltaMap
public boolean test(Map.Entry> e) {
if (e.getValue() == removedValue) {
return false;
}
return true;
}
};
Iterator>> iter2 = new FilteredIterator<>(deltaMap.entrySet().iterator(), filter2);
return new ConcatenationIterator<>(iter1, iter2);
}
@Override
public int size() {
int size = 0;
for (// @SuppressWarnings("unused") // this makes javac v1.5 barf!!
Entry> entry : this) {
ErasureUtils.noop(entry);
size++;
}
return size;
}
};
}
public DeltaCollectionValuedMap(CollectionValuedMap originalMap) {
this.originalMap = originalMap;
this.cf = originalMap.cf;
this.mf = originalMap.mf;
this.deltaMap = mf.newMap();
}
}