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