/* * utility_ringbuffer.hpp * * Created on: Mar 12, 2021 * Author: erki */ #ifndef UTILITY_RINGBUFFER_HPP_ #define UTILITY_RINGBUFFER_HPP_ #include #include #include namespace Utility { template 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 void emplace_back(Args&&... args) { if (size() == N) return; new (&*_tail)T(std::forward(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::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 _data; bool _is_full = false; iterator _head; iterator _tail; }; } #endif /* UTILITY_RINGBUFFER_HPP_ */