gem5  v20.1.0.0
circular_queue.hh
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2018 ARM Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are
16  * met: redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer;
18  * redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution;
21  * neither the name of the copyright holders nor the names of its
22  * contributors may be used to endorse or promote products derived from
23  * this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 #ifndef __BASE_CIRCULAR_QUEUE_HH__
39 #define __BASE_CIRCULAR_QUEUE_HH__
40 
41 #include <cassert>
42 #include <cstddef>
43 #include <cstdint>
44 #include <iterator>
45 #include <type_traits>
46 #include <vector>
47 
85 template <typename T>
86 class CircularQueue : private std::vector<T>
87 {
88  protected:
90  using typename Base::reference;
91  using typename Base::const_reference;
92  const uint32_t _capacity;
93  uint32_t _head;
94  uint32_t _tail;
95  uint32_t _empty;
96 
103  uint32_t _round;
104 
106  static uint32_t
107  moduloAdd(uint32_t op1, uint32_t op2, uint32_t size)
108  {
109  return (op1 + op2) % size;
110  }
111 
113  static uint32_t
114  moduloSub(uint32_t op1, uint32_t op2, uint32_t size)
115  {
116  int32_t ret = sub(op1, op2, size);
117  return ret >= 0 ? ret : ret + size;
118  }
119 
120  static int32_t
121  sub(uint32_t op1, uint32_t op2, uint32_t size)
122  {
123  if (op1 > op2)
124  return (op1 - op2) % size;
125  else
126  return -((op2 - op1) % size);
127  }
128 
129  void increase(uint32_t& v, size_t delta = 1)
130  {
131  v = moduloAdd(v, delta, _capacity);
132  }
133 
134  void decrease(uint32_t& v)
135  {
136  v = (v ? v : _capacity) - 1;
137  }
138 
154  public:
155  struct iterator {
157  uint32_t _idx;
158  uint32_t _round;
159 
160  public:
164  iterator(CircularQueue* cq, uint32_t idx, uint32_t round)
165  : _cq(cq), _idx(idx), _round(round) {}
166 
173  using value_type = T;
174  using difference_type = std::ptrdiff_t;
176  using const_reference = const value_type&;
177  using pointer = value_type*;
178  using const_pointer = const value_type*;
179  using iterator_category = std::random_access_iterator_tag; // end of api_base_utils
181 
185  static_assert(std::is_same<reference, T&>::value,
186  "reference type is not assignable as required");
187 
191  iterator() : _cq(nullptr), _idx(0), _round(0) { }
192 
196  iterator(const iterator& it)
197  : _cq(it._cq), _idx(it._idx), _round(it._round) {}
198 
202  iterator&
203  operator=(const iterator& it)
204  {
205  _cq = it._cq;
206  _idx = it._idx;
207  _round = it._round;
208  return *this;
209  }
210 
214  ~iterator() { _cq = nullptr; _idx = 0; _round = 0; }
215 
232  bool
234  {
235  return _cq != nullptr && _cq->isValidIdx(_idx, _round);
236  }
237 
249  bool operator==(const iterator& that) const
250  {
251  return _cq == that._cq && _idx == that._idx &&
252  _round == that._round;
253  }
254 
262  bool operator!=(const iterator& that)
263  {
264  return !(*this == that);
265  }
266 
273  {
274  /* this has to be dereferenceable. */
275  return (*_cq)[_idx];
276  }
277 
282  {
283  /* this has to be dereferenceable. */
284  return (*_cq)[_idx];
285  }
286 
294  {
295  return &((*_cq)[_idx]);
296  }
297 
302  {
303  return &((*_cq)[_idx]);
304  }
305 
312  {
313  /* this has to be dereferenceable. */
314  _cq->increase(_idx);
315  if (_idx == 0)
316  ++_round;
317  return *this;
318  }
319 
325  iterator
327  {
328  iterator t = *this;
329  ++*this;
330  return t;
331  }
332 
338  private:
346  bool
348  {
349  return _cq && !(_idx == _cq->head() &&
350  (_cq->empty() ||
351  (_idx == 0 && _round != _cq->_round + 1) ||
352  (_idx !=0 && _round != _cq->_round)));
353  }
354 
355  public:
362  {
363  /* this has to be decrementable. */
364  assert(decrementable());
365  if (_idx == 0)
366  --_round;
367  _cq->decrease(_idx);
368  return *this;
369  }
370 
376  iterator operator--(int ) { iterator t = *this; --*this; return t; }
377 
384  {
385  assert(_cq);
386  _round += (t + _idx) / _cq->capacity();
387  _idx = _cq->moduloAdd(_idx, t);
388  return *this;
389  }
390 
395  {
396  assert(_cq);
397 
398  /* C does not do euclidean division, so we have to adjust */
399  if (t >= 0) {
400  _round += (-t + _idx) / _cq->capacity();
401  _idx = _cq->moduloSub(_idx, t);
402  } else {
403  *this += -t;
404  }
405  return *this;
406  }
407 
414  {
415  iterator ret(*this);
416  return ret += t;
417  }
418 
423  {
424  iterator ret = it;
425  return ret += t;
426  }
427 
434  {
435  iterator ret(*this);
436  return ret -= t;
437  }
438 
443  {
444  iterator ret = it;
445  return ret -= t;
446  }
447 
455  {
456  /* If a is already at the end, we can safely return 0. */
457  auto ret = _cq->sub(this->_idx, that._idx, _cq->capacity());
458 
459  if (this->_round != that._round) {
460  ret += ((this->_round - that._round) * _cq->capacity());
461  }
462  return ret;
463  }
464 
471  template<typename Idx>
472  typename std::enable_if<std::is_integral<Idx>::value,reference>::type
473  operator[](const Idx& index) { return *(*this + index); }
474 
480  bool
481  operator<(const iterator& that) const
482  {
483  assert(_cq && that._cq == _cq);
484  return (this->_round < that._round) ||
485  (this->_round == that._round && _idx < that._idx);
486  }
487 
491  bool
492  operator>(const iterator& that) const
493  { return !(*this <= that); }
494 
498  bool operator>=(const iterator& that) const
499  { return !(*this < that); }
500 
504  bool operator<=(const iterator& that) const
505  { return !(that < *this); }
506 
510  size_t idx() const { return _idx; }
511  };
512 
513  public:
517  using Base::operator[];
518 
522  explicit CircularQueue(uint32_t size = 0)
523  : _capacity(size), _head(1), _tail(0), _empty(true), _round(0)
524  {
525  Base::resize(size);
526  }
527 
536  void flush()
537  {
538  _head = 1;
539  _round = 0;
540  _tail = 0;
541  _empty = true;
542  }
543 
547  bool isValidIdx(size_t idx) const
548  {
549  /* An index is invalid if:
550  * - The queue is empty.
551  * (6,T,3,2): |-|-|-]|[-|-|x|
552  * - head is small than tail and:
553  * - It is greater than both head and tail.
554  * (6,F,1,3): |-|[o|o|o]|-|x|
555  * - It is less than both head and tail.
556  * (6,F,1,3): |x|[o|o|o]|-|-|
557  * - It is greater than the tail and not than the head.
558  * (6,F,4,1): |o|o]|-|x|[o|o|
559  */
560  return !(_empty || (
561  (_head < _tail) && (
562  (_head < idx && _tail < idx) ||
563  (_head > idx && _tail > idx)
564  )) || (_tail < idx && idx < _head));
565  }
566 
571  bool isValidIdx(size_t idx, uint32_t round) const
572  {
573  /* An index is valid if:
574  * - The queue is not empty.
575  * - round == R and
576  * - index <= tail (if index > tail, that would be PTE)
577  * - Either:
578  * - head <= index
579  * (6,F,1,3,R): |-|[o|(*,r)|o]|-|-|
580  * - head > tail
581  * (6,F,5,3,R): |o|o|(*,r)|o]|-|[o|
582  * The remaining case means the the iterator is BTB:
583  * (6,F,3,4,R): |-|-|(x,r)|[o|o]|-|
584  * - round + 1 == R and:
585  * - index > tail. If index <= tail, that would be BTB:
586  * (6,F,2,3,r): | -|- |[(*,r)|o]|-|-|
587  * (6,F,0,1,r+1): |[o|o]| (x,r)|- |-|-|
588  * (6,F,0,3,r+1): |[o|o | (*,r)|o]|-|-|
589  * - index >= head. If index < head, that would be BTB:
590  * (6,F,5,2,R): |o|o]|-|-|(x,r)|[o|
591  * - head > tail. If head <= tail, that would be BTB:
592  * (6,F,3,4,R): |[o|o]|(x,r)|-|-|-|
593  * Other values of the round meand that the index is PTE or BTB
594  */
595  return (!_empty && (
596  (round == _round && idx <= _tail && (
597  _head <= idx || _head > _tail)) ||
598  (round + 1 == _round &&
599  idx > _tail &&
600  idx >= _head &&
601  _head > _tail)
602  ));
603  }
604 
608  reference front() { return (*this)[_head]; }
609 
613  reference back() { return (*this)[_tail]; }
614 
618  uint32_t head() const { return _head; }
619 
623  uint32_t tail() const { return _tail; }
624 
628  size_t capacity() const { return _capacity; }
629 
633  uint32_t size() const
634  {
635  if (_empty)
636  return 0;
637  else if (_head <= _tail)
638  return _tail - _head + 1;
639  else
640  return _capacity - _head + _tail + 1;
641  }
642 
643  uint32_t moduloAdd(uint32_t s1, uint32_t s2) const
644  {
645  return moduloAdd(s1, s2, _capacity);
646  }
647 
648  uint32_t moduloSub(uint32_t s1, uint32_t s2) const
649  {
650  return moduloSub(s1, s2, _capacity);
651  }
652 
663  void pop_front(size_t num_elem = 1)
664  {
665  if (num_elem == 0) return;
666  auto hIt = begin();
667  hIt += num_elem;
668  assert(hIt <= end());
669  _empty = hIt == end();
670  _head = hIt._idx;
671  }
672 
678  void pop_back()
679  {
680  assert (!_empty);
681  _empty = _head == _tail;
682  if (_tail == 0)
683  --_round;
684  decrease(_tail);
685  }
686 
692  void push_back(typename Base::value_type val)
693  {
694  advance_tail();
695  (*this)[_tail] = val;
696  }
697 
705  {
706  increase(_tail);
707  if (_tail == 0)
708  ++_round;
709 
710  if (_tail == _head && !_empty)
711  increase(_head);
712 
713  _empty = false;
714  }
715 
723  void advance_tail(uint32_t len)
724  {
725  for (auto idx = 0; idx < len; idx++)
726  advance_tail();
727  }
728 
734  bool empty() const { return _empty; }
735 
744  bool full() const
745  {
746  return !_empty &&
747  (_tail + 1 == _head || (_tail + 1 == _capacity && _head == 0));
748  }
749 
755  iterator begin()
756  {
757  if (_empty)
758  return end();
759  else if (_head > _tail)
760  return iterator(this, _head, _round - 1);
761  else
762  return iterator(this, _head, _round);
763  }
764 
765  /* TODO: This should return a const_iterator. */
769  iterator begin() const
770  {
771  if (_empty)
772  return end();
773  else if (_head > _tail)
774  return iterator(const_cast<CircularQueue*>(this), _head,
775  _round - 1);
776  else
777  return iterator(const_cast<CircularQueue*>(this), _head,
778  _round);
779  }
780 
784  iterator end()
785  {
786  auto poi = moduloAdd(_tail, 1);
787  auto round = _round;
788  if (poi == 0)
789  ++round;
790  return iterator(this, poi, round);
791  }
792 
796  iterator end() const
797  {
798  auto poi = moduloAdd(_tail, 1);
799  auto round = _round;
800  if (poi == 0)
801  ++round;
802  return iterator(const_cast<CircularQueue*>(this), poi, round);
803  }
804 
812  iterator getIterator(size_t idx)
813  {
814  assert(isValidIdx(idx) || moduloAdd(_tail, 1) == idx);
815  if (_empty)
816  return end();
817 
818  uint32_t round = _round;
819  if (idx > _tail) {
820  if (idx >= _head && _head > _tail) {
821  round -= 1;
822  }
823  } else if (idx < _head && _tail + 1 == _capacity) {
824  round += 1;
825  }
826  return iterator(this, idx, round);
827  }
828 };
829 
830 #endif /* __BASE_CIRCULARQUEUE_HH__ */
CircularQueue::head
uint32_t head() const
Definition: circular_queue.hh:618
CircularQueue::iterator::operator->
pointer operator->()
Dereference operator.
Definition: circular_queue.hh:293
CircularQueue::decrease
void decrease(uint32_t &v)
Definition: circular_queue.hh:134
CircularQueue::moduloSub
static uint32_t moduloSub(uint32_t op1, uint32_t op2, uint32_t size)
General modular subtraction.
Definition: circular_queue.hh:114
CircularQueue::_capacity
const uint32_t _capacity
Definition: circular_queue.hh:92
CircularQueue::_head
uint32_t _head
Definition: circular_queue.hh:93
CircularQueue::iterator::difference_type
std::ptrdiff_t difference_type
Definition: circular_queue.hh:174
CircularQueue::iterator::const_reference
const value_type & const_reference
Definition: circular_queue.hh:176
CircularQueue::advance_tail
void advance_tail()
Increases the tail by one.
Definition: circular_queue.hh:704
CircularQueue::iterator::dereferenceable
bool dereferenceable() const
Test dereferenceability.
Definition: circular_queue.hh:233
MipsISA::index
Bitfield< 30, 0 > index
Definition: pra_constants.hh:44
CircularQueue::iterator::operator+
iterator operator+(const difference_type &t)
Addition operator.
Definition: circular_queue.hh:413
CircularQueue::iterator::operator-
difference_type operator-(const iterator &that)
Difference operator.
Definition: circular_queue.hh:454
CircularQueue::iterator::operator+
friend iterator operator+(const difference_type &t, iterator &it)
Definition: circular_queue.hh:422
CircularQueue::getIterator
iterator getIterator(size_t idx)
Return an iterator to an index in the vector.
Definition: circular_queue.hh:812
CircularQueue::iterator::operator++
iterator operator++(int)
Post-increment operator.
Definition: circular_queue.hh:326
CircularQueue::moduloSub
uint32_t moduloSub(uint32_t s1, uint32_t s2) const
Definition: circular_queue.hh:648
CircularQueue::iterator::operator--
iterator & operator--()
Pre-decrement operator.
Definition: circular_queue.hh:361
CircularQueue::iterator::operator*
const_reference operator*() const
Definition: circular_queue.hh:281
CircularQueue::iterator::value_type
T value_type
Iterator Traits.
Definition: circular_queue.hh:173
type
uint8_t type
Definition: inet.hh:421
CircularQueue::pop_back
void pop_back()
Circularly decrease the tail pointer.
Definition: circular_queue.hh:678
CircularQueue
Circular queue.
Definition: circular_queue.hh:86
CircularQueue::iterator::operator-
iterator operator-(const difference_type &t)
Substraction operator.
Definition: circular_queue.hh:433
CircularQueue::begin
iterator begin()
Iterators.
Definition: circular_queue.hh:755
std::vector
STL vector class.
Definition: stl.hh:37
CircularQueue::sub
static int32_t sub(uint32_t op1, uint32_t op2, uint32_t size)
Definition: circular_queue.hh:121
CircularQueue::iterator::operator[]
std::enable_if< std::is_integral< Idx >::value, reference >::type operator[](const Idx &index)
Index operator.
Definition: circular_queue.hh:473
CircularQueue::flush
void flush()
Remove all the elements in the queue.
Definition: circular_queue.hh:536
CircularQueue::iterator
Iterator to the circular queue.
Definition: circular_queue.hh:155
CircularQueue::iterator::operator++
iterator & operator++()
Pre-increment operator.
Definition: circular_queue.hh:311
CircularQueue::full
bool full() const
Is the queue full? A queue is full if the head is the 0^{th} element and the tail is the (size-1)^{th...
Definition: circular_queue.hh:744
CircularQueue::back
reference back()
Definition: circular_queue.hh:613
CircularQueue::iterator::operator>
bool operator>(const iterator &that) const
Definition: circular_queue.hh:492
CircularQueue::iterator::operator+=
iterator & operator+=(const difference_type &t)
RandomAccessIterator requirements.
Definition: circular_queue.hh:383
CircularQueue::iterator::const_pointer
const value_type * const_pointer
Definition: circular_queue.hh:178
CircularQueue::front
reference front()
Definition: circular_queue.hh:608
CircularQueue::iterator::operator--
iterator operator--(int)
Post-decrement operator.
Definition: circular_queue.hh:376
CircularQueue::iterator::iterator
iterator(const iterator &it)
Definition: circular_queue.hh:196
CircularQueue::iterator::idx
size_t idx() const
OutputIterator has no extra requirements.
Definition: circular_queue.hh:510
CircularQueue::size
uint32_t size() const
Definition: circular_queue.hh:633
CircularQueue::isValidIdx
bool isValidIdx(size_t idx, uint32_t round) const
Test if the index is in the range of valid elements.
Definition: circular_queue.hh:571
CircularQueue::end
iterator end()
Definition: circular_queue.hh:784
CircularQueue::iterator::reference
value_type & reference
Definition: circular_queue.hh:175
CircularQueue::iterator::operator-=
iterator & operator-=(const difference_type &t)
Definition: circular_queue.hh:394
CircularQueue::end
iterator end() const
Definition: circular_queue.hh:796
X86ISA::val
Bitfield< 63 > val
Definition: misc.hh:769
CircularQueue::push_back
void push_back(typename Base::value_type val)
Pushes an element at the end of the queue.
Definition: circular_queue.hh:692
CircularQueue::_round
uint32_t _round
Counter for how many times the tail wraps around.
Definition: circular_queue.hh:103
CircularQueue::iterator::decrementable
bool decrementable() const
ForwardIterator The multipass guarantee is provided by the reliance on _idx.
Definition: circular_queue.hh:347
CircularQueue::increase
void increase(uint32_t &v, size_t delta=1)
Definition: circular_queue.hh:129
CircularQueue::iterator::operator>=
bool operator>=(const iterator &that) const
Definition: circular_queue.hh:498
CircularQueue::iterator::_cq
CircularQueue * _cq
Definition: circular_queue.hh:156
CircularQueue::pop_front
void pop_front(size_t num_elem=1)
Circularly increase the head pointer.
Definition: circular_queue.hh:663
CircularQueue::iterator::operator<=
bool operator<=(const iterator &that) const
Definition: circular_queue.hh:504
CircularQueue::iterator::operator<
bool operator<(const iterator &that) const
Comparisons.
Definition: circular_queue.hh:481
CircularQueue::iterator::operator*
reference operator*()
Dereference operator.
Definition: circular_queue.hh:272
CircularQueue::empty
bool empty() const
Is the queue empty?
Definition: circular_queue.hh:734
CircularQueue::iterator::operator-
friend iterator operator-(const difference_type &t, iterator &it)
Definition: circular_queue.hh:442
CircularQueue::iterator::iterator_category
std::random_access_iterator_tag iterator_category
Definition: circular_queue.hh:179
CircularQueue::_empty
uint32_t _empty
Definition: circular_queue.hh:95
CircularQueue::moduloAdd
uint32_t moduloAdd(uint32_t s1, uint32_t s2) const
Definition: circular_queue.hh:643
CircularQueue::iterator::operator==
bool operator==(const iterator &that) const
InputIterator.
Definition: circular_queue.hh:249
CircularQueue::capacity
size_t capacity() const
Definition: circular_queue.hh:628
ArmISA::t
Bitfield< 5 > t
Definition: miscregs_types.hh:67
ArmISA::len
Bitfield< 18, 16 > len
Definition: miscregs_types.hh:439
CircularQueue::iterator::operator!=
bool operator!=(const iterator &that)
Inequality operator.
Definition: circular_queue.hh:262
CircularQueue::iterator::_idx
uint32_t _idx
Definition: circular_queue.hh:157
CircularQueue::iterator::operator->
const_pointer operator->() const
Definition: circular_queue.hh:301
CircularQueue::moduloAdd
static uint32_t moduloAdd(uint32_t op1, uint32_t op2, uint32_t size)
General modular addition.
Definition: circular_queue.hh:107
CircularQueue::begin
iterator begin() const
Definition: circular_queue.hh:769
CircularQueue::iterator::operator=
iterator & operator=(const iterator &it)
Definition: circular_queue.hh:203
CircularQueue::isValidIdx
bool isValidIdx(size_t idx) const
Test if the index is in the range of valid elements.
Definition: circular_queue.hh:547
CircularQueue::CircularQueue
CircularQueue(uint32_t size=0)
Definition: circular_queue.hh:522
CircularQueue::_tail
uint32_t _tail
Definition: circular_queue.hh:94
CircularQueue::tail
uint32_t tail() const
Definition: circular_queue.hh:623
CircularQueue::iterator::_round
uint32_t _round
Definition: circular_queue.hh:158
CircularQueue::advance_tail
void advance_tail(uint32_t len)
Increases the tail by a specified number of steps.
Definition: circular_queue.hh:723
CircularQueue::iterator::iterator
iterator(CircularQueue *cq, uint32_t idx, uint32_t round)
Definition: circular_queue.hh:164
CircularQueue::iterator::pointer
value_type * pointer
Definition: circular_queue.hh:177
CircularQueue::iterator::iterator
iterator()
Trait reference type iterator satisfies OutputIterator, therefore reference must be T&.
Definition: circular_queue.hh:191
ArmISA::v
Bitfield< 28 > v
Definition: miscregs_types.hh:51
CircularQueue::iterator::~iterator
~iterator()
Definition: circular_queue.hh:214

Generated on Wed Sep 30 2020 14:02:07 for gem5 by doxygen 1.8.17