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/11/19 00:23:05 UTC
cvs commit: jakarta-commons/collections/src/java/org/apache/commons/collections/map Flat3Map.java package.html
scolebourne 2003/11/18 15:23:05
Modified: collections/src/test/org/apache/commons/collections
MapPerformance.java
collections/src/test/org/apache/commons/collections/map
TestAll.java
collections/src/java/org/apache/commons/collections/map
package.html
Added: collections/src/test/org/apache/commons/collections/map
TestFlat3Map.java
collections/src/java/org/apache/commons/collections/map
Flat3Map.java
Removed: collections/src/test/org/apache/commons/collections
TestFlat3Map.java
collections/src/java/org/apache/commons/collections
Flat3Map.java
Log:
Move Flat3Map to map subpackage
Revision Changes Path
1.2 +3 -1 jakarta-commons/collections/src/test/org/apache/commons/collections/MapPerformance.java
Index: MapPerformance.java
===================================================================
RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/MapPerformance.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- MapPerformance.java 2 Nov 2003 23:43:00 -0000 1.1
+++ MapPerformance.java 18 Nov 2003 23:23:05 -0000 1.2
@@ -65,6 +65,8 @@
import java.util.Set;
import java.util.TreeMap;
+import org.apache.commons.collections.map.Flat3Map;
+
/**
* <code>TestMapPerformance</code> is designed to perform basic Map performance tests.
*
1.2 +3 -2 jakarta-commons/collections/src/test/org/apache/commons/collections/map/TestAll.java
Index: TestAll.java
===================================================================
RCS file: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/map/TestAll.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- TestAll.java 16 Nov 2003 00:05:46 -0000 1.1
+++ TestAll.java 18 Nov 2003 23:23:05 -0000 1.2
@@ -85,6 +85,7 @@
suite.addTest(TestFixedSizeMap.suite());
suite.addTest(TestFixedSizeSortedMap.suite());
+ suite.addTest(TestFlat3Map.suite());
suite.addTest(TestLazyMap.suite());
suite.addTest(TestLazySortedMap.suite());
suite.addTest(TestListOrderedMap.suite());
1.1 jakarta-commons/collections/src/test/org/apache/commons/collections/map/TestFlat3Map.java
Index: TestFlat3Map.java
===================================================================
/*
* $Header: /home/cvs/jakarta-commons/collections/src/test/org/apache/commons/collections/map/TestFlat3Map.java,v 1.1 2003/11/18 23:23:05 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
* <http://www.apache.org/>.
*
*/
package org.apache.commons.collections.map;
import java.util.Map;
import junit.framework.Test;
import junit.textui.TestRunner;
import org.apache.commons.collections.BulkTest;
import org.apache.commons.collections.iterators.AbstractTestMapIterator;
import org.apache.commons.collections.iterators.MapIterator;
/**
* JUnit tests.
*
* @version $Revision: 1.1 $ $Date: 2003/11/18 23:23:05 $
*
* @author Stephen Colebourne
*/
public class TestFlat3Map extends AbstractTestMap {
public TestFlat3Map(String testName) {
super(testName);
}
public static void main(String[] args) {
TestRunner.run(suite());
}
public static Test suite() {
return BulkTest.makeSuite(TestFlat3Map.class);
}
public Map makeEmptyMap() {
return new Flat3Map();
}
//-----------------------------------------------------------------------
public BulkTest bulkTestMapIterator() {
return new TestFlatMapIterator();
}
public class TestFlatMapIterator extends AbstractTestMapIterator {
public TestFlatMapIterator() {
super("TestFlatMapIterator");
}
public Object[] addSetValues() {
return TestFlat3Map.this.getNewSampleValues();
}
public boolean supportsRemove() {
return TestFlat3Map.this.isRemoveSupported();
}
public boolean supportsSetValue() {
return TestFlat3Map.this.isSetValueSupported();
}
public MapIterator makeEmptyMapIterator() {
resetEmpty();
return ((Flat3Map) TestFlat3Map.this.map).mapIterator();
}
public MapIterator makeFullMapIterator() {
resetFull();
return ((Flat3Map) TestFlat3Map.this.map).mapIterator();
}
public Map getMap() {
// assumes makeFullMapIterator() called first
return TestFlat3Map.this.map;
}
public Map getConfirmedMap() {
// assumes makeFullMapIterator() called first
return TestFlat3Map.this.confirmed;
}
public void verify() {
super.verify();
TestFlat3Map.this.verify();
}
}
}
1.2 +1 -0 jakarta-commons/collections/src/java/org/apache/commons/collections/map/package.html
Index: package.html
===================================================================
RCS file: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/map/package.html,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- package.html 16 Nov 2003 00:05:45 -0000 1.1
+++ package.html 18 Nov 2003 23:23:05 -0000 1.2
@@ -16,6 +16,7 @@
<li>FixedSize - ensures that the size of the map cannot change
<li>Lazy - creates objects in the map on demand
<li>ListOrdered - ensures that insertion order is retained
+<li>Flat3 - designed for good performance at size 3 or less
</ul>
</pre>
</BODY>
1.1 jakarta-commons/collections/src/java/org/apache/commons/collections/map/Flat3Map.java
Index: Flat3Map.java
===================================================================
/*
* $Header: /home/cvs/jakarta-commons/collections/src/java/org/apache/commons/collections/map/Flat3Map.java,v 1.1 2003/11/18 23:23:05 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
* <http://www.apache.org/>.
*
*/
package org.apache.commons.collections.map;
import java.util.AbstractCollection;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.apache.commons.collections.IteratorUtils;
import org.apache.commons.collections.iterators.EntrySetMapIterator;
import org.apache.commons.collections.iterators.MapIterator;
import org.apache.commons.collections.iterators.ResettableIterator;
/**
* A <code>Map</code> implementation that stores data in simple fields until
* the size is greater than 3.
* <p>
* This map is designed for performance and can outstrip HashMap.
* It also has good garbage collection characteristics.
* <ul>
* <li>Optimised for operation at size 3 or less.
* <li>Still works well once size 3 exceeded.
* <li>Gets at size 3 or less are about 0-10% faster than HashMap,
* <li>Puts at size 3 or less are over 4 times faster than HashMap.
* <li>Performance 5% slower than HashMap once size 3 exceeded once.
* </ul>
* The design uses two distinct modes of operation - flat and delegate.
* While the map is size 3 or less, operations map straight onto fields using
* switch statements. Once size 4 is reached, the map switches to delegate mode
* and only switches back when cleared. In delegate mode, all operations are
* forwarded straight to a HashMap resulting in the 5% performance loss.
* <p>
* The performance gains on puts are due to not needing to create a Map Entry
* object. This is a large saving not only in performance but in garbage collection.
* <p>
* Whilst in flat mode this map is also easy for the garbage collector to dispatch.
* This is because it contains no complex objects or arrays which slow the progress.
* <p>
* Do not use <code>Flat3Map</code> if the size is likely to grow beyond 3.
*
* @since Commons Collections 3.0
* @version $Revision: 1.1 $ $Date: 2003/11/18 23:23:05 $
*
* @author Stephen Colebourne
*/
public class Flat3Map implements Map {
/** The size of the map, used while in flat mode */
private int iSize;
/** Hash, used while in flat mode */
private int iHash1;
/** Hash, used while in flat mode */
private int iHash2;
/** Hash, used while in flat mode */
private int iHash3;
/** Key, used while in flat mode */
private Object iKey1;
/** Key, used while in flat mode */
private Object iKey2;
/** Key, used while in flat mode */
private Object iKey3;
/** Value, used while in flat mode */
private Object iValue1;
/** Value, used while in flat mode */
private Object iValue2;
/** Value, used while in flat mode */
private Object iValue3;
/** Map, used while in delegate mode */
private HashMap iMap;
/**
* Constructor.
*/
public Flat3Map() {
super();
}
/**
* Constructor copying elements from another map.
*
* @param map the map to copy
*/
public Flat3Map(Map map) {
super();
putAll(map);
}
//-----------------------------------------------------------------------
/**
* Gets the value mapped to the key specified.
*
* @param key the key
* @return the mapped value, null if no match
*/
public Object get(Object key) {
if (iMap != null) {
return iMap.get(key);
}
if (key == null) {
switch (iSize) {
// drop through
case 3:
if (iKey3 == null) return iValue3;
case 2:
if (iKey2 == null) return iValue2;
case 1:
if (iKey1 == null) return iValue1;
}
} else {
if (iSize > 0) {
int hashCode = key.hashCode();
switch (iSize) {
// drop through
case 3:
if (iHash3 == hashCode && key.equals(iKey3)) return iValue3;
case 2:
if (iHash2 == hashCode && key.equals(iKey2)) return iValue2;
case 1:
if (iHash1 == hashCode && key.equals(iKey1)) return iValue1;
}
}
}
return null;
}
/**
* Gets the size of the map.
*
* @return the size
*/
public int size() {
if (iMap != null) {
return iMap.size();
}
return iSize;
}
/**
* Checks whether the map is currently empty.
*
* @return true if the map is currently size zero
*/
public boolean isEmpty() {
return (size() == 0);
}
//-----------------------------------------------------------------------
/**
* Checks whether the map contains the specified key.
*
* @param key the key to search for
* @return true if the map contains the key
*/
public boolean containsKey(Object key) {
if (iMap != null) {
return iMap.containsKey(key);
}
if (key == null) {
switch (iSize) { // drop through
case 3:
if (iKey3 == null) return true;
case 2:
if (iKey2 == null) return true;
case 1:
if (iKey1 == null) return true;
}
} else {
if (iSize > 0) {
int hashCode = key.hashCode();
switch (iSize) { // drop through
case 3:
if (iHash3 == hashCode && key.equals(iKey3)) return true;
case 2:
if (iHash2 == hashCode && key.equals(iKey2)) return true;
case 1:
if (iHash1 == hashCode && key.equals(iKey1)) return true;
}
}
}
return false;
}
/**
* Checks whether the map contains the specified value.
*
* @param value the value to search for
* @return true if the map contains the key
*/
public boolean containsValue(Object value) {
if (iMap != null) {
return iMap.containsValue(value);
}
if (value == null) { // drop through
switch (iSize) {
case 3:
if (iValue3 == null) return true;
case 2:
if (iValue2 == null) return true;
case 1:
if (iValue1 == null) return true;
}
} else {
switch (iSize) { // drop through
case 3:
if (value.equals(iValue3)) return true;
case 2:
if (value.equals(iValue2)) return true;
case 1:
if (value.equals(iValue1)) return true;
}
}
return false;
}
//-----------------------------------------------------------------------
/**
* Puts a key-value mapping into this map.
*
* @param key the key to add
* @param value the value to add
* @return the value previously mapped to this key, null if none
*/
public Object put(Object key, Object value) {
if (iMap != null) {
return iMap.put(key, value);
}
// change existing mapping
if (key == null) {
switch (iSize) { // drop through
case 3:
if (iKey3 == null) {
Object old = iValue3;
iValue3 = value;
return old;
}
case 2:
if (iKey2 == null) {
Object old = iValue2;
iValue2 = value;
return old;
}
case 1:
if (iKey1 == null) {
Object old = iValue1;
iValue1 = value;
return old;
}
}
} else {
if (iSize > 0) {
int hashCode = key.hashCode();
switch (iSize) { // drop through
case 3:
if (iHash3 == hashCode && key.equals(iKey3)) {
Object old = iValue3;
iValue3 = value;
return old;
}
case 2:
if (iHash2 == hashCode && key.equals(iKey2)) {
Object old = iValue2;
iValue2 = value;
return old;
}
case 1:
if (iHash1 == hashCode && key.equals(iKey1)) {
Object old = iValue1;
iValue1 = value;
return old;
}
}
}
}
// add new mapping
switch (iSize) {
default:
convertToMap();
iMap.put(key, value);
return null;
case 2:
iHash3 = (key == null ? 0 : key.hashCode());
iKey3 = key;
iValue3 = value;
break;
case 1:
iHash2 = (key == null ? 0 : key.hashCode());
iKey2 = key;
iValue2 = value;
break;
case 0:
iHash1 = (key == null ? 0 : key.hashCode());
iKey1 = key;
iValue1 = value;
break;
}
iSize++;
return null;
}
/**
* Puts all the values from the specified map into this map.
*
* @param map
*/
public void putAll(Map map) {
int size = map.size();
if (size == 0) {
return;
}
if (iMap != null) {
iMap.putAll(map);
}
if (size < 4) {
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
put(entry.getKey(), entry.getValue());
}
} else {
convertToMap();
iMap.putAll(map);
}
}
/**
* Converts the flat map data to a HashMap.
*/
private void convertToMap() {
iMap = new HashMap();
switch (iSize) { // drop through
case 3:
iMap.put(iKey3, iValue3);
case 2:
iMap.put(iKey2, iValue2);
case 1:
iMap.put(iKey1, iValue1);
}
iSize = 0;
iHash1 = iHash2 = iHash3 = 0;
iKey1 = iKey2 = iKey3 = null;
iValue1 = iValue2 = iValue3 = null;
}
/**
* Removes the specified mapping from this map.
*
* @param key the mapping to remove
* @return the value mapped to the removed key, null if key not in map
*/
public Object remove(Object key) {
if (iMap != null) {
return iMap.remove(key);
}
if (iSize == 0) {
return null;
}
if (key == null) {
switch (iSize) { // drop through
case 3:
if (iKey3 == null) {
Object old = iValue3;
iHash3 = 0;
iKey3 = null;
iValue3 = null;
iSize = 2;
return old;
}
if (iKey2 == null) {
Object old = iValue3;
iHash2 = iHash3;
iKey2 = iKey3;
iValue2 = iValue3;
iHash3 = 0;
iKey3 = null;
iValue3 = null;
iSize = 2;
return old;
}
if (iKey1 == null) {
Object old = iValue3;
iHash1 = iHash3;
iKey1 = iKey3;
iValue1 = iValue3;
iHash3 = 0;
iKey3 = null;
iValue3 = null;
iSize = 2;
return old;
}
return null;
case 2:
if (iKey2 == null) {
Object old = iValue2;
iHash2 = 0;
iKey2 = null;
iValue2 = null;
iSize = 1;
return old;
}
if (iKey1 == null) {
Object old = iValue2;
iHash1 = iHash2;
iKey1 = iKey2;
iValue1 = iValue2;
iHash2 = 0;
iKey2 = null;
iValue2 = null;
iSize = 1;
return old;
}
return null;
case 1:
if (iKey1 == null) {
Object old = iValue1;
iHash1 = 0;
iKey1 = null;
iValue1 = null;
iSize = 0;
return old;
}
}
} else {
if (iSize > 0) {
int hashCode = key.hashCode();
switch (iSize) { // drop through
case 3:
if (iHash3 == hashCode && key.equals(iKey3)) {
Object old = iValue3;
iHash3 = 0;
iKey3 = null;
iValue3 = null;
iSize = 2;
return old;
}
if (iHash2 == hashCode && key.equals(iKey2)) {
Object old = iValue3;
iHash2 = iHash3;
iKey2 = iKey3;
iValue2 = iValue3;
iHash3 = 0;
iKey3 = null;
iValue3 = null;
iSize = 2;
return old;
}
if (iHash1 == hashCode && key.equals(iKey1)) {
Object old = iValue3;
iHash1 = iHash3;
iKey1 = iKey3;
iValue1 = iValue3;
iHash3 = 0;
iKey3 = null;
iValue3 = null;
iSize = 2;
return old;
}
return null;
case 2:
if (iHash2 == hashCode && key.equals(iKey2)) {
Object old = iValue2;
iHash2 = 0;
iKey2 = null;
iValue2 = null;
iSize = 1;
return old;
}
if (iHash1 == hashCode && key.equals(iKey1)) {
Object old = iValue2;
iHash1 = iHash2;
iKey1 = iKey2;
iValue1 = iValue2;
iHash2 = 0;
iKey2 = null;
iValue2 = null;
iSize = 1;
return old;
}
return null;
case 1:
if (iHash1 == hashCode && key.equals(iKey1)) {
Object old = iValue1;
iHash1 = 0;
iKey1 = null;
iValue1 = null;
iSize = 0;
return old;
}
}
}
}
return null;
}
/**
* Clears the map, resetting the size to zero and nullifying references
* to avoid garbage collection issues.
*/
public void clear() {
if (iMap != null) {
iMap.clear(); // should aid gc
iMap = null; // switch back to flat mode
} else {
iSize = 0;
iHash1 = iHash2 = iHash3 = 0;
iKey1 = iKey2 = iKey3 = null;
iValue1 = iValue2 = iValue3 = null;
}
}
//-----------------------------------------------------------------------
/**
* Gets an iterator over the map.
* Changes made to the iterator affect this map.
* <p>
* A MapIterator returns the keys in the map. It also provides convenient
* methods to get the key and value, and set the value.
* It avoids the need to create an entrySet/keySet/values object.
* It also avoids creating the Mep Entry object.
*
* @return the map iterator
*/
public MapIterator mapIterator() {
if (iMap != null) {
return new EntrySetMapIterator(this);
}
if (iSize == 0) {
return IteratorUtils.EMPTY_MAP_ITERATOR;
}
return new FlatMapIterator(this);
}
/**
* FlatMapIterator
*/
static class FlatMapIterator implements MapIterator, ResettableIterator {
private final Flat3Map iFlatMap;
private int iIndex = 0;
private boolean iCanRemove = false;
FlatMapIterator(Flat3Map map) {
super();
iFlatMap = map;
}
public boolean hasNext() {
return (iIndex < iFlatMap.iSize);
}
public Object next() {
if (hasNext() == false) {
throw new NoSuchElementException("No more elements in the iteration");
}
iCanRemove = true;
iIndex++;
return getKey();
}
public void remove() {
if (iCanRemove == false) {
throw new IllegalStateException("Iterator remove() can only be called once after next()");
}
iFlatMap.remove(getKey());
iIndex--;
iCanRemove = false;
}
public Object getKey() {
if (iCanRemove == false) {
throw new IllegalStateException("Map Entry cannot be queried");
}
switch (iIndex) {
case 3:
return iFlatMap.iKey3;
case 2:
return iFlatMap.iKey2;
case 1:
return iFlatMap.iKey1;
}
throw new IllegalStateException("Invalid map index");
}
public Object getValue() {
if (iCanRemove == false) {
throw new IllegalStateException("Map Entry cannot be queried");
}
switch (iIndex) {
case 3:
return iFlatMap.iValue3;
case 2:
return iFlatMap.iValue2;
case 1:
return iFlatMap.iValue1;
}
throw new IllegalStateException("Invalid map index");
}
public Object setValue(Object value) {
if (iCanRemove == false) {
throw new IllegalStateException("Map Entry cannot be changed");
}
Object old = getValue();
switch (iIndex) {
case 3:
iFlatMap.iValue3 = value;
case 2:
iFlatMap.iValue2 = value;
case 1:
iFlatMap.iValue1 = value;
}
return old;
}
public void reset() {
iIndex = 0;
iCanRemove = false;
}
public String toString() {
if (iCanRemove) {
return "MapIterator[" + getKey() + "=" + getValue() + "]";
} else {
return "MapIterator[]";
}
}
}
/**
* Gets the entrySet view of the map.
* Changes made to the view affect this map.
* The Map Entry is not an independent object and changes as the
* iterator progresses.
* To simply iterate through the entries, use {@link #mapIterator()}.
*
* @return the entrySet view
*/
public Set entrySet() {
if (iMap != null) {
return iMap.entrySet();
}
return new EntrySet(this);
}
/**
* EntrySet
*/
static class EntrySet extends AbstractSet {
private final Flat3Map iFlatMap;
EntrySet(Flat3Map map) {
super();
iFlatMap = map;
}
public int size() {
return iFlatMap.size();
}
public void clear() {
iFlatMap.clear();
}
public boolean remove(Object obj) {
if (obj instanceof Map.Entry == false) {
return false;
}
Map.Entry entry = (Map.Entry) obj;
Object key = entry.getKey();
boolean result = iFlatMap.containsKey(key);
iFlatMap.remove(key);
return result;
}
public Iterator iterator() {
if (iFlatMap.iMap != null) {
return iFlatMap.iMap.entrySet().iterator();
}
if (iFlatMap.size() == 0) {
return IteratorUtils.EMPTY_ITERATOR;
}
return new EntrySetIterator(iFlatMap);
}
}
/**
* EntrySetIterator and MapEntry
*/
static class EntrySetIterator implements Iterator, Map.Entry {
private final Flat3Map iFlatMap;
private int iIndex = 0;
private boolean iCanRemove = false;
EntrySetIterator(Flat3Map map) {
super();
iFlatMap = map;
}
public boolean hasNext() {
return (iIndex < iFlatMap.iSize);
}
public Object next() {
if (hasNext() == false) {
throw new NoSuchElementException("No more elements in the iteration");
}
iCanRemove = true;
iIndex++;
return this;
}
public void remove() {
if (iCanRemove == false) {
throw new IllegalStateException("Iterator remove() can only be called once after next()");
}
iFlatMap.remove(getKey());
iIndex--;
iCanRemove = false;
}
public Object getKey() {
if (iCanRemove == false) {
throw new IllegalStateException("Map Entry cannot be queried");
}
switch (iIndex) {
case 3:
return iFlatMap.iKey3;
case 2:
return iFlatMap.iKey2;
case 1:
return iFlatMap.iKey1;
}
throw new IllegalStateException("Invalid map index");
}
public Object getValue() {
if (iCanRemove == false) {
throw new IllegalStateException("Map Entry cannot be queried");
}
switch (iIndex) {
case 3:
return iFlatMap.iValue3;
case 2:
return iFlatMap.iValue2;
case 1:
return iFlatMap.iValue1;
}
throw new IllegalStateException("Invalid map index");
}
public Object setValue(Object value) {
if (iCanRemove == false) {
throw new IllegalStateException("Map Entry cannot be changed");
}
Object old = getValue();
switch (iIndex) {
case 3:
iFlatMap.iValue3 = value;
case 2:
iFlatMap.iValue2 = value;
case 1:
iFlatMap.iValue1 = value;
}
return old;
}
public boolean equals(Object obj) {
if (iCanRemove == false) {
return false;
}
if (obj instanceof Map.Entry == false) {
return false;
}
Map.Entry other = (Map.Entry) obj;
Object key = getKey();
Object value = getValue();
return (key == null ? other.getKey() == null : key.equals(other.getKey())) &&
(value == null ? other.getValue() == null : value.equals(other.getValue()));
}
public int hashCode() {
if (iCanRemove == false) {
return 0;
}
Object key = getKey();
Object value = getValue();
return (key == null ? 0 : key.hashCode()) ^
(value == null ? 0 : value.hashCode());
}
public String toString() {
if (iCanRemove) {
return getKey() + "=" + getValue();
} else {
return "";
}
}
}
/**
* Gets the keySet view of the map.
* Changes made to the view affect this map.
* To simply iterate through the keys, use {@link #mapIterator()}.
*
* @return the keySet view
*/
public Set keySet() {
if (iMap != null) {
return iMap.keySet();
}
return new KeySet(this);
}
/**
* KeySet
*/
static class KeySet extends AbstractSet {
private final Flat3Map iFlatMap;
KeySet(Flat3Map map) {
super();
iFlatMap = map;
}
public int size() {
return iFlatMap.size();
}
public void clear() {
iFlatMap.clear();
}
public boolean contains(Object key) {
return iFlatMap.containsKey(key);
}
public boolean remove(Object key) {
boolean result = iFlatMap.containsKey(key);
iFlatMap.remove(key);
return result;
}
public Iterator iterator() {
if (iFlatMap.iMap != null) {
return iFlatMap.iMap.keySet().iterator();
}
if (iFlatMap.size() == 0) {
return IteratorUtils.EMPTY_ITERATOR;
}
return new KeySetIterator(iFlatMap);
}
}
/**
* KeySetIterator
*/
static class KeySetIterator extends EntrySetIterator {
KeySetIterator(Flat3Map map) {
super(map);
}
public Object next() {
super.next();
return getKey();
}
}
/**
* Gets the values view of the map.
* Changes made to the view affect this map.
* To simply iterate through the values, use {@link #mapIterator()}.
*
* @return the values view
*/
public Collection values() {
if (iMap != null) {
return iMap.values();
}
return new Values(this);
}
/**
* Values
*/
static class Values extends AbstractCollection {
private final Flat3Map iFlatMap;
Values(Flat3Map map) {
super();
iFlatMap = map;
}
public int size() {
return iFlatMap.size();
}
public void clear() {
iFlatMap.clear();
}
public boolean contains(Object value) {
return iFlatMap.containsValue(value);
}
public Iterator iterator() {
if (iFlatMap.iMap != null) {
return iFlatMap.iMap.values().iterator();
}
if (iFlatMap.size() == 0) {
return IteratorUtils.EMPTY_ITERATOR;
}
return new ValuesIterator(iFlatMap);
}
}
/**
* ValuesIterator
*/
static class ValuesIterator extends EntrySetIterator {
ValuesIterator(Flat3Map map) {
super(map);
}
public Object next() {
super.next();
return getValue();
}
}
//-----------------------------------------------------------------------
/**
* Compares this map with another.
*
* @param obj the object to compare to
* @return true if equal
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (iMap != null) {
return iMap.equals(obj);
}
if (obj instanceof Map == false) {
return false;
}
Map other = (Map) obj;
if (iSize != other.size()) {
return false;
}
if (iSize > 0) {
Object otherValue = null;
switch (iSize) { // drop through
case 3:
if (other.containsKey(iKey3) == false) {
otherValue = other.get(iKey3);
if (iValue3 == null ? otherValue != null : !iValue3.equals(otherValue)) {
return false;
}
}
case 2:
if (other.containsKey(iKey2) == false) {
otherValue = other.get(iKey2);
if (iValue2 == null ? otherValue != null : !iValue2.equals(otherValue)) {
return false;
}
}
case 1:
if (other.containsKey(iKey1) == false) {
otherValue = other.get(iKey1);
if (iValue1 == null ? otherValue != null : !iValue1.equals(otherValue)) {
return false;
}
}
}
}
return true;
}
/**
* Gets the standard Map hashCode.
*
* @return the hashcode defined in the Map interface
*/
public int hashCode() {
if (iMap != null) {
return iMap.hashCode();
}
int total = 0;
switch (iSize) { // drop through
case 3:
total += (iHash3 ^ (iValue3 == null ? 0 : iValue3.hashCode()));
case 2:
total += (iHash2 ^ (iValue2 == null ? 0 : iValue2.hashCode()));
case 1:
total += (iHash1 ^ (iValue1 == null ? 0 : iValue1.hashCode()));
}
return total;
}
/**
* Gets the map as a String.
*
* @return a string version of the map
*/
public String toString() {
if (iMap != null) {
return iMap.toString();
}
if (iSize == 0) {
return "{}";
}
StringBuffer buf = new StringBuffer(128);
buf.append('{');
switch (iSize) { // drop through
case 3:
buf.append(iKey3);
buf.append('=');
buf.append(iValue3);
buf.append(',');
case 2:
buf.append(iKey2);
buf.append('=');
buf.append(iValue2);
buf.append(',');
case 1:
buf.append(iKey1);
buf.append('=');
buf.append(iValue1);
}
buf.append('}');
return buf.toString();
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org