From b943acfc64147d49bbb97b4c1903dd4707a96774 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Mon, 6 Oct 2003 23:47:17 +0000 Subject: [PATCH] Rename HashBidiMap to DualHashBidiMap Add AbstractDualBidiMap Test and fix bugs git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/collections/trunk@131254 13f79535-47bb-0310-9956-ffa450edef68 --- ...hBidiMap.java => AbstractDualBidiMap.java} | 202 +++++++++--------- .../apache/commons/collections/BidiMap.java | 27 ++- .../commons/collections/DualHashBidiMap.java | 116 ++++++++++ .../apache/commons/collections/TestAll.java | 6 +- .../commons/collections/TestBidiMap.java | 24 ++- ...hBidiMap.java => TestDualHashBidiMap.java} | 20 +- 6 files changed, 268 insertions(+), 127 deletions(-) rename src/java/org/apache/commons/collections/{HashBidiMap.java => AbstractDualBidiMap.java} (71%) mode change 100755 => 100644 create mode 100644 src/java/org/apache/commons/collections/DualHashBidiMap.java rename src/test/org/apache/commons/collections/{TestHashBidiMap.java => TestDualHashBidiMap.java} (84%) mode change 100755 => 100644 diff --git a/src/java/org/apache/commons/collections/HashBidiMap.java b/src/java/org/apache/commons/collections/AbstractDualBidiMap.java old mode 100755 new mode 100644 similarity index 71% rename from src/java/org/apache/commons/collections/HashBidiMap.java rename to src/java/org/apache/commons/collections/AbstractDualBidiMap.java index b380e5671..a8dfdd6d0 --- a/src/java/org/apache/commons/collections/HashBidiMap.java +++ b/src/java/org/apache/commons/collections/AbstractDualBidiMap.java @@ -1,10 +1,10 @@ /* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/Attic/HashBidiMap.java,v 1.4 2003/10/05 20:40:52 scolebourne Exp $ + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/Attic/AbstractDualBidiMap.java,v 1.1 2003/10/06 23:47:17 scolebourne Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 * - * Copyright (c) 2002-2003 The Apache Software Foundation. All rights + * Copyright (c) 2001-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -58,7 +58,6 @@ package org.apache.commons.collections; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; @@ -68,72 +67,75 @@ import org.apache.commons.collections.decorators.AbstractIteratorDecorator; import org.apache.commons.collections.decorators.AbstractMapEntryDecorator; /** - * Default implementation of BidiMap. + * Abstract BidiMap implemented using two maps. + *

+ * An implementation can be written simply by implementing the + * createMap method. * * @since Commons Collections 3.0 - * @version $Id: HashBidiMap.java,v 1.4 2003/10/05 20:40:52 scolebourne Exp $ + * @version $Id: AbstractDualBidiMap.java,v 1.1 2003/10/06 23:47:17 scolebourne Exp $ * * @author Matthew Hawthorne + * @author Stephen Colebourne */ -public class HashBidiMap implements BidiMap { +public abstract class AbstractDualBidiMap implements BidiMap { /** * Delegate map array. The first map contains standard entries, and the * second contains inverses. */ - protected final Map[] maps = new Map[2]; + protected transient final Map[] maps = new Map[2]; /** * Inverse view of this map. */ - protected BidiMap inverseBidiMap = null; + protected transient BidiMap inverseBidiMap = null; /** * View of the keys. */ - protected Set keySet = null; - /** - * View of the values. - */ - protected Collection values = null; + protected transient Set keySet = null; /** * View of the entries. */ - protected Set entrySet = null; + protected transient Set entrySet = null; /** - * Creates an empty HashBidiMap + * Creates an empty map. + *

+ * 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 */ - public HashBidiMap() { + protected AbstractDualBidiMap(Map normalMap, Map reverseMap) { super(); - maps[0] = new HashMap(); - maps[1] = new HashMap(); + maps[0] = normalMap; + maps[1] = reverseMap; } /** - * Constructs a HashBidiMap and copies the mappings from - * specified Map. - * - * @param map the map whose mappings are to be placed in this map - */ - public HashBidiMap(Map map) { - super(); - maps[0] = new HashMap(); - maps[1] = new HashMap(); - putAll(map); - } - - /** - * Constructs a HashBidiMap that decorates the specified maps. + * 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 HashBidiMap(Map normalMap, Map reverseMap, BidiMap inverseBidiMap) { + 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 //----------------------------------------------------------------------- @@ -221,11 +223,11 @@ public class HashBidiMap implements BidiMap { public BidiMap inverseBidiMap() { if (inverseBidiMap == null) { - inverseBidiMap = new HashBidiMap(maps[1], maps[0], this); + inverseBidiMap = createBidiMap(maps[1], maps[0], this); } return inverseBidiMap; } - + // Map views //----------------------------------------------------------------------- public Set keySet() { @@ -236,10 +238,7 @@ public class HashBidiMap implements BidiMap { } public Collection values() { - if (values == null) { - values = new Values(this); - } - return values; + return inverseBidiMap().keySet(); } public Set entrySet() { @@ -255,14 +254,17 @@ public class HashBidiMap implements BidiMap { */ protected static abstract class View extends AbstractCollectionDecorator { - protected final HashBidiMap map; + protected final AbstractDualBidiMap map; - protected View(Collection coll, HashBidiMap 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()) { @@ -275,6 +277,13 @@ public class HashBidiMap implements BidiMap { } 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()) { @@ -296,25 +305,12 @@ public class HashBidiMap implements BidiMap { */ protected static class KeySet extends View implements Set { - protected KeySet(HashBidiMap map) { + protected KeySet(AbstractDualBidiMap map) { super(map.maps[0].keySet(), map); } public Iterator iterator() { - return new AbstractIteratorDecorator(super.iterator()) { - private Object last; - - 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); - } - }; + return new KeySetIterator(super.iterator(), map); } public boolean remove(Object key) { @@ -328,64 +324,42 @@ public class HashBidiMap implements BidiMap { } /** - * Inner class Values. + * Inner class KeySetIterator. */ - protected static class Values extends View { + protected static class KeySetIterator extends AbstractIteratorDecorator { - protected Values(HashBidiMap map) { - super(map.maps[0].values(), map); - } - - public Iterator iterator() { - return new AbstractIteratorDecorator(super.iterator()) { - private Object last; - - public Object next() { - last = super.next(); - return last; - } - - public void remove() { - super.remove(); - map.maps[1].remove(last); - } - }; + private final AbstractDualBidiMap map; + private Object last; + + protected KeySetIterator(Iterator iterator, AbstractDualBidiMap map) { + super(iterator); + this.map = map; } - public boolean remove(Object value) { - if (contains(value)) { - Object key = map.maps[1].remove(value); - map.maps[0].remove(key); - return true; - } - return false; + 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(HashBidiMap map) { + protected EntrySet(AbstractDualBidiMap map) { super(map.maps[0].entrySet(), map); } 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; - } - - public void remove() { - super.remove(); - map.maps[0].remove(last.getValue()); - } - }; + return new EntrySetIterator(super.iterator(), map); } public boolean remove(Object obj) { @@ -402,11 +376,39 @@ public class HashBidiMap implements BidiMap { } } + /** + * 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 HashBidiMap map; + protected final AbstractDualBidiMap map; - protected MapEntry(Map.Entry entry, HashBidiMap map) { + protected MapEntry(Map.Entry entry, AbstractDualBidiMap map) { super(entry); this.map = map; } diff --git a/src/java/org/apache/commons/collections/BidiMap.java b/src/java/org/apache/commons/collections/BidiMap.java index 057139547..7461e687f 100644 --- a/src/java/org/apache/commons/collections/BidiMap.java +++ b/src/java/org/apache/commons/collections/BidiMap.java @@ -1,5 +1,5 @@ /* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/BidiMap.java,v 1.2 2003/10/05 20:38:55 scolebourne Exp $ + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/BidiMap.java,v 1.3 2003/10/06 23:47:17 scolebourne Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 @@ -62,11 +62,20 @@ import java.util.Map; /** * Defines a map that allows bidirectional lookup between key and values. *

+ * This extended Map represents a mapping where a key may + * lookup a value and a value may lookup a key with equal ease. + * Th interface extends Map 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 BidiMap. + *

* 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 values + * method is usually to return inverseBidiMap().keySet(). + * + * @see org.apache.commons.collections.DualHashBidiMap * @since Commons Collections 3.0 - * @version $Revision: 1.2 $ $Date: 2003/10/05 20:38:55 $ + * @version $Revision: 1.3 $ $Date: 2003/10/06 23:47:17 $ * * @author Stephen Colebourne */ @@ -79,11 +88,11 @@ public interface BidiMap extends Map { * against a different key. That mapping is removed, to ensure that the * value only occurs once in the inverse map. *

-     *  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
      * 
@@ -100,7 +109,7 @@ public interface BidiMap extends Map { * @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 @@ public interface BidiMap extends Map { * @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 @@ public interface BidiMap extends Map { * @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 @@ public interface BidiMap extends Map { * * @return an inverted bidirectional map */ - public BidiMap inverseBidiMap(); + BidiMap inverseBidiMap(); } diff --git a/src/java/org/apache/commons/collections/DualHashBidiMap.java b/src/java/org/apache/commons/collections/DualHashBidiMap.java new file mode 100644 index 000000000..9338ff61c --- /dev/null +++ b/src/java/org/apache/commons/collections/DualHashBidiMap.java @@ -0,0 +1,116 @@ +/* + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/Attic/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 apache@apache.org. + * + * 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 + * . + * + */ +package org.apache.commons.collections; + +import java.util.HashMap; +import java.util.Map; + +/** + * Implementation of BidiMap that uses two HashMap 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 HashBidiMap + */ + public DualHashBidiMap() { + super(new HashMap(), new HashMap()); + } + + /** + * Constructs a HashBidiMap and copies the mappings from + * specified Map. + * + * @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 HashBidiMap 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); + } + + +} diff --git a/src/test/org/apache/commons/collections/TestAll.java b/src/test/org/apache/commons/collections/TestAll.java index 2c13b48cd..5a26fb363 100644 --- a/src/test/org/apache/commons/collections/TestAll.java +++ b/src/test/org/apache/commons/collections/TestAll.java @@ -1,5 +1,5 @@ /* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/TestAll.java,v 1.49 2003/10/05 21:03:44 scolebourne Exp $ + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/TestAll.java,v 1.50 2003/10/06 23:47:17 scolebourne Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 @@ -64,7 +64,7 @@ import junit.framework.TestSuite; /** * Entry point for all Collections package tests. * - * @version $Revision: 1.49 $ $Date: 2003/10/05 21:03:44 $ + * @version $Revision: 1.50 $ $Date: 2003/10/06 23:47:17 $ * * @author Rodney Waldhoff * @author Stephen Colebourne @@ -104,7 +104,7 @@ public class TestAll extends TestCase { 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()); diff --git a/src/test/org/apache/commons/collections/TestBidiMap.java b/src/test/org/apache/commons/collections/TestBidiMap.java index aec0f472d..7e39f999b 100755 --- a/src/test/org/apache/commons/collections/TestBidiMap.java +++ b/src/test/org/apache/commons/collections/TestBidiMap.java @@ -1,5 +1,5 @@ /* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/Attic/TestBidiMap.java,v 1.4 2003/10/05 20:52:29 scolebourne Exp $ + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/Attic/TestBidiMap.java,v 1.5 2003/10/06 23:47:17 scolebourne Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 @@ -63,7 +63,7 @@ import java.util.Map; /** * JUnit tests. * - * @version $Revision: 1.4 $ $Date: 2003/10/05 20:52:29 $ + * @version $Revision: 1.5 $ $Date: 2003/10/06 23:47:17 $ * * @author Matthew Hawthorne */ @@ -132,13 +132,6 @@ public abstract class TestBidiMap extends AbstractTestMap { 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 @@ public abstract class TestBidiMap extends AbstractTestMap { assertEquals("E", inverse.get("F")); } + /** + * Verifies that {@link #map} is still equal to {@link #confirmed}. + *

+ * 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() { diff --git a/src/test/org/apache/commons/collections/TestHashBidiMap.java b/src/test/org/apache/commons/collections/TestDualHashBidiMap.java old mode 100755 new mode 100644 similarity index 84% rename from src/test/org/apache/commons/collections/TestHashBidiMap.java rename to src/test/org/apache/commons/collections/TestDualHashBidiMap.java index bc2e6d190..d80c832cd --- a/src/test/org/apache/commons/collections/TestHashBidiMap.java +++ b/src/test/org/apache/commons/collections/TestDualHashBidiMap.java @@ -1,5 +1,5 @@ /* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/Attic/TestHashBidiMap.java,v 1.2 2003/10/05 20:52:29 scolebourne Exp $ + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/Attic/TestDualHashBidiMap.java,v 1.1 2003/10/06 23:47:17 scolebourne Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 @@ -63,26 +63,34 @@ import junit.textui.TestRunner; /** * JUnit tests. * - * @version $Revision: 1.2 $ $Date: 2003/10/05 20:52:29 $ + * @version $Revision: 1.1 $ $Date: 2003/10/06 23:47:17 $ * * @author Matthew Hawthorne + * @author Stephen Colebourne */ -public class TestHashBidiMap extends TestBidiMap { +public class TestDualHashBidiMap extends TestBidiMap { public static void main(String[] args) { TestRunner.run(suite()); } public static Test suite() { - return BulkTest.makeSuite(TestHashBidiMap.class); + return BulkTest.makeSuite(TestDualHashBidiMap.class); } - public TestHashBidiMap(String testName) { + public TestDualHashBidiMap(String testName) { super(testName); } protected BidiMap makeEmptyBidiMap() { - return new HashBidiMap(); + return new DualHashBidiMap(); } + /** + * Override to prevent infinite recursion of tests. + */ + protected String[] ignoredTests() { + return new String[] {"TestDualHashBidiMap.bulkTestInverseMap.bulkTestInverseMap"}; + } + }