From 446426c11c4366efa31fd9255ad3e1e54523bc11 Mon Sep 17 00:00:00 2001 From: River <26424577+wusatosi@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:11:04 -0500 Subject: [PATCH] add tests for [container.reqmts] --- .../beman/inplace_vector/inplace_vector.hpp | 29 ++-- tests/beman/inplace_vector/constexpr.test.cpp | 125 ++++++++++++++++++ 2 files changed, 138 insertions(+), 16 deletions(-) diff --git a/include/beman/inplace_vector/inplace_vector.hpp b/include/beman/inplace_vector/inplace_vector.hpp index c3b33be..e591bdd 100644 --- a/include/beman/inplace_vector/inplace_vector.hpp +++ b/include/beman/inplace_vector/inplace_vector.hpp @@ -100,24 +100,24 @@ struct inplace_vector_destruct_base { // [containers.sequences.inplace.vector.cons], construct/copy/destroy constexpr inplace_vector_destruct_base() = default; - inplace_vector_destruct_base( + constexpr inplace_vector_destruct_base( const inplace_vector_destruct_base &other) noexcept(std::is_nothrow_copy_constructible_v) : elems(), size_(other.size_) {} - inplace_vector_destruct_base( + constexpr inplace_vector_destruct_base( const inplace_vector_destruct_base &&other) noexcept(std::is_nothrow_move_constructible_v) - : elems(), size_(other.size()) {} + : elems(), size_(other.size_) {} - inplace_vector_destruct_base & + constexpr inplace_vector_destruct_base & operator=(const inplace_vector_destruct_base &other) noexcept( std::is_nothrow_copy_constructible_v && std::is_nothrow_copy_assignable_v) { size_ = other.size_; } - inplace_vector_destruct_base & + constexpr inplace_vector_destruct_base & operator=(const inplace_vector_destruct_base &&other) noexcept( std::is_nothrow_move_constructible_v && std::is_nothrow_move_assignable_v) { @@ -142,19 +142,18 @@ struct inplace_vector_base : public inplace_vector_destruct_base { // [containers.sequences.inplace.vector.cons], construct/copy/destroy constexpr inplace_vector_base() = default; - inplace_vector_base(const inplace_vector_base &other) noexcept( + constexpr inplace_vector_base(const inplace_vector_base &other) noexcept( std::is_nothrow_copy_constructible_v) - : inplace_vector_destruct_base(other.size) { + : inplace_vector_destruct_base(other.size_) { std::copy(other.begin(), other.end(), begin()); } - inplace_vector_base(inplace_vector_base &&other) noexcept( + constexpr inplace_vector_base(inplace_vector_base &&other) noexcept( Capacity == 0 || std::is_nothrow_move_constructible_v) : inplace_vector_destruct_base(other.size_) { std::copy(other.begin(), other.end(), begin()); - std::destroy(other.begin(), other.end()); - other.size_ = 0; } - inplace_vector_base &operator=(const inplace_vector_base &other) noexcept( + constexpr inplace_vector_base & + operator=(const inplace_vector_base &other) noexcept( std::is_nothrow_copy_constructible_v && std::is_nothrow_copy_assignable_v) { const auto diff = static_cast(other.size() - size()); @@ -175,7 +174,8 @@ struct inplace_vector_base : public inplace_vector_destruct_base { return *this; } - inplace_vector_base &operator=(inplace_vector_base &&other) noexcept( + constexpr inplace_vector_base & + operator=(inplace_vector_base &&other) noexcept( Capacity == 0 || (std::is_nothrow_move_constructible_v && std::is_nothrow_move_assignable_v)) { const auto diff = static_cast(other.size() - size()); @@ -185,13 +185,10 @@ struct inplace_vector_base : public inplace_vector_destruct_base { std::destroy(new_end, end()); // other size is grater than size } else { - std::move(other, other.begin(), other.begin() + size(), begin()); + std::move(other.begin(), other.begin() + size(), begin()); std::move(other.begin() + size(), other.end(), end()); } this->size_ = other.size(); - std::destroy(other.begin(), other.end()); - // reset size to zero - other.change_size(-static_cast(other.size())); return *this; } constexpr inplace_vector_base(const size_type size) diff --git a/tests/beman/inplace_vector/constexpr.test.cpp b/tests/beman/inplace_vector/constexpr.test.cpp index c5a1822..75e6830 100644 --- a/tests/beman/inplace_vector/constexpr.test.cpp +++ b/tests/beman/inplace_vector/constexpr.test.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -148,6 +149,130 @@ static_assert(std::invoke([]() { }), "Basic mutation"); +// [container.reqmts] General container requirements +using X = inplace_vector; + +constexpr bool reqmts_default() { + { + X u; + S_ASSERT(u.empty()); + } + { + X u = X(); + S_ASSERT(u.empty()); + } + + return true; +} + +static_assert(reqmts_default()); + +constexpr bool reqmts_copy() { + constexpr X exp{1, 2, 3}; + + X a{1, 2, 3}; + + { + X u(a); + S_ASSERT(std::ranges::equal(exp, u)); + S_ASSERT(std::ranges::equal(exp, a)); + } + { + X u = a; + S_ASSERT(std::ranges::equal(exp, u)); + S_ASSERT(std::ranges::equal(exp, a)); + } + + return true; +} + +static_assert(reqmts_copy()); + +constexpr bool reqmts_move() { + /* + * TODO: Need to keep in check with revision + * + * Move semantics + * A moved-from inplace_vector is left in a valid but unspecified state + * (option 3 below) unless T is trivially-copyable, in which case the size of + * the inplace_vector does not change (array semantics, option 2 below). That + * is: + * + * inplace_vector a(10); + * inplace_vector b(std::move(a)); + * assert(a.size() == 10); // MAY FAIL + * + * moves a's elements element-wise into b, and afterwards the size of the + * moved-from inplace_vector may have changed. + * + * This prevents code from relying on the size staying the same (and therefore + * being incompatible with changing an inplace_vector type back to vector) + * without incuring the cost of having to clear the inplace_vector. + * + * When T is trivially-copyable, array semantics are used to provide trivial + * move operations. + */ + + { + constexpr X exp{1, 2, 3}; + X mov_from(exp); + X u(std::move(mov_from)); + S_ASSERT(std::ranges::equal(exp, u)); + + static_assert(std::is_trivially_copyable_v); + S_ASSERT(mov_from.size() == exp.size()); + } + { + // Note(river): for later non-trivial type implementation, verify: + // Effects: All existing elements of a are either move assigned to or + // destroyed. + constexpr X origin{1, 2, 3}; + constexpr X exp{1, 2}; + + X a(origin); + X mov_from(exp); + a = std::move(mov_from); + + S_ASSERT(std::ranges::equal(exp, a)); + static_assert(std::is_trivially_copyable_v); + S_ASSERT(mov_from.size() == exp.size()); + } + + return true; +} + +static_assert(reqmts_move()); + +// destructor implicilty tested + +constexpr bool reqmts_itr() { + constexpr X exp{1, 2, 3}; + + { + X b = exp; + auto beg = b.begin(); + auto end = b.end(); + end--; + + S_ASSERT(*b.begin() == 1); + S_ASSERT(*end == 3); + } + + { + X b = exp; + auto beg = b.cbegin(); + auto end = b.cend(); + end--; + + S_ASSERT(*b.begin() == 1); + S_ASSERT(*end == 3); + } + + return true; +} + +static_assert(reqmts_itr()); + int main() { // compile means pass }