229 lines
4.3 KiB
C++
229 lines
4.3 KiB
C++
/*
|
|
* utility_ringbuffer.hpp
|
|
*
|
|
* Created on: Mar 12, 2021
|
|
* Author: erki
|
|
*/
|
|
|
|
#ifndef SKULLC_UTILITY_RINGBUFFER_HPP_
|
|
#define SKULLC_UTILITY_RINGBUFFER_HPP_
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <iterator>
|
|
|
|
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_;
|
|
|
|
if (tail_ == head_)
|
|
is_full_ = true;
|
|
}
|
|
|
|
template<typename... Args>
|
|
void emplace_back(Args&&... args)
|
|
{
|
|
if (size() == N)
|
|
return;
|
|
|
|
new (&*tail_) T(std::forward<Args>(args)...);
|
|
++tail_;
|
|
}
|
|
|
|
void increment_tail()
|
|
{
|
|
if (is_full_)
|
|
++head_;
|
|
|
|
++tail_;
|
|
}
|
|
|
|
void pop_front()
|
|
{
|
|
if (empty())
|
|
return;
|
|
|
|
++head_;
|
|
is_full_ = false;
|
|
}
|
|
|
|
reference front() { return *head_; }
|
|
|
|
const_reference front() const { return *head_; }
|
|
|
|
reference back()
|
|
{
|
|
if (empty())
|
|
return *tail_;
|
|
else
|
|
return *(tail_ - 1);
|
|
}
|
|
|
|
const_reference back() const
|
|
{
|
|
if (empty())
|
|
return *tail_;
|
|
else
|
|
return *(tail_ - 1);
|
|
}
|
|
|
|
size_type size() const
|
|
{
|
|
if (head_ == tail_)
|
|
{
|
|
if (is_full_)
|
|
return N;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
const typename Ringbuffer<T, N>::iterator::difference_type distance =
|
|
tail_ - head_;
|
|
|
|
if (distance > 0)
|
|
{
|
|
return distance;
|
|
}
|
|
else
|
|
{
|
|
return head_ - tail_ + 1;
|
|
}
|
|
}
|
|
|
|
constexpr size_type max_size() const { return N; }
|
|
|
|
bool empty() const { return size() == 0; }
|
|
|
|
private:
|
|
std::array<T, N> data_;
|
|
bool is_full_ = false;
|
|
|
|
iterator head_;
|
|
iterator tail_;
|
|
};
|
|
|
|
}// namespace Utility
|
|
|
|
#endif /* SKULLC_UTILITY_RINGBUFFER_HPP_ */
|