home *** CD-ROM | disk | FTP | other *** search
/ Symantec Visual Cafe for Java 2.5 / symantec-visual-cafe-2.5-database-dev-edition.iso / Extras / OSpace / jgl.exe / jgl_2_0 / src / COM / objectspace / jgl / Array.java < prev    next >
Encoding:
Java Source  |  1997-03-14  |  26.5 KB  |  872 lines

  1. // Copyright(c) 1996,1997 ObjectSpace, Inc.
  2. // Portions Copyright(c) 1995, 1996 Hewlett-Packard Company.
  3.  
  4. package COM.objectspace.jgl;
  5.  
  6. import java.util.Enumeration;
  7. import java.lang.Math;
  8.  
  9. /**
  10.  * An Array is a sequence that is very similar to a regular array except that it
  11.  * can expand to accomodate new elements.
  12.  * <p>
  13.  * An Array is the simplest kind of JGL container. In addition to the common container
  14.  * functions described earlier in this book, an Array includes functions for accessing
  15.  * its extremities, appending, inserting, erasing, and adjusting its capacity.
  16.  * <p>
  17.  * The underlying architecture of Arrays makes them ideal for storing elements whose
  18.  * order is significant and where fast numeric indexing is important. Inserting elements
  19.  * anywhere except at the end of an Array is slow, so they should not be used where
  20.  * this kind of operation is common. If inserting is common, consider using a List or
  21.  * a Deque instead.
  22.  * <p>
  23.  * The implementation store elements in a contiguous linear memory space so that
  24.  * index-based access is very quick. When an Array's originally allocated memory space
  25.  * is exceeded, its elements are copied into a new memory space that is larger than the
  26.  * old space and then the old space is deallocated. For efficiency, memory is typically
  27.  * allocated in units of the machine's page size.
  28.  * <p>
  29.  * If an insertion causes reallocation, all iterators and references are invalidated;
  30.  * otherwise, only the iterators and references after the insertion point are invalidated.
  31.  * Inserting a single element into an Array is linear in the distance from the insertion
  32.  * point to the end of the array. The amortized complexity over the lifetime of an Array
  33.  * of inserting a single element at its end is constant. Insertion of multiple elements
  34.  * into an Array with a single call of the insert member is linear in the sum of the
  35.  * number of elements plus the distance to the end of the Array. In other words, it is
  36.  * much faster to insert many elements into the middle of an Array at once than to do the
  37.  * insertion one at a time.
  38.  * <p>
  39.  * A remove invalidates all of the iterators and references after the point of the remove.
  40.  * <p>
  41.  * @see COM.objectspace.jgl.Sequence
  42.  * @see COM.objectspace.jgl.examples.ArrayExamples
  43.  * @version 2.0.2
  44.  * @author ObjectSpace, Inc.
  45.  */
  46.  
  47. public class Array implements Sequence
  48.   {
  49.   Object myStorage[]; // My storage.
  50.   int myLength; // The number of objects I currently contain.
  51.   static final int DEFAULT_SIZE = 10;
  52.   static final int THRESHOLD = 2000;
  53.   static final int MULTIPLIER = 2;
  54.  
  55.   /**
  56.    * Construct myself to be an empty Array.
  57.    */
  58.   public Array()
  59.     {
  60.     myStorage = new Object[ DEFAULT_SIZE ];
  61.     }
  62.  
  63.   /**
  64.    * Construct myself to contain a specified number of null elements.
  65.    * @param size The number of elements to contain.
  66.    * @exception java.lang.IllegalArgumentException If size is negative.
  67.    */
  68.   public Array( int size )
  69.     {
  70.     if ( size < 0 )
  71.       throw new IllegalArgumentException( "Attempt to create an Array with a negative size" );
  72.  
  73.     myLength = size;
  74.     myStorage = new Object[ myLength ];
  75.     }
  76.  
  77.   /**
  78.    * Construct myself to contain a specified number of elements set to
  79.    * a particular object.
  80.    * @param size The number of elements to contain.
  81.    * @param object The initial value of each element.
  82.    * @exception java.lang.IllegalArgumentException If size is negative.
  83.    */
  84.   public Array( int size, Object object )
  85.     {
  86.     this( size );
  87.  
  88.     for ( int i = 0; i < myLength; i++ )
  89.       myStorage[ i ] = object;
  90.     }
  91.  
  92.   /**
  93.    * Construct myself to use a specified array as my initial storage.
  94.    * @param The array to use as initial storage.
  95.    */
  96.   public Array( Object array[] )
  97.     {
  98.     synchronized( array )
  99.       {
  100.       myStorage = array;
  101.       myLength = array.length;
  102.       }
  103.     }
  104.  
  105.   /**
  106.    * Construct myself to be a shallow copy of an existing Array.
  107.    * @param array The Array to copy.
  108.    */
  109.   public Array( Array array )
  110.     {
  111.     synchronized( array )
  112.       {
  113.       myLength = array.myLength;
  114.       myStorage = new Object[ myLength ];
  115.       System.arraycopy( array.myStorage, 0, myStorage, 0, myLength );
  116.       }
  117.     }
  118.  
  119.   /**
  120.    * Return a shallow copy of myself.
  121.    */
  122.   public synchronized Object clone()
  123.     {
  124.     return new Array( this );
  125.     }
  126.  
  127.   /**
  128.    * Return true if I'm equal to another object.
  129.    * @param object The object to compare myself against.
  130.    */
  131.   public boolean equals( Object object )
  132.     {
  133.     return object instanceof Array && equals( (Array) object );
  134.     }
  135.  
  136.   /**
  137.    * Return true if I contain the same items in the same order as
  138.    * another Array. Use equals() to compare the individual elements.
  139.    * @param array The Array to compare myself against.
  140.    */
  141.   public synchronized boolean equals( Array array )
  142.     {
  143.     synchronized( array )
  144.       {
  145.       return Comparing.equal( this, array );
  146.       }
  147.     }
  148.  
  149.   /**
  150.    * Return my hash code for support of hashing containers
  151.    */
  152.   public synchronized int hashCode()
  153.     {
  154.     return Hashing.orderedHash( this );
  155.     }
  156.  
  157.  
  158.   /**
  159.    * Return a string that describes me.
  160.    */
  161.   public synchronized String toString()
  162.     {
  163.     return Printing.toString( this, "Array" );
  164.     }
  165.  
  166.   /**
  167.    * Become a shallow copy of an existing Array.
  168.    * @param array The Array that I shall become a shallow copy of.
  169.    */
  170.   public synchronized void copy( Array array )
  171.     {
  172.     if ( this == array )
  173.       return;
  174.  
  175.     synchronized( array )
  176.       {
  177.       if ( array.myLength > myStorage.length )
  178.         {
  179.         myStorage = new Object[ array.myLength ];
  180.         System.arraycopy( array.myStorage, 0, myStorage, 0, array.myLength );
  181.         }
  182.       else if ( myLength > array.myLength )
  183.         {
  184.         System.arraycopy( array.myStorage, 0, myStorage, 0, array.myLength );
  185.  
  186.         for ( int i = array.myLength; i < myLength; i++ )
  187.           myStorage[ i ] = null; // To allow garbage collection.
  188.         }
  189.       else
  190.         {
  191.         System.arraycopy( array.myStorage, 0, myStorage, 0, array.myLength );
  192.         }
  193.  
  194.       myLength = array.myLength;
  195.       }
  196.     }
  197.  
  198.   /**
  199.    * Copy my elements into the specified array.
  200.    * The number of items that are copied is equal to the smaller of my
  201.    * length and the size of the specified array.
  202.    * @param array The array that I shall copy my elements into.
  203.    */
  204.   public synchronized void copyTo( Object[] array )
  205.     {
  206.     synchronized( array )
  207.       {
  208.       if ( myLength < array.length )
  209.         System.arraycopy( myStorage, 0, array, 0, myLength );
  210.       else
  211.         System.arraycopy( myStorage, 0, array, 0, array.length );
  212.       }
  213.     }
  214.  
  215.   /**
  216.    * Return true if I contain no entries.
  217.    */
  218.   public boolean isEmpty()
  219.     {
  220.     return myLength == 0;
  221.     }
  222.  
  223.   /**
  224.    * Return the number of entries that I contain.
  225.    */
  226.   public int size()
  227.     {
  228.     return myLength;
  229.     }
  230.  
  231.   /**
  232.    * Return the maximum number of entries that I can contain.
  233.    */
  234.   public int maxSize()
  235.     {
  236.     return Allocator.maxSize();
  237.     }
  238.  
  239.   /**
  240.    * Return the number of elements that I contain without allocating more
  241.    * internal storage.
  242.    */
  243.   public int capacity()
  244.     {
  245.     return myStorage.length;
  246.     }
  247.  
  248.   /**
  249.    * Return my last item.
  250.    * @exception COM.objectspace.jgl.InvalidOperationException If the Array is empty.
  251.    */
  252.   public synchronized Object back()
  253.     {
  254.     if ( myLength == 0 )
  255.       throw new InvalidOperationException( "Array is empty" );
  256.  
  257.     return myStorage[ myLength - 1 ];
  258.     }
  259.  
  260.   /**
  261.    * Return my first item.
  262.    * @exception COM.objectspace.jgl.InvalidOperationException If the Array is empty.
  263.    */
  264.   public synchronized Object front()
  265.     {
  266.     if ( myLength == 0 )
  267.       throw new InvalidOperationException( "Array is empty" );
  268.  
  269.     return myStorage[ 0 ];
  270.     }
  271.  
  272.   /**
  273.    * Return the element at the specified index.
  274.    * @param index The index.
  275.    * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
  276.    */
  277.   public synchronized Object at( int index )
  278.     {
  279.     if (  index < 0 || index >= myLength )
  280.       throw new IndexOutOfBoundsException( "Attempt to access index " + index + " when valid range is 0.." + (myLength - 1) );
  281.  
  282.     return myStorage[ index ];
  283.     }
  284.  
  285.   /**
  286.    * Set the element at the specified index to a particular object.
  287.    * @param index The index.
  288.    * @param object The object.
  289.    * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
  290.    */
  291.   public synchronized void put( int index, Object object )
  292.     {
  293.     if ( /* index < 0 || */ index >= myLength )
  294.       throw new IndexOutOfBoundsException( "Attempt to access index " + index + " when valid range is 0.." + (myLength - 1) );
  295.  
  296.     myStorage[ index ] = object;
  297.     }
  298.  
  299.   /**
  300.    * Remove all of my elements.
  301.    */
  302.   public synchronized void clear()
  303.     {
  304.     myStorage = new Object[ DEFAULT_SIZE ];
  305.     myLength = 0;
  306.     }
  307.  
  308.   /**
  309.    * Remove the element at a particular position.
  310.    * @param pos An enumeration positioned at the element to remove.
  311.    * @exception IllegalArgumentException is the Enumeration isn't an
  312.    * ArrayIterator for this Array object.
  313.    */
  314.   public Object remove( Enumeration pos )
  315.     {
  316.     if ( ! (pos instanceof ArrayIterator) )
  317.       throw new IllegalArgumentException( "Enumeration not an ArrayIterator" );
  318.  
  319.     if ( ((ArrayIterator)pos).myArray != this )
  320.       throw new IllegalArgumentException( "Enumeration not for this Array " );
  321.  
  322.     Object retval = ( (ArrayIterator)pos ).get();
  323.     remove( ((ArrayIterator)pos).myIndex );
  324.     return retval;
  325.     }
  326.  
  327.   /**
  328.    * Remove the element at a particular index.
  329.    * @param index The index of the element to remove.
  330.    * @return The object removed.
  331.    * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
  332.    */
  333.   public synchronized Object remove( int index )
  334.     {
  335.     if ( index < 0 || index >= myLength )
  336.       throw new IndexOutOfBoundsException( "Attempt to access index " + index + " when valid range is 0.." + (myLength - 1) );
  337.  
  338.     Object retval = myStorage[ index ];
  339.     System.arraycopy( myStorage, index + 1, myStorage, index, myLength - index - 1 );
  340.  
  341.     myStorage[ --myLength ] = null;
  342.     return retval;
  343.     }
  344.  
  345.   /**
  346.    * Remove the elements in the specified range.
  347.    * @param first An Enumeration positioned at the first element to remove.
  348.    * @param last An Enumeration positioned immediately after the last element to remove.
  349.    * @return The number of elements removed.
  350.    * @exception IllegalArgumentException is the Enumeration isn't an
  351.    * ArrayIterator for this Array object.
  352.    */
  353.   public int remove( Enumeration first, Enumeration last )
  354.     {
  355.     if ( !( first instanceof ArrayIterator && last instanceof ArrayIterator ) )
  356.       throw new IllegalArgumentException( "Enumeration not an ArrayIterator" );
  357.  
  358.     if ( ( (ArrayIterator)first ).myArray != this || ( (ArrayIterator)last ).myArray != this )
  359.       throw new IllegalArgumentException( "Enumeration not for this Array " );
  360.  
  361.     return remove( ( (ArrayIterator)first ).myIndex, ( (ArrayIterator)last ).myIndex - 1 );
  362.     }
  363.  
  364.   /**
  365.    * Remove the elements within a range of indices.
  366.    * @param first The index of the first element to remove.
  367.    * @param last The index of the last element to remove.
  368.    * @return The number of elements removed.
  369.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  370.    */
  371.   public synchronized int remove( int first, int last )
  372.     {
  373.     if ( last < first )
  374.       return 0;
  375.  
  376.     checkRange( first, last );
  377.     int amount = last - first + 1;
  378.     System.arraycopy( myStorage, last + 1, myStorage, first, myLength - last - 1 );
  379.  
  380.     for ( int i = myLength - amount; i < myLength; i++ )
  381.       myStorage[ i ] = null;
  382.  
  383.     myLength -= amount;
  384.     return amount;
  385.     }
  386.  
  387.   /**
  388.    * Remove and return my last element.
  389.    * @exception COM.objectspace.jgl.InvalidOperationException If the Array is empty.
  390.    */
  391.   public synchronized Object popBack()
  392.     {
  393.     if ( myLength == 0 )
  394.       throw new InvalidOperationException( "Array is empty" );
  395.  
  396.     Object r = myStorage[ --myLength ];
  397.     myStorage[ myLength ] = null;
  398.     return r;
  399.     }
  400.  
  401.   /**
  402.    * Add an object after my last element.  Returns null.
  403.    * This function is a synonym for pushBack().
  404.    * @param object The object to add.
  405.    */
  406.   public synchronized Object add( Object object )
  407.     {
  408.     if ( myLength == myStorage.length )
  409.       {
  410.       Object[] tmp = getNextStorage();
  411.       System.arraycopy( myStorage, 0, tmp, 0, myLength );
  412.       myStorage = tmp;
  413.       }
  414.  
  415.     myStorage[ myLength++ ] = object;
  416.     return null;
  417.     }
  418.  
  419.   /**
  420.    * Add an object after my last element.
  421.    * @param The object to add.
  422.    */
  423.   public void pushBack( Object object )
  424.     {
  425.     add( object );
  426.     }
  427.  
  428.   /**
  429.    * Insert an object at a particular position and return an iterator
  430.    * positioned at the new element.
  431.    * @param pos An iterator positioned at the element that the object will be inserted immediately before.
  432.    * @param object The object to insert.
  433.    */
  434.   public ArrayIterator insert( ArrayIterator pos, Object object )
  435.     {
  436.     insert( pos.myIndex, object );
  437.     return new ArrayIterator( this, pos.myIndex );
  438.     }
  439.  
  440.   /**
  441.    * Insert an object at a particular index.
  442.    * @param index The index of the element that the object will be inserted immediately before.
  443.    * @param object The object to insert.
  444.    * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
  445.    */
  446.   public synchronized void insert( int index, Object object )
  447.     {
  448.     if ( index > myLength )
  449.       throw new IndexOutOfBoundsException( "Attempt to insert at index " + index + " when valid range is 0.." + myLength );
  450.  
  451.     if ( myLength != myStorage.length )
  452.       {
  453.       if ( index != myLength )
  454.         System.arraycopy( myStorage, index, myStorage, index + 1, myLength - index );
  455.       }
  456.     else
  457.       {
  458.       Object[] tmp = getNextStorage();
  459.       System.arraycopy( myStorage, 0, tmp, 0, index );
  460.       System.arraycopy( myStorage, index, tmp, index + 1, myLength - index );
  461.       myStorage = tmp;
  462.       }
  463.  
  464.     myStorage[ index ] = object;
  465.     ++myLength;
  466.     }
  467.  
  468.   /**
  469.    * Insert multiple objects at a particular position.
  470.    * @param pos An iterator positioned at the element that the objects will be inserted immediately before.
  471.    * @param n The number of objects to insert.
  472.    * @param object The object to insert.
  473.    */
  474.   public void insert( ArrayIterator pos, int n, Object object )
  475.     {
  476.     insert( pos.myIndex, n, object );
  477.     }
  478.  
  479.   /**
  480.    * Insert multiple objects at a particular index.
  481.    * @param index The index of the element that the objects will be inserted immediately before.
  482.    * @param object The object to insert.
  483.    * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
  484.    * @exception java.lang.IllegalArgumentException If the number of objects is negative.
  485.    */
  486.   public synchronized void insert( int index, int n, Object object )
  487.     {
  488.     if ( index < 0 || index > myLength )
  489.       throw new IndexOutOfBoundsException( "Attempt to insert at index " + index + " when valid range is 0.." + myLength );
  490.  
  491.     if ( n < 0 )
  492.       throw new IllegalArgumentException( "Attempt to insert a negative number of objects." );
  493.  
  494.     if ( n == 0 )
  495.       return;
  496.  
  497.     if ( myStorage.length - myLength >= n )
  498.       {
  499.       System.arraycopy( myStorage, index, myStorage, index + n, myLength - index );
  500.       }
  501.     else
  502.       {
  503.       Object[] tmp = getNextStorage( n );
  504.       System.arraycopy( myStorage, 0, tmp, 0, index );
  505.       System.arraycopy( myStorage, index, tmp, index + n, myLength - index );
  506.       myStorage = tmp;
  507.       }
  508.  
  509.     for ( int i = index; i < index + n; i++ )
  510.       myStorage[ i ] = object;
  511.  
  512.     myLength += n;
  513.     }
  514.  
  515.   /**
  516.    * Insert a sequence of objects at a particular location.
  517.    * @param pos The location of the element that the objects will be inserted immediately before.
  518.    * @param first An iterator positioned at the first element to insert.
  519.    * @param last An iterator positioned immediately after the last element to insert.
  520.    */
  521.   public void insert( ArrayIterator pos, ForwardIterator first, ForwardIterator last )
  522.     {
  523.     insert( pos.myIndex, first, last );
  524.     }
  525.  
  526.   /**
  527.    * Insert a sequence of objects at a particular index.
  528.    * @param index The index of the element that the objects will be inserted immediately before.
  529.    * @param first An iterator positioned at the first element to insert.
  530.    * @param last An iterator positioned immediately after the last element to insert.
  531.    */
  532.   public synchronized void insert( int index, ForwardIterator first, ForwardIterator last )
  533.     {
  534.     int n = first.distance( last );
  535.  
  536.     if ( n == 0 )
  537.       return;
  538.  
  539.     ForwardIterator firstx = (ForwardIterator) first.clone();
  540.  
  541.     if ( myStorage.length - myLength >= n )
  542.       {
  543.       System.arraycopy( myStorage, index, myStorage, index + n, myLength - index );
  544.       }
  545.     else
  546.       {
  547.       Object[] tmp = getNextStorage( n );
  548.       System.arraycopy( myStorage, 0, tmp, 0, index );
  549.       System.arraycopy( myStorage, index, tmp, index + n, myLength - index );
  550.       myStorage = tmp;
  551.       }
  552.  
  553.     for ( int i = index; i < index + n; i++ )
  554.       myStorage[ i ] = firstx.nextElement();
  555.  
  556.     myLength += n;
  557.     }
  558.  
  559.   /**
  560.    * Swap my contents with another Array.
  561.    * @param array The Array that I will swap my contents with.
  562.    */
  563.   public synchronized void swap( Array array )
  564.     {
  565.     synchronized( array )
  566.       {
  567.       int oldSize = myLength;
  568.       Object oldStorage[] = myStorage;
  569.  
  570.       myLength = array.myLength;
  571.       myStorage = array.myStorage;
  572.  
  573.       array.myLength = oldSize;
  574.       array.myStorage = oldStorage;
  575.       }
  576.     }
  577.  
  578.   /**
  579.    * Return an Enumeration of my components.
  580.    */
  581.   public synchronized Enumeration elements()
  582.     {
  583.     return new ArrayIterator( this, 0 );
  584.     }
  585.  
  586.   /**
  587.    * Return an iterator positioned at my first item.
  588.    */
  589.   public ForwardIterator start()
  590.     {
  591.     return begin();
  592.     }
  593.  
  594.   /**
  595.    * Return an iterator positioned immediately after my last item.
  596.    */
  597.   public ForwardIterator finish()
  598.     {
  599.     return end();
  600.     }
  601.  
  602.   /**
  603.    * Return an iterator positioned at my first item.
  604.    */
  605.   public synchronized ArrayIterator begin()
  606.     {
  607.     return new ArrayIterator( this, 0 );
  608.     }
  609.  
  610.   /**
  611.    * Return an iterator positioned immediately after my last item.
  612.    */
  613.   public synchronized ArrayIterator end()
  614.     {
  615.     return new ArrayIterator( this, myLength );
  616.     }
  617.  
  618.   /**
  619.    * If my storage space is currently larger than my total number of elements,
  620.    * reallocate the elements into a storage space that is exactly the right size.
  621.    */
  622.   public synchronized void trimToSize()
  623.     {
  624.     if ( myLength < myStorage.length )
  625.       {
  626.       Object oldData[] = myStorage;
  627.       myStorage = new Object[ myLength ];
  628.       System.arraycopy( oldData, 0, myStorage, 0, myLength );
  629.       }
  630.     }
  631.  
  632.   /**
  633.    * Pre-allocate enough space to hold a specified number of elements.
  634.    * This operation does not change the value returned by size().
  635.    * @param n The amount of space to pre-allocate.
  636.    * @exception java.lang.IllegalArgumentException If the specified size is negative.
  637.    */
  638.   public synchronized void ensureCapacity( int n )
  639.     {
  640.     if ( n < 0 )
  641.       throw new IllegalArgumentException( "Attempt to reserve a negative size." );
  642.  
  643.     if ( myStorage.length < n )
  644.       {
  645.       Object[] tmp = new Object[ n ];
  646.  
  647.       if ( myLength > 0 )
  648.         System.arraycopy( myStorage, 0, tmp, 0, myLength );
  649.  
  650.       myStorage = tmp;
  651.       }
  652.     }
  653.  
  654.   /**
  655.    * Remove and return my first element.
  656.    * @exception COM.objectspace.jgl.InvalidOperationException If the Array is empty.
  657.    */
  658.   public synchronized Object popFront()
  659.     {
  660.     if ( myLength == 0 )
  661.       throw new InvalidOperationException( "Array is empty" );
  662.  
  663.     Object result = myStorage[ 0 ];
  664.     remove( 0 );
  665.     return result;
  666.     }
  667.  
  668.   /**
  669.    * Insert an object in front of my first element.
  670.    * @param object The object to insert.
  671.    */
  672.   public void pushFront( Object object )
  673.     {
  674.     insert( 0, object );
  675.     }
  676.  
  677.   /**
  678.    * Remove all elements that match a particular object and return the number of
  679.    * objects that were removed.
  680.    * @param object The object to remove.
  681.    */
  682.   public int remove( Object object )
  683.     {
  684.     return remove( 0, myLength - 1, object );
  685.     }
  686.  
  687.   /**
  688.    * Remove at most a given number of elements that match a particular object and return the number of
  689.    * objects that were removed.
  690.    * @param object The object to remove.
  691.    * @param count The maximum number of objects to remove.
  692.    */
  693.   public synchronized int remove( Object object, int count )
  694.     {
  695.     int removed = 0;
  696.     while ( count > 0 )
  697.       {
  698.       int i = indexOf( object );
  699.       if ( i >= 0 )
  700.         {
  701.         --count;
  702.         ++removed;
  703.         remove( i );
  704.         }
  705.       }
  706.     return removed;
  707.     }
  708.  
  709.   /**
  710.    * Remove all elements within a range of indices that match a particular object
  711.    * and return the number of objects that were removed.
  712.    * @param first The index of the first object to consider.
  713.    * @param last The index of the last object to consider.
  714.    * @param object The object to remove.
  715.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  716.    */
  717.   public synchronized int remove( int first, int last, Object object )
  718.     {
  719.     if ( last < first )
  720.       return 0;
  721.  
  722.     checkRange( first, last );
  723.     ArrayIterator firstx = new ArrayIterator( this, first );
  724.     ArrayIterator lastx = new ArrayIterator( this, last + 1 );
  725.     ArrayIterator finish = (ArrayIterator)Removing.remove( firstx, lastx, object );
  726.     return remove( finish.myIndex, last );
  727.     }
  728.  
  729.   /**
  730.    * Replace all elements that match a particular object with a new value and return
  731.    * the number of objects that were replaced.
  732.    * @param oldValue The object to be replaced.
  733.    * @param newValue The value to substitute.
  734.    */
  735.   public synchronized int replace( Object oldValue, Object newValue )
  736.     {
  737.     return Replacing.replace( this, oldValue, newValue );
  738.     }
  739.  
  740.   /**
  741.    * Replace all elements within a range of indices that match a particular object
  742.    * with a new value and return the number of objects that were replaced.
  743.    * @param first The index of the first object to be considered.
  744.    * @param last The index of the last object to be considered.
  745.    * @param oldValue The object to be replaced.
  746.    * @param newValue The value to substitute.
  747.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  748.    */
  749.   public synchronized int replace( int first, int last, Object oldValue, Object newValue )
  750.     {
  751.     if ( last < first )
  752.       return 0;
  753.  
  754.     checkRange( first, last );
  755.     return Replacing.replace( new ArrayIterator( this, first ), new ArrayIterator( this, last + 1 ), oldValue, newValue );
  756.     }
  757.  
  758.   /**
  759.    * Return the number of objects that match a particular value.
  760.    * @param object The object to count.
  761.    */
  762.   public synchronized int count( Object object )
  763.     {
  764.     return Counting.count( this, object );
  765.     }
  766.  
  767.   /**
  768.    * Return the number of objects within a particular range of indices that match a
  769.    * particular value.
  770.    * @param first The index of the first object to consider.
  771.    * @param last The index of the last object to consider.
  772.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  773.    */
  774.   public synchronized int count( int first, int last, Object object )
  775.     {
  776.     if ( last < first )
  777.       return 0;
  778.  
  779.     checkRange( first, last );
  780.     return Counting.count( new ArrayIterator( this, first ), new ArrayIterator( this, last + 1 ), object );
  781.     }
  782.  
  783.   /**
  784.    * Return the index of the first object that matches a particular value, or -1
  785.    * if the object is not found.
  786.    * @param object The object to find.
  787.    */
  788.   public int indexOf( Object object )
  789.     {
  790.     return indexOf( 0, myLength - 1, object );
  791.     }
  792.  
  793.   /**
  794.    * Return the index of the first object within a range of indices that match a
  795.    * particular object, or -1 if the object is not found.
  796.    * @param first The index of the first object to consider.
  797.    * @param last The index of the last object to consider.
  798.    * @param object The object to find.
  799.    * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
  800.    */
  801.   public synchronized int indexOf( int first, int last, Object object )
  802.     {
  803.     if ( last < first )
  804.       return -1;
  805.  
  806.     checkRange( first, last );
  807.     int index = ((ArrayIterator) Finding.find( new ArrayIterator( this, first ), new ArrayIterator( this, last + 1 ), object )).myIndex;
  808.     return index == last + 1 ? -1 : index;
  809.     }
  810.  
  811.   /**
  812.    * Sets the size of the Array. if the size shrinks, the extra elements (at
  813.    * the end of the array) are lost; if the size increases, the new elements
  814.    * are set to null.
  815.    * @param newSize The new size of the Array.
  816.    */
  817.   public synchronized void setSize( int newSize )
  818.     {
  819.     if ( myLength > newSize )
  820.       remove( newSize, myLength - 1 );
  821.     else if ( myLength < newSize )
  822.       insert( myLength, newSize - myLength, null );
  823.     }
  824.  
  825.   /**
  826.    * Return true if I contain a particular object.
  827.    * @param object The object in question.
  828.    */
  829.   public boolean contains( Object object )
  830.     {
  831.     return indexOf( object ) != -1;
  832.     }
  833.  
  834.   private void checkRange( int lo, int hi )
  835.     {
  836.     if ( lo < 0 || lo >= myLength )
  837.       throw new IndexOutOfBoundsException( "Attempt to access index " + lo + " when valid range is 0.." + (myLength - 1) );
  838.  
  839.     if ( hi < 0 || hi >= myLength )
  840.       throw new IndexOutOfBoundsException( "Attempt to access index " + hi + " when valid range is 0.." + (myLength - 1) );
  841.     }
  842.  
  843.   private int getNextSize()
  844.     {
  845.     // multiply by MULTIPLIER until THRESHOLD reached; increment by THRESHOLD
  846.     // from then on
  847.     int newSize = myLength > THRESHOLD
  848.       ? myLength + THRESHOLD
  849.       : myLength * MULTIPLIER;
  850.     return Math.max( 1, newSize );
  851.     }
  852.  
  853.   /**
  854.    * Same as getNextStorage( 1 ).
  855.    */
  856.   private Object[] getNextStorage()
  857.     {
  858.     Object[] tmp = new Object[ getNextSize() ];
  859.     return tmp;
  860.     }
  861.  
  862.   /**
  863.    * Ensure that there is enough space for at least n new objects.
  864.    */
  865.   private Object[] getNextStorage( int n )
  866.     {
  867.     int newSize = Math.max( getNextSize(), myLength + n );
  868.     Object[] tmp = new Object[ newSize ];
  869.     return tmp;
  870.     }
  871.   }
  872.