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 2004/04/09 16:46:35 UTC

cvs commit: jakarta-commons/collections/data/test SingletonMap.emptyCollection.version3.1.obj SingletonMap.fullCollection.version3.1.obj

scolebourne    2004/04/09 07:46:35

  Modified:    collections RELEASE-NOTES.html
               collections/src/test/org/apache/commons/collections/map
                        TestAll.java
  Added:       collections/src/java/org/apache/commons/collections/map
                        SingletonMap.java
               collections/src/test/org/apache/commons/collections/map
                        TestSingletonMap.java
               collections/data/test
                        SingletonMap.emptyCollection.version3.1.obj
                        SingletonMap.fullCollection.version3.1.obj
  Log:
  Add fully featured SingletonMap
  
  Revision  Changes    Path
  1.1                  jakarta-commons/collections/src/java/org/apache/commons/collections/map/SingletonMap.java
  
  Index: SingletonMap.java
  ===================================================================
  /*
   *  Copyright 2003-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.Serializable;
  import java.util.AbstractSet;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.NoSuchElementException;
  import java.util.Set;
  
  import org.apache.commons.collections.BoundedMap;
  import org.apache.commons.collections.KeyValue;
  import org.apache.commons.collections.MapIterator;
  import org.apache.commons.collections.OrderedMap;
  import org.apache.commons.collections.OrderedMapIterator;
  import org.apache.commons.collections.ResettableIterator;
  import org.apache.commons.collections.iterators.SingletonIterator;
  import org.apache.commons.collections.keyvalue.TiedMapEntry;
  
  /**
   * A <code>Map</code> implementation that holds a single item and is fixed size.
   * <p>
   * The single key/value pair is specified at creation.
   * The map is fixed size so any action that would change the size is disallowed.
   * However, the <code>put</code> or <code>setValue</code> methods can <i>change</i>
   * the value associated with the key.
   * <p>
   * If trying to remove or clear the map, an UnsupportedOperationException is thrown.
   * If trying to put a new mapping into the map, an  IllegalArgumentException is thrown.
   * The put method will only suceed if the key specified is the same as the 
   * singleton key.
   * <p>
   * The key and value can be obtained by:
   * <ul>
   * <li>normal Map methods and views
   * <li>the <code>MapIterator</code>, see {@link #mapIterator()}
   * <li>the <code>KeyValue</code> interface (just cast - no object creation)
   * </ul>
   * 
   * @since Commons Collections 3.1
   * @version $Revision: 1.1 $ $Date: 2004/04/09 14:46:35 $
   *
   * @author Stephen Colebourne
   */
  public class SingletonMap
          implements OrderedMap, BoundedMap, KeyValue, Serializable, Cloneable {
  
      /** Serialization version */
      private static final long serialVersionUID = -8931271118676803261L;
  
      /** Singleton key */
      private final Object key;
      /** Singleton value */
      private Object value;
  
      /**
       * Constructor that creates a map of <code>null</code> to <code>null</code>.
       */
      public SingletonMap() {
          super();
          this.key = null;
      }
  
      /**
       * Constructor specifying the key and value.
       *
       * @param key  the key to use
       * @param value  the value to use
       */
      public SingletonMap(Object key, Object value) {
          super();
          this.key = key;
          this.value = value;
      }
  
      /**
       * Constructor specifying the key and value as a <code>KeyValue</code>.
       *
       * @param keyValue  the key value pair to use
       */
      public SingletonMap(KeyValue keyValue) {
          super();
          this.key = keyValue.getKey();
          this.value = keyValue.getValue();
      }
  
      /**
       * Constructor specifying the key and value as a <code>MapEntry</code>.
       *
       * @param keyValue  the key value pair to use
       */
      public SingletonMap(Map.Entry entry) {
          super();
          this.key = entry.getKey();
          this.value = entry.getValue();
      }
  
      /**
       * Constructor copying elements from another map.
       *
       * @param map  the map to copy, must be size 1
       * @throws NullPointerException if the map is null
       * @throws IllegalArgumentException if the size is not 1
       */
      public SingletonMap(Map map) {
          super();
          if (map.size() != 1) {
              throw new IllegalArgumentException("The map size must be 1");
          }
          Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
          this.key = entry.getKey();
          this.value = entry.getValue();
      }
  
      // KeyValue
      //-----------------------------------------------------------------------
      /**
       * Gets the key.
       *
       * @return the key 
       */
      public Object getKey() {
          return key;
      }
  
      /**
       * Gets the value.
       *
       * @return the value
       */
      public Object getValue() {
          return value;
      }
  
      /**
       * Sets the value.
       *
       * @param value  the new value to set
       * @return the old value
       */
      public Object setValue(Object value) {
          Object old = this.value;
          this.value = value;
          return old;
      }
  
      // BoundedMap
      //-----------------------------------------------------------------------
      /**
       * Is the map currently full, always true.
       *
       * @return true always
       */
      public boolean isFull() {
          return true;
      }
  
      /**
       * Gets the maximum size of the map, always 1.
       * 
       * @return 1 always
       */
      public int maxSize() {
          return 1;
      }
  
      // 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 (isEqualKey(key)) {
              return value;
          }
          return null;
      }
  
      /**
       * Gets the size of the map, always 1.
       * 
       * @return the size of 1
       */
      public int size() {
          return 1;
      }
  
      /**
       * Checks whether the map is currently empty, which it never is.
       * 
       * @return false always
       */
      public boolean isEmpty() {
          return false;
      }
  
      //-----------------------------------------------------------------------
      /**
       * 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) {
          return (isEqualKey(key));
      }
  
      /**
       * 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) {
          return (isEqualValue(value));
      }
  
      //-----------------------------------------------------------------------
      /**
       * Puts a key-value mapping into this map where the key must match the existing key.
       * <p>
       * An IllegalArgumentException is thrown if the key does not match as the map
       * is fixed size.
       * 
       * @param key  the key to set, must be the key of the map
       * @param value  the value to set
       * @return the value previously mapped to this key, null if none
       * @throws IllegalArgumentException if the key does not match
       */
      public Object put(Object key, Object value) {
          if (isEqualKey(key)) {
              return setValue(value);
          }
          throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size singleton");
      }
  
      /**
       * Puts the values from the specified map into this map.
       * <p>
       * The map must be of size 0 or size 1.
       * If it is size 1, the key must match the key of this map otherwise an
       * IllegalArgumentException is thrown.
       * 
       * @param map  the map to add, must be size 0 or 1, and the key must match
       * @throws NullPointerException if the map is null
       * @throws IllegalArgumentException if the key does not match
       */
      public void putAll(Map map) {
          switch (map.size()) {
              case 0:
                  return;
              
              case 1:
                  Map.Entry entry = (Map.Entry) map.entrySet().iterator().next();
                  put(entry.getKey(), entry.getValue());
                  return;
              
              default:
                  throw new IllegalArgumentException("The map size must be 0 or 1");
          }
      }
  
      /**
       * Unsupported operation.
       * 
       * @param key  the mapping to remove
       * @return the value mapped to the removed key, null if key not in map
       * @throws UnsupportedOperationException always
       */
      public Object remove(Object key) {
          throw new UnsupportedOperationException();
      }
  
      /**
       * Unsupported operation.
       */
      public void clear() {
          throw new UnsupportedOperationException();
      }
  
      //-----------------------------------------------------------------------
      /**
       * Gets the entrySet view of the map.
       * Changes made via <code>setValue</code> affect this map.
       * To simply iterate through the entries, use {@link #mapIterator()}.
       * 
       * @return the entrySet view
       */
      public Set entrySet() {
          Map.Entry entry = new TiedMapEntry(this, getKey());
          return Collections.singleton(entry);
      }
      
      /**
       * Gets the unmodifiable 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() {
          return Collections.singleton(key);
      }
  
      /**
       * Gets the unmodifiable 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() {
          return new SingletonValues(this);
      }
  
      /**
       * Gets an iterator over the map.
       * Changes made to the iterator using <code>setValue</code> affect this map.
       * The <code>remove</code> method is unsupported.
       * <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 Map Entry object.
       * 
       * @return the map iterator
       */
      public MapIterator mapIterator() {
          return new SingletonMapIterator(this);
      }
  
      // OrderedMap
      //-----------------------------------------------------------------------
      /**
       * Obtains an <code>OrderedMapIterator</code> over the map.
       * <p>
       * A ordered map iterator is an efficient way of iterating over maps
       * in both directions.
       * 
       * @return an ordered map iterator
       */
      public OrderedMapIterator orderedMapIterator() {
          return new SingletonMapIterator(this);
      }
  
      /**
       * Gets the first (and only) key in the map.
       * 
       * @return the key
       */
      public Object firstKey() {
          return getKey();
      }
  
      /**
       * Gets the last (and only) key in the map.
       * 
       * @return the key
       */
      public Object lastKey() {
          return getKey();
      }
  
      /**
       * Gets the next key after the key specified, always null.
       * 
       * @param key  the next key
       * @return null always
       */
      public Object nextKey(Object key) {
          return null;
      }
  
      /**
       * Gets the previous key before the key specified, always null.
       * 
       * @param key  the next key
       * @return null always
       */
      public Object previousKey(Object key) {
          return null;
      }
  
      //-----------------------------------------------------------------------
      /**
       * Compares the specified key to the stored key.
       * 
       * @param key  the key to compare
       * @return true if equal
       */
      protected boolean isEqualKey(Object key) {
          return (key == null ? getKey() == null : key.equals(getKey()));
      }
  
      /**
       * Compares the specified value to the stored value.
       * 
       * @param value  the value to compare
       * @return true if equal
       */
      protected boolean isEqualValue(Object value) {
          return (value == null ? getValue() == null : value.equals(getValue()));
      }
  
      //-----------------------------------------------------------------------
      /**
       * SingletonMapIterator.
       */
      static class SingletonMapIterator implements OrderedMapIterator, ResettableIterator {
          private final SingletonMap parent;
          private boolean hasNext = true;
          private boolean canGetSet = false;
          
          SingletonMapIterator(SingletonMap parent) {
              super();
              this.parent = parent;
          }
  
          public boolean hasNext() {
              return hasNext;
          }
  
          public Object next() {
              if (hasNext == false) {
                  throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
              }
              hasNext = false;
              canGetSet = true;
              return parent.getKey();
          }
  
          public boolean hasPrevious() {
              return (hasNext == false);
          }
  
          public Object previous() {
              if (hasNext == true) {
                  throw new NoSuchElementException(AbstractHashedMap.NO_PREVIOUS_ENTRY);
              }
              hasNext = true;
              return parent.getKey();
          }
  
          public void remove() {
              throw new UnsupportedOperationException();
          }
  
          public Object getKey() {
              if (canGetSet == false) {
                  throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
              }
              return parent.getKey();
          }
  
          public Object getValue() {
              if (canGetSet == false) {
                  throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
              }
              return parent.getValue();
          }
  
          public Object setValue(Object value) {
              if (canGetSet == false) {
                  throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
              }
              return parent.setValue(value);
          }
          
          public void reset() {
              hasNext = true;
          }
          
          public String toString() {
              if (hasNext) {
                  return "Iterator[]";
              } else {
                  return "Iterator[" + getKey() + "=" + getValue() + "]";
              }
          }
      }
      
      /**
       * Values implementation for the SingletonMap.
       * This class is needed as values is a view that must update as the map updates.
       */
      static class SingletonValues extends AbstractSet implements Serializable {
          private static final long serialVersionUID = -3689524741863047872L;
          private final SingletonMap parent;
  
          SingletonValues(SingletonMap parent) {
              super();
              this.parent = parent;
          }
  
          public int size() {
              return 1;
          }
          public boolean isEmpty() {
              return false;
          }
          public boolean contains(Object object) {
              return parent.containsValue(object);
          }
          public void clear() {
              throw new UnsupportedOperationException();
          }
          public Iterator iterator() {
              return new SingletonIterator(parent.getValue(), false);
          }
      }
      
      //-----------------------------------------------------------------------
      /**
       * Clones the map without cloning the key or value.
       *
       * @return a shallow clone
       */
      public Object clone() {
          try {
              SingletonMap cloned = (SingletonMap) super.clone();
              return cloned;
          } catch (CloneNotSupportedException ex) {
              throw new InternalError();
          }
      }
  
      /**
       * 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 (obj instanceof Map == false) {
              return false;
          }
          Map other = (Map) obj;
          if (other.size() != 1) {
              return false;
          }
          Map.Entry entry = (Map.Entry) other.entrySet().iterator().next();
          return isEqualKey(entry.getKey()) && isEqualValue(entry.getValue());
      }
  
      /**
       * Gets the standard Map hashCode.
       * 
       * @return the hash code defined in the Map interface
       */
      public int hashCode() {
          return (getKey() == null ? 0 : getKey().hashCode()) ^
                 (getValue() == null ? 0 : getValue().hashCode()); 
      }
  
      /**
       * Gets the map as a String.
       * 
       * @return a string version of the map
       */
      public String toString() {
          return new StringBuffer(128)
              .append('{')
              .append((getKey() == this ? "(this Map)" : getKey()))
              .append('=')
              .append((getValue() == this ? "(this Map)" : getValue()))
              .append('}')
              .toString();
      }
  
  }
  
  
  
  1.32      +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.31
  retrieving revision 1.32
  diff -u -r1.31 -r1.32
  --- RELEASE-NOTES.html	9 Apr 2004 14:42:36 -0000	1.31
  +++ RELEASE-NOTES.html	9 Apr 2004 14:46:35 -0000	1.32
  @@ -25,6 +25,7 @@
   
   <center><h3>NEW CLASSES</h3></center>
   <ul>
  +<li>SingletonMap - fully featured singleton Map implementation</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>
   </ul>
  
  
  
  1.15      +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.14
  retrieving revision 1.15
  diff -u -r1.14 -r1.15
  --- TestAll.java	18 Feb 2004 01:20:37 -0000	1.14
  +++ TestAll.java	9 Apr 2004 14:46:35 -0000	1.15
  @@ -60,6 +60,7 @@
           suite.addTest(TestTransformedSortedMap.suite());
           suite.addTest(TestPredicatedMap.suite());
           suite.addTest(TestPredicatedSortedMap.suite());
  +        suite.addTest(TestSingletonMap.suite());
           suite.addTest(TestUnmodifiableMap.suite());
           suite.addTest(TestUnmodifiableOrderedMap.suite());
           suite.addTest(TestUnmodifiableSortedMap.suite());
  
  
  
  1.1                  jakarta-commons/collections/src/test/org/apache/commons/collections/map/TestSingletonMap.java
  
  Index: TestSingletonMap.java
  ===================================================================
  /*
   *  Copyright 2001-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.HashMap;
  import java.util.Map;
  
  import junit.framework.Test;
  import junit.textui.TestRunner;
  
  import org.apache.commons.collections.BoundedMap;
  import org.apache.commons.collections.BulkTest;
  import org.apache.commons.collections.KeyValue;
  
  /**
   * JUnit tests.
   * 
   * @version $Revision: 1.1 $ $Date: 2004/04/09 14:46:35 $
   * 
   * @author Stephen Colebourne
   */
  public class TestSingletonMap extends AbstractTestOrderedMap {
  
      private static final Integer ONE = new Integer(1);
      private static final Integer TWO = new Integer(2);
      private static final String TEN = "10";
      private static final String TWENTY = "20";
          
      public TestSingletonMap(String testName) {
          super(testName);
      }
  
      public static void main(String[] args) {
          TestRunner.run(suite());
      }
      
      public static Test suite() {
          return BulkTest.makeSuite(TestSingletonMap.class);
      }
  
      //-----------------------------------------------------------------------
      public Map makeEmptyMap() {
          // need an empty singleton map, but thats not possible
          // use a ridiculous fake instead to make the tests pass
          return UnmodifiableOrderedMap.decorate(ListOrderedMap.decorate(new HashMap()));
      }
      
      public String[] ignoredTests() {
          // the ridiculous map above still doesn't pass these tests
          // but its not relevant, so we ignore them
          return new String[] {
              "TestSingletonMap.bulkTestMapIterator.testEmptyMapIterator",
              "TestSingletonMap.bulkTestOrderedMapIterator.testEmptyMapIterator",
          };
      }
  
  
      public Map makeFullMap() {
          return new SingletonMap(ONE, TWO);
      }
  
      public boolean isPutAddSupported() {
          return false;
      }
  
      public boolean isRemoveSupported() {
          return false;
      }
  
      public Object[] getSampleKeys() {
          return new Object[] {ONE};
      }
  
      public Object[] getSampleValues() {
          return new Object[] {TWO};
      }
  
      public Object[] getNewSampleValues() {
          return new Object[] {TEN};
      }
  
      //-----------------------------------------------------------------------
      public void testClone() {
          SingletonMap map = new SingletonMap(ONE, TWO);
          assertEquals(1, map.size());
          SingletonMap cloned = (SingletonMap) map.clone();
          assertEquals(1, cloned.size());
          assertEquals(true, cloned.containsKey(ONE));
          assertEquals(true, cloned.containsValue(TWO));
      }
  
      public void testKeyValue() {
          SingletonMap map = new SingletonMap(ONE, TWO);
          assertEquals(1, map.size());
          assertEquals(ONE, map.getKey());
          assertEquals(TWO, map.getValue());
          assertTrue(map instanceof KeyValue);
      }
  
      public void testBoundedMap() {
          SingletonMap map = new SingletonMap(ONE, TWO);
          assertEquals(1, map.size());
          assertEquals(true, map.isFull());
          assertEquals(1, map.maxSize());
          assertTrue(map instanceof BoundedMap);
      }
  
      //-----------------------------------------------------------------------
  //    public BulkTest bulkTestMapIterator() {
  //        return new TestFlatMapIterator();
  //    }
  //    
  //    public class TestFlatMapIterator extends AbstractTestOrderedMapIterator {
  //        public TestFlatMapIterator() {
  //            super("TestFlatMapIterator");
  //        }
  //        
  //        public Object[] addSetValues() {
  //            return TestSingletonMap.this.getNewSampleValues();
  //        }
  //        
  //        public boolean supportsRemove() {
  //            return TestSingletonMap.this.isRemoveSupported();
  //        }
  //
  //        public boolean supportsSetValue() {
  //            return TestSingletonMap.this.isSetValueSupported();
  //        }
  //
  //        public MapIterator makeEmptyMapIterator() {
  //            resetEmpty();
  //            return ((Flat3Map) TestSingletonMap.this.map).mapIterator();
  //        }
  //
  //        public MapIterator makeFullMapIterator() {
  //            resetFull();
  //            return ((Flat3Map) TestSingletonMap.this.map).mapIterator();
  //        }
  //        
  //        public Map getMap() {
  //            // assumes makeFullMapIterator() called first
  //            return TestSingletonMap.this.map;
  //        }
  //        
  //        public Map getConfirmedMap() {
  //            // assumes makeFullMapIterator() called first
  //            return TestSingletonMap.this.confirmed;
  //        }
  //        
  //        public void verify() {
  //            super.verify();
  //            TestSingletonMap.this.verify();
  //        }
  //    }
      
      public String getCompatibilityVersion() {
          return "3.1";
      }
  
  //    public void testCreate() throws Exception {
  //        resetEmpty();
  //        writeExternalFormToDisk(
  //            (java.io.Serializable) map,
  //            "D:/dev/collections/data/test/SingletonMap.emptyCollection.version3.1.obj");
  //        resetFull();
  //        writeExternalFormToDisk(
  //            (java.io.Serializable) map,
  //            "D:/dev/collections/data/test/SingletonMap.fullCollection.version3.1.obj");
  //    }
  }
  
  
  
  1.1                  jakarta-commons/collections/data/test/SingletonMap.emptyCollection.version3.1.obj
  
  	<<Binary file>>
  
  
  1.1                  jakarta-commons/collections/data/test/SingletonMap.fullCollection.version3.1.obj
  
  	<<Binary file>>
  
  

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