DeSiGNAR  0.5a
Data Structures General Library
queue.H
Go to the documentation of this file.
1 /*
2  This file is part of Designar.
3  Copyright (C) 2017 by Alejandro J. Mujica
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  Any user request of this software, write to
19 
20  Alejandro Mujica
21 
22  aledrums@gmail.com
23 */
24 
25 # ifndef DSGQUEUE_H
26 # define DSGQUEUE_H
27 
28 # include <array.H>
29 # include <list.H>
30 
31 namespace Designar
32 {
33 
34  template <typename T, nat_t CAP = 100>
35  class FixedQueue
36  {
37  T array[CAP];
38  nat_t num_items;
39  nat_t f;
40  nat_t r;
41 
42  void copy_queue(const FixedQueue &);
43 
44  void swap(FixedQueue & q)
45  {
46  std::swap(array, q.array);
47  std::swap(num_items, q.num_items);
48  std::swap(f, q.f);
49  std::swap(r, q.r);
50  }
51 
52  public:
53  using ItemType = T;
54  using KeyType = T;
55  using DataType = T;
56  using ValueType = T;
57  using SizeType = nat_t;
58 
60  : num_items(0), f(0), r(CAP - 1)
61  {
62  // empty
63  }
64 
66  : num_items(q.num_items)
67  {
68  copy_queue(q);
69  }
70 
72  : FixedQueue()
73  {
74  swap(q);
75  }
76 
78  {
79  if (this == &q)
80  return *this;
81 
82  num_items = q.num_items;
83  f = q.f;
84  r = q.r;
85  copy_queue(q);
86 
87  return *this;
88  }
89 
91  {
92  swap(q);
93  return *this;
94  }
95 
96  bool is_empty() const
97  {
98  return num_items == 0;
99  }
100 
101  bool is_full() const
102  {
103  return num_items == CAP;
104  }
105 
106  nat_t size() const
107  {
108  return num_items;
109  }
110 
112  {
113  return CAP;
114  }
115 
116  void clear()
117  {
118  num_items = 0;
119  f = 0;
120  r = CAP - 1;
121  }
122 
123  T & front()
124  {
125  if (is_empty())
126  throw std::underflow_error("Queue is empty");
127 
128  return array[f];
129  }
130 
131  const T & front() const
132  {
133  if (is_empty())
134  throw std::underflow_error("Queue is empty");
135 
136  return array[f];
137  }
138 
139  T & rear()
140  {
141  if (is_empty())
142  throw std::underflow_error("Queue is empty");
143 
144  return array[r];
145  }
146 
147  const T & rear() const
148  {
149  if (is_empty())
150  throw std::underflow_error("Queue is empty");
151 
152  return array[r];
153  }
154 
155  T & put(const T & item)
156  {
157  if (is_full())
158  throw std::overflow_error("Queue is full");
159 
160  r = (r + 1) % CAP;
161  array[r] = item;
162  ++num_items;
163  return array[r];
164  }
165 
166  T & put(T && item)
167  {
168  if (is_full())
169  throw std::overflow_error("Queue is full");
170 
171  r = (r + 1) % CAP;
172  array[r] = std::move(item);
173  ++num_items;
174  return array[r];
175  }
176 
177  T get()
178  {
179  if (is_empty())
180  throw std::underflow_error("Queue is empty");
181 
182  T ret_val = std::move(array[f]);
183  f = (f + 1) % CAP;
184  --num_items;
185  return ret_val;
186  }
187  };
188 
189  template <typename T, nat_t CAP>
191  {
192  nat_t ii = q.f;
193 
194  for (nat_t i = 0; i < num_items; ++i)
195  {
196  array[i] = q.array[ii];
197  ii = (ii + 1) % CAP;
198  }
199 
200  f = 0;
201  r = num_items - 1;
202  }
203 
204  template <typename T>
205  class DynQueue : private FixedArray<T>
206  {
207  using BaseArray = FixedArray<T>;
208 
209  static constexpr nat_t MIN_SIZE = 32;
210  static constexpr real_t RESIZE_FACTOR = 0.4;
211 
212  nat_t num_items;
213  nat_t f;
214  nat_t r;
215 
216  void copy_queue(const DynQueue &);
217 
218  void swap(DynQueue & q)
219  {
220  BaseArray::swap(q);
221  std::swap(num_items, q.num_items);
222  std::swap(f, q.f);
223  std::swap(r, q.r);
224  }
225 
226  void resize(nat_t);
227 
228  void resize_up()
229  {
230  if (num_items < BaseArray::get_capacity())
231  return;
232 
233  assert(BaseArray::get_capacity() * (1 + RESIZE_FACTOR) > num_items);
234 
235  resize(BaseArray::get_capacity() * (1 + RESIZE_FACTOR));
236  }
237 
238  void resize_down()
239  {
240  if (num_items > BaseArray::get_capacity() * RESIZE_FACTOR or
241  BaseArray::get_capacity() == MIN_SIZE)
242  return;
243 
244  assert(BaseArray::get_capacity() * (1 - RESIZE_FACTOR) > num_items);
245 
246  resize(BaseArray::get_capacity() * (1 - RESIZE_FACTOR));
247  }
248 
249  public:
250  using ItemType = T;
251  using KeyType = T;
252  using DataType = T;
253  using ValueType = T;
254  using SizeType = nat_t;
255 
257  : BaseArray(MIN_SIZE), num_items(0), f(0), r(MIN_SIZE - 1)
258  {
259  // empty
260  }
261 
262  DynQueue(const DynQueue & q)
263  : BaseArray(q.get_capacity()), num_items(q.num_items)
264  {
265  copy_queue(q);
266  }
267 
269  : BaseArray(), num_items(0), f(0), r(0)
270  {
271  swap(q);
272  }
273 
275  {
276  if (this == &q)
277  return *this;
278 
279  BaseArray arr(q.get_capacity());
280  BaseArray::swap(arr);
281  num_items = q.num_items;
282  copy_queue(q);
283 
284  return *this;
285  }
286 
288  {
289  swap(q);
290  return *this;
291  }
292 
293  bool is_empty() const
294  {
295  return num_items == 0;
296  }
297 
298  nat_t size() const
299  {
300  return num_items;
301  }
302 
303  void clear()
304  {
305  num_items = 0;
306 
307  if (BaseArray::get_capacity() != MIN_SIZE)
308  {
309  BaseArray new_array(MIN_SIZE);
310  BaseArray::swap(new_array);
311  }
312 
313  f = 0;
314  r = MIN_SIZE - 1;
315  }
316 
317  T & front()
318  {
319  if (is_empty())
320  throw std::underflow_error("Queue is empty");
321 
322  return BaseArray::at(f);
323  }
324 
325  const T & front() const
326  {
327  if (is_empty())
328  throw std::underflow_error("Queue is empty");
329 
330  return BaseArray::at(f);
331  }
332 
333  T & rear()
334  {
335  if (is_empty())
336  throw std::underflow_error("Queue is empty");
337 
338  return BaseArray::at(r);
339  }
340 
341  const T & rear() const
342  {
343  if (is_empty())
344  throw std::underflow_error("Queue is empty");
345 
346  return BaseArray::at(r);
347  }
348 
349  T & put(const T & item)
350  {
351  r = (r + 1) % BaseArray::get_capacity();
352  BaseArray::at(r) = item;
353  ++num_items;
354  resize_up();
355  return BaseArray::at(r);
356  }
357 
358  T & put(T && item)
359  {
360  r = (r + 1) % BaseArray::get_capacity();
361  BaseArray::at(r) = std::move(item);
362  ++num_items;
363  resize_up();
364  return BaseArray::at(r);
365  }
366 
367  T get()
368  {
369  if (is_empty())
370  throw std::underflow_error("Queue is empty");
371 
372  T ret_val = std::move(BaseArray::at(f));
373  f = (f + 1) % BaseArray::get_capacity();
374  --num_items;
375  resize_down();
376  return ret_val;
377  }
378  };
379 
380  template <typename T>
381  void DynQueue<T>::copy_queue(const DynQueue & q)
382  {
383  nat_t ii = q.f;
384 
385  for (nat_t i = 0; i < num_items; ++i)
386  {
387  BaseArray::at(i) = q.at(ii);
388  ii = (ii + 1) % BaseArray::get_capacity();
389  }
390 
391  f = 0;
392  r = num_items - 1;
393  }
394 
395  template <typename T>
396  void DynQueue<T>::resize(nat_t sz)
397  {
398  if (sz < MIN_SIZE)
399  sz = MIN_SIZE;
400 
401  BaseArray new_array(sz);
402 
403  nat_t ii = f;
404 
405  for (nat_t i = 0; i < num_items; ++i)
406  {
407  new_array.at(i) = BaseArray::at(ii);
408  ii = (ii + 1) % BaseArray::get_capacity();
409  }
410 
411  BaseArray::swap(new_array);
412 
413  f = 0;
414  r = num_items - 1;
415  }
416 
417  template <typename T>
418  class ListQueue : private SLList<T>
419  {
420  using BaseList = SLList<T>;
421 
422  public:
423  using ItemType = T;
424  using KeyType = T;
425  using DataType = T;
426  using ValueType = T;
427  using SizeType = nat_t;
428 
430  : BaseList()
431  {
432  // empty
433  }
434 
435  ListQueue(const ListQueue & q)
436  : BaseList(q)
437  {
438  // empty
439  }
440 
442  : BaseList(std::forward<ListQueue<T>>(q))
443  {
444  // empty
445  }
446 
448  {
449  if (this == &q)
450  return *this;
451 
452  (BaseList &) *this = q;
453  return *this;
454  }
455 
457  {
458  BaseList::swap(q);
459  return *this;
460  }
461 
462  bool is_empty() const
463  {
464  return BaseList::is_empty();
465  }
466 
467  nat_t size() const
468  {
469  return BaseList::size();
470  }
471 
472  void clear()
473  {
474  BaseList::clear();
475  }
476 
477  T & front()
478  {
479  if (is_empty())
480  throw std::underflow_error("Queue is empty");
481 
482  return BaseList::get_first();
483  }
484 
485  const T & front() const
486  {
487  if (is_empty())
488  throw std::underflow_error("Queue is empty");
489 
490  return BaseList::get_first();
491  }
492 
493  T & rear()
494  {
495  if (is_empty())
496  throw std::underflow_error("Queue is empty");
497 
498  return BaseList::get_last();
499  }
500 
501  const T & rear() const
502  {
503  if (is_empty())
504  throw std::underflow_error("Queue is empty");
505 
506  return BaseList::get_last();
507  }
508 
509  T & put(const T & item)
510  {
511  return BaseList::append(item);
512  }
513 
514  T & put(T && item)
515  {
516  return BaseList::append(std::forward<T>(item));
517  }
518 
519  T get()
520  {
521  if (is_empty())
522  throw std::underflow_error("Queue is empty");
523 
524  return BaseList::remove_first();
525  }
526  };
527 
528  template <typename T, class Queue = ListQueue<T>>
530  {
531  std::mutex mtx;
532  std::condition_variable cond_var;
533  Queue queue;
534 
535  public:
536  T & put(const T & item)
537  {
538  std::lock_guard<std::mutex> lck(mtx);
539  T & ret = queue.put(item);
540  cond_var.notify_one();
541  return ret;
542  }
543 
544  T & put(T && item)
545  {
546  std::lock_guard<std::mutex> lck(mtx);
547  T & ret = queue.put(std::move(item));
548  cond_var.notify_one();
549  return ret;
550  }
551 
552  T get()
553  {
554  std::unique_lock<std::mutex> lck(mtx);
555  cond_var.wait(lck, [this] { return not queue.is_empty(); });
556  return queue.get();
557  }
558 
559  nat_t size() const
560  {
561  std::lock_guard<std::mutex> lck(const_cast<std::mutex &>(mtx));
562  return queue.size();
563  }
564 
565  bool is_empty() const
566  {
567  std::lock_guard<std::mutex> lck(const_cast<std::mutex &>(mtx));
568  return queue.is_empty();
569  }
570  };
571 
572 } // end namespace Designar
573 
574 # endif // DSGQUEUE_H
nat_t size() const
Definition: queue.H:298
T & front()
Definition: queue.H:123
Definition: list.H:35
T DataType
Definition: array.H:194
bool is_empty() const
Definition: queue.H:565
Definition: queue.H:35
FixedQueue(const FixedQueue &q)
Definition: queue.H:65
T & rear()
Definition: queue.H:139
const T & front() const
Definition: queue.H:485
bool is_empty() const
Definition: queue.H:96
T & put(T &&item)
Definition: queue.H:358
DynQueue(const DynQueue &q)
Definition: queue.H:262
double real_t
Definition: types.H:51
T ValueType
Definition: list.H:211
Definition: queue.H:205
T & put(const T &item)
Definition: queue.H:536
T ItemType
Definition: queue.H:53
bool is_full() const
Definition: queue.H:101
T DataType
Definition: queue.H:55
T & rear()
Definition: queue.H:333
const T & rear() const
Definition: queue.H:341
T & put(T &&item)
Definition: queue.H:544
const T & rear() const
Definition: queue.H:501
const T & rear() const
Definition: queue.H:147
void clear()
Definition: queue.H:472
T KeyType
Definition: list.H:209
T & put(T &&item)
Definition: queue.H:514
FixedQueue()
Definition: queue.H:59
FixedQueue(FixedQueue &&q)
Definition: queue.H:71
bool is_empty() const
Definition: queue.H:293
nat_t size() const
Definition: queue.H:106
nat_t size() const
Definition: queue.H:559
bool is_empty() const
Definition: queue.H:462
T ItemType
Definition: array.H:192
nat_t size() const
Definition: queue.H:467
T & put(const T &item)
Definition: queue.H:155
void clear()
Definition: queue.H:116
T KeyType
Definition: queue.H:54
nat_t SizeType
Definition: queue.H:57
T & front()
Definition: queue.H:477
Definition: italgorithms.H:33
ListQueue()
Definition: queue.H:429
T & put(T &&item)
Definition: queue.H:166
T & rear()
Definition: queue.H:493
void clear()
Definition: queue.H:303
T DataType
Definition: list.H:210
nat_t SizeType
Definition: array.H:196
nat_t SizeType
Definition: list.H:212
Definition: array.H:182
Definition: array.H:32
nat_t get_capacity() const
Definition: array.H:266
T ValueType
Definition: array.H:195
unsigned long int nat_t
Definition: types.H:50
ListQueue(const ListQueue &q)
Definition: queue.H:435
DynQueue()
Definition: queue.H:256
nat_t get_capacity() const
Definition: queue.H:111
T ValueType
Definition: queue.H:56
FixedQueue & operator=(const FixedQueue &q)
Definition: queue.H:77
T & put(const T &item)
Definition: queue.H:349
DynQueue(DynQueue &&q)
Definition: queue.H:268
const T & front() const
Definition: queue.H:325
T & front()
Definition: queue.H:317
Definition: queue.H:418
T ItemType
Definition: list.H:208
Definition: queue.H:529
const T & front() const
Definition: queue.H:131
T KeyType
Definition: array.H:193
T & at(nat_t i)
Definition: array.H:276
ListQueue(ListQueue &&q)
Definition: queue.H:441
T & put(const T &item)
Definition: queue.H:509