MADARA  3.4.1
LQueue.cpp
Go to the documentation of this file.
1 #ifndef _LQUEUE_CPP
2 #define _LQUEUE_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 {
22 template<class T>
24 {
25  friend class LQueue<T>;
26  friend class LQueueIterator<T>;
27  friend class LQueueConstIterator<T>;
28 
29 public:
31  LQueueNode(const T& item, LQueueNode<T>* next = 0);
32 
35 
37  LQueueNode(void);
38 
41  void* operator new(size_t bytes);
42 
44  void operator delete(void* ptr);
45 
47  LQueueNode* next(void);
48 
51  static void free_list_allocate(size_t n);
52 
54  static void free_list_release(void);
55 
56 private:
60 
62  T item_;
63 
66 };
67 }
68 }
69 
70 /* static */
71 template<class T>
73 
74 // Allocate a new <LQueueNode>, 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(LQueueNode<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  LQueueNode<T>* node = static_cast<LQueueNode<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
127  while (LQueueNode<T>::free_list_ != 0)
128  {
131  ::operator delete(node);
132  }
133 }
134 
135 // Preallocate <n> <LQueueNodes> 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  LQueueNode<T>* new_node =
146  reinterpret_cast<LQueueNode<T>*>(::operator new(sizeof(LQueueNode<T>)));
147 
148  new_node->next_ = LQueueNode<T>::free_list_;
149 
150  // make the new element the top of the list
151  LQueueNode<T>::free_list_ = new_node;
152  }
153 }
154 
155 template<class T>
157  const T& item, madara::utility::LQueueNode<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 template<class T>
172 {
173 }
174 
175 // Returns the current size.
176 template<class T>
178 {
179  return count_;
180 }
181 
182 // Constructor.
183 
184 template<class T>
186  // Initialize fields here.
187  : tail_(0), count_(0)
188 {
189  // use the size_hint to preallocate memory for nodes
191 
192  // create the dummy node
193  tail_ = new LQueueNode<T>();
194 }
195 
196 // Copy constructor.
197 
198 template<class T>
200  // Initialize fields here.
201  : tail_(0), count_(0) // count_ will be set correctly by copy_list
202 {
203  // insert a dummy node first and keep it as an auto_ptr for exception
204  // safety issues
205  ::std::unique_ptr<LQueueNode<T> > tail(new LQueueNode<T>());
206  tail_ = tail.get();
207 
208  // copy_list has strong exception safety, so no try catch block
209  // is necessary here
210  copy_list(rhs);
211 
212  // from here on, the auto_ptr should not try to delete the
213  // tail pointer anymore.
214  tail.release();
215 }
216 
217 // Copy a linked list of nodes
218 template<class T>
220  const madara::utility::LQueue<T>& rhs)
221 {
222  LQueue<T> temp;
223 
224  // enqueue the elements into the temporary list
225  for (typename LQueue<T>::const_iterator it = rhs.begin(); it != rhs.end();
226  ++it)
227  {
228  temp.enqueue(*it);
229  }
230 
231  // we only swap the lists if the temporary list has been successfully
232  // created. This ensures strong exception guarantees.
233  ::std::swap(tail_, temp.tail_);
234 
235  // swap the counts too
236  ::std::swap(count_, temp.count_);
237 }
238 
239 // Delete a linked list of nodes
240 template<class T>
242 {
243  // we do not delete the dummy node here. This will be done in the destructor
244  // we dequeue all elements until the queue is empty again
245  while (!is_empty())
246  {
247  dequeue_i();
248  }
249 }
250 
251 // Assignment operator.
252 template<class T>
254  const madara::utility::LQueue<T>& rhs)
255 {
256  // test for self assignment first
257  if (this != &rhs)
258  {
259  // delete old data of the rhs
260  delete_list();
261 
262  // copy new data
263  copy_list(rhs);
264  }
265 
266  return *this;
267 }
268 
269 // Perform actions needed when queue goes out of scope.
270 
271 template<class T>
273 {
274  // delete all elements of the list
275  delete_list();
276 
277  // delete the last dummy node here
278  delete tail_;
279 }
280 
281 // Compare this queue with <rhs> for equality. Returns true if the
282 // size()'s of the two queues are equal and all the elements from 0
283 // .. size() are equal, else false.
284 template<class T>
286  const madara::utility::LQueue<T>& rhs) const
287 {
288  return (size() == rhs.size()) && ::std::equal(begin(), end(), rhs.begin());
289 }
290 
291 // Compare this queue with <rhs> for inequality such that <*this> !=
292 // <s> is always the complement of the boolean return value of
293 // <*this> == <s>.
294 
295 template<class T>
297  const madara::utility::LQueue<T>& rhs) const
298 {
299  return !(*this == rhs);
300 }
301 
302 // Place a <new_item> at the tail of the queue. Throws
303 // the <Overflow> exception if the queue is full.
304 
305 template<class T>
306 void madara::utility::LQueue<T>::enqueue(const T& new_item)
307 {
308  try
309  {
310  // assign the value to the tail element before the new allocation
311  // to make sure that exceptions thrown in the assignment operator
312  // of T does leave the queue structure altered
313  tail_->item_ = new_item;
314 
315  // integrate the new node into the list
316  tail_->next_ = new LQueueNode<T>(tail_->next_);
317  tail_ = tail_->next_;
318 
319  // increment the element count
320  ++count_;
321  }
322  catch (const ::std::bad_alloc&)
323  {
324  // we transform a bad_alloc excption into an overflow exception,
325  // because it basically means, that it is no longer possible
326  // to enqueue new elements
327  throw Overflow();
328  }
329 }
330 
331 // Remove and return the front item on the queue.
332 // Throws the <Underflow> exception if the queue is empty.
333 
334 template<class T>
336 {
337  // check for empty queue first
338  if (is_empty())
339  {
340  throw Underflow();
341  }
342 
343  // extract the value of the head node. This is done before we actually
344  // remove the element for exceptions could be thrown in the assignment
345  // operator.
346  T item = tail_->next_->item_;
347 
348  // call actual dequeue implementation
349  dequeue_i();
350 
351  return item;
352 }
353 
354 template<class T>
356 {
357  // remember the current queue head
358  LQueueNode<T>* head = tail_->next_;
359 
360  // remove the head from the queue
361  tail_->next_ = head->next_;
362 
363  // decrement the element count
364  --count_;
365 
366  // delete the old head node
367  delete head;
368 }
369 
370 // Returns the front queue item without removing it.
371 // Throws the <Underflow> exception if the queue is empty.
372 
373 template<class T>
375 {
376  // check for empty queue first
377  if (is_empty())
378  throw Underflow();
379 
380  // return the item in head
381  return tail_->next_->item_;
382 }
383 
384 // Returns true if the queue is empty, otherwise returns false.
385 
386 template<class T>
388 {
389  return count_ == 0;
390 }
391 
392 // Returns true if the queue is full, otherwise returns false.
393 
394 template<class T>
396 {
397  // there is no upper limit for the queue
398  return false;
399 }
400 
401 // Get an iterator to the begining of the queue
402 template<typename T>
404  void)
405 {
406  // iterator starts at the head element
407  return typename LQueue<T>::iterator(*this, tail_->next_);
408 }
409 
410 // Get an iterator pointing past the end of the queue
411 template<typename T>
413  void)
414 {
415  // iterator starts at the tail element
416  return typename LQueue<T>::iterator(*this, tail_);
417 }
418 
419 // Get an iterator to the begining of the queue
420 template<typename T>
423 {
424  // iterator starts at the head element
425  return typename LQueue<T>::const_iterator(*this, tail_->next_);
426 }
427 
428 // Get an iterator pointing past the end of the queue
429 template<typename T>
432 {
433  // iterator starts at the tail element
434  return typename LQueue<T>::const_iterator(*this, tail_);
435 }
436 
437 template<typename T>
439 {
440  return pos_->item_;
441 }
442 
443 template<typename T>
445 {
446  return pos_->item_;
447 }
448 
449 template<typename T>
451 operator++(void)
452 {
453  // advance to the next position
454  pos_ = pos_->next_;
455 
456  return *this;
457 }
458 
459 // Post-increment.
460 template<typename T>
462 operator++(int)
463 {
464  // keep copy of the original iterator
465  LQueueIterator<T> copy = *this;
466 
467  // advance to the next position
468  pos_ = pos_->next_;
469 
470  // return original iterator
471  return copy;
472 }
473 
474 template<typename T>
476  const madara::utility::LQueueIterator<T>& rhs) const
477 {
478  // check if the iterator points to the same position in the same queue
479  // (we could even omit the check for queue equality, because it is
480  // very unlikely that two queues share the same node pointer)
481  return (pos_ == rhs.pos_);
482 }
483 
484 template<typename T>
486  const madara::utility::LQueueIterator<T>& rhs) const
487 {
488  // implement != in terms of ==
489  return !(*this == rhs);
490 }
491 
492 template<typename T>
494  madara::utility::LQueue<T>& queue, size_t pos)
495  : queue_(queue), pos_(queue.tail_->next_)
496 {
497  // iterator over the queue unto the right position
498  // we save iterations for values > count_ by doing modulo calculations
499  for (pos = pos % (queue_.count_ - 1); pos > 0; --pos)
500  {
501  // advance one position each time
502  pos_ = pos_->next_;
503  }
504 }
505 
506 template<typename T>
509  : queue_(queue), pos_(pos)
510 {
511 }
512 
513 template<typename T>
515 {
516  return pos_->item_;
517 }
518 
519 template<typename T>
522 {
523  // advance to the next position
524  pos_ = pos_->next_;
525 
526  return *this;
527 }
528 
529 template<typename T>
532 {
533  // keep copy of the original iterator
534  LQueueConstIterator<T> copy = *this;
535 
536  // advance to the next position
537  pos_ = pos_->next_;
538 
539  // return original iterator
540  return copy;
541 }
542 
543 template<typename T>
546 {
547  // check if the iterator points to the same position in the same queue
548  return (pos_ == rhs.pos_);
549 }
550 
551 template<typename T>
554 {
555  return !(*this == rhs);
556 }
557 
558 template<typename T>
560  const madara::utility::LQueue<T>& queue, size_t pos)
561  : queue_(queue), pos_(queue.tail_->next_)
562 {
563  // iterator over the queue unto the right position
564  // we save iterations for values > count_ by doing modulo calculations
565  for (pos = pos % (queue_.count_ - 1); pos > 0; --pos)
566  {
567  // advance one position each time
568  pos_ = pos_->next_;
569  }
570 }
571 
572 template<typename T>
574  const LQueue<T>& queue, LQueueNode<T>* pos)
575  : queue_(queue), pos_(pos)
576 {
577 }
578 
579 #endif /* _LQUEUE_CPP */
Implements a forward iterator for LQueue type classes.
Definition: LQueue.h:207
const LQueueConstIterator< T > & operator++(void) const
Preincrement operator.
Definition: LQueue.cpp:521
const T & operator*(void) const
Dereference operator returns a const reference to the item contained at the current position.
Definition: LQueue.cpp:514
const LQueue< T > & queue_
the queue we are dealing with
Definition: LQueue.h:240
LQueueConstIterator(const LQueue< T > &queue, size_t pos=0)
Construct an LQueueIterator at position pos.
Definition: LQueue.cpp:559
bool operator!=(const LQueueConstIterator< T > &lhs) const
Nonequality operator.
Definition: LQueue.cpp:552
bool operator==(const LQueueConstIterator< T > &rhs) const
Equality operator.
Definition: LQueue.cpp:544
Implements a forward iterator for LQueue type classes.
Definition: LQueue.h:155
LQueue< T > & queue_
the queue we are dealing with
Definition: LQueue.h:191
LQueueIterator(LQueue< T > &queue, size_t pos=0)
Construct an LQueueIterator at position pos.
Definition: LQueue.cpp:493
bool operator==(const LQueueIterator< T > &rhs) const
Equality operator.
Definition: LQueue.cpp:475
bool operator!=(const LQueueIterator< T > &lhs) const
Nonequality operator.
Definition: LQueue.cpp:485
T & operator*(void)
Dereference operator returns a reference to the item contained at the current position.
Definition: LQueue.cpp:438
LQueueIterator< T > & operator++(void)
Preincrement operator.
Definition: LQueue.cpp:451
LQueueNode< T > * pos_
Definition: LQueue.h:194
Defines a node in the LQueue that's implemented as a circular linked list.
Definition: LQueue.cpp:24
LQueueNode(LQueueNode< T > *next)
Constructor.
Definition: LQueue.cpp:163
LQueueNode< T > * next_
Pointer to the next node.
Definition: LQueue.cpp:65
LQueueNode(const T &item, LQueueNode< T > *next=0)
Constructor.
Definition: LQueue.cpp:156
static void free_list_allocate(size_t n)
Preallocate n LQueueNodes and store them on the free_list_.
Definition: LQueue.cpp:139
T item_
Item in this node.
Definition: LQueue.cpp:62
static LQueueNode< T > * free_list_
Head of the free list, which is a stack of LQueueNodes used to speed up allocation.
Definition: LQueue.cpp:59
LQueueNode(void)
Default constructor that doesn't initialize item_.
Definition: LQueue.cpp:171
static void free_list_release(void)
Returns all dynamic memory on the free list to the free store.
Definition: LQueue.cpp:124
LQueueNode * next(void)
Return the next node to which this node points.
Definition: LQueue.cpp:116
Exception thrown by methods in this class when an overflow condition occurs.
Definition: LQueue.h:62
Exception thrown by methods in this class when an underflow condition occurs.
Definition: LQueue.h:53
Defines a generic "first-in/first-out" (FIFO) Abstract Data Type (ADT) using a circular linked list.
Definition: LQueue.h:39
LQueue< T > & operator=(const LQueue< T > &rhs)
Assignment operator.
Definition: LQueue.cpp:253
T front(void) const
Returns the front queue item without removing it.
Definition: LQueue.cpp:374
bool is_full(void) const
Returns 1 if the queue is full, otherwise returns 0.
Definition: LQueue.cpp:395
iterator begin(void)
Get an iterator that points to the beginning of the queue.
Definition: LQueue.cpp:403
LQueueNode< T > * tail_
We only need to keep a single pointer for the circular linked list.
Definition: LQueue.h:139
T dequeue(void)
Remove and return the front item on the queue.
Definition: LQueue.cpp:335
LQueue(size_t size_hint=0)
Constructor.
Definition: LQueue.cpp:185
LQueueConstIterator< T > const_iterator
Definition: LQueue.h:110
void enqueue(const T &new_item)
Place a new_item at the tail of the queue.
Definition: LQueue.cpp:306
bool operator==(const LQueue< T > &rhs) const
Compare this queue with rhs for equality.
Definition: LQueue.cpp:285
size_t size(void) const
Returns the current number of elements in the queue.
Definition: LQueue.cpp:177
bool operator!=(const LQueue< T > &s) const
Compare this queue with rhs for inequality such that *this>!=s is always the complement of the boolea...
Definition: LQueue.cpp:296
size_t count_
Number of items that are currently in the queue.
Definition: LQueue.h:142
void delete_list(void)
Definition: LQueue.cpp:241
bool is_empty(void) const
Returns 1 if the queue is empty, otherwise returns 0.
Definition: LQueue.cpp:387
void dequeue_i(void)
Remove the front item on the queue. Does not throw exceptions.
Definition: LQueue.cpp:355
void copy_list(const LQueue< T > &rhs)
Definition: LQueue.cpp:219
iterator end(void)
Get an iterator that points to the end of the queue.
Definition: LQueue.cpp:412
LQueueIterator< T > iterator
Definition: LQueue.h:109
Provides utility functions and classes for common tasks and needs.
Definition: IteratorImpl.h:15
Copyright(c) 2020 Galois.