//
// $Id: Iterator.h,v 1.33 2005/07/12 19:15:37 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004
 * Will Mason
 *
 * Portions:
 *
 * Copyright (c) 1994
 * Hewlett-Packard Company
 *
 * Copyright (c) 1996,1997
 * Silicon Graphics Computer Systems, Inc.
 *
 * Copyright (c) 1997
 * Moscow Center for SPARC Technology
 *
 * Copyright (c) 1999 
 * Boris Fomitchev
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * You may contact the author at will_mason@users.sourceforge.net.
 */

#if !defined(ITERATOR_OL_GUARD)
#define ITERATOR_OL_GUARD

#import <ObjectiveLib/Copying.h>
#import <ObjectiveLib/Pair.h>

/**
 * @defgroup Iterators
 *
 * Iterators are used to access members of container classes. There are various
 * types of iterators that provide functionality that can vary depending on
 * the type of container to which the iterator refers. Iterator types differ
 * in the type of movement between elements that is allowed. All iterators provide
 * the ability to access the element to which the iterator points and to
 * assign a new value to the element. Additionally, they may provide forward
 * stepwise motion, backward stepwise motion or arbitrary motion in either
 * direction.
 *
 * One of the primary uses of iterators is to allow @ref OLAlgorithm "algorithms" to
 * operate generically on containers of various types. Most @ref OLAlgorithm "algorithms" take
 * ranges defined by two iteratos as arguments, and perform their operations by
 * traversing the underlying collection. Thus, @ref OLAlgorithm "algorithms" do
 * not have to be aware of details of the data structure on which they are
 * operating.
 *
 * Iterator ranges are by convention expressed by two iterators, @a first and
 * @a last, and the range covers all elements in <tt>[first, last)</tt>. That is,
 * the range includes the first element, but not the last element. Therefore,
 * a typical way of visiting every element in a given range is as follows. Assume
 * that the @ref OLVector "vector" in the following example has already been
 * initialized.
 * @code
OLVector* v;
OLForwardIterator* cur;
OLForwardIterator* end;
id value;

for (cur = [v begin], end = [v end]; ![cur isEqual: end]; [cur advance])
{
    value = [cur dereference];
    // Do something with value...
}
 * @endcode
 * <h3>Memory Management</h3>
 *
 * Iterators never retain or attempt to maintain ownership of the container into which
 * they point. Therefore, it is impossible to dispose of a container and continue
 * to use an iterator that refers to it.
 */

/**
 * @defgroup InsertIterators Insert Iterators
 *
 * Insert iterators are a special type of iterator that can insert elements into
 * a @ref Containers "container". A primary use of insert iterators is with
 * @ref Algorithms "algorithms" that copy elements to a destination range.
 * Rather than providing a valid range as the destination for the algorithm,
 * an insert iterator can be used with an initially empty container, and the algorithm
 * will insert new elements into the container. There are three types of insert
 * iterator for inserting elements at the front, at the back, and at an arbitrary
 * location in the container.
 *
 * @ingroup Iterators
 */

/**
 * @class OLIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * An abstract base class for iterators. Iterators exist to travsere
 * the objects that are held in containers. All iterators share the ability
 * retrieve a reference to the object to which they point and to assign
 * an object to the iterator's position in its container. How they differ
 * is in how they are able to move through their containers. Some iterators
 * can only go forward (OLForwardIterator), some can go forward and backward
 * (OLBidirectionalIterator), and some can move at will (OLRandomAccessIterator).
 * Additionally there are specialized iterators for inserting elements into
 * a container (rather than simply assigning to elements already in the
 * container) and for reversing the motion of other iterators.
 *
 * Note that by convention a pair of iterators @c first and @c last describing
 * a range of elements refers to the range <tt>[first, last)</tt>. That is,
 * the last iterator points to a position one step beyond the range under
 * consideration.
 *
 * @ingroup Iterators
 */
@interface OLIterator : NSObject <OLCopying>
{
}

/**
 * Advance the iterator by a certain distance. The message tests the iterator
 * for its type and chooses the most efficient method available for advancing
 * the iterator. If the iterator is not a type of OLRandomAccessIterator,
 * then its advance or reverse messages will simply be sent enough to times
 * to complete the operation. If the iterator cannot support the operation,
 * for example if @a count is negative and the iterator is not a
 * OLBidirectionalIterator, then the message will simply return.
 *
 * @param itor the iterator to advance
 * @param count the number of positions to advance (or reverse) the iterator
 */
