Menu

RingBuffer.h

Go to the documentation of this file.
00001 /*******************************************************************************
00002  *
00003  * Copyright (c) 2010 Philipp Werner <philipp.werner@st.ovgu.de>
00004  * All rights reserved.
00005  *
00006  *    Redistribution and use in source and binary forms, with or without
00007  *    modification, are permitted provided that the following conditions
00008  *    are met:
00009  *
00010  *    * Redistributions of source code must retain the above copyright
00011  *      notice, this list of conditions and the following disclaimer.
00012  *
00013  *    * Redistributions in binary form must reproduce the above copyright
00014  *      notice, this list of conditions and the following disclaimer in
00015  *      the documentation and/or other materials provided with the
00016  *      distribution.
00017  *
00018  *    * Neither the name of the copyright holders nor the names of
00019  *      contributors may be used to endorse or promote products derived
00020  *      from this software without specific prior written permission.
00021  *
00022  *
00023  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00024  *    IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00025  *    TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00026  *    PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00027  *    OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00028  *    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00029  *    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00030  *    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00031  *    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032  *    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033  *    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  *
00036  * $Id$
00037  *
00038  ******************************************************************************/
00039 
00040 #ifndef __RINGBUFFER_H_E7CCEE63FC08A7__
00041 #define __RINGBUFFER_H_E7CCEE63FC08A7__
00042 
00043 
00044 #include "debug.h"
00045 #include "config/type_traits/SmallestUnsignedTypeSelector.h"
00046 #include "config/type_traits/ExpandedRangeTypeSelector.h"
00047 
00048 
00049 namespace object {
00050 
00057     template <class T, unsigned int N>
00058     class RingBuffer {
00059         public:
00060 
00062             typedef typename SmallestUnsignedTypeSelector<N>::type SizeT;
00063 
00064         protected:
00065 
00067             typedef typename ExpandedRangeTypeSelector<SizeT>::type DoubleSizeT;
00068 
00070             T buffer[N];
00071 
00073             SizeT first;
00074 
00076             SizeT count;
00077 
00078 
00085             SizeT get_idx(SizeT num) const {
00086                 FAMOUSO_ASSERT(num < N);
00087                 // Avoid overflow of SizeT
00088                 DoubleSizeT idx = (DoubleSizeT)(first) + (DoubleSizeT)(num);
00089                 // Handle overflow over element count (N)
00090                 // Avoid modulo because it is expensive on AVR
00091                 if (idx < N)
00092                     return idx;
00093                 else
00094                     return idx - N;
00095             }
00096 
00098             void increment_first() {
00099                 // Avoid modulo because it is expensive on AVR
00100                 if (first == N-1)
00101                     first = 0;
00102                 else
00103                     first++;
00104             }
00105 
00107             void decrement_first() {
00108                 // Avoid modulo because it is expensive on AVR
00109                 if (first == 0)
00110                     first = N-1;
00111                 else
00112                     first--;
00113             }
00114 
00116             SizeT get_last() const {
00117                 FAMOUSO_ASSERT(!is_empty());
00118                 return get_idx(count - 1);
00119             }
00120 
00122             SizeT get_behind_last() const {
00123                 return get_idx(count);
00124             }
00125 
00127             SizeT get_infront_first() const {
00128                 return get_idx(N-1);
00129             }
00130 
00131         public:
00133             RingBuffer() :
00134                     first(0), count(0) {
00135             }
00136 
00138             SizeT get_count() const {
00139                 return count;
00140             }
00141 
00143             bool is_empty() const {
00144                 return count == 0;
00145             }
00146 
00148             bool is_full() const {
00149                 return count == N;
00150             }
00151 
00156             T & front() {
00157                 FAMOUSO_ASSERT(!is_empty());
00158                 return buffer[first];
00159             }
00160 
00165             const T & front() const {
00166                 FAMOUSO_ASSERT(!is_empty());
00167                 return buffer[first];
00168             }
00169 
00174             T & back() {
00175                 return buffer[get_last()];
00176             }
00177 
00182             const T & back() const {
00183                 return buffer[get_last()];
00184             }
00185 
00191             T & operator[] (SizeT i) {
00192                 return buffer[get_idx(i)];
00193             }
00194 
00200             const T & operator[] (SizeT i) const {
00201                 return buffer[get_idx(i)];
00202             }
00203 
00209             void push_front(const T & obj) {
00210                 FAMOUSO_ASSERT(!is_full());
00211                 buffer[get_infront_first()] = obj;
00212                 decrement_first();
00213                 count++;
00214             }
00215 
00221             void push_back(const T & obj) {
00222                 FAMOUSO_ASSERT(!is_full());
00223                 buffer[get_behind_last()] = obj;
00224                 count++;
00225             }
00226 
00231             void pop_front() {
00232                 FAMOUSO_ASSERT(!is_empty());
00233                 increment_first();
00234                 count--;
00235             }
00236 
00241             void pop_back() {
00242                 FAMOUSO_ASSERT(!is_empty());
00243                 count--;
00244             }
00245     };
00246 
00247 } // namespace object
00248 
00249 
00250 #endif // __RINGBUFFER_H_E7CCEE63FC08A7__
00251