home *** CD-ROM | disk | FTP | other *** search
Java Source | 1996-09-10 | 29.0 KB | 957 lines |
- // Copyright(c) 1996 ObjectSpace, Inc.
- // Portions Copyright(c) 1995, 1996 Hewlett-Packard Company.
-
- package jgl;
-
- import java.util.Enumeration;
-
- /**
- * A Deque is a sequential container that is optimized for fast indexed-based access
- * and efficient insertion at either of its extremities.
- * <p>
- * Deques are useful in circumstances where order, compact storage, and fast insertion at
- * extremeties is important. A Deque is ideal for implementing any kind of FIFO structure.
- * If a strict FIFO structure is required that does not allow index-based access, then
- * you should consider using a Queue adaptor with a Deque as the underlying container.
- * If you require very fast insertion near the middle of a sequential structure, then
- * consider using a List instead of a Deque.
- * <p>
- * The implementation allocates storage for a Deque's elements in 4K blocks
- * (a usual page size) of contiguous memory, and use an array to keep track of a deque's
- * blocks. When a Deque is constructed, it has no associated storage. As elements are
- * added, blocks of storage are added to the beginning or the end of the deque as
- * necessary. A result of this architecture is that items may be inserted very
- * efficiently near either extremity. Once a block has been allocated to a Deque, it is
- * not deallocated until the Deque is destroyed. Insertions are careful to expand the
- * Deque in the direction that involves the least amount of copying. Removals take
- * similar precautions.
- * <p>
- * If an insertion causes reallocation, all iterators and references are invalidated;
- * otherwise, iterators and references are only invalidated if an item is not inserted
- * at an extremity. In the worst cast, inserting a single element into a Deque takes
- * linear time in the minimum of the distance from the insertion point to the beginning
- * of the Deque and the distance from the insertion point to the end of the Deque.
- * Inserting a single element either at the beginning or end of a Deque always takes
- * constant time.
- * <p>
- * If the first or last item is removed, all iterators and references remain valid; if any
- * other item is removed, all iterators and references are invalidated.
- * <p>
- * @see jgl.Sequence
- * @see jgl.examples.DequeExamples
- * @version 1.1
- * @author ObjectSpace, Inc.
- */
-
- public class Deque implements Sequence
- {
- DequeIterator myStart = new DequeIterator( this, 0, 0 );
- DequeIterator myFinish = new DequeIterator( this, 0, 0 );
- int myLength;
- Object[][] myMap;
- static final int BLOCK_SIZE = Allocator.pageSize() / 8;
-
- /**
- * Construct myself to be an empty Deque.
- */
- public Deque()
- {
- }
-
- /**
- * Construct myself to contain a specified number of null elements.
- * @param size The number of elements to contain.
- * @exception java.lang.IllegalArgumentException If size is negative.
- */
- public Deque( int size )
- {
- insert( myStart, size, null );
- }
-
- /**
- * Construct myself to contain a specified number of elements set to
- * a particular object.
- * @param size The number of elements to contain.
- * @param object The initial value of each element.
- * @exception java.lang.IllegalArgumentException If size is negative.
- */
- public Deque( int size, Object object )
- {
- insert( myStart, size, object );
- }
-
- /**
- * Construct myself to be a shallow copy of an existing Deque.
- * @param deque The Deque to copy.
- */
- public Deque( Deque deque )
- {
- Copying.copy( deque, new InsertIterator( this ) );
- }
-
- /**
- * Return a shallow copy of myself.
- */
- public synchronized Object clone()
- {
- return new Deque( this );
- }
-
- /**
- * Return true if I'm equal to another object.
- * @param object The object to compare myself against.
- */
- public boolean equals( Object object )
- {
- return object instanceof Deque && equals( (Deque) object );
- }
-
- /**
- * Return true if I contain the same items in the same order as
- * another Deque. Use equals() to compare the individual elements.
- * @param deque The Deque to compare myself against.
- */
- public synchronized boolean equals( Deque deque )
- {
- return Comparing.equal( this, deque );
- }
-
- /**
- * Return my hash code for support of hashing containers
- */
- public int hashCode()
- {
- return Hashing.orderedHash( this );
- }
-
-
- /**
- * Return a string that describes me.
- */
- public synchronized String toString()
- {
- return Printing.toString( this, "Deque" );
- }
-
- /**
- * Become a shallow copy of an existing Deque.
- * @param deque The Deque that I shall become a shallow copy of.
- */
- public synchronized void copy( Deque deque )
- {
- if( this == deque )
- return;
-
- if( myLength >= deque.myLength )
- {
- DequeIterator begin = (DequeIterator) Copying.copy( deque.myStart, deque.myFinish, myStart );
- remove( begin, myFinish );
- }
- else
- {
- DequeIterator end = deque.myStart.copy( myLength );
- Copying.copy( deque.myStart, end, myStart );
-
- for( DequeIterator iterator = end; iterator.hasMoreElements(); iterator.advance() )
- add( iterator.get() );
- }
- }
-
- /**
- * Return true if I contain no entries.
- */
- public boolean isEmpty()
- {
- return myLength == 0;
- }
-
- /**
- * Return the number of entries that I contain.
- */
- public int size()
- {
- return myLength;
- }
-
- /**
- * Return the maximum number of entries that I can contain.
- */
- public int maxSize()
- {
- return Allocator.maxSize();
- }
-
- /**
- * Add an object after my last element and return null.
- * This function is a synonym for pushBack().
- * @param object The object to add.
- */
- public synchronized Object add( Object object )
- {
- if( myLength++ == 0 )
- {
- createMap();
- myMap[ myFinish.myMapIndex ][ myFinish.myBlockIndex++ ] = object;
- }
- else
- {
- myMap[ myFinish.myMapIndex ][ myFinish.myBlockIndex++ ] = object;
-
- if( myFinish.myBlockIndex == BLOCK_SIZE )
- {
- if( myFinish.myMapIndex == myMap.length - 1 )
- growMap();
-
- myMap[ ++myFinish.myMapIndex ] = new Object[ BLOCK_SIZE ];
- myFinish.myBlockIndex = 0;
- }
- }
- return null;
- }
-
- /**
- * Add an object after my last element.
- * @param The object to add.
- */
- public void pushBack( Object object )
- {
- add( object );
- }
-
- /**
- * Insert an object in front of my first element.
- * @param object The object to insert.
- */
- public synchronized void pushFront( Object object )
- {
- if( myLength++ == 0 )
- {
- createMap();
- }
- else if( --myStart.myBlockIndex < 0 )
- {
- if( myStart.myMapIndex == 0 )
- growMap();
-
- myMap[ --myStart.myMapIndex ] = new Object[ BLOCK_SIZE ];
- myStart.myBlockIndex = BLOCK_SIZE - 1;
- }
-
- myMap[ myStart.myMapIndex ][ myStart.myBlockIndex ] = object;
- }
-
- /**
- * Remove and return my first element.
- * @exception jgl.InvalidOperationException If the Deque is empty.
- */
- public synchronized Object popFront()
- {
- if( myLength == 0 )
- throw new InvalidOperationException( "Deque is empty" );
-
- Object r = at(0);
- if( --myLength == 0 )
- {
- clear();
- }
- else
- {
- r = myMap[ myStart.myMapIndex ][ myStart.myBlockIndex ];
- myMap[ myStart.myMapIndex ][ myStart.myBlockIndex++ ] = null;
-
- if( myStart.myBlockIndex == BLOCK_SIZE )
- {
- myMap[ myStart.myMapIndex++ ] = null;
- myStart.myBlockIndex = 0;
- }
- }
- return r;
- }
-
- /**
- * Remove and return my last element.
- * @exception jgl.InvalidOperationException If the Deque is empty.
- */
- public synchronized Object popBack()
- {
- if( myLength == 0 )
- throw new InvalidOperationException( "Deque is empty" );
-
- Object r = at(0);
- if( --myLength == 0 )
- {
- clear();
- }
- else
- {
- if( myFinish.myBlockIndex-- == 0 )
- {
- myMap[ myFinish.myMapIndex-- ] = null;
- myFinish.myBlockIndex = BLOCK_SIZE - 1;
- }
- r = myMap[ myFinish.myMapIndex ][ myFinish.myBlockIndex ];
- myMap[ myFinish.myMapIndex ][ myFinish.myBlockIndex ] = null;
- }
- return r;
- }
-
- /**
- * Remove all of my elements.
- */
- public synchronized void clear()
- {
- myMap = null;
- myStart.myMapIndex = 0;
- myStart.myBlockIndex = 0;
- myFinish.myMapIndex = 0;
- myFinish.myBlockIndex = 0;
- myLength = 0;
- }
-
- /**
- * Return an Enumeration of my components
- */
- public synchronized Enumeration elements()
- {
- return new DequeIterator( myStart );
- }
-
- /**
- * Return an iterator positioned at my first item.
- */
- public synchronized DequeIterator begin()
- {
- return new DequeIterator( myStart );
- }
-
- /**
- * Return an iterator positioned immediately after my last item.
- */
- public synchronized DequeIterator end()
- {
- return new DequeIterator( myFinish );
- }
-
- /**
- * Return an iterator positioned at my first item
- */
- public synchronized ForwardIterator start()
- {
- return new DequeIterator( myStart );
- }
-
- /**
- * Return an iterator positioned immediately afer my last item.
- */
- public synchronized ForwardIterator finish()
- {
- return new DequeIterator( myFinish );
- }
-
- /**
- * Return my first item.
- * @exception jgl.InvalidOperationException If the Deque is empty.
- */
- public synchronized Object front()
- {
- if( myLength == 0 )
- throw new InvalidOperationException( "Deque is empty" );
-
- return myMap[ myStart.myMapIndex ][ myStart.myBlockIndex ];
- }
-
- /**
- * Return my last item.
- * @exception jgl.InvalidOperationException If the Deque is empty.
- */
- public synchronized Object back()
- {
- if( myLength == 0 )
- throw new InvalidOperationException( "Deque is empty" );
-
- if( myFinish.myBlockIndex > 0 )
- return myMap[ myFinish.myMapIndex ][ myFinish.myBlockIndex - 1 ];
- else
- return myMap[ myFinish.myMapIndex - 1 ][ BLOCK_SIZE - 1 ];
- }
-
- /**
- * Return the element at the specified index.
- * @param index The index.
- * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
- */
- public synchronized Object at( int index )
- {
- if( index < 0 || index >= myLength )
- throw new IndexOutOfBoundsException( "Attempt to access index " + index + " when valid range is 0.." + (myLength - 1) );
-
- int blockIndex = myStart.myBlockIndex + index;
- int mapIndex = myStart.myMapIndex;
-
- if( blockIndex >= BLOCK_SIZE )
- {
- int jump = blockIndex / BLOCK_SIZE;
- mapIndex += jump;
- blockIndex %= BLOCK_SIZE;
- }
- else if( blockIndex < 0 )
- {
- int jump = ( BLOCK_SIZE - 1 - blockIndex ) / BLOCK_SIZE;
- mapIndex -= jump;
- blockIndex += jump * BLOCK_SIZE;
- }
-
- return myMap[ mapIndex ][ blockIndex ];
- }
-
- /**
- * Set the element at the specified index to a particular object.
- * @param index The index.
- * @param object The object.
- * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
- */
- public synchronized void put( int index, Object object )
- {
- if( index < 0 || index >= myLength )
- throw new IndexOutOfBoundsException( "Attempt to access index " + index + " when valid range is 0.." + (myLength - 1) );
-
- int blockIndex = myStart.myBlockIndex + index;
- int mapIndex = myStart.myMapIndex;
-
- if( blockIndex >= BLOCK_SIZE )
- {
- int jump = blockIndex / BLOCK_SIZE;
- mapIndex += jump;
- blockIndex %= BLOCK_SIZE;
- }
- else if( blockIndex < 0 )
- {
- int jump = ( BLOCK_SIZE - 1 - blockIndex ) / BLOCK_SIZE;
- mapIndex -= jump;
- blockIndex += jump * BLOCK_SIZE;
- }
-
- myMap[ mapIndex ][ blockIndex ] = object;
- }
-
- /**
- * Swap my contents with another Deque.
- * @param deque The Deque that I will swap my contents with.
- */
- public synchronized void swap( Deque deque )
- {
- DequeIterator tmpStart = myStart;
- myStart = deque.myStart;
- myStart.myDeque = this;
- deque.myStart = tmpStart;
- deque.myStart.myDeque = deque;
-
- DequeIterator tmpFinish = myFinish;
- myFinish = deque.myFinish;
- myFinish.myDeque = this;
- deque.myFinish = tmpFinish;
- deque.myFinish.myDeque = deque;
-
- int tmpLength = myLength;
- myLength = deque.myLength;
- deque.myLength = tmpLength;
-
- Object[][] tmpMap = myMap;
- myMap = deque.myMap;
- deque.myMap = tmpMap;
- }
-
- /**
- * Remove the element at a particular index.
- * @param index The index of the element to remove.
- * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
- */
- public synchronized void remove( int index )
- {
- if( index < 0 || index >= myLength )
- throw new IndexOutOfBoundsException( "Attempt to access index " + index + " when valid range is 0.." + (myLength - 1) );
-
- remove( myStart.copy( index ) );
- }
-
- /**
- * Remove the element at a particular position.
- * @param e An Enumeration positioned at the element to remove.
- * @exception IllegalArgumentException if the Enumeration isn't a
- * DequeIterator for this Deque object.
- */
- public synchronized void remove( Enumeration e )
- {
- if( ! (e instanceof DequeIterator) )
- throw new IllegalArgumentException( "Enumeration not a DequeIterator" );
-
- if( ((DequeIterator)e).myDeque != this )
- throw new IllegalArgumentException( "Enumeration not for this Deque" );
-
- DequeIterator pos = (DequeIterator)e;
- DequeIterator tmp = pos.copy( 1 );
-
- if( myStart.distance( pos ) < pos.distance( myFinish ) )
- {
- Copying.copy( tmp, myFinish, pos );
- popBack();
- }
- else
- {
- Copying.copyBackward( myStart, pos, tmp );
- popFront();
- }
- }
-
- /**
- * Remove the elements within a range of indices.
- * @param first The index of the first element to remove.
- * @param last The index of the last element to remove.
- * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
- */
- public synchronized void remove( int first, int last )
- {
- if( last < first )
- return;
-
- checkRange( first, last );
- remove( myStart.copy( first ), myStart.copy( last + 1 ) );
- }
-
- /**
- * Remove the elements in the range [ first..last ).
- * @param first An Enumeration positioned at the first element to remove.
- * @param last An Enumeration positioned immediately after the last element to remove.
- * @exception IllegalArgumentException if the Enumeration isn't a
- * DequeIterator for this Deque object.
- */
- public synchronized void remove( Enumeration first, Enumeration last )
- {
- if( ( ! (first instanceof DequeIterator) ) ||
- ( ! (last instanceof DequeIterator) ) )
- throw new IllegalArgumentException( "Enumeration not a DequeIterator" );
-
- if( ( ((DequeIterator)first).myDeque != this ) ||
- ( ((DequeIterator)last).myDeque != this ) )
- throw new IllegalArgumentException( "Enumeration not for this Deque" );
-
- DequeIterator begin = (DequeIterator)first;
- DequeIterator end = (DequeIterator)last;
-
- int n = begin.distance( end );
-
- if( end.distance( myFinish ) > myStart.distance( begin ) )
- {
- Copying.copyBackward( myStart, begin, end );
-
- while( n-- > 0 )
- popFront();
- }
- else
- {
- Copying.copy( end, myFinish, begin );
-
- while( n-- > 0 )
- popBack();
- }
- }
-
- /**
- * Insert an object at a particular index and return an iterator
- * positioned at the new element.
- * @param index The index of the element that the object will be inserted immediately before.
- * @param object The object to insert.
- * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
- */
- public synchronized DequeIterator insert( int index, Object object )
- {
- if( index < 0 || index > myLength )
- throw new IndexOutOfBoundsException( "Attempt to insert at index " + index + " when valid range is 0.." + myLength );
-
- return insert( myStart.copy( index ), object );
- }
-
- /**
- * Insert an object at a particular position and return an iterator
- * positioned at the new element.
- * @param pos An iterator positioned at the element that the object will be inserted immediately before.
- * @param object The object to insert.
- */
- public synchronized DequeIterator insert( DequeIterator pos, Object value )
- {
- if( pos.equals( myStart ) )
- {
- pushFront( value );
- return new DequeIterator( myStart );
- }
- else if( pos.equals( myFinish ) )
- {
- pushBack( value );
- return myFinish.copy( -1 );
- }
- else
- {
- int index = myStart.distance( pos );
-
- if( pos.distance( myFinish ) > index )
- {
- pushFront( myStart.get() );
- Copying.copy( myStart.copy( 2 ), myStart.copy( index + 1 ), myStart.copy( 1 ) );
- DequeIterator i = myStart.copy( index );
- i.put( value );
- return i;
- }
- else
- {
- DequeIterator i2 = myFinish.copy( -1 );
- pushBack( i2.get() );
- DequeIterator i = myStart.copy( index );
- Copying.copyBackward( i, myFinish.copy( -2 ), myFinish.copy( -1 ) );
- i.put( value );
- return i;
- }
- }
- }
-
- /**
- * Insert multiple objects at a particular index.
- * @param index The index of the element that the objects will be inserted immediately before.
- * @param object The object to insert.
- * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
- * @exception java.lang.IllegalArgumentException If the number of objects to insert is negative.
- */
- public synchronized void insert( int index, int n, Object value )
- {
- if( n < 0 )
- throw new IllegalArgumentException( "Attempt to insert a negative n1umber of objects." );
-
- if( index < 0 || index > myLength )
- throw new IndexOutOfBoundsException( "Attempt to insert at index " + index + " when valid range is 0.." + myLength );
-
- insert( myStart.copy( index ), n , value );
- }
-
- /**
- * Insert multiple objects at a particular position.
- * @param pos An iterator positioned at the element that the objects will be inserted immediately before.
- * @param n The number of objects to insert.
- * @param object The object to insert.
- * @exception java.lang.IllegalArgumentException If the number of objects to insert is negative.
- */
- public synchronized void insert( DequeIterator pos, int n, Object value )
- {
- if( n < 0 )
- throw new IllegalArgumentException( "Attempt to insert a negative number of objects" );
-
- if( n == 0 )
- return;
-
- int left = myStart.distance( pos ); // Number to left of insertion point.
- int right = pos.distance( myFinish ); // Number to right of insertion point.
-
- if( right > left )
- {
- if( n > left )
- {
- int m = n - left;
-
- while( m-- > 0 )
- pushFront( value );
-
- for( int j = 1; j <= left; j++ )
- pushFront( at( n - 1 ) );
-
- Filling.fill( myStart.copy( n ), myStart.copy( n + left ), value );
- }
- else
- {
- for( int j = 1; j <= n; j++ )
- pushFront( at( n - 1 ) );
-
- DequeIterator i = myStart.copy( n + left );
- Copying.copy( myStart.copy( n + n ), i, myStart.copy( n ) );
- Filling.fill( myStart.copy( left ), i, value );
- }
- }
- else
- {
- int oldSize = size(); // Size of deque before insertion.
-
- if( n > right )
- {
- int m = n - right;
-
- while( m-- > 0 )
- pushBack( value );
-
- for( int j = left; j < oldSize; j++ )
- pushBack( at( j ) );
-
- Filling.fill( myStart.copy( left ), myStart.copy( oldSize ), value );
- }
- else
- {
- int index = oldSize - n;
-
- for( int j = index; j < oldSize; j++ )
- pushBack( at( j ) );
-
- DequeIterator i = myStart.copy( left );
- Copying.copyBackward( i, myStart.copy( index ), myStart.copy( oldSize) );
- Filling.fill( i, myStart.copy( left + n ), value );
- }
- }
- }
-
- /**
- * Insert a sequence of objects at a particular index.
- * @param pos The index of the element that the objects will be inserted immediately before.
- * @param first An iterator positioned at the first element to insert.
- * @param last An iterator positioned immediately after the last element to insert.
- * @exception java.lang.IndexOutOfBoundsException If the index is invalid.
- */
- public synchronized void insert( int index, BidirectionalIterator first, BidirectionalIterator last )
- {
- if( index < 0 || index > myLength )
- throw new IndexOutOfBoundsException( "Attempt to insert at index " + index + " when valid range is 0.." + myLength );
-
- insert( myStart.copy( index ), first, last );
- }
-
- /**
- * Insert a sequence of objects at a particular location.
- * @param pos The location of the element that the objects will be inserted immediately before.
- * @param first An iterator positioned at the first element to insert.
- * @param last An iterator positioned immediately after the last element to insert.
- */
- public synchronized void insert( DequeIterator pos, BidirectionalIterator first, BidirectionalIterator last )
- {
- int n = first.distance( last );
- int left = myStart.distance( pos ); // Number to left of insertion point.
- int right = pos.distance( myFinish ); // Number to right of insertion point.
-
- if( right > left )
- {
- if( n > left )
- {
- BidirectionalIterator m = (BidirectionalIterator) last.clone();
- m.retreat( left );
- BidirectionalIterator q = (BidirectionalIterator) m.clone();
-
- while( !m.equals( first ) )
- {
- m.retreat();
- pushFront( m.get() );
- }
-
- for( int j = 1; j <= left; j++ )
- pushFront( at( n - 1 ) );
-
- Copying.copy( q, last, myStart.copy( n ) );
- }
- else
- {
- for( int j = 1; j <= n; j++ )
- pushFront( at( n - 1 ) );
-
- Copying.copy( myStart.copy( n + n ), myStart.copy( n + left ), myStart.copy( n ) );
- Copying.copy( first, last, myStart.copy( left ) );
- }
- }
- else
- {
- int oldSize = size(); // Size of deque before insertion.
-
- if( n > right )
- {
- BidirectionalIterator m = (BidirectionalIterator) first.clone();
- m.advance( right );
- BidirectionalIterator q = (BidirectionalIterator) m.clone();
-
- while( !m.equals( last ) )
- pushBack( m.nextElement() );
-
- for( int j = left; j < oldSize; j++ )
- pushBack( at( j ) );
-
- Copying.copy( first, q, myStart.copy( left ) );
- }
- else
- {
- int index = oldSize - n;
-
- for( int j = index; j < oldSize; j++ )
- pushBack( at( j ) );
-
- DequeIterator i = myStart.copy( left );
- Copying.copyBackward( i, myStart.copy( index ), myStart.copy( oldSize) );
- Copying.copy( first, last, myStart.copy( left ) );
- }
- }
- }
-
- /**
- * Remove all elements that match a particular object and return the numbers of
- * objects that were removed.
- * @param object The object to remove.
- */
- public int remove( Object object )
- {
- return remove( 0, myLength - 1, object );
- }
-
- /**
- * Remove all elements within a range of indices that match a particular object
- * and return the number of objects that were removed.
- * @param first The index of the first object to consider.
- * @param last The index of the last object to consider.
- * @param object The object to remove.
- * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
- */
- public synchronized int remove( int first, int last, Object object )
- {
- if( last < first )
- return 0;
-
- checkRange( first, last );
- DequeIterator firstx = myStart.copy( first );
- DequeIterator lastx = myStart.copy( last + 1 );
- DequeIterator finish = (DequeIterator) Removing.remove( firstx, lastx, object );
- int n = finish.distance( lastx );
- remove( finish, lastx );
- return n;
- }
-
- /**
- * Replace all elements that match a particular object with a new value and return
- * the number of objects that were replaced.
- * @param oldValue The object to be replaced.
- * @param newValue The value to substitute.
- */
- public synchronized int replace( Object oldValue, Object newValue )
- {
- return Replacing.replace( this, oldValue, newValue );
- }
-
- /**
- * Replace all elements within a range of indices that match a particular object
- * with a new value and return the number of objects that were replaced.
- * @param first The index of the first object to be considered.
- * @param last The index of the last object to be considered.
- * @param oldValue The object to be replaced.
- * @param newValue The value to substitute.
- * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
- */
- public synchronized int replace( int first, int last, Object oldValue, Object newValue )
- {
- if( last < first )
- return 0;
-
- checkRange( first, last );
- return Replacing.replace( myStart.copy( first ), myStart.copy( last + 1 ), oldValue, newValue );
- }
-
- /**
- * Return the number of objects that match a particular value.
- * @param object The object to count.
- */
- public synchronized int count( Object object )
- {
- return Counting.count( this, object );
- }
-
- /**
- * Return the number of objects within a particular range of indices that match a
- * particular value.
- * @param first The index of the first object to consider.
- * @param last The index of the last object to consider.
- * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
- */
- public synchronized int count( int first, int last, Object object )
- {
- if( last < first )
- return 0;
-
- checkRange( first, last );
- return Counting.count( myStart.copy( first ), myStart.copy( last + 1 ), object );
- }
-
- /**
- * Return the index of the first object that matches a particular value, or -1
- * if the object is not found.
- * @param object The object to find.
- */
- public synchronized int indexOf( Object object )
- {
- DequeIterator i = (DequeIterator) Finding.find( myStart, myFinish, object );
- return i.atEnd() ? -1 : myStart.distance( i );
- }
-
- /**
- * Return the index of the first object within a range of indices that match a
- * particular object, or -1 if the object is not found.
- * @param first The index of the first object to consider.
- * @param last The index of the last object to consider.
- * @param object The object to find.
- * @exception java.lang.IndexOutOfBoundsException If either index is invalid.
- */
- public synchronized int indexOf( int first, int last, Object object )
- {
- if( last < first )
- return -1;
-
- checkRange( first, last );
- DequeIterator end = myStart.copy( last + 1 );
- DequeIterator i = (DequeIterator) Finding.find( myStart.copy( first ), end, object );
- return i.equals( end ) ? -1 : myStart.distance( i );
- }
-
- /**
- * Return true if I contain a particular object.
- * @param object The object in question.
- */
- public boolean contains( Object object )
- {
- return indexOf( object ) != -1;
- }
-
- private void growMap()
- {
- // Create space for new map that is twice the size of the current map.
- int newMapSize = myMap.length * 2;
- Object[][] tmp = new Object[ newMapSize ][];
-
- // Copy the old map to the new map.
- int i = newMapSize / 4;
- int count = myFinish.myMapIndex - myStart.myMapIndex + 1;
- System.arraycopy( myMap, myStart.myMapIndex, tmp, i, count );
-
- // Update the start, finish, and map variables.
- myFinish.myMapIndex = i;
- myStart.myMapIndex = i + count - 1;
- myMap = tmp;
- }
-
- private void createMap()
- {
- myMap = new Object[ Allocator.pageSize() ][];
- int mapIndex = myMap.length / 2;
- myMap[ mapIndex ] = new Object[ BLOCK_SIZE ];
- int blockIndex = BLOCK_SIZE / 2;
- myStart.myBlockIndex = blockIndex;
- myStart.myMapIndex = mapIndex;
- myFinish.myBlockIndex = blockIndex;
- myFinish.myMapIndex = mapIndex;
- }
-
- private void checkRange( int lo, int hi )
- {
- if( lo < 0 || lo >= myLength )
- throw new IndexOutOfBoundsException( "Attempt to access index " + lo + " when valid range is 0.." + (myLength - 1) );
-
- if( hi < 0 || hi >= myLength )
- throw new IndexOutOfBoundsException( "Attempt to access index " + hi + " when valid range is 0.." + (myLength - 1) );
- }
- }
-
-