+ (void) advanceIterator: (OLIterator*)itor distance: (int)count;

/**
 * Compute the distance that exists between two iterators. This message simply
 * sends the message #distanceFrom:to:allocator: using the default allocator.
 *
 * @param first the first in the series
 * @param last the last in the series
 * @return the distance from @a first to @a last
 */
+ (unsigned) distanceFrom: (OLIterator*)first to: (OLIterator*)last;

/**
 * Compute the distance that exists between two iterators. The distance is computed
 * using the most efficient means possible given the type of iterator. For example,
 * random access iterators can compute distances in one step, while forward iterators
 * must be advance multiple times to find a distance. If the iterators are not
 * random access iterators, then a copy of @a first will be made using @a allocator
 * and discarded after the distance has been computed.
 *
 * @pre The iterators must refer to the same container and @a first must be before
 * @a last in the sequence.
 *
 * @param first the first in the series
 * @param last the last in the series
 * @param allocator the allocator to use for allocating a copy of @a first
 * @return the distance from @a first to @a last
 */
+ (unsigned) distanceFrom: (OLIterator*)first to: (OLIterator*)last allocator: (OLAllocator*)allocator;

/**
 * Assign an object to the position in the controlled sequence to which this
 * iterator refers. The object currently at the position will be removed and
 * replaced with the given object.
 *
 * @param object the object to assign
 * @return a reference to this iterator
 */
- (id) assign: (id)object;
- (id) copyWithAllocator: (OLAllocator*)alloc;
- (id) copyWithZone: (NSZone*)zone;

/**
 * Dereference the iterator. Return the id of the object to which this iterator points.
 *
 * @return the id of the referenced object
 */
- (id) dereference;

/**
 * Return whether this object is equal to another one.
 *
 * @param object the object to test
 * @return YES if the iterator is equal to the object, NO if not
 */
- (BOOL) isEqual: (id)object;

@end

/**
 * @class OLForwardIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * An iterator that can go forward one step at a time. This is an abstract class;
 * the default implementation of #advance does nothing.
 *
 * @ingroup Iterators
 */
@interface OLForwardIterator : OLIterator
{
}

/**
 * Advance the iterator. After advancing the iterator will point to a position
 * in the container one step beyond the previous position.
 *
 * @return a reference to this iterator
 */
- (id) advance;

@end

/**
 * @class OLBidirectionalIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * An iterator that can traverse a collection both forwards and backwards. This
 * is an abstract class; the default implementation of #reverse does nothing.
 *
 * @ingroup Iterators
 */
@interface OLBidirectionalIterator : OLForwardIterator
{
}

/**
 * Reverse the iterator by one position. After reversing the iterator will point to
 * a position in the container one step before the previous position.
 *
 * @return a reference to this iterator
 */
- (id) reverse;

@end

/**
 * @class OLRandomAccessIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * An iterator that provides random access. The iterator can be made to
 * refer to any member of a collection with one operation.
 *
 * @ingroup Iterators
 */
@interface OLRandomAccessIterator : OLBidirectionalIterator
{
}

/**
 * Advance or reverse the iterator by a given number of positions.
 *
 * @param count the number of positions to move the iterator, either forward
 * or backward
 * @return a reference to this iterator
 */
- (id) advanceBy: (int)count;

/**
 * Compute the number of positions that lie between this iterator and another
 * one. If @a other is after this iterator in the collection, the result will
 * be negative, otherwise the result will be greater than or equal to zero..
 *
 * @pre Both iterators must refer to the same collection.
 *
 * @param other the iterator for which to compute the distance from this one
 * @return the number of positions that lie between this iterator and the other
 * one
 */
- (int) difference: (OLRandomAccessIterator*)other;

@end

/**
 * @class OLReverseBidiIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * A class to reverse the behavior of a given iterator. All operations are
 * performed on the the iterator that is passed to this iterator. However,
 * they are reversed: #advance causes the target iterator to reverse, and
 * so forth.
 *
 * @ingroup Iterators
 */
@interface OLReverseBidiIterator : OLBidirectionalIterator
{
@protected
    /**
     * The target iterator on which this iterator performs its operations.
     */
    OLBidirectionalIterator* current;
}

/**
 * @name Initializers and Deallocators
 */
/* @{ */

/**
 * Initialize the iterator with its target.
 *
 * @param itor the iterator on which to perform operations
 * @return a reference to this iterator
 */
- (id) initWithIterator: (OLBidirectionalIterator*)itor;

/**
 * Finalize the iterator and deallocate any allocated memory.
 */
