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:
parent
b397fc2d7d
commit
765e28849c
2 changed files with 131 additions and 0 deletions
63
src/circularbuffer.hpp
Normal file
63
src/circularbuffer.hpp
Normal 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
68
src/circularbuffer.inl
Normal 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
|
Loading…
Reference in a new issue