const_container/include/const_vector.hpp

227 lines
8.1 KiB
C++

//
// Created by Patrick Maschek on 19.12.2023.
//
#ifndef UDIFF_IMMARRAY_H_
#define UDIFF_IMMARRAY_H_
#include <algorithm>
#include <initializer_list>
#include <iterator>
#include <utility>
#include "helper.h"
namespace cc {
template<typename T, std::size_t N>
class const_vector {
static_assert(N > 0, "Capacity of const_vector has to be greater than 0");
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 *;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
protected:
T _arr[N] = {};
static constexpr const size_type _len = N;
size_type _size = 0;
public:
constexpr const_vector() noexcept = default;
constexpr explicit const_vector(const value_type &value) noexcept;
constexpr const_vector(size_type count, const value_type &value) noexcept;
constexpr explicit const_vector(const value_type (&array)[N]) noexcept;
constexpr const_vector(std::initializer_list<value_type> values) noexcept;
template<std::input_iterator InputIt>
constexpr const_vector(InputIt first, InputIt last);
constexpr const_vector(const const_vector& other) noexcept;
constexpr const_vector(const_vector&& other) noexcept;
constexpr const_vector<T, N>& operator=(const const_vector& other);
constexpr const_vector<T, N>& operator=(const_vector&& other) noexcept;
constexpr const_vector<T, N>& operator=(const value_type (&array)[N]) noexcept;
constexpr void assign(size_type count, const value_type& value) noexcept;
template<std::input_iterator InputIt>
constexpr void assign(InputIt first, InputIt last);
constexpr void assign(std::initializer_list<value_type> values);
constexpr reference at(size_type pos);
constexpr const_reference at(size_type pos) const;
[[nodiscard]] constexpr reference front() noexcept{ return _arr[0]; }
[[nodiscard]] constexpr const_reference front() const noexcept { return _arr[0]; }
[[nodiscard]] constexpr reference back() noexcept { return _arr[_size]; }
[[nodiscard]] constexpr const_reference back() const noexcept { return _arr[_size]; }
[[nodiscard]] constexpr value_type * data() noexcept { return _arr; }
[[nodiscard]] constexpr const value_type * data() const noexcept { return _arr; }
[[nodiscard]] constexpr iterator begin() noexcept { return _arr; };
[[nodiscard]] constexpr const_iterator cbegin() const noexcept { return _arr; };
[[nodiscard]] constexpr iterator end() noexcept { return _arr + _size; };
[[nodiscard]] constexpr const_iterator cend() const noexcept { return _arr + _size; };
[[nodiscard]] constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator<iterator>(_arr + _size); };
[[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return std::reverse_iterator<const_iterator>(_arr + _size); };
[[nodiscard]] constexpr reverse_iterator rend() noexcept { return std::reverse_iterator<iterator>(_arr); };
[[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return std::reverse_iterator<const_iterator>(_arr); };
[[nodiscard]] constexpr size_type size() const noexcept { return _size; }
constexpr T& operator[](size_type pos) { return _arr[pos]; }
constexpr const T& operator[](size_type pos) const { return _arr[pos]; }
#ifdef UNIT_TEST
friend test_const_vector;
#endif
};
template<typename A>
const_vector(A[]) -> const_vector<A, helper::array_size<A>>;
template<typename ...T>
const_vector(T...) -> const_vector<std::common_type_t<T...>, sizeof...(T)>;
template<typename T, std::size_t N>
constexpr const_vector<T, N>::const_vector(const value_type &value) noexcept
: _size(N)
{
std::fill(std::begin(_arr), std::end(_arr), value);
}
template<typename T, std::size_t N>
constexpr const_vector<T, N>::const_vector(size_type count, const value_type &value) noexcept
{
if (count > N) count = N;
_size = count;
std::fill(_arr, _arr + _size, value);
}
template<typename T, std::size_t N>
constexpr const_vector<T, N>::const_vector(const value_type (&array)[N]) noexcept
: _size(N)
{
std::move(std::begin(array), std::end(array), _arr);
}
template<typename T, std::size_t N>
constexpr const_vector<T, N>::const_vector(std::initializer_list<value_type> values) noexcept
: _size(values.size())
{
std::move(values.begin(), values.end(), _arr);
}
template<typename T, std::size_t N>
template<std::input_iterator InputIt>
constexpr const_vector<T, N>::const_vector(InputIt first, InputIt last) {
//static_assert(std::distance(first, last) > N, "tried inserting more elements than const_vector is in size");
_size = std::distance(first, last);
std::copy(first, last, _arr);
}
template<typename T, std::size_t N>
constexpr const_vector<T, N>::const_vector(const const_vector &other) noexcept {
static_assert(N >= other._size, "size of other has to be equal to or smaller than this");
std::copy(other._arr, other._arr, _arr);
}
template<typename T, std::size_t N>
constexpr const_vector<T, N>::const_vector(const_vector &&other) noexcept {
static_assert(N == other.N, "size of const_vectors does not match");
std::move(other.begin(), other.end(), _arr);
}
template<typename T, std::size_t N>
constexpr const_vector<T, N> &const_vector<T, N>::operator=(const const_vector &other)
{
if (this == &other) return *this;
static_assert(N == other._len, "Cannot assign const_vector to other with different size");
assign(other.begin(), other.end());
return *this;
}
template<typename T, std::size_t N>
constexpr const_vector<T, N> &const_vector<T, N>::operator=(const_vector &&other) noexcept
{
static_assert(N == other._len, "Cannot assign const_vector to other with different size");
if (N != other.N) throw std::exception();
std::move(other.begin(), other.end(), _arr);
return *this;
}
template<typename T, std::size_t N>
constexpr const_vector<T, N> &const_vector<T, N>::operator=(const value_type (&array)[N]) noexcept
{
assign(std::begin(array), std::end(array));
return *this;
}
template<typename T, std::size_t N>
constexpr void const_vector<T, N>::assign(const_vector::size_type count, const value_type &value) noexcept {
if (count > N) count = N;
_size = count;
std::fill(std::begin(_arr), std::end(_arr), value);
}
template<typename T, std::size_t N>
template<std::input_iterator InputIt>
constexpr void const_vector<T, N>::assign(InputIt first, InputIt last) {
auto distance = std::distance(first, last);
if (distance > N) throw std::invalid_argument("Iterator distance in assign surpasses size" + std::to_string(distance) + ">=" + std::to_string(N));
_size = distance;
std::copy(first, last, _arr);
}
template<typename T, std::size_t N>
constexpr void const_vector<T, N>::assign(std::initializer_list<value_type> values) {
auto values_size = std::distance(values.begin(), values.end());
if (values_size > N) throw std::invalid_argument("Initializer list in assign has more elements than size" + std::to_string(values_size) + ">=" + std::to_string(N));
_size = values_size;
std::copy(values.begin(), values.end(), _arr);
}
template<typename T, std::size_t N>
constexpr const_vector<T, N>::reference const_vector<T, N>::at(const_vector::size_type pos) {
if (pos >= _size) throw std::out_of_range("Pos " + std::to_string(pos) + " is out of range");
return _arr[pos];
}
template<typename T, std::size_t N>
constexpr const_vector<T, N>::const_reference const_vector<T, N>::at(const_vector::size_type pos) const {
if (pos >= _size) throw std::out_of_range("Pos " + std::to_string(pos) + " is out of range");
return _arr[pos];
}
}; // cc
#endif //UDIFF_IMMARRAY_H_