Simpatico  v1.10
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 
15 class ListTest;
16 
17 namespace 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>
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>
323  void List<Data>::insertNext(Node<Data>& previous, Node<Data>& newNode)
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>
449  void List<Data>::begin(ListIterator<Data> &iterator) const
450  {
451  assert(front_ != 0);
452  iterator.setCurrent(front_);
453  }
454 
455  /*
456  * Check validity of linked list.
457  */
458  template <typename Data>
459  bool List<Data>::isValid() const
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>
538  void List<Data>::setEmpty()
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>
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>
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
Node< Data > * next() const
Get the next pointer.
Definition: Node.h:52
List()
Default constructor.
Definition: List.h:192
Node< Data > & popBack()
Remove a node from the back of the list.
Definition: List.h:273
int size() const
Get the number of elements.
Definition: List.h:217
void setPrev(Node< Data > *prev)
Set pointer to the previous Node.
Definition: Node.h:100
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
void attachNext(Node< Data > &other)
Set pointers connecting the other node after this node.
Definition: Node.h:132
void insertPrev(Node< Data > &node, Node< Data > &newNode)
Insert newNode into list before node.
Definition: List.h:340
File containing preprocessor macros for error handling.
List< Data > & list() const
Get a reference to the List.
Definition: Node.h:84
void begin(ListIterator< Data > &iterator) const
Set an iterator to the front of this List.
Definition: List.h:449
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
Node< Data > * prev() const
Get the previous pointer.
Definition: Node.h:60
Utility classes for scientific computation.
Definition: accumulators.mod:1
void clear()
Nullify previous and next pointers, and nullify the list pointer.
Definition: Node.h:165
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 attachPrev(Node< Data > &other)
Set pointers connecting the other node before this node.
Definition: Node.h:152
int capacity() const
Get capacity of the array.
Definition: List.h:224
void pushBack(Node< Data > &node)
Push a node onto the the back of the List.
Definition: List.h:231
Linked list class template.
Definition: List.h:32
Bidirectional iterator for a List.
Definition: List.h:20
Linked List Node, class template.
Definition: Node.h:22
void setNext(Node< Data > *next)
Set pointer to the next Node.
Definition: Node.h:92
void setList(List< Data > &list)
Set the list.
Definition: Node.h:108
virtual ~List()
Destructor (does nothing).
Definition: List.h:45
Node< Data > & popFront()
Remove a node from the front of the list.
Definition: List.h:298
void setCurrent(Node< Data > *nodePtr)
Point the iterator at a Node.
Definition: ListIterator.h:61