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