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
/
Deque.java
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Java Source
|
1997-03-14
|
30.3 KB
|
1,006 lines
// Copyright(c) 1996,1997 ObjectSpace, Inc.
// Portions Copyright(c) 1995, 1996 Hewlett-Packard Company.
package COM.objectspace.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 COM.objectspace.jgl.Sequence
* @see COM.objectspace.jgl.examples.DequeExamples
* @version 2.0.2
* @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 )
{
synchronized( 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 )
{
synchronized( deque )
{
return Comparing.equal( this, deque );
}
}
/**
* Return my hash code for support of hashing containers
*/
public synchronized 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;
synchronized( deque )
{
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 )
{
add( object );
return;
}
++myLength;
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 COM.objectspace.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 COM.objectspace.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 ForwardIterator start()
{
return begin();
}
/**
* Return an iterator positioned immediately afer my last item.
*/
public ForwardIterator finish()
{
return end();
}
/**
* Return my first item.
* @exception COM.objectspace.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 COM.objectspace.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 )
{
synchronized( 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.
* @return The object removed.
* @exception java.lang.IndexOutOfBoundsException If the index is invalid.
*/
public synchronized Object remove( int index )
{
if ( index < 0 || index >= myLength )
throw new IndexOutOfBoundsException( "Attempt to access index " + index + " when valid range is 0.." + (myLength - 1) );
return remove( myStart.copy( index ) );
}
/**
* Remove the element at a particular position.
* @param e An Enumeration positioned at the element to remove.
* @return The object removed.
* @exception IllegalArgumentException if the Enumeration isn't a
* DequeIterator for this Deque object.
*/
public synchronized Object 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;
Object retval = pos.get();
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();
}
return retval;
}
/**
* 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.
* @return The number of elements removed.
* @exception java.lang.IndexOutOfBoundsException If either index is invalid.
*/
public synchronized int remove( int first, int last )
{
if ( last < first )
return 0;
checkRange( first, last );
return 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.
* @return The number of elements removed.
* @exception IllegalArgumentException if the Enumeration isn't a
* DequeIterator for this Deque object.
*/
public synchronized int 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 );
int count = n;
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();
}
return count;
}
/**
* 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.
* @return The number of objects removed.
*/
public int remove( Object object )
{
return remove( 0, myLength - 1, object );
}
/**
* Remove at most a given number of elements that match a particular object and return the number of
* objects that were removed.
* @param object The object to remove.
* @param count The maximum number of objects to remove.
* @return The number of objects removed.
*/
public synchronized int remove( Object object, int count )
{
int removed = 0;
while ( count > 0 )
{
int i = indexOf( object );
if ( i >= 0 )
{
--count;
++removed;
remove( i );
}
}
return removed;
}
/**
* 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.
* @return The number of objects removed.
* @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) );
}
}