home *** CD-ROM | disk | FTP | other *** search
/ ActiveX Programming Unleashed CD / AXU.iso / jgl_1_1 / src / dlist.java < prev    next >
Encoding:
Java Source  |  1996-09-10  |  29.4 KB  |  973 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 DList is a doubly-linked list, a sequential container that is optimized for insertion 
  10.  * and erasure at arbitrary points in its structure.
  11.  * <p>
  12.  * A DList is useful when the order of items and fast arbitrary insertion/erasure are 
  13.  * important. DLists are not as efficient as Deques when insertion and erasure only take 
  14.  * place at the extremities.
  15.  * <p>
  16.  * A DList is implemented as a doubly-linked list in which every node in the list 
  17.  * has a pointer to the previous node and a pointer to the next node.
  18.  * <p>
  19.  * Insertion does not affect iterators or references. Insertion of a single element into 
  20.  * a DList takes constant time. Insertion of multiple elements into a DList is linear in 
  21.  * the number of elements inserted.
  22.  * <p>
  23.  * Removal only invalidates the iterators and references to the removed elements. Removing 
  24.  * a single element is a constant time operation. Removing a range in a DList is linear 
  25.  * time in the size of the range.
  26.  * <p>
  27.  * @see jgl.Sequence
  28.  * @see jgl.examples.DListExamples
  29.  * @version 1.1
  30.  * @author ObjectSpace, Inc.
  31.  */
  32.  
  33. public class DList implements Sequence
  34.   {
  35.   DListNode myNode = new DListNode();
  36.   int myLength;
  37.  
  38.   /**
  39.    * Construct myself to be an empty DList.
  40.    */
  41.   public DList()
  42.     {
  43.     myNode.next = myNode;
  44.     myNode.previous = myNode;
  45.     }
  46.  
  47.   /**
  48.    * Construct myself to contain a specified number of null elements.
  49.    * @param size The number of elements to contain.
  50.    * @exception java.lang.IllegalArgumentException If the specified size is negative.
  51.    */
  52.   public DList( int size )
  53.     {
  54.     this();
  55.     insert( myNode.next, size, null );
  56.     }
  57.  
  58.   /**
  59.    * Construct myself to contain a specified number of elements set to
  60.    * a particular object.
  61.    * @param size The number of elements to contain.
  62.    * @param object The initial value of each element.
  63.    * @exception java.lang.IllegalArgumentException If the specified size is negative.
  64.    */
  65.   public DList( int size, Object object )
  66.     {
  67.     this();
  68.     insert( myNode.next, size, object );
  69.     }
  70.  
  71.   /**
  72.    * Construct myself to be a shallow copy of an existing DList.
  73.    * @param DList The DList to copy.
  74.    */
  75.   public DList( DList list )
  76.     {
  77.     this();
  78.     insert( myNode.next, list.myNode.next, list.myNode );
  79.     }
  80.  
  81.   /**
  82.    * Return a shallow copy of myself.
  83.    */
  84.   public synchronized Object clone()
  85.     {
  86.     return new DList( this );
  87.     }
  88.  
  89.   /**
  90.    * Return true if I'm equal to another object.
  91.    * @param object The object to compare myself against.
  92.    */
  93.   public boolean equals( Object object )
  94.     {
  95.     return object instanceof DList && equals( (DList) object );
  96.     }
  97.  
  98.   /**
  99.    * Return true if I contain the same items in the same order as 
  100.    * another DList. Use equals() to compare the individual elements.
  101.    * @param list The DList to compare myself against.
  102.    */
  103.   public synchronized boolean equals( DList list )
  104.     {
  105.     return Comparing.equal( this, list );
  106.     }
  107.  
  108.   /**
  109.    * Return my hash code for support of hashing containers
  110.    */
  111.   public int hashCode()
  112.     {
  113.     return Hashing.orderedHash( this );
  114.     }
  115.   
  116.  
  117.   /**
  118.    * Return a string that describes me.
  119.    */
  120.   public synchronized String toString()
  121.     {
  122.     return Printing.toString( this, "DList" );
  123.     }
  124.  
  125.   /**
  126.    * Become a shallow copy of an existing DList.
  127.    * @param list The DList that I shall become a shallow copy of.
  128.    */
  129.   public synchronized void copy( DList list )
  130.     {
  131.     if( this == list )
  132.       return;
  133.  
  134.     DListNode first1 = myNode.next;
  135.     DListNode last1 = myNode;
  136.     DListNode first2 = list.myNode.next;
  137.     DListNode last2 = list.myNode;
  138.  
  139.     while( first1 != last1 && first2 != last2 )
  140.       {
  141.       first1.object = first2.object;
  142.       first1 = first1.next;
  143.       first2 = first2.next;
  144.       }
  145.  
  146.     if( first2 == last2 ) 
  147.       remove( first1, last1 );
  148.     else
  149.       insert( last1, first2, last2 );
  150.     }
  151.  
  152.   /**
  153.    * Return true if I contain no entries.
  154.    */
  155.   public boolean isEmpty()
  156.     {
  157.     return myLength == 0;
  158.     }
  159.  
  160.   /** 
  161.    * Return the number of entries that I contain.
  162.    */
  163.   public int size()
  164.     {
  165.     return myLength;
  166.     }
  167.  
  168.   /**
  169.    * Return the maximum number of entries that I can contain.
  170.    */
  171.   public int maxSize()
  172.     {
  173.     return Allocator.maxSize();
  174.     }
  175.  
  176.   /**
  177.    * Return the element at the specified index.
  178.    * @param index The index.
  179.    * @exception java.lang.IndexOutOfBoundsException If the index is not valid.
  180.    */
  181.   public synchronized Object at( int index )
  182.     {
  183.     if( index < 0 || index >= myLength )
  184.       throw new IndexOutOfBoundsException( "Attempt to access index " + index + " when valid range is 0.." + (myLength - 1) );
  185.  
  186.     DListNode node = myNode.next;
  187.  
  188.     while( index-- > 0 )
  189.       node = node.next;
  190.  
  191.     return node.object;
  192.     }
  193.  
  194.   /**
  195.    * Set the element at the specified index to a particular object.
  196.    * @param index The index.
  197.    * @param object The object.
  198.    * @exception java.lang.IndexOutOfBoundsException If the index is not valid.
  199.    */
  200.   public synchronized void put( int index, Object object )
  201.     {
  202.     if( index < 0 || index >= myLength )
  203.       throw new IndexOutOfBoundsException( "Attempt to access index " + index + " when valid range is 0.." + (myLength - 1) );
  204.  
  205.     DListNode node = myNode.next;
  206.  
  207.     while( index-- > 0 )
  208.       node = node.next;
  209.  
  210.     node.object = object;
  211.     }
  212.  
  213.   /**
  214.    * Insert an object at a particular position and return an iterator
  215.    * positioned at the new element.
  216.    * @param pos An iterator positioned at the element that the object will be inserted immediately before.
  217.    * @param object The object to insert.
  218.    */
  219.   public synchronized DListIterator insert( DListIterator pos, Object object )
  220.     {
  221.     return new DListIterator( this, insert( pos.myNode, object ) );
  222.     }
  223.  
  224.   /**
  225.    * Insert an object at a particular index.
  226.    * @param index The index of the element that the object will be inserted immediately before.
  227.    * @param object The object to insert.
  228.    * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
  229.    */
  230.   public synchronized void insert( int index, Object object )
  231.     {
  232.     if( index > myLength )
  233.       throw new IndexOutOfBoundsException( "Attempt to insert at index " + index + " when valid range is 0.." + myLength );
  234.  
  235.     insert( nodeAt( index ), object );
  236.     }
  237.  
  238.   /**
  239.    * Insert multiple objects at a particular position.
  240.    * @param pos An iterator positioned at the element that the objects will be inserted immediately before.
  241.    * @param n The number of objects to insert.
  242.    * @param object The object to insert.
  243.    */
  244.   public synchronized void insert( DListIterator pos, int n, Object object )
  245.     {
  246.     insert( pos.myNode, n, object );
  247.     }
  248.  
  249.   /**
  250.    * Insert multiple objects at a particular index.
  251.    * @param index The index of the element that the objects will be inserted immediately before.
  252.    * @param object The object to insert.
  253.    * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
  254.    */
  255.   public synchronized void insert( int index, int n, Object object )
  256.     {
  257.     if( index > myLength )
  258.       throw new IndexOutOfBoundsException( "Attempt to insert at index " + index + " when valid range is 0.." + myLength );
  259.  
  260.     insert( nodeAt( index ), n, object );
  261.     }
  262.  
  263.   /**
  264.    * Insert a sequence of objects at a particular location.
  265.    * @param pos The location of the element that the objects will be inserted immediately before.
  266.    * @param first An iterator positioned at the first element to insert.
  267.    * @param last An iterator positioned immediately after the last element to insert.
  268.    */
  269.   public synchronized void insert( DListIterator pos, InputIterator first, InputIterator last )
  270.     {
  271.     InputIterator firstx = (InputIterator) first.clone();
  272.  
  273.     while( !firstx.equals( last ) )
  274.       insert( pos.myNode, firstx.nextElement() );
  275.     }
  276.  
  277.   /**
  278.    * Return my last item.
  279.    * @exception jgl.InvalidOperationException If the DList is empty.
  280.    */
  281.   public synchronized Object back()
  282.     {
  283.     if( myLength == 0 )
  284.       throw new InvalidOperationException( "DList is empty" );
  285.  
  286.     return myNode.previous.object;
  287.     }
  288.  
  289.   /**
  290.    * Return my first item.
  291.    * @exception jgl.InvalidOperationException If the DList is empty.
  292.    */
  293.   public synchronized Object front()
  294.     {
  295.     if( myLength == 0 )
  296.       throw new InvalidOperationException( "DList is empty" );
  297.  
  298.     return myNode.next.object;
  299.     }
  300.  
  301.   /**
  302.    * Remove all of my elements.
  303.    */   
  304.   public synchronized void clear()
  305.     {
  306.     myNode.next = myNode;
  307.     myNode.previous = myNode;
  308.     myLength = 0;
  309.     }
  310.  
  311.   /**
  312.    * Remove the elements within a range of indices.
  313.    * @param first The index of the first element to remove.
  314.    * @param last The index of the last element to remove.
  315.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  316.    */
  317.   public synchronized void remove( int first, int last )
  318.     {
  319.     if( last < first )
  320.       return;
  321.  
  322.     checkRange( first, last );
  323.     remove( nodeAt( first ), nodeAt( last + 1 ) );
  324.     }
  325.  
  326.   /**
  327.    * Remove the elements in the range [ first..last ).
  328.    * @param first An Enumeration positioned at the first object to remove.
  329.    * @param last An Enumeration positioned immediately after the last object to remove.
  330.    * @exception IllegalArgumentException is the Enumeration isn't a 
  331.    * DListIterator for this DList object.
  332.    */
  333.   public synchronized void remove( Enumeration first, Enumeration last )
  334.     {
  335.     if( ( ! (first instanceof DListIterator) ) ||
  336.         ( ! (last instanceof DListIterator) ) )
  337.       throw new IllegalArgumentException( "Enumeration not a DListIterator" );
  338.  
  339.     if( ( ((DListIterator)first).myDList != this ) ||
  340.         ( ((DListIterator)last).myDList != this ) )
  341.       throw new IllegalArgumentException( "Enumeration not for this DList" );
  342.  
  343.     DListIterator begin = (DListIterator)first;
  344.     DListIterator end = (DListIterator)last;
  345.     remove( begin.myNode, end.myNode );
  346.     }
  347.  
  348.   /**
  349.    * Remove the element at a particular index.
  350.    * @param index The index of the element to remove.
  351.    * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
  352.    */
  353.   public synchronized void remove( int index )
  354.     {
  355.     if( index < 0 || index >= myLength )
  356.       throw new IndexOutOfBoundsException( "Attempt to access index " + index + " when valid range is 0.." + (myLength - 1) );
  357.  
  358.     remove( nodeAt( index ) );
  359.     }
  360.  
  361.   /**
  362.    * Remove the element at a particular position.
  363.    * @param pos An Enumeration positioned at the element to remove.
  364.    * @exception IllegalArgumentException is the Enumeration isn't a 
  365.    * DListIterator for this DList object.
  366.    */
  367.   public synchronized void remove( Enumeration pos )
  368.     {
  369.       if( ! (pos instanceof DListIterator) )
  370.       throw new IllegalArgumentException( "Enumeration not a DListIterator" );
  371.  
  372.     if( ((DListIterator)pos).myDList != this )
  373.       throw new IllegalArgumentException( "Enumeration not for this DList" );
  374.  
  375.     remove( ((DListIterator)pos).myNode );
  376.     }
  377.  
  378.   /** 
  379.    * Remove all of the elements in a specified DList and insert them at a particular
  380.    * position.
  381.    * @param index The index of the element that the items will be inserted immediately before.
  382.    * @param list The DList to splice the elements from.
  383.    * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
  384.    */
  385.   public synchronized void splice( int index, DList list )
  386.     {
  387.     if( index > myLength )
  388.       throw new IndexOutOfBoundsException( "Attempt to insert at index " + index + " when valid range is 0.." + myLength );
  389.  
  390.     splice( nodeAt( index ), list );
  391.     }
  392.  
  393.   /** 
  394.    * Remove all of the elements in a specified DList and insert them at a particular
  395.    * position.
  396.    * @param pos The position to insert the elements.
  397.    * @param list The DList to splice the elements from.
  398.    */
  399.   public synchronized void splice( DListIterator pos, DList list )
  400.     {
  401.     splice( pos.myNode, list );
  402.     }
  403.  
  404.   /**
  405.    * Remove a specified element from a DList and insert it at a particular position.
  406.    * @param to The position to insert the element.
  407.    * @param list The DList to splice the element from.
  408.    * @param from The position of the element to remove.
  409.    */
  410.   public synchronized void splice( DListIterator to, DList list, DListIterator from )
  411.     {
  412.     splice( to.myNode, list, from.myNode );
  413.     }
  414.  
  415.   /**
  416.    * Remove a specified element from a DList and insert it at a particular position.
  417.    * @param to The index of the element that the item will be inserted immediately before.
  418.    * @param list The DList to splice the element from.
  419.    * @param from The index of the element to remove.
  420.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  421.    */
  422.   public synchronized void splice( int to, DList list, int from )
  423.     {
  424.     if( to > myLength )
  425.       throw new IndexOutOfBoundsException( "Attempt to insert at index " + to + " when valid range is 0.." + myLength );
  426.  
  427.     if( from < 0 || from >= list.myLength )
  428.       throw new IndexOutOfBoundsException( "Attempt to access index " + from + " when valid range is 0.." + (list.myLength - 1) );
  429.  
  430.     splice( nodeAt( to ), list, list.nodeAt( from ) );
  431.     }
  432.  
  433.   /**
  434.    * Remove a range of elements from a DList and insert them at a particular position.
  435.    * @param pos The position to insert the elements.
  436.    * @param list The list to splice the elements from.
  437.    * @param first An iterator positioned at the first element to remove.
  438.    * @param last An iterator positioned immediately after the last element to remove.
  439.    */
  440.   public synchronized void splice( DListIterator pos, DList list, DListIterator first, DListIterator last )
  441.     {
  442.     if( first.myNode != last.myNode )
  443.       {
  444.       if( list != this )
  445.         {
  446.         int n = first.distance( last );
  447.         list.myLength -= n;
  448.         myLength += n;
  449.         }
  450.       else
  451.         {
  452.         DListNode tmp = first.myNode.next;
  453.         while (tmp != last.myNode)
  454.           {
  455.           if (pos.myNode == tmp)
  456.             throw new InvalidOperationException("Tried to splice into an overlapping area.");
  457.           tmp = tmp.next;
  458.           }
  459.         }
  460.       transfer( pos.myNode, first.myNode, last.myNode );
  461.       }
  462.     }
  463.  
  464.   /**
  465.    * Remove a range of elements from a DList and insert them at a particular position.
  466.    * @param index The index of the item that the elements should be inserted immediately before.
  467.    * @param list The DList to splice the elements from.
  468.    * @param first The index of the first element to remove.
  469.    * @param last The index of the last element to remove.
  470.    * @exception java.lang.IndexOutOfBoundsException If any index is invalid.
  471.    */
  472.   public synchronized void splice( int index, DList list, int first, int last )
  473.     {
  474.     if( index > myLength )
  475.       throw new IndexOutOfBoundsException( "Attempt to insert at index " + index + " when valid range is 0.." + myLength );
  476.  
  477.     if( first < 0 || first >= list.myLength )
  478.       throw new IndexOutOfBoundsException( "Attempt to access index " + first + " when valid range is 0.." + (list.myLength - 1) );
  479.  
  480.     if( last < 0 || last >= list.myLength )
  481.       throw new IndexOutOfBoundsException( "Attempt to access index " + last + " when valid range is 0.." + (list.myLength - 1) );
  482.  
  483.     splice( iteratorAt( index ), list, list.iteratorAt( first ), list.iteratorAt( last + 1 ) );
  484.     }  
  485.  
  486.   /**
  487.    * Replace all repeating sequences of a single element by a single occurrence of
  488.    * that element.
  489.    */
  490.   public synchronized void unique()
  491.     {
  492.     if( myLength == 0 )
  493.       return;
  494.  
  495.     DListNode first = myNode.next;
  496.     DListNode last = myNode;
  497.  
  498.     for( DListNode next = first.next; next != last; next = first.next )
  499.       if( first.object.equals( next.object ) )
  500.         {
  501.         next.previous.next = next.next;
  502.         next.next.previous = next.previous;
  503.         --myLength;
  504.         }
  505.       else
  506.         {
  507.         first = next;
  508.         }
  509.     }
  510.  
  511.   /**
  512.    * Remove and return my last element.
  513.    * @exception jgl.InvalidOperationException If the DList is empty.
  514.    */
  515.   public synchronized Object popBack()
  516.     {
  517.     if( myLength == 0 )
  518.       throw new InvalidOperationException( "DList is empty" );
  519.  
  520.     DListNode node = myNode.previous;
  521.     node.previous.next = node.next;
  522.     node.next.previous = node.previous;
  523.     --myLength;
  524.     return node.object;
  525.     }
  526.  
  527.   /**
  528.    * Insert an object in front of my first element.
  529.    * @param object The object to insert.
  530.    */
  531.   public synchronized void pushFront( Object object )
  532.     {
  533.     insert( myNode.next, object );
  534.     }
  535.  
  536.   /**
  537.    * Remove and return my first element.
  538.    * @exception jgl.InvalidOperationException If the DList is empty.
  539.    */
  540.   public synchronized Object popFront()
  541.     {
  542.     if( myLength == 0 )
  543.       throw new InvalidOperationException( "DList is empty" );
  544.  
  545.     DListNode node = myNode.next;
  546.     node.previous.next = node.next;
  547.     node.next.previous = node.previous;
  548.     --myLength;
  549.     return node.object;
  550.     }
  551.  
  552.   /**
  553.    * Add an object after my last element and return null.
  554.    * This function is a synonym for pushBack().
  555.    * @param object The object to add.
  556.    */
  557.   public synchronized Object add( Object object )
  558.     {
  559.     insert( myNode, object );
  560.     return null;
  561.     }
  562.  
  563.   /**
  564.    * Add an object after my last element.
  565.    * @param The object to add.
  566.    */
  567.   public synchronized void pushBack( Object object )
  568.     {
  569.     insert( myNode, object );
  570.     }
  571.  
  572.   /**
  573.    * Swap my contents with another DList.
  574.    * @param list The DList that I will swap my contents with.
  575.    */
  576.   public synchronized void swap( DList list )
  577.     {
  578.     DListNode tmpNode = myNode;
  579.     int tmpLength = myLength;
  580.     myNode = list.myNode;
  581.  
  582.     myLength = list.myLength;
  583.     list.myNode = tmpNode;
  584.     list.myLength = tmpLength;
  585.     }
  586.  
  587.   /**
  588.    * Remove all elements that match a particular object and return the numbers of
  589.    * objects that were removed.
  590.    * @param object The object to remove.
  591.    */
  592.   public int remove( Object object )
  593.     {
  594.     return remove( begin(), end(), object );
  595.     }
  596.  
  597.   /**
  598.    * Remove all elements within a specified range that match a particular object
  599.    * and return the number of objects that were removed.
  600.    * @param first An Enumeration positioned at the first object to remove.
  601.    * @param last An Enumeration positioned immediately after the last object to remove.
  602.    * @param object The object to remove.
  603.    * @exception IllegalArgumentException is the Enumeration isn't a 
  604.    * DListIterator for this DList object.
  605.    */
  606.   public synchronized int remove( Enumeration first, Enumeration last, Object object )
  607.     {
  608.     if( ( ! (first instanceof DListIterator) ) ||
  609.         ( ! (last instanceof DListIterator) ) )
  610.       throw new IllegalArgumentException( "Enumeration not a DListIterator" );
  611.  
  612.     if( ( ((DListIterator)first).myDList != this ) ||
  613.         ( ((DListIterator)last).myDList != this ) )
  614.       throw new IllegalArgumentException( "Enumeration not for this DList" );
  615.  
  616.     DListIterator begin = (DListIterator)first;
  617.     DListIterator end = (DListIterator)last;
  618.     return remove( begin.myNode, end.myNode, object );
  619.     }
  620.  
  621.   /**
  622.    * Remove all elements within a specified range that match a particular object
  623.    * and return the number of objects that were removed.
  624.    * @param first The index of the first object to remove.
  625.    * @param last The index of the last object to remove.
  626.    * @param object The object to remove.
  627.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  628.    */
  629.   public synchronized int remove( int first, int last, Object object )
  630.     {
  631.     if( last < first )
  632.       return 0;
  633.  
  634.     checkRange( first, last );
  635.     return remove( nodeAt( first ), nodeAt( last + 1 ), object );
  636.     }
  637.  
  638.   /**
  639.    * Return an iterator positioned at my first item.
  640.    */
  641.   public synchronized DListIterator begin()
  642.     {
  643.     return new DListIterator( this, myNode.next );
  644.     }
  645.  
  646.   /**
  647.    * Return an iterator positioned at my first item.
  648.    */
  649.   public synchronized ForwardIterator start()
  650.     {
  651.     return new DListIterator( this, myNode.next );
  652.     }
  653.  
  654.   /**
  655.    * Return an iterator positioned immediately afer my last item.
  656.    */
  657.   public synchronized ForwardIterator finish()
  658.     {
  659.     return new DListIterator( this, myNode );
  660.     }
  661.  
  662.   /**
  663.    * Return an iterator positioned immediately after my last item.
  664.    */
  665.   public synchronized DListIterator end()
  666.     {
  667.     return new DListIterator( this, myNode );
  668.     }
  669.  
  670.   /**
  671.    * Return an Enumeration of my components.
  672.    */
  673.   public synchronized Enumeration elements()
  674.     {
  675.     return new DListIterator( this, myNode.next );
  676.     }
  677.  
  678.   /**
  679.    * Replace all elements that match a particular object with a new value and return
  680.    * the number of objects that were replaced.
  681.    * @param oldValue The object to be replaced.
  682.    * @param newValue The value to substitute.
  683.    */
  684.   public synchronized int replace( Object oldValue, Object newValue )
  685.     {
  686.     return Replacing.replace( this, oldValue, newValue );
  687.     }
  688.  
  689.   /**
  690.    * Replace all elements within a specified range that match a particular object
  691.    * with a new value and return the number of objects that were replaced.
  692.    * @param first An iterator positioned at the first object to be considered.
  693.    * @param last An iterator positioned immediately after the last object to be considered.
  694.    * @param oldValue The object to be replaced.
  695.    * @param newValue The value to substitute.
  696.    */
  697.   public synchronized int replace( DListIterator first, DListIterator last, Object oldValue, Object newValue )
  698.     {
  699.     return Replacing.replace( first, last, oldValue, newValue );
  700.     }
  701.  
  702.   /**
  703.    * Replace all elements within a specified range that match a particular object
  704.    * with a new value and return the number of objects that were replaced.
  705.    * @param first The index of the first object to be considered.
  706.    * @param last The index of the last object to be considered.
  707.    * @param oldValue The object to be replaced.
  708.    * @param newValue The value to substitute.
  709.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  710.    */
  711.   public synchronized int replace( int first, int last, Object oldValue, Object newValue )
  712.     {
  713.     if( last < first )
  714.       return 0;
  715.  
  716.     checkRange( first, last );
  717.     return Replacing.replace( iteratorAt( first ), iteratorAt( last + 1 ), oldValue, newValue );
  718.     }
  719.  
  720.   /**
  721.    * Return the number of objects that match a particular value.
  722.    * @param object The object to count.
  723.    */
  724.   public synchronized int count( Object object )
  725.     {
  726.     return Counting.count( this, object );
  727.     }
  728.  
  729.   /**
  730.    * Return the number of objects within a specified range of that match a
  731.    * particular value.
  732.    * @param first An iterator positioned at the first object to consider.
  733.    * @param last An iterator positioned immediately after the last object to consider.
  734.    */
  735.   public synchronized int count( DListIterator first, DListIterator last, Object object )
  736.     {
  737.     return Counting.count( first, last, object );
  738.     }
  739.  
  740.   /**
  741.    * Return the number of objects within a specified range of that match a
  742.    * particular value.
  743.    * @param first The index of the first object to consider.
  744.    * @param last The index of the last object to consider.
  745.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  746.    */
  747.   public synchronized int count( int first, int last, Object object )
  748.     {
  749.     if( last < first )
  750.       return 0;
  751.  
  752.     checkRange( first, last );
  753.     return Counting.count( iteratorAt( first ), iteratorAt( last + 1 ), object );
  754.     }
  755.  
  756.   /**
  757.    * Return an iterator positioned at the first object that matches a particular value, or 
  758.    * end() if the object is not found.
  759.    * @param object The object to find.
  760.    */
  761.   public synchronized DListIterator find( Object object )
  762.     {
  763.     return (DListIterator) Finding.find( this, object );
  764.     }
  765.  
  766.   /**
  767.    * Return the index of the first object that matches a particular value, or 
  768.    * -1 if the object is not found.
  769.    * @param object The object to find.
  770.    */
  771.   public synchronized int indexOf( Object object )
  772.     {
  773.     DListIterator iterator = (DListIterator) Finding.find( this, object );
  774.     return iterator.myNode == myNode ? -1 : iterator.index();
  775.     }
  776.  
  777.   /**
  778.    * Return an iterator positioned at the first object within a specified range that 
  779.    * matches a particular object, or end() if the object is not found.
  780.    * @param first An iterator positioned at the first object to consider.
  781.    * @param last An iterator positioned immediately after the last object to consider.
  782.    * @param object The object to find.
  783.    */
  784.   public synchronized DListIterator find( DListIterator first, DListIterator last, Object object )
  785.     {
  786.     return (DListIterator) Finding.find( first, last, object );
  787.     }
  788.  
  789.   /**
  790.    * Return an iterator positioned at the first object within a specified range that 
  791.    * matches a particular object, or -1 if the object is not found.
  792.    * @param first The index of the first object to consider.
  793.    * @param last The index of the last object to consider.
  794.    * @param object The object to find.
  795.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  796.    */
  797.   public synchronized int indexOf( int first, int last, Object object )
  798.     {
  799.     if( last < first )
  800.       return 0;
  801.  
  802.     checkRange( first, last );
  803.     DListIterator end = iteratorAt( last + 1 );
  804.     DListIterator iterator = find( iteratorAt( first ), end, object );
  805.     return iterator.myNode == end.myNode ? -1 : iterator.index();
  806.     }
  807.  
  808.   /**
  809.    * Return true if I contain a particular object.
  810.    * @param object The object in question.
  811.    */
  812.   public synchronized boolean contains( Object object )
  813.     {
  814.     return !find( object ).equals( end() );
  815.     }
  816.  
  817.   /**
  818.    * Reverse the order of my elements.
  819.    */
  820.   public synchronized void reverse()
  821.     {
  822.     if( myLength < 2 )
  823.       return;
  824.  
  825.     DListNode first = myNode.next.next;
  826.  
  827.     while( first != myNode )
  828.       {
  829.       DListNode old = first;
  830.       first = first.next;
  831.       transfer( myNode.next, old, first );
  832.       }
  833.     }
  834.  
  835.   private void insert( DListNode node, int n, Object value )
  836.     {
  837.     if( n < 0 )
  838.       throw new IllegalArgumentException( "Attempt to specify a insert a negative number of objects" );
  839.  
  840.     while( n-- > 0 )
  841.       insert( node, value );
  842.     }
  843.  
  844.   private void splice( DListNode node, DList list )
  845.     {
  846.     if( list.myLength > 0 )
  847.       {
  848.       transfer( node, list.myNode.next, list.myNode );
  849.       myLength += list.myLength;
  850.       list.myLength = 0;
  851.       }
  852.     }
  853.  
  854.   private void splice( DListNode to, DList list, DListNode from )
  855.     {
  856.     if( to != from && to != from.next )
  857.       {
  858.       transfer( to, from, from.next );
  859.       ++myLength;
  860.       --list.myLength;
  861.       }
  862.     }
  863.  
  864.   private DListNode insert( DListNode pos, Object value )
  865.     {
  866.     DListNode tmp = new DListNode();
  867.     tmp.object = value;
  868.     tmp.next = pos;
  869.     tmp.previous = pos.previous;
  870.     pos.previous.next = tmp;
  871.     pos.previous = tmp;
  872.     ++myLength;
  873.     return tmp;
  874.     }
  875.  
  876.   private void insert( DListNode pos, DListNode first, DListNode last )
  877.     {
  878.     while( first != last )
  879.       {
  880.       insert( pos, first.object );
  881.       first = first.next;
  882.       }
  883.     }
  884.  
  885.   private void transfer( DListNode pos, DListNode first, DListNode last )
  886.     {
  887.     if ((pos != first) && (pos != last))
  888.       {
  889.       last.previous.next = pos;
  890.       first.previous.next = last;
  891.       pos.previous.next = first;
  892.       DListNode tmp = pos.previous;
  893.       pos.previous = last.previous;
  894.       last.previous = first.previous;
  895.       first.previous = tmp;
  896.       }
  897.     }
  898.  
  899.   private void remove( DListNode node )
  900.     {
  901.     node.previous.next = node.next;
  902.     node.next.previous = node.previous;
  903.     --myLength;
  904.     }
  905.  
  906.   private void remove( DListNode first, DListNode last )
  907.     {
  908.     while( first != last )
  909.       {
  910.       first.previous.next = first.next;
  911.       first.next.previous = first.previous;
  912.       --myLength;
  913.       first = first.next;
  914.       }
  915.     }
  916.  
  917.   private int remove( DListNode first, DListNode last, Object object )
  918.     {
  919.     int n = 0;
  920.  
  921.     for( DListNode node = first; node != last; node = node.next )
  922.       if( node.object.equals( object ) )
  923.         {
  924.         node.previous.next = node.next;
  925.         node.next.previous = node.previous;
  926.         ++n;
  927.         }
  928.  
  929.     myLength -= n;
  930.     return n;
  931.     }
  932.  
  933.   private DListIterator iteratorAt( int index )
  934.     {
  935.     DListNode node = myNode.next;
  936.  
  937.     while( index-- > 0 )
  938.       node = node.next;
  939.  
  940.     return new DListIterator( this, node );
  941.     }
  942.  
  943.   private DListNode nodeAt( int index )
  944.     {
  945.     DListNode node = myNode.next;
  946.  
  947.     while( index-- > 0 )
  948.       node = node.next;
  949.  
  950.     return node;
  951.     }
  952.  
  953.   private void checkRange( int lo, int hi )
  954.     {
  955.     if( lo < 0 || lo >= myLength )
  956.       throw new IndexOutOfBoundsException( "Attempt to access index " + lo + " when valid range is 0.." + (myLength - 1) );
  957.  
  958.     if( hi < 0 || hi >= myLength )
  959.       throw new IndexOutOfBoundsException( "Attempt to access index " + hi + " when valid range is 0.." + (myLength - 1) );
  960.     }
  961.   }
  962.  
  963.  
  964. final class DListNode
  965.   {
  966.   public DListNode previous;
  967.   public DListNode next;
  968.   public Object object;
  969.   }
  970.  
  971.  
  972.  
  973.