Created
September 14, 2016 15:30
-
-
Save zavorka/190d660ba8c38196effe9efed74a34b5 to your computer and use it in GitHub Desktop.
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 <algorithm> | |
#include <type_traits> | |
#include <utility> | |
namespace re { | |
namespace lib { | |
template <typename C> | |
class Ring | |
{ | |
public: | |
using value_type = typename C::value_type; | |
using pointer = value_type*; | |
using reference = value_type&; | |
using const_reference = value_type const&; | |
using universal_reference = value_type&&; | |
using size_type = typename C::size_type; | |
using difference_type = typename C::difference_type; | |
using index_type = difference_type; | |
using iterator = typename C::iterator; | |
using const_iterator = typename C::const_iterator; | |
using reverse_iterator = typename C::reverse_iterator; | |
using const_reverse_iterator = typename C::const_reverse_iterator; | |
constexpr Ring() | |
noexcept(std::is_nothrow_default_constructible<C>::value) | |
{ | |
} | |
constexpr Ring(Ring const& ring) | |
noexcept(std::is_nothrow_copy_constructible<C>::value) : | |
c(ring.c) | |
{ | |
} | |
constexpr Ring(Ring&& ring) | |
noexcept(std::is_nothrow_move_constructible<C>::value) : | |
c(std::move(ring.c)) | |
{ | |
} | |
constexpr Ring(C const& rhs) | |
noexcept(std::is_nothrow_copy_constructible<C>::value) : | |
c(rhs) | |
{ | |
} | |
constexpr Ring(C&& rhs) | |
noexcept(std::is_nothrow_move_constructible<C>::value) : | |
c(std::move(rhs)) | |
{ | |
} | |
constexpr Ring& operator=(Ring const& rhs) | |
noexcept(std::is_nothrow_copy_assignable<C>::value) { | |
c = rhs.c; | |
return *this; | |
} | |
constexpr Ring& operator=(Ring&& rhs) | |
noexcept(std::is_nothrow_move_assignable<C>::value) { | |
c = std::move(rhs.c); | |
return *this; | |
} | |
constexpr Ring& operator=(C const& rhs) | |
noexcept(std::is_nothrow_copy_assignable<C>::value) { | |
c = rhs; | |
return *this; | |
} | |
constexpr Ring& operator=(C&& rhs) | |
noexcept(std::is_nothrow_move_assignable<C>::value) { | |
c = std::move(rhs); | |
return *this; | |
} | |
template <typename T, typename std::enable_if_t<std::is_assignable<C, T>::value>> | |
constexpr Ring& operator=(T&& t) | |
noexcept(std::is_nothrow_assignable<C, T>::value) { | |
c = std::forward<T>(t); | |
return *this; | |
} | |
void swap(Ring& rhs) | |
noexcept (c.swap(rhs.c)) { | |
c.swap(rhs.c); | |
} | |
void swap(C& rhs) | |
noexcept (c.swap(rhs)) { | |
c.swap(rhs); | |
} | |
constexpr size_type size() const noexcept { return c.size(); } | |
constexpr size_type max_size() const noexcept { return size(); } | |
constexpr bool empty() const noexcept { return c.empty(); } | |
constexpr pointer data() const noexcept { return c.data(); } | |
constexpr void fill(const_reference value) | |
noexcept(std::is_nothrow_copy_constructible<value_type>::value) { | |
std::fill(begin(), end(), value); | |
} | |
constexpr reference operator[](index_type i) { return c[i]; } | |
constexpr const_reference operator[](index_type i) const noexcept { return c[i]; } | |
constexpr reference at() { return c.back(); } | |
constexpr const_reference at() const { return c.back(); } | |
constexpr reference front() noexcept { return c.front(); } | |
constexpr const_reference front() const noexcept { return c.front(); } | |
constexpr reference back() noexcept { return c.back(); } | |
constexpr const_reference back() const noexcept { return c.back(); } | |
constexpr iterator begin() const noexcept { return c.begin(); } | |
constexpr iterator end() noexcept { return c.end(); } | |
constexpr const_iterator begin() noexcept { return c.begin(); } | |
constexpr const_iterator end() const noexcept { return c.end(); } | |
constexpr const_iterator cbegin() const noexcept { return c.cbegin(); } | |
constexpr const_iterator cend() const noexcept { return c.cend(); } | |
constexpr reverse_iterator rbegin() noexcept { return c.rbegin(); } | |
constexpr reverse_iterator rend() noexcept { return c.rend(); } | |
constexpr const_reverse_iterator rbegin() const noexcept { return c.rbegin(); } | |
constexpr const_reverse_iterator rend() const noexcept { return c.rend(); } | |
constexpr const_reverse_iterator crbegin() const noexcept { return c.crbegin(); } | |
constexpr const_reverse_iterator crend() const noexcept { return c.crend(); } | |
constexpr void push_back(const_reference value) | |
noexcept(std::is_nothrow_copy_constructible<value_type>::value) { | |
auto value_copy{value}; | |
emplace_back(std::move(value_copy)); | |
} | |
constexpr void push_back(universal_reference value) | |
noexcept(std::is_nothrow_move_assignable<value_type>::value) { | |
emplace_back(std::move(value)); | |
} | |
template <typename... From> | |
constexpr reference emplace_back(From&&... from) | |
noexcept(std::is_nothrow_constructible<value_type, From...>::value | |
&& std::is_nothrow_move_assignable<value_type>::value) | |
{ | |
front() = value_type(std::forward<From>(from)...); | |
std::rotate(begin(), begin() + 1, end()); | |
return back(); | |
} | |
constexpr void push_front(const_reference value) | |
noexcept(std::is_nothrow_copy_constructible<value_type>::value) { | |
auto value_copy{value}; | |
emplace_front(std::move(value_copy)); | |
} | |
constexpr void push_front(universal_reference value) | |
noexcept(std::is_nothrow_move_assignable<value_type>::value) { | |
emplace_front(std::move(value)); | |
} | |
template <typename... From> | |
constexpr reference emplace_front(From&&... from) | |
noexcept(std::is_nothrow_constructible<value_type, From...>::value | |
&& std::is_nothrow_move_assignable<value_type>::value) { | |
back() = value_type(std::forward<From>(from)...); | |
std::rotate(begin(), end() - 1, end()); | |
return front(); | |
} | |
constexpr void insert(const_iterator pos, size_type n, value_type value) | |
noexcept(std::is_nothrow_copy_constructible<value_type>::value | |
&& std::is_nothrow_move_assignable<value_type>::value) { | |
difference_type d = std::distance(cbegin(), pos); | |
d = std::min(d, static_cast<difference_type>(n)); | |
while (d-- > 0) { | |
insert(pos, value); | |
} | |
} | |
template <typename InputIt> | |
constexpr void insert(const_iterator pos, InputIt first, InputIt last) | |
noexcept(std::is_nothrow_copy_constructible<value_type>::value | |
&& std::is_nothrow_move_assignable<value_type>::value) { | |
while (first != last) { | |
insert(pos, *(first++)); | |
} | |
} | |
constexpr iterator insert(const_iterator pos, const_reference value) | |
noexcept(std::is_nothrow_copy_constructible<value_type>::value | |
&& std::is_nothrow_move_assignable<value_type>::value) { | |
auto value_copy{value}; | |
return emplace(pos, std::move(value_copy)); | |
} | |
constexpr iterator insert(const_iterator pos, universal_reference value) | |
noexcept(std::is_nothrow_move_assignable<value_type>::value) { | |
return emplace(pos, std::move(value)); | |
} | |
constexpr void rinsert(const_iterator pos, size_type n, value_type value) | |
noexcept(std::is_nothrow_copy_constructible<value_type>::value | |
&& std::is_nothrow_move_assignable<value_type>::value) { | |
difference_type d = std::distance(pos, cend()); | |
d = std::min(d, static_cast<difference_type>(n)); | |
while (d-- > 0) { | |
rinsert(pos, value); | |
} | |
} | |
template <typename InputIt> | |
constexpr void rinsert(const_iterator pos, InputIt first, InputIt last) | |
noexcept(std::is_nothrow_copy_constructible<value_type>::value | |
&& std::is_nothrow_move_assignable<value_type>::value) { | |
while (first != last) { | |
rinsert(pos, *(first++)); | |
} | |
} | |
constexpr iterator rinsert(const_iterator pos, const_reference value) | |
noexcept(std::is_nothrow_copy_constructible<value_type>::value | |
&& std::is_nothrow_move_assignable<value_type>::value) { | |
auto value_copy{value}; | |
return remplace(pos, std::move(value_copy)); | |
} | |
constexpr iterator rinsert(const_iterator pos, universal_reference value) | |
noexcept(std::is_nothrow_move_assignable<value_type>::value) { | |
return remplace(pos, std::move(value)); | |
} | |
template <typename... From> | |
constexpr iterator emplace(const_iterator pos, From&&... from) | |
noexcept(std::is_nothrow_constructible<value_type, From...>::value | |
&& std::is_nothrow_move_assignable<value_type>::value) | |
{ | |
auto d = std::distance(cbegin(), pos); | |
if (d == 0) { | |
return begin(); | |
} | |
front() = value_type(std::forward<From>(from)...); | |
if (d == 1) { | |
return begin(); | |
} | |
auto last = begin() + d; | |
std::rotate(begin(), begin() + 1, last); | |
return last; | |
} | |
template <typename... From> | |
constexpr iterator remplace(const_iterator pos, From&&... from) | |
noexcept(std::is_nothrow_constructible<value_type, From...>::value | |
&& std::is_nothrow_move_assignable<value_type>::value) | |
{ | |
auto d = std::distance(pos, end()); | |
if (d == 0) { | |
return end(); | |
} | |
back() = value_type(std::forward<From>(from)...); | |
if (d == 1) { | |
return end() - 1; | |
} | |
auto first = end() - d; | |
std::rotate(first, end() - 1, end()) - 1; | |
return first; | |
} | |
private: | |
C c; | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment