scolebourne 2003/10/06 16:47:17 Modified: collections/src/test/org/apache/commons/collections TestBidiMap.java TestAll.java collections/src/java/org/apache/commons/collections BidiMap.java Added: collections/src/test/org/apache/commons/collections TestDualHashBidiMap.java collections/src/java/org/apache/commons/collections DualHashBidiMap.java AbstractDualBidiMap.java Removed: collections/src/test/org/apache/commons/collections TestHashBidiMap.java collections/src/java/org/apache/commons/collections HashBidiMap.java Log: Rename HashBidiMap to DualHashBidiMap Add AbstractDualBidiMap Test and fix bugs Revision Changes Path 1.5 +15 -9 jakarta-commons/collections/src/test/org/apache/commons/collections/TestBidiMap.java Index: TestBidiMap.java =================================================================== RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/TestBidiMap.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- TestBidiMap.java 5 Oct 2003 20:52:29 -0000 1.4 +++ TestBidiMap.java 6 Oct 2003 23:47:17 -0000 1.5 @@ -132,13 +132,6 @@ return false; } - /** - * Override to prevent infinite recursion of tests. - */ - protected String[] ignoredTests() { - return new String[] {"TestHashBidiMap.bulkTestInverseMap.bulkTestInverseMap"}; - } - // BidiPut //----------------------------------------------------------------------- public void testBidiPut() { @@ -172,6 +165,19 @@ assertEquals("E", inverse.get("F")); } + /** + * Verifies that [EMAIL PROTECTED] #map} is still equal to [EMAIL PROTECTED] #confirmed}. + * <p> + * This implementation checks the inverse map as well. + */ + protected void verify() { + // verify inverse + assertEquals(map.size(), ((BidiMap) map).inverseBidiMap().size()); + + // verify fully + super.verify(); + } + // testGetKey //----------------------------------------------------------------------- public void testBidiGetKey() { 1.50 +3 -3 jakarta-commons/collections/src/test/org/apache/commons/collections/TestAll.java Index: TestAll.java =================================================================== RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/TestAll.java,v retrieving revision 1.49 retrieving revision 1.50 diff -u -r1.49 -r1.50 --- TestAll.java 5 Oct 2003 21:03:44 -0000 1.49 +++ TestAll.java 6 Oct 2003 23:47:17 -0000 1.50 @@ -104,7 +104,7 @@ suite.addTest(TestFastTreeMap.suite()); suite.addTest(TestFastTreeMap1.suite()); suite.addTest(TestHashBag.suite()); - suite.addTest(TestHashBidiMap.suite()); + suite.addTest(TestDualHashBidiMap.suite()); suite.addTest(TestIteratorUtils.suite()); suite.addTest(TestLRUMap.suite()); suite.addTest(TestMultiHashMap.suite()); 1.1 jakarta-commons/collections/src/test/org/apache/commons/collections/TestDualHashBidiMap.java Index: TestDualHashBidiMap.java =================================================================== /* * $Header: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/TestDualHashBidiMap.java,v 1.1 2003/10/06 23:47:17 scolebourne Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.commons.collections; import junit.framework.Test; import junit.textui.TestRunner; /** * JUnit tests. * * @version $Revision: 1.1 $ $Date: 2003/10/06 23:47:17 $ * * @author Matthew Hawthorne * @author Stephen Colebourne */ public class TestDualHashBidiMap extends TestBidiMap { public static void main(String[] args) { TestRunner.run(suite()); } public static Test suite() { return BulkTest.makeSuite(TestDualHashBidiMap.class); } public TestDualHashBidiMap(String testName) { super(testName); } protected BidiMap makeEmptyBidiMap() { return new DualHashBidiMap(); } /** * Override to prevent infinite recursion of tests. */ protected String[] ignoredTests() { return new String[] {"TestDualHashBidiMap.bulkTestInverseMap.bulkTestInverseMap"}; } } 1.3 +18 -9 jakarta-commons/collections/src/java/org/apache/commons/collections/BidiMap.java Index: BidiMap.java =================================================================== RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/BidiMap.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- BidiMap.java 5 Oct 2003 20:38:55 -0000 1.2 +++ BidiMap.java 6 Oct 2003 23:47:17 -0000 1.3 @@ -62,9 +62,18 @@ /** * Defines a map that allows bidirectional lookup between key and values. * <p> + * This extended <code>Map</code> represents a mapping where a key may + * lookup a value and a value may lookup a key with equal ease. + * Th interface extends <code>Map</code> and so may be used anywhere a map + * is required. The interface provides an inverse map view, enabling + * full access to both directions of the <code>BidiMap</code>. + * <p> * Implementations should allow a value to be looked up from a key and * a key to be looked up from a value with equal performance. - * + * It should be noted that the quickest way to implement the <code>values</code> + * method is usually to return <code>inverseBidiMap().keySet()</code>. + * + * @see org.apache.commons.collections.DualHashBidiMap * @since Commons Collections 3.0 * @version $Revision$ $Date$ * @@ -79,11 +88,11 @@ * against a different key. That mapping is removed, to ensure that the * value only occurs once in the inverse map. * <pre> - * BidiMap map1 = new HashBidiMap(); + * BidiMap map1 = new DualHashBidiMap(); * map.put("A","B"); // contains A mapped to B, as per Map * map.put("A","C"); // contains A mapped to C, as per Map * - * BidiMap map2 = new HashBidiMap(); + * BidiMap map2 = new DualHashBidiMap(); * map.put("A","B"); // contains A mapped to B, as per Map * map.put("C","B"); // contains C mapped to B, key A is removed * </pre> @@ -100,7 +109,7 @@ * @throws NullPointerException (optional) if the map limits the values to * non-null and null was specified */ - public Object put(Object key, Object value); + Object put(Object key, Object value); /** * Gets the key that is currently mapped to the specified value. @@ -118,7 +127,7 @@ * @throws NullPointerException (optional) if the map limits the values to * non-null and null was specified */ - public Object getKey(Object value); + Object getKey(Object value); /** * Removes the key-value pair that is currently mapped to the specified @@ -139,7 +148,7 @@ * @throws UnsupportedOperationException if this method is not supported * by the implementation */ - public Object removeKey(Object value); + Object removeKey(Object value); /** * Gets a view of this map where the keys and values are reversed. @@ -153,6 +162,6 @@ * * @return an inverted bidirectional map */ - public BidiMap inverseBidiMap(); + BidiMap inverseBidiMap(); } 1.1 jakarta-commons/collections/src/java/org/apache/commons/collections/DualHashBidiMap.java Index: DualHashBidiMap.java =================================================================== /* * $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/DualHashBidiMap.java,v 1.1 2003/10/06 23:47:17 scolebourne Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.commons.collections; import java.util.HashMap; import java.util.Map; /** * Implementation of <code>BidiMap</code> that uses two <code>HashMap</code> instances. * * @since Commons Collections 3.0 * @version $Id: DualHashBidiMap.java,v 1.1 2003/10/06 23:47:17 scolebourne Exp $ * * @author Matthew Hawthorne * @author Stephen Colebourne */ public class DualHashBidiMap extends AbstractDualBidiMap { /** * Creates an empty <code>HashBidiMap</code> */ public DualHashBidiMap() { super(new HashMap(), new HashMap()); } /** * Constructs a <code>HashBidiMap</code> and copies the mappings from * specified <code>Map</code>. * * @param map the map whose mappings are to be placed in this map */ public DualHashBidiMap(Map map) { super(new HashMap(), new HashMap()); putAll(map); } /** * 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 DualHashBidiMap(Map normalMap, Map reverseMap, BidiMap inverseBidiMap) { super(normalMap, reverseMap, inverseBidiMap); } /** * Creates a new instance of this object. * * @param normalMap the normal direction map * @param reverseMap the reverse direction map * @param inverseBidiMap the inverse BidiMap * @return new bidi map */ protected BidiMap createBidiMap(Map normalMap, Map reverseMap, BidiMap inverseMap) { return new DualHashBidiMap(normalMap, reverseMap, inverseMap); } } 1.1 jakarta-commons/collections/src/java/org/apache/commons/collections/AbstractDualBidiMap.java Index: AbstractDualBidiMap.java =================================================================== /* * $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/AbstractDualBidiMap.java,v 1.1 2003/10/06 23:47:17 scolebourne Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowledgement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgement may appear in the software itself, * if and wherever such third-party acknowledgements normally appear. * * 4. The names "The Jakarta Project", "Commons", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ package org.apache.commons.collections; import java.util.Collection; 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; /** * Abstract <code>BidiMap</code> implemented using two maps. * <p> * An implementation can be written simply by implementing the * <code>createMap</code> method. * * @since Commons Collections 3.0 * @version $Id: AbstractDualBidiMap.java,v 1.1 2003/10/06 23:47:17 scolebourne Exp $ * * @author Matthew Hawthorne * @author Stephen Colebourne */ public abstract class AbstractDualBidiMap implements BidiMap { /** * Delegate map array. The first map contains standard entries, and the * second contains inverses. */ protected transient final Map[] maps = new Map[2]; /** * Inverse view of this map. */ protected transient BidiMap inverseBidiMap = null; /** * View of the keys. */ protected transient Set keySet = null; /** * View of the entries. */ protected transient Set entrySet = null; /** * Creates an empty map. * <p> * The maps passed in are not validated, so subclasses need to ensure * that they are non-null, empty and compatible. * * @param normalMap the normal direction map * @param reverseMap the reverse direction map */ protected AbstractDualBidiMap(Map normalMap, Map reverseMap) { super(); maps[0] = normalMap; maps[1] = reverseMap; } /** * Constructs a map that decorates the specified maps. * * @param normalMap the normal direction map * @param reverseMap the reverse direction map * @param inverseBidiMap the inverse BidiMap */ protected AbstractDualBidiMap(Map normalMap, Map reverseMap, BidiMap inverseBidiMap) { super(); maps[0] = normalMap; maps[1] = reverseMap; this.inverseBidiMap = inverseBidiMap; } /** * Creates a new instance of the subclass. * * @param normalMap the normal direction map * @param reverseMap the reverse direction map * @param inverseMap this map, which is the inverse in the new map * @return the inverse map */ protected abstract BidiMap createBidiMap(Map normalMap, Map reverseMap, BidiMap inverseMap); // Map delegation //----------------------------------------------------------------------- public Object get(Object key) { return maps[0].get(key); } public int size() { return maps[0].size(); } public boolean isEmpty() { return maps[0].isEmpty(); } public boolean containsKey(Object key) { return maps[0].containsKey(key); } public boolean equals(Object obj) { return maps[0].equals(obj); } public int hashCode() { return maps[0].hashCode(); } public String toString() { return maps[0].toString(); } // 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 Object remove(Object key) { Object value = null; if (maps[0].containsKey(key)) { value = maps[0].remove(key); maps[1].remove(value); } return value; } public void clear() { maps[0].clear(); maps[1].clear(); } public boolean containsValue(Object value) { return maps[1].containsKey(value); } // BidiMap //----------------------------------------------------------------------- public Object getKey(Object value) { return maps[1].get(value); } 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 BidiMap inverseBidiMap() { if (inverseBidiMap == null) { inverseBidiMap = createBidiMap(maps[1], maps[0], this); } return inverseBidiMap; } // Map views //----------------------------------------------------------------------- public Set keySet() { if (keySet == null) { keySet = new KeySet(this); } return keySet; } public Collection values() { return inverseBidiMap().keySet(); } public Set entrySet() { if (entrySet == null) { entrySet = new EntrySet(this); } return entrySet; } //----------------------------------------------------------------------- /** * Inner class View. */ protected static abstract class View extends AbstractCollectionDecorator { protected final AbstractDualBidiMap map; protected View(Collection coll, AbstractDualBidiMap map) { super(coll); this.map = map; } public boolean removeAll(Collection coll) { if (map.isEmpty() || coll.isEmpty()) { return false; } boolean modified = false; Iterator it = iterator(); while (it.hasNext()) { if (coll.contains(it.next())) { it.remove(); modified = true; } } return modified; } public boolean retainAll(Collection coll) { if (map.isEmpty()) { return false; } if (coll.isEmpty()) { map.clear(); return true; } boolean modified = false; Iterator it = iterator(); while (it.hasNext()) { if (coll.contains(it.next()) == false) { it.remove(); modified = true; } } return modified; } public void clear() { map.clear(); } } /** * Inner class KeySet. */ protected static class KeySet extends View implements Set { protected KeySet(AbstractDualBidiMap map) { super(map.maps[0].keySet(), map); } public Iterator iterator() { return new KeySetIterator(super.iterator(), map); } 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 KeySetIterator. */ protected static class KeySetIterator extends AbstractIteratorDecorator { private final AbstractDualBidiMap map; private Object last; protected KeySetIterator(Iterator iterator, AbstractDualBidiMap map) { super(iterator); this.map = map; } public Object next() { last = super.next(); return last; } public void remove() { Object value = map.maps[0].get(last); super.remove(); map.maps[1].remove(value); last = null; } } /** * Inner class EntrySet. */ protected static class EntrySet extends View implements Set { protected EntrySet(AbstractDualBidiMap map) { super(map.maps[0].entrySet(), map); } public Iterator iterator() { return new EntrySetIterator(super.iterator(), map); } 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; } } /** * Inner class EntrySetIterator. */ protected static class EntrySetIterator extends AbstractIteratorDecorator { private final AbstractDualBidiMap map; private Map.Entry last; protected EntrySetIterator(Iterator iterator, AbstractDualBidiMap map) { super(iterator); this.map = map; } public Object next() { last = new MapEntry((Map.Entry) super.next(), map); return last; } public void remove() { super.remove(); map.maps[1].remove(last.getValue()); last = null; } } /** * Inner class MapEntry. */ protected static class MapEntry extends AbstractMapEntryDecorator { protected final AbstractDualBidiMap map; protected MapEntry(Map.Entry entry, AbstractDualBidiMap 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); return oldValue; } } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]