MADARA  3.1.8
LStack.cpp
Go to the documentation of this file.
1 #ifndef _LSTACK_CPP_
2 #define _LSTACK_CPP_
3 
4 #include <memory>
6 
7 #ifdef _MSC_VER
8 // It's fine to use "this" in base-member initializations.
9 #pragma warning(disable:4355)
10 #endif
11 
12 namespace madara
13 {
14  namespace utility
15  {
20  template <class T>
21  class LStackNode
22  {
23  friend class madara::utility::LStack<T>;
26  public:
27  // = Initialization methods
28  LStackNode (const T &item,
29  LStackNode<T> *next = 0);
30 
32 
33  LStackNode (void);
34  // Default constructor that doesn't initialize <item_>.
35 
36  void *operator new (size_t bytes);
37  // Allocate a new <LStackNode>, trying first from the
38  // <free_list_> and if that's empty try from the global <::operator
39  // new>.
40 
41  void operator delete (void *ptr);
42  // Return <ptr> to the <free_list_>.
43 
44  LStackNode *next (void);
45  // Return the next node to which this node points.
46  // This method is added to support the ScopedList class below.
47 
48  static void free_list_allocate (size_t n);
49  // Preallocate <n> <LStackNodes> and store them on the
50  // <free_list_>.
51 
52  static void free_list_release (void);
53  // Returns all dynamic memory on the free list to the free store.
54 
55  private:
56 
58  // Head of the "free list", which is a stack of
59  // <LStackNodes> used to speed up allocation.
60 
61  T item_;
62  // Item in this node.
63 
65  // Pointer to the next node.
66  };
67  }
68 }
69 
70 /* static */
71 template <class T> madara::utility::LStackNode<T> *
73 
74 // Allocate a new <LStackNode>, trying first from the
75 // <free_list_> and if that's empty try from the global <::operator
76 // new>.
77 
78 template <class T> void *
80 {
81  // extract element from the free_list_ if there is one left
83  {
84  // get the top element of the list
86 
87  // "remove" the element from the list and pass it to the caller
88  LStackNode<T>::free_list_ = new_node->next_;
89 
90  return new_node;
91  }
92 
93  return ::operator new (sizeof (LStackNode<T>));
94 }
95 
96 // Return <ptr> to the <free_list_>.
97 
98 template <class T> void
100 {
101  // do nothing on a null pointer
102  if (ptr != 0)
103  {
104  // cast to a node pointer
105  LStackNode<T>* node = static_cast<LStackNode<T>*> (ptr);
106 
107  // put the node back into the list
109 
111  }
112 }
113 
114 // Returns the next node to which this node points.
115 template <class T> madara::utility::LStackNode<T> *
117 {
118  return next_;
119 }
120 
121 // Returns all dynamic memory on the free list to the free store.
122 
123 template <class T> void
125 {
126  // delete free list element by element
127  while (LStackNode<T>::free_list_ != 0)
128  {
131  ::operator delete (node);
132  }
133 }
134 
135 // Preallocate <n> <LStackNodes> and store them on the
136 // <free_list_>.
137 
138 template <class T> void
140 {
141  // add a new element to the stack n times
142  for (size_t node_number = 0; node_number < n; ++node_number)
143  {
144  // create a new element avoiding the overwritten new operator
145  LStackNode<T>* new_node =
146  reinterpret_cast<LStackNode<T>*> (
147  ::operator new (sizeof (LStackNode<T>)));
148 
149  new_node->next_ = LStackNode<T>::free_list_;
150 
151  // make the new element the top of the list
152  LStackNode<T>::free_list_ = new_node;
153  }
154 }
155 
156 template <class T>
159  : item_ (item),
160  next_ (next)
161 {
162 }
163 
164 template <class T>
167  : next_ (next)
168 {
169 }
170 
171 // This method is helpful to implement the dummy node in a concise
172 // way.
173 
174 template <class T>
176  : next_ (this)
177 {
178 }
179 
180 // Returns the current size.
181 template <class T> size_t
183 {
184  return count_;
185 }
186 
187 // Constructor.
188 
189 template <class T>
191  // Initialize fields here.
192  : head_ (0),
193  count_ (0)
194 {
195  // use the size_hint to preallocate memory for nodes
197 }
198 
199 // Copy constructor.
200 
201 template <class T>
203  const madara::utility::LStack<T> &rhs)
204  // Initialize fields here.
205  : head_ (0),
206  count_ (0) // count_ will be set correctly by copy_list
207 {
208  // insert a dummy node first and keep it as an auto_ptr for exception
209  // safety issues
210  ::std::unique_ptr <LStackNode<T> > tail (new LStackNode<T> ());
211  head_ = tail.get ();
212 
213  // copy_list has strong exception safety, so no try catch block
214  // is necessary here
215  copy_list (rhs);
216 
217  // from here on, the auto_ptr should not try to delete the
218  // tail pointer anymore.
219  tail.release ();
220 }
221 
222 // Copy a linked list of nodes
223 template <class T> void
225  const madara::utility::LStack<T> &rhs)
226 {
227  LStack<T> temp;
228  LStackNode<T>* prev = 0;
229 
230  // Iterate along the list of stack nodes in <s>, creating a new
231  // corresponding node and chaining them along. Note that we
232  // can't use push() to insert at the head since it will reverse
233  // the stack.
234 
235  ::std::unique_ptr <LStackNode<T> > new_node;
236 
237  for (typename LStack<T>::const_iterator it = rhs.begin ();
238  it != rhs.end ();
239  ++it)
240  {
241  new_node.reset (new LStackNode<T> (*it));
242 
243  if (it == rhs.begin ())
244  {
245  // special case for the first iteration: set the head element of
246  // temporary stack
247  temp.head_ = new_node.release ();
248  prev = temp.head_;
249  }
250  else
251  {
252  // standard case: add one element to prev
253  prev->next_ = new_node.release ();
254  prev = prev->next_;
255  }
256 
257  // make sure that the element count of temp stays correct
258  ++temp.count_;
259  }
260 
261  // we only swap the lists if the temporary list has been successfully
262  // created. This ensures strong exception guarantees.
263  ::std::swap (head_, temp.head_);
264 
265  // set the counts correctly
266  ::std::swap (count_, temp.count_);
267 }
268 
269 // Delete a linked list of nodes
270 template <class T> void
272 {
273  // we do not delete the dummy node here. This will be done in the destructor
274  // we pop all elements until the queue is empty again
275  while (!is_empty ())
276  {
277  pop_i ();
278  }
279 }
280 
281 // Delete a linked list of nodes
282 template <class T> void
284 {
285  delete_list ();
286 }
287 
288 // Assignment operator.
289 template <class T> madara::utility::LStack<T> &
291 {
292  // test for self assignment first
293  if (this != &rhs)
294  {
295  // delete old data of the rhs
296  delete_list ();
297 
298  // copy new data
299  copy_list (rhs);
300  }
301 
302  return *this;
303 }
304 
305 // Perform actions needed when queue goes out of scope.
306 
307 template <class T>
309 {
310  // delete all elements of the list
311  delete_list ();
312 }
313 
314 // Compare this queue with <rhs> for equality. Returns true if the
315 // size()'s of the two queues are equal and all the elements from 0
316 // .. size() are equal, else false.
317 template <class T> bool
319  const madara::utility::LStack<T> &rhs) const
320 {
321  return (size () == rhs.size ()) &&
322  ::std::equal (begin (), end (), rhs.begin ());
323 }
324 
325 // Compare this queue with <rhs> for inequality such that <*this> !=
326 // <s> is always the complement of the boolean return value of
327 // <*this> == <s>.
328 
329 template <class T> bool
331  const madara::utility::LStack<T> &rhs) const
332 {
333  return !(*this == rhs);
334 }
335 
336 // Place a <new_item> at the tail of the queue. Throws
337 // the <Overflow> exception if the queue is full.
338 
339 template <class T> void
341 {
342  try
343  {
344  // create a temporary new node for exception safety reasons
345  ::std::unique_ptr <LStackNode<T> > temp (new LStackNode<T> (new_item, head_));
346 
347  // integrate the new node into the list
348  head_ = temp.release ();
349 
350  // increment the element count
351  ++count_;
352  }
353  catch (const ::std::bad_alloc&)
354  {
355  // we transform a bad_alloc excption into an overflow exception,
356  // because it basically means, that it is no longer possible
357  // to push new elements
358  throw Overflow ();
359  }
360 }
361 
362 // Remove and return the front item on the queue.
363 // Throws the <Underflow> exception if the queue is empty.
364 
365 template <class T> T
367 {
368  // check for empty queue first
369  if (is_empty ())
370  {
371  throw Underflow ();
372  }
373 
374  // extract the value of the head node. This is done before we actually
375  // remove the element for exceptions could be thrown in the assignment
376  // operator.
377  T item = head_->item_;
378 
379  // call actual pop implementation
380  pop_i ();
381 
382  return item;
383 }
384 
385 template <class T> void
387 {
388  // remember the current queue head
389  LStackNode<T>* head = head_;
390 
391  // remove the head from the queue
392  head_ = head->next_;
393 
394  // decrement the element count
395  --count_;
396 
397  // delete the old head node
398  delete head;
399 }
400 
401 // Returns the front queue item without removing it.
402 // Throws the <Underflow> exception if the queue is empty.
403 
404 template <class T> T
406 {
407  // check for empty queue first
408  if (is_empty())
409  throw Underflow ();
410 
411  // return the item in head
412  return head_->item_;
413 }
414 
415 // Returns true if the queue is empty, otherwise returns false.
416 
417 template <class T> bool
419 {
420  return count_ == 0;
421 }
422 
423 // Returns true if the queue is full, otherwise returns false.
424 
425 template <class T> bool
427 {
428  // there is no upper limit for the queue
429  return false;
430 }
431 
432 // Get an iterator to the begining of the queue
433 template <typename T> typename madara::utility::LStack<T>::iterator
435 {
436  // iterator starts at the head element
437  return typename LStack<T>::iterator (*this, head_);
438 }
439 
440 // Get an iterator pointing past the end of the queue
441 template <typename T> typename madara::utility::LStack<T>::iterator
443 {
444  // iterator starts at the tail element
445  return typename LStack<T>::iterator (*this, (LStackNode<T>*) 0);
446 }
447 
448 // Get an iterator to the begining of the queue
449 template <typename T> typename madara::utility::LStack<T>::const_iterator
451 {
452  // iterator starts at the head element
453  return typename LStack<T>::const_iterator (*this, head_);
454 }
455 
456 // Get an iterator pointing past the end of the queue
457 template <typename T> typename madara::utility::LStack<T>::const_iterator
459 {
460  // iterator starts at the tail element
461  return typename LStack<T>::const_iterator (*this, (LStackNode<T>*) 0);
462 }
463 
464 template <typename T> T &
466 {
467  return pos_->item_;
468 }
469 
470 template <typename T> const T &
472 {
473  return pos_->item_;
474 }
475 
476 template <typename T> madara::utility::LStackIterator<T> &
478 {
479  // advance to the next position
480  pos_ = pos_->next_;
481 
482  return *this;
483 }
484 
485 // Post-increment.
486 template <typename T> madara::utility::LStackIterator<T>
488 {
489  // keep copy of the original iterator
490  LStackIterator<T> copy = *this;
491 
492  // advance to the next position
493  pos_ = pos_->next_;
494 
495  // return original iterator
496  return copy;
497 }
498 
499 template <typename T> bool
501  const madara::utility::LStackIterator<T> &rhs) const
502 {
503  // check if the iterator points to the same position in the same queue
504  // (we could even omit the check for queue equality, because it is
505  // very unlikely that two queues share the same node pointer)
506  return (pos_ == rhs.pos_);
507 }
508 
509 template <typename T> bool
511  const madara::utility::LStackIterator<T> &rhs) const
512 {
513  // implement != in terms of ==
514  return !(*this == rhs);
515 }
516 
517 template <typename T>
519  madara::utility::LStack<T> &stack, size_t pos)
520  : stack_ (stack),
521  pos_ (stack.head_)
522 {
523  // iterator over the stack unto the right position
524  // we save iterations for values > count_ by doing modulo calculations
525  for (pos = pos % (stack_.count_ -1);
526  pos > 0;
527  --pos)
528  {
529  // advance one position each time
530  pos_ = pos_->next_;
531  }
532 }
533 
534 template <typename T>
537  : stack_ (stack),
538  pos_ (pos)
539 {
540 }
541 
542 template <typename T> const T &
544 {
545  return pos_->item_;
546 }
547 
548 template <typename T> const madara::utility::LStackConstIterator<T> &
550 {
551  // advance to the next position
552  pos_ = pos_->next_;
553 
554  return *this;
555 }
556 
557 template <typename T> madara::utility::LStackConstIterator<T>
559 {
560  // keep copy of the original iterator
561  LStackConstIterator<T> copy = *this;
562 
563  // advance to the next position
564  pos_ = pos_->next_;
565 
566  // return original iterator
567  return copy;
568 }
569 
570 template <typename T>
571 bool
574 {
575  // check if the iterator points to the same position in the same stack
576  return (pos_ == rhs.pos_);
577 }
578 
579 template <typename T> bool
581  const madara::utility::LStackConstIterator<T> & rhs) const
582 {
583  return !(*this == rhs);
584 }
585 
586 template <typename T>
588  const madara::utility::LStack<T> & stack, size_t pos)
589  : stack_ (stack),
590  pos_ (stack.head_)
591 {
592  // iterator over the stack unto the right position
593  // we save iterations for values > count_ by doing modulo calculations
594  for (pos = pos % (stack_.count_ -1);
595  pos > 0;
596  --pos)
597  {
598  // advance one position each time
599  pos_ = pos_->next_;
600  }
601 }
602 
603 template <typename T>
606  : stack_ (stack),
607  pos_ (pos)
608 {
609 }
610 
611 #endif /* _LSTACK_CPP_ */
LStackNode< T > * next_
Definition: LStack.cpp:64
bool operator==(const LStackIterator< T > &rhs) const
Equality operator.
Definition: LStack.cpp:500
size_t count_
Number of items that are currently in the stack.
Definition: LStack.h:131
T top(void) const
Returns the front stack item without removing it.
Definition: LStack.cpp:405
LStack< T > & operator=(const LStack< T > &rhs)
Assignment operator.
Definition: LStack.cpp:290
bool is_empty(void) const
Returns 1 if the stack is empty, otherwise returns 0.
Definition: LStack.cpp:418
T pop(void)
Remove and return the front item on the stack.
Definition: LStack.cpp:366
static void free_list_allocate(size_t n)
Definition: LStack.cpp:139
size_t size(void) const
Returns the current number of elements in the stack.
Definition: LStack.cpp:182
const LStackConstIterator< T > & operator++(void) const
Preincrement operator.
Definition: LStack.cpp:549
bool is_full(void) const
Returns 1 if the stack is full, otherwise returns 0.
Definition: LStack.cpp:426
static LStackNode< T > * free_list_
Definition: LStack.cpp:57
bool operator==(const LStack< T > &rhs) const
Compare this stack with rhs for equality.
Definition: LStack.cpp:318
~LStack(void)
Perform actions needed when stack goes out of scope.
Definition: LStack.cpp:308
iterator begin(void)
Get an iterator that points to the beginning of the stack.
Definition: LStack.cpp:434
void pop_i(void)
Remove the front item on the stack. does not throw exceptions.
Definition: LStack.cpp:386
static void free_list_release(void)
Definition: LStack.cpp:124
const T & operator*(void) const
Dereference operator returns a const reference to the item contained at the current position...
Definition: LStack.cpp:543
LStackConstIterator(const LStack< T > &stack, size_t pos=0)
Construct an LStackIterator at position pos.
Definition: LStack.cpp:587
LStackIterator(LStack< T > &stack, size_t pos=0)
Construct an LStackIterator at position pos.
Definition: LStack.cpp:518
LStack< T > & stack_
the stack we are dealing with
Definition: LStack.h:182
bool operator==(const LStackConstIterator< T > &rhs) const
Equality operator.
Definition: LStack.cpp:572
void erase(void)
Delete all the nodes in the LStack.
Definition: LStack.cpp:283
T & operator*(void)
Dereference operator returns a reference to the item contained at the current position.
Definition: LStack.cpp:465
bool operator!=(const LStackConstIterator< T > &lhs) const
Nonequality operator.
Definition: LStack.cpp:580
bool operator!=(const LStack< T > &s) const
Definition: LStack.cpp:330
LStackNode< T > * pos_
Definition: LStack.h:185
LStackNode * next(void)
Definition: LStack.cpp:116
Implements a forward iterator for LStack type classes.
Definition: LStack.h:18
bool operator!=(const LStackIterator< T > &lhs) const
Nonequality operator.
Definition: LStack.cpp:510
void copy_list(const LStack< T > &rhs)
Copy a linked list of nodes.
Definition: LStack.cpp:224
iterator end(void)
Get an iterator that points to the end of the stack.
Definition: LStack.cpp:442
Provides utility functions and classes for common tasks and needs.
Definition: IteratorImpl.h:14
LStackIterator< T > iterator
Definition: LStack.h:98
Exception thrown by methods in this class when an underflow condition occurs.
Definition: LStack.h:42
LStack(size_t size_hint=0)
Constructor.
Definition: LStack.cpp:190
Defines a generic "last-in/first-out" (LIFO) Abstract Data Type (ADT) using a stack that&#39;s implemente...
Definition: LStack.h:29
Exception thrown by methods in this class when an overflow condition occurs.
Definition: LStack.h:49
Copyright (c) 2015 Carnegie Mellon University.
Implements a forward iterator for LStack type classes.
Definition: LStack.h:21
const LStack< T > & stack_
the stack we are dealing with
Definition: LStack.h:233
Defines a node in the LStack that&#39;s implemented as a linked list.
Definition: LStack.cpp:21
LStackConstIterator< T > const_iterator
Definition: LStack.h:99
void push(const T &new_item)
Place a new_item at the tail of the stack.
Definition: LStack.cpp:340
LStackNode< T > * head_
We only need to keep a single pointer for the circular linked list.
Definition: LStack.h:128
void delete_list(void)
Delete a linked list of nodes.
Definition: LStack.cpp:271
LStackIterator< T > & operator++(void)
Preincrement operator.
Definition: LStack.cpp:477