skullc-peripherals/Utility/Inc/utility_ringbuffer.hpp
2021-03-14 15:19:04 +02:00

231 lines
3.8 KiB
C++

/*
* utility_ringbuffer.hpp
*
* Created on: Mar 12, 2021
* Author: erki
*/
#ifndef UTILITY_RINGBUFFER_HPP_
#define UTILITY_RINGBUFFER_HPP_
#include <array>
#include <iterator>
#include <cstddef>
namespace Utility
{
template<typename T, size_t N>
class Ringbuffer
{
public:
using value_type = T;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
struct iterator
{
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = value_type*;
using reference = value_type&;
iterator(const pointer ptr, const pointer begin, const pointer end)
: _ptr(ptr)
, _arr_begin(begin)
, _arr_end(end)
{ }
iterator(const iterator&) = default;
iterator(iterator&&) noexcept = default;
iterator& operator=(const iterator&) = default;
reference operator*() const
{
return *_ptr;
}
pointer operator->()
{
return _ptr;
}
iterator& operator++()
{
_ptr++;
if (_ptr == _arr_end)
_ptr = _arr_begin;
return *this;
}
iterator operator++(int)
{
iterator tmp = *this;
++(*this);
return tmp;
}
iterator operator+(const difference_type n) const
{
const pointer naive = _ptr + n;
if (naive < _arr_end)
{
return iterator(naive, _arr_begin, _arr_end);
}
else
{
const pointer remainder = pointer(naive - _arr_end);
return iterator(_arr_begin + difference_type(remainder), _arr_begin, _arr_end);
}
}
iterator operator-(const difference_type n) const
{
const pointer naive = _ptr - n;
if (naive >= _arr_begin)
{
return iterator(naive, _arr_begin, _arr_end);
}
else
{
const pointer remainder = pointer(_arr_begin - naive);
return iterator(_arr_end - difference_type(remainder), _arr_begin, _arr_end);
}
}
friend bool operator==(const iterator& a, const iterator& b)
{
return a._ptr == b._ptr;
}
friend bool operator!=(const iterator& a, const iterator& b)
{
return a._ptr != b._ptr;
}
friend difference_type operator-(const iterator& a, const iterator& b)
{
return a._ptr - b._ptr;
}
friend difference_type operator+(const iterator& a, const iterator& b)
{
return a._ptr + b._ptr;
}
private:
pointer _ptr;
pointer _arr_begin;
pointer _arr_end;
};
Ringbuffer()
: _head(&_data[0], &_data[0], &_data[N])
, _tail(_head)
{ }
Ringbuffer(const Ringbuffer&) = delete;
Ringbuffer(Ringbuffer&&) noexcept = default;
iterator begin()
{
return _head;
}
iterator end()
{
return _tail;
}
void clear()
{
_head = _tail;
}
void push_back(const T& value)
{
if (size() == N)
return;
*_tail = value;
++_tail;
}
template<typename... Args>
void emplace_back(Args&&... args)
{
if (size() == N)
return;
new (&*_tail)T(std::forward<Args>(args)...);
return *(_tail++);
}
void pop_front()
{
if (empty())
return;
++_head;
}
reference front()
{
return *_head;
}
const_reference front() const
{
return *_head;
}
reference back()
{
return *(_tail - 1);
}
const_reference back() const
{
return *(_tail - 1);
}
size_type size() const
{
if (_head == _tail)
return 0;
const typename Ringbuffer<T, N>::iterator::difference_type distance = _tail - _head;
if (distance > 0)
{
return distance;
}
else
{
return _head - _tail;
}
}
bool empty() const
{
return size() == 0;
}
private:
std::array<T, N> _data;
iterator _head;
iterator _tail;
};
}
#endif /* UTILITY_RINGBUFFER_HPP_ */