Skip to content

Instantly share code, notes, and snippets.

@zavorka
Created August 13, 2016 11:01
Show Gist options
  • Save zavorka/1a703224b8adb34b8d42724af49acf81 to your computer and use it in GitHub Desktop.
Save zavorka/1a703224b8adb34b8d42724af49acf81 to your computer and use it in GitHub Desktop.
Simple fixed-sized ring "buffer"
// Copyright (c) 2016 Roman Beránek. All rights reserved.
//
// This program 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.
//
// This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <cassert>
#include <array>
#include <iterator>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace reBass {
template <typename T, std::size_t Size>
class Ring_array {
public:
typedef T value_type;
typedef T& reference;
typedef T const& const_reference;
typedef std::array<value_type, Size> container_type;
typedef typename container_type::size_type size_type;
typedef typename container_type::difference_type difference_type;
typedef typename container_type::pointer pointer;
typedef typename container_type::const_pointer const_pointer;
template <bool Is_const = false>
class iterator: public std::iterator<
std::random_access_iterator_tag,
value_type,
difference_type,
pointer
> {
public:
explicit iterator(
std::conditional_t<
Is_const,
Ring_array const&,
Ring_array&
> ring,
size_type position
) noexcept :
ring(ring),
position(position) {
}
explicit iterator(
iterator const& it,
difference_type diff
) noexcept :
ring(it.ring),
position(it.position + diff) {
}
/* TODO
iterator<true>(iterator<false> const& non_const_iterator) {
return iterator<true>(
non_const_iterator.ring,
non_const_iterator.position
);
}
*/
inline iterator& operator++() noexcept {
++position;
return *this;
}
inline iterator& operator++(int) noexcept {
++position;
return *this;
}
inline iterator& operator--() noexcept {
--position;
return *this;
}
inline iterator& operator--(int) noexcept {
--position;
return *this;
}
inline iterator operator+(iterator const& rhs) const noexcept {
assert(&ring == &rhs.ring);
return iterator(ring, position + rhs.position);
}
inline iterator operator-(iterator const& rhs) const noexcept {
assert(&ring == &rhs.ring);
return iterator(ring, position - rhs.position);
}
inline iterator operator+(difference_type rhs) const noexcept {
return iterator(ring, position + rhs);
}
inline iterator& operator+=(difference_type rhs) noexcept {
position += rhs;
return *this;
}
inline iterator operator-(difference_type rhs) const noexcept {
return iterator(ring, position - rhs);
}
inline iterator& operator-=(difference_type rhs) noexcept {
position -= rhs;
return *this;
}
inline bool operator==(iterator const& rhs) const noexcept {
return (&ring == &rhs.ring) && (position == rhs.position);
}
inline bool operator!=(iterator const& rhs) const noexcept {
return (&ring != &rhs.ring) || (position != rhs.position);
}
inline bool operator<(iterator const& rhs) const noexcept {
assert(&ring == &rhs.ring);
return position < rhs.position;
}
inline bool operator<=(iterator const& rhs) const noexcept {
assert(&ring == &rhs.ring);
return position <= rhs.position;
}
inline bool operator>(iterator const& rhs) const noexcept {
assert(&ring == &rhs.ring);
return position > rhs.position;
}
inline bool operator>=(iterator const& rhs) const noexcept {
assert(&ring == &rhs.ring);
return position >= rhs.position;
}
inline std::conditional_t<Is_const, const_reference, reference>
operator[](difference_type d) const noexcept {
return ring[static_cast<size_type>(position + d)];
}
inline std::conditional_t<Is_const, const_reference, reference>
operator*() const noexcept {
return ring[position];
}
inline std::conditional_t<Is_const, const_pointer, pointer>
operator->() const noexcept {
return &ring[position];
}
private:
std::conditional_t<Is_const, Ring_array const&, Ring_array&> ring;
size_type position;
};
typedef iterator<true> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
constexpr Ring_array()
noexcept(std::is_nothrow_default_constructible_v<T>) :
next(std::begin(c))
{
}
Ring_array(Ring_array const& rhs)
noexcept(std::is_nothrow_copy_constructible_v<T>) :
c(rhs.c),
next(std::begin(c) + std::distance(std::begin(rhs.c), rhs.next))
{
}
Ring_array(Ring_array&& rhs)
noexcept(std::is_nothrow_move_constructible_v<T>) :
c(std::move(rhs.c)),
next(std::begin(c) + std::distance(std::begin(rhs.c), rhs.next))
{
}
Ring_array(container_type const& rhs)
noexcept(std::is_nothrow_copy_constructible_v<T>) :
c(rhs),
next(std::begin(c))
{
}
Ring_array(container_type&& rhs)
noexcept(std::is_nothrow_move_constructible_v<T>) :
c(std::move(rhs)),
next(std::begin(c))
{
}
Ring_array& operator=(Ring_array const& rhs)
noexcept(std::is_nothrow_copy_assignable_v<T>) {
c = rhs.c;
next = std::begin(c) + std::distance(std::begin(rhs.c), rhs.next);
return *this;
}
Ring_array& operator=(Ring_array&& rhs)
noexcept(std::is_nothrow_move_assignable_v<T>) {
auto position = static_cast<size_type>(
std::distance(std::begin(rhs.c), rhs.next)
);
c = std::move(rhs.c);
next = std::begin(c) + position;
return *this;
}
constexpr size_type size() noexcept {
return Size;
}
constexpr bool empty() noexcept {
return Size == 0;
}
inline reference operator[](size_type position) noexcept {
return c[position_to_index(position)];
}
inline const_reference operator[](size_type position) const noexcept {
return c[position_to_index(position)];
}
inline reference at(size_type position) {
if (position >= Size || position < 0) {
throw_out_of_range();
}
return c[position_to_index(position)];
}
inline const_reference at(size_type position) const {
if (position >= Size || position < 0) {
throw_out_of_range();
}
return c[position_to_index(position)];
}
inline reference back() noexcept {
return (next != std::begin(c)) ? *(next - 1) : c.front();
}
inline const_reference back() const noexcept {
return (next != std::begin(c)) ? *(next - 1) : c.front();
}
inline reference front() noexcept {
return *next;
}
inline const_reference front() const noexcept {
return *next;
}
inline iterator begin() noexcept {
return iterator(*this, 0u);
}
inline iterator end() noexcept {
return iterator(*this, Size);
}
inline const_iterator cbegin() const noexcept {
return const_iterator(*this, 0u);
}
inline const_iterator cend() const noexcept {
return const_iterator(*this, Size);
}
inline reverse_iterator rbegin() noexcept {
return reverse_iterator(end());
}
inline reverse_iterator rend() noexcept {
return reverse_iterator(begin());
}
inline const_reverse_iterator crbegin() const noexcept {
return const_reverse_iterator(cend());
}
inline const_reverse_iterator crend() const noexcept {
return const_reverse_iterator(cbegin());
}
void push_back(value_type&& value)
noexcept(std::is_nothrow_move_assignable_v<T>) {
*(next++) = std::move(value);
if (next == std::end(c)) {
next = std::begin(c);
}
}
template <typename... From>
void emplace_back(From&&... from)
noexcept(std::is_nothrow_constructible_v<T, From...>
&& std::is_nothrow_move_assignable_v<T>) {
*(next++) = T(std::forward<From>(from)...);
if (next == std::end(c)) {
next = std::begin(c);
}
}
template <typename InputIterator>
void insert_at_end(InputIterator first, InputIterator last) {
assert(std::distance(first, last) >= 0);
while (first != last) {
push_back(*(first++));
}
}
private:
inline void throw_out_of_range() const {
throw std::out_of_range("Ring_array");
}
inline size_type position_to_index(size_type position) const noexcept {
difference_type d = std::distance(next, std::end(c));
assert(d < Size && d >= 0);
size_type index = static_cast<size_type>(d) + position;
return (index < Size) ? index : (index - Size);
}
container_type c;
container_type::iterator next;
};
/* TODO
template <typename T, std::size_t N>
inline Ring_array<T, N>::iterator operator+(
Ring_array<T, N>::difference_type lhs,
Ring_array<T, N>::iterator const& rhs
) noexcept {
return Ring_array<T, N>::iterator(rhs, lhs);
}
template <typename T, std::size_t N>
inline Ring_array<T, N>::iterator operator-(
Ring_array<T, N>::difference_type lhs,
Ring_array<T, N>::iterator const& rhs
) noexcept {
return Ring_array<T, N>::iterator(rhs, -lhs);
}
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment