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
27namespace nodes {
28
29// nice names for the positions of the next link and the previous link in
30// our node's indices.
31const int PREVIOUS = 0;
32const 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
119bool 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
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
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/*
191node *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
221void doubly_linked_list::zap(iterator &where) { delete remove(where); }
222
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
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
const int NEXT
const int PREVIOUS