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