+#ifndef DOUBLY_LINKED_LIST_CLASS
+#define DOUBLY_LINKED_LIST_CLASS
+
+/*
+* Name : doubly_linked_list
+* Author : Chris Koeritz
+**
+* Copyright (c) 1998-$now By Author. This program is free software; you can
+* redistribute it and/or modify it under the terms of the GNU General Public
+* License as published by the Free Software Foundation; either version 2 of
+* the License or (at your option) any later version. This is online at:
+* http://www.fsf.org/copyleft/gpl.html
+* Please send any updates to: fred@gruntose.com
+*/
+
+namespace nodes {
+
+class node; // forward.
+
+//! Implements a guarded, doubly linked list structure.
+/*!
+ The list is viewed one element at a time, through the monocular of an
+ iterator, which keeps track of the current position in the list. the
+ iterator's cursor can be shifted around at will. nodes can be added to
+ the list before or after the cursor, and the node pointed at by the cursor
+ can be queried or modified. Using multiple iterators is fine as long as
+ you guarantee that they either are all just reading the list or that you
+ have a valid access pattern of reads and writes such that no iterator's
+ cursor is affected. Note that this list is not thread safe.
+*/
+
+
+//hmmm: is this class really for real? it's doing all sorts of stuff with nodes, rather than with the list object itself.
+// consider dropping the current implementation and providing more standard list operations, on an object that is actually using itself in its definition, rather than a different class (node).
+// this would be easy to do if we just break down and define the dl list as a node itself. then we have something to work with.
+
+//current iterator implementation here is bunk.
+
+
+class doubly_linked_list
+{
+public:
+ doubly_linked_list();
+ //!< constructs a blank list.
+
+ ~doubly_linked_list();
+ //!< invalidates all contents of the list and destroys all child nodes.
+
+ int elements() const;
+ //!< returns the number of items currently in the list.
+ /*!< this is a costly operation. */
+
+ bool empty() const;
+ //!< returns true if the list is empty.
+ /*!< this is really quick compared to checking the number of elements. */
+
+ //! iterators allow the list to be traversed.
+ /*! NOTE: it is an error to use an iterator on one list with a different
+ list; the methods will do nothing or return empty results in this
+ situation. */
+
+ class iterator {
+ public:
+ iterator(const doubly_linked_list *mgr, node *start) : _cursor(start), _manager(mgr) {}
+ //!< opens up an iterator on a list.
+ /*!< the preferred method to construct an iterator is to use the
+ head/tail functions in list. */
+
+ void operator ++(); //!< go to next item.
+ void operator --(); //!< go to previous item.
+ void operator ++(int) { ++(*this); } //!< post-fix synonym for ++.
+ void operator --(int) { --(*this); } //!< post-fix synonym for --.
+
+
+ void next() { (*this)++; } //!< synonym for ++.
+ void previous() { (*this)--; } //!< synonyms for --.
+
+ bool operator ==(const iterator &to_compare) const;
+ //!< returns true if the two iterators are at the same position.
+
+ bool is_head() const;
+ //!< returns true if the cursor is at the head of the list.
+ /*!< Note: head() and tail() only return true if the iterator is
+ actually positioned _at_ the head or tail guard. for example, if the
+ cursor is pointing at the last actual element in the list (but not at
+ the guard itself), then is_tail() returns false. so, in iteration,
+ your iterator will actually go past the last valid element before
+ is_tail() returns true. thus it is very important to check is_tail()
+ *before* looking at the node with observe() or access(), since those
+ two will shift the list position to the nearest valid node and away
+ from the guard. */
+ bool is_tail() const;
+ //!< returns true if the cursor is at the tail of the list.
+
+ void jump_head(); //!< set the iterator to the head.
+ void jump_tail(); //!< set the iterator to the tail.
+
+ const node *observe(); //!< peek at the current element.
+ /*!< Note: observe() and access() will return the first element if the
+ list is positioned at the head (or the last if at the tail), and will
+ not return NULL_POINTER for these two positions as long as the list has some
+ elements in it. the cursor will also have been moved to point at the
+ element that is returned.
+ Another Note: it is extremely important that you do not mess with the
+ links owned by the node (or at least the first two links).
+ A Third Note: these two functions can return NULL_POINTER if the list is empty. */
+ node *access(); //!< obtain access to the current element.
+
+ private:
+ node *_cursor; //!< the current position.
+ friend class doubly_linked_list; //!< lists have full access to this object.
+ const doubly_linked_list *_manager; //!< our friendly manager.
+ };
+
+ iterator head() const { return iterator(this, _head); }
+ //!< returns an iterator located at the head of the list.
+ iterator tail() const { return iterator(this, _tail); }
+ //!< returns an iterator located at the tail of the list.
+
+ int index(const iterator &it) const { return items_from_head(it); }
+ //!< returns the zero-based index of the cursor's position from the head.
+ /*!< this is a synonym for items_from_head(). */
+
+ bool set_index(iterator &to_set, int new_index);
+ //!< positions the iterator "to_set" at the index specified.
+
+ // storage and retrieval actions.
+ // Note: all of these methods shift the iterator onto the next valid node
+ // if it is positioned at the beginning or end of the list.
+
+ void append(iterator &where, node *new_node);
+ //!< adds a "new_node" into the list immediately after "where".
+ /*!< the nodes previously following the current node (if any) will follow
+ after the "new_node". this does not change the current position.
+ ownership of "new_node" is taken over by the list. */
+
+ void insert(iterator &where, node *new_node);
+ //!< places a "new_node" immediately before the current node in the list.
+ /*!< the "new_node" will follow the prior precursor to the current node.
+ this does not change the current position. ownership of "new_node"
+ is taken over by the list. after the call, the iterator points at
+ the new node. */
+
+ node *remove(iterator &where);
+ //!< extracts the current item from "where" and repairs the hole.
+ /*!< NULL_POINTER is returned if the list was empty. the current position is set
+ to the node that used to be after the node that has been removed. after
+ the call, the iterator points at the new node. */
+
+ void zap(iterator &where);
+ //!< wipes out the item at "where", including its contents.
+ /*!< the current position is reset to the item after the now defunct
+ item (or the tail). */
+
+ void zap_all();
+ //!< destroys all the list elements and makes the list empty.
+ /*!< any existing iterators will be invalidated by this. */
+
+ // the following positioning functions could fail if the request is out of
+ // bounds. for example, forward cannot go beyond the end of the list. in
+ // such cases, false is returned and the list pointer is not moved.
+
+ bool forward(iterator &where, int count);
+ //!< moves the list pointer "count" items towards the tail.
+ /*!< Note: forward and backward operate on elements; the head and tail
+ guard are not included in the count. Also, negative values of "count"
+ are ignored. */
+ bool backward(iterator &where, int count);
+ //!< moves the list pointer "count" items towards the head.
+
+ int items_from_head(const iterator &where) const;
+ //!< Returns the number of elements between the current item and the head.
+ /*!< zero is returned if this is at the first element or the head. */
+ int items_from_tail(const iterator &where) const;
+ //!< Returns the number of elements between the current item and the tail.
+ /*!< zero is returned if this is at the last element or the tail. */
+
+private:
+ friend class iterator;
+ node *_head; //!< pointer to the first item.
+ node *_tail; //!< pointer to the last item.
+
+ bool skip_or_ignore(iterator &where, int count);
+ //!< zips the list to the position indicated by "count", if it can.
+
+ // not permitted.
+ doubly_linked_list(const doubly_linked_list &);
+ doubly_linked_list &operator =(const doubly_linked_list &);
+};
+
+} // namespace.
+
+#endif
+