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