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