commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From scolebou...@apache.org
Subject cvs commit: jakarta-commons/collections/src/java/org/apache/commons/collections/map MultiKeyMap.java
Date Mon, 12 Apr 2004 12:05:30 GMT
scolebourne    2004/04/12 05:05:30

  Modified:    collections RELEASE-NOTES.html
               collections/src/test/org/apache/commons/collections/map
                        TestAll.java
  Added:       collections/data/test
                        MultiKeyMap.emptyCollection.version3.1.obj
                        MultiKeyMap.fullCollection.version3.1.obj
               collections/src/test/org/apache/commons/collections/map
                        TestMultiKeyMap.java
               collections/src/java/org/apache/commons/collections/map
                        MultiKeyMap.java
  Log:
  Add MultiKeyMap implementation
  
  Revision  Changes    Path
  1.35      +1 -0      jakarta-commons/collections/RELEASE-NOTES.html
  
  Index: RELEASE-NOTES.html
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/collections/RELEASE-NOTES.html,v
  retrieving revision 1.34
  retrieving revision 1.35
  diff -u -r1.34 -r1.35
  --- RELEASE-NOTES.html	9 Apr 2004 22:56:00 -0000	1.34
  +++ RELEASE-NOTES.html	12 Apr 2004 12:05:29 -0000	1.35
  @@ -26,6 +26,7 @@
   <center><h3>NEW CLASSES</h3></center>
   <ul>
   <li>SingletonMap - fully featured singleton Map implementation</li>
  +<li>MultiKeyMap - A map that allows multiple keys to be used to map the value</li>
   <li>TransformedPredicate - A predicate where the input object is transformed [26946]</li>
   <li>ObjectGraphIterator - An iterator that can iterate over a graph of objects</li>
   <li>AbstractReferenceMap - New base class for reference maps [26503]</li>
  
  
  
  1.1                  jakarta-commons/collections/data/test/MultiKeyMap.emptyCollection.version3.1.obj
  
  	<<Binary file>>
  
  
  1.1                  jakarta-commons/collections/data/test/MultiKeyMap.fullCollection.version3.1.obj
  
  	<<Binary file>>
  
  
  1.17      +2 -1      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.16
  retrieving revision 1.17
  diff -u -r1.16 -r1.17
  --- TestAll.java	10 Apr 2004 21:24:21 -0000	1.16
  +++ TestAll.java	12 Apr 2004 12:05:29 -0000	1.17
  @@ -48,6 +48,7 @@
           suite.addTest(TestIdentityMap.suite());
           suite.addTest(TestLinkedMap.suite());
           suite.addTest(TestLRUMap.suite());
  +        suite.addTest(TestMultiKeyMap.suite());
           suite.addTest(TestReferenceMap.suite());
           suite.addTest(TestStaticBucketMap.suite());
           suite.addTest(TestSingletonMap.suite());
  
  
  
  1.1                  jakarta-commons/collections/src/test/org/apache/commons/collections/map/TestMultiKeyMap.java
  
  Index: TestMultiKeyMap.java
  ===================================================================
  /*
   *  Copyright 2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   */
  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.MapIterator;
  import org.apache.commons.collections.keyvalue.MultiKey;
  
  /**
   * JUnit tests.
   * 
   * @version $Revision: 1.1 $ $Date: 2004/04/12 12:05:30 $
   * 
   * @author Stephen Colebourne
   */
  public class TestMultiKeyMap extends AbstractTestIterableMap {
      
      static final Integer I1 = new Integer(1);
      static final Integer I2 = new Integer(2);
      static final Integer I3 = new Integer(3);
      static final Integer I4 = new Integer(4);
      static final Integer I5 = new Integer(5);
      static final Integer I6 = new Integer(6);
      static final Integer I7 = new Integer(7);
      static final Integer I8 = new Integer(8);
  
      public TestMultiKeyMap(String testName) {
          super(testName);
      }
  
      public static void main(String[] args) {
          TestRunner.run(suite());
      }
  
      public static Test suite() {
          return BulkTest.makeSuite(TestMultiKeyMap.class);
      }
  
      public Map makeEmptyMap() {
          return new MultiKeyMap();
      }
  
      public Object[] getSampleKeys() {
          return getMultiKeyKeys();
      }
  
      private MultiKey[] getMultiKeyKeys() {
          return new MultiKey[] {
              new MultiKey(I1, I2),
              new MultiKey(I2, I3),
              new MultiKey(I3, I4),
              new MultiKey(I1, I1, I2),
              new MultiKey(I2, I3, I4),
              new MultiKey(I3, I7, I6),
              new MultiKey(I1, I1, I2, I3),
              new MultiKey(I2, I4, I5, I6),
              new MultiKey(I3, I6, I7, I8),
              new MultiKey(I1, I1, I2, I3, I4),
              new MultiKey(I2, I3, I4, I5, I6),
              new MultiKey(I3, I5, I6, I7, I8),
          };
      }
  
      public Object[] getSampleValues() {
          return new Object[] {
              "2A", "2B", "2C",
              "3D", "3E", "3F",
              "4G", "4H", "4I",
              "5J", "5K", "5L",
          };
      }
  
      public Object[] getNewSampleValues() {
          return new Object[] {
              "1a", "1b", "1c",
              "2d", "2e", "2f",
              "3g", "3h", "3i",
              "4j", "4k", "4l",
          };
      }
  
      public Object[] getOtherKeys() {
          return new Object[] {
              new MultiKey(I1, I7),
              new MultiKey(I1, I8),
              new MultiKey(I2, I4),
              new MultiKey(I2, I5),
          };
      }
      
      public boolean isAllowNullKey() {
          return false;
      }
  
      //-----------------------------------------------------------------------
      public void testMultiKeyGet() {
          resetFull();
          MultiKeyMap multimap = (MultiKeyMap) map;
          MultiKey[] keys = getMultiKeyKeys();
          Object[] values = getSampleValues();
          
          for (int i = 0; i < keys.length; i++) {
              MultiKey key = keys[i];
              Object value = values[i];
              
              switch (key.size()) {
                  case 2:
                  assertEquals(value, multimap.get(key.getKey(0), key.getKey(1)));
                  assertEquals(null, multimap.get(null, key.getKey(1)));
                  assertEquals(null, multimap.get(key.getKey(0), null));
                  assertEquals(null, multimap.get(null, null));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null, null));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null, null, null));
                  break;
                  case 3:
                  assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2)));
                  assertEquals(null, multimap.get(null, key.getKey(1), key.getKey(2)));
                  assertEquals(null, multimap.get(key.getKey(0), null, key.getKey(2)));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null));
                  assertEquals(null, multimap.get(null, null, null));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null, null));
                  break;
                  case 4:
                  assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(null, multimap.get(null, key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(null, multimap.get(key.getKey(0), null, key.getKey(2), key.getKey(3)));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null, key.getKey(3)));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null));
                  assertEquals(null, multimap.get(null, null, null, null));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
                  break;
                  case 5:
                  assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(null, multimap.get(null, key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(null, multimap.get(key.getKey(0), null, key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), null, key.getKey(3), key.getKey(4)));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), null, key.getKey(4)));
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
                  assertEquals(null, multimap.get(null, null, null, null, null));
                  break;
                  default:
                  fail("Invalid key size");
              }
          }
      }
      
      public void testMultiKeyContainsKey() {
          resetFull();
          MultiKeyMap multimap = (MultiKeyMap) map;
          MultiKey[] keys = getMultiKeyKeys();
          Object[] values = getSampleValues();
          
          for (int i = 0; i < keys.length; i++) {
              MultiKey key = keys[i];
              Object value = values[i];
              
              switch (key.size()) {
                  case 2:
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1)));
                  assertEquals(false, multimap.containsKey(null, key.getKey(1)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), null));
                  assertEquals(false, multimap.containsKey(null, null));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null, null));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null, null, null));
                  break;
                  case 3:
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
                  assertEquals(false, multimap.containsKey(null, key.getKey(1), key.getKey(2)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), null, key.getKey(2)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null));
                  assertEquals(false, multimap.containsKey(null, null, null));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null, null));
                  break;
                  case 4:
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(false, multimap.containsKey(null, key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), null, key.getKey(2), key.getKey(3)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null, key.getKey(3)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null));
                  assertEquals(false, multimap.containsKey(null, null, null, null));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
                  break;
                  case 5:
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(false, multimap.containsKey(null, key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), null, key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), null, key.getKey(3), key.getKey(4)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), null, key.getKey(4)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
                  assertEquals(false, multimap.containsKey(null, null, null, null, null));
                  break;
                  default:
                  fail("Invalid key size");
              }
          }
      }
      
      public void testMultiKeyPut() {
          MultiKey[] keys = getMultiKeyKeys();
          Object[] values = getSampleValues();
          
          for (int i = 0; i < keys.length; i++) {
              MultiKeyMap multimap = new MultiKeyMap();
              
              MultiKey key = keys[i];
              Object value = values[i];
              
              switch (key.size()) {
                  case 2:
                  assertEquals(null, multimap.put(key.getKey(0), key.getKey(1), value));
                  assertEquals(1, multimap.size());
                  assertEquals(value, multimap.get(key.getKey(0), key.getKey(1)));
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1)));
                  assertEquals(true, multimap.containsKey(new MultiKey(key.getKey(0), key.getKey(1))));
                  assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), null));
                  assertEquals(1, multimap.size());
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1)));
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1)));
                  break;
                  case 3:
                  assertEquals(null, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), value));
                  assertEquals(1, multimap.size());
                  assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2)));
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
                  assertEquals(true, multimap.containsKey(new MultiKey(key.getKey(0), key.getKey(1), key.getKey(2))));
                  assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), null));
                  assertEquals(1, multimap.size());
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2)));
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
                  break;
                  case 4:
                  assertEquals(null, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), value));
                  assertEquals(1, multimap.size());
                  assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(true, multimap.containsKey(new MultiKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3))));
                  assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), null));
                  assertEquals(1, multimap.size());
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  break;
                  case 5:
                  assertEquals(null, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4), value));
                  assertEquals(1, multimap.size());
                  assertEquals(value, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(true, multimap.containsKey(new MultiKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4))));
                  assertEquals(value, multimap.put(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4), null));
                  assertEquals(1, multimap.size());
                  assertEquals(null, multimap.get(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  break;
                  default:
                  fail("Invalid key size");
              }
          }
      }
      
      public void testMultiKeyRemove() {
          MultiKey[] keys = getMultiKeyKeys();
          Object[] values = getSampleValues();
          
          for (int i = 0; i < keys.length; i++) {
              resetFull();
              MultiKeyMap multimap = (MultiKeyMap) map;
              int size = multimap.size();
              
              MultiKey key = keys[i];
              Object value = values[i];
              
              switch (key.size()) {
                  case 2:
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1)));
                  assertEquals(value, multimap.remove(key.getKey(0), key.getKey(1)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1)));
                  assertEquals(size - 1, multimap.size());
                  assertEquals(null, multimap.remove(key.getKey(0), key.getKey(1)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1)));
                  break;
                  case 3:
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
                  assertEquals(value, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
                  assertEquals(size - 1, multimap.size());
                  assertEquals(null, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2)));
                  break;
                  case 4:
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(value, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(size - 1, multimap.size());
                  assertEquals(null, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3)));
                  break;
                  case 5:
                  assertEquals(true, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(value, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(size - 1, multimap.size());
                  assertEquals(null, multimap.remove(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  assertEquals(false, multimap.containsKey(key.getKey(0), key.getKey(1), key.getKey(2), key.getKey(3), key.getKey(4)));
                  break;
                  default:
                  fail("Invalid key size");
              }
          }
      }
      
      public void testMultiKeyRemoveAll1() {
          resetFull();
          MultiKeyMap multimap = (MultiKeyMap) map;
          assertEquals(12, multimap.size());
          
          multimap.removeAll(I1);
          assertEquals(8, multimap.size());
          for (MapIterator it = multimap.mapIterator(); it.hasNext();) {
              MultiKey key = (MultiKey) it.next();
              assertEquals(false, I1.equals(key.getKey(0)));
          }
      }
      
      public void testMultiKeyRemoveAll2() {
          resetFull();
          MultiKeyMap multimap = (MultiKeyMap) map;
          assertEquals(12, multimap.size());
          
          multimap.removeAll(I2, I3);
          assertEquals(9, multimap.size());
          for (MapIterator it = multimap.mapIterator(); it.hasNext();) {
              MultiKey key = (MultiKey) it.next();
              assertEquals(false, I2.equals(key.getKey(0)) && I3.equals(key.getKey(1)));
          }
      }
      
      public void testMultiKeyRemoveAll3() {
          resetFull();
          MultiKeyMap multimap = (MultiKeyMap) map;
          assertEquals(12, multimap.size());
          
          multimap.removeAll(I1, I1, I2);
          assertEquals(9, multimap.size());
          for (MapIterator it = multimap.mapIterator(); it.hasNext();) {
              MultiKey key = (MultiKey) it.next();
              assertEquals(false, I1.equals(key.getKey(0)) && I1.equals(key.getKey(1)) && I2.equals(key.getKey(2)));
          }
      }
      
      public void testMultiKeyRemoveAll4() {
          resetFull();
          MultiKeyMap multimap = (MultiKeyMap) map;
          assertEquals(12, multimap.size());
          
          multimap.removeAll(I1, I1, I2, I3);
          assertEquals(10, multimap.size());
          for (MapIterator it = multimap.mapIterator(); it.hasNext();) {
              MultiKey key = (MultiKey) it.next();
              assertEquals(false, I1.equals(key.getKey(0)) && I1.equals(key.getKey(1)) && I2.equals(key.getKey(2)) && key.size() >= 4 && I3.equals(key.getKey(3)));
          }
      }
      
      //-----------------------------------------------------------------------
      public void testClone() {
          MultiKeyMap map = new MultiKeyMap();
          map.put(new MultiKey(I1, I2), "1-2");
          Map cloned = (Map) map.clone();
          assertEquals(map.size(), cloned.size());
          assertSame(map.get(new MultiKey(I1, I2)), cloned.get(new MultiKey(I1, I2)));
      }
  
      public String getCompatibilityVersion() {
          return "3.1";
      }
  
  //    public void testCreate() throws Exception {
  //        resetEmpty();
  //        writeExternalFormToDisk(
  //            (java.io.Serializable) map,
  //            "D:/dev/collections/data/test/MultiKeyMap.emptyCollection.version3.1.obj");
  //        resetFull();
  //        writeExternalFormToDisk(
  //            (java.io.Serializable) map,
  //            "D:/dev/collections/data/test/MultiKeyMap.fullCollection.version3.1.obj");
  //    }
  }
  
  
  
  1.1                  jakarta-commons/collections/src/java/org/apache/commons/collections/map/MultiKeyMap.java
  
  Index: MultiKeyMap.java
  ===================================================================
  /*
   *  Copyright 2004 The Apache Software Foundation
   *
   *  Licensed under the Apache License, Version 2.0 (the "License");
   *  you may not use this file except in compliance with the License.
   *  You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   *  Unless required by applicable law or agreed to in writing, software
   *  distributed under the License is distributed on an "AS IS" BASIS,
   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   *  See the License for the specific language governing permissions and
   *  limitations under the License.
   */
  package org.apache.commons.collections.map;
  
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.io.Serializable;
  import java.util.Map;
  
  import org.apache.commons.collections.MapIterator;
  import org.apache.commons.collections.keyvalue.MultiKey;
  
  /**
   * A <code>Map</code> implementation that uses multiple keys to map the value.
   * <p>
   * This class is the most efficient way to uses multiple keys to map to a value.
   * The best way to use this class is via the additional map-style methods.
   * These provide <code>get</code>, <code>containsKey</code>, <code>put</code> and
   * <code>remove</code> for individual keys which operate without extra object creation.
   * <p>
   * The additional methods are the main interface of this map.
   * As such, you will not mormally hold this map in a variable of type <code>Map</code>.
   * The normal map methods take in and return a {@link MultiKey}.
   * <p>
   * As an example, consider a cache that uses a String airline code and a Locale
   * to lookup the airline's name:
   * <pre>
   * public String getAirlineName(String code, String locale) {
   *   MultiKeyMap cache = getCache();
   *   String name = (String) cache.get(code, locale);
   *   if (name == null) {
   *     name = getAirlineNameFromDB(code, locale);
   *     cache.put(code, locale, name);
   *   }
   *   return name;
   * }
   * </pre>
   *
   * @since Commons Collections 3.1
   * @version $Revision: 1.1 $ $Date: 2004/04/12 12:05:30 $
   *
   * @author Stephen Colebourne
   */
  public class MultiKeyMap
          extends AbstractHashedMap implements Serializable, Cloneable {
  
      /** Serialisation version */
      private static final long serialVersionUID = -1788199231038721040L;
      
      /**
       * Constructs a new empty map with default size and load factor.
       */
      public MultiKeyMap() {
          super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD);
      }
  
      /**
       * Constructs a new, empty map with the specified initial capacity. 
       *
       * @param initialCapacity  the initial capacity
       * @throws IllegalArgumentException if the initial capacity is less than one
       */
      public MultiKeyMap(int initialCapacity) {
          super(initialCapacity);
      }
  
      /**
       * Constructs a new, empty map with the specified initial capacity and
       * load factor. 
       *
       * @param initialCapacity  the initial capacity
       * @param loadFactor  the load factor
       * @throws IllegalArgumentException if the initial capacity is less than one
       * @throws IllegalArgumentException if the load factor is less than zero
       */
      public MultiKeyMap(int initialCapacity, float loadFactor) {
          super(initialCapacity, loadFactor);
      }
  
      /**
       * Constructor copying elements from another map.
       *
       * @param map  the map to copy
       * @throws NullPointerException if the map is null
       */
      public MultiKeyMap(Map map) {
          super(map);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Clones the map without cloning the keys or values.
       *
       * @return a shallow clone
       */
      public Object clone() {
          return super.clone();
      }
      
      /**
       * Write the map out using a custom routine.
       */
      private void writeObject(ObjectOutputStream out) throws IOException {
          out.defaultWriteObject();
          doWriteObject(out);
      }
  
      /**
       * Read the map in using a custom routine.
       */
      private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
          in.defaultReadObject();
          doReadObject(in);
      }
  
      //-----------------------------------------------------------------------
      /**
       * Gets the value mapped to the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @return the mapped value, null if no match
       */
      public Object get(Object key1, Object key2) {
          int hashCode = hash(key1, key2);
          HashEntry entry = data[hashIndex(hashCode, data.length)];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
                  return entry.getValue();
              }
              entry = entry.next;
          }
          return null;
      }
  
      /**
       * Checks whether the map contains the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @return true if the map contains the key
       */
      public boolean containsKey(Object key1, Object key2) {
          int hashCode = hash(key1, key2);
          HashEntry entry = data[hashIndex(hashCode, data.length)];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
                  return true;
              }
              entry = entry.next;
          }
          return false;
      }
  
      /**
       * Stores the value against the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param value  the value to store
       * @return the value previously mapped to this combined key, null if none
       */
      public Object put(Object key1, Object key2, Object value) {
          int hashCode = hash(key1, key2);
          int index = hashIndex(hashCode, data.length);
          HashEntry entry = data[index];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
                  Object oldValue = entry.getValue();
                  updateEntry(entry, value);
                  return oldValue;
              }
              entry = entry.next;
          }
          
          addMapping(index, hashCode, new MultiKey(key1, key2), value);
          return null;
      }
  
      /**
       * Removes the specified multi-key from this map.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @return the value mapped to the removed key, null if key not in map
       */
      public Object remove(Object key1, Object key2) {
          int hashCode = hash(key1, key2);
          int index = hashIndex(hashCode, data.length);
          HashEntry entry = data[index];
          HashEntry previous = null;
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2)) {
                  Object oldValue = entry.getValue();
                  removeMapping(entry, index, previous);
                  return oldValue;
              }
              previous = entry;
              entry = entry.next;
          }
          return null;
      }
  
      /**
       * Gets the hash code for the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @return the hash code
       */
      protected int hash(Object key1, Object key2) {
          int h = 0;
          if (key1 != null) {
              h ^= key1.hashCode();
          }
          if (key2 != null) {
              h ^= key2.hashCode();
          }
          h += ~(h << 9);
          h ^=  (h >>> 14);
          h +=  (h << 4);
          h ^=  (h >>> 10);
          return h;
      }
  
      /**
       * Is the key equal to the combined key.
       * 
       * @param entry  the entry to compare to
       * @param key1  the first key
       * @param key2  the second key
       * @return true if the key matches
       */
      protected boolean isEqualKey(HashEntry entry, Object key1, Object key2) {
          MultiKey multi = (MultiKey) entry.getKey();
          return
              multi.size() == 2 &&
              (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
              (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1)));
      }
  
      //-----------------------------------------------------------------------
      /**
       * Gets the value mapped to the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @return the mapped value, null if no match
       */
      public Object get(Object key1, Object key2, Object key3) {
          int hashCode = hash(key1, key2, key3);
          HashEntry entry = data[hashIndex(hashCode, data.length)];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
                  return entry.getValue();
              }
              entry = entry.next;
          }
          return null;
      }
  
      /**
       * Checks whether the map contains the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @return true if the map contains the key
       */
      public boolean containsKey(Object key1, Object key2, Object key3) {
          int hashCode = hash(key1, key2, key3);
          HashEntry entry = data[hashIndex(hashCode, data.length)];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
                  return true;
              }
              entry = entry.next;
          }
          return false;
      }
  
      /**
       * Stores the value against the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param value  the value to store
       * @return the value previously mapped to this combined key, null if none
       */
      public Object put(Object key1, Object key2, Object key3, Object value) {
          int hashCode = hash(key1, key2, key3);
          int index = hashIndex(hashCode, data.length);
          HashEntry entry = data[index];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
                  Object oldValue = entry.getValue();
                  updateEntry(entry, value);
                  return oldValue;
              }
              entry = entry.next;
          }
          
          addMapping(index, hashCode, new MultiKey(key1, key2, key3), value);
          return null;
      }
  
      /**
       * Removes the specified multi-key from this map.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @return the value mapped to the removed key, null if key not in map
       */
      public Object remove(Object key1, Object key2, Object key3) {
          int hashCode = hash(key1, key2, key3);
          int index = hashIndex(hashCode, data.length);
          HashEntry entry = data[index];
          HashEntry previous = null;
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3)) {
                  Object oldValue = entry.getValue();
                  removeMapping(entry, index, previous);
                  return oldValue;
              }
              previous = entry;
              entry = entry.next;
          }
          return null;
      }
  
      /**
       * Gets the hash code for the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @return the hash code
       */
      protected int hash(Object key1, Object key2, Object key3) {
          int h = 0;
          if (key1 != null) {
              h ^= key1.hashCode();
          }
          if (key2 != null) {
              h ^= key2.hashCode();
          }
          if (key3 != null) {
              h ^= key3.hashCode();
          }
          h += ~(h << 9);
          h ^=  (h >>> 14);
          h +=  (h << 4);
          h ^=  (h >>> 10);
          return h;
      }
  
      /**
       * Is the key equal to the combined key.
       * 
       * @param entry  the entry to compare to
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @return true if the key matches
       */
      protected boolean isEqualKey(HashEntry entry, Object key1, Object key2, Object key3) {
          MultiKey multi = (MultiKey) entry.getKey();
          return
              multi.size() == 3 &&
              (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
              (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
              (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2)));
      }
  
      //-----------------------------------------------------------------------
      /**
       * Gets the value mapped to the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @return the mapped value, null if no match
       */
      public Object get(Object key1, Object key2, Object key3, Object key4) {
          int hashCode = hash(key1, key2, key3, key4);
          HashEntry entry = data[hashIndex(hashCode, data.length)];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
                  return entry.getValue();
              }
              entry = entry.next;
          }
          return null;
      }
  
      /**
       * Checks whether the map contains the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @return true if the map contains the key
       */
      public boolean containsKey(Object key1, Object key2, Object key3, Object key4) {
          int hashCode = hash(key1, key2, key3, key4);
          HashEntry entry = data[hashIndex(hashCode, data.length)];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
                  return true;
              }
              entry = entry.next;
          }
          return false;
      }
  
      /**
       * Stores the value against the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @param value  the value to store
       * @return the value previously mapped to this combined key, null if none
       */
      public Object put(Object key1, Object key2, Object key3, Object key4, Object value) {
          int hashCode = hash(key1, key2, key3, key4);
          int index = hashIndex(hashCode, data.length);
          HashEntry entry = data[index];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
                  Object oldValue = entry.getValue();
                  updateEntry(entry, value);
                  return oldValue;
              }
              entry = entry.next;
          }
          
          addMapping(index, hashCode, new MultiKey(key1, key2, key3, key4), value);
          return null;
      }
  
      /**
       * Removes the specified multi-key from this map.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @return the value mapped to the removed key, null if key not in map
       */
      public Object remove(Object key1, Object key2, Object key3, Object key4) {
          int hashCode = hash(key1, key2, key3, key4);
          int index = hashIndex(hashCode, data.length);
          HashEntry entry = data[index];
          HashEntry previous = null;
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4)) {
                  Object oldValue = entry.getValue();
                  removeMapping(entry, index, previous);
                  return oldValue;
              }
              previous = entry;
              entry = entry.next;
          }
          return null;
      }
  
      /**
       * Gets the hash code for the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @return the hash code
       */
      protected int hash(Object key1, Object key2, Object key3, Object key4) {
          int h = 0;
          if (key1 != null) {
              h ^= key1.hashCode();
          }
          if (key2 != null) {
              h ^= key2.hashCode();
          }
          if (key3 != null) {
              h ^= key3.hashCode();
          }
          if (key4 != null) {
              h ^= key4.hashCode();
          }
          h += ~(h << 9);
          h ^=  (h >>> 14);
          h +=  (h << 4);
          h ^=  (h >>> 10);
          return h;
      }
  
      /**
       * Is the key equal to the combined key.
       * 
       * @param entry  the entry to compare to
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @return true if the key matches
       */
      protected boolean isEqualKey(HashEntry entry, Object key1, Object key2, Object key3, Object key4) {
          MultiKey multi = (MultiKey) entry.getKey();
          return
              multi.size() == 4 &&
              (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
              (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
              (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) &&
              (key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3)));
      }
  
      //-----------------------------------------------------------------------
      /**
       * Gets the value mapped to the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @param key5  the fifth key
       * @return the mapped value, null if no match
       */
      public Object get(Object key1, Object key2, Object key3, Object key4, Object key5) {
          int hashCode = hash(key1, key2, key3, key4, key5);
          HashEntry entry = data[hashIndex(hashCode, data.length)];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
                  return entry.getValue();
              }
              entry = entry.next;
          }
          return null;
      }
  
      /**
       * Checks whether the map contains the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @param key5  the fifth key
       * @return true if the map contains the key
       */
      public boolean containsKey(Object key1, Object key2, Object key3, Object key4, Object key5) {
          int hashCode = hash(key1, key2, key3, key4, key5);
          HashEntry entry = data[hashIndex(hashCode, data.length)];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
                  return true;
              }
              entry = entry.next;
          }
          return false;
      }
  
      /**
       * Stores the value against the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @param key5  the fifth key
       * @param value  the value to store
       * @return the value previously mapped to this combined key, null if none
       */
      public Object put(Object key1, Object key2, Object key3, Object key4, Object key5, Object value) {
          int hashCode = hash(key1, key2, key3, key4, key5);
          int index = hashIndex(hashCode, data.length);
          HashEntry entry = data[index];
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
                  Object oldValue = entry.getValue();
                  updateEntry(entry, value);
                  return oldValue;
              }
              entry = entry.next;
          }
          
          addMapping(index, hashCode, new MultiKey(key1, key2, key3, key4, key5), value);
          return null;
      }
  
      /**
       * Removes the specified multi-key from this map.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @param key5  the fifth key
       * @return the value mapped to the removed key, null if key not in map
       */
      public Object remove(Object key1, Object key2, Object key3, Object key4, Object key5) {
          int hashCode = hash(key1, key2, key3, key4, key5);
          int index = hashIndex(hashCode, data.length);
          HashEntry entry = data[index];
          HashEntry previous = null;
          while (entry != null) {
              if (entry.hashCode == hashCode && isEqualKey(entry, key1, key2, key3, key4, key5)) {
                  Object oldValue = entry.getValue();
                  removeMapping(entry, index, previous);
                  return oldValue;
              }
              previous = entry;
              entry = entry.next;
          }
          return null;
      }
  
      /**
       * Gets the hash code for the specified multi-key.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @param key5  the fifth key
       * @return the hash code
       */
      protected int hash(Object key1, Object key2, Object key3, Object key4, Object key5) {
          int h = 0;
          if (key1 != null) {
              h ^= key1.hashCode();
          }
          if (key2 != null) {
              h ^= key2.hashCode();
          }
          if (key3 != null) {
              h ^= key3.hashCode();
          }
          if (key4 != null) {
              h ^= key4.hashCode();
          }
          if (key5 != null) {
              h ^= key5.hashCode();
          }
          h += ~(h << 9);
          h ^=  (h >>> 14);
          h +=  (h << 4);
          h ^=  (h >>> 10);
          return h;
      }
  
      /**
       * Is the key equal to the combined key.
       * 
       * @param entry  the entry to compare to
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @param key5  the fifth key
       * @return true if the key matches
       */
      protected boolean isEqualKey(HashEntry entry, Object key1, Object key2, Object key3, Object key4, Object key5) {
          MultiKey multi = (MultiKey) entry.getKey();
          return
              multi.size() == 5 &&
              (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
              (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
              (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) &&
              (key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3))) &&
              (key5 == null ? multi.getKey(4) == null : key5.equals(multi.getKey(4)));
      }
  
      //-----------------------------------------------------------------------
      /**
       * Removes all mappings where the first key is that specified.
       * <p>
       * This method removes all the mappings where the <code>MultiKey</code>
       * has one or more keys, and the first matches that specified.
       * 
       * @param key1  the first key
       * @return true if any elements were removed
       */
      public boolean removeAll(Object key1) {
          boolean modified = false;
          MapIterator it = mapIterator();
          while (it.hasNext()) {
              MultiKey multi = (MultiKey) it.next();
              if (multi.size() >= 1 &&
                  (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0)))) {
                  it.remove();
                  modified = true;
              }
          }
          return modified;
      }
  
      /**
       * Removes all mappings where the first two keys are those specified.
       * <p>
       * This method removes all the mappings where the <code>MultiKey</code>
       * has two or more keys, and the first two match those specified.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @return true if any elements were removed
       */
      public boolean removeAll(Object key1, Object key2) {
          boolean modified = false;
          MapIterator it = mapIterator();
          while (it.hasNext()) {
              MultiKey multi = (MultiKey) it.next();
              if (multi.size() >= 2 &&
                  (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
                  (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1)))) {
                  it.remove();
                  modified = true;
              }
          }
          return modified;
      }
  
      /**
       * Removes all mappings where the first three keys are those specified.
       * <p>
       * This method removes all the mappings where the <code>MultiKey</code>
       * has three or more keys, and the first three match those specified.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @return true if any elements were removed
       */
      public boolean removeAll(Object key1, Object key2, Object key3) {
          boolean modified = false;
          MapIterator it = mapIterator();
          while (it.hasNext()) {
              MultiKey multi = (MultiKey) it.next();
              if (multi.size() >= 3 &&
                  (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
                  (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
                  (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2)))) {
                  it.remove();
                  modified = true;
              }
          }
          return modified;
      }
  
      /**
       * Removes all mappings where the first four keys are those specified.
       * <p>
       * This method removes all the mappings where the <code>MultiKey</code>
       * has four or more keys, and the first four match those specified.
       * 
       * @param key1  the first key
       * @param key2  the second key
       * @param key3  the third key
       * @param key4  the fourth key
       * @return true if any elements were removed
       */
      public boolean removeAll(Object key1, Object key2, Object key3, Object key4) {
          boolean modified = false;
          MapIterator it = mapIterator();
          while (it.hasNext()) {
              MultiKey multi = (MultiKey) it.next();
              if (multi.size() >= 4 &&
                  (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) &&
                  (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) &&
                  (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) &&
                  (key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3)))) {
                  it.remove();
                  modified = true;
              }
          }
          return modified;
      }
  
      //-----------------------------------------------------------------------
      /**
       * Override superclass to ensure that input keys are valid MultiKey objects.
       * 
       * @param key  the key to check
       * @return the validated key
       */
      protected Object convertKey(Object key) {
          if (key == null) {
              throw new NullPointerException("Key must not be null");
          }
          if (key instanceof MultiKey == false) {
              throw new ClassCastException("Key must be a MultiKey");
          }
          return key;
      }
  
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message