#ifndef VECTOR_N_H #define VECTOR_N_H #include #include template > class vector_n { template friend bool operator==(const vector_n& lhs, const vector_n& rhs); template friend bool operator!=(const vector_n& lhs, const vector_n& rhs); public: using value_type = typename std::vector::value_type; using allocator_type = typename std::vector::allocator_type; using size_type_n = typename std::vector::size_type; using size_type = std::vector; using static_size_type = std::initializer_list; using difference_type_n = typename std::vector::size_type; using difference_type = std::vector; using reference = typename std::vector::reference; using const_reference = typename std::vector::const_reference; using pointer = typename std::vector::pointer; using const_pointer = typename std::vector::const_pointer; using iterator = typename std::vector::iterator; using const_iterator = typename std::vector::const_iterator; using reverse_iterator = typename std::vector::reverse_iterator; using const_reverse_iterator = typename std::vector::const_reverse_iterator; private: std::vector elements; size_type count; struct index_coefficient_dimension { size_type_n index; size_type_n coefficient; size_type_n dimension; index_coefficient_dimension() : index{0}, coefficient{1}, dimension{0} {} index_coefficient_dimension(size_type_n index, size_type_n coef, size_type_n dim) : index{index}, coefficient{coef}, dimension{dim} {} }; static size_type_n count_n(const size_type& count) { auto accumulator = [](size_type_n left, size_type_n right) { return left * right; }; return std::accumulate(count.begin(), count.end(), 1, accumulator); } static size_type_n count_n(static_size_type count) { auto accumulator = [](size_type_n left, size_type_n right) { return left * right; }; return std::accumulate(count.begin(), count.end(), 1, accumulator); } size_type_n pos_n(const size_type& pos) const { auto accumulator = [&](index_coefficient_dimension partial, size_type_n index) -> index_coefficient_dimension { return {partial.index + partial.coefficient * index, partial.coefficient * count.begin()[partial.dimension], partial.dimension + 1}; }; return std::accumulate(std::rbegin(pos), std::rend(pos), index_coefficient_dimension{}, accumulator) .index; } size_type_n pos_n(static_size_type pos) const { auto accumulator = [&](index_coefficient_dimension partial, size_type_n index) -> index_coefficient_dimension { return {partial.index + partial.coefficient * index, partial.coefficient * count.begin()[partial.dimension], partial.dimension + 1}; }; return std::accumulate(std::rbegin(pos), std::rend(pos), index_coefficient_dimension{}, accumulator) .index; } public: vector_n() noexcept(noexcept(Allocator())) {} explicit vector_n(const Allocator& alloc) noexcept : elements(alloc) {} vector_n(size_type count, const T& value, const allocator_type& alloc = allocator_type()) : elements(count_n(count), value, alloc), count(std::move(count)) {} explicit vector_n(size_type count, const allocator_type& alloc = allocator_type()) : elements(count_n(count), alloc), count(std::move(count)) {} vector_n(static_size_type count, const T& value, const allocator_type& alloc = allocator_type()) : elements(count_n(count), value, alloc), count(std::move(count)) {} explicit vector_n(static_size_type count, const allocator_type& alloc = allocator_type()) : elements(count_n(count), alloc), count(std::move(count)) {} vector_n(const vector_n& other) : elements(other.elements), count(other.count) {} vector_n(const vector_n& other, const allocator_type& alloc) : elements(other.elements, alloc), count(other.count) {} vector_n(vector_n&& other) noexcept : elements(std::move(other).data), count(std::move(other).count) {} vector_n(vector_n&& other, const allocator_type& alloc) : elements(std::move(other).data, alloc), count(std::move(other).count) { } vector_n& operator=(const vector_n& other) { elements = other.elements; count = other.count; } vector_n& operator=(vector_n&& other) noexcept( std::allocator_traits< allocator_type>::propagate_on_container_move_assignment::value || std::allocator_traits::is_always_equal::value) { elements = std::move(other).data; count = std::move(other).count; } void assign(size_type count, const T& value) { elements.assign(count_n(count), value); count = std::move(count); } void assign(static_size_type count, const T& value) { elements.assign(count_n(count), value); count = std::move(count); } allocator_type get_allocator() const { return elements.get_allocator(); } reference at(size_type pos) { return elements.at(pos_n(pos)); } const_reference at(size_type pos) const { return elements.at(pos_n(pos)); } reference at(static_size_type pos) { return elements.at(pos_n(pos)); } const_reference at(static_size_type pos) const { return elements.at(pos_n(pos)); } reference operator[](size_type pos) { return elements[pos_n(pos)]; } const_reference operator[](size_type pos) const { return elements[pos_n(pos)]; } reference operator[](static_size_type pos) { return elements[pos_n(pos)]; } const_reference operator[](static_size_type pos) const { return elements[pos_n(pos)]; } reference front() { return elements.front(); } const_reference front() const { return elements.front(); } reference back() { return elements.back(); } const_reference back() const { return elements.back(); } T* data() noexcept { return elements.data(); } const T* data() const noexcept { return elements.data(); } iterator begin() noexcept { return elements.begin(); } const_iterator begin() const noexcept { return elements.begin(); } const_iterator cbegin() const noexcept { return elements.cbegin(); } iterator end() noexcept { return elements.end(); } const_iterator end() const noexcept { return elements.end(); } const_iterator cend() const noexcept { return elements.cend(); } iterator rbegin() noexcept { return elements.rbegin(); } const_iterator rbegin() const noexcept { return elements.rbegin(); } const_iterator crbegin() const noexcept { return elements.crbegin(); } iterator rend() noexcept { return elements.rend(); } const_iterator rend() const noexcept { return elements.rend(); } const_iterator crend() const noexcept { return elements.crend(); } bool empty() const noexcept { return elements.empty(); } size_type size() const noexcept { return count; } size_type_n max_size() const noexcept { return elements.max_size(); } void clear() noexcept { elements.clear(); count.clear(); } void resize(size_type count) { elements.resize(count_n(count)); vector_n::count = std::move(count); } void resize(size_type count, const value_type& value) { elements.resize(count_n(count), value); vector_n::count = std::move(count); } void resize(static_size_type count) { elements.resize(count_n(count)); vector_n::count = std::move(count); } void resize(static_size_type count, const value_type& value) { elements.resize(count_n(count), value); vector_n::count = std::move(count); } void swap(vector_n& other) noexcept( std::allocator_traits::propagate_on_container_swap::value || std::allocator_traits::is_always_equal::value) { elements.swap(other.elements); count.swap(other.count); } }; template bool operator==(const vector_n& lhs, const vector_n& rhs) { return lhs.count == rhs.count && lhs.elements == rhs.elements; } template bool operator!=(const vector_n& lhs, const vector_n& rhs) { return lhs.count != rhs.count || lhs.elements != rhs.elements; } template void swap(vector_n& lhs, vector_n& rhs) noexcept(noexcept(lhs.swap(rhs))) { lhs.swap(rhs); } #endif // VECTOR_N_H