RingBuffer.h
Go to the documentation of this file.
00001 // this is for emacs file handling -*- mode: c++; indent-tabs-mode: nil -*-
00002 
00003 // -- BEGIN LICENSE BLOCK ----------------------------------------------
00004 // This file is part of FZIs ic_workspace.
00005 //
00006 // This program is free software licensed under the LGPL
00007 // (GNU LESSER GENERAL PUBLIC LICENSE Version 3).
00008 // You can find a copy of this license in LICENSE folder in the top
00009 // directory of the source code.
00010 //
00011 // © Copyright 2016 FZI Forschungszentrum Informatik, Karlsruhe, Germany
00012 //
00013 // -- END LICENSE BLOCK ------------------------------------------------
00014 
00015 //----------------------------------------------------------------------
00022 //----------------------------------------------------------------------
00023 #ifndef ICL_CORE_RING_BUFFER_H_INCLUDED
00024 #define ICL_CORE_RING_BUFFER_H_INCLUDED
00025 
00026 #include <stdexcept>
00027 #include <iterator>
00028 #include <vector>
00029 
00030 #include "icl_core/BaseTypes.h"
00031 
00032 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
00033 # include "icl_core/Deprecate.h"
00034 #endif
00035 
00036 namespace icl_core {
00037 
00044 template <typename T>
00045 class RingBuffer
00046 {
00047 public:
00048   typedef T value_type;
00049   typedef typename std::vector<T>::size_type size_type;
00050   typedef typename std::vector<T>::difference_type difference_type;
00052   typedef std::pair<T*, size_type> array_range;
00054   typedef std::pair<const T*, size_type> const_array_range;
00055   static const size_type cDEFAULT_CAPACITY = 32;
00056 
00058   class const_iterator : public std::iterator<std::random_access_iterator_tag, T>
00059   {
00060     friend class RingBuffer;
00061 
00062   public:
00063     const_iterator(const const_iterator& other)
00064       : m_current(other.m_current), m_cbegin(other.m_cbegin), m_cend(other.m_cend), m_begin(other.m_begin)
00065     { }
00066 
00067     const_iterator& operator = (const const_iterator& other)
00068     {
00069       m_current = other.m_current; m_cbegin = other.m_cbegin; m_cend = other.m_cend; m_begin = other.m_begin;
00070       return *this;
00071     }
00072 
00073     const_iterator& operator ++ ()
00074     {
00075       ++m_current;
00076       if (m_current == m_cend) { m_current = m_cbegin; }
00077       return *this;
00078     }
00079     const_iterator operator ++ (int)
00080     {
00081       const_iterator answer = *this;
00082       operator ++ ();
00083       return answer;
00084     }
00085 
00086     const_iterator& operator -- ()
00087     {
00088       if (m_current == m_cbegin)
00089       {
00090         m_current = m_cend;
00091       }
00092       --m_current;
00093       return *this;
00094     }
00095     const_iterator operator -- (int)
00096     {
00097       const_iterator answer = *this;
00098       operator -- ();
00099       return answer;
00100     }
00101 
00102     const_iterator& operator += (difference_type offset)
00103     {
00104       m_current += offset;
00105       if (m_current >= m_cend)
00106       {
00107         m_current -= m_cend - m_cbegin;
00108       }
00109       if (m_cbegin > m_current)
00110       {
00111         m_current += m_cend - m_cbegin;
00112       }
00113       return *this;
00114     }
00115     const_iterator& operator -= (difference_type offset)
00116     {
00117       return operator += (-offset);
00118     }
00119     const_iterator operator + (difference_type offset) const
00120     {
00121       const_iterator answer = *this;
00122       answer += offset;
00123       return answer;
00124     }
00125     const_iterator operator - (difference_type offset) const
00126     {
00127       const_iterator answer = *this;
00128       answer -= offset;
00129       return answer;
00130     }
00131 
00132     difference_type operator - (const const_iterator& other) const
00133     {
00134       if ((m_current >= m_begin && other.m_current >= other.m_begin)
00135           || (m_current < m_begin && other.m_current < other.m_begin))
00136       {
00137         return m_current - other.m_current;
00138       }
00139       else if (m_current >= m_begin)
00140       {
00141         return m_current - other.m_current + m_cbegin - m_cend;
00142       }
00143       else
00144       {
00145         return m_current - other.m_current + m_cend - m_cbegin;
00146       }
00147     }
00148 
00149     bool operator == (const const_iterator& other) const { return m_current == other.m_current; }
00150     bool operator != (const const_iterator& other) const { return m_current != other.m_current; }
00151 
00152     const T& operator * () const { return *m_current; }
00153     const T *operator -> () const { return m_current; }
00154 
00155   protected:
00156     const_iterator(const T *current, const T *cbegin, const T *cend, const T *begin)
00157       : m_current(current), m_cbegin(cbegin), m_cend(cend), m_begin(begin)
00158     { }
00159 
00160     const T *m_current;
00162     const T *m_cbegin;
00164     const T *m_cend;
00166     const T *m_begin;
00167   };
00168 
00174   class iterator : public const_iterator
00175   {
00176     friend class RingBuffer;
00177 
00178   public:
00179     iterator(const iterator& other)
00180       : const_iterator(other)
00181     { }
00182 
00183     iterator& operator = (const iterator& other)
00184     {
00185       const_iterator::m_current = other.m_current;
00186       const_iterator::m_cbegin = other.m_cbegin;
00187       const_iterator::m_cend = other.m_cend;
00188       const_iterator::m_begin = other.m_begin;
00189       return *this;
00190     }
00191 
00192     T& operator * () const { return *const_cast<T *>(const_iterator::m_current); }
00193     T *operator -> () const { return const_cast<T *>(const_iterator::m_current); }
00194 
00195   protected:
00196     iterator(const T *current, const T *cbegin, const T *cend, const T *begin)
00197       : const_iterator(current, cbegin, cend, begin)
00198     { }
00199   };
00200 
00202   RingBuffer(size_type capacity = cDEFAULT_CAPACITY)
00203     : m_buffer(capacity+1), m_write(0), m_read(0)
00204   { }
00205 
00207   RingBuffer(const RingBuffer<T>& other)
00208     : m_buffer(other.m_buffer), m_write(other.m_write), m_read(other.m_read)
00209   { }
00210 
00212   RingBuffer& operator = (const RingBuffer<T>& other)
00213   {
00214     m_buffer = other.m_buffer;
00215     m_write = other.m_write;
00216     m_read = other.m_read;
00217     return *this;
00218   }
00219 
00221   void clear() { m_write = 0; m_read = 0; }
00222 
00224   bool empty() const { return m_write == m_read; }
00225 
00227   bool full() const { return ((m_write+1) % m_buffer.size()) == m_read; }
00228 
00230 
00234   void write(const T& val, bool overwrite=false)
00235   {
00236     size_type new_write_pos = m_write+1;
00237     if (new_write_pos >= m_buffer.size())
00238     {
00239       new_write_pos = 0;
00240     }
00241     if (new_write_pos == m_read)
00242     {
00243       if (overwrite)
00244       {
00245         skip();
00246       }
00247       else
00248       {
00249         throw std::out_of_range("RingBuffer::write: capacity exceeded");
00250       }
00251     }
00252     m_buffer[m_write] = val;
00253     m_write = new_write_pos;
00254   }
00255 
00262   void fakeWrite(size_t count);
00263 
00265 
00269   const T& at(size_type pos) const
00270   {
00271     if (pos < size())
00272     {
00273       pos += m_read;
00274       if (pos >= m_buffer.size())
00275       {
00276         pos -= m_buffer.size();
00277       }
00278       return m_buffer[pos];
00279     }
00280     else
00281     {
00282       throw std::out_of_range("RingBuffer::at: out of range");
00283     }
00284   }
00285 
00287 
00291   T& at(size_type pos)
00292   {
00293     if (pos < size())
00294     {
00295       pos += m_read;
00296       if (pos >= m_buffer.size())
00297       {
00298         pos -= m_buffer.size();
00299       }
00300       return m_buffer[pos];
00301     }
00302     else
00303     {
00304       throw std::out_of_range("RingBuffer::at: out of range");
00305     }
00306   }
00307 
00308   const T& front() const { return at(0); }
00309   T& front() { return at(0); }
00310 
00312   void skip()
00313   {
00314     if (m_write == m_read)
00315     {
00316       throw std::out_of_range("RingBuffer::skip: buffer empty");
00317     }
00318     m_read++;
00319     if (m_read >= m_buffer.size())
00320     {
00321       m_read = 0;
00322     }
00323   }
00324 
00328   void skip(size_type count);
00329 
00331 
00333   T read()
00334   {
00335     if (m_write == m_read)
00336     {
00337       throw std::out_of_range("RingBuffer::read: buffer empty");
00338     }
00339     size_type read_pos = m_read;
00340     m_read++;
00341     if (m_read >= m_buffer.size())
00342     {
00343       m_read = 0;
00344     }
00345     return m_buffer[read_pos];
00346   }
00347 
00349   inline size_type size() const
00350   {
00351     if (m_write >= m_read)
00352     {
00353       return m_write-m_read;
00354     }
00355     else
00356     {
00357       return m_write+m_buffer.size()-m_read;
00358     }
00359   }
00360 
00362   size_type capacity() const { return m_buffer.size()-1; }
00363 
00365   size_type reserve() const
00366   {
00367     return capacity() - size();
00368   }
00369 
00371 
00375   void setCapacity(size_type capacity)
00376   {
00377     size_type old_size = size();
00378     size_type new_size = (capacity < old_size) ? capacity : old_size;
00379     std::vector<T> old_buffer(m_buffer);
00380     size_type old_read = m_read;
00381 
00382     // Adjust capacity.
00383     m_buffer.resize(capacity+1);
00384     // Skip elements that will not fit.
00385     old_read += old_size-new_size;
00386     if (old_read >= old_buffer.size())
00387     {
00388       old_read -= old_buffer.size();
00389     }
00390     // Copy the rest.
00391     for (size_type i=0; i<new_size; i++)
00392     {
00393       m_buffer[i] = old_buffer[old_read];
00394       old_read++;
00395       if (old_read >= old_buffer.size())
00396       {
00397         old_read = 0;
00398       }
00399     }
00400     // Update pointers.
00401     m_read = 0;
00402     m_write = new_size;
00403   }
00404 
00408   ~RingBuffer()
00409   { }
00410 
00411   const_iterator begin() const
00412   { return const_iterator(&m_buffer[m_read], &m_buffer[0], &m_buffer[0]+m_buffer.size(), &m_buffer[m_read]); }
00413   iterator begin()
00414   { return iterator(&m_buffer[m_read], &m_buffer[0], &m_buffer[0]+m_buffer.size(), &m_buffer[m_read]); }
00415 
00416   const_iterator end() const
00417   { return const_iterator(&m_buffer[m_write], &m_buffer[0], &m_buffer[0]+m_buffer.size(), &m_buffer[m_read]); }
00418   iterator end()
00419   { return iterator(&m_buffer[m_write], &m_buffer[0], &m_buffer[0]+m_buffer.size(), &m_buffer[m_read]); }
00420 
00436   array_range arrayOne();
00441   const_array_range arrayOne() const;
00442 
00447   array_range arrayTwo();
00452   const_array_range arrayTwo() const;
00453 
00458   array_range emptyArrayOne();
00463   const_array_range emptyArrayOne() const;
00468   array_range emptyArrayTwo();
00473   const_array_range emptyArrayTwo() const;
00474 
00476 #ifdef _IC_BUILDER_DEPRECATED_STYLE_
00477 
00481   ICL_CORE_VC_DEPRECATE_STYLE void Clear() ICL_CORE_GCC_DEPRECATE_STYLE;
00482 
00484 
00489   ICL_CORE_VC_DEPRECATE_STYLE
00490   void Write(const T& val, bool overwrite=false) ICL_CORE_GCC_DEPRECATE_STYLE;
00491 
00493 
00498   ICL_CORE_VC_DEPRECATE_STYLE const T& At(size_type pos) const ICL_CORE_GCC_DEPRECATE_STYLE;
00499 
00501 
00506   ICL_CORE_VC_DEPRECATE_STYLE T& At(size_type pos) ICL_CORE_GCC_DEPRECATE_STYLE;
00507 
00511   ICL_CORE_VC_DEPRECATE_STYLE void Skip() ICL_CORE_GCC_DEPRECATE_STYLE;
00512 
00514 
00517   ICL_CORE_VC_DEPRECATE_STYLE T Read() ICL_CORE_GCC_DEPRECATE_STYLE;
00518 
00522   inline ICL_CORE_VC_DEPRECATE_STYLE size_type Size() const ICL_CORE_GCC_DEPRECATE_STYLE;
00523 
00527   ICL_CORE_VC_DEPRECATE_STYLE size_type Capacity() const ICL_CORE_GCC_DEPRECATE_STYLE;
00528 
00530 
00535   ICL_CORE_VC_DEPRECATE_STYLE void SetCapacity(size_type capacity) ICL_CORE_GCC_DEPRECATE_STYLE;
00536 
00537 #endif
00538 
00539 
00540 private:
00541   std::vector<T> m_buffer;
00542   size_type m_write;
00543   size_type m_read;
00544 };
00545 
00546 }
00547 
00548 #include "icl_core/RingBuffer.hpp"
00549 
00550 #endif


fzi_icl_core
Author(s):
autogenerated on Tue Aug 8 2017 02:28:03