home *** CD-ROM | disk | FTP | other *** search
/ ActiveX Programming Unleashed CD / AXU.iso / jgl_1_1 / jgl_1_1.exe / src / OrderedMap.java < prev    next >
Encoding:
Java Source  |  1996-09-10  |  15.1 KB  |  474 lines

  1. // Copyright(c) 1996 ObjectSpace, Inc.
  2. // Portions Copyright(c) 1995, 1996 Hewlett-Packard Company.
  3.  
  4. package jgl;
  5.  
  6. import java.util.Dictionary;
  7. import java.util.Enumeration;
  8.  
  9. /**
  10.  * An OrderedMap is an associative container that manages a set of ordered key/value pairs. 
  11.  * The pairs are ordered by key, using a comparator. By default, a HashComparator is used,
  12.  * which orders keys based on their hash value. By default, only one value may be associated with 
  13.  * a particular key. A OrderedMap's underlying data structure allows you to very efficiently 
  14.  * find all of the values associated with a particular key.
  15.  * <p>
  16.  * A OrderedMap is useful for implementing a collection of one-to-one or one-to-many mappings.
  17.  * <p>
  18.  * Strictly speaking, there is no reason why null is not a valid key. However, most 
  19.  * comparators (including the default HashComparator) will fail and throw an exception
  20.  * if you attempt to add a null key because they cast the key to a class and then
  21.  * activate one of its methods. It is perfectly possible to hand-craft a comparator
  22.  * that will accept null as a valid key.
  23.  * <p>
  24.  * There are many different approaches that could be used to implementing an associative 
  25.  * container. For example, most of the older libraries used a hashing scheme for 
  26.  * positioning and retrieving items. This implementation use a data structure called a 
  27.  * red-black tree. A red-black tree is a binary search tree that uses an extra field in 
  28.  * every node to store the node's color. Red-black trees constrain the way that nodes may 
  29.  * be colored in such a way that the tree remains reasonably balanced. This property is 
  30.  * important for ensuring a good overall performance - red-black trees guarantee that the 
  31.  * worst case performance for the most common dynamic set operations is O(log N). One 
  32.  * conseqence of using a binary tree for storage of data is that the items remain in a 
  33.  * sorted order. This allows JGL users to iterate through an associative container and 
  34.  * access its elements in a sequenced manner. Each node of the red-black tree holds a 
  35.  * Pair( key, value ). The comparator is used to order the Pairs based only on their keys. 
  36.  * <p>
  37.  * Insertion does not affect iterators or references.
  38.  * <p>
  39.  * Removal only invalidates the iterators and references to the removed elements. 
  40.  * <p>
  41.  * @see jgl.OrderedMultimap
  42.  * @see jgl.BinaryPredicate
  43.  * @see jgl.examples.OrderedMapExamples
  44.  * @version 1.1
  45.  * @author ObjectSpace, Inc.
  46.  */
  47.  
  48. public class OrderedMap extends Dictionary implements Container
  49.   {
  50.   Tree myTree;
  51.  
  52.   /**
  53.    * Construct myself to be an empty OrderedMap that orders its keys based on 
  54.    * their hash value and does not allow duplicates.
  55.    */
  56.   public OrderedMap()
  57.     {
  58.     myTree = new Tree( true, false, this );
  59.     }
  60.  
  61.   /**
  62.    * Construct myself to be an empty OrderedMap that orders its keys based on 
  63.    * their hash value and conditionally allows duplicates.
  64.    * @param allowDuplicates true if duplicates are allowed.
  65.    */
  66.   public OrderedMap( boolean allowDuplicates )
  67.     {
  68.     myTree = new Tree( true, allowDuplicates, this );
  69.     }
  70.  
  71.  
  72.   /**
  73.    * Construct myself to be an empty OrderedMap that orders its keys using 
  74.    * a specified binary predicate and does not allow duplicates.
  75.    * @param comparator The predicate for ordering keys.
  76.    */ 
  77.   public OrderedMap( BinaryPredicate comparator )
  78.     {
  79.     myTree = new Tree( true, false, comparator, this );
  80.     }
  81.  
  82.   /**
  83.    * Construct myself to be an empty OrderedMap that orders its keys using 
  84.    * a specified binary predicate and conditionally allows duplicates.
  85.    * @param comparator The predicate for ordering keys.
  86.    * @param allowDuplicates true if duplicates are allowed.
  87.    */ 
  88.   public OrderedMap( BinaryPredicate comparator, boolean allowDuplicates )
  89.     {
  90.     myTree = new Tree( true, allowDuplicates, comparator, this );
  91.     }
  92.  
  93.   /**
  94.    * Construct myself to be a shallow copy of an existing OrderedMap.
  95.    * @param map The OrderedMap to copy.
  96.    */
  97.   public OrderedMap( OrderedMap map )
  98.     {
  99.     myTree = new Tree( map.myTree );
  100.     }
  101.  
  102.   /**
  103.    * Return true if duplicates are allowed.
  104.    */
  105.   public boolean allowsDuplicates()
  106.     {
  107.     return myTree.myInsertAlways;
  108.     }
  109.  
  110.   /**
  111.    * Return a shallow copy of myself.
  112.    */
  113.   public synchronized Object clone()
  114.     {
  115.     return new OrderedMap( this );
  116.     }
  117.  
  118.   /**
  119.    * Become a shallow copy of an existing OrderedMap.
  120.    * @param map The OrderedMap that I shall become a shallow copy of.
  121.    */
  122.   public synchronized void copy( OrderedMap map )
  123.     {
  124.     myTree.copy( map.myTree );
  125.     }
  126.  
  127.   /**
  128.    * Return a string that describes me.
  129.    */
  130.   public synchronized String toString()
  131.     {
  132.     return Printing.toString( this, "OrderedMap" ); 
  133.     }
  134.  
  135.   /**
  136.    * Return an Enumeration of my values
  137.    */
  138.   public synchronized Enumeration elements()
  139.     {
  140.     return myTree.beginMap( OrderedMapIterator.VALUE );
  141.     }
  142.  
  143.   /**
  144.    * Return an iterator positioned at my first pair.
  145.    */
  146.   public synchronized ForwardIterator start()
  147.     {
  148.     return myTree.beginMap( OrderedMapIterator.PAIR );
  149.     }
  150.  
  151.   /**
  152.    * Return an iterator positioned immediately afer my last pair.
  153.    */
  154.   public synchronized ForwardIterator finish()
  155.     {
  156.     return myTree.endMap( OrderedMapIterator.PAIR );
  157.     }
  158.  
  159.   /**
  160.    * Return an iterator positioned at my first pair.
  161.    */
  162.   public synchronized OrderedMapIterator begin()
  163.     {
  164.     return myTree.beginMap( OrderedMapIterator.PAIR );
  165.     }
  166.  
  167.   /**
  168.    * Return an iterator positioned immediately after my last pair.
  169.    */
  170.   public synchronized OrderedMapIterator end()
  171.     {
  172.     return myTree.endMap( OrderedMapIterator.PAIR );
  173.     }
  174.  
  175.   /**
  176.    * Return true if I contain no entries.
  177.    */
  178.   public boolean isEmpty()
  179.     {
  180.     return myTree.size == 0;
  181.     }
  182.  
  183.   /** 
  184.    * Return the number of entries that I contain.
  185.    */
  186.   public int size()
  187.     {
  188.     return myTree.size;
  189.     }
  190.  
  191.   /**
  192.    * Return the maximum number of entries that I can contain.
  193.    */
  194.   public int maxSize()
  195.     {
  196.     return myTree.maxSize();
  197.     } 
  198.  
  199.   /**
  200.    * Return true if I'm equal to another object.
  201.    * @param object The object to compare myself against.
  202.    */
  203.   public boolean equals( Object object )
  204.     {
  205.     return object instanceof OrderedMap && equals( (OrderedMap) object );
  206.     }
  207.  
  208.   /**
  209.    * Return true if I contain the same items in the same order as 
  210.    * another OrderedMap. Use equals() to compare the individual elements.
  211.    * @param map The OrderedMap to compare myself against.
  212.    */
  213.   public synchronized boolean equals( OrderedMap map )
  214.     {
  215.     return Comparing.equal( this, map );
  216.     }
  217.  
  218.   /**
  219.    * Return my hash code for support of hashing containers
  220.    */
  221.   public int hashCode()
  222.     {                             
  223.     ForwardIterator start = myTree.beginMap( OrderedMapIterator.KEY );
  224.     ForwardIterator end = myTree.endMap( OrderedMapIterator.KEY );
  225.     return Hashing.orderedHash( start, end );
  226.     }
  227.   
  228.   /**
  229.    * Swap my contents with another OrderedMap.
  230.    * @param map The OrderedMap that I will swap my contents with.
  231.    */
  232.   public synchronized void swap( OrderedMap map )
  233.     {
  234.     Tree tmp = myTree;
  235.     myTree = map.myTree;
  236.     map.myTree = tmp;
  237.     }
  238.  
  239.   /**
  240.    * Remove all of my elements.
  241.    */   
  242.   public synchronized void clear()
  243.     {
  244.     myTree.clear();
  245.     }
  246.  
  247.   /**
  248.    * If I contain key/value pair(s) that matches a particular key, 
  249.    * remove them and return the value of the first key removed, otherwise return null.
  250.    * @param key The key of the pair(s) to be removed.
  251.    * @return The value that was removed or null if none.
  252.    */
  253.   public synchronized Object remove( Object key )
  254.     {
  255.     return myTree.remove( key );
  256.     }
  257.  
  258.   /**
  259.    * Remove the element at a particular position and return its value.
  260.    * @param pos An Enumeration positioned at the element to remove.
  261.    * @return The value that was removed or null if none.
  262.    * @exception IllegalArgumentException is the Enumeration isn't an 
  263.    * OrderedMapIterator for this OrderedMap object.
  264.    */
  265.   public synchronized Object remove( Enumeration pos )
  266.     {
  267.     if( ! (pos instanceof OrderedMapIterator) )
  268.       throw new IllegalArgumentException( "Enumeration not an OrderedMapIterator" );
  269.  
  270.     if( ((OrderedMapIterator)pos).myOrderedMap != this )
  271.       throw new IllegalArgumentException( "Enumeration not for this OrderedMap" );
  272.  
  273.     TreeNode node = myTree.remove( ((OrderedMapIterator)pos).myNode );
  274.     return ( node == null ? null : node.object );
  275.     }
  276.  
  277.   /**
  278.    * Remove the elements within a specified range, returning the first value
  279.    * of the key in that range.
  280.    * @param first An iterator positioned at the first element to remove.
  281.    * @param last An iterator positioned immediately after the last element to remove.
  282.    * @exception IllegalArgumentException is the Enumeration isn't an 
  283.    * OrderedMapIterator for this OrderedMap object.
  284.    */
  285.   public synchronized Object remove( Enumeration first, Enumeration last )
  286.     {
  287.     if( ( ! (first instanceof OrderedMapIterator) ) ||
  288.         ( ! (last instanceof OrderedMapIterator) ) )
  289.       throw new IllegalArgumentException( "Enumeration not an OrderedMapIterator" );
  290.  
  291.     if( ( ((OrderedMapIterator)first).myOrderedMap != this ) ||
  292.         ( ((OrderedMapIterator)last).myOrderedMap != this ) )
  293.       throw new IllegalArgumentException( "Enumeration not for this OrderedMap" );
  294.  
  295.     return myTree.remove( ((OrderedMapIterator)first).myNode, 
  296.                           ((OrderedMapIterator)last).myNode );
  297.     }
  298.  
  299.   /**
  300.    * Find a key/value pair based on its key and return its position. 
  301.    * If the pair is not found, return end().
  302.    * @param object The object to locate.
  303.    */
  304.   public synchronized OrderedMapIterator find( Object key )
  305.     {
  306.     return new OrderedMapIterator( myTree, myTree.find( key ), this, OrderedMapIterator.PAIR );
  307.     }
  308.  
  309.   /**
  310.    * Return the number of key/value pairs that match a particular key.
  311.    * @param key The key to match against.
  312.    */
  313.   public synchronized int count( Object key )
  314.     {
  315.     return myTree.count( key );
  316.     }
  317.  
  318.   /**
  319.    * Return the number of values that match a given object.
  320.    * @param value The value to match against.
  321.    */
  322.   public synchronized int countValues( Object value )
  323.     {
  324.     return Counting.count( myTree.beginMap( OrderedMapIterator.VALUE ),
  325.                            myTree.endMap( OrderedMapIterator.VALUE ),
  326.                            value );
  327.     }
  328.  
  329.   /**
  330.    * Return an iterator positioned at the first location that a 
  331.    * pair with a specified key could be inserted without violating the ordering 
  332.    * criteria. If no such location is found, return an iterator positioned at end().
  333.    * @param key The key.
  334.    */
  335.   public synchronized OrderedMapIterator lowerBound( Object key )
  336.     {
  337.     return new OrderedMapIterator( myTree, myTree.lowerBound( key ), this, OrderedMapIterator.PAIR );
  338.     }
  339.  
  340.   /**
  341.    * Return an iterator positioned at the last location that 
  342.    * a pair with a specified key could be inserted without violating the ordering 
  343.    * criteria. If no such location is found, return an iterator positioned at end().
  344.    * @param key The key.
  345.    */
  346.   public synchronized OrderedMapIterator upperBound( Object key )
  347.     {
  348.     return new OrderedMapIterator( myTree, myTree.upperBound( key ), this, OrderedMapIterator.PAIR );
  349.     }
  350.  
  351.   /**
  352.    * Return my comparator.
  353.    */
  354.   public BinaryPredicate getComparator()
  355.     {
  356.     return myTree.myComparator;
  357.     }
  358.  
  359.   /**
  360.    * Return the value associated with key, or null if the key does not exist.
  361.    * @param key The key to search against.
  362.    */
  363.   public synchronized Object get( Object key )
  364.     {
  365.     return myTree.get( key );
  366.     }
  367.  
  368.   /**
  369.    * If the key doesn't exist, associate the value with the key and return null, 
  370.    * otherwise replace the first value associated with the key and return the old value. 
  371.    * @param key The key.
  372.    * @param value The value.
  373.    * @exception java.lang.NullPointerException If the key or value is null.
  374.    */
  375.   public synchronized Object put( Object key, Object value )
  376.     {
  377.     if( key == null || value == null )
  378.       throw new NullPointerException();
  379.  
  380.     InsertResult result = myTree.put( new Pair( key, value ) );
  381.  
  382.     if( result.ok )
  383.       {
  384.       return null;
  385.       }
  386.     else
  387.       {
  388.       Pair pair = (Pair) result.node.object;
  389.       Object previous = pair.second;
  390.       pair.second = value;
  391.       return previous;
  392.       }
  393.     }
  394.  
  395.   /**
  396.    * Assume that the specified object is a Pair whose first field is a key and whose
  397.    * second field is a value. If the key doesn't exist or duplicates are allowed, 
  398.    * associate the value with the key and return null, otherwise don't modify the map and 
  399.    * return the current value associated with the key. 
  400.    * @param object The pair to add.
  401.    * @exception java.lang.IllegalArgumentException If the object is not a Pair
  402.    * @exception java.lang.NullPointerException If the object is null or if the first 
  403.    * or second items in the pair are null.
  404.    */
  405.   public Object add( Object object )
  406.     {
  407.     if( object == null )
  408.       throw new NullPointerException();
  409.  
  410.     if ( !(object instanceof Pair) ) 
  411.       throw new IllegalArgumentException( "object is not Pair" );
  412.  
  413.     if( ((Pair)object).first == null || ((Pair)object).second == null )
  414.       throw new NullPointerException();
  415.  
  416.     Pair pair = (Pair) object;
  417.     return add( pair.first, pair.second );
  418.     }
  419.  
  420.   /**
  421.    * If the key doesn't exist or duplicates are allowed, associate the value with the 
  422.    * key and return null, otherwise don't modify the map and return the current value 
  423.    * associated with the key. 
  424.    * @param key The key.
  425.    * @param value The value.
  426.    * @exception java.lang.NullPointerException If the key or value is null.
  427.    */
  428.   public Object add( Object key, Object value )
  429.     {
  430.     if( key == null || value == null )
  431.       throw new NullPointerException();
  432.    
  433.     InsertResult result = myTree.insert( new Pair( key, value ) );
  434.     return result.ok ? null : ((Pair) result.node.object).second;
  435.     }
  436.  
  437.   /**
  438.    * Return an Enumeration of all my keys.
  439.    */
  440.   public synchronized Enumeration keys()
  441.     {
  442.     return myTree.beginMap( OrderedMapIterator.KEY );
  443.     }
  444.  
  445.   /**
  446.    * Return an Enumeration of all my keys that are associated with a particular value.
  447.    * @param value The value to match.
  448.    */
  449.   public synchronized Enumeration keys( Object value )
  450.     {
  451.     return myTree.keys( value ).elements();
  452.     }
  453.  
  454.   /**
  455.    * Return an Enumeration of all my values that are associated with a particular key.
  456.    * @param key The key to match.
  457.    */
  458.   public synchronized Enumeration values( Object key )
  459.     {
  460.     return myTree.values( key ).elements();
  461.     }
  462.  
  463.   /**
  464.    * Return a pair of iterators whose first element is equal to
  465.    * lowerBound() and whose second element is equal to upperBound().
  466.    * @param object The object whose bounds are to be found.
  467.    */
  468.   public synchronized Range equalRange( Object object )
  469.     {
  470.     return new Range( lowerBound( object ), upperBound( object ) );
  471.     }
  472.   }
  473.  
  474.