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