feisty meow concerns codebase  2.140
doubly_linked_list.cpp
Go to the documentation of this file.
1 /*
2 *
3 * Name : doubly_linked_list
4 * Author : Chris Koeritz
5 **
6 * Copyright (c) 1998-$now By Author. This program is free software; you can
7 * redistribute it and/or modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation; either version 2 of
9 * the License or (at your option) any later version. This is online at:
10 * http://www.fsf.org/copyleft/gpl.html
11 * Please send any updates to: fred@gruntose.com
12 */
13 
14 /*
15  * POLICIES:
16  *
17  * + the cursor should never be stored to or deleted; it is merely a scanner that runs through the list.
18  * + the cursor can point at the head or tail. any storage action is taken to mean that it applies to the closest real object, if one exists. any query action is taken similarly.
19  */
20 
21 #include "doubly_linked_list.h"
22 
23 #include "node.h"
24 
25 #include <basis/functions.h>
26 
27 namespace nodes {
28 
29 // nice names for the positions of the next link and the previous link in
30 // our node's indices.
31 const int PREVIOUS = 0;
32 const int NEXT = 1;
33 
35 
36 // iterator functions:
37 
39 {
40  if (is_tail()) return; // already at the end.
41  _cursor = _cursor->get_link(NEXT);
42 }
43 
45 {
46  if (is_head()) return; // already at the front.
47  _cursor = _cursor->get_link(PREVIOUS);
48 }
49 
51 { return _cursor == to_compare._cursor; }
52 
54 {
55  if (!_manager || _manager->empty()) return NULL_POINTER;
56  if (*this == _manager->head()) next();
57  if (*this == _manager->tail()) previous();
58  return _cursor;
59 }
60 
62 {
63  if (!_manager || _manager->empty()) return NULL_POINTER;
64  if (*this == _manager->head()) next();
65  if (*this == _manager->tail()) previous();
66  return _cursor;
67 }
68 
70 {
71  if (!_manager) return false;
72  return _cursor == _manager->_head;
73 }
74 
76 {
77  if (!_manager) return false;
78  return _cursor == _manager->_tail;
79 }
80 
82 {
83  if (!_manager) return;
84  _cursor = _manager->_head;
85 }
86 
88 {
89  if (!_manager) return;
90  _cursor = _manager->_tail;
91 }
92 
94 
96 : _head(NULL_POINTER), _tail(NULL_POINTER)
97 {
98  _head = new node(2);
99  _tail = new node(2);
100  _head->set_link(NEXT, _tail);
101  _tail->set_link(PREVIOUS, _head);
102 }
103 
105 {
106  iterator zapper = head();
107  while (!empty())
108  zap(zapper);
109  WHACK(_head);
110  WHACK(_tail);
111 }
112 
114 {
115  if (_head->get_link(NEXT) == _tail) return true;
116  return false;
117 }
118 
119 bool doubly_linked_list::set_index(iterator &where, int new_index)
120 {
121  if (where._manager != this) return false;
122  if (empty()) return false;
123  node *skipper = _head->get_link(NEXT);
124  for (int i = 0; i < new_index; i++) {
125  skipper = skipper->get_link(NEXT);
126  if (skipper == _tail) return false; // out of bounds now.
127  }
128  where._cursor = skipper;
129  return true;
130 }
131 
132 bool doubly_linked_list::forward(iterator &where, int count)
133 {
134  if (where._manager != this) return false;
135  if (count <= 0) return true;
136  if (items_from_tail(where) < count) return false;
137  if (where.is_head()) where.next(); // skip the head guard.
138  for (int i = 0; i < count; i++) where.next();
139  return true;
140 }
141 
142 bool doubly_linked_list::backward(iterator &where, int count)
143 {
144  if (where._manager != this) return false;
145  if (count <= 0) return true;
146  if (items_from_head(where) < count) return false;
147  if (where.is_tail()) where.previous(); // skip the tail guard.
148  for (int i = 0; i < count; i++) where.previous();
149  return true;
150 }
151 
153 {
154  if (empty()) return 0;
155  int to_return = 0;
156  node *skipper = _head->get_link(NEXT);
157  while (skipper != _tail) {
158  to_return++;
159  skipper = skipper->get_link(NEXT);
160  }
161  return to_return;
162 }
163 
165 {
166  if (where._manager != this) return 0;
167  if (where.is_head()) return 0; // make sure it's not there already.
168  int index = 0;
169  node *skipper = _head->get_link(NEXT);
170  while ( (where._cursor != skipper) && (skipper != _tail) ) {
171  index++;
172  skipper = skipper->get_link(NEXT);
173  }
174  return index;
175 }
176 
178 {
179  if (where._manager != this) return 0;
180  if (where.is_tail()) return 0; // make sure it's not there already.
181  int index = 0;
182  node *skipper = _tail->get_link(PREVIOUS);
183  while ( (where._cursor != skipper) && (skipper != _head) ) {
184  index++;
185  skipper = skipper->get_link(PREVIOUS);
186  }
187  return index;
188 }
189 
190 /*
191 node *list::get()
192 {
193  if (empty()) return NULL_POINTER; // make sure the list isn't empty.
194  if (_cursor == _head) return _head->get_link(NEXT);
195  // check special case for pointing at the head.
196  if (_cursor == _tail) return _tail->get_link(PREVIOUS);
197  // check special case for pointing at the tail.
198  return _cursor;
199 }
200 */
201 
203 {
204  if (where._manager != this) return NULL_POINTER;
205  if (empty()) return NULL_POINTER;
206  if (where._cursor == _head)
207  where._cursor = _head->get_link(NEXT);
208  if (where._cursor == _tail)
209  where._cursor = _tail->get_link(PREVIOUS);
210  node *old_cursor = where._cursor;
211  node *old_previous = old_cursor->get_link(PREVIOUS);
212  node *old_next = old_cursor->get_link(NEXT);
213  old_cursor->set_link(PREVIOUS, NULL_POINTER);
214  old_cursor->set_link(NEXT, NULL_POINTER);
215  old_previous->set_link(NEXT, old_next);
216  old_next->set_link(PREVIOUS, old_previous);
217  where._cursor = old_next;
218  return old_cursor;
219 }
220 
221 void doubly_linked_list::zap(iterator &where) { delete remove(where); }
222 
223 void doubly_linked_list::append(iterator &where, node *new_node)
224 {
225  if (where._manager != this) return;
226  while (new_node->links() < 2) new_node->insert_link(0, NULL_POINTER);
227  if (empty()) where._cursor = _head;
228  if (where._cursor == _tail)
229  where._cursor = _tail->get_link(PREVIOUS);
230  // shift from the tail sentinel to the tail element.
231  node *save_next = where._cursor->get_link(NEXT);
232  where._cursor->set_link(NEXT, new_node);
233  new_node->set_link(PREVIOUS, where._cursor);
234  new_node->set_link(NEXT, save_next);
235  save_next->set_link(PREVIOUS, new_node);
236  where._cursor = new_node;
237 }
238 
239 void doubly_linked_list::insert(iterator &where, node *new_node)
240 {
241  if (where._manager != this) return;
242  while (new_node->links() < 2) new_node->insert_link(0, NULL_POINTER);
243  if (empty()) where._cursor = _tail;
244  if (where._cursor == _head)
245  where._cursor = _head->get_link(NEXT);
246  // shift from head sentinel to the head element.
247  node *save_prior = where._cursor->get_link(PREVIOUS);
248  where._cursor->set_link(PREVIOUS, new_node);
249  new_node->set_link(NEXT, where._cursor);
250  new_node->set_link(PREVIOUS, save_prior);
251  save_prior->set_link(NEXT, new_node);
252  where._cursor = new_node;
253 }
254 
256 {
257  iterator zapper = head();
258  while (!empty()) zap(zapper);
259 }
260 
261 } // namespace.
262 
263 
264 
265 
iterators allow the list to be traversed.
void jump_head()
set the iterator to the head.
void jump_tail()
set the iterator to the tail.
bool is_tail() const
returns true if the cursor is at the tail of the list.
bool is_head() const
returns true if the cursor is at the head of the list.
node * access()
obtain access to the current element.
const node * observe()
peek at the current element.
bool operator==(const iterator &to_compare) const
returns true if the two iterators are at the same position.
void operator--()
go to previous item.
bool backward(iterator &where, int count)
moves the list pointer "count" items towards the head.
bool forward(iterator &where, int count)
moves the list pointer "count" items towards the tail.
int elements() const
returns the number of items currently in the list.
int index(const iterator &it) const
returns the zero-based index of the cursor's position from the head.
bool empty() const
returns true if the list is empty.
~doubly_linked_list()
invalidates all contents of the list and destroys all child nodes.
int items_from_head(const iterator &where) const
Returns the number of elements between the current item and the head.
doubly_linked_list()
constructs a blank list.
iterator head() const
returns an iterator located at the head of the list.
node * remove(iterator &where)
extracts the current item from "where" and repairs the hole.
void append(iterator &where, node *new_node)
adds a "new_node" into the list immediately after "where".
void zap(iterator &where)
wipes out the item at "where", including its contents.
int items_from_tail(const iterator &where) const
Returns the number of elements between the current item and the tail.
void zap_all()
destroys all the list elements and makes the list empty.
void insert(iterator &where, node *new_node)
places a "new_node" immediately before the current node in the list.
bool set_index(iterator &to_set, int new_index)
positions the iterator "to_set" at the index specified.
An object representing the interstitial cell in most linked data structures.
Definition: node.h:41
void set_link(int link_number, node *new_link)
Connects the node "new_link" to this node.
Definition: node.cpp:62
int links() const
Returns the number of links the node currently holds.
Definition: node.cpp:51
void insert_link(int where, node *to_add=NULL_POINTER)
adds a new link prior to the position specified in "where".
Definition: node.cpp:74
node * get_link(int link_number) const
Returns the node that is connected to the specified "link_number".
Definition: node.cpp:85
#define NULL_POINTER
The value representing a pointer to nothing.
Definition: definitions.h:32
void WHACK(contents *&ptr)
deletion with clearing of the pointer.
Definition: functions.h:121
const int NEXT
const int PREVIOUS