Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 
     18 #ifndef ANDROID_SERVICE_UTILS_RING_BUFFER_H
     19 #define ANDROID_SERVICE_UTILS_RING_BUFFER_H
     20 
     21 #include <utils/Log.h>
     22 #include <cutils/compiler.h>
     23 
     24 #include <iterator>
     25 #include <utility>
     26 #include <vector>
     27 
     28 namespace android {
     29 
     30 /**
     31  * A RingBuffer class that maintains an array of objects that can grow up to a certain size.
     32  * Elements added to the RingBuffer are inserted in the logical front of the buffer, and
     33  * invalidate all current iterators for that RingBuffer object.
     34  */
     35 template <class T>
     36 class RingBuffer final {
     37 public:
     38 
     39     /**
     40      * Construct a RingBuffer that can grow up to the given length.
     41      */
     42     explicit RingBuffer(size_t length);
     43 
     44     /**
     45      * Forward iterator to this class.  Implements an std:forward_iterator.
     46      */
     47     class iterator : public std::iterator<std::forward_iterator_tag, T> {
     48     public:
     49         iterator(T* ptr, size_t size, size_t pos, size_t ctr);
     50 
     51         iterator& operator++();
     52 
     53         iterator operator++(int);
     54 
     55         bool operator==(const iterator& rhs);
     56 
     57         bool operator!=(const iterator& rhs);
     58 
     59         T& operator*();
     60 
     61         T* operator->();
     62 
     63     private:
     64         T* mPtr;
     65         size_t mSize;
     66         size_t mPos;
     67         size_t mCtr;
     68     };
     69 
     70     /**
     71      * Constant forward iterator to this class.  Implements an std:forward_iterator.
     72      */
     73     class const_iterator : public std::iterator<std::forward_iterator_tag, T> {
     74     public:
     75         const_iterator(const T* ptr, size_t size, size_t pos, size_t ctr);
     76 
     77         const_iterator& operator++();
     78 
     79         const_iterator operator++(int);
     80 
     81         bool operator==(const const_iterator& rhs);
     82 
     83         bool operator!=(const const_iterator& rhs);
     84 
     85         const T& operator*();
     86 
     87         const T* operator->();
     88 
     89     private:
     90         const T* mPtr;
     91         size_t mSize;
     92         size_t mPos;
     93         size_t mCtr;
     94     };
     95 
     96     /**
     97      * Adds item to the front of this RingBuffer.  If the RingBuffer is at its maximum length,
     98      * this will result in the last element being replaced (this is done using the element's
     99      * assignment operator).
    100      *
    101      * All current iterators are invalidated.
    102      */
    103     void add(const T& item);
    104 
    105     /**
    106      * Moves item to the front of this RingBuffer.  Following a call to this, item should no
    107      * longer be used.  If the RingBuffer is at its maximum length, this will result in the
    108      * last element being replaced (this is done using the element's assignment operator).
    109      *
    110      * All current iterators are invalidated.
    111      */
    112     void add(T&& item);
    113 
    114     /**
    115      * Construct item in-place in the front of this RingBuffer using the given arguments.  If
    116      * the RingBuffer is at its maximum length, this will result in the last element being
    117      * replaced (this is done using the element's assignment operator).
    118      *
    119      * All current iterators are invalidated.
    120      */
    121     template <class... Args>
    122     void emplace(Args&&... args);
    123 
    124     /**
    125      * Get an iterator to the front of this RingBuffer.
    126      */
    127     iterator begin();
    128 
    129     /**
    130      * Get an iterator to the end of this RingBuffer.
    131      */
    132     iterator end();
    133 
    134     /**
    135      * Get a const_iterator to the front of this RingBuffer.
    136      */
    137     const_iterator begin() const;
    138 
    139     /**
    140      * Get a const_iterator to the end of this RingBuffer.
    141      */
    142     const_iterator end() const;
    143 
    144     /**
    145      * Return a reference to the element at a given index.  If the index is out of range for
    146      * this ringbuffer, [0, size), the behavior for this is undefined.
    147      */
    148     T& operator[](size_t index);
    149 
    150     /**
    151      * Return a const reference to the element at a given index.  If the index is out of range
    152      * for this ringbuffer, [0, size), the behavior for this is undefined.
    153      */
    154     const T& operator[](size_t index) const;
    155 
    156     /**
    157      * Return the current size of this RingBuffer.
    158      */
    159     size_t size() const;
    160 
    161     /**
    162      * Remove all elements from this RingBuffer and set the size to 0.
    163      */
    164     void clear();
    165 
    166 private:
    167     size_t mFrontIdx;
    168     size_t mMaxBufferSize;
    169     std::vector<T> mBuffer;
    170 }; // class RingBuffer
    171 
    172 
    173 template <class T>
    174 RingBuffer<T>::RingBuffer(size_t length) : mFrontIdx{0}, mMaxBufferSize{length} {}
    175 
    176 template <class T>
    177 RingBuffer<T>::iterator::iterator(T* ptr, size_t size, size_t pos, size_t ctr) :
    178         mPtr{ptr}, mSize{size}, mPos{pos}, mCtr{ctr} {}
    179 
    180 template <class T>
    181 typename RingBuffer<T>::iterator& RingBuffer<T>::iterator::operator++() {
    182     ++mCtr;
    183 
    184     if (CC_UNLIKELY(mCtr == mSize)) {
    185         mPos = mSize;
    186         return *this;
    187     }
    188 
    189     mPos = ((CC_UNLIKELY(mPos == 0)) ? mSize - 1 : mPos - 1);
    190     return *this;
    191 }
    192 
    193 template <class T>
    194 typename RingBuffer<T>::iterator RingBuffer<T>::iterator::operator++(int) {
    195     iterator tmp{mPtr, mSize, mPos, mCtr};
    196     ++(*this);
    197     return tmp;
    198 }
    199 
    200 template <class T>
    201 bool RingBuffer<T>::iterator::operator==(const iterator& rhs) {
    202     return (mPtr + mPos) == (rhs.mPtr + rhs.mPos);
    203 }
    204 
    205 template <class T>
    206 bool RingBuffer<T>::iterator::operator!=(const iterator& rhs) {
    207     return (mPtr + mPos) != (rhs.mPtr + rhs.mPos);
    208 }
    209 
    210 template <class T>
    211 T& RingBuffer<T>::iterator::operator*() {
    212     return *(mPtr + mPos);
    213 }
    214 
    215 template <class T>
    216 T* RingBuffer<T>::iterator::operator->() {
    217     return mPtr + mPos;
    218 }
    219 
    220 template <class T>
    221 RingBuffer<T>::const_iterator::const_iterator(const T* ptr, size_t size, size_t pos, size_t ctr) :
    222         mPtr{ptr}, mSize{size}, mPos{pos}, mCtr{ctr} {}
    223 
    224 template <class T>
    225 typename RingBuffer<T>::const_iterator& RingBuffer<T>::const_iterator::operator++() {
    226     ++mCtr;
    227 
    228     if (CC_UNLIKELY(mCtr == mSize)) {
    229         mPos = mSize;
    230         return *this;
    231     }
    232 
    233     mPos = ((CC_UNLIKELY(mPos == 0)) ? mSize - 1 : mPos - 1);
    234     return *this;
    235 }
    236 
    237 template <class T>
    238 typename RingBuffer<T>::const_iterator RingBuffer<T>::const_iterator::operator++(int) {
    239     const_iterator tmp{mPtr, mSize, mPos, mCtr};
    240     ++(*this);
    241     return tmp;
    242 }
    243 
    244 template <class T>
    245 bool RingBuffer<T>::const_iterator::operator==(const const_iterator& rhs) {
    246     return (mPtr + mPos) == (rhs.mPtr + rhs.mPos);
    247 }
    248 
    249 template <class T>
    250 bool RingBuffer<T>::const_iterator::operator!=(const const_iterator& rhs) {
    251     return (mPtr + mPos) != (rhs.mPtr + rhs.mPos);
    252 }
    253 
    254 template <class T>
    255 const T& RingBuffer<T>::const_iterator::operator*() {
    256     return *(mPtr + mPos);
    257 }
    258 
    259 template <class T>
    260 const T* RingBuffer<T>::const_iterator::operator->() {
    261     return mPtr + mPos;
    262 }
    263 
    264 template <class T>
    265 void RingBuffer<T>::add(const T& item) {
    266     if (mBuffer.size() < mMaxBufferSize) {
    267         mBuffer.push_back(item);
    268         mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
    269         return;
    270     }
    271 
    272     mBuffer[mFrontIdx] = item;
    273     mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
    274 }
    275 
    276 template <class T>
    277 void RingBuffer<T>::add(T&& item) {
    278     if (mBuffer.size() != mMaxBufferSize) {
    279         mBuffer.push_back(std::forward<T>(item));
    280         mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
    281         return;
    282     }
    283 
    284     // Only works for types with move assignment operator
    285     mBuffer[mFrontIdx] = std::forward<T>(item);
    286     mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
    287 }
    288 
    289 template <class T>
    290 template <class... Args>
    291 void RingBuffer<T>::emplace(Args&&... args) {
    292     if (mBuffer.size() != mMaxBufferSize) {
    293         mBuffer.emplace_back(std::forward<Args>(args)...);
    294         mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
    295         return;
    296     }
    297 
    298     // Only works for types with move assignment operator
    299     mBuffer[mFrontIdx] = T(std::forward<Args>(args)...);
    300     mFrontIdx = ((mFrontIdx + 1) % mMaxBufferSize);
    301 }
    302 
    303 template <class T>
    304 typename RingBuffer<T>::iterator RingBuffer<T>::begin() {
    305     size_t tmp = (mBuffer.size() == 0) ? 0 : mBuffer.size() - 1;
    306     return iterator(mBuffer.data(), mBuffer.size(), (mFrontIdx == 0) ? tmp : mFrontIdx - 1, 0);
    307 }
    308 
    309 template <class T>
    310 typename RingBuffer<T>::iterator RingBuffer<T>::end() {
    311     size_t s = mBuffer.size();
    312     return iterator(mBuffer.data(), s, s, s);
    313 }
    314 
    315 template <class T>
    316 typename RingBuffer<T>::const_iterator RingBuffer<T>::begin() const {
    317     size_t tmp = (mBuffer.size() == 0) ? 0 : mBuffer.size() - 1;
    318     return const_iterator(mBuffer.data(), mBuffer.size(),
    319             (mFrontIdx == 0) ? tmp : mFrontIdx - 1, 0);
    320 }
    321 
    322 template <class T>
    323 typename RingBuffer<T>::const_iterator RingBuffer<T>::end() const {
    324     size_t s = mBuffer.size();
    325     return const_iterator(mBuffer.data(), s, s, s);
    326 }
    327 
    328 template <class T>
    329 T& RingBuffer<T>::operator[](size_t index) {
    330     LOG_ALWAYS_FATAL_IF(index >= mBuffer.size(), "Index %zu out of bounds, size is %zu.",
    331             index, mBuffer.size());
    332     size_t pos = (index >= mFrontIdx) ?
    333             mBuffer.size() - 1 - (index - mFrontIdx) : mFrontIdx - 1 - index;
    334     return mBuffer[pos];
    335 }
    336 
    337 template <class T>
    338 const T& RingBuffer<T>::operator[](size_t index) const {
    339     LOG_ALWAYS_FATAL_IF(index >= mBuffer.size(), "Index %zu out of bounds, size is %zu.",
    340             index, mBuffer.size());
    341     size_t pos = (index >= mFrontIdx) ?
    342             mBuffer.size() - 1 - (index - mFrontIdx) : mFrontIdx - 1 - index;
    343     return mBuffer[pos];
    344 }
    345 
    346 template <class T>
    347 size_t RingBuffer<T>::size() const {
    348     return mBuffer.size();
    349 }
    350 
    351 template <class T>
    352 void RingBuffer<T>::clear() {
    353     mBuffer.clear();
    354     mFrontIdx = 0;
    355 }
    356 
    357 }; // namespace android
    358 
    359 #endif // ANDROID_SERVICE_UTILS_RING_BUFFER_H
    360 
    361 
    362