/* Soot - a J*va Optimization Framework * Copyright (C) 2002 Sable Research Group * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * Modified by the Sable Research Group and others 1997-1999. * See the 'credits' file distributed with Soot for the complete list of * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot) */ package soot.util; import java.util.*; public class IterableMap implements Map { private HashMap<Object, Object> content_map, back_map; private HashChain key_chain, value_chain; public IterableMap() { this( 7, 0.7f); } public IterableMap( int initialCapacity) { this( initialCapacity, 0.7f); } public IterableMap( int initialCapacity, float loadFactor) { content_map = new HashMap<Object, Object>( initialCapacity, loadFactor); back_map = new HashMap<Object, Object>( initialCapacity, loadFactor); key_chain = new HashChain(); value_chain = new HashChain(); } public void clear() { Iterator kcit = key_chain.iterator(); while (kcit.hasNext()) content_map.remove( kcit.next()); Iterator vcit = value_chain.iterator(); while (vcit.hasNext()) back_map.remove( vcit.next()); key_chain.clear(); value_chain.clear(); } public Iterator iterator() { return key_chain.iterator(); } public boolean containsKey(Object key) { return key_chain.contains( key); } public boolean containsValue(Object value) { return value_chain.contains( value); } public Set entrySet() { return content_map.entrySet(); } public boolean equals( Object o) { if (o == this) return true; if ((o instanceof IterableMap) == false) return false; IterableMap other = (IterableMap) o; if (key_chain.equals( other.key_chain) == false) return false; // check that the other has our mapping Iterator kcit = key_chain.iterator(); while (kcit.hasNext()) { Object ko = kcit.next(); if (other.content_map.get( ko) != content_map.get( ko)) return false; } return true; } public Object get( Object key) { return content_map.get( key); } public int hashCode() { return content_map.hashCode(); } public boolean isEmpty() { return key_chain.isEmpty(); } private transient Set<Object> keySet = null; private transient Set<Object> valueSet = null; private transient Collection<Object> values = null; public Set<Object> keySet() { if (keySet == null) { keySet = new AbstractSet() { public Iterator iterator() { return key_chain.iterator(); } public int size() { return key_chain.size(); } public boolean contains(Object o) { return key_chain.contains(o); } public boolean remove(Object o) { if (key_chain.contains(o) == false) { return false; } if (IterableMap.this.content_map.get( o) == null) { IterableMap.this.remove(o); return true; } return (IterableMap.this.remove(o) != null); } public void clear() { IterableMap.this.clear(); } }; } return keySet; } public Set<Object> valueSet() { if (valueSet == null) { valueSet = new AbstractSet() { public Iterator iterator() { return value_chain.iterator(); } public int size() { return value_chain.size(); } public boolean contains(Object o) { return value_chain.contains(o); } public boolean remove(Object o) { if (value_chain.contains( o) == false) { return false; } HashChain c = (HashChain) IterableMap.this.back_map.get( o); Iterator it = c.snapshotIterator(); while (it.hasNext()) { Object ko = it.next(); if (IterableMap.this.content_map.get( o) == null) { IterableMap.this.remove(ko); } else if (IterableMap.this.remove( ko) == null) { return false; } } return true; } public void clear() { IterableMap.this.clear(); } }; } return valueSet; } public Object put( Object key, Object value) { if (key_chain.contains( key)) { Object old_value = content_map.get( key); if (old_value == value) return value; HashChain kc = (HashChain) back_map.get( old_value); kc.remove( key); if (kc.isEmpty()) { value_chain.remove( old_value); back_map.remove( old_value); } kc = (HashChain) back_map.get( value); if (kc == null) { kc = new HashChain(); back_map.put( value, kc); value_chain.add( value); } kc.add( key); return old_value; } else { key_chain.add(key); content_map.put( key, value); HashChain kc = (HashChain) back_map.get( value); if (kc == null) { kc = new HashChain(); back_map.put( value, kc); value_chain.add( value); } kc.add( key); return null; } } public void putAll( Map t) { Iterator kit = (t instanceof IterableMap) ? ((IterableMap) t).key_chain.iterator() : t.keySet().iterator(); while (kit.hasNext()) { Object key = kit.next(); put( key, t.get( key)); } } public Object remove( Object key) { if (key_chain.contains( key) == false) return null; key_chain.remove( key); Object value = content_map.remove( key); HashChain c = (HashChain) back_map.get( value); c.remove( key); if (c.size() == 0) back_map.remove( value); return value; } public int size() { return key_chain.size(); } public Collection<Object> values() { if (values==null) { values = new AbstractCollection() { public Iterator iterator() { return new Mapping_Iterator( IterableMap.this.key_chain, IterableMap.this.content_map); } public int size() { return key_chain.size(); } public boolean contains(Object o) { return value_chain.contains(o); } public void clear() { IterableMap.this.clear(); } }; } return values; } public class Mapping_Iterator implements Iterator { private final Iterator it; private HashMap<Object, Object> m; public Mapping_Iterator( HashChain c, HashMap<Object, Object> m) { it = c.iterator(); this.m = m; } public boolean hasNext() { return it.hasNext(); } public Object next() throws NoSuchElementException { return m.get( it.next()); } public void remove() throws UnsupportedOperationException { throw new UnsupportedOperationException("You cannot remove from an Iterator on the values() for an IterableMap."); } } }