Created
August 13, 2016 11:01
-
-
Save zavorka/1a703224b8adb34b8d42724af49acf81 to your computer and use it in GitHub Desktop.
Simple fixed-sized ring "buffer"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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