All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.stanford.nlp.util.DeltaMap Maven / Gradle / Ivy

package edu.stanford.nlp.util;

import java.util.*;
import java.util.function.Predicate;

/**
 * A Map which wraps an original Map, and only stores the changes (deltas) from
 * the original Map. This increases Map access time (roughly doubles it) but eliminates
 * Map creation time and decreases memory usage (if you're keeping the original Map in memory
 * anyway).
 * 

* @author Teg Grenager ([email protected]) * @version Jan 9, 2004 9:19:06 AM */ public class DeltaMap extends AbstractMap { private Map originalMap; private Map deltaMap; private static Object nullValue = new Object(); private static Object removedValue = new Object(); 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; } @Override public boolean equals(Object o) { if (!(o instanceof Map.Entry)) { return false; } @SuppressWarnings("unchecked") Map.Entry e = (Map.Entry) 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)); } } /** * This is more expensive. * * @param key key whose presence in this map is to be tested. * @return true if this map contains a mapping for the specified * key. */ @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; } /** * This may cost twice what it would in the original Map. * * @param key key whose associated value is to be returned. * @return the value to which this map maps the specified key, or * null if the map contains no mapping for this key. */ @Override public V 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 V deltaResult = deltaMap.get(key); if (deltaResult == null) { return originalMap.get(key); } if (deltaResult == nullValue) { return null; } if (deltaResult == removedValue) { return null; } return deltaResult; } // Modification Operations /** * This may cost twice what it would in the original Map because we have to find * the original value for this key. * * @param key key with which the specified value is to be associated. * @param value value to be associated with the specified key. * @return previous value associated with specified key, or null * if there was no mapping for key. A null return can * also indicate that the map previously associated null * with the specified key, if the implementation supports * null values. */ @Override @SuppressWarnings("unchecked") public V put(K key, V value) { if (value == null) { return put(key, (V)nullValue); } // 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 V result = deltaMap.put(key, value); if (result == null) { return originalMap.get(key); } if (result == nullValue) { return null; } if (result == removedValue) { return null; } return result; } /** * */ @Override @SuppressWarnings("unchecked") public V remove(Object key) { // always put it locally return put((K)key, (V)removedValue); } // Bulk Operations /** * This is more expensive than normal. */ @Override @SuppressWarnings("unchecked") public void clear() { // iterate over all keys in originalMap and set them to null in deltaMap for (K key : originalMap.keySet()) { deltaMap.put(key, (V)removedValue); } } // 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 = 1L; // only accepts stuff not overwritten by deltaMap public boolean test(Map.Entry e) { K key = e.getKey(); return ! deltaMap.containsKey(key); } }; 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) { Object value = e.getValue(); if (value == removedValue) { return false; } return true; } }; class NullingIterator implements Iterator> { private Iterator> i; public NullingIterator(Iterator> i) { this.i = i; } public boolean hasNext() { return i.hasNext(); } public Map.Entry next() { Map.Entry e = i.next(); Object o = e.getValue(); if (o == nullValue) { return new SimpleEntry<>(e.getKey(), null); } return e; } public void remove() { throw new UnsupportedOperationException(); } } Iterator> iter2 = new FilteredIterator<>(new NullingIterator<>(deltaMap.entrySet().iterator()), filter2); return new ConcatenationIterator<>(iter1, iter2); } @Override public int size() { int size = 0; for (Entry kvEntry : this) { ErasureUtils.noop(kvEntry); size++; } return size; } }; } /** * This is very cheap. * * @param originalMap will serve as the basis for this DeltaMap */ public DeltaMap(Map originalMap, MapFactory mf) { this.originalMap = Collections.unmodifiableMap(originalMap); // unmodifiable for debugging only this.deltaMap = mf.newMap(); } @SuppressWarnings("unchecked") public DeltaMap(Map originalMap) { this(originalMap, MapFactory.HASH_MAP_FACTORY); } /** * For testing only. * * @param args from command line */ public static void main(String[] args) { Map originalMap = Generics.newHashMap(); Random r = new Random(); for (int i = 0; i < 1000; i++) { originalMap.put(Integer.valueOf(i), Integer.valueOf(r.nextInt(1000))); } Map originalCopyMap = Generics.newHashMap(originalMap); Map deltaCopyMap = Generics.newHashMap(originalMap); Map deltaMap = new DeltaMap<>(originalMap); // now make a lot of changes to deltaMap; // add and change some stuff for (int i = 900; i < 1100; i++) { Integer rInt = Integer.valueOf(r.nextInt(1000)); deltaMap.put(Integer.valueOf(i), rInt); deltaCopyMap.put(Integer.valueOf(i), rInt); } // remove some stuff for (int i = 0; i < 100; i++) { Integer rInt = Integer.valueOf(r.nextInt(1100)); deltaMap.remove(rInt); deltaCopyMap.remove(rInt); } // set some stuff to null for (int i = 0; i < 100; i++) { Integer rInt = Integer.valueOf(r.nextInt(1100)); deltaMap.put(rInt, null); deltaCopyMap.put(rInt, null); } System.out.println("Original preserved? " + originalCopyMap.equals(originalMap)); System.out.println("Delta accurate? " + deltaMap.equals(deltaCopyMap)); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy