Add a circular buffer class.

This was necessary as the one provided by boost didn't work
with my use case (though I don't remember, I wrote this code
months ago and I'm only committing now).
This commit is contained in:
King_DuckZ 2014-07-04 13:22:42 +02:00
parent b397fc2d7d
commit 765e28849c
2 changed files with 131 additions and 0 deletions

63
src/circularbuffer.hpp Normal file
View file

@ -0,0 +1,63 @@
/*
Copyright 2014 Michele "King_DuckZ" Santullo
This file is part of CloonelJump.
CloonelJump is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CloonelJump is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CloonelJump. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef idF67A018826604CAFBE25BCA939A1FBC9
#define idF67A018826604CAFBE25BCA939A1FBC9
#include <boost/noncopyable.hpp>
#include <iterator>
#include <stdexcept>
#include <ciso646>
namespace cloonel {
template <typename Iterator>
class CircularBuffer : public boost::noncopyable {
public:
typedef size_t size_type;
typedef typename std::iterator_traits<Iterator>::value_type value_type;
typedef typename std::iterator_traits<Iterator>::reference reference;
CircularBuffer ( Iterator parFirst, Iterator parLast );
CircularBuffer ( CircularBuffer&& parOther );
~CircularBuffer ( void ) noexcept = default;
CircularBuffer& operator= ( CircularBuffer&& parOther );
reference operator[] ( size_type parIndex );
size_type size ( void ) const { return (m_used >= capacity() ? capacity() : m_used); }
bool empty ( void ) const { return 0 == m_used; }
size_type capacity ( void ) const { return m_end - m_start; }
void push ( value_type&& parObj );
void reset ( void );
void reset ( Iterator parFirst, Iterator parLast );
reference front ( void );
reference back ( void );
private:
Iterator m_start;
Iterator m_end;
Iterator m_curr;
size_type m_used;
};
} //namespace cloonel
#include "circularbuffer.inl"
#endif

68
src/circularbuffer.inl Normal file
View file

@ -0,0 +1,68 @@
namespace cloonel {
template <typename Iterator>
CircularBuffer<Iterator>::CircularBuffer (Iterator parFirst, Iterator parLast) :
m_start(parFirst),
m_end(parLast),
m_curr(parFirst),
m_used(0)
{
}
template <typename Iterator>
void CircularBuffer<Iterator>::push (value_type&& parObj) {
*m_curr = std::move(parObj);
++m_curr;
++m_used;
if (m_curr == m_end) {
m_curr = m_start;
m_used = capacity();
}
}
template <typename Iterator>
void CircularBuffer<Iterator>::reset() {
m_used = 0;
m_curr = m_start;
}
template <typename Iterator>
void CircularBuffer<Iterator>::reset (Iterator parFirst, Iterator parLast) {
m_start = parFirst;
m_end = parLast;
reset();
}
template <typename Iterator>
typename CircularBuffer<Iterator>::reference CircularBuffer<Iterator>::front() {
if (empty())
throw std::out_of_range("The circular buffer is empty, but front() was called.");
if (m_curr == m_start)
return *(m_start + (capacity() - 1));
else
return *(m_curr - 1);
}
template <typename Iterator>
typename CircularBuffer<Iterator>::reference CircularBuffer<Iterator>::back() {
if (empty())
throw std::out_of_range("The circular buffer is empty, but back() was called.");
const auto cap = capacity();
if (m_used != cap) {
return *m_start;
}
else {
const auto currPos = m_curr - m_start;
const auto index = (currPos + cap - 1) % cap;
return *(m_start + index);
}
}
template <typename Iterator>
typename CircularBuffer<Iterator>::reference CircularBuffer<Iterator>::operator[] (size_type parIndex) {
if (parIndex < 0 or parIndex >= size())
throw std::out_of_range("Index out of range in CircularBuffer");
const auto index = (m_curr - m_start + parIndex) % capacity();
return *(m_start + index);
}
} //namespace cloonel