| package annotations.util.coll; |
| |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| /*>>> |
| import org.checkerframework.checker.nullness.qual.Nullable; |
| */ |
| |
| /** |
| * A {@link VivifyingMap} is a map that can create "empty" values on demand |
| * and prune "empty" values, for some definition of "empty". |
| */ |
| public abstract class VivifyingMap<K, V> extends WrapperMap<K, V> { |
| /** |
| * Constructs a new {@link VivifyingMap} backed by the given map. All |
| * reads and writes to this {@link VivifyingMap} go through to the backing |
| * map. However, since the {@link VivifyingMap} generally provides a |
| * superset of the functionality of the backing map, it is rarely useful to |
| * access the backing map directly; the parameter is given mainly so you |
| * can provide a new map of your favorite class ({@link java.util.HashMap}, |
| * {@link java.util.LinkedHashMap}, etc.). |
| */ |
| public VivifyingMap(Map<K, V> back) { |
| super(back); |
| } |
| |
| /** |
| * Returns the value to which the specified key is mapped; if the key is |
| * not currently mapped to a value, a new, empty value is created, stored, |
| * and returned. |
| */ |
| public V vivify(K k) { |
| if (containsKey(k)) { |
| return get(k); |
| } else { |
| V v = createValueFor(k); |
| put(k, v); |
| return v; |
| } |
| } |
| |
| /** |
| * Prunes this map by deleting entries with empty values (i.e., entries |
| * that could be recreated by {@link #vivify} without information loss). |
| */ |
| public boolean prune() { |
| boolean empty = true; |
| for (Iterator<Map.Entry<K, V>> ei |
| = entrySet().iterator(); ei.hasNext(); ) { |
| Map.Entry<K, V> e = ei.next(); |
| boolean subEmpty = subPrune(e.getValue()); |
| if (subEmpty) { |
| ei.remove(); |
| } else { |
| empty = false; |
| } |
| } |
| return empty; |
| } |
| |
| /** |
| * Returns a new, "empty" value to which the key <code>k</code> can be |
| * mapped; subclasses must implement. |
| */ |
| protected abstract V createValueFor(K k); |
| |
| /** |
| * Returns whether the given value is "empty" and thus may be discarded |
| * by {@link #prune}. Before returning, {@link #subPrune} may carry out |
| * some sort of recursive pruning on the value; for example, if the value |
| * is another {@link VivifyingMap}, {@link #subPrune} could prune that map. |
| */ |
| protected abstract boolean subPrune(V v); |
| } |