You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sc...@apache.org on 2003/10/05 22:40:52 UTC
cvs commit: jakarta-commons/collections/src/java/org/apache/commons/collections HashBidiMap.java
scolebourne 2003/10/05 13:40:52
Modified: collections/src/java/org/apache/commons/collections
HashBidiMap.java
Log:
Refactor implementation to act as more of a decorator
Fixed some bugs too
Revision Changes Path
1.4 +298 -165 jakarta-commons/collections/src/java/org/apache/commons/collections/HashBidiMap.java
Index: HashBidiMap.java
===================================================================
RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/HashBidiMap.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- HashBidiMap.java 29 Sep 2003 23:24:18 -0000 1.3
+++ HashBidiMap.java 5 Oct 2003 20:40:52 -0000 1.4
@@ -57,14 +57,16 @@
*/
package org.apache.commons.collections;
-import java.io.Serializable;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
+import org.apache.commons.collections.decorators.AbstractCollectionDecorator;
+import org.apache.commons.collections.decorators.AbstractIteratorDecorator;
+import org.apache.commons.collections.decorators.AbstractMapEntryDecorator;
+
/**
* Default implementation of <code>BidiMap</code>.
*
@@ -73,220 +75,351 @@
*
* @author Matthew Hawthorne
*/
-public class HashBidiMap extends AbstractMap implements BidiMap, Serializable {
+public class HashBidiMap implements BidiMap {
/**
* Delegate map array. The first map contains standard entries, and the
* second contains inverses.
*/
- final Map[] maps = new Map[] { new HashMap(), new HashMap()};
-
+ protected final Map[] maps = new Map[2];
/**
* Inverse view of this map.
*/
- private final BidiMap inverseBidiMap = new InverseBidiMap();
+ protected BidiMap inverseBidiMap = null;
+ /**
+ * View of the keys.
+ */
+ protected Set keySet = null;
+ /**
+ * View of the values.
+ */
+ protected Collection values = null;
+ /**
+ * View of the entries.
+ */
+ protected Set entrySet = null;
/**
* Creates an empty <code>HashBidiMap</code>
*/
- public HashBidiMap() {}
+ public HashBidiMap() {
+ super();
+ maps[0] = new HashMap();
+ maps[1] = new HashMap();
+ }
/**
- * Constructs a new <tt>HashMap</tt> with the same mappings as the
- * specified <tt>Map</tt>.
+ * Constructs a <code>HashBidiMap</code> and copies the mappings from
+ * specified <code>Map</code>.
*
- * @param m the map whose mappings are to be placed in this map.
+ * @param map the map whose mappings are to be placed in this map
*/
- public HashBidiMap(Map m) {
- putAll(m);
+ public HashBidiMap(Map map) {
+ super();
+ maps[0] = new HashMap();
+ maps[1] = new HashMap();
+ putAll(map);
}
- public Object getKey(Object value) {
- return maps[1].get(value);
+ /**
+ * Constructs a <code>HashBidiMap</code> that decorates the specified maps.
+ *
+ * @param normalMap the normal direction map
+ * @param reverseMap the reverse direction map
+ * @param inverseBidiMap the inverse BidiMap
+ */
+ protected HashBidiMap(Map normalMap, Map reverseMap, BidiMap inverseBidiMap) {
+ super();
+ maps[0] = normalMap;
+ maps[1] = reverseMap;
+ this.inverseBidiMap = inverseBidiMap;
}
- public BidiMap inverseBidiMap() {
- return inverseBidiMap;
+ // Map delegation
+ //-----------------------------------------------------------------------
+ public Object get(Object key) {
+ return maps[0].get(key);
}
- public Object removeKey(Object value) {
- final Object key = maps[1].get(value);
- return remove(key);
+ public int size() {
+ return maps[0].size();
}
- public Object put(Object key, Object value) {
- // Removes pair from standard map if a previous inverse entry exists
- final Object oldValue = maps[1].put(value, key);
- if (oldValue != null) {
- maps[0].remove(oldValue);
- }
-
- final Object obj = maps[0].put(key, value);
- return obj;
+ public boolean isEmpty() {
+ return maps[0].isEmpty();
}
- public Set entrySet() {
- // The entrySet is the root of most Map methods, care must be taken not
- // to reference instance methods like size()
-
- // Creates anonymous AbstractSet
- return new AbstractSet() {
-
- public Iterator iterator() {
- // Creates anonymous Iterator
- return new Iterator() {
+ public boolean containsKey(Object key) {
+ return maps[0].containsKey(key);
+ }
- // Delegate iterator.
- final Iterator it = maps[0].entrySet().iterator();
+ public boolean equals(Object obj) {
+ return maps[0].equals(obj);
+ }
- // Current iterator entry
- Map.Entry currentEntry;
+ public int hashCode() {
+ return maps[0].hashCode();
+ }
- public void remove() {
- // Removes from standard and inverse Maps.
+ public String toString() {
+ return maps[0].toString();
+ }
- // Object must be removed using the iterator or a
- // ConcurrentModificationException is thrown
- it.remove();
- HashBidiMap.this.maps[1].remove(
- currentEntry.getValue());
- }
+ // BidiMap changes
+ //-----------------------------------------------------------------------
+ public Object put(Object key, Object value) {
+ if (maps[0].containsKey(key)) {
+ maps[1].remove(maps[0].get(key));
+ }
+ if (maps[1].containsKey(value)) {
+ maps[0].remove(maps[1].get(value));
+ }
+ final Object obj = maps[0].put(key, value);
+ maps[1].put(value, key);
+ return obj;
+ }
+
+ public void putAll(Map map) {
+ for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
+ Map.Entry entry = (Map.Entry) it.next();
+ put(entry.getKey(), entry.getValue());
+ }
+ }
- public boolean hasNext() {
- return it.hasNext();
- }
+ public Object remove(Object key) {
+ Object value = null;
+ if (maps[0].containsKey(key)) {
+ value = maps[0].remove(key);
+ maps[1].remove(value);
+ }
+ return value;
+ }
- public Object next() {
- currentEntry = (Map.Entry)it.next();
+ public void clear() {
+ maps[0].clear();
+ maps[1].clear();
+ }
- // returns anonymous Map.Entry
- return new Map.Entry() {
+ public boolean containsValue(Object value) {
+ return maps[1].containsKey(value);
+ }
- public Object getKey() {
- return currentEntry.getKey();
- }
+ // BidiMap
+ //-----------------------------------------------------------------------
+ public Object getKey(Object value) {
+ return maps[1].get(value);
+ }
- public Object getValue() {
- return currentEntry.getValue();
- }
+ public Object removeKey(Object value) {
+ Object key = null;
+ if (maps[1].containsKey(value)) {
+ key = maps[1].remove(value);
+ maps[0].remove(key);
+ }
+ return key;
+ }
- public Object setValue(Object value) {
- final Object oldValue =
- currentEntry.setValue(value);
+ public BidiMap inverseBidiMap() {
+ if (inverseBidiMap == null) {
+ inverseBidiMap = new HashBidiMap(maps[1], maps[0], this);
+ }
+ return inverseBidiMap;
+ }
- // Gets old key and pairs with new value
- final Object inverseKey =
- HashBidiMap.this.maps[1].remove(oldValue);
- HashBidiMap.this.maps[1].put(value, inverseKey);
+ // Map views
+ //-----------------------------------------------------------------------
+ public Set keySet() {
+ if (keySet == null) {
+ keySet = new KeySet(this);
+ }
+ return keySet;
+ }
- return oldValue;
- }
+ public Collection values() {
+ if (values == null) {
+ values = new Values(this);
+ }
+ return values;
+ }
- }; // anonymous Map.Entry
- };
- }; // anonymous Iterator
- }
+ public Set entrySet() {
+ if (entrySet == null) {
+ entrySet = new EntrySet(this);
+ }
+ return entrySet;
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Inner class View.
+ */
+ protected static abstract class View extends AbstractCollectionDecorator {
+
+ protected final HashBidiMap map;
+
+ protected View(Collection coll, HashBidiMap map) {
+ super(coll);
+ this.map = map;
+ }
- public boolean remove(Object obj) {
- // XXX Throws ClassCastException if obj is not a Map.Entry.
- // Is this acceptable?
- final Object removed =
- HashBidiMap.this.remove(((Map.Entry)obj).getKey());
- return removed != null;
+ public boolean removeAll(Collection coll) {
+ boolean modified = false;
+ Iterator it = iterator();
+ while (it.hasNext()) {
+ if (coll.contains(it.next())) {
+ it.remove();
+ modified = true;
+ }
}
+ return modified;
+ }
- public int size() {
- return HashBidiMap.this.maps[0].size();
+ public boolean retainAll(Collection coll) {
+ boolean modified = false;
+ Iterator it = iterator();
+ while (it.hasNext()) {
+ if (coll.contains(it.next()) == false) {
+ it.remove();
+ modified = true;
+ }
}
+ return modified;
+ }
- }; // anonymous AbstractSet
-
- } // entrySet()
-
+ public void clear() {
+ map.clear();
+ }
+ }
+
/**
- * Inverse view of this BidiMap.
+ * Inner class KeySet.
*/
- private final class InverseBidiMap extends AbstractMap implements BidiMap {
-
- public Object getKey(Object value) {
- return HashBidiMap.this.get(value);
+ protected static class KeySet extends View implements Set {
+
+ protected KeySet(HashBidiMap map) {
+ super(map.maps[0].keySet(), map);
}
- public BidiMap inverseBidiMap() {
- return HashBidiMap.this;
- }
+ public Iterator iterator() {
+ return new AbstractIteratorDecorator(super.iterator()) {
+ private Object last;
+
+ public Object next() {
+ last = super.next();
+ return last;
+ }
- public Object removeKey(Object value) {
- return HashBidiMap.this.remove(value);
+ public void remove() {
+ Object value = map.maps[0].get(last);
+ super.remove();
+ map.maps[1].remove(value);
+ }
+ };
+ }
+
+ public boolean remove(Object key) {
+ if (contains(key)) {
+ Object value = map.maps[0].remove(key);
+ map.maps[1].remove(value);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Inner class Values.
+ */
+ protected static class Values extends View {
+
+ protected Values(HashBidiMap map) {
+ super(map.maps[0].values(), map);
}
- public Set entrySet() {
- // Gets entry set from outer class
- final Set entrySet = HashBidiMap.this.entrySet();
-
- // Returns anonymous Set
- return new AbstractSet() {
-
- public int size() {
- return HashBidiMap.this.size();
+ public Iterator iterator() {
+ return new AbstractIteratorDecorator(super.iterator()) {
+ private Object last;
+
+ public Object next() {
+ last = super.next();
+ return last;
}
- public Iterator iterator() {
- final Iterator delegate = entrySet.iterator();
-
- // Returns anonymous Iterator
- return new Iterator() {
-
- public boolean hasNext() {
- return delegate.hasNext();
- }
-
- public Object next() {
- final Map.Entry entry = (Map.Entry)delegate.next();
-
- // Returns anonymous Map.Entry
- return new Map.Entry() {
-
- public Object getKey() {
- return entry.getValue();
- }
-
- public Object getValue() {
- return entry.getKey();
- }
-
- public Object setValue(Object value) {
- // This is confusing. Basically, we are
- // setting a new key for existing value
-
- // Gets value for current key
- final Object oldValue =
- HashBidiMap.this.maps[0].remove(getValue());
-
- // Puts new key and value into map
- HashBidiMap.this.maps[0].put(
- value,
- oldValue);
-
- // Returns old value
- return oldValue;
- }
-
- }; // anonymous Map.Entry
-
- }
-
- public void remove() {
- delegate.remove();
- }
-
- }; // anonymous Iterator
+ public void remove() {
+ super.remove();
+ map.maps[1].remove(last);
}
+ };
+ }
+
+ public boolean remove(Object value) {
+ if (contains(value)) {
+ Object key = map.maps[1].remove(value);
+ map.maps[0].remove(key);
+ return true;
+ }
+ return false;
+ }
+
+ }
+
+ /**
+ * Inner class EntrySet.
+ */
+ protected static class EntrySet extends View implements Set {
+
+ protected EntrySet(HashBidiMap map) {
+ super(map.maps[0].entrySet(), map);
+ }
- }; // anonymous AbstractSet
-
- } // entrySet()
+ public Iterator iterator() {
+ return new AbstractIteratorDecorator(super.iterator()) {
+ private Map.Entry last;
+
+ public Object next() {
+ last = new MapEntry((Map.Entry) super.next(), map);
+ return last;
+ }
- } // InverseBidiMap
+ public void remove() {
+ super.remove();
+ map.maps[0].remove(last.getValue());
+ }
+ };
+ }
+
+ public boolean remove(Object obj) {
+ if (obj instanceof Map.Entry == false) {
+ return false;
+ }
+ Map.Entry entry = (Map.Entry) obj;
+ if (map.containsKey(entry.getKey())) {
+ Object value = map.maps[0].remove(entry.getKey());
+ map.maps[1].remove(value);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ protected static class MapEntry extends AbstractMapEntryDecorator {
+
+ protected final HashBidiMap map;
+
+ protected MapEntry(Map.Entry entry, HashBidiMap map) {
+ super(entry);
+ this.map = map;
+ }
+
+ public Object setValue(Object value) {
+ final Object oldValue = super.setValue(value);
+
+ // Gets old key and pairs with new value
+ final Object inverseKey = map.maps[1].remove(oldValue);
+ map.maps[1].put(value, inverseKey);
-} // HashBidiMap
+ return oldValue;
+ }
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org