circular_queue.hh revision 13797:1969bb477391
113531Sjairo.balart@metempsy.com/* 214167Sgiacomo.travaglini@arm.com * Copyright (c) 2017-2018 ARM Limited 314167Sgiacomo.travaglini@arm.com * All rights reserved 414167Sgiacomo.travaglini@arm.com * 514167Sgiacomo.travaglini@arm.com * The license below extends only to copyright in the software and shall 614167Sgiacomo.travaglini@arm.com * not be construed as granting a license to any other intellectual 714167Sgiacomo.travaglini@arm.com * property including but not limited to intellectual property relating 814167Sgiacomo.travaglini@arm.com * to a hardware implementation of the functionality of the software 914167Sgiacomo.travaglini@arm.com * licensed hereunder. You may use the software subject to the license 1014167Sgiacomo.travaglini@arm.com * terms below provided that you ensure that this notice is replicated 1114167Sgiacomo.travaglini@arm.com * unmodified and in its entirety in all distributions of the software, 1214167Sgiacomo.travaglini@arm.com * modified or unmodified, in source code or in binary form. 1314167Sgiacomo.travaglini@arm.com * 1413531Sjairo.balart@metempsy.com * Redistribution and use in source and binary forms, with or without 1513531Sjairo.balart@metempsy.com * modification, are permitted provided that the following conditions are 1613531Sjairo.balart@metempsy.com * met: redistributions of source code must retain the above copyright 1713531Sjairo.balart@metempsy.com * notice, this list of conditions and the following disclaimer; 1813531Sjairo.balart@metempsy.com * redistributions in binary form must reproduce the above copyright 1913531Sjairo.balart@metempsy.com * notice, this list of conditions and the following disclaimer in the 2013531Sjairo.balart@metempsy.com * documentation and/or other materials provided with the distribution; 2113531Sjairo.balart@metempsy.com * neither the name of the copyright holders nor the names of its 2213531Sjairo.balart@metempsy.com * contributors may be used to endorse or promote products derived from 2313531Sjairo.balart@metempsy.com * this software without specific prior written permission. 2413531Sjairo.balart@metempsy.com * 2513531Sjairo.balart@metempsy.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2613531Sjairo.balart@metempsy.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2713531Sjairo.balart@metempsy.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2813531Sjairo.balart@metempsy.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2913531Sjairo.balart@metempsy.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3013531Sjairo.balart@metempsy.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3113531Sjairo.balart@metempsy.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3213531Sjairo.balart@metempsy.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3313531Sjairo.balart@metempsy.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3413531Sjairo.balart@metempsy.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3513531Sjairo.balart@metempsy.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3613531Sjairo.balart@metempsy.com * 3713531Sjairo.balart@metempsy.com * Authors: Rekai Gonzalez-Alberquilla 3813531Sjairo.balart@metempsy.com */ 3913531Sjairo.balart@metempsy.com 4013531Sjairo.balart@metempsy.com#ifndef __BASE_CIRCULAR_QUEUE_HH__ 4113531Sjairo.balart@metempsy.com#define __BASE_CIRCULAR_QUEUE_HH__ 4213756Sjairo.balart@metempsy.com 4313531Sjairo.balart@metempsy.com#include <vector> 4413531Sjairo.balart@metempsy.com 4513531Sjairo.balart@metempsy.com/** Circular queue. 4613531Sjairo.balart@metempsy.com * Circular queue implemented on top of a standard vector. Instead of using 4713531Sjairo.balart@metempsy.com * a sentinel entry, we use a boolean to distinguish the case in which the 4813531Sjairo.balart@metempsy.com * queue is full or empty. 4913531Sjairo.balart@metempsy.com * Thus, a circular queue is represented by the 5-tuple 5013531Sjairo.balart@metempsy.com * (Capacity, IsEmpty?, Head, Tail, Round) 5113531Sjairo.balart@metempsy.com * Where: 5213756Sjairo.balart@metempsy.com * - Capacity is the size of the underlying vector. 5313756Sjairo.balart@metempsy.com * - IsEmpty? can be T or F. 5413756Sjairo.balart@metempsy.com * - Head is the index in the vector of the first element of the queue. 5513756Sjairo.balart@metempsy.com * - Tail is the index in the vector of the last element of the queue. 5613756Sjairo.balart@metempsy.com * - Round is the counter of how many times the Tail has wrapped around. 5713756Sjairo.balart@metempsy.com * A queue is empty when 5813756Sjairo.balart@metempsy.com * Head == (Tail + 1 mod Capacity) && IsEmpty?. 5913531Sjairo.balart@metempsy.com * Conversely, a queue if full when 6013756Sjairo.balart@metempsy.com * Head == (Tail + 1 mod Capacity) && !IsEmpty?. 6113756Sjairo.balart@metempsy.com * Comments may show depictions of the underlying vector in the following 6213756Sjairo.balart@metempsy.com * format: '|' delimit the 'cells' of the underlying vector. '-' represents 6313756Sjairo.balart@metempsy.com * an element of the vector that is out-of-bounds of the circular queue, 6413756Sjairo.balart@metempsy.com * while 'o' represents and element that is inside the bounds. The 6513756Sjairo.balart@metempsy.com * characters '[' and ']' are added to mark the entries that hold the head 6613756Sjairo.balart@metempsy.com * and tail of the circular queue respectively. 6713531Sjairo.balart@metempsy.com * E.g.: 6813531Sjairo.balart@metempsy.com * - Empty queues of capacity 4: 6913531Sjairo.balart@metempsy.com * (4,T,1,0,_): |-]|[-|-|-| (4,T,3,2): |-|-|-]|[-| 7013531Sjairo.balart@metempsy.com * - Full queues of capacity 4: 7113531Sjairo.balart@metempsy.com * (4,F,1,0,_): |o]|[o|o|o| (4,F,3,2): |o|o|o]|[o| 7213531Sjairo.balart@metempsy.com * - Queues of capacity 4 with 2 elements: 7313531Sjairo.balart@metempsy.com * (4,F,0,1,_): |[o|o]|-|-| (4,F,3,0): |o]|-|-|[o| 7413531Sjairo.balart@metempsy.com * 7513531Sjairo.balart@metempsy.com * The Round number is only relevant for checking validity of indices, 7613531Sjairo.balart@metempsy.com * therefore it will be omitted or shown as '_' 7713531Sjairo.balart@metempsy.com */ 7813531Sjairo.balart@metempsy.comtemplate <typename T> 7914167Sgiacomo.travaglini@arm.comclass CircularQueue : private std::vector<T> 8014167Sgiacomo.travaglini@arm.com{ 8114167Sgiacomo.travaglini@arm.com protected: 8214167Sgiacomo.travaglini@arm.com using Base = std::vector<T>; 8314167Sgiacomo.travaglini@arm.com using typename Base::reference; 8414167Sgiacomo.travaglini@arm.com using typename Base::const_reference; 8513531Sjairo.balart@metempsy.com const uint32_t _capacity; 8613531Sjairo.balart@metempsy.com uint32_t _head; 8713531Sjairo.balart@metempsy.com uint32_t _tail; 8813531Sjairo.balart@metempsy.com uint32_t _empty; 8913531Sjairo.balart@metempsy.com 9013531Sjairo.balart@metempsy.com /** Counter for how many times the tail wraps around. 9113531Sjairo.balart@metempsy.com * Some parts of the code rely on getting the past the end iterator, and 9213531Sjairo.balart@metempsy.com * expect to use it after inserting on the tail. To support this without 9313531Sjairo.balart@metempsy.com * ambiguity, we need the round number to guarantee that it did not become 9413531Sjairo.balart@metempsy.com * a before-the-beginning iterator. 9513531Sjairo.balart@metempsy.com */ 9613531Sjairo.balart@metempsy.com uint32_t _round; 9713531Sjairo.balart@metempsy.com 9813531Sjairo.balart@metempsy.com /** General modular addition. */ 9913531Sjairo.balart@metempsy.com static uint32_t 10013531Sjairo.balart@metempsy.com moduloAdd(uint32_t op1, uint32_t op2, uint32_t size) 10113531Sjairo.balart@metempsy.com { 10213531Sjairo.balart@metempsy.com return (op1 + op2) % size; 10313531Sjairo.balart@metempsy.com } 10413531Sjairo.balart@metempsy.com 10513531Sjairo.balart@metempsy.com /** General modular subtraction. */ 10613531Sjairo.balart@metempsy.com static uint32_t 10713531Sjairo.balart@metempsy.com moduloSub(uint32_t op1, uint32_t op2, uint32_t size) 10813531Sjairo.balart@metempsy.com { 10913531Sjairo.balart@metempsy.com int32_t ret = sub(op1, op2, size); 11013531Sjairo.balart@metempsy.com return ret >= 0 ? ret : ret + size; 11113531Sjairo.balart@metempsy.com } 11213531Sjairo.balart@metempsy.com 11313531Sjairo.balart@metempsy.com static int32_t 11413531Sjairo.balart@metempsy.com sub(uint32_t op1, uint32_t op2, uint32_t size) 11513531Sjairo.balart@metempsy.com { 11613531Sjairo.balart@metempsy.com if (op1 > op2) 11713531Sjairo.balart@metempsy.com return (op1 - op2) % size; 11813531Sjairo.balart@metempsy.com else 11913531Sjairo.balart@metempsy.com return -((op2 - op1) % size); 12013531Sjairo.balart@metempsy.com } 12113531Sjairo.balart@metempsy.com 12213531Sjairo.balart@metempsy.com void increase(uint32_t& v, size_t delta = 1) 12313531Sjairo.balart@metempsy.com { 12413531Sjairo.balart@metempsy.com v = moduloAdd(v, delta, _capacity); 12513531Sjairo.balart@metempsy.com } 12613531Sjairo.balart@metempsy.com 12713531Sjairo.balart@metempsy.com void decrease(uint32_t& v) 12813531Sjairo.balart@metempsy.com { 12913531Sjairo.balart@metempsy.com v = (v ? v : _capacity) - 1; 13013531Sjairo.balart@metempsy.com } 13113531Sjairo.balart@metempsy.com 13213531Sjairo.balart@metempsy.com /** Iterator to the circular queue. 13313531Sjairo.balart@metempsy.com * iterator implementation to provide the circular-ness that the 13413531Sjairo.balart@metempsy.com * standard std::vector<T>::iterator does not implement. 13513531Sjairo.balart@metempsy.com * Iterators to a queue are represented by a pair of a character and the 13613531Sjairo.balart@metempsy.com * round counter. For the character, '*' denotes the element pointed to by 13713531Sjairo.balart@metempsy.com * the iterator if it is valid. 'x' denotes the element pointed to by the 13813531Sjairo.balart@metempsy.com * iterator when it is BTB or PTE. 13913531Sjairo.balart@metempsy.com * E.g.: 14013531Sjairo.balart@metempsy.com * - Iterator to the head of a queue of capacity 4 with 2 elems. 14113531Sjairo.balart@metempsy.com * (4,F,0,1,R): |[(*,R)|o]|-|-| (4,F,3,0): |o]|-|-|[(*,R)| 14213531Sjairo.balart@metempsy.com * - Iterator to the tail of a queue of capacity 4 with 2 elems. 14313531Sjairo.balart@metempsy.com * (4,F,0,1,R): |[o|(*,R)]|-|-| (4,F,3,0): |(*,R)]|-|-|[o| 14413531Sjairo.balart@metempsy.com * - Iterator to the end of a queue of capacity 4 with 2 elems. 14513531Sjairo.balart@metempsy.com * (4,F,0,1,R): |[o|o]|(x,R)|-| (4,F,3,0): |o]|(x,R)|-|[o| 14613531Sjairo.balart@metempsy.com */ 14713531Sjairo.balart@metempsy.com public: 14813531Sjairo.balart@metempsy.com struct iterator { 14913756Sjairo.balart@metempsy.com CircularQueue* _cq; 15013531Sjairo.balart@metempsy.com uint32_t _idx; 15113531Sjairo.balart@metempsy.com uint32_t _round; 15213531Sjairo.balart@metempsy.com 15313531Sjairo.balart@metempsy.com public: 15413756Sjairo.balart@metempsy.com iterator(CircularQueue* cq, uint32_t idx, uint32_t round) 15513531Sjairo.balart@metempsy.com : _cq(cq), _idx(idx), _round(round) {} 15613531Sjairo.balart@metempsy.com 15713531Sjairo.balart@metempsy.com /** Iterator Traits */ 15813531Sjairo.balart@metempsy.com using value_type = T; 15913531Sjairo.balart@metempsy.com using difference_type = std::ptrdiff_t; 16013531Sjairo.balart@metempsy.com using reference = value_type&; 16113531Sjairo.balart@metempsy.com using const_reference = const value_type&; 16213531Sjairo.balart@metempsy.com using pointer = value_type*; 16313531Sjairo.balart@metempsy.com using const_pointer = const value_type*; 16413756Sjairo.balart@metempsy.com using iterator_category = std::random_access_iterator_tag; 16513756Sjairo.balart@metempsy.com 16613531Sjairo.balart@metempsy.com /** Trait reference type 16713531Sjairo.balart@metempsy.com * iterator satisfies OutputIterator, therefore reference 16813531Sjairo.balart@metempsy.com * must be T& */ 16913531Sjairo.balart@metempsy.com static_assert(std::is_same<reference, T&>::value, 17013531Sjairo.balart@metempsy.com "reference type is not assignable as required"); 17113531Sjairo.balart@metempsy.com 17213531Sjairo.balart@metempsy.com iterator() : _cq(nullptr), _idx(0), _round(0) { } 17313531Sjairo.balart@metempsy.com 17413531Sjairo.balart@metempsy.com iterator(const iterator& it) 17513531Sjairo.balart@metempsy.com : _cq(it._cq), _idx(it._idx), _round(it._round) {} 17613531Sjairo.balart@metempsy.com 17713531Sjairo.balart@metempsy.com iterator& 17813531Sjairo.balart@metempsy.com operator=(const iterator& it) 17913531Sjairo.balart@metempsy.com { 18013531Sjairo.balart@metempsy.com _cq = it._cq; 18113531Sjairo.balart@metempsy.com _idx = it._idx; 18213531Sjairo.balart@metempsy.com _round = it._round; 18313531Sjairo.balart@metempsy.com return *this; 18413531Sjairo.balart@metempsy.com } 18513756Sjairo.balart@metempsy.com 18613756Sjairo.balart@metempsy.com ~iterator() { _cq = nullptr; _idx = 0; _round = 0; } 18713531Sjairo.balart@metempsy.com 18813531Sjairo.balart@metempsy.com /** Test dereferenceability. 18913531Sjairo.balart@metempsy.com * An iterator is dereferenceable if it is pointing to a non-null 19013531Sjairo.balart@metempsy.com * circular queue, it is not the past-the-end iterator and the 19113531Sjairo.balart@metempsy.com * index is a valid index to that queue. PTE test is required to 19213531Sjairo.balart@metempsy.com * distinguish between: 19313531Sjairo.balart@metempsy.com * - An iterator to the first element of a full queue 19413531Sjairo.balart@metempsy.com * (4,F,1,0): |o]|[*|o|o| 19513531Sjairo.balart@metempsy.com * - The end() iterator of a full queue 19613531Sjairo.balart@metempsy.com * (4,F,1,0): |o]|x[o|o|o| 19713756Sjairo.balart@metempsy.com * Sometimes, though, users will get the PTE iterator and expect it 19813531Sjairo.balart@metempsy.com * to work after growing the buffer on the tail, so we have to 19913531Sjairo.balart@metempsy.com * check if the iterator is still PTE. 20013531Sjairo.balart@metempsy.com */ 20113531Sjairo.balart@metempsy.com bool 20213531Sjairo.balart@metempsy.com dereferenceable() const 20313531Sjairo.balart@metempsy.com { 20413531Sjairo.balart@metempsy.com return _cq != nullptr && _cq->isValidIdx(_idx, _round); 20513531Sjairo.balart@metempsy.com } 20613756Sjairo.balart@metempsy.com 20713756Sjairo.balart@metempsy.com /** InputIterator. */ 20813531Sjairo.balart@metempsy.com 20913531Sjairo.balart@metempsy.com /** Equality operator. 21013531Sjairo.balart@metempsy.com * Two iterators must point to the same, possibly null, circular 21113531Sjairo.balart@metempsy.com * queue and the same element on it, including PTE, to be equal. 21213531Sjairo.balart@metempsy.com * In case the clients the the PTE iterator and then grow on the back 21313531Sjairo.balart@metempsy.com * and expect it to work, we have to check if the PTE is still PTE 21413531Sjairo.balart@metempsy.com */ 21513531Sjairo.balart@metempsy.com bool operator==(const iterator& that) const 21613531Sjairo.balart@metempsy.com { 21713531Sjairo.balart@metempsy.com return _cq == that._cq && _idx == that._idx && 21813531Sjairo.balart@metempsy.com _round == that._round; 21913531Sjairo.balart@metempsy.com } 22013531Sjairo.balart@metempsy.com 22113756Sjairo.balart@metempsy.com /** Inequality operator. 22213531Sjairo.balart@metempsy.com * Conversely, two iterators are different if they both point to 22313531Sjairo.balart@metempsy.com * different circular queues or they point to different elements. 22413531Sjairo.balart@metempsy.com */ 22513531Sjairo.balart@metempsy.com bool operator!=(const iterator& that) 22613531Sjairo.balart@metempsy.com { 22713531Sjairo.balart@metempsy.com return !(*this == that); 22813531Sjairo.balart@metempsy.com } 22913531Sjairo.balart@metempsy.com 23013756Sjairo.balart@metempsy.com /** Dereference operator. */ 23113756Sjairo.balart@metempsy.com reference operator*() 23213531Sjairo.balart@metempsy.com { 23313531Sjairo.balart@metempsy.com /* this has to be dereferenceable. */ 23413531Sjairo.balart@metempsy.com return (*_cq)[_idx]; 23513531Sjairo.balart@metempsy.com } 23613531Sjairo.balart@metempsy.com 23713531Sjairo.balart@metempsy.com const_reference operator*() const 23813531Sjairo.balart@metempsy.com { 23913531Sjairo.balart@metempsy.com /* this has to be dereferenceable. */ 24013531Sjairo.balart@metempsy.com return (*_cq)[_idx]; 24113531Sjairo.balart@metempsy.com } 24213531Sjairo.balart@metempsy.com 24313531Sjairo.balart@metempsy.com /** Dereference operator. 24413756Sjairo.balart@metempsy.com * Rely on operator* to check for dereferenceability. 24513531Sjairo.balart@metempsy.com */ 24613531Sjairo.balart@metempsy.com pointer operator->() 24713531Sjairo.balart@metempsy.com { 24813531Sjairo.balart@metempsy.com return &((*_cq)[_idx]); 24913531Sjairo.balart@metempsy.com } 25013531Sjairo.balart@metempsy.com 25113531Sjairo.balart@metempsy.com const_pointer operator->() const 25213531Sjairo.balart@metempsy.com { 25313531Sjairo.balart@metempsy.com return &((*_cq)[_idx]); 25413531Sjairo.balart@metempsy.com } 25513756Sjairo.balart@metempsy.com 25613756Sjairo.balart@metempsy.com /** Pre-increment operator. */ 25713531Sjairo.balart@metempsy.com iterator& operator++() 25813531Sjairo.balart@metempsy.com { 25913531Sjairo.balart@metempsy.com /* this has to be dereferenceable. */ 26013531Sjairo.balart@metempsy.com _cq->increase(_idx); 26113531Sjairo.balart@metempsy.com if (_idx == 0) 26213531Sjairo.balart@metempsy.com ++_round; 26313531Sjairo.balart@metempsy.com return *this; 26413531Sjairo.balart@metempsy.com } 26513531Sjairo.balart@metempsy.com 26613531Sjairo.balart@metempsy.com /** Post-increment operator. */ 26713531Sjairo.balart@metempsy.com iterator 26813531Sjairo.balart@metempsy.com operator++(int) 26913756Sjairo.balart@metempsy.com { 27013531Sjairo.balart@metempsy.com iterator t = *this; 27113531Sjairo.balart@metempsy.com ++*this; 27213531Sjairo.balart@metempsy.com return t; 27313531Sjairo.balart@metempsy.com } 27413531Sjairo.balart@metempsy.com 27513531Sjairo.balart@metempsy.com /** ForwardIterator 27613531Sjairo.balart@metempsy.com * The multipass guarantee is provided by the reliance on _idx. 27713531Sjairo.balart@metempsy.com */ 27813531Sjairo.balart@metempsy.com 27913531Sjairo.balart@metempsy.com /** BidirectionalIterator requirements. */ 28013756Sjairo.balart@metempsy.com private: 28113756Sjairo.balart@metempsy.com /** Test decrementability. 28213531Sjairo.balart@metempsy.com * An iterator to a non-null circular queue is not-decrementable 28313531Sjairo.balart@metempsy.com * if it is pointing to the head element, unless the queue is full 28413531Sjairo.balart@metempsy.com * and we are talking about the past-the-end iterator. In that case, 28513531Sjairo.balart@metempsy.com * the iterator round equals the cq round unless the head is at the 28613531Sjairo.balart@metempsy.com * zero position and the round is one more than the cq round. 28713531Sjairo.balart@metempsy.com */ 28813531Sjairo.balart@metempsy.com bool 28913531Sjairo.balart@metempsy.com decrementable() const 29013531Sjairo.balart@metempsy.com { 29113531Sjairo.balart@metempsy.com return _cq && !(_idx == _cq->head() && 29213531Sjairo.balart@metempsy.com (_cq->empty() || 29313756Sjairo.balart@metempsy.com (_idx == 0 && _round != _cq->_round + 1) || 29413531Sjairo.balart@metempsy.com (_idx !=0 && _round != _cq->_round))); 29513531Sjairo.balart@metempsy.com } 29613531Sjairo.balart@metempsy.com 29713531Sjairo.balart@metempsy.com public: 29813531Sjairo.balart@metempsy.com /** Pre-decrement operator. */ 29913531Sjairo.balart@metempsy.com iterator& operator--() 30013531Sjairo.balart@metempsy.com { 30113531Sjairo.balart@metempsy.com /* this has to be decrementable. */ 30213531Sjairo.balart@metempsy.com assert(decrementable()); 30313756Sjairo.balart@metempsy.com if (_idx == 0) 30413756Sjairo.balart@metempsy.com --_round; 30513531Sjairo.balart@metempsy.com _cq->decrease(_idx); 30613531Sjairo.balart@metempsy.com return *this; 30713531Sjairo.balart@metempsy.com } 30813531Sjairo.balart@metempsy.com 30913531Sjairo.balart@metempsy.com /** Post-decrement operator. */ 31013531Sjairo.balart@metempsy.com iterator operator--(int ) { iterator t = *this; --*this; return t; } 31113531Sjairo.balart@metempsy.com 31213531Sjairo.balart@metempsy.com /** RandomAccessIterator requirements.*/ 31313531Sjairo.balart@metempsy.com iterator& operator+=(const difference_type& t) 31413531Sjairo.balart@metempsy.com { 31513531Sjairo.balart@metempsy.com assert(_cq); 31613531Sjairo.balart@metempsy.com _round += (t + _idx) / _cq->capacity(); 31713531Sjairo.balart@metempsy.com _idx = _cq->moduloAdd(_idx, t); 31813531Sjairo.balart@metempsy.com return *this; 31913531Sjairo.balart@metempsy.com } 32013531Sjairo.balart@metempsy.com 32113531Sjairo.balart@metempsy.com iterator& operator-=(const difference_type& t) 32213531Sjairo.balart@metempsy.com { 32313531Sjairo.balart@metempsy.com assert(_cq); 32413531Sjairo.balart@metempsy.com 32513531Sjairo.balart@metempsy.com /* C does not do euclidean division, so we have to adjust */ 32613531Sjairo.balart@metempsy.com if (t >= 0) { 32713756Sjairo.balart@metempsy.com _round += (-t + _idx) / _cq->capacity(); 32813531Sjairo.balart@metempsy.com _idx = _cq->moduloSub(_idx, t); 32913531Sjairo.balart@metempsy.com } else { 33013531Sjairo.balart@metempsy.com *this += -t; 33113531Sjairo.balart@metempsy.com } 33213531Sjairo.balart@metempsy.com return *this; 33313531Sjairo.balart@metempsy.com } 33413531Sjairo.balart@metempsy.com 33513531Sjairo.balart@metempsy.com /** Addition operator. */ 33613531Sjairo.balart@metempsy.com iterator operator+(const difference_type& t) 33713531Sjairo.balart@metempsy.com { 33813756Sjairo.balart@metempsy.com iterator ret(*this); 33913756Sjairo.balart@metempsy.com return ret += t; 34013531Sjairo.balart@metempsy.com } 34113531Sjairo.balart@metempsy.com 34213531Sjairo.balart@metempsy.com friend iterator operator+(const difference_type& t, iterator& it) 34313531Sjairo.balart@metempsy.com { 34413531Sjairo.balart@metempsy.com iterator ret = it; 34513531Sjairo.balart@metempsy.com return ret += t; 34613531Sjairo.balart@metempsy.com } 34713531Sjairo.balart@metempsy.com 34813531Sjairo.balart@metempsy.com /** Substraction operator. */ 34913531Sjairo.balart@metempsy.com iterator operator-(const difference_type& t) 35013531Sjairo.balart@metempsy.com { 35113531Sjairo.balart@metempsy.com iterator ret(*this); 35213531Sjairo.balart@metempsy.com return ret -= t; 35313531Sjairo.balart@metempsy.com } 35413531Sjairo.balart@metempsy.com 35513531Sjairo.balart@metempsy.com friend iterator operator-(const difference_type& t, iterator& it) 35613531Sjairo.balart@metempsy.com { 35713531Sjairo.balart@metempsy.com iterator ret = it; 35813531Sjairo.balart@metempsy.com return ret -= t; 35913531Sjairo.balart@metempsy.com } 36013531Sjairo.balart@metempsy.com 36113531Sjairo.balart@metempsy.com /** Difference operator. 36213531Sjairo.balart@metempsy.com * that + ret == this 36313531Sjairo.balart@metempsy.com */ 36413531Sjairo.balart@metempsy.com difference_type operator-(const iterator& that) 36513531Sjairo.balart@metempsy.com { 36613531Sjairo.balart@metempsy.com /* If a is already at the end, we can safely return 0. */ 36713531Sjairo.balart@metempsy.com auto ret = _cq->sub(this->_idx, that._idx, _cq->capacity()); 36813531Sjairo.balart@metempsy.com 36913531Sjairo.balart@metempsy.com if (this->_round != that._round) { 37013756Sjairo.balart@metempsy.com ret += ((this->_round - that._round) * _cq->capacity()); 37113531Sjairo.balart@metempsy.com } 37213531Sjairo.balart@metempsy.com return ret; 37313531Sjairo.balart@metempsy.com } 37413531Sjairo.balart@metempsy.com 37513531Sjairo.balart@metempsy.com /** Index operator. 37613531Sjairo.balart@metempsy.com * The use of * tests for dereferenceability. 37713756Sjairo.balart@metempsy.com */ 37813531Sjairo.balart@metempsy.com template<typename Idx> 37913531Sjairo.balart@metempsy.com typename std::enable_if<std::is_integral<Idx>::value,reference>::type 38013531Sjairo.balart@metempsy.com operator[](const Idx& index) { return *(*this + index); } 38113531Sjairo.balart@metempsy.com 38213531Sjairo.balart@metempsy.com /** Comparisons. */ 38313531Sjairo.balart@metempsy.com bool 38413531Sjairo.balart@metempsy.com operator<(const iterator& that) const 38513531Sjairo.balart@metempsy.com { 38613531Sjairo.balart@metempsy.com assert(_cq && that._cq == _cq); 38713531Sjairo.balart@metempsy.com return (this->_round < that._round) || 38813531Sjairo.balart@metempsy.com (this->_round == that._round && _idx < that._idx); 38913531Sjairo.balart@metempsy.com } 39013531Sjairo.balart@metempsy.com 39113531Sjairo.balart@metempsy.com bool 39213531Sjairo.balart@metempsy.com operator>(const iterator& that) const 39313756Sjairo.balart@metempsy.com { return !(*this <= that); } 39413531Sjairo.balart@metempsy.com 39513531Sjairo.balart@metempsy.com bool operator>=(const iterator& that) const 39613531Sjairo.balart@metempsy.com { return !(*this < that); } 39713531Sjairo.balart@metempsy.com 39813531Sjairo.balart@metempsy.com bool operator<=(const iterator& that) const 39913531Sjairo.balart@metempsy.com { return !(that < *this); } 40013531Sjairo.balart@metempsy.com 40113531Sjairo.balart@metempsy.com /** OutputIterator has no extra requirements.*/ 40213531Sjairo.balart@metempsy.com size_t idx() const { return _idx; } 40313531Sjairo.balart@metempsy.com }; 40413531Sjairo.balart@metempsy.com 40513531Sjairo.balart@metempsy.com public: 40613531Sjairo.balart@metempsy.com using Base::operator[]; 40713531Sjairo.balart@metempsy.com 40813531Sjairo.balart@metempsy.com explicit CircularQueue(uint32_t size = 0) 40913531Sjairo.balart@metempsy.com : _capacity(size), _head(1), _tail(0), _empty(true), _round(0) 41013531Sjairo.balart@metempsy.com { 41113531Sjairo.balart@metempsy.com Base::resize(size); 41213531Sjairo.balart@metempsy.com } 41313531Sjairo.balart@metempsy.com 41413531Sjairo.balart@metempsy.com /** 41513531Sjairo.balart@metempsy.com * Remove all the elements in the queue. 41613531Sjairo.balart@metempsy.com * 41713531Sjairo.balart@metempsy.com * Note: This does not actually remove elements from the backing 41813531Sjairo.balart@metempsy.com * store. 41913531Sjairo.balart@metempsy.com */ 42013531Sjairo.balart@metempsy.com void flush() 42113531Sjairo.balart@metempsy.com { 42213531Sjairo.balart@metempsy.com _head = 1; 42313531Sjairo.balart@metempsy.com _round = 0; 42413531Sjairo.balart@metempsy.com _tail = 0; 42513531Sjairo.balart@metempsy.com _empty = true; 42613531Sjairo.balart@metempsy.com } 42713531Sjairo.balart@metempsy.com 42813531Sjairo.balart@metempsy.com /** Test if the index is in the range of valid elements. */ 42913531Sjairo.balart@metempsy.com bool isValidIdx(size_t idx) const 43013531Sjairo.balart@metempsy.com { 43113531Sjairo.balart@metempsy.com /* An index is invalid if: 43213531Sjairo.balart@metempsy.com * - The queue is empty. 43313531Sjairo.balart@metempsy.com * (6,T,3,2): |-|-|-]|[-|-|x| 43413531Sjairo.balart@metempsy.com * - head is small than tail and: 43513531Sjairo.balart@metempsy.com * - It is greater than both head and tail. 43613531Sjairo.balart@metempsy.com * (6,F,1,3): |-|[o|o|o]|-|x| 43713531Sjairo.balart@metempsy.com * - It is less than both head and tail. 43813531Sjairo.balart@metempsy.com * (6,F,1,3): |x|[o|o|o]|-|-| 43913531Sjairo.balart@metempsy.com * - It is greater than the tail and not than the head. 44013531Sjairo.balart@metempsy.com * (6,F,4,1): |o|o]|-|x|[o|o| 44113531Sjairo.balart@metempsy.com */ 44213531Sjairo.balart@metempsy.com return !(_empty || ( 44313531Sjairo.balart@metempsy.com (_head < _tail) && ( 44413531Sjairo.balart@metempsy.com (_head < idx && _tail < idx) || 44513531Sjairo.balart@metempsy.com (_head > idx && _tail > idx) 44613531Sjairo.balart@metempsy.com )) || (_tail < idx && idx < _head)); 44713531Sjairo.balart@metempsy.com } 44813531Sjairo.balart@metempsy.com 44913531Sjairo.balart@metempsy.com /** Test if the index is in the range of valid elements. 45013531Sjairo.balart@metempsy.com * The round counter is used to disambiguate aliasing. 45113531Sjairo.balart@metempsy.com */ 45213531Sjairo.balart@metempsy.com bool isValidIdx(size_t idx, uint32_t round) const 45313531Sjairo.balart@metempsy.com { 45413531Sjairo.balart@metempsy.com /* An index is valid if: 45513531Sjairo.balart@metempsy.com * - The queue is not empty. 45613531Sjairo.balart@metempsy.com * - round == R and 45713531Sjairo.balart@metempsy.com * - index <= tail (if index > tail, that would be PTE) 45813531Sjairo.balart@metempsy.com * - Either: 45913531Sjairo.balart@metempsy.com * - head <= index 46013531Sjairo.balart@metempsy.com * (6,F,1,3,R): |-|[o|(*,r)|o]|-|-| 46113531Sjairo.balart@metempsy.com * - head > tail 46213531Sjairo.balart@metempsy.com * (6,F,5,3,R): |o|o|(*,r)|o]|-|[o| 46313531Sjairo.balart@metempsy.com * The remaining case means the the iterator is BTB: 46413531Sjairo.balart@metempsy.com * (6,F,3,4,R): |-|-|(x,r)|[o|o]|-| 46513531Sjairo.balart@metempsy.com * - round + 1 == R and: 46613531Sjairo.balart@metempsy.com * - index > tail. If index <= tail, that would be BTB: 46713531Sjairo.balart@metempsy.com * (6,F,2,3,r): | -|- |[(*,r)|o]|-|-| 46813531Sjairo.balart@metempsy.com * (6,F,0,1,r+1): |[o|o]| (x,r)|- |-|-| 46913531Sjairo.balart@metempsy.com * (6,F,0,3,r+1): |[o|o | (*,r)|o]|-|-| 47013531Sjairo.balart@metempsy.com * - index >= head. If index < head, that would be BTB: 47113531Sjairo.balart@metempsy.com * (6,F,5,2,R): |o|o]|-|-|(x,r)|[o| 47213531Sjairo.balart@metempsy.com * - head > tail. If head <= tail, that would be BTB: 47313531Sjairo.balart@metempsy.com * (6,F,3,4,R): |[o|o]|(x,r)|-|-|-| 47413531Sjairo.balart@metempsy.com * Other values of the round meand that the index is PTE or BTB 47513531Sjairo.balart@metempsy.com */ 47613531Sjairo.balart@metempsy.com return (!_empty && ( 47713690Sjairo.balart@metempsy.com (round == _round && idx <= _tail && ( 47813531Sjairo.balart@metempsy.com _head <= idx || _head > _tail)) || 47913531Sjairo.balart@metempsy.com (round + 1 == _round && 48013531Sjairo.balart@metempsy.com idx > _tail && 48113531Sjairo.balart@metempsy.com idx >= _head && 48213531Sjairo.balart@metempsy.com _head > _tail) 48313531Sjairo.balart@metempsy.com )); 48413531Sjairo.balart@metempsy.com } 48513531Sjairo.balart@metempsy.com 48613531Sjairo.balart@metempsy.com reference front() { return (*this)[_head]; } 48713531Sjairo.balart@metempsy.com reference back() { return (*this)[_tail]; } 48813531Sjairo.balart@metempsy.com uint32_t head() const { return _head; } 48913531Sjairo.balart@metempsy.com uint32_t tail() const { return _tail; } 49013531Sjairo.balart@metempsy.com size_t capacity() const { return _capacity; } 49113531Sjairo.balart@metempsy.com 49213927Sgiacomo.travaglini@arm.com uint32_t size() const 49313690Sjairo.balart@metempsy.com { 49413531Sjairo.balart@metempsy.com if (_empty) 49513531Sjairo.balart@metempsy.com return 0; 49613531Sjairo.balart@metempsy.com else if (_head <= _tail) 49713531Sjairo.balart@metempsy.com return _tail - _head + 1; 49813531Sjairo.balart@metempsy.com else 49913531Sjairo.balart@metempsy.com return _capacity - _head + _tail + 1; 50013531Sjairo.balart@metempsy.com } 50113531Sjairo.balart@metempsy.com 50213531Sjairo.balart@metempsy.com uint32_t moduloAdd(uint32_t s1, uint32_t s2) const 50313531Sjairo.balart@metempsy.com { 50413531Sjairo.balart@metempsy.com return moduloAdd(s1, s2, _capacity); 50513756Sjairo.balart@metempsy.com } 50614167Sgiacomo.travaglini@arm.com 50713531Sjairo.balart@metempsy.com uint32_t moduloSub(uint32_t s1, uint32_t s2) const 50814167Sgiacomo.travaglini@arm.com { 50914167Sgiacomo.travaglini@arm.com return moduloSub(s1, s2, _capacity); 51013531Sjairo.balart@metempsy.com } 51114167Sgiacomo.travaglini@arm.com 51214167Sgiacomo.travaglini@arm.com /** Circularly increase the head pointer. 51313531Sjairo.balart@metempsy.com * By increasing the head pointer we are removing elements from 51413531Sjairo.balart@metempsy.com * the begin of the circular queue. 51514167Sgiacomo.travaglini@arm.com * Check that the queue is not empty. And set it to empty if it 51613531Sjairo.balart@metempsy.com * had only one value prior to insertion. 51714167Sgiacomo.travaglini@arm.com * 51814167Sgiacomo.travaglini@arm.com * @params num_elem number of elements to remove 51913531Sjairo.balart@metempsy.com */ 52013531Sjairo.balart@metempsy.com void pop_front(size_t num_elem = 1) 52113531Sjairo.balart@metempsy.com { 52213531Sjairo.balart@metempsy.com if (num_elem == 0) return; 52313531Sjairo.balart@metempsy.com auto hIt = begin(); 52413531Sjairo.balart@metempsy.com hIt += num_elem; 52513531Sjairo.balart@metempsy.com assert(hIt <= end()); 52613531Sjairo.balart@metempsy.com _empty = hIt == end(); 52713531Sjairo.balart@metempsy.com _head = hIt._idx; 52813531Sjairo.balart@metempsy.com } 52913531Sjairo.balart@metempsy.com 53013531Sjairo.balart@metempsy.com /** Circularly decrease the tail pointer. */ 53113531Sjairo.balart@metempsy.com void pop_back() 53213531Sjairo.balart@metempsy.com { 53313531Sjairo.balart@metempsy.com assert (!_empty); 53413531Sjairo.balart@metempsy.com _empty = _head == _tail; 53513531Sjairo.balart@metempsy.com if (_tail == 0) 53613531Sjairo.balart@metempsy.com --_round; 53713531Sjairo.balart@metempsy.com decrease(_tail); 53813531Sjairo.balart@metempsy.com } 53913531Sjairo.balart@metempsy.com 54013531Sjairo.balart@metempsy.com /** Pushes an element at the end of the queue. */ 54113531Sjairo.balart@metempsy.com void push_back(typename Base::value_type val) 54213531Sjairo.balart@metempsy.com { 54313531Sjairo.balart@metempsy.com advance_tail(); 54413531Sjairo.balart@metempsy.com (*this)[_tail] = val; 54513531Sjairo.balart@metempsy.com } 54613531Sjairo.balart@metempsy.com 54713531Sjairo.balart@metempsy.com /** Increases the tail by one. 54813756Sjairo.balart@metempsy.com * Check for wrap-arounds to update the round counter. 54913531Sjairo.balart@metempsy.com */ 55013531Sjairo.balart@metempsy.com void advance_tail() 55113531Sjairo.balart@metempsy.com { 55213531Sjairo.balart@metempsy.com increase(_tail); 55313531Sjairo.balart@metempsy.com if (_tail == 0) 55413531Sjairo.balart@metempsy.com ++_round; 55513756Sjairo.balart@metempsy.com 55613531Sjairo.balart@metempsy.com if (_tail == _head && !_empty) 55713531Sjairo.balart@metempsy.com increase(_head); 55813531Sjairo.balart@metempsy.com 55913531Sjairo.balart@metempsy.com _empty = false; 56013531Sjairo.balart@metempsy.com } 56113531Sjairo.balart@metempsy.com 56213531Sjairo.balart@metempsy.com /** Increases the tail by a specified number of steps 56313531Sjairo.balart@metempsy.com * 56413756Sjairo.balart@metempsy.com * @param len Number of steps 56513756Sjairo.balart@metempsy.com */ 56613531Sjairo.balart@metempsy.com void advance_tail(uint32_t len) 56713531Sjairo.balart@metempsy.com { 56813531Sjairo.balart@metempsy.com for (auto idx = 0; idx < len; idx++) 56913531Sjairo.balart@metempsy.com advance_tail(); 57013531Sjairo.balart@metempsy.com } 57113531Sjairo.balart@metempsy.com 57213531Sjairo.balart@metempsy.com /** Is the queue empty? */ 57313531Sjairo.balart@metempsy.com bool empty() const { return _empty; } 57413531Sjairo.balart@metempsy.com 57513531Sjairo.balart@metempsy.com /** Is the queue full? 57613531Sjairo.balart@metempsy.com * A queue is full if the head is the 0^{th} element and the tail is 57713531Sjairo.balart@metempsy.com * the (size-1)^{th} element, or if the head is the n^{th} element and 57813531Sjairo.balart@metempsy.com * the tail the (n-1)^{th} element. 57913531Sjairo.balart@metempsy.com */ 58013531Sjairo.balart@metempsy.com bool full() const 58113531Sjairo.balart@metempsy.com { 58213531Sjairo.balart@metempsy.com return !_empty && 58313531Sjairo.balart@metempsy.com (_tail + 1 == _head || (_tail + 1 == _capacity && _head == 0)); 58413531Sjairo.balart@metempsy.com } 58513531Sjairo.balart@metempsy.com 58613531Sjairo.balart@metempsy.com /** Iterators. */ 58713531Sjairo.balart@metempsy.com iterator begin() 58813812Sgiacomo.travaglini@arm.com { 58913812Sgiacomo.travaglini@arm.com if (_empty) 59013812Sgiacomo.travaglini@arm.com return end(); 59113812Sgiacomo.travaglini@arm.com else if (_head > _tail) 59213531Sjairo.balart@metempsy.com return iterator(this, _head, _round - 1); 59313756Sjairo.balart@metempsy.com else 59413756Sjairo.balart@metempsy.com return iterator(this, _head, _round); 59513531Sjairo.balart@metempsy.com } 59613531Sjairo.balart@metempsy.com 59713531Sjairo.balart@metempsy.com /* TODO: This should return a const_iterator. */ 59813531Sjairo.balart@metempsy.com iterator begin() const 59913531Sjairo.balart@metempsy.com { 60013531Sjairo.balart@metempsy.com if (_empty) 60113531Sjairo.balart@metempsy.com return end(); 60213531Sjairo.balart@metempsy.com else if (_head > _tail) 60313531Sjairo.balart@metempsy.com return iterator(const_cast<CircularQueue*>(this), _head, 60413531Sjairo.balart@metempsy.com _round - 1); 60513531Sjairo.balart@metempsy.com else 60613531Sjairo.balart@metempsy.com return iterator(const_cast<CircularQueue*>(this), _head, 60713531Sjairo.balart@metempsy.com _round); 60813531Sjairo.balart@metempsy.com } 60913531Sjairo.balart@metempsy.com 61013531Sjairo.balart@metempsy.com iterator end() 61113531Sjairo.balart@metempsy.com { 61213531Sjairo.balart@metempsy.com auto poi = moduloAdd(_tail, 1); 61313531Sjairo.balart@metempsy.com auto round = _round; 61413756Sjairo.balart@metempsy.com if (poi == 0) 61513531Sjairo.balart@metempsy.com ++round; 61613531Sjairo.balart@metempsy.com return iterator(this, poi, round); 61713531Sjairo.balart@metempsy.com } 61813531Sjairo.balart@metempsy.com 61913531Sjairo.balart@metempsy.com iterator end() const 62013531Sjairo.balart@metempsy.com { 62113531Sjairo.balart@metempsy.com auto poi = moduloAdd(_tail, 1); 62213756Sjairo.balart@metempsy.com auto round = _round; 62313756Sjairo.balart@metempsy.com if (poi == 0) 62413531Sjairo.balart@metempsy.com ++round; 62513531Sjairo.balart@metempsy.com return iterator(const_cast<CircularQueue*>(this), poi, round); 62613531Sjairo.balart@metempsy.com } 62713531Sjairo.balart@metempsy.com 62813531Sjairo.balart@metempsy.com /** Return an iterator to an index in the vector. 62913531Sjairo.balart@metempsy.com * This poses the problem of round determination. By convention, the round 63013531Sjairo.balart@metempsy.com * is picked so that isValidIndex(idx, round) is true. If that is not 63113531Sjairo.balart@metempsy.com * possible, then the round value is _round, unless _tail is at the end of 63213531Sjairo.balart@metempsy.com * the storage, in which case the PTE wraps up and becomes _round + 1 63313531Sjairo.balart@metempsy.com */ 63413531Sjairo.balart@metempsy.com iterator getIterator(size_t idx) 63513531Sjairo.balart@metempsy.com { 63613531Sjairo.balart@metempsy.com assert(isValidIdx(idx) || moduloAdd(_tail, 1) == idx); 63713531Sjairo.balart@metempsy.com if (_empty) 63813531Sjairo.balart@metempsy.com return end(); 63913531Sjairo.balart@metempsy.com 64013531Sjairo.balart@metempsy.com uint32_t round = _round; 64113531Sjairo.balart@metempsy.com if (idx > _tail) { 64213531Sjairo.balart@metempsy.com if (idx >= _head && _head > _tail) { 64313531Sjairo.balart@metempsy.com round -= 1; 64413756Sjairo.balart@metempsy.com } 64513531Sjairo.balart@metempsy.com } else if (idx < _head && _tail + 1 == _capacity) { 64613531Sjairo.balart@metempsy.com round += 1; 64713531Sjairo.balart@metempsy.com } 64813531Sjairo.balart@metempsy.com return iterator(this, idx, round); 64913531Sjairo.balart@metempsy.com } 65013531Sjairo.balart@metempsy.com}; 65113531Sjairo.balart@metempsy.com 65213756Sjairo.balart@metempsy.com#endif /* __BASE_CIRCULARQUEUE_HH__ */ 65313756Sjairo.balart@metempsy.com