4 /*****************************************************************************\
7 * Author : Chris Koeritz *
9 *******************************************************************************
10 * Copyright (c) 1998-$now By Author. This program is free software; you can *
11 * redistribute it and/or modify it under the terms of the GNU General Public *
12 * License as published by the Free Software Foundation; either version 2 of *
13 * the License or (at your option) any later version. This is online at: *
14 * http://www.fsf.org/copyleft/gpl.html *
15 * Please send any updates to: fred@gruntose.com *
16 \*****************************************************************************/
22 class node; // forward.
24 //! Implements a guarded, doubly linked list structure.
26 The list is viewed one element at a time, through the monocular of an
27 iterator, which keeps track of the current position in the list. the
28 iterator's cursor can be shifted around at will. nodes can be added to
29 the list before or after the cursor, and the node pointed at by the cursor
30 can be queried or modified. Using multiple iterators is fine as long as
31 you guarantee that they either are all just reading the list or that you
32 have a valid access pattern of reads and writes such that no iterator's
33 cursor is affected. Note that this list is not thread safe.
40 //!< constructs a blank list.
43 //!< invalidates all contents of the list and destroys all child nodes.
46 //!< returns the number of items currently in the list.
47 /*!< this is a costly operation. */
50 //!< returns true if the list is empty.
51 /*!< this is really quick compared to checking the number of elements. */
53 //! iterators allow the list to be traversed.
54 /*! NOTE: it is an error to use an iterator on one list with a different
55 list; the methods will do nothing or return empty results in this
60 iterator(const list *mgr, node *start) : _cursor(start), _manager(mgr) {}
61 //!< opens up an iterator on a list.
62 /*!< the preferred method to construct an iterator is to use the
63 head/tail functions in list. */
65 void operator ++(); //!< go to next item.
66 void operator --(); //!< go to previous item.
67 void operator ++(int) { ++(*this); } //!< post-fix synonym for ++.
68 void operator --(int) { --(*this); } //!< post-fix synonym for --.
71 void next() { (*this)++; } //!< synonym for ++.
72 void previous() { (*this)--; } //!< synonyms for --.
74 bool operator ==(const iterator &to_compare) const;
75 //!< returns true if the two iterators are at the same position.
78 //!< returns true if the cursor is at the head of the list.
79 /*!< Note: head() and tail() only return true if the iterator is
80 actually positioned _at_ the head or tail guard. for example, if the
81 cursor is pointing at the last actual element in the list (but not at
82 the guard itself), then is_tail() returns false. so, in iteration,
83 your iterator will actually go past the last valid element before
84 is_tail() returns true. thus it is very important to check is_tail()
85 *before* looking at the node with observe() or access(), since those
86 two will shift the list position to the nearest valid node and away
89 //!< returns true if the cursor is at the tail of the list.
91 void jump_head(); //!< set the iterator to the head.
92 void jump_tail(); //!< set the iterator to the tail.
94 const node *observe(); //!< peek at the current element.
95 /*!< Note: observe() and access() will return the first element if the
96 list is positioned at the head (or the last if at the tail), and will
97 not return NIL for these two positions as long as the list has some
98 elements in it. the cursor will also have been moved to point at the
99 element that is returned.
100 Another Note: it is extremely important that you do not mess with the
101 links owned by the node (or at least the first two links).
102 A Third Note: these two functions can return NIL if the list is empty. */
103 node *access(); //!< obtain access to the current element.
106 node *_cursor; //!< the current position.
107 friend class list; //!< lists have full access to this object.
108 const list *_manager; //!< our friendly manager.
111 iterator head() const { return iterator(this, _head); }
112 //!< returns an iterator located at the head of the list.
113 iterator tail() const { return iterator(this, _tail); }
114 //!< returns an iterator located at the tail of the list.
116 int index(const iterator &it) const { return items_from_head(it); }
117 //!< returns the zero-based index of the cursor's position from the head.
118 /*!< this is a synonym for items_from_head(). */
120 bool set_index(iterator &to_set, int new_index);
121 //!< positions the iterator "to_set" at the index specified.
123 // storage and retrieval actions.
124 // Note: all of these methods shift the iterator onto the next valid node
125 // if it is positioned at the beginning or end of the list.
127 void append(iterator &where, node *new_node);
128 //!< adds a "new_node" into the list immediately after "where".
129 /*!< the nodes previously following the current node (if any) will follow
130 after the "new_node". this does not change the current position.
131 ownership of "new_node" is taken over by the list. */
133 void insert(iterator &where, node *new_node);
134 //!< places a "new_node" immediately before the current node in the list.
135 /*!< the "new_node" will follow the prior precursor to the current node.
136 this does not change the current position. ownership of "new_node"
137 is taken over by the list. after the call, the iterator points at
140 node *remove(iterator &where);
141 //!< extracts the current item from "where" and repairs the hole.
142 /*!< NIL is returned if the list was empty. the current position is set
143 to the node that used to be after the node that has been removed. after
144 the call, the iterator points at the new node. */
146 void zap(iterator &where);
147 //!< wipes out the item at "where", including its contents.
148 /*!< the current position is reset to the item after the now defunct
149 item (or the tail). */
152 //!< destroys all the list elements and makes the list empty.
153 /*!< any existing iterators will be invalidated by this. */
155 // the following positioning functions could fail if the request is out of
156 // bounds. for example, forward cannot go beyond the end of the list. in
157 // such cases, false is returned and the list pointer is not moved.
159 bool forward(iterator &where, int count);
160 //!< moves the list pointer "count" items towards the tail.
161 /*!< Note: forward and backward operate on elements; the head and tail
162 guard are not included in the count. Also, negative values of "count"
164 bool backward(iterator &where, int count);
165 //!< moves the list pointer "count" items towards the head.
167 int items_from_head(const iterator &where) const;
168 //!< Returns the number of elements between the current item and the head.
169 /*!< zero is returned if this is at the first element or the head. */
170 int items_from_tail(const iterator &where) const;
171 //!< Returns the number of elements between the current item and the tail.
172 /*!< zero is returned if this is at the last element or the tail. */
175 friend class iterator;
176 node *_head; //!< pointer to the first item.
177 node *_tail; //!< pointer to the last item.
179 bool skip_or_ignore(iterator &where, int count);
180 //!< zips the list to the position indicated by "count", if it can.
184 list &operator =(const list &);