/* * This file is part of the X10 project (http://x10-lang.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.opensource.org/licenses/eclipse-1.0.php * * This file was originally derived from the Polyglot extensible compiler framework. * * (C) Copyright 2000-2007 Polyglot project group, Cornell University * (C) Copyright IBM Corporation 2007-2012. */ package polyglot.util; import java.util.*; import polyglot.util.FilteringIterator; import x10.util.CollectionFactory; /** * A NestedMap is a map which, when it cannot find an element in itself, * defers to another map. Modifications, however, are not passed on to * the supermap. * * A NestedMap and its backing collections and iterators support all * operations except 'remove' and 'clear', since operations to a * NestedMap must not affect the backing map. Instead, use the 'release' * method. * * It is used to implement nested namespaces, such as those which store * local-variable bindings. **/ public class NestedMap<K,V> extends AbstractMap<K,V> implements Map<K,V> { /** * Creates a new nested map, which defers to <containing>. If containing * is null, it defaults to a NilMap. **/ public NestedMap(Map<K,V> containing) { this.superMap = containing; this.myMap = CollectionFactory.newHashMap(); setView = new EntrySet(); nShadowed = 0; } ///// // For NestedMap. ///// /** * Returns the map to which this map defers, or null for none. **/ public Map<K,V> getContainingMap() { return superMap; } /** * Removes any binding in this for <key>, returning to the binding (if any) * from the supermap. **/ public void release(Object key) { myMap.remove(key); } /** * Returns the map containing the elements for this level of nesting. **/ public Map<K,V> getInnerMap() { return myMap; } ///// // Methods required for AbstractMap. ///// public Set<Map.Entry<K,V>> entrySet() { return setView; } public int size() { return superMap.size() + myMap.size() - nShadowed; } public boolean containsKey(Object key) { return myMap.containsKey(key) || superMap.containsKey(key); } public V get(Object key) { if (myMap.containsKey(key)) return myMap.get(key); else return superMap.get(key); } public V put(K key, V value) { if (myMap.containsKey(key)) { return myMap.put(key,value); } else { V oldV = superMap.get(key); myMap.put(key,value); nShadowed++; return oldV; } } public V remove(Object key) { throw new UnsupportedOperationException("Remove from NestedMap"); } public void clear() { throw new UnsupportedOperationException("Clear in NestedMap"); } public final class KeySet extends AbstractSet<K> { public Iterator<K> iterator() { return new ConcatenatedIterator<K>( myMap.keySet().iterator(), new FilteringIterator<K>(superMap.keySet(), keyNotInMyMap)); } public int size() { return NestedMap.this.size(); } // No add; it's not meaningful. public boolean contains(Object o) { return NestedMap.this.containsKey(o); } public boolean remove(Object o) { throw new UnsupportedOperationException( "Remove from NestedMap.keySet"); } } private final class EntrySet extends AbstractSet<Map.Entry<K,V>> { public Iterator<Map.Entry<K,V>> iterator() { return new ConcatenatedIterator<Map.Entry<K,V>>( myMap.entrySet().iterator(), new FilteringIterator<Map.Entry<K, V>>(superMap.entrySet(), entryKeyNotInMyMap)); } public int size() { return NestedMap.this.size(); } // No add; it's not meaningful. @SuppressWarnings("unchecked") // Casting to a generic type public boolean contains(Object o) { if (!(o instanceof Map.Entry<?,?>)) return false; Map.Entry<K,V> ent = (Map.Entry<K,V>) o; K entKey = ent.getKey(); V entVal = ent.getValue(); if (entVal != null) { V val = NestedMap.this.get(entKey); return (val != null) && val.equals(entVal); } else { return NestedMap.this.containsKey(entKey) && (NestedMap.this.get(entKey) == null); } } public boolean remove(Object o) { throw new UnsupportedOperationException( "Remove from NestedMap.entrySet"); } } private Map<K,V> myMap; private int nShadowed; private Set<Map.Entry<K,V>> setView; // the set view of this. private Map<K,V> superMap; private Predicate<Map.Entry<K,V>> entryKeyNotInMyMap = new Predicate<Map.Entry<K,V>>() { public boolean isTrue(Map.Entry<K,V> ent) { return ! myMap.containsKey(ent.getKey()); } }; private Predicate<K> keyNotInMyMap = new Predicate<K>() { public boolean isTrue(K o) { return ! myMap.containsKey(o); } }; }