Merge branch 'master' of feistymeow.org:feisty_meow
[feisty_meow.git] / nucleus / library / nodes / doubly_linked_list.h
diff --git a/nucleus/library/nodes/doubly_linked_list.h b/nucleus/library/nodes/doubly_linked_list.h
new file mode 100644 (file)
index 0000000..987e248
--- /dev/null
@@ -0,0 +1,194 @@
+#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
+