- (void) dealloc;

/* @} */

/**
 * Advance the iterator. This has the effect of reversing the underlying
 * target iterator by one step.
 *
 * @return a reference to this iterator
 */
- (id) advance;

- (id) assign: (id)object;
- (id) copyWithAllocator: (OLAllocator*)alloc;
- (id) copyWithZone: (NSZone*)zone;
- (id) dereference;
- (BOOL) isEqual: (id)object;

/**
 * Reverse the iterator. This has the effect of advancing the underlying
 * target iterator by one step.
 *
 * @return a reference to this iterator
 */
- (id) reverse;

@end

/**
 * @class OLReverseRandomIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * A class to reverse the behavior of a given iterator. All operations are
 * performed on the the iterator that is passed to this iterator. However,
 * they are reversed: #advance causes the target iterator to reverse, and
 * so forth.
 *
 * @ingroup Iterators
 */
@interface OLReverseRandomIterator : OLReverseBidiIterator
{
}

/**
 * Advance or reverse the iterator by a given number of positions. This has the
 * effect of advancing or reversing the underlying target iterator by the
 * negation of @a count.
 *
 * @param count the number of positions to move the iterator, either forward
 * or backward
 * @return a reference to this iterator
 */
- (id) advanceBy: (int)count;
- (id) copyWithAllocator: (OLAllocator*)alloc;
- (id) copyWithZone: (NSZone*)zone;
- (BOOL) isEqual: (id)object;

@end

/**
 * @protocol OLBackInserter Iterator.h ObjectiveLib/Iterator.h
 *
 * A type of object that supports inserting objects at the back of
 * the controlled sequence. OLBackInserter objects are used to
 * support the insertion behavior of OLBackInsertIterator, and any
 * object that supports this protocol may be used as the container
 * with a OLBackInsertIterator.
 *
 * @sa OLBackInsertIterator, OLDeque, OLList, OLVector
 */
@protocol OLBackInserter

/**
 * Test whether a given object is equal to this one. The meaning of equality
 * depends on the type of object implementing this protocol.
 *
 * @param object the object to test
 * @return YES if this object is equal to the given one, NO if not
 */
- (BOOL) isEqual: (id)object;

/**
 * Insert a given object at the back of the controlled sequence. The object
 * is added to the collection in a manner dependent on the type of object
 * implementing this protocol.
 *
 * @param object the object to add to the controlled sequence
 */
- (void) pushBack: (id)object;

@end

/**
 * @class OLBackInsertIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * An iterator that can be used to insert items into a container. The iterator's
 * #assign: message inserts the object to be assigned at the back of the
 * container.
 *
 * @ingroup InsertIterators
 */
@interface OLBackInsertIterator : OLForwardIterator
{
@protected
    /**
     * The container into which items will be inserted by the #assign: message.
     */
    id<OLBackInserter> container;
}

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the iterator with the given container. All insertions will be
 * performed using the given container.
 *
 * @pre The container must support the OLBackInserter protocol.
 *
 * @param cnr the container that implements the OLBackInserter protocol
 * into which to insert items
 * @return a reference to this iterator
 */
- (id) initWithBackInserter: (id<OLBackInserter>)cnr;
/* @} */

/**
 * Insert @a object at the back of the underlying container.
 *
 * @param object the object to insert
 * @return a reference to this iterator
 */
- (id) assign: (id)object;
- (id) copyWithAllocator: (OLAllocator*)alloc;
- (id) copyWithZone: (NSZone*)zone;
- (BOOL) isEqual: (id)object;

@end

/**
 * @protocol OLFrontInserter Iterator.h ObjectiveLib/Iterator.h
 *
 * A type of object that supports inserting objects at the front of
 * the controlled sequence. OLFrontInserter objects are used to
 * support the insertion behavior of OLFrontInsertIterator, and any
 * object that supports this protocol may be used as the container
 * with a OLFrontInsertIterator.
 *
 * @sa OLFrontInsertIterator, OLDeque, OLList
 */
@protocol OLFrontInserter

/**
 * Test whether a given object is equal to this one. The meaning of equality
 * depends on the type of object implementing this protocol.
 *
 * @param object the object to test
 * @return YES if this object is equal to the given one, NO if not
 */
- (BOOL) isEqual: (id)object;

/**
 * Insert a given object at the front of the controlled sequence. The object
 * is added to the collection in a manner dependent on the type of object
 * implementing this protocol.
 *
 * @param object the object to add to the controlled sequence
 */
- (void) pushFront: (id)object;

@end

