PSCF v1.1
List.h
1#ifndef UTIL_LIST_H
2#define UTIL_LIST_H
3
4/*
5* Util Package - C++ Utilities for Scientific Computation
6*
7* Copyright 2010 - 2017, The Regents of the University of Minnesota
8* Distributed under the terms of the GNU General Public License.
9*/
10
11#include <util/containers/Node.h>
12#include <util/containers/ListIterator.h>
13#include <util/global.h>
14
15class ListTest;
16
17namespace Util
18{
19
20 template <typename Data> class ListIterator;
21
31 template <typename Data>
32 class List
33 {
34
35 public:
36
40 List();
41
45 virtual ~List()
46 {}
47
51 void initialize(Node<Data>* nodes, int capacity);
52
58 int size() const;
59
65 int capacity() const;
66
72 void pushBack(Node<Data>& node);
73
79 void pushFront(Node<Data>& node);
80
87
94
101 void insertNext(Node<Data>& node, Node<Data>& newNode);
102
109 void insertPrev(Node<Data>& node, Node<Data>& newNode);
110
116 void insert(Node<Data> &node);
117
123 void remove(Node<Data> &node);
124
130 void begin(ListIterator<Data> &iterator) const;
131
137 bool isValid() const;
138
139 private:
140
142 Node<Data>* nodes_;
143
145 Node<Data>* front_;
146
148 Node<Data>* back_;
149
151 Node<Data>* lower_;
152
154 Node<Data>* upper_;
155
157 int capacity_;
158
160 int size_;
161
165 void setEmpty();
166
172 void expandBounds(Node<Data>& node);
173
179 void contractBounds(Node<Data>& node);
180
181 //friends
182
183 friend class ::ListTest;
184
185 }; // end class List
186
187
188 /*
189 * Default constructor.
190 */
191 template <typename Data>
193 : nodes_(0),
194 front_(0),
195 back_(0),
196 lower_(0),
197 upper_(0),
198 capacity_(0),
199 size_(0)
200 {}
201
202 /*
203 * Provide a C array of Node<Data> objects for this List.
204 */
205 template <typename Data>
206 void List<Data>::initialize(Node<Data>* nodes, int capacity)
207 {
208 nodes_ = nodes;
209 capacity_ = capacity;
210 setEmpty();
211 }
212
213 /*
214 * Get number of elements in list.
215 */
216 template <typename Data>
217 inline int List<Data>::size() const
218 { return size_; }
219
220 /*
221 * Get capacity of underlying array.
222 */
223 template <typename Data>
224 inline int List<Data>::capacity() const
225 { return capacity_; }
226
227 /*
228 * Push a node onto the the back of the List.
229 */
230 template <typename Data>
232 {
233 if (back_ == 0) {
234 node.setList(*this);
235 front_ = &node;
236 lower_ = &node;
237 upper_ = &node;
238 } else {
239 back_->attachNext(node);
240 expandBounds(node);
241 }
242 back_ = &node;
243 node.setNext(0);
244 ++size_;
245 }
246
247 /*
248 * Push a node onto the the front of the List.
249 */
250 template <typename Data>
252 {
253 if (front_ == 0) {
254 node.setList(*this);
255 front_ = &node;
256 back_ = &node;
257 lower_ = &node;
258 upper_ = &node;
259 size_ = 1;
260 } else {
261 front_->attachPrev(node);
262 front_ = &node;
263 expandBounds(node);
264 ++size_;
265 }
266 node.setPrev(0);
267 }
268
269 /*
270 * Remove a node from the back of the list.
271 */
272 template <typename Data>
274 {
275 if (size_ == 0) {
276 UTIL_THROW("Attempted popBack from empty List");
277 }
278 assert(back_ != 0);
279 assert(front_ != 0);
280 Node<Data>& oldBack = *back_;
281 if (back_ == front_) {
282 back_->clear();
283 setEmpty();
284 } else {
285 back_ = oldBack.prev();
286 back_->setNext(0);
287 contractBounds(oldBack);
288 oldBack.clear();
289 --size_;
290 }
291 return oldBack;
292 }
293
294 /*
295 * Remove a node from the back of the list.
296 */
297 template <typename Data>
299 {
300 if (size_ == 0) {
301 UTIL_THROW("Attempted popFront from empty List");
302 }
303 assert(front_ != 0);
304 assert(back_ != 0);
305 Node<Data>& oldFront = *front_;
306 if (front_ == back_) {
307 front_->clear();
308 setEmpty();
309 } else {
310 front_ = oldFront.next();
311 front_->setPrev(0);
312 contractBounds(oldFront);
313 oldFront.clear();
314 --size_;
315 }
316 return oldFront;
317 }
318
319 /*
320 * Insert newNode into the list after previous.
321 */
322 template <typename Data>
324 {
325 if (&previous == back_) {
326 back_ = &newNode;
327 newNode.setNext(0);
328 } else {
329 previous.next()->attachPrev(newNode);
330 }
331 previous.attachNext(newNode);
332 expandBounds(newNode);
333 ++size_;
334 }
335
336 /*
337 * Insert newNode into the list before next.
338 */
339 template <typename Data>
341 {
342 if (&next == front_ ) {
343 front_ = &newNode;
344 newNode.setPrev(0);
345 } else {
346 next.prev()->attachNext(newNode);
347 }
348 next.attachPrev(newNode);
349 expandBounds(newNode);
350 ++size_;
351 }
352
353 /*
354 * Remove a specific node from the list.
355 */
356 template <typename Data>
358 {
359 assert( &node.list() == this );
360 if (&node == back_) {
361 if (back_ == front_) {
362 back_->clear();
363 setEmpty();
364 return;
365 } else {
366 back_ = node.prev();
367 back_->setNext(0);
368 }
369 } else
370 if (&node == front_) {
371 front_ = node.next();
372 front_->setPrev(0);
373 } else {
374 node.prev()->setNext( node.next() );
375 node.next()->setPrev( node.prev() );
376 }
377 contractBounds(node);
378 node.clear();
379 --size_;
380 }
381
382 /*
383 * Insert one new node.
384 */
385 template <typename Data>
387 {
388 //List<Data>& list = node.list();
389 Node<Data>* current;
390 Node<Data>* target;
391
392 // Assert that node does not already belong to this list
393 assert( &node.list() != this);
394
395 // If list is empty
396 if (front_ == 0) {
397 node.setList(*this);
398 front_ = &node;
399 back_ = &node;
400 lower_ = &node;
401 upper_ = &node;
402 size_ = 1;
403 return;
404 }
405
406 // If node address is above highest address
407 if (&node > upper_) {
408 target = upper_->next();
409 upper_->attachNext(node);
410 upper_ = &node;
411 } else // If node address is below lowest address
412 if (&node < lower_) {
413 target = lower_->prev();
414 if (target) {
415 target->attachNext(node);
416 } else {
417 node.setPrev(0);
418 node.setList(*this);
419 front_ = &node;
420 }
421 target = lower_;
422 lower_ = &node;
423 } else // If between lowest and highest addresses
424 {
425 current = &node;
426 do {
427 assert(current > lower_);
428 --current;
429 } while (&current->list() != this);
430 target = current->next();
431 current->attachNext(node);
432 }
433
434 // Set Next for new Node, or set to back_
435 if (target != 0) {
436 node.attachNext(*target);
437 } else {
438 node.setNext(0);
439 back_ = &node;
440 }
441
442 ++size_;
443 }
444
445 /*
446 * Set iterator to front of list.
447 */
448 template <typename Data>
450 {
451 assert(front_ != 0);
452 iterator.setCurrent(front_);
453 }
454
455 /*
456 * Check validity of linked list.
457 */
458 template <typename Data>
460 {
461 if (front_ == 0) {
462
463 if (size_ != 0) {
464 UTIL_THROW("List<Data>::isValid: front_ == 0 and size_ != 0.");
465 return false;
466 }
467
468 if (back_ != 0) {
469 UTIL_THROW("List<Data>::isValid: front_ == 0 and back_ != 0.");
470 return false;
471 }
472
473 if (lower_ != nodes_ + capacity_) {
474 UTIL_THROW("front_ == 0 and lower_ != nodes_+capacity.");
475 return false;
476 }
477
478 if (upper_ != nodes_ -1) {
479 UTIL_THROW("List<Data>::isValid: front_ == 0 and upper_ != nodes_-1.");
480 return false;
481 }
482
483 } else {
484
485 int i=1;
486 Node<Data>* prev = 0;
487 Node<Data>* node = front_;
488 while (node->next() != 0 ) {
489 if (node->prev() != prev) {
490 UTIL_THROW("List<Data>::isValid: node->prev() != prev.");
491 return false;
492 }
493 if (&node->list() != this) {
494 UTIL_THROW("List<Data>::isValid: &node->list() != this.");
495 return false;
496 }
497 if (node > upper_) {
498 UTIL_THROW("List<Data>::isValid: node > upper_.");
499 return false;
500 }
501 if (node < lower_) {
502 UTIL_THROW("List<Data>::isValid: node < lower_.");
503 return false;
504 }
505 prev = node;
506 node = node->next();
507 ++i;
508 }
509
510 if (i < size_) {
511 UTIL_THROW("List<Data>::isValid: # elements < size_.");
512 return false;
513 }
514 if (i > size_) {
515 UTIL_THROW("List<Data>::isValid: # elements > size_.");
516 return false;
517 }
518 if (node != back_) {
519 UTIL_THROW("List<Data>::isValid: Last node != back_.");
520 return false;
521 }
522 if (node->next() != 0) {
523 UTIL_THROW("List<Data>::isValid: Last node, node->next() != 0.");
524 return false;
525 }
526
527 }
528 // If no errors were detected to this point, the list is valid.
529 return true;
530 }
531
532 // Private methods
533
534 /*
535 * Set list to empty state.
536 */
537 template <typename Data>
539 {
540 size_ = 0;
541 front_ = 0;
542 back_ = 0;
543
544 // Set lower above all addresses and upper below all so that the
545 // expandBounds method will reset both values when a node is added.
546 lower_ = nodes_ + capacity_ ;
547 upper_ = nodes_ - 1;
548
549 }
550
551 /*
552 * Update upper_ and lower_ bounds for a new node.
553 */
554 template <typename Data>
555 void List<Data>::expandBounds(Node<Data>& node)
556 {
557 if (&node > upper_) {
558 upper_ = &node;
559 }
560 if (&node < lower_) {
561 lower_ = &node;
562 }
563 }
564
565 /*
566 * Update upper_ and lower_ bounds to reflect removal of a node.
567 */
568 template <typename Data>
569 void List<Data>::contractBounds(Node<Data>& node)
570 {
571 if (&node == upper_) {
572 do {
573 --upper_;
574 } while ( &(upper_->list()) != this );
575 }
576 if (&node == lower_) {
577 do {
578 ++lower_;
579 } while ( &(lower_->list()) != this );
580 }
581 }
582
583}
584#endif
Bidirectional iterator for a List.
Definition: ListIterator.h:28
void setCurrent(Node< Data > *nodePtr)
Point the iterator at a Node.
Definition: ListIterator.h:61
Linked list class template.
Definition: List.h:33
Node< Data > & popBack()
Remove a node from the back of the list.
Definition: List.h:273
void begin(ListIterator< Data > &iterator) const
Set an iterator to the front of this List.
Definition: List.h:449
Node< Data > & popFront()
Remove a node from the front of the list.
Definition: List.h:298
void insertNext(Node< Data > &node, Node< Data > &newNode)
Insert newNode into list after node.
Definition: List.h:323
bool isValid() const
Check validity of linked list.
Definition: List.h:459
void remove(Node< Data > &node)
Remove node from list.
Definition: List.h:357
void pushFront(Node< Data > &node)
Push a node onto the the front of the List.
Definition: List.h:251
int size() const
Get the number of elements.
Definition: List.h:217
List()
Default constructor.
Definition: List.h:192
void pushBack(Node< Data > &node)
Push a node onto the the back of the List.
Definition: List.h:231
virtual ~List()
Destructor (does nothing).
Definition: List.h:45
void insert(Node< Data > &node)
Insert node into list in sequential order.
Definition: List.h:386
void initialize(Node< Data > *nodes, int capacity)
Provide an array of Node<Data> objects for this List.
Definition: List.h:206
void insertPrev(Node< Data > &node, Node< Data > &newNode)
Insert newNode into list before node.
Definition: List.h:340
int capacity() const
Get capacity of the array.
Definition: List.h:224
Linked List Node, class template.
Definition: Node.h:23
List< Data > & list() const
Get a reference to the List.
Definition: Node.h:84
void setPrev(Node< Data > *prev)
Set pointer to the previous Node.
Definition: Node.h:100
void clear()
Nullify previous and next pointers, and nullify the list pointer.
Definition: Node.h:165
Node< Data > * next() const
Get the next pointer.
Definition: Node.h:52
void attachPrev(Node< Data > &other)
Set pointers connecting the other node before this node.
Definition: Node.h:152
void setList(List< Data > &list)
Set the list.
Definition: Node.h:108
void attachNext(Node< Data > &other)
Set pointers connecting the other node after this node.
Definition: Node.h:132
void setNext(Node< Data > *next)
Set pointer to the next Node.
Definition: Node.h:92
Node< Data > * prev() const
Get the previous pointer.
Definition: Node.h:60
File containing preprocessor macros for error handling.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
Utility classes for scientific computation.
Definition: accumulators.mod:1