//
// $Id: Deque.h,v 1.32 2007/03/06 20:42:19 will_mason Exp $
//
// vi: set ft=objc:

/*
 * ObjectiveLib - a library of containers and algorithms for Objective-C
 *
 * Copyright (c) 2004-2007
 * 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(DEQUE_OL_GUARD)
#define DEQUE_OL_GUARD

#include <ObjectiveLib/Iterator.h>

/**
 * @class OLDequeIterator Deque.h ObjectiveLib/Deque.h
 *
 * An iterator that knows about double-ended queues. This is a basic
 * random access iterator that is specialized to understand queues.
 *
 * @sa OLDeque
 *
 * @ingroup Iterators
 */
@interface OLDequeIterator : OLRandomAccessIterator
{
@protected
    /**
     * The current object in view.
     */
    id*     current;

    /**
     * The first valid item in this node of the deque.
     */
    id*     first;

    /**
     * The last valid item in this node of the deque.
     */
    id*     last;

    /**
     * The node currently in view.
     */
    id**    node;
}

- (id) advance;
- (id) advanceBy: (int)count;
- (id) assign: (id)object;
#if defined(OL_NO_OPENSTEP)
- (id) copy;
#else
- (id) copyWithZone: (NSZone*)zone;
#endif
- (id) dereference;
- (int) difference: (OLRandomAccessIterator*)other;
- (BOOL) isEqual: (id)object;
- (id) reverse;

@end

/**
 * @class OLDeque Deque.h ObjectiveLib/Deque.h
 *
 * A double-ended queue. A double-ended queue is similar to a @ref OLVector "vector"
 * or array, except that its storage is additionally optimized for insertion and removal
 * from the beginning of the sequence as well as from the end. It provides random
 * access to its elements. It also serves as a suitable container for use by
 * OLBackInsertIterator, OLFrontInsertIterator and OLInsertIterator.
 *
 * @sa OLDequeIterator
 *
 * @ingroup Containers
 */
@interface OLDeque :
#if defined(OL_NO_OPENSTEP)
    Object <OLBackInserter, OLFrontInserter, OLInserter, OLStreamable>
#else
    NSObject  <OLBackInserter, OLFrontInserter, OLInserter, OLStreamable, NSCopying, NSCoding>
#endif
{
@protected
    /**
     * The beginning of the sequence
     */
    OLDequeIterator*    start;

    /**
     * The end of the sequence
     */
    OLDequeIterator*    finish;

    /**
     * The map of deque nodes
     */
    id**                map;

    /**
     * The number of nodes
     */
    unsigned            mapSize;
}

/**
 * Create and return a new deque. The deque is empty.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @return a new deque
 */
+ (id) deque;

/**
 * Create and return a new deque. The deque is initialized with the contents of
 * the range <tt>[first, last)</tt>.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @param first the first in the range of elements to insert
 * @param last one beyond the last in the range of elements to insert
 * @return a new deque
 */
+ (id) dequeFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last;

/**
 * Create and return a new deque. The deque is initialized with the contents of
 * @a right.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @param right the deque with which to initialize the new one
 * @return a new deque
 */
+ (id) dequeWithDeque: (OLDeque*)right;

/**
 * Create and return a new deque. The deque is initialized with a size of @a size
 * and is filled with @a value.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @param size the number of elements to insert
 * @param value the object to be copied
 * @return a new deque
 */
+ (id) dequeWithSize: (unsigned)size filledWith: (id)value;

/**
 * @name Initializers and Deallocators
 */
/* @{ */
/**
 * Initialize the deque. The deque begins life empty.
 *
 * @return a reference to this deque
 */
- (id) init;

/**
 * Initialize the deque. The deque inserts all
 * elements referred to in the range <tt>[first, last)</tt>.
 *
 * @param first the first in the range of elements to insert
 * @param last one beyond the last in the range of elements to insert
 * @return a reference to this deque
 */
- (id) initFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last;

#if !defined(OL_NO_OPENSTEP)
/**
 * Initialize the deque. This initializer creates a new deque
 * from an archive and returns it.
 *
 * @post The deque returned will be identical to the deque
 * saved to the archive using the #encodeWithCoder: message.
 *
 * @param decoder the coder which will decode the archived deque
 * @return a reference to this deque
 */
- (id) initWithCoder: (NSCoder*)decoder;
#endif

/**
 * Initialize the deque. The deque is initialized with the contents of the give deque.
 *
 * @param deque the deque to copy
 * @return a reference to this deque
 */