/**
 * @class OLFrontInsertIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * An iterator that can be used to insert items into a container. The iterator's
 * #assign: message inserts the object to be assigned at the front of the
 * container.
 *
 * @ingroup InsertIterators
 */
@interface OLFrontInsertIterator : OLForwardIterator
{
@protected
    /**
     * The container into which items will be inserted by the #assign: message.
     */
    id<OLFrontInserter> container;
}

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the iterator with the given container. All insertions will be
 * performed using the given container.
 *
 * @pre The container must support the OLFrontInserter protocol.
 *
 * @param cnr the container that implements the OLFrontInserter protocol
 * into which to insert items
 * @return a reference to this iterator
 */
- (id) initWithFrontInserter: (id<OLFrontInserter>)cnr;
/* @} */

/**
 * Insert @a object at the front of the underlying container.
 *
 * @param object the object to insert
 * @return a reference to this iterator
 */
- (id) assign: (id)object;
- (id) copyWithAllocator: (OLAllocator*)alloc;
- (id) copyWithZone: (NSZone*)zone;
- (BOOL) isEqual: (id)object;

@end

/**
 * @protocol OLInserter Iterator.h ObjectiveLib/Iterator.h
 *
 * A type of object that can insert values at a certain position in the
 * controlled sequence. OLInserter objects are used to support the insertion
 * behavior of OLInsertIterator, and any object that supports this protocol
 * may be used as the container with a OLInsertIterator.
 *
 * @sa OLInsertIterator, OLDeque, OLList, OLMap, OLSet, OLVector
 */
@protocol OLInserter

/**
 * Insert a given object at the given position in the container.
 *
 * @param where the position at which to insert the new object
 * @param object the object to insert
 * @return an iterator that points to the newly added object
 */
- (OLIterator*) insertAt: (OLIterator*)where value: (id)object;

/**
 * Test whether a given object is equal to this one. The meaning of equality
 * depends on the type of object implementing this protocol.
 *
 * @param object the object to test
 * @return YES if this object is equal to the given one, NO if not
 */
- (BOOL) isEqual: (id)object;

@end

/**
 * @class OLInsertIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * An iterator that can be used to insert items into a container. The iterator's
 * #assign: message inserts the object to be assigned at the position identified
 * by another iterator that is passed during intialization. The insertion will
 * always take place just before the last point of insertion.
 *
 * @ingroup InsertIterators
 */
@interface OLInsertIterator : OLForwardIterator
{
@protected
    /**
     * The container into which to insert items.
     */
    id<OLInserter>      container;

    /**
     * An iterator for keeping track of where the next insertion should
     * take place.
     */
    OLForwardIterator*  iterator;
}

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the iterator with the given container and iterator. The container
 * is the target of future insertions, and the iterator shows where in the
 * container insertion should begin.
 *
 * @pre The iterator, @a itor, must refer to a position in the container, @a cnr.
 *
 * @param cnr the container into which to insert items
 * @param itor the iterator showing the location of the first insertion
 * @return a reference to this iterator
 */
- (id) initWithInserter: (id<OLInserter>)cnr iterator: (OLForwardIterator*)itor;
/**
 * Finalize the iterator and deallocate any allocated memory.
 */
- (void) dealloc;
/* @} */

/**
 * Insert @a object just before the last insertion, or just before the iterator
 * passed to the initializer if it is the first insertion.
 *
 * @param object the object to insert
 * @return a reference to this iterator
 */
- (id) assign: (id)object;
- (id) copyWithAllocator: (OLAllocator*)alloc;
- (id) copyWithZone: (NSZone*)zone;
- (BOOL) isEqual: (id)object;

@end

/**
 * @internal Node of a red-black tree used to implement the underlying data structure
 * behind sets and maps.
 *
 */
@class OLTreeNode;

/**
 * @class OLAssociativeIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * An iterator for traversing associative containers like sets and
 * maps. This is a basic bidirectional iterator that knows how to
 * find its way around associative containers.
 *
 * @sa OLMap, OLMultiMap, OLSet, OLMultiSet
 *
 * @ingroup Iterators
 */
@interface OLAssociativeIterator : OLBidirectionalIterator
{
@private
    /**
     * The node to which this iterator currently points. This member is
     * private because OLTreeNode is a class for internal use only, and
     * has no public API.
     */
    OLTreeNode* node;
}

- (id) advance;
- (id) assign: (id)object;
- (id) copyWithAllocator: (OLAllocator*)alloc;
- (id) copyWithZone: (NSZone*)zone;
- (id) dereference;
- (BOOL) isEqual: (id)object;
- (id) reverse;

@end

/**
 * @class OLArrayIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * An iterator that can traverse arrays of objects. This is a random
 * access iterator that can be used to traverse arbitrary arrays of
 * ids.
 *
 * @sa OLVector
 *
 * @ingroup Iterators
 */
@interface OLArrayIterator : OLRandomAccessIterator
{
@protected
    /**
     * The object to which this iterator currently points.
     */
    id* current;
}

/**
 * Return a pair of array iterators. This message is the same as
 * #pairWithPointer:andPointer:allocator: but uses the default allocator
 * instead of a given one.
 *
 * @param p1 the first pointer in the range covered by the pair
 * @param p2 the second pointer in the range covered by the pair
 * @return a pair of iterators covering the given range
 */
+ (OLPair*) pairWithPointer: (id*)p1 andPointer: (id*)p2;

/**
 * Return a pair of array iterators. The iterators and pair returned are
 * allocated using the given allocator and can be used in operations
 * that require iterators covering a range of objects.
 *
 * Note that the message will attempt to autorelease the returned pair. This
 * will only occur if the platform and allocator both support autorelease.
 *
 * @sa OLAlgorithm, OLAllocator
 *
 * @param p1 the first pointer in the range covered by the pair
 * @param p2 the second pointer in the range covered by the pair
 * @param alloc the allocator to use to allocate the pair and the two iterators
 * @return a pair of iterators covering the given range
 */
+ (OLPair*) pairWithPointer: (id*)p1 andPointer: (id*)p2 allocator: alloc;

/**
 * Return a pair of array iterators. This message is the same as
 * #pairWithPointer:distance:allocator: but uses the default allocator
 * instead of a given one.
 *
 * @param p the pointer at the beginning of the desired range
 * @param count the number of objects that should be included in the range
 * @return a pair of iterators covering the given range
 */
+ (OLPair*) pairWithPointer: (id*)p distance: (unsigned)count;

/**
 * Return a pair of array iterators. The iterators and pair returned are
 * allocated using the given allocator and can be used in operations
 * that require iterators covering a range of objects.
 *
 * Note that the message will attempt to autorelease the returned pair. This
 * will only occur if the platform and allocator both support autorelease.
 *
 * @sa OLAlgorithm, OLAllocator
 *
 * @param p the pointer at the beginning of the desired range
 * @param count the number of objects that should be included in the range
 * @param alloc the allocator to use to allocate the pair and the two iterators
 * @return a pair of iterators covering the given range
 */
+ (OLPair*) pairWithPointer: (id*)p distance: (unsigned)count allocator: alloc;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the iterator with the given pointer. The iterator will not attempt
 * to take ownership of the pointer, as iterators never own the objects to
 * which they point.
 *
 * @param ptr the pointer at the beginning of the array
 * @return a reference to this iterator
 */
- (id) initWithPointer: (id*)ptr;
/* @} */

- (id) advance;
- (id) advanceBy: (int)count;
- (id) assign: (id)object;
- (id) copyWithAllocator: (OLAllocator*)alloc;
- (id) copyWithZone: (NSZone*)zone;
- (id) dereference;
- (int) difference: (OLRandomAccessIterator*)other;
- (BOOL) isEqual: (id)object;
- (id) reverse;

@end

/**
 * @internal A node in a hash table.
 */
struct _OLHashTableNode;

/**
 * @internal A hash table used for the underlying data structure behind all hash table
 * based data structures.
 */
@class OLHashTable;

/**
 * @class OLHashIterator Iterator.h ObjectiveLib/Iterator.h
 *
 * An iterator that knows about hash tables. This is a basic forward iterator
 * that knows enough about hash tables to be able to navigate them.
 *
 * @sa OLHashMap, OLHashMultiMap, OLHashMultiSet, OLHashSet
 *
 * @ingroup Iterators
 */
@interface OLHashIterator : OLForwardIterator
{
@private
    /**
     * The hash table being traversed. This member is private because hash tables
     * are internal structures with no public API.
     */
    OLHashTable*                table;

    /**
     * The hash table node currently in view. This member is private because hash tables
     * are internal structures with no public API.
     */
    struct _OLHashTableNode*    current;
}

- (id) advance;
- (id) assign: (id)object;
- (id) copyWithAllocator: (OLAllocator*)alloc;
- (id) copyWithZone: (NSZone*)zone;
- (id) dereference;
- (BOOL) isEqual: (id)object;

@end

#endif
