scolebourne 2003/10/28 16:06:25 Modified: collections/src/java/org/apache/commons/collections AbstractDualBidiMap.java BidiMap.java collections/src/test/org/apache/commons/collections AbstractTestBidiMap.java collections build.xml Added: collections/src/java/org/apache/commons/collections MapIterator.java Log: Add MapIterator to BidiMap Revision Changes Path 1.4 +66 -2 jakarta-commons/collections/src/java/org/apache/commons/collections/AbstractDualBidiMap.java Index: AbstractDualBidiMap.java =================================================================== RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/AbstractDualBidiMap.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- AbstractDualBidiMap.java 10 Oct 2003 21:09:49 -0000 1.3 +++ AbstractDualBidiMap.java 29 Oct 2003 00:06:25 -0000 1.4 @@ -214,6 +214,10 @@ // BidiMap //----------------------------------------------------------------------- + public MapIterator mapIterator() { + return new BidiMapIterator(this); + } + public Object getKey(Object value) { return maps[1].get(value); } @@ -435,6 +439,66 @@ 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; + } + } + + /** + * Inner class MapIterator. + */ + protected static class BidiMapIterator extends AbstractIteratorDecorator implements MapIterator { + + protected final AbstractDualBidiMap map; + private Map.Entry last = null; + private boolean canRemove = false; + + protected BidiMapIterator(AbstractDualBidiMap map) { + super(map.maps[0].entrySet().iterator()); + this.map = map; + } + + public Object next() { + last = new MapEntry((Map.Entry) super.next(), map); + canRemove = true; + return last.getKey(); + } + + public void remove() { + if (canRemove == false) { + throw new IllegalStateException("Iterator remove() can only be called once after next()"); + } + // store value as remove may change the entry in the decorator (eg.TreeMap) + Object value = last.getValue(); + super.remove(); + map.maps[1].remove(value); + last = null; + canRemove = false; + } + + public Object getKey() { + if (last == null) { + throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()"); + } + return last.getKey(); + } + + public Object getValue() { + if (last == null) { + throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()"); + } + return last.getValue(); + } + + public Object setValue(Object value) { + if (last == null) { + throw new IllegalStateException("Iterator setValue() can only be called after next() and before remove()"); + } + Object oldValue = last.setValue(value); // Gets old key and pairs with new value final Object inverseKey = map.maps[1].remove(oldValue); 1.4 +20 -4 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.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- BidiMap.java 6 Oct 2003 23:47:17 -0000 1.3 +++ BidiMap.java 29 Oct 2003 00:06:25 -0000 1.4 @@ -70,8 +70,6 @@ * <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 @@ -80,6 +78,24 @@ * @author Stephen Colebourne */ public interface BidiMap extends Map { + + /** + * Obtains a <code>MapIterator</code> over the map. + * <p> + * A map iterator is an efficient way of iterating over maps. + * It does not require that the map is stored using Map Entry objects + * which can increase performance. + * <pre> + * BidiMap map = new DualHashBidiMap(); + * MapIterator it = map.mapIterator(); + * Object key = it.next(); + * Object value = it.getValue(); + * it.setValue("newValue"); + * </pre> + * + * @return a map iterator + */ + MapIterator mapIterator(); /** * Puts the key-value pair into the map, replacing any previous pair. 1.1 jakarta-commons/collections/src/java/org/apache/commons/collections/MapIterator.java Index: MapIterator.java =================================================================== /* * $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/MapIterator.java,v 1.1 2003/10/29 00:06:25 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.Iterator; /** * Defines an iterator that operates over a <code>Map</code>. * <p> * This iterator is a special version designed for maps. It is much more * efficient to use this rather than an entry set iterator where the option * is available. A map that provides this interface may not hold the data * internally using Map Entry objects, thus this interface can avoid lots * of object creation. * <p> * In use, this iterator iterates through the keys in the map. After each * call to <code>next()</code>, the <code>getValue()</code> method provides * direct access to the value. The value can also be set using * <code>setValue()</code>. * * @since Commons Collections 3.0 * @version $Revision: 1.1 $ $Date: 2003/10/29 00:06:25 $ * * @author Stephen Colebourne */ public interface MapIterator extends Iterator { /** * Checks to see if there are more entries still to be iterated. * * @return <code>true</code> if the iterator has more elements */ boolean hasNext(); /** * Gets the next <em>key</em> from the <code>Map</code>. * * @return the next key in the iteration * @throws NoSuchElementException if the iteration is finished */ Object next(); //----------------------------------------------------------------------- /** * Gets the current key, which is the key returned by the last call * to <code>next()</code>. * * @return the current key * @throws IllegalStateException if <code>next()</code> has not yet been called */ Object getKey(); /** * Gets the current value, which is the value associated with the last key * returned by <code>next()</code>. * * @return the current value * @throws IllegalStateException if <code>next()</code> has not yet been called */ Object getValue(); //----------------------------------------------------------------------- /** * Removes the last returned key from the underlying <code>Map</code> (optional operation). * <p> * This method can be called once per call to <code>next()</code>. * * @throws UnsupportedOperationException if remove is not supported by the map * @throws IllegalStateException if <code>next()</code> has not yet been called * @throws IllegalStateException if <code>remove()</code> has already been called * since the last call to <code>next()</code> */ void remove(); /** * Sets the value associated with the current key. * * @param value the new value * @return the previous value * @throws IllegalStateException if <code>next()</code> has not yet been called * @throws IllegalStateException if <code>remove()</code> has been called since the * last call to <code>next()</code> */ Object setValue(Object value); } 1.2 +109 -3 jakarta-commons/collections/src/test/org/apache/commons/collections/AbstractTestBidiMap.java Index: AbstractTestBidiMap.java =================================================================== RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/AbstractTestBidiMap.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- AbstractTestBidiMap.java 10 Oct 2003 21:11:39 -0000 1.1 +++ AbstractTestBidiMap.java 29 Oct 2003 00:06:25 -0000 1.2 @@ -59,9 +59,10 @@ import java.util.HashMap; import java.util.Map; +import java.util.NoSuchElementException; /** - * JUnit tests. + * Abstract test class for [EMAIL PROTECTED] BidiMap} methods and contracts. * * @version $Revision$ $Date$ * @@ -375,4 +376,109 @@ } + //----------------------------------------------------------------------- + public void testBidiMapIteratorEmpty() { + resetEmpty(); + BidiMap bidi = (BidiMap) map; + MapIterator it = bidi.mapIterator(); + assertEquals(false, it.hasNext()); + try { + it.next(); + } catch (NoSuchElementException ex) {} + try { + it.getKey(); + } catch (IllegalStateException ex) { + } + try { + it.getValue(); + } catch (IllegalStateException ex) { + } + try { + it.remove(); + } catch (UnsupportedOperationException ex) { + } catch (IllegalStateException ex) { + } + try { + it.setValue(null); + } catch (UnsupportedOperationException ex) { + } catch (IllegalStateException ex) { + } + verify(); + } + + //----------------------------------------------------------------------- + public void testBidiMapIteratorFull() { + resetFull(); + BidiMap bidi = (BidiMap) map; + MapIterator it = bidi.mapIterator(); + + assertEquals(true, it.hasNext()); + while (it.hasNext()) { + Object key = it.next(); + assertSame(key, it.getKey()); + + Object value = it.getValue(); + assertSame(bidi.get(key), value); + } + verify(); + } + + //----------------------------------------------------------------------- + public void testBidiMapIteratorRemove() { + resetFull(); + BidiMap bidi = (BidiMap) map; + MapIterator it = bidi.mapIterator(); + assertEquals(true, it.hasNext()); + Object key = it.next(); + + if (isRemoveSupported() == false) { + try { + it.remove(); + } catch (UnsupportedOperationException ex) { + } + return; + } + + it.remove(); + confirmed.remove(key); + assertEquals(false, bidi.containsKey(key)); + verify(); + + try { + it.remove(); // second remove fails + } catch (IllegalStateException ex) { + } + verify(); + } + + //----------------------------------------------------------------------- + public void testBidiMapIteratorSet() { + resetFull(); + BidiMap bidi = (BidiMap) map; + MapIterator it = bidi.mapIterator(); + assertEquals(true, it.hasNext()); + Object key = it.next(); + + if (isPutChangeSupported() == false) { + try { + it.setValue(getOtherValues()[0]); + } catch (UnsupportedOperationException ex) { + } + return; + } + + it.setValue(getOtherValues()[0]); + confirmed.put(key, getOtherValues()[0]); + assertEquals(getOtherValues()[0], bidi.get(key)); + verify(); + + it.remove(); + confirmed.remove(key); + try { + it.setValue(getOtherValues()[0]); + } catch (IllegalStateException ex) { + } + verify(); + } + } 1.50 +2 -1 jakarta-commons/collections/build.xml Index: build.xml =================================================================== RCS file: /home/cvs/jakarta-commons/collections/build.xml,v retrieving revision 1.49 retrieving revision 1.50 diff -u -r1.49 -r1.50 --- build.xml 27 Oct 2003 23:08:21 -0000 1.49 +++ build.xml 29 Oct 2003 00:06:25 -0000 1.50 @@ -37,6 +37,7 @@ <patternset id="patternset-testframework-source"> <include name="**/Bag.java"/> <include name="**/BidiMap.java"/> + <include name="**/MapIterator.java"/> <include name="**/SortedBag.java"/> <include name="**/AbstractTest*.java"/> <include name="**/BulkTest*.java"/>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]