- (id) initWithDeque: (OLDeque*)deque;

- (id) initWithObjectInStream: (OLObjectInStream*)stream;

/**
 * Initialize the deque. The initial size of the deque will be @a count, and @a value
 * will be copied into the deque @a count times.
 *
 * @param count the number of elements to insert
 * @param value the object to be copied
 * @return a reference to this deque
 */
- (id) initWithSize: (unsigned)count filledWith: (id)value;

/**
 * Finalize the deque and deallocate any allocated memory.
 */
#if defined(OL_NO_OPENSTEP)
- (id) free;
#else
- (void) dealloc;
#endif
/* @} */

/**
 * Assign objects to the deque. The current contents of the deque are removed,
 * and the deque is filled with @a count elements of @a value.
 *
 * @param count the number of elements to assign
 * @param value the object to be copied into the deque
 */
- (void) assign: (unsigned)count filledWith: (id)value;

/**
 * Assign @a object to the position at @a index. The object currently in possession
 * of the position at @a index is removed and replaced with @a object.
 *
 * @note The range of the deque is not checked prior to performing this operation.
 * Using values of @a index that do not lie within the deque's range will produce
 * undefined results.
 *
 * @param index the index to which to assign
 * @param object the object to put at @a index
 */
- (void) assignAt: (unsigned)index value: (id)object;

/**
 * Assign a range of objects to the deque. The current contents of the deque are
 * removed, and all elements in the range <tt>[first, last)</tt> are inserted
 * into the deque.
 *
 * @param first the first in the range of objects to assign
 * @param last one beyond the last in the range of objects to assign
 */
- (void) assignFrom: (OLForwardIterator*)first to: (OLForwardIterator*)last;

/**
 * Return the object at @a index. A reference to the object is returned, though
 * the deque still owns the object in question.
 *
 * @note The range of the deque is not checked prior to performing this operation.
 * Using values of @a index that do not lie within the deque's range will produce
 * undefined results.
 *
 * @param index the index of the object to look up
 * @return a reference to the object at @a index
 */
- (id) at: (unsigned)index;

/**
 * Return the last object in the deque. A reference to the object is returned, though
 * the deque still owns the object in question.
 *
 * @note The behavior of this message is undefined if the deque is empty.
 *
 * @return the last object
 */
- (id) back;

/**
 * Return an iterator pointing to the beginning of the sequence.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @return an iterator pointing to the first element
 */
- (OLDequeIterator*) begin;

/**
 * Remove all elements.
 */
- (void) clear;

/**
 * Compare this deque to another object. If the other object is of type OLDeque, each
 * of the contained objects is compared to the corresponding object in @a other by
 * calling the @c compare: method.
 *
 * @param other the object with which to compare this one
 * @return a value greater than, equal to, or less than zero accoringly as this object
 * is greater than, equal to, or less than @a other
 */
- (int) compare: (id)other;

#if defined(OL_NO_OPENSTEP)
/**
 * Make a copy of this deque.
 *
 * @return the copy
 */
- (id) copy;
#else
/**
 * Make a copy of this deque allocating memory from the given zone.
 *
 * @param zone the zone from which to allocate memory
 * @return the copy
 */
- (id) copyWithZone: (NSZone*)zone;
#endif

/**
 * Test whether the deque is empty.
 *
 * @return YES if the deque is empty, NO otherwise
 */
- (BOOL) empty;

#if !defined(OL_NO_OPENSTEP)
/**
 * Encode the deque. The deque is saved to an archive using @a encoder. The deque
 * will be retrieved from the archive using the initializer #initWithCoder:.
 *
 * @param encoder the coder which will save the bit set to the archive
 */
- (void) encodeWithCoder: (NSCoder*)encoder;
#endif

/**
 * Return an iterator pointing to one position beyond the end of the sequence.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @return an iterator pointing to one position beyond the last element
 */
- (OLDequeIterator*) end;

/**
 * Remove the element designated by @a where.
 *
 * @pre @a where must point to an element in this deque.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @param where an iterator designating the element to remove
 * @return an iterator indicating the next element in the sequence remaining after @a where
 */
- (OLDequeIterator*) erase: (OLDequeIterator*)where;

/**
 * Remove a range of elements. All elements in the range <tt>[first, last)</tt> will
 * be removed from the deque.
 *
 * @pre @a first and @a last must refer to elements in this deque.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @param first the first in the range of elements to remove
 * @param last one position beyond the last in the range of elements to remove
 * @return an iterator indicating the next element in the sequence remaining after
 * removal of the range
 */
- (OLDequeIterator*) eraseFrom: (OLDequeIterator*)first to: (OLDequeIterator*)last;

/**
 * Return the first object in the deque. A reference to the object is returned, though
 * the deque still owns the object in question.
 *
 * @note The behavior of this message is undefined if the deque is empty.
 *
 * @return the first object
 */
- (id) front;

/**
 * Insert a number of objects into the deque. @a num objects of @a value will be inserted
 * just before the position referred to by @a where. Thus, it is valid to use an iterator returned
 * by #end as an argument.
 *
 * @pre @a where must refer to a position in this deque
 *
 * @param where the position at which to insert the objects
 * @param num the number of objects to insert
 * @param value the object to be copied into the deque
 */
- (void) insertAt: (OLDequeIterator*)where count: (unsigned)num filledWith: (id)value;

/**
 * Insert a range of objects into the deque. All objects in the range <tt>[first, last)</tt>
 * are inserted just before the position referred to by @a where. Thus, it is valid to
 * use an iterator returned by #end as an argument.
 *
 * @param where the position at which to insert the objects
 * @param first the first in the range of objects to insert
 * @param last one position beyond the last in the range of objects to insert
 */
- (void) insertAt: (OLDequeIterator*)where from: (OLForwardIterator*)first to: (OLForwardIterator*)last;

/**
 * Insert an object into the deque. The @a object will be inserted just before the
 * position referred to by @a where. Thus, it is valid to use an iterator returned
 * by #end as an argument.
 *
 * @pre @a where must refer to a position in this deque
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @param where the position at which to insert @a object
 * @param object the object to insert
 * @return an iterator pointing to the newly inserted object
 */
- (OLDequeIterator*) insertAt: (OLDequeIterator*)where value: (id)object;

/**
 * Return whether this deque is equal to another one. Two deques are considered equal
 * if they both contain the same number of objects that all return YES to the message
 * @c isEqual: and they are in the same order.
 *
 * @param object the object to test
 * @return YES if @a object is equal to this deque
 */
- (BOOL) isEqual: (id)object;

/**
 * Return the maxiumum number of objects that can be stored in a deque. This limit is
 * theoretical, meaning that there is no guarantee that you can insert this many
 * objects into any given deque. The memory conditions of the run-time system play an
 * important role.
 *
 * @return the maximum number of objects for a deque
 */
- (unsigned) maxSize;

/**
 * Remove the last element in the deque.
 *
 * @note If there are no elements in the deque, then the behavior of this message
 * is undefined.
 */
- (void) popBack;

/**
 * Remove the first element in the deque.
 *
 * @note If there are no elements in the deque, then the behavior of this message
 * is undefined.
 */
- (void) popFront;

/**
 * Insert @a object at the end of the sequence.
 *
 * @param object the object to insert
 */
- (void) pushBack: (id)object;

/**
 * Insert @a object at the beginning of the sequence.
 *
 * @param object the object to insert
 */
- (void) pushFront: (id)object;

/**
 * Return a reverse iterator pointing to the end of the sequence. Advancing the returned
 * iterator will move backwards through the sequence to the point indicated by the
 * iterator returned by #rend.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @return a reverse iterator for the end of the sequence
 */
- (OLReverseRandomIterator*) rbegin;

/**
 * Return a reverse iterator pointing to the beginning of the sequence. This iterator
 * indicates one position beyond the last position that may be referenced by a
 * reverse iterator.
 *
 * @note If OpenStep is present the returned object will be autoreleased
 * before being returned.
 *
 * @return a reverse iterator for the beginning of the sequence
 */
- (OLReverseRandomIterator*) rend;

/**
 * Resize the deque to @a newsize. If @a newsize is smaller than the current #size, then
 * the sequence will be truncated. If @a newsize is larger than the current #size,
 * then @a value will be inserted at the end of the deque as many times as necessary
 * to fill the new size.
 *
 * @param newsize the new size of the deque
 * @param value the value with which to fill new elements, if necessary
 */
- (void) resize: (unsigned)newsize filledWith: (id)value;

/**
 * Return the number of elements in the deque.
 *
 * @return the number of elements
 */
- (unsigned) size;

/**
 * Swap this deque with another one. All elements in @a right will be placed into
 * this deque, and all elements in this deque will be placed in @a right.
 *
 * @param right the deque with which to swap this one
 */
- (void) swap: (OLDeque*)right;

- (void) writeSelfToStream: (OLObjectOutStream*)stream;

@end

#endif
