From b3a062688eec5304a030f421e41bc56940f246d3 Mon Sep 17 00:00:00 2001 From: cyborg1811m Date: Thu, 4 Jan 2024 16:16:44 +0100 Subject: [PATCH] added first version of methods --- include/const_vector.hpp | 263 ++++++++++++++++++++++++++++++++++++--- include/helper.h | 53 +++++++- 2 files changed, 298 insertions(+), 18 deletions(-) diff --git a/include/const_vector.hpp b/include/const_vector.hpp index ce4b459..88f55d8 100644 --- a/include/const_vector.hpp +++ b/include/const_vector.hpp @@ -54,6 +54,8 @@ namespace cc { constexpr const_vector(const const_vector& other) noexcept; constexpr const_vector(const_vector&& other) noexcept; + constexpr ~const_vector() = default; // elements in static array should be destroyed automatically + constexpr const_vector& operator=(const const_vector& other); constexpr const_vector& operator=(const_vector&& other) noexcept; constexpr const_vector& operator=(const value_type (&array)[N]) noexcept; @@ -66,6 +68,9 @@ namespace cc { constexpr reference at(size_type pos); constexpr const_reference at(size_type pos) const; + constexpr T& operator[](size_type pos) { return _arr[pos]; } + constexpr const T& operator[](size_type pos) const { return _arr[pos]; } + [[nodiscard]] constexpr reference front() noexcept{ return _arr[0]; } [[nodiscard]] constexpr const_reference front() const noexcept { return _arr[0]; } @@ -76,21 +81,54 @@ namespace cc { [[nodiscard]] constexpr const value_type * data() const noexcept { return _arr; } [[nodiscard]] constexpr iterator begin() noexcept { return _arr; }; + [[nodiscard]] constexpr const_iterator begin() const noexcept { return _arr; }; [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return _arr; }; [[nodiscard]] constexpr iterator end() noexcept { return _arr + _size; }; + [[nodiscard]] constexpr const_iterator end() const noexcept { return _arr + _size; }; [[nodiscard]] constexpr const_iterator cend() const noexcept { return _arr + _size; }; [[nodiscard]] constexpr reverse_iterator rbegin() noexcept { return std::reverse_iterator(_arr + _size); }; + [[nodiscard]] constexpr const_reverse_iterator rbegin() const noexcept { return std::reverse_iterator(_arr + _size); }; [[nodiscard]] constexpr const_reverse_iterator crbegin() const noexcept { return std::reverse_iterator(_arr + _size); }; [[nodiscard]] constexpr reverse_iterator rend() noexcept { return std::reverse_iterator(_arr); }; + [[nodiscard]] constexpr const_reverse_iterator rend() const noexcept { return std::reverse_iterator(_arr); }; [[nodiscard]] constexpr const_reverse_iterator crend() const noexcept { return std::reverse_iterator(_arr); }; + [[nodiscard]] constexpr bool empty() const noexcept { return begin() == end(); } // vector standard defines empty as this + [[nodiscard]] constexpr size_type max_size() const noexcept { return _len; } + [[nodiscard]] constexpr size_type capacity() const noexcept { return _len; } [[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]; } + constexpr void clear() { _erase_no_move(std::begin(_arr), std::end(_arr)); } + + constexpr iterator insert(const_iterator pos, const T& value); + constexpr iterator insert(const_iterator pos, T&& value); + constexpr iterator insert(const_iterator pos, size_type count, const T& value); + template + constexpr iterator insert(const_iterator pos, InputIt first, InputIt last); + constexpr iterator insert(const_iterator pos, std::initializer_list values); + + template + constexpr iterator emplace(const_iterator pos, Args&&... args); + + constexpr iterator erase(const_iterator pos); + constexpr iterator erase(const_iterator first, const_iterator last); + + constexpr void push_back(const T& value); + constexpr void push_back(T&& value); + + template + constexpr reference emplace_back(Args&&... args); + + constexpr void pop_back(); + + template + constexpr void swap(const_vector& other); + + protected: + constexpr inline void _erase_no_move(const_iterator first, const_iterator last) { std::destroy(first, last); } #ifdef UNIT_TEST friend test_const_vector; @@ -103,7 +141,48 @@ namespace cc { template const_vector(T...) -> const_vector, sizeof...(T)>; - + + + template + constexpr bool operator==(const const_vector& lhs, + const const_vector& rhs) + { + return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + template + constexpr auto operator<=>(const const_vector& lhs, + const const_vector& rhs) + { + return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end(), std::compare_three_way()); + } + + template + constexpr void swap(const const_vector& lhs, + const const_vector& rhs) + { + return lhs.swap(rhs); + } + + template + constexpr const_vector::size_type erase(const_vector& vec, const U& value) + { + auto it = std::remove(vec.begin(), vec.end(), value); + auto r = vec.end() - it; + vec.erase(it, vec.end()); + + return r; + } + + template + constexpr const_vector::size_type erase(const_vector& vec, Pred pred) + { + auto it = std::remove_if(vec.begin(), vec.end(), pred); + auto r = vec.end() - it; + vec.erase(it, vec.end()); + + return r; + } template @@ -137,21 +216,26 @@ namespace cc { template template - constexpr const_vector::const_vector(InputIt first, InputIt last) { + constexpr const_vector::const_vector(InputIt first, InputIt last) + : _size(std::distance(first, 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 - constexpr const_vector::const_vector(const const_vector &other) noexcept { - static_assert(N >= other._size, "size of other has to be equal to or smaller than this"); + constexpr const_vector::const_vector(const const_vector &other) noexcept + : _size(other._size) + { + if (N >= other._size) throw std::invalid_argument("size of other has to be equal to or smaller than this"); std::copy(other._arr, other._arr, _arr); } template - constexpr const_vector::const_vector(const_vector &&other) noexcept { - static_assert(N == other.N, "size of const_vectors does not match"); + constexpr const_vector::const_vector(const_vector &&other) noexcept + : _size(other._size) + { + static_assert(N == other._len, "size of const_vectors does not match"); std::move(other.begin(), other.end(), _arr); } @@ -171,10 +255,12 @@ namespace cc { constexpr const_vector &const_vector::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(); - + if (N != other._len) throw std::exception(); + + clear(); std::move(other.begin(), other.end(), _arr); - + _size = other._size; + return *this; } @@ -186,23 +272,28 @@ namespace cc { } template - constexpr void const_vector::assign(const_vector::size_type count, const value_type &value) noexcept { + constexpr void const_vector::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 template - constexpr void const_vector::assign(InputIt first, InputIt last) { + constexpr void const_vector::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::destroy(_arr, _arr + _size); std::copy(first, last, _arr); } template - constexpr void const_vector::assign(std::initializer_list values) { + constexpr void const_vector::assign(std::initializer_list 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; @@ -210,17 +301,157 @@ namespace cc { } template - constexpr const_vector::reference const_vector::at(const_vector::size_type pos) { + constexpr const_vector::reference const_vector::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 - constexpr const_vector::const_reference const_vector::at(const_vector::size_type pos) const { + constexpr const_vector::const_reference const_vector::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]; } + template + constexpr const_vector::iterator const_vector::insert(const_vector::const_iterator pos, const T &value) + { + if (_size == N) throw std::exception(); + + ptrdiff_t i = pos - _arr; + std::move(_arr + i, _arr + _size, _arr + i + 1); + _arr[i] = value; + + ++_size; + return pos; + } + + template + constexpr const_vector::iterator const_vector::insert(const_vector::const_iterator pos, T &&value) + { + if (_size == N) throw std::exception(); + + ptrdiff_t i = pos - _arr; + std::move(_arr + i, _arr + _size, _arr + i + 1); + _arr[i] = std::move(value); + + ++_size; + return pos; + } + + template + constexpr const_vector::iterator + const_vector::insert(const_vector::const_iterator pos, const_vector::size_type count, const T &value) + { + if (count == 0) return pos; + if (_size + count >= N) throw std::exception(); + + std::move(pos, _arr + _size, pos + count); + std::fill(pos, pos + count, value); + + _size += count; + return pos; + } + + template + template + constexpr const_vector::iterator + const_vector::insert(const_vector::const_iterator pos, InputIt first, InputIt last) + { + auto count = std::distance(first, last); + + if (first == last) return pos; + if (_size + count >= N) throw std::exception(); + + + std::move(pos, _arr + _size, pos + count); + std::copy(first, last, pos); + + _size += count; + return pos; + } + + template + constexpr const_vector::iterator + const_vector::insert(const_vector::const_iterator pos, std::initializer_list values) + { + return insert(pos, values.begin(), values.end()); + } + + template + template + constexpr const_vector::iterator const_vector::emplace(const_vector::const_iterator pos, Args &&... args) + { + if (_size == N) throw std::exception(); + + T obj(std::forward(args)...); + + ptrdiff_t i = pos - _arr; + std::move(_arr + i, _arr + _size, _arr + i + 1); + _erase_no_move(pos); + _arr[i] = std::move(obj); + + return pos; + } + + template + constexpr const_vector::iterator const_vector::erase(const_vector::const_iterator pos) + { + _erase_no_move(pos); + std::move(pos + 1, end(), pos); + --_size; + + return pos; + } + + template + constexpr const_vector::iterator + const_vector::erase(const_vector::const_iterator first, const_vector::const_iterator last) + { + _erase_no_move(first, last); + std::move(last + 1, end(), first); + _size -= (last - first); + + return first; + } + + template + constexpr void const_vector::push_back(const const_vector::value_type &value) + { + insert(end(), value); + } + + template + constexpr void const_vector::push_back(T&& value) + { + insert(end(), value); + } + + template + template + constexpr const_vector::reference const_vector::emplace_back(Args&&... args) + { + emplace(end(), std::forward(args)...); + } + + template + constexpr void const_vector::pop_back() + { + _erase_no_move(end() - 1, end()); + --_size; + } + + template + template + constexpr void const_vector::swap(const_vector &other) + { + if (_size > other._len || other._size > N) throw std::exception(); + + cc::helper::swap_iter_range(begin(), end(), std::end(_arr), other.begin(), other.end(), std::end(other._arr)); + std::swap(_size, other._size); + } + }; // cc #endif //UDIFF_IMMARRAY_H_ diff --git a/include/helper.h b/include/helper.h index dd98101..f4c1592 100644 --- a/include/helper.h +++ b/include/helper.h @@ -8,10 +8,59 @@ #include namespace cc::helper { - + + template + inline auto advanced(Iter i, Distance n) { std::advance(i, n); return i; } + template constexpr std::size_t array_size(const T(&)[N]) { return N; } - + + template + requires ((InputIt1::value_type == InputIt2::value_type) + && std::indirectly_writable && std::indirectly_readable + && std::indirectly_writable && std::indirectly_readable) + constexpr void swap_iter_range(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2) + { + auto dist1 = std::distance(first1, last1); + auto dist2 = std::distance(first2, last2); + + if (dist1 == dist2) { + std::swap_ranges(first1, last1, first2); + return; + } + + auto swap_dist = std::min(dist1, dist2); + + std::swap_ranges(first1, advanced(first1, swap_dist), first2, advanced(first2, swap_dist)); + + std::advance(first1, swap_dist); + std::advance(first2, swap_dist); + + if (dist1 < dist2) { + std::move(first2, last2, last1); + } else { + std::move(first1, last1, last2); + } + } + + template + requires ((InputIt1::value_type == InputIt2::value_type) + && std::indirectly_writable && std::indirectly_readable + && std::indirectly_writable && std::indirectly_readable) + constexpr void swap(InputIt1 first1, InputIt1 last1, InputIt1 end1, InputIt2 first2, InputIt2 last2, InputIt2 end2) + { + auto max_dist = std::min(std::distance(first1, end1), std::distance(first2, end2)); + + auto dist1 = std::distance(first1, last1); + auto dist2 = std::distance(first2, last2); + + if (max_dist < dist1 || max_dist < dist2) throw std::invalid_argument("Distance between iterators does not fit inbetween other " + "(Range 1: " + std::to_string(dist1) + "/" + std::to_string(std::distance(first1, end1)) + ", " + + "Range 2: " + std::to_string(dist2) + "/" + std::to_string(std::distance(first2, end2)) + ")"); + + swap_iter_range(first1, last1, first2, last2); + } + }; // cc #endif //UDIFF_HELPER_H_