diff --git a/.github/workflows/ci_tests.yml b/.github/workflows/ci_tests.yml index a4b5c03..970f129 100644 --- a/.github/workflows/ci_tests.yml +++ b/.github/workflows/ci_tests.yml @@ -53,6 +53,8 @@ jobs: args: "-DCMAKE_CXX_FLAGS=-fsanitize=thread" - description: "ASan" args: "-DCMAKE_CXX_FLAGS='-fsanitize=address -fsanitize=undefined'" + - description: "delete freestanding" + args: "-DBEMAN_INPLACE_VECTOR_FREESTANDING_DELETED=ON" - description: "NoExcep" args: "-DBEMAN_INPLACE_VECTOR_NO_EXCEPTIONS=on" include: diff --git a/CMakeLists.txt b/CMakeLists.txt index e5330c7..38a6347 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,12 +27,29 @@ option( ${PROJECT_IS_TOP_LEVEL} ) +option( + BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED + "Enable freestanding mode. Default: OFF. Values: { ON, OFF }." + OFF +) + option( BEMAN_INPLACE_VECTOR_NO_EXCEPTIONS "Disable exceptions by replacing throw calls with abort. Default: OFF. Values: { ON, OFF }." OFF ) +if( + BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED + AND BEMAN_INPLACE_VECTOR_NO_EXCEPTIONS +) + message( + WARNING + "There's no throwing functions in freestanding implementation," + "disabling exception does not influence implementation." + ) +endif() + configure_file( "${PROJECT_SOURCE_DIR}/include/beman/inplace_vector/config.hpp.in" "${PROJECT_BINARY_DIR}/include/beman/inplace_vector/config.hpp" @@ -52,6 +69,7 @@ target_include_directories( $ $ $ + $ ) # Install the InplaceVector library to the appropriate destination diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 496bc08..4d8fd2e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,6 +1,10 @@ # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -set(ALL_EXAMPLES fibonacci) +set(ALL_EXAMPLES) + +if(!BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED) + list(APPEND ALL_EXAMPLES fibonacci) +endif() message("Examples to be built: ${ALL_EXAMPLES}") diff --git a/include/beman/inplace_vector/config.hpp.in b/include/beman/inplace_vector/config.hpp.in index b551164..0ab65d0 100644 --- a/include/beman/inplace_vector/config.hpp.in +++ b/include/beman/inplace_vector/config.hpp.in @@ -1,6 +1,11 @@ +// include/beman/inplace_vector/config.hpp.in -*-C++-*- +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + #ifndef BEMAN_INPLACE_VECTOR_CONFIG_HPP #define BEMAN_INPLACE_VECTOR_CONFIG_HPP #cmakedefine01 BEMAN_INPLACE_VECTOR_NO_EXCEPTIONS() +#cmakedefine01 BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() + #endif diff --git a/include/beman/inplace_vector/inplace_vector.hpp b/include/beman/inplace_vector/inplace_vector.hpp index da3c45d..7ec4d59 100644 --- a/include/beman/inplace_vector/inplace_vector.hpp +++ b/include/beman/inplace_vector/inplace_vector.hpp @@ -25,6 +25,12 @@ // Artifact from previous implementation, can be used as hints for optimizer #define IV_EXPECT(EXPR) +#if BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() +#define BEMAN_IV_FREESTANDING_DELETE(impl) = delete +#else +#define BEMAN_IV_FREESTANDING_DELETE(impl) impl +#endif + #ifndef BEMAN_IV_THROW_OR_ABORT #if BEMAN_INPLACE_VECTOR_NO_EXCEPTIONS() #include // for abort @@ -271,11 +277,13 @@ struct inplace_vector constexpr size_type size() const noexcept { return storage_size(); } static constexpr size_type max_size() noexcept { return N; } static constexpr size_type capacity() noexcept { return N; } - constexpr void reserve(size_type n) { + + constexpr void reserve(size_type n) BEMAN_IV_FREESTANDING_DELETE({ if (n > N) [[unlikely]] { BEMAN_IV_THROW_OR_ABORT(std::bad_alloc()); } - } + }); + constexpr void shrink_to_fit() {} // element access @@ -363,24 +371,23 @@ struct inplace_vector template constexpr T &emplace_back(Args &&...args) requires(std::constructible_from) - { - if (!try_emplace_back(std::forward(args)...)) [[unlikely]] { + BEMAN_IV_FREESTANDING_DELETE({ + if (!try_emplace_back(std::forward(args)...)) [[unlikely]] BEMAN_IV_THROW_OR_ABORT(std::bad_alloc()); - } return back(); - } + }); constexpr T &push_back(const T &x) requires(std::constructible_from) - { + BEMAN_IV_FREESTANDING_DELETE({ emplace_back(x); return back(); - } + }); constexpr T &push_back(T &&x) requires(std::constructible_from) - { + BEMAN_IV_FREESTANDING_DELETE({ emplace_back(std::forward(x)); return back(); - } + }); constexpr T *try_push_back(const T &x) requires(std::constructible_from) @@ -407,7 +414,7 @@ struct inplace_vector template R> constexpr void append_range(R &&rg) requires(std::constructible_from>) - { + BEMAN_IV_FREESTANDING_DELETE({ if constexpr (std::ranges::sized_range) { if (size() + std::ranges::size(rg) > capacity()) [[unlikely]] { BEMAN_IV_THROW_OR_ABORT(std::bad_alloc()); @@ -419,7 +426,7 @@ struct inplace_vector } emplace_back(std::forward(e)); } - } + }); template R> constexpr std::ranges::borrowed_iterator_t try_append_range(R &&rg) @@ -436,21 +443,21 @@ struct inplace_vector template constexpr iterator emplace(const_iterator position, Args &&...args) requires(std::constructible_from && std::movable) - { + BEMAN_IV_FREESTANDING_DELETE({ assert_iterator_in_range(position); auto b = end(); emplace_back(std::forward(args)...); auto pos = begin() + (position - begin()); std::rotate(pos, b, end()); return pos; - } + }); template constexpr iterator insert(const_iterator position, InputIterator first, InputIterator last) requires(std::constructible_from> && std::movable) - { + BEMAN_IV_FREESTANDING_DELETE({ assert_iterator_in_range(position); if constexpr (std::random_access_iterator) { if (size() + static_cast(std::distance(first, last)) > @@ -464,28 +471,26 @@ struct inplace_vector auto pos = begin() + (position - begin()); std::rotate(pos, b, end()); return pos; - } + }); template R> constexpr iterator insert_range(const_iterator position, R &&rg) requires(std::constructible_from> && std::movable) - { + BEMAN_IV_FREESTANDING_DELETE({ return insert(position, std::begin(rg), std::end(rg)); - } + }); constexpr iterator insert(const_iterator position, std::initializer_list il) requires(std::constructible_from< T, std::ranges::range_reference_t>> && std::movable) - { - return insert_range(position, il); - } + BEMAN_IV_FREESTANDING_DELETE({ return insert_range(position, il); }); constexpr iterator insert(const_iterator position, size_type n, const T &x) requires(std::constructible_from && std::copyable) - { + BEMAN_IV_FREESTANDING_DELETE({ assert_iterator_in_range(position); auto b = end(); for (size_type i = 0; i < n; ++i) @@ -493,56 +498,46 @@ struct inplace_vector auto pos = begin() + (position - begin()); std::rotate(pos, b, end()); return pos; - } + }); constexpr iterator insert(const_iterator position, const T &x) requires(std::constructible_from && std::copyable) - { - return insert(position, 1, x); - } + BEMAN_IV_FREESTANDING_DELETE({ return insert(position, 1, x); }); constexpr iterator insert(const_iterator position, T &&x) requires(std::constructible_from && std::movable) - { - return emplace(position, std::move(x)); - } + BEMAN_IV_FREESTANDING_DELETE({ return emplace(position, std::move(x)); }); constexpr inplace_vector(std::initializer_list il) requires(std::constructible_from< T, std::ranges::range_reference_t>> && std::movable) - { - insert(begin(), il); - } + BEMAN_IV_FREESTANDING_DELETE({ insert(begin(), il); }); constexpr inplace_vector(size_type n, const T &value) requires(std::constructible_from && std::copyable) - { - insert(begin(), n, value); - } + BEMAN_IV_FREESTANDING_DELETE({ insert(begin(), n, value); }); constexpr explicit inplace_vector(size_type n) requires(std::constructible_from && std::default_initializable) - { + BEMAN_IV_FREESTANDING_DELETE({ for (size_type i = 0; i < n; ++i) emplace_back(T{}); - } + }); template // BUGBUG: why not std::ranges::input_iterator? constexpr inplace_vector(InputIterator first, InputIterator last) requires(std::constructible_from> && std::movable) - { - insert(begin(), first, last); - } + BEMAN_IV_FREESTANDING_DELETE({ insert(begin(), first, last); }); template R> constexpr inplace_vector(beman::from_range_t, R &&rg) requires(std::constructible_from> && std::movable) - { + BEMAN_IV_FREESTANDING_DELETE({ insert_range(begin(), std::forward(rg)); - } + }); constexpr iterator erase(const_iterator first, const_iterator last) requires(std::movable) @@ -569,7 +564,7 @@ struct inplace_vector constexpr void resize(size_type sz, const T &c) requires(std::constructible_from && std::copyable) - { + BEMAN_IV_FREESTANDING_DELETE({ if (sz == size()) return; else if (sz > N) [[unlikely]] { @@ -580,10 +575,10 @@ struct inplace_vector unsafe_destroy(begin() + sz, end()); unsafe_set_size(sz); } - } + }); constexpr void resize(size_type sz) requires(std::constructible_from && std::default_initializable) - { + BEMAN_IV_FREESTANDING_DELETE({ if (sz == size()) return; else if (sz > N) [[unlikely]] { @@ -595,20 +590,19 @@ struct inplace_vector unsafe_destroy(begin() + sz, end()); unsafe_set_size(sz); } - } + }); - constexpr reference at(size_type pos) { - if (pos >= size()) [[unlikely]] { - BEMAN_IV_THROW_OR_ABORT(std::out_of_range("inplace_vector::at")); - } - return details::inplace_vector::index(*this, pos); - } - constexpr const_reference at(size_type pos) const { - if (pos >= size()) [[unlikely]] { + constexpr reference at(size_type pos) BEMAN_IV_FREESTANDING_DELETE({ + if (pos >= size()) [[unlikely]] BEMAN_IV_THROW_OR_ABORT(std::out_of_range("inplace_vector::at")); - } return details::inplace_vector::index(*this, pos); - } + }); + constexpr const_reference at(size_type pos) const + BEMAN_IV_FREESTANDING_DELETE({ + if (pos >= size()) [[unlikely]] + BEMAN_IV_THROW_OR_ABORT(std::out_of_range("inplace_vector::at")); + return details::inplace_vector::index(*this, pos); + }); constexpr void pop_back() { IV_EXPECT(size() > 0 && "pop_back from empty inplace_vector!"); @@ -682,10 +676,10 @@ struct inplace_vector requires(std::constructible_from< T, std::ranges::range_reference_t>> && std::movable) - { + BEMAN_IV_FREESTANDING_DELETE({ assign_range(il); return *this; - } + }); constexpr void swap(inplace_vector &x) noexcept(N == 0 || @@ -702,31 +696,31 @@ struct inplace_vector constexpr void assign(InputIterator first, InputIterator last) requires(std::constructible_from> && std::movable) - { + BEMAN_IV_FREESTANDING_DELETE({ clear(); insert(begin(), first, last); - } + }); template R> constexpr void assign_range(R &&rg) requires(std::constructible_from> && std::movable) - { - assign(std::begin(rg), std::end(rg)); - } + BEMAN_IV_FREESTANDING_DELETE({ + assign(std::ranges::begin(rg), std::ranges::end(rg)); + }); constexpr void assign(size_type n, const T &u) requires(std::constructible_from && std::movable) - { + BEMAN_IV_FREESTANDING_DELETE({ clear(); insert(begin(), n, u); - } + }); constexpr void assign(std::initializer_list il) requires(std::constructible_from< T, std::ranges::range_reference_t>> && std::movable) - { + BEMAN_IV_FREESTANDING_DELETE({ clear(); insert_range(begin(), il); - } + }); constexpr friend auto operator<=>(const inplace_vector &x, const inplace_vector &y) @@ -769,5 +763,6 @@ constexpr std::size_t erase_if(inplace_vector &c, Predicate pred) { } // namespace beman #undef IV_EXPECT +#undef BEMAN_IV_FREESTANDING_DELETE #endif // BEMAN_INPLACE_VECTOR_INPLACE_VECTOR_HPP diff --git a/tests/beman/inplace_vector/CMakeLists.txt b/tests/beman/inplace_vector/CMakeLists.txt index 2f93633..5258ef8 100644 --- a/tests/beman/inplace_vector/CMakeLists.txt +++ b/tests/beman/inplace_vector/CMakeLists.txt @@ -5,9 +5,7 @@ # Tests add_executable(beman.inplace_vector.test inplace_vector.test.cpp) - target_link_libraries(beman.inplace_vector.test PRIVATE beman.inplace_vector) - add_test(NAME beman.inplace_vector.test COMMAND beman.inplace_vector.test) # Migrated test from original implementation @@ -38,14 +36,23 @@ endfunction() add_gtest(container_requirements) add_gtest(triviality) add_gtest(compare) -add_gtest(constructors) add_gtest(size_n_data) add_gtest(erasure) add_gtest(modifiers) +if(BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED) + add_gtest(freestanding) +else() + add_gtest(container_requirements_fs) + add_gtest(constructors_fs) + add_gtest(size_n_data_fs) + add_gtest(modifiers_fs) +endif() + # only add noexception tests if NO_EXCEPTIONS option is set and compiler supports -fno-exceptions if( BEMAN_INPLACE_VECTOR_NO_EXCEPTIONS + AND (NOT BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED) AND ( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" diff --git a/tests/beman/inplace_vector/compare.test.cpp b/tests/beman/inplace_vector/compare.test.cpp index cdaa458..d0c657d 100644 --- a/tests/beman/inplace_vector/compare.test.cpp +++ b/tests/beman/inplace_vector/compare.test.cpp @@ -27,6 +27,14 @@ template struct vec_list { T lesser_bigger; // lesser number of elements but bigger values }; +template +T Vec(std::initializer_list list) { + T vec; + for (auto &ele : list) + vec.unchecked_push_back(ele); + return vec; +} + template static void runtests(vec_list &list) { static_assert(std::three_way_comparable || lessthan_comparable); @@ -86,32 +94,34 @@ template static void runtests(vec_list &list) { }; TEST(Compare, threeway_int) { - vec_list> list{ + using IV = inplace_vector; + vec_list list{ .empty{}, - .base{1, 2, 3}, - .copy{1, 2, 3}, - .greater{4, 5, 6}, - .lesser{0, 0, 0}, - .bigger{1, 2, 3, 0}, - .smaller{1, 2}, - .greater_smaller{2, 2}, - .lesser_bigger{0, 2, 3, 4}, + .base{Vec({1, 2, 3})}, + .copy{Vec({1, 2, 3})}, + .greater{Vec({4, 5, 6})}, + .lesser{Vec({0, 0, 0})}, + .bigger{Vec({1, 2, 3, 0})}, + .smaller{Vec({1, 2})}, + .greater_smaller{Vec({2, 2})}, + .lesser_bigger{Vec({0, 2, 3, 4})}, }; runtests(list); } TEST(Compare, threeway_float) { - vec_list> list{ + using IV = inplace_vector; + vec_list list{ .empty{}, - .base{1.0f, 2.0f, 3.0f}, - .copy{1.0f, 2.0f, 3.0f}, - .greater{4.0f, 5.0f, 6.0f}, - .lesser{0.0f, 0.0f, 0.0f}, - .bigger{1.0f, 2.0f, 3.0f, 0.0f}, - .smaller{1.0f, 2.0f}, - .greater_smaller{2.0f, 2.0f}, - .lesser_bigger{0.0f, 2.0f, 3.0f, 4.0f}, + .base{Vec({1.0f, 2.0f, 3.0f})}, + .copy{Vec({1.0f, 2.0f, 3.0f})}, + .greater{Vec({4.0f, 5.0f, 6.0f})}, + .lesser{Vec({0.0f, 0.0f, 0.0f})}, + .bigger{Vec({1.0f, 2.0f, 3.0f, 0.0f})}, + .smaller{Vec({1.0f, 2.0f})}, + .greater_smaller{Vec({2.0f, 2.0f})}, + .lesser_bigger{Vec({0.0f, 2.0f, 3.0f, 4.0f})}, }; runtests(list); @@ -125,8 +135,8 @@ TEST(Compare, threeway_float) { EXPECT_FALSE(std::nanf("") >= std::nanf("")); EXPECT_FALSE(std::nanf("") <= std::nanf("")); - inplace_vector vnan{std::nanf("")}; - inplace_vector vnan2{std::nanf("")}; + auto vnan = Vec({std::nanf("")}); + auto vnan2 = Vec({std::nanf("")}); EXPECT_EQ(vnan <=> vnan2, std::partial_ordering::unordered); EXPECT_FALSE(vnan == vnan2); @@ -148,17 +158,16 @@ TEST(Compare, threeway_comparable1) { static_assert(std::three_way_comparable>); static_assert(has_threeway>); - vec_list> list{ - .empty{}, - .base{{1, 2}, {3, 4}}, - .copy{{1, 2}, {3, 4}}, - .greater{{5, 6}, {7, 8}}, - .lesser{{0, 0}, {0, 0}}, - .bigger{{1, 2}, {3, 4}, {5, 6}}, - .smaller{{1, 2}}, - .greater_smaller{{2, 2}, {3, 3}}, - .lesser_bigger{{0, 2}, {3, 3}, {4, 4}}, - }; + using IV = inplace_vector; + vec_list list{.empty{}, + .base{Vec({{1, 2}, {3, 4}})}, + .copy{Vec({{1, 2}, {3, 4}})}, + .greater{Vec({{5, 6}, {7, 8}})}, + .lesser{Vec({{0, 0}, {0, 0}})}, + .bigger{Vec({{1, 2}, {3, 4}, {5, 6}})}, + .smaller{Vec({{1, 2}})}, + .greater_smaller{Vec({{2, 2}, {3, 3}})}, + .lesser_bigger{Vec({{0, 2}, {3, 3}, {4, 4}})}}; runtests(list); } @@ -180,17 +189,16 @@ TEST(Compare, threeway_comparable2) { static_assert(std::three_way_comparable>); static_assert(has_threeway>); - vec_list> list{ - .empty{}, - .base{{1, 2}, {3, 4}}, - .copy{{1, 2}, {3, 4}}, - .greater{{5, 6}, {7, 8}}, - .lesser{{0, 0}, {0, 0}}, - .bigger{{1, 2}, {3, 4}, {5, 6}}, - .smaller{{1, 2}}, - .greater_smaller{{2, 2}, {3, 3}}, - .lesser_bigger{{0, 2}, {3, 3}, {4, 4}}, - }; + using IV = inplace_vector; + vec_list list{.empty{}, + .base{Vec({{1, 2}, {3, 4}})}, + .copy{Vec({{1, 2}, {3, 4}})}, + .greater{Vec({{5, 6}, {7, 8}})}, + .lesser{Vec({{0, 0}, {0, 0}})}, + .bigger{Vec({{1, 2}, {3, 4}, {5, 6}})}, + .smaller{Vec({{1, 2}})}, + .greater_smaller{Vec({{2, 2}, {3, 3}})}, + .lesser_bigger{Vec({{0, 2}, {3, 3}, {4, 4}})}}; runtests(list); } @@ -203,19 +211,16 @@ TEST(Compare, threeway_strong_ordering) { operator<=>(const weaktype &other) const = default; }; - using T = weaktype; - - vec_list> list{ - .empty{}, - .base{T{1}, T{2}, T{3}}, - .copy{T{1}, T{2}, T{3}}, - .greater{T{4}, T{5}, T{6}}, - .lesser{T{0}, T{0}, T{0}}, - .bigger{T{1}, T{2}, T{3}, T{0}}, - .smaller{T{1}, T{2}}, - .greater_smaller{T{2}, T{2}}, - .lesser_bigger{T{0}, T{2}, T{3}, T{4}}, - }; + using IV = inplace_vector; + vec_list list{.empty{}, + .base{Vec({{1}, {2}, {3}})}, + .copy{Vec({{1}, {2}, {3}})}, + .greater{Vec({{4}, {5}, {6}})}, + .lesser{Vec({{0}, {0}, {0}})}, + .bigger{Vec({{1}, {2}, {3}, {0}})}, + .smaller{Vec({{1}, {2}})}, + .greater_smaller{Vec({{2}, {2}})}, + .lesser_bigger{Vec({{0}, {2}, {3}, {4}})}}; runtests(list); } @@ -228,19 +233,16 @@ TEST(Compare, threeway_weak_ordering) { operator<=>(const weaktype &other) const = default; }; - using T = weaktype; - - vec_list> list{ - .empty{}, - .base{T{1}, T{2}, T{3}}, - .copy{T{1}, T{2}, T{3}}, - .greater{T{4}, T{5}, T{6}}, - .lesser{T{0}, T{0}, T{0}}, - .bigger{T{1}, T{2}, T{3}, T{0}}, - .smaller{T{1}, T{2}}, - .greater_smaller{T{2}, T{2}}, - .lesser_bigger{T{0}, T{2}, T{3}, T{4}}, - }; + using IV = inplace_vector; + vec_list list{.empty{}, + .base{Vec({{1}, {2}, {3}})}, + .copy{Vec({{1}, {2}, {3}})}, + .greater{Vec({{4}, {5}, {6}})}, + .lesser{Vec({{0}, {0}, {0}})}, + .bigger{Vec({{1}, {2}, {3}, {0}})}, + .smaller{Vec({{1}, {2}})}, + .greater_smaller{Vec({{2}, {2}})}, + .lesser_bigger{Vec({{0}, {2}, {3}, {4}})}}; runtests(list); } @@ -263,18 +265,16 @@ TEST(Compare, threeway_partial_ordering) { }; using T = custom; - - vec_list> list{ - .empty{}, - .base{T{1}, T{2}, T{3}}, - .copy{T{1}, T{2}, T{3}}, - .greater{T{4}, T{5}, T{6}}, - .lesser{T{0}, T{0}, T{0}}, - .bigger{T{1}, T{2}, T{3}, T{0}}, - .smaller{T{1}, T{2}}, - .greater_smaller{T{2}, T{2}}, - .lesser_bigger{T{0}, T{2}, T{3}, T{4}}, - }; + using IV = inplace_vector; + vec_list list{.empty{}, + .base{Vec({{1}, {2}, {3}})}, + .copy{Vec({{1}, {2}, {3}})}, + .greater{Vec({{4}, {5}, {6}})}, + .lesser{Vec({{0}, {0}, {0}})}, + .bigger{Vec({{1}, {2}, {3}, {0}})}, + .smaller{Vec({{1}, {2}})}, + .greater_smaller{Vec({{2}, {2}})}, + .lesser_bigger{Vec({{0}, {2}, {3}, {4}})}}; runtests(list); @@ -282,8 +282,8 @@ TEST(Compare, threeway_partial_ordering) { T t2 = t1; EXPECT_EQ(t1 <=> t2, std::partial_ordering::unordered); - inplace_vector v1{t1}; - inplace_vector v2{t2}; + auto v1 = Vec({t1}); + auto v2 = Vec({t2}); EXPECT_EQ(v1 <=> v2, std::partial_ordering::unordered); EXPECT_FALSE(v1 == v2); diff --git a/tests/beman/inplace_vector/constexpr.test.cpp b/tests/beman/inplace_vector/constexpr.test.cpp index 2d44642..cbba780 100644 --- a/tests/beman/inplace_vector/constexpr.test.cpp +++ b/tests/beman/inplace_vector/constexpr.test.cpp @@ -49,6 +49,19 @@ static_assert(!has_constexpr_support, 50>>); }), \ "##NAME"); +template +constexpr IV vec_of(std::initializer_list &&il) { +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() + return IV(il); +#else + IV res; + for (auto &ele : il) { + res.unchecked_push_back(ele); + } + return res; +#endif +} + template constexpr void test_constructors() { using T = IV::value_type; @@ -58,6 +71,7 @@ template constexpr void test_constructors() { { IV v; } +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() { IV v(10); } @@ -71,15 +85,16 @@ template constexpr void test_constructors() { IV v(beman::from_range_t{}, arr); } { - IV other{0, 1}; - IV copy(other); + IV v({0, 1}); } +#endif { - IV other{0, 1}; - IV copy(std::move(other)); + auto other = vec_of({0, 1}); + IV copy(other); } { - IV v({0, 1}); + auto other = vec_of({0, 1}); + IV copy(std::move(other)); } } TEST(test_constructors); @@ -88,17 +103,21 @@ template constexpr void test_op_eq() { using T = IV::value_type; { - IV v, other{0, 1}; + IV v; + auto other = vec_of({0, 1}); v = other; } { - IV v, other{0, 1}; + IV v; + auto other = vec_of({0, 1}); v = std::move(other); } +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() { IV v; v = {0, 1}; } +#endif } TEST(test_op_eq); @@ -108,6 +127,7 @@ template constexpr void test_assignment() { std::array arr; arr.fill(T(20)); +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() { IV v; v.assign(arr.begin(), arr.end()); @@ -124,27 +144,25 @@ template constexpr void test_assignment() { IV v; v.assign({0, 1, 2}); } +#endif } TEST(test_assignment); template constexpr void test_iterator_access() { - using T = IV::value_type; - - { - IV v{0, 1}; - (void)v.begin(); - (void)v.end(); - (void)v.rbegin(); - (void)v.rend(); - (void)v.cbegin(); - (void)v.cend(); - (void)v.crbegin(); - (void)v.crend(); - } + auto v = vec_of({0, 1}); + (void)v.begin(); + (void)v.end(); + (void)v.rbegin(); + (void)v.rend(); + (void)v.cbegin(); + (void)v.cend(); + (void)v.crbegin(); + (void)v.crend(); } TEST(test_iterator_access); template constexpr void test_size_capacity() { +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() using T = IV::value_type; { @@ -166,22 +184,27 @@ template constexpr void test_size_capacity() { v.reserve(5); v.shrink_to_fit(); } +#endif } TEST(test_size_capacity); template constexpr void test_element_access() { { - IV v{0, 1}; + auto v = vec_of({0, 1}); (void)v[0]; +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() (void)v.at(0); +#endif (void)v.front(); (void)v.back(); } { - const IV v{0, 1}; + auto v = vec_of({0, 1}); (void)v[0]; +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() (void)v.at(0); +#endif (void)v.front(); (void)v.back(); } @@ -190,11 +213,11 @@ TEST(test_element_access); template constexpr void test_data_access() { { - IV v{0, 1}; + auto v = vec_of({0, 1}); v.data(); } { - const IV v{0, 1}; + auto v = vec_of({0, 1}); v.data(); } } @@ -206,6 +229,7 @@ template constexpr void test_modifiers() { std::array arr; arr.fill(T(20)); +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() { IV v; v.emplace_back(20); @@ -214,6 +238,7 @@ template constexpr void test_modifiers() { v.append_range(arr); v.pop_back(); } +#endif { IV v; @@ -230,6 +255,7 @@ template constexpr void test_modifiers() { v.unchecked_push_back(T(20)); } +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() { IV v{0, 1}; v.emplace(v.begin(), 20); @@ -242,21 +268,24 @@ template constexpr void test_modifiers() { v.erase(v.begin()); v.erase(v.begin(), v.begin() + 2); } +#endif { - IV v, other{0, 1}; + IV v; + auto other = vec_of({0, 1}); v.swap(other); } { - IV v{0, 1}; + auto v = vec_of({0, 1}); v.clear(); } } TEST(test_modifiers); template constexpr void test_op_comp() { - IV v{0, 1, 2}, other{3, 4}; + auto v = vec_of({0, 1, 2}); + auto other = vec_of({3, 4}); (void)(v == v); (void)(v == other); @@ -266,7 +295,7 @@ template constexpr void test_op_comp() { TEST(test_op_comp); template constexpr void test_erase() { - IV v{0, 1, 2, 3, 3, 5}; + auto v = vec_of({0, 1, 2, 3, 3, 5}); (void)beman::erase(v, 3); (void)beman::erase_if(v, [](auto v) { return v < 3; }); } @@ -304,18 +333,22 @@ template constexpr void speical_test_empty() { { IV v; } +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() { IV v(0, T{50}); } +#endif { IV a, b; a = b; a = IV(); } +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() { IV v; v.assign(0, T{50}); } +#endif { IV v; (void)v.begin(); @@ -333,9 +366,11 @@ template constexpr void speical_test_empty() { (void)v.size(); (void)v.max_size(); (void)v.capacity(); +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() v.resize(0); v.resize(0, T{40}); v.reserve(0); +#endif v.shrink_to_fit(); } { @@ -360,4 +395,5 @@ TEST_EMPTY(speical_test_empty); int main() { // compile means passing + return 0; } diff --git a/tests/beman/inplace_vector/constructors.test.cpp b/tests/beman/inplace_vector/constructors_fs.test.cpp similarity index 100% rename from tests/beman/inplace_vector/constructors.test.cpp rename to tests/beman/inplace_vector/constructors_fs.test.cpp diff --git a/tests/beman/inplace_vector/container_requirements.test.cpp b/tests/beman/inplace_vector/container_requirements.test.cpp index aaa9c1b..ff5f3d4 100644 --- a/tests/beman/inplace_vector/container_requirements.test.cpp +++ b/tests/beman/inplace_vector/container_requirements.test.cpp @@ -177,7 +177,7 @@ TYPED_TEST(ContainerRequirements, CopyAssignment) { // Complexity: Linear. X const v(TestFixture::unique(X::max_size() / 2)); for (typename X::size_type n = 0; n <= X::max_size(); ++n) { - X t(n); + X t = TestFixture::vec_of(n); t = v; EXPECT_TRUE((std::is_same_v)); EXPECT_EQ(t, v); @@ -202,7 +202,7 @@ TYPED_TEST(ContainerRequirements, MoveAssignment) { if constexpr (counts_objects_v) { T::num_objects = 0; } - X t(n); + X t = TestFixture::vec_of(n); if constexpr (counts_objects_v) { ASSERT_EQ(T::num_objects, t.size()); } @@ -228,7 +228,8 @@ TYPED_TEST(ContainerRequirements, Destructor) { T::num_objects = 0; } alignas(X) std::byte storage[sizeof(X)]; - X *pa = new (static_cast(storage)) X(X::max_size()); + X *pa = new (static_cast(storage)) X; + *pa = TestFixture::unique(); X &a = *pa; if constexpr (counts_objects_v) { ASSERT_EQ(T::num_objects, X::max_size()); @@ -254,8 +255,8 @@ TYPED_TEST(ContainerRequirements, Begin) { // Complexity: Constant. for (typename X::size_type n = 0; n <= X::max_size(); ++n) { - X b(n); - X const cb(n); + X b = TestFixture::vec_of(n); + X const cb = TestFixture::vec_of(n); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE( (std::is_same_v)); @@ -284,8 +285,8 @@ TYPED_TEST(ContainerRequirements, End) { // Complexity: Constant. for (typename X::size_type n = 0; n <= X::max_size(); ++n) { - X b(n); - X const cb(n); + X b = TestFixture::vec_of(n); + X const cb = TestFixture::vec_of(n); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE( (std::is_same_v)); @@ -350,9 +351,10 @@ TYPED_TEST(ContainerRequirements, Equality) { : X{}; // { 0, 1, ... } values[1] = values[0]; if (values[1].size() < X::max_size()) { - values[1].push_back(TestFixture::unique(1)[0]); + values[1].unchecked_push_back(TestFixture::unique(1)[0]); } // { 0, 1, 2, ... } - values[2] = X::max_size() > 0 ? X(X::max_size() - 1) : X{}; // { 0, 0, ... } + values[2] = X::max_size() > 0 ? TestFixture::vec_of(X::max_size() - 1) + : X{}; // { 0, 0, ... } for (X const &c : values) { EXPECT_TRUE(c == c); for (X const &b : values) { @@ -379,7 +381,7 @@ TYPED_TEST(ContainerRequirements, Swap) { // Effects: Equivalent to t.swap(s). X const t_proto(TestFixture::unique()); - X const s_proto(X::max_size()); + X const s_proto = TestFixture::vec_of(X::max_size()); X t(t_proto); X s(s_proto); @@ -407,7 +409,7 @@ TYPED_TEST(ContainerRequirements, Size) { // defined by the rules of constructors, inserts, and erases. for (typename X::size_type n = 0; n <= X::max_size(); ++n) { - X c(n); + X c = TestFixture::vec_of(n); EXPECT_TRUE((std::is_same_v)); EXPECT_EQ(c.size(), std::distance(c.begin(), c.end())); } @@ -422,7 +424,7 @@ TYPED_TEST(ContainerRequirements, MaxSize) { // Result: size_type. // Returns: distance(begin(), end()) for the largest possible container. // Complexity: Constant. - X c(N); + X c = TestFixture::vec_of(N); EXPECT_TRUE((std::is_same_v)); EXPECT_EQ(c.max_size(), std::distance(c.begin(), c.end())); // How to test complexity? @@ -438,7 +440,7 @@ TYPED_TEST(ContainerRequirements, Empty) { // Remarks: If the container is empty, then c.empty() is true.} for (typename X::size_type n = 0; n <= X::max_size(); ++n) { - X c(n); + X c = TestFixture::vec_of(n); EXPECT_TRUE((std::is_same_v)); EXPECT_EQ(c.empty(), c.begin() == c.end()); } @@ -471,7 +473,7 @@ TYPED_TEST(ContainerRequirements, NothrowPopBack) { // pop_back() has a narrow contract, therefore we cannot check noexcept(). for (typename X::size_type n = 0; n <= X::max_size(); ++n) { - X c(n); + X c = TestFixture::vec_of(n); if (n > 0) { EXPECT_NO_THROW(c.pop_back()); } @@ -540,8 +542,8 @@ TYPED_TEST(ReversibleContainerRequirements, RBegin) { // Complexity: Constant. for (typename X::size_type n = 0; n <= X::max_size(); ++n) { - X a(n); - X const ca(n); + X a = TestFixture::vec_of(n); + X const ca = TestFixture::vec_of(n); EXPECT_TRUE( (std::is_same_v)); EXPECT_TRUE((std::is_same_v)); EXPECT_TRUE((std::is_same_vunique(); - - const auto correct = this->unique(); - - device.assign(correct.begin(), correct.end()); - EXPECT_EQ(device, correct); - - std::array ref{}; - SAFE_EXPECT_THROW(device.assign(ref.begin(), ref.end()), std::bad_alloc); - } - - { - IV device; - device.assign(InputIterator{0}, InputIterator{IV::max_size()}); - EXPECT_EQ(device.size(), IV::max_size()); - // Each iterator in the range [i, j) is dereferenced exactly once. - if (!device.empty()) { - EXPECT_EQ(device.back(), T{static_cast(IV::max_size() - 1)}); - } - - // [containers.sequences.inplace.vector.overview] - // 5. Any member function of inplace_vector that would cause the size - // to exceed N throws an exception of type bad_alloc. - SAFE_EXPECT_THROW( - device.assign(InputIterator{0}, InputIterator{IV::max_size() + 1}), - std::bad_alloc); - } -} - // a.assign_range(rg) -// Result: void -// Mandates: assignable_from> is modeled. -// Preconditions: T is Cpp17EmplaceConstructible into X from -// *ranges​::​begin(rg). For vector, if R models neither -// ranges​::​sized_range nor ranges​::​forward_range, T is also -// Cpp17MoveInsertable into X. rg and a do not overlap. Effects: Replaces -// elements in a with a copy of each element in rg. Invalidates all references, -// pointers, and iterators referring to the elements of a. For vector and deque, -// also invalidates the past-the-end iterator. Each iterator in the range rg is -// dereferenced exactly once. - -TYPED_TEST(SequenceContainerRequirements, AssignRange) { - using IV = TestFixture::IV; - using T = TestFixture::T; - - auto device = this->unique(); - auto correct = this->unique(); - - device.assign_range(correct); - EXPECT_EQ(device, correct); - - std::array ref; - std::copy(correct.begin(), correct.end(), ref.begin()); - ref.back() = T{5}; - SAFE_EXPECT_THROW(device.assign_range(ref), std::bad_alloc); -} - // a.assign(il) -// Effects: Equivalent to a.assign(il.begin(), il.end()). - -TYPED_TEST(SequenceContainerRequirements, AssignFuncInitializerList) { - using IV = TestFixture::IV; - using T = TestFixture::T; - - auto device = this->unique(); - - if (device.capacity() == 0) { - SAFE_EXPECT_THROW(device.assign({T{50}}), std::bad_alloc); - return; - } - - device.assign({T{50}}); - EXPECT_EQ(device, IV{T{50}}); -} - // a.assign(n, t) -// Result: void -// Preconditions: T is Cpp17CopyInsertable into X and Cpp17CopyAssignable. t is -// not a reference into a. -// Effects: Replaces elements in a with n copies of t. -// Invalidates all references, pointers and iterators referring to the elements -// of a. For vector and deque, also invalidates the past-the-end iterator. For -// every sequence container defined in this Clause and in [strings]: -// -// If the constructor -// template -// X(InputIterator first, InputIterator last, -// const allocator_type& alloc = allocator_type()); -// -// is called with a type InputIterator that does not qualify as an input -// iterator, then the constructor shall not participate in overload resolution. -// -// If the member functions of the forms: -// template -// return-type F(const_iterator p, -// InputIterator first, InputIterator last); // such as -// insert -// -// template -// return-type F(InputIterator first, InputIterator last); // such as -// append, assign -// -// template -// return-type F(const_iterator i1, const_iterator i2, -// InputIterator first, InputIterator last); // such as -// replace -// -// are called with a type InputIterator that does not qualify as an input -// iterator, then these functions shall not participate in overload resolution. -// A deduction guide for a sequence container shall not participate in overload -// resolution if it has an InputIterator template parameter and a type that does -// not qualify as an input iterator is deduced for that parameter, or if it has -// an Allocator template parameter and a type that does not qualify as an -// allocator is deduced for that parameter. The following operations are -// provided for some types of sequence containers but not others. Operations -// other than prepend_range and append_range are implemented so as to take -// amortized constant time. - -TYPED_TEST(SequenceContainerRequirements, AssignMulti) { - using IV = TestFixture::IV; - using T = TestFixture::T; - - auto device = this->unique(); - device.assign(0, T{6312}); - - EXPECT_EQ(device, IV()); - - if (device.capacity() > 0) { - device.assign(1, T{6312}); - - EXPECT_EQ(device, IV{T{6312}}); - - device.assign(device.capacity(), T{5972}); - EXPECT_EQ(device, IV(IV::capacity(), T{5972})); - } - - device.clear(); - SAFE_EXPECT_THROW(device.assign(device.capacity() + 1, T{12}), - std::bad_alloc); -} // a.front() // Result: reference; const_reference for constant a. @@ -1003,22 +809,7 @@ TYPED_TEST(SequenceContainerRequirements, ElementAccess) { EXPECT_EQ(device[i], *(device.begin() + i)); } +// These functions are marked as freestand delete. // a.at(n) -// Result: reference; const_reference for constant a -// Returns: *(a.begin() + n) -// Throws: out_of_range if n >= a.size(). - -TYPED_TEST(SequenceContainerRequirements, ElementAccessAt) { - using IV = TestFixture::IV; - using T = TestFixture::T; - - auto device = this->unique(); - - for (auto i = 0ul; i < device.size(); ++i) { - EXPECT_EQ(device.at(i), *(device.begin() + i)); - } - - SAFE_EXPECT_THROW(device.at(IV::capacity()), std::out_of_range); -} }; // namespace diff --git a/tests/beman/inplace_vector/container_requirements_fs.test.cpp b/tests/beman/inplace_vector/container_requirements_fs.test.cpp new file mode 100644 index 0000000..3473257 --- /dev/null +++ b/tests/beman/inplace_vector/container_requirements_fs.test.cpp @@ -0,0 +1,253 @@ +#include "gtest/gtest.h" +#include +#include +#include +#include + +#include "gtest_setup.hpp" + +namespace { + +// [sequence.reqmts] +template +class SequenceContainerRequirements : public IVBasicTest {}; +TYPED_TEST_SUITE(SequenceContainerRequirements, IVAllTypes); + +// X(il) +// Effects: Equivalent to X(il.begin(), il.end()). + +TYPED_TEST(SequenceContainerRequirements, ConstructorInitializerList) { + using IV = TestFixture::IV; + using T = TestFixture::T; + + if (IV::capacity() == 0) { + SAFE_EXPECT_THROW(IV({T{20}}), std::bad_alloc); + return; + } + + IV device({T{20}}); + + IV correct; + correct.emplace_back(20); + EXPECT_EQ(device, correct); + + if (IV::capacity() == 1) + return; + + device = IV({T{20}, T{21}}); + correct.emplace_back(21); + + EXPECT_EQ(device, correct); +} + +// a = il +// Result: X&. +// Preconditions: T is Cpp17CopyInsertable into X and Cpp17CopyAssignable. +// Effects: Assigns the range [il.begin(), il.end()) into a. All existing +// elements of a are either assigned to or destroyed. Returns: *this. + +TYPED_TEST(SequenceContainerRequirements, AssignInitializerList) { + using IV = TestFixture::IV; + using T = TestFixture::T; + + if (IV::capacity() == 0) { + IV device; + SAFE_EXPECT_THROW(device = {T{52}}, std::bad_alloc); + return; + } + + IV device; + device = {T{20}}; + EXPECT_EQ(device, IV{T{20}}); +} + +// a.assign(i, j) +// Result: void +// Preconditions: T is Cpp17EmplaceConstructible into X from *i and assignable +// from *i. For vector, if the iterator does not meet the forward iterator +// requirements ([forward.iterators]), T is also Cpp17MoveInsertable into X. +// Neither i nor j are iterators into a. +// Effects: Replaces elements in a with a copy of [i, j). Invalidates all +// references, pointers and iterators referring to the elements of a. For vector +// and deque, also invalidates the past-the-end iterator. Each iterator in the +// range [i, j) is dereferenced exactly once. + +TYPED_TEST(SequenceContainerRequirements, AssignIterRange) { + using IV = TestFixture::IV; + using T = TestFixture::T; + using InputIterator = TestFixture::InputIterator; + + { + auto device = this->unique(); + + const auto correct = this->unique(); + + device.assign(correct.begin(), correct.end()); + EXPECT_EQ(device, correct); + + std::array ref{}; + SAFE_EXPECT_THROW(device.assign(ref.begin(), ref.end()), std::bad_alloc); + } + + { + IV device; + device.assign(InputIterator{0}, InputIterator{IV::max_size()}); + EXPECT_EQ(device.size(), IV::max_size()); + // Each iterator in the range [i, j) is dereferenced exactly once. + if (!device.empty()) { + EXPECT_EQ(device.back(), T{static_cast(IV::max_size() - 1)}); + } + + // [containers.sequences.inplace.vector.overview] + // 5. Any member function of inplace_vector that would cause the size + // to exceed N throws an exception of type bad_alloc. + SAFE_EXPECT_THROW( + device.assign(InputIterator{0}, InputIterator{IV::max_size() + 1}), + std::bad_alloc); + } +} + +// a.assign_range(rg) +// Result: void +// Mandates: assignable_from> is modeled. +// Preconditions: T is Cpp17EmplaceConstructible into X from +// *ranges​::​begin(rg). For vector, if R models neither +// ranges​::​sized_range nor ranges​::​forward_range, T is also +// Cpp17MoveInsertable into X. rg and a do not overlap. Effects: Replaces +// elements in a with a copy of each element in rg. Invalidates all references, +// pointers, and iterators referring to the elements of a. For vector and deque, +// also invalidates the past-the-end iterator. Each iterator in the range rg is +// dereferenced exactly once. + +TYPED_TEST(SequenceContainerRequirements, AssignRange) { + using IV = TestFixture::IV; + using T = TestFixture::T; + + auto device = this->unique(); + auto correct = this->unique(); + + device.assign_range(correct); + EXPECT_EQ(device, correct); + + std::array ref; + std::copy(correct.begin(), correct.end(), ref.begin()); + ref.back() = T{5}; + SAFE_EXPECT_THROW(device.assign_range(ref), std::bad_alloc); +} + +// a.assign(il) +// Effects: Equivalent to a.assign(il.begin(), il.end()). + +TYPED_TEST(SequenceContainerRequirements, AssignFuncInitializerList) { + using IV = TestFixture::IV; + using T = TestFixture::T; + + auto device = this->unique(); + + if (device.capacity() == 0) { + SAFE_EXPECT_THROW(device.assign({T{50}}), std::bad_alloc); + return; + } + + device.assign({T{50}}); + EXPECT_EQ(device, IV{T{50}}); +} + +// a.assign(n, t) +// Result: void +// Preconditions: T is Cpp17CopyInsertable into X and Cpp17CopyAssignable. t is +// not a reference into a. +// Effects: Replaces elements in a with n copies of t. +// Invalidates all references, pointers and iterators referring to the elements +// of a. For vector and deque, also invalidates the past-the-end iterator. For +// every sequence container defined in this Clause and in [strings]: +// +// If the constructor +// template +// X(InputIterator first, InputIterator last, +// const allocator_type& alloc = allocator_type()); +// +// is called with a type InputIterator that does not qualify as an input +// iterator, then the constructor shall not participate in overload resolution. +// +// If the member functions of the forms: +// template +// return-type F(const_iterator p, +// InputIterator first, InputIterator last); // such as +// insert +// +// template +// return-type F(InputIterator first, InputIterator last); // such as +// append, assign +// +// template +// return-type F(const_iterator i1, const_iterator i2, +// InputIterator first, InputIterator last); // such as +// replace +// +// are called with a type InputIterator that does not qualify as an input +// iterator, then these functions shall not participate in overload resolution. +// A deduction guide for a sequence container shall not participate in overload +// resolution if it has an InputIterator template parameter and a type that does +// not qualify as an input iterator is deduced for that parameter, or if it has +// an Allocator template parameter and a type that does not qualify as an +// allocator is deduced for that parameter. The following operations are +// provided for some types of sequence containers but not others. Operations +// other than prepend_range and append_range are implemented so as to take +// amortized constant time. + +TYPED_TEST(SequenceContainerRequirements, AssignMulti) { + using IV = TestFixture::IV; + using T = TestFixture::T; + + auto device = this->unique(); + device.assign(0, T{6312}); + + EXPECT_EQ(device, IV()); + + if (device.capacity() > 0) { + device.assign(1, T{6312}); + + EXPECT_EQ(device, IV{T{6312}}); + + device.assign(device.capacity(), T{5972}); + EXPECT_EQ(device, IV(IV::capacity(), T{5972})); + } + + device.clear(); + SAFE_EXPECT_THROW(device.assign(device.capacity() + 1, T{12}), + std::bad_alloc); +} + +// a.at(n) +// Result: reference; const_reference for constant a +// Returns: *(a.begin() + n) +// Throws: out_of_range if n >= a.size(). + +TYPED_TEST(SequenceContainerRequirements, ElementAccessAt) { + using IV = TestFixture::IV; + using T = TestFixture::T; + + auto device = this->unique(); + + for (auto i = 0ul; i < device.size(); ++i) { + EXPECT_EQ(device.at(i), *(device.begin() + i)); + } + + SAFE_EXPECT_THROW(device.at(IV::capacity()), std::out_of_range); +} + +TYPED_TEST(SequenceContainerRequirements, ElementAccessAtConst) { + using IV = TestFixture::IV; + using T = TestFixture::T; + + const auto device = this->unique(); + + for (auto i = 0ul; i < device.size(); ++i) { + EXPECT_EQ(device.at(i), *(device.begin() + i)); + } + + SAFE_EXPECT_THROW(device.at(IV::capacity()), std::out_of_range); +} + +}; // namespace diff --git a/tests/beman/inplace_vector/erasure.test.cpp b/tests/beman/inplace_vector/erasure.test.cpp index d446458..b98641d 100644 --- a/tests/beman/inplace_vector/erasure.test.cpp +++ b/tests/beman/inplace_vector/erasure.test.cpp @@ -30,9 +30,9 @@ TYPED_TEST(Erasure, ByValue) { auto uniques = this->unique(device.capacity() / 2); for (auto i = 0ul; i < uniques.size(); ++i) { - device.push_back(uniques[i]); + device.unchecked_push_back(uniques[i]); if (device.size() != device.capacity()) - device.push_back(duplicates); + device.unchecked_push_back(duplicates); } beman::erase(device, duplicates); @@ -57,7 +57,7 @@ TYPED_TEST(Erasure, ByPred) { return; for (auto i = 0; i < static_cast(device.capacity()); ++i) - device.push_back(T{i}); + device.unchecked_push_back(T{i}); beman::erase_if(device, [&](auto &v) { return v.value > (device.capacity() / 2); }); diff --git a/tests/beman/inplace_vector/freestanding.test.cpp b/tests/beman/inplace_vector/freestanding.test.cpp new file mode 100644 index 0000000..b59e2b3 --- /dev/null +++ b/tests/beman/inplace_vector/freestanding.test.cpp @@ -0,0 +1,34 @@ +#include +#include + +#include "gtest_setup.hpp" + +namespace { + +template class Freestanding : public IVBasicTest {}; +TYPED_TEST_SUITE(Freestanding, IVAllTypes); + +TYPED_TEST(Freestanding, alltypes) { + using IV = TestFixture::IV; + using T = TestFixture::T; + using size_type = IV::size_type; + + IV vec; + for (size_type i = 0; i < IV::capacity(); ++i) { + EXPECT_NE(vec.try_push_back(T{}), nullptr); + } + EXPECT_EQ(vec.try_push_back(T{}), nullptr); + EXPECT_EQ(vec.size(), IV::capacity()); + vec.clear(); + EXPECT_EQ(vec.size(), 0); + + static_assert(requires(IV vec, T t) { vec.try_push_back(t); }); + static_assert(requires(IV vec, T t) { vec.try_emplace_back(t); }); + + static_assert(!requires(IV vec, T t) { vec.push_back(t); }); + static_assert(!requires(IV vec, T t) { vec.emplace_back(t); }); + static_assert(!requires(IV vec, size_type t) { vec.reserve(t); }); + + // TODO make sure all of the freestanding-delete functions are deleted +} +} // namespace diff --git a/tests/beman/inplace_vector/gtest_setup.hpp b/tests/beman/inplace_vector/gtest_setup.hpp index 1517492..1e959c3 100644 --- a/tests/beman/inplace_vector/gtest_setup.hpp +++ b/tests/beman/inplace_vector/gtest_setup.hpp @@ -351,12 +351,48 @@ template class IVBasicTest : public ::testing::Test { using X = beman::inplace_vector; using IV = X; + // Implements inplace_vector's freestanding constructors for convenience + // testing in a freestanding context + + static X vec_of(std::size_t size) { +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() + return X(size); +#else + X vec; + for (auto i = 0; i < size; ++i) + vec.unchecked_emplace_back(); + return vec; +#endif + } + + static X vec_of(std::initializer_list &&il) { +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() + return X(il); +#else + X vec; + for (auto &ele : il) + vec.unchecked_push_back(ele); + return vec; +#endif + } + + template static X vec_of(Itr begin, Itr end) { +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() + return X(begin, end); +#else + X vec; + for (auto itr = begin; itr != end; ++itr) + vec.unchecked_push_back(*itr); + return vec; +#endif + } + // Returns IV of size n with unique values static IV unique(typename IV::size_type n = IV::max_size()) { static T val = T{}; IV res; while (n > 0) { - res.push_back(val); + res.unchecked_push_back(val); ++val.value; --n; } diff --git a/tests/beman/inplace_vector/inplace_vector.test.cpp b/tests/beman/inplace_vector/inplace_vector.test.cpp index cfb1d9c..b91586b 100644 --- a/tests/beman/inplace_vector/inplace_vector.test.cpp +++ b/tests/beman/inplace_vector/inplace_vector.test.cpp @@ -6,8 +6,22 @@ using namespace beman; template constexpr void test() { using vec = inplace_vector; +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() vec range{T(1), T(1337), T(42), T(12), T(0), T(-1)}; const vec const_range{T(0), T(42), T(1337), T(42), T(5), T(-42)}; +#else + vec range; + for (auto &ele : {T(1), T(1337), T(42), T(12), T(0), T(-1)}) { + range.unchecked_push_back(ele); + } + + vec const_range_builder; + for (auto &ele : {T(0), T(42), T(1337), T(42), T(5), T(-42)}) { + const_range_builder.unchecked_push_back(ele); + } + + const vec const_range = const_range_builder; +#endif auto &&bracket = range[3]; static_assert(std::is_same::value, @@ -65,11 +79,9 @@ template constexpr void test() { assert(const_data == std::addressof(const_front)); } -#if BEMAN_INPLACE_VECTOR_NO_EXCEPTIONS() -int main() { - test(); - return 0; -} +#if BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() | \ + BEMAN_INPLACE_VECTOR_NO_EXCEPTIONS() +void test_exceptions() {}; #else void test_exceptions() { using vec = inplace_vector; @@ -92,10 +104,10 @@ void test_exceptions() { } } } +#endif int main() { test(); test_exceptions(); return 0; } -#endif diff --git a/tests/beman/inplace_vector/modifiers.test.cpp b/tests/beman/inplace_vector/modifiers.test.cpp index 068d2c5..2bc251c 100644 --- a/tests/beman/inplace_vector/modifiers.test.cpp +++ b/tests/beman/inplace_vector/modifiers.test.cpp @@ -8,428 +8,25 @@ namespace { template class Modifiers : public IVBasicTest {}; TYPED_TEST_SUITE(Modifiers, IVAllTypes); -TYPED_TEST(Modifiers, InsertSingleConstRef) { - // constexpr iterator insert(const_iterator position, const T& x); - - using IV = TestFixture::IV; - using T = TestFixture::T; - - IV device; - IV reference; - - if (device.capacity() > 0) { - reference = this->unique(); - - auto res = device.insert(device.begin(), reference[0]); - EXPECT_EQ(res, device.begin()); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + 1)); - - if (device.capacity() > 1) { - res = device.insert(device.end(), reference.back()); - EXPECT_EQ(res, device.end() - 1); - EXPECT_EQ(device, IV({reference[0], reference.back()})); - - for (auto i = 1ul; i < (reference.size() - 1); ++i) { - res = device.insert(device.end() - 1, reference[i]); - EXPECT_EQ(res, device.begin() + i); - - IV correct(reference.begin(), reference.begin() + i + 1); - correct.push_back(reference.back()); - - EXPECT_EQ(device, correct); - } - } - } - - T val{272}; - SAFE_EXPECT_THROW(device.insert(device.begin(), val), std::bad_alloc); - EXPECT_EQ(device, reference); - - SAFE_EXPECT_THROW(device.insert(device.begin(), val), std::bad_alloc); - EXPECT_EQ(device, reference); -} - -TYPED_TEST(Modifiers, InsertSingleRV) { - // constexpr iterator insert(const_iterator position, T&& x); - - using IV = TestFixture::IV; - using T = TestFixture::T; - - IV device; - IV reference; - - if (device.capacity() > 0) { - reference = this->unique(); - - auto res = device.insert(device.begin(), T{reference[0]}); - EXPECT_EQ(res, device.begin()); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + 1)); - - if (device.capacity() > 1) { - res = device.insert(device.end(), T{reference.back()}); - EXPECT_EQ(res, device.end() - 1); - EXPECT_EQ(device, IV({reference[0], reference.back()})); - - for (auto i = 1ul; i < (reference.size() - 1); ++i) { - res = device.insert(device.end() - 1, T{reference[i]}); - EXPECT_EQ(res, device.begin() + i); - - IV correct(reference.begin(), reference.begin() + i + 1); - correct.push_back(reference.back()); - - EXPECT_EQ(device, correct); - } - } - } - - SAFE_EXPECT_THROW(device.insert(device.begin(), T{272}), std::bad_alloc); - EXPECT_EQ(device, reference); - - SAFE_EXPECT_THROW(device.insert(device.begin(), T{272}), std::bad_alloc); - EXPECT_EQ(device, reference); -} - -TYPED_TEST(Modifiers, InsertEmplace) { - // constexpr iterator emplace(const_iterator position, Args&&... args); - - using IV = TestFixture::IV; - - IV device; - IV reference; - - if (device.capacity() > 0) { - reference = this->unique(); - - auto res = device.emplace(device.begin(), reference[0].value); - EXPECT_EQ(res, device.begin()); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + 1)); - - if (device.capacity() > 1) { - res = device.emplace(device.end(), reference.back().value); - EXPECT_EQ(res, device.end() - 1); - EXPECT_EQ(device, IV({reference[0], reference.back()})); - - for (auto i = 1ul; i < (reference.size() - 1); ++i) { - res = device.emplace(device.end() - 1, reference[i].value); - EXPECT_EQ(res, device.begin() + i); - - IV correct(reference.begin(), reference.begin() + i + 1); - correct.push_back(reference.back()); - - EXPECT_EQ(device, correct); - } - } - } - - SAFE_EXPECT_THROW(device.emplace(device.begin(), 272), std::bad_alloc); - EXPECT_EQ(device, reference); - - SAFE_EXPECT_THROW(device.emplace(device.begin(), 272), std::bad_alloc); - EXPECT_EQ(device, reference); -} - -TYPED_TEST(Modifiers, InsertMulti) { - // constexpr iterator insert(const_iterator position, size_type n, const T& - // x); - // - // Complexity: Linear in the number of elements inserted plus the distance - // to the end of the vector. - // Remarks: If an exception is thrown other than by the copy constructor, - // move constructor, assignment operator, or move assignment operator of T or - // by any InputIterator operation, there are no effects. Otherwise, if an - // exception is thrown, then size()  ≥ n and elements in the range begin() + - // [0, n) are not modified. - - using IV = TestFixture::IV; - - IV device; - - if (device.capacity() > 0) { - auto duplicate = this->unique(1)[0]; - IV reference(device.capacity(), duplicate); - - if (device.capacity() > 1) { - auto front = this->unique(1)[0]; - reference[0] = front; - device.push_back(front); - } - - auto num_fill = device.capacity() - device.size(); - device.insert(device.end(), num_fill, duplicate); - - EXPECT_EQ(device, IV(reference.begin(), reference.end())); - } - - EXPECT_NO_THROW(device.insert(device.begin(), 0, {2538})); - SAFE_EXPECT_THROW(device.insert(device.begin(), 1, {2538}), std::bad_alloc); -} - -TYPED_TEST(Modifiers, InsertInitList) { - // constexpr iterator insert(const_iterator position, initializer_list il); - // - // Let n be the value of size() before this call for the append_range - // overload, and distance(begin, position) otherwise. - // Complexity: Linear in the number of elements inserted plus the distance - // to the end of the vector. - // Remarks: If an exception is thrown other than by the copy constructor, - // move constructor, assignment operator, or move assignment operator of T or - // by any InputIterator operation, there are no effects. Otherwise, if an - // exception is thrown, then size()  ≥ n and elements in the range begin() + - // [0, n) are not modified. - - using IV = TestFixture::IV; - using T = TestFixture::T; - - IV device; - auto res = device.insert(device.end(), {}); - EXPECT_EQ(res, device.end()); - EXPECT_EQ(device, IV()); - - if (device.capacity() > 0) { - res = device.insert(device.begin(), {T{0}}); - EXPECT_EQ(res, device.begin()); - EXPECT_EQ(device, IV{T{0}}); - - if (device.capacity() >= 3) { - res = device.insert(device.begin(), {T{1}, T{2}}); - EXPECT_EQ(res, device.begin()); - - IV expected{T{1}, T{2}, T{0}}; - EXPECT_EQ(device, expected); - } - } - - auto full = this->unique(); - EXPECT_NO_THROW(full.insert(full.begin(), {})); - SAFE_EXPECT_THROW(full.insert(full.begin(), {T{25}}), std::bad_alloc); -} - -TYPED_TEST(Modifiers, InsertRange) { - // template R> - // constexpr iterator insert_range(const_iterator position, R&& rg); - // - // Let n be the value of size() before this call for the append_range - // overload, and distance(begin, position) otherwise. - // Complexity: Linear in the number of elements inserted plus the distance - // to the end of the vector. - // Remarks: If an exception is thrown other than by the copy constructor, - // move constructor, assignment operator, or move assignment operator of T or - // by any InputIterator operation, there are no effects. Otherwise, if an - // exception is thrown, then size()  ≥ n and elements in the range begin() + - // [0, n) are not modified. - - using IV = TestFixture::IV; - using T = TestFixture::T; - - IV device; - auto reference = this->unique(); - - auto res = device.insert_range(device.end(), reference | std::views::take(0)); - EXPECT_EQ(res, device.end()); - - res = device.insert_range(device.end(), reference); - EXPECT_EQ(res, device.begin()); - EXPECT_EQ(device, reference); - device.clear(); - - if (device.capacity() > 0) { - res = device.insert_range(device.end(), reference | std::views::take(1)); - EXPECT_EQ(res, device.begin()); - EXPECT_EQ(device, IV({reference.front()})); - - if (device.capacity() > 1) { - res = device.insert_range( - device.begin() + 1, - std::ranges::subrange(reference.end() - 1, reference.end())); - EXPECT_EQ(res, device.begin() + 1); - EXPECT_EQ(device, IV({reference.front(), reference.back()})); - - if (device.capacity() > 2) { - res = device.insert_range(device.begin() + 1, - reference | std::views::drop(1) | - std::views::take(reference.size() - 2)); - EXPECT_EQ(res, device.begin() + 1); - EXPECT_EQ(device, reference); - } - } - } - - EXPECT_NO_THROW(device.insert_range(device.begin(), std::array{})); - EXPECT_EQ(device, reference); - - SAFE_EXPECT_THROW( - device.insert_range(device.begin(), std::array{T{25}}), - std::bad_alloc); -} - -TYPED_TEST(Modifiers, InsertItrRange) { - // constexpr iterator emplace(const_iterator position, Args&&... args); - // template R> - // constexpr void append_range(R&& rg); - // - // Let n be the value of size() before this call for the append_range - // overload, and distance(begin, position) otherwise. - // Complexity: Linear in the number of elements inserted plus the distance - // to the end of the vector. - // Remarks: If an exception is thrown other than by the copy constructor, - // move constructor, assignment operator, or move assignment operator of T or - // by any InputIterator operation, there are no effects. Otherwise, if an - // exception is thrown, then size()  ≥ n and elements in the range begin() + - // [0, n) are not modified. - - using IV = TestFixture::IV; - using T = TestFixture::T; - - IV device; - auto reference = this->unique(); - - auto res = device.insert(device.end(), reference.end(), reference.end()); - EXPECT_EQ(res, device.end()); - - res = device.insert(device.end(), reference.begin(), reference.end()); - EXPECT_EQ(res, device.begin()); - EXPECT_EQ(device, reference); - device.clear(); - - if (device.capacity() > 0) { - res = device.insert(device.end(), reference.begin(), reference.begin() + 1); - EXPECT_EQ(res, device.begin()); - EXPECT_EQ(device, IV({reference.front()})); - - if (device.capacity() > 1) { - res = device.insert(device.begin() + 1, reference.end() - 1, - reference.end()); - EXPECT_EQ(res, device.begin() + 1); - EXPECT_EQ(device, IV({reference.front(), reference.back()})); - - if (device.capacity() > 2) { - res = device.insert(device.begin() + 1, reference.begin() + 1, - reference.end() - 1); - EXPECT_EQ(res, device.begin() + 1); - EXPECT_EQ(device, reference); - } - } - } - - EXPECT_NO_THROW( - device.insert(device.begin(), reference.end(), reference.end())); - EXPECT_EQ(device, reference); - - std::array single_array{T{25}}; - SAFE_EXPECT_THROW( - device.insert(device.begin(), single_array.begin(), single_array.end()), - std::bad_alloc); -} - -TYPED_TEST(Modifiers, InsertAppendRange) { - // template R> - // constexpr void append_range(R&& rg); - // - // Let n be the value of size() before this call for the append_range - // overload, and distance(begin, position) otherwise. - // Complexity: Linear in the number of elements inserted plus the distance - // to the end of the vector. - // Remarks: If an exception is thrown other than by the copy constructor, - // move constructor, assignment operator, or move assignment operator of T or - // by any InputIterator operation, there are no effects. Otherwise, if an - // exception is thrown, then size()  ≥ n and elements in the range begin() + - // [0, n) are not modified. - - using IV = TestFixture::IV; - - IV device; - auto reference = this->unique(); - - device.append_range(reference | std::views::take(0)); - EXPECT_EQ(device, IV()); - - device.append_range(reference); - EXPECT_EQ(device, reference); - device.clear(); - - auto half_size = std::midpoint(0ul, reference.size()); - device.append_range(reference | std::views::take(half_size)); - device.append_range(reference | std::views::drop(half_size)); - EXPECT_EQ(device, reference); -} - -TYPED_TEST(Modifiers, PushBackConstRef) { - // constexpr reference push_back(const T& x); - // - // Returns: back(). - // Throws: bad_alloc or any exception thrown by the initialization of the - // inserted element. - // Complexity: Constant. - // Remarks: If an exception is thrown, there are no effects on *this. - - using IV = TestFixture::IV; - using T = TestFixture::T; - - const auto reference = this->unique(); - - IV device; - for (auto i = 0ul; i < reference.size(); ++i) { - auto val = reference[i]; - auto res = device.push_back(val); - EXPECT_EQ(res, device.back()); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); - } - - T val{0}; - SAFE_EXPECT_THROW(device.push_back(val), std::bad_alloc); -} - -TYPED_TEST(Modifiers, PushBackRV) { - // constexpr reference push_back(T&& x); - // - // Returns: back(). - // Throws: bad_alloc or any exception thrown by the initialization of the - // inserted element. - // Complexity: Constant. - // Remarks: If an exception is thrown, there are no effects on *this. - - using IV = TestFixture::IV; - using T = TestFixture::T; - - const auto reference = this->unique(); - - IV device; - for (auto i = 0ul; i < reference.size(); ++i) { - T val{reference[i]}; - auto res = device.push_back(std::move(val)); - EXPECT_EQ(res, device.back()); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); - } - - T val{0}; - SAFE_EXPECT_THROW(device.push_back(val), std::bad_alloc); -} - -// TODO: Check if there's extra copies - -TYPED_TEST(Modifiers, EmplaceBack) { - // template - // constexpr reference emplace_back(Args&&... args); - // - // Returns: back(). - // Throws: bad_alloc or any exception thrown by the initialization of the - // inserted element. - // Complexity: Constant. - // Remarks: If an exception is thrown, there are no effects on *this. - - using IV = TestFixture::IV; - - const auto reference = this->unique(); - - IV device; - for (auto i = 0ul; i < reference.size(); ++i) { - auto res = device.emplace_back(reference[i].value); - EXPECT_EQ(res, device.back()); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); - } - - SAFE_EXPECT_THROW(device.emplace_back(0), std::bad_alloc); -} +// These functions are marked as freestand delete. +// See modifiers_fs.test.cpp. +// +// constexpr iterator insert(const_iterator position, const T& x); +// constexpr iterator insert(const_iterator position, T&& x); +// constexpr iterator emplace(const_iterator position, Args&&... args); +// constexpr iterator insert(const_iterator position, size_type n, const T& x); +// constexpr iterator insert(const_iterator position, initializer_list il); +// template R> +// constexpr iterator insert_range(const_iterator position, R&& rg); +// template R> +// constexpr void append_range(R&& rg); +// template R> +// constexpr void append_range(R&& rg); +// constexpr reference push_back(const T& x); +// constexpr reference push_back(T&& x); +// template +// constexpr reference emplace_back(Args&&... args); +// static constexpr void reserve(size_type n); TYPED_TEST(Modifiers, TryEmplaceBack) { // template @@ -459,7 +56,8 @@ TYPED_TEST(Modifiers, TryEmplaceBack) { for (auto i = 0ul; i < reference.size(); ++i) { auto res = device.try_emplace_back(reference[i].value); EXPECT_EQ(res, std::addressof(device.back())); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); + EXPECT_EQ(device, TestFixture::vec_of(reference.begin(), + reference.begin() + i + 1)); } auto res = device.try_emplace_back(reference[0].value); @@ -501,7 +99,8 @@ TYPED_TEST(Modifiers, TryPushBackConstRef) { for (auto i = 0ul; i < reference.size(); ++i) { auto res = device.try_push_back(reference[i]); EXPECT_EQ(res, std::addressof(device.back())); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); + EXPECT_EQ(device, TestFixture::vec_of(reference.begin(), + reference.begin() + i + 1)); } auto res = device.try_push_back(reference[0]); @@ -548,7 +147,8 @@ TYPED_TEST(Modifiers, TryPushBackRV) { auto res = device.try_push_back(std::move(val)); EXPECT_EQ(res, std::addressof(device.back())); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); + EXPECT_EQ(device, TestFixture::vec_of(reference.begin(), + reference.begin() + i + 1)); } auto res = device.try_push_back(reference[0]); @@ -636,7 +236,8 @@ TYPED_TEST(Modifiers, UncheckedEmplacedBack) { for (auto i = 0ul; i < reference.size(); ++i) { auto res = device.unchecked_emplace_back(reference[i].value); EXPECT_EQ(res, device.back()); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); + EXPECT_EQ(device, TestFixture::vec_of(reference.begin(), + reference.begin() + i + 1)); } } @@ -655,7 +256,8 @@ TYPED_TEST(Modifiers, UncheckedPushBackConstRef) { for (auto i = 0ul; i < reference.size(); ++i) { auto res = device.unchecked_push_back(reference[i]); EXPECT_EQ(res, device.back()); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); + EXPECT_EQ(device, TestFixture::vec_of(reference.begin(), + reference.begin() + i + 1)); } } @@ -677,56 +279,11 @@ TYPED_TEST(Modifiers, UncheckedPushBackRV) { auto res = device.unchecked_push_back(std::move(val)); EXPECT_EQ(res, device.back()); - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); + EXPECT_EQ(device, TestFixture::vec_of(reference.begin(), + reference.begin() + i + 1)); } } -TYPED_TEST(Modifiers, ReserveNonEmpty) { - // static constexpr void reserve(size_type n); - // - // Effects: None. - // Throws: bad_alloc if n > capacity() is true. - - using IV = TestFixture::IV; - - const auto reference = this->unique(); - - IV device(reference); - - device.reserve(device.size()); - EXPECT_EQ(device, reference); - - device.reserve(0); - EXPECT_EQ(device, reference); - - device.reserve(device.capacity()); - EXPECT_EQ(device, reference); - - SAFE_EXPECT_THROW(device.reserve(device.capacity() + 1), std::bad_alloc); -} - -TYPED_TEST(Modifiers, ReserveEmpty) { - // static constexpr void reserve(size_type n); - // - // Effects: None. - // Throws: bad_alloc if n > capacity() is true. - - using IV = TestFixture::IV; - - IV device; - - device.reserve(device.size()); - EXPECT_EQ(device, IV()); - - device.reserve(0); - EXPECT_EQ(device, IV()); - - device.reserve(device.capacity()); - EXPECT_EQ(device, IV()); - - SAFE_EXPECT_THROW(device.reserve(device.capacity() + 1), std::bad_alloc); -} - TYPED_TEST(Modifiers, ShrinkToFitNonEmpty) { // static constexpr void shrink_to_fit() noexcept; // Effects: None. @@ -853,7 +410,8 @@ TYPED_TEST(Modifiers, EraseRange) { itr = device.erase(device.begin(), device.begin() + 1); EXPECT_EQ(itr, device.begin()); - EXPECT_EQ(device, IV(reference.begin() + 1, reference.end())); + EXPECT_EQ(device, + TestFixture::vec_of(reference.begin() + 1, reference.end())); if (device.empty()) return; @@ -864,7 +422,8 @@ TYPED_TEST(Modifiers, EraseRange) { itr = device.erase(last_itr, device.end()); EXPECT_EQ(itr, device.end()); - EXPECT_EQ(device, IV(reference.begin(), reference.end() - 1)); + EXPECT_EQ(device, + TestFixture::vec_of(reference.begin(), reference.end() - 1)); if (device.size() >= 4) { reference = IV(device); @@ -874,7 +433,7 @@ TYPED_TEST(Modifiers, EraseRange) { itr = device.erase(from_itr, to_itr); EXPECT_EQ(itr, device.begin() + 1); - EXPECT_EQ(device, IV({reference[0], reference.back()})); + EXPECT_EQ(device, TestFixture::vec_of({reference[0], reference.back()})); } } @@ -917,11 +476,13 @@ TYPED_TEST(Modifiers, PopBack) { return; for (auto i = int(reference.size()); i > 0; --i) { - EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i)); + EXPECT_EQ(device, + TestFixture::vec_of(reference.begin(), reference.begin() + i)); device.pop_back(); } EXPECT_TRUE(device.empty()) << "device still have " << device.size() << " elements"; } + }; // namespace diff --git a/tests/beman/inplace_vector/modifiers_fs.test.cpp b/tests/beman/inplace_vector/modifiers_fs.test.cpp new file mode 100644 index 0000000..1f6cf65 --- /dev/null +++ b/tests/beman/inplace_vector/modifiers_fs.test.cpp @@ -0,0 +1,480 @@ +#include + +#include "gtest_setup.hpp" +#include + +namespace { +// 23.3.14.5 Modifiers [inplace.vector.modifiers] +template class Modifiers : public IVBasicTest {}; +TYPED_TEST_SUITE(Modifiers, IVAllTypes); + +TYPED_TEST(Modifiers, InsertSingleConstRef) { + // constexpr iterator insert(const_iterator position, const T& x); + + using IV = TestFixture::IV; + using T = TestFixture::T; + + IV device; + IV reference; + + if (device.capacity() > 0) { + reference = this->unique(); + + auto res = device.insert(device.begin(), reference[0]); + EXPECT_EQ(res, device.begin()); + EXPECT_EQ(device, IV(reference.begin(), reference.begin() + 1)); + + if (device.capacity() > 1) { + res = device.insert(device.end(), reference.back()); + EXPECT_EQ(res, device.end() - 1); + EXPECT_EQ(device, IV({reference[0], reference.back()})); + + for (auto i = 1ul; i < (reference.size() - 1); ++i) { + res = device.insert(device.end() - 1, reference[i]); + EXPECT_EQ(res, device.begin() + i); + + IV correct(reference.begin(), reference.begin() + i + 1); + correct.push_back(reference.back()); + + EXPECT_EQ(device, correct); + } + } + } + + T val{272}; + SAFE_EXPECT_THROW(device.insert(device.begin(), val), std::bad_alloc); + EXPECT_EQ(device, reference); + + SAFE_EXPECT_THROW(device.insert(device.begin(), val), std::bad_alloc); + EXPECT_EQ(device, reference); +} + +TYPED_TEST(Modifiers, InsertSingleRV) { + // constexpr iterator insert(const_iterator position, T&& x); + + using IV = TestFixture::IV; + using T = TestFixture::T; + + IV device; + IV reference; + + if (device.capacity() > 0) { + reference = this->unique(); + + auto res = device.insert(device.begin(), T{reference[0]}); + EXPECT_EQ(res, device.begin()); + EXPECT_EQ(device, IV(reference.begin(), reference.begin() + 1)); + + if (device.capacity() > 1) { + res = device.insert(device.end(), T{reference.back()}); + EXPECT_EQ(res, device.end() - 1); + EXPECT_EQ(device, IV({reference[0], reference.back()})); + + for (auto i = 1ul; i < (reference.size() - 1); ++i) { + res = device.insert(device.end() - 1, T{reference[i]}); + EXPECT_EQ(res, device.begin() + i); + + IV correct(reference.begin(), reference.begin() + i + 1); + correct.push_back(reference.back()); + + EXPECT_EQ(device, correct); + } + } + } + + SAFE_EXPECT_THROW(device.insert(device.begin(), T{272}), std::bad_alloc); + EXPECT_EQ(device, reference); + + SAFE_EXPECT_THROW(device.insert(device.begin(), T{272}), std::bad_alloc); + EXPECT_EQ(device, reference); +} + +TYPED_TEST(Modifiers, InsertEmplace) { + // constexpr iterator emplace(const_iterator position, Args&&... args); + + using IV = TestFixture::IV; + + IV device; + IV reference; + + if (device.capacity() > 0) { + reference = this->unique(); + + auto res = device.emplace(device.begin(), reference[0].value); + EXPECT_EQ(res, device.begin()); + EXPECT_EQ(device, IV(reference.begin(), reference.begin() + 1)); + + if (device.capacity() > 1) { + res = device.emplace(device.end(), reference.back().value); + EXPECT_EQ(res, device.end() - 1); + EXPECT_EQ(device, IV({reference[0], reference.back()})); + + for (auto i = 1ul; i < (reference.size() - 1); ++i) { + res = device.emplace(device.end() - 1, reference[i].value); + EXPECT_EQ(res, device.begin() + i); + + IV correct(reference.begin(), reference.begin() + i + 1); + correct.push_back(reference.back()); + + EXPECT_EQ(device, correct); + } + } + } + + SAFE_EXPECT_THROW(device.emplace(device.begin(), 272), std::bad_alloc); + EXPECT_EQ(device, reference); + + SAFE_EXPECT_THROW(device.emplace(device.begin(), 272), std::bad_alloc); + EXPECT_EQ(device, reference); +} + +TYPED_TEST(Modifiers, InsertMulti) { + // constexpr iterator insert(const_iterator position, size_type n, const T& + // x); + // + // Complexity: Linear in the number of elements inserted plus the distance + // to the end of the vector. + // Remarks: If an exception is thrown other than by the copy constructor, + // move constructor, assignment operator, or move assignment operator of T or + // by any InputIterator operation, there are no effects. Otherwise, if an + // exception is thrown, then size()  ≥ n and elements in the range begin() + + // [0, n) are not modified. + + using IV = TestFixture::IV; + + IV device; + + if (device.capacity() > 0) { + auto duplicate = this->unique(1)[0]; + IV reference(device.capacity(), duplicate); + + if (device.capacity() > 1) { + auto front = this->unique(1)[0]; + reference[0] = front; + device.push_back(front); + } + + auto num_fill = device.capacity() - device.size(); + device.insert(device.end(), num_fill, duplicate); + + EXPECT_EQ(device, IV(reference.begin(), reference.end())); + } + + EXPECT_NO_THROW(device.insert(device.begin(), 0, {2538})); + SAFE_EXPECT_THROW(device.insert(device.begin(), 1, {2538}), std::bad_alloc); +} + +TYPED_TEST(Modifiers, InsertInitList) { + // constexpr iterator insert(const_iterator position, initializer_list il); + // + // Let n be the value of size() before this call for the append_range + // overload, and distance(begin, position) otherwise. + // Complexity: Linear in the number of elements inserted plus the distance + // to the end of the vector. + // Remarks: If an exception is thrown other than by the copy constructor, + // move constructor, assignment operator, or move assignment operator of T or + // by any InputIterator operation, there are no effects. Otherwise, if an + // exception is thrown, then size()  ≥ n and elements in the range begin() + + // [0, n) are not modified. + + using IV = TestFixture::IV; + using T = TestFixture::T; + + IV device; + auto res = device.insert(device.end(), {}); + EXPECT_EQ(res, device.end()); + EXPECT_EQ(device, IV()); + + if (device.capacity() > 0) { + res = device.insert(device.begin(), {T{0}}); + EXPECT_EQ(res, device.begin()); + EXPECT_EQ(device, IV{T{0}}); + + if (device.capacity() >= 3) { + res = device.insert(device.begin(), {T{1}, T{2}}); + EXPECT_EQ(res, device.begin()); + + IV expected{T{1}, T{2}, T{0}}; + EXPECT_EQ(device, expected); + } + } + + auto full = this->unique(); + EXPECT_NO_THROW(full.insert(full.begin(), {})); + SAFE_EXPECT_THROW(full.insert(full.begin(), {T{25}}), std::bad_alloc); +} + +TYPED_TEST(Modifiers, InsertRange) { + // template R> + // constexpr iterator insert_range(const_iterator position, R&& rg); + // + // Let n be the value of size() before this call for the append_range + // overload, and distance(begin, position) otherwise. + // Complexity: Linear in the number of elements inserted plus the distance + // to the end of the vector. + // Remarks: If an exception is thrown other than by the copy constructor, + // move constructor, assignment operator, or move assignment operator of T or + // by any InputIterator operation, there are no effects. Otherwise, if an + // exception is thrown, then size()  ≥ n and elements in the range begin() + + // [0, n) are not modified. + + using IV = TestFixture::IV; + using T = TestFixture::T; + + IV device; + auto reference = this->unique(); + + auto res = device.insert_range(device.end(), reference | std::views::take(0)); + EXPECT_EQ(res, device.end()); + + res = device.insert_range(device.end(), reference); + EXPECT_EQ(res, device.begin()); + EXPECT_EQ(device, reference); + device.clear(); + + if (device.capacity() > 0) { + res = device.insert_range(device.end(), reference | std::views::take(1)); + EXPECT_EQ(res, device.begin()); + EXPECT_EQ(device, IV({reference.front()})); + + if (device.capacity() > 1) { + res = device.insert_range( + device.begin() + 1, + std::ranges::subrange(reference.end() - 1, reference.end())); + EXPECT_EQ(res, device.begin() + 1); + EXPECT_EQ(device, IV({reference.front(), reference.back()})); + + if (device.capacity() > 2) { + res = device.insert_range(device.begin() + 1, + reference | std::views::drop(1) | + std::views::take(reference.size() - 2)); + EXPECT_EQ(res, device.begin() + 1); + EXPECT_EQ(device, reference); + } + } + } + + EXPECT_NO_THROW(device.insert_range(device.begin(), std::array{})); + EXPECT_EQ(device, reference); + + SAFE_EXPECT_THROW( + device.insert_range(device.begin(), std::array{T{25}}), + std::bad_alloc); +} + +TYPED_TEST(Modifiers, InsertItrRange) { + // constexpr iterator emplace(const_iterator position, Args&&... args); + // template R> + // constexpr void append_range(R&& rg); + // + // Let n be the value of size() before this call for the append_range + // overload, and distance(begin, position) otherwise. + // Complexity: Linear in the number of elements inserted plus the distance + // to the end of the vector. + // Remarks: If an exception is thrown other than by the copy constructor, + // move constructor, assignment operator, or move assignment operator of T or + // by any InputIterator operation, there are no effects. Otherwise, if an + // exception is thrown, then size()  ≥ n and elements in the range begin() + + // [0, n) are not modified. + + using IV = TestFixture::IV; + using T = TestFixture::T; + + IV device; + auto reference = this->unique(); + + auto res = device.insert(device.end(), reference.end(), reference.end()); + EXPECT_EQ(res, device.end()); + + res = device.insert(device.end(), reference.begin(), reference.end()); + EXPECT_EQ(res, device.begin()); + EXPECT_EQ(device, reference); + device.clear(); + + if (device.capacity() > 0) { + res = device.insert(device.end(), reference.begin(), reference.begin() + 1); + EXPECT_EQ(res, device.begin()); + EXPECT_EQ(device, IV({reference.front()})); + + if (device.capacity() > 1) { + res = device.insert(device.begin() + 1, reference.end() - 1, + reference.end()); + EXPECT_EQ(res, device.begin() + 1); + EXPECT_EQ(device, IV({reference.front(), reference.back()})); + + if (device.capacity() > 2) { + res = device.insert(device.begin() + 1, reference.begin() + 1, + reference.end() - 1); + EXPECT_EQ(res, device.begin() + 1); + EXPECT_EQ(device, reference); + } + } + } + + EXPECT_NO_THROW( + device.insert(device.begin(), reference.end(), reference.end())); + EXPECT_EQ(device, reference); + + std::array single_array{T{25}}; + SAFE_EXPECT_THROW( + device.insert(device.begin(), single_array.begin(), single_array.end()), + std::bad_alloc); +} + +TYPED_TEST(Modifiers, InsertAppendRange) { + // template R> + // constexpr void append_range(R&& rg); + // + // Let n be the value of size() before this call for the append_range + // overload, and distance(begin, position) otherwise. + // Complexity: Linear in the number of elements inserted plus the distance + // to the end of the vector. + // Remarks: If an exception is thrown other than by the copy constructor, + // move constructor, assignment operator, or move assignment operator of T or + // by any InputIterator operation, there are no effects. Otherwise, if an + // exception is thrown, then size()  ≥ n and elements in the range begin() + + // [0, n) are not modified. + + using IV = TestFixture::IV; + + IV device; + auto reference = this->unique(); + + device.append_range(reference | std::views::take(0)); + EXPECT_EQ(device, IV()); + + device.append_range(reference); + EXPECT_EQ(device, reference); + device.clear(); + + auto half_size = std::midpoint(0ul, reference.size()); + device.append_range(reference | std::views::take(half_size)); + device.append_range(reference | std::views::drop(half_size)); + EXPECT_EQ(device, reference); +} + +TYPED_TEST(Modifiers, PushBackConstRef) { + // constexpr reference push_back(const T& x); + // + // Returns: back(). + // Throws: bad_alloc or any exception thrown by the initialization of the + // inserted element. + // Complexity: Constant. + // Remarks: If an exception is thrown, there are no effects on *this. + + using IV = TestFixture::IV; + using T = TestFixture::T; + + const auto reference = this->unique(); + + IV device; + for (auto i = 0ul; i < reference.size(); ++i) { + auto val = reference[i]; + auto res = device.push_back(val); + EXPECT_EQ(res, device.back()); + EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); + } + + T val{0}; + SAFE_EXPECT_THROW(device.push_back(val), std::bad_alloc); +} + +TYPED_TEST(Modifiers, PushBackRV) { + // constexpr reference push_back(T&& x); + // + // Returns: back(). + // Throws: bad_alloc or any exception thrown by the initialization of the + // inserted element. + // Complexity: Constant. + // Remarks: If an exception is thrown, there are no effects on *this. + + using IV = TestFixture::IV; + using T = TestFixture::T; + + const auto reference = this->unique(); + + IV device; + for (auto i = 0ul; i < reference.size(); ++i) { + T val{reference[i]}; + auto res = device.push_back(std::move(val)); + EXPECT_EQ(res, device.back()); + EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); + } + + T val{0}; + SAFE_EXPECT_THROW(device.push_back(val), std::bad_alloc); +} + +// TODO: Check if there's extra copies + +TYPED_TEST(Modifiers, EmplaceBack) { + // template + // constexpr reference emplace_back(Args&&... args); + // + // Returns: back(). + // Throws: bad_alloc or any exception thrown by the initialization of the + // inserted element. + // Complexity: Constant. + // Remarks: If an exception is thrown, there are no effects on *this. + + using IV = TestFixture::IV; + + const auto reference = this->unique(); + + IV device; + for (auto i = 0ul; i < reference.size(); ++i) { + auto res = device.emplace_back(reference[i].value); + EXPECT_EQ(res, device.back()); + EXPECT_EQ(device, IV(reference.begin(), reference.begin() + i + 1)); + } + + SAFE_EXPECT_THROW(device.emplace_back(0), std::bad_alloc); +} + +TYPED_TEST(Modifiers, ReserveNonEmpty) { + // static constexpr void reserve(size_type n); + // + // Effects: None. + // Throws: bad_alloc if n > capacity() is true. + + using IV = TestFixture::IV; + + const auto reference = this->unique(); + + IV device(reference); + + device.reserve(device.size()); + EXPECT_EQ(device, reference); + + device.reserve(0); + EXPECT_EQ(device, reference); + + device.reserve(device.capacity()); + EXPECT_EQ(device, reference); + + SAFE_EXPECT_THROW(device.reserve(device.capacity() + 1), std::bad_alloc); +} + +TYPED_TEST(Modifiers, ReserveEmpty) { + // static constexpr void reserve(size_type n); + // + // Effects: None. + // Throws: bad_alloc if n > capacity() is true. + + using IV = TestFixture::IV; + + IV device; + + device.reserve(device.size()); + EXPECT_EQ(device, IV()); + + device.reserve(0); + EXPECT_EQ(device, IV()); + + device.reserve(device.capacity()); + EXPECT_EQ(device, IV()); + + SAFE_EXPECT_THROW(device.reserve(device.capacity() + 1), std::bad_alloc); +} + +}; // namespace diff --git a/tests/beman/inplace_vector/ref_impl.test.cpp b/tests/beman/inplace_vector/ref_impl.test.cpp index 83c0564..3a0d597 100644 --- a/tests/beman/inplace_vector/ref_impl.test.cpp +++ b/tests/beman/inplace_vector/ref_impl.test.cpp @@ -83,6 +83,7 @@ template struct beman::inplace_vector; template struct beman::inplace_vector; template struct beman::inplace_vector; +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() // non-trivial template struct beman::inplace_vector; template struct beman::inplace_vector; @@ -90,6 +91,7 @@ template struct beman::inplace_vector; // move-only: template struct beman::inplace_vector, 3>; template struct beman::inplace_vector, 3>; +#endif struct tint { std::size_t i; @@ -178,6 +180,7 @@ template struct vec { vec(std::initializer_list /*il*/) {} }; +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() template constexpr void test_il_constructor() { auto v = [] { switch (N) { @@ -238,6 +241,7 @@ template constexpr void test_il_assignment() { std::bad_alloc); } } +#endif template constexpr void test_default_constructor() { vector v; @@ -250,6 +254,7 @@ template constexpr void test_default_constructor_bounds_and_contiguous_iterators(std::size_t sz) { CHECK(sz <= N); +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() vector v(sz); CHECK(v.size() == sz); CHECK(v.max_size() == N); @@ -257,6 +262,12 @@ test_default_constructor_bounds_and_contiguous_iterators(std::size_t sz) { for (std::size_t i = 0; i != sz; ++i) { CHECK(v[i] == T{}); } +#else + vector v; + for (auto i = 0; i < sz; ++i) { + v.unchecked_push_back(T{}); + } +#endif for (std::size_t i = 0; i < v.size(); ++i) { // contiguous CHECK(*(v.begin() + i) == *(std::addressof(*v.begin()) + i)); CHECK(*(v.cbegin() + i) == *(std::addressof(*v.cbegin()) + i)); @@ -313,6 +324,7 @@ template constexpr void test_iterators() { } } +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() template constexpr void test_constructor_input_iterators() { CHECK(N < 11); @@ -333,10 +345,16 @@ constexpr void test_constructor_input_iterators() { CHECK(std::distance(i, c.end()) == c.size() - idx); } } +#else +template +constexpr void test_constructor_input_iterators() {} +#endif template constexpr bool test_all_() { +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() test_il_constructor(); test_il_assignment(); +#endif test_default_constructor(); for (size_t i = 0; i < N; ++i) test_default_constructor_bounds_and_contiguous_iterators(i); @@ -351,6 +369,19 @@ template void test_all() { test_all_(); } +template +T vec_of(std::initializer_list il) { +#if BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() + T vec; + for (auto &v : il) { + vec.unchecked_push_back(v); + } + return vec; +#else + return T(il); +#endif +} + int main() { { // storage using beman::details::inplace_vector::storage::non_trivial; @@ -371,6 +402,7 @@ int main() { // test_all(); +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() { // capacity vector a; static_assert(a.capacity() == std::size_t(10)); @@ -694,14 +726,6 @@ int main() { } } - { - constexpr vector v; - static_assert(v.data() != nullptr); - - constexpr vector v0; - static_assert(v0.data() == nullptr); - } - { // emplace: { vector c; @@ -768,6 +792,32 @@ int main() { CHECK(c.back().getd() == 4.5); CHECK_THROWS(c.emplace_back(2, 3.5), std::bad_alloc); } + + { // emplace extra: + { // + vector v; + v = {1, 2, 3}; + + v.emplace(v.begin(), v.back()); + CHECK(v[0] == 3); + } + { + vector v; + v = {1, 2, 3}; + v.emplace(v.begin(), v.back()); + CHECK(v[0] == 3); + } + } +#endif + + { + constexpr vector v; + static_assert(v.data() != nullptr); + + constexpr vector v0; + static_assert(v0.data() == nullptr); + } + { // try_emplace_back vector c; CHECK((uintptr_t)c.begin() == (uintptr_t)c.try_emplace_back(2, 3.5)); @@ -797,26 +847,9 @@ int main() { CHECK(c.back().getd() == 4.5); } - { // emplace extra: - { // - vector v; - v = {1, 2, 3}; - - v.emplace(v.begin(), v.back()); - CHECK(v[0] == 3); - } - { - vector v; - v = {1, 2, 3}; - v.emplace(v.begin(), v.back()); - CHECK(v[0] == 3); - } - } - { // erase { - int a1[] = {1, 2, 3}; - vector l1(a1, a1 + 3); + auto l1 = vec_of>({1, 2, 3}); CHECK(l1.size() == 3); vector::const_iterator i = l1.begin(); ++i; @@ -839,40 +872,40 @@ int main() { } { // erase iter iter - int a1[] = {1, 2, 3}; using vec_t = vector; { - vec_t l1(a1, a1 + 3); + auto l1 = vec_of({1, 2, 3}); vec_t::iterator i = l1.erase(l1.cbegin(), l1.cbegin()); CHECK(l1.size() == 3); CHECK(std::distance(l1.cbegin(), l1.cend()) == 3); CHECK(i == l1.begin()); } { - vec_t l1(a1, a1 + 3); + auto l1 = vec_of({1, 2, 3}); vec_t::iterator i = l1.erase(l1.cbegin(), std::next(l1.cbegin())); CHECK(l1.size() == 2); CHECK(std::distance(l1.cbegin(), l1.cend()) == 2); CHECK(i == l1.begin()); - CHECK(l1 == vec_t(a1 + 1, a1 + 3)); + CHECK(l1 == vec_of({2, 3})); } { - vec_t l1(a1, a1 + 3); + auto l1 = vec_of({1, 2, 3}); vec_t::iterator i = l1.erase(l1.cbegin(), std::next(l1.cbegin(), 2)); CHECK(l1.size() == 1); CHECK(std::distance(l1.cbegin(), l1.cend()) == 1); CHECK(i == l1.begin()); - CHECK(l1 == vec_t(a1 + 2, a1 + 3)); + CHECK(l1 == vec_of({3})); } { - vec_t l1(a1, a1 + 3); + auto l1 = vec_of({1, 2, 3}); vec_t::iterator i = l1.erase(l1.cbegin(), std::next(l1.cbegin(), 3)); CHECK(l1.empty()); CHECK(std::distance(l1.cbegin(), l1.cend()) == 0); CHECK(i == l1.begin()); } { - vector outer(2, vec_t(1)); + auto outer = + vec_of>({vec_of({1}), vec_of({1})}); outer.erase(outer.begin(), outer.begin()); CHECK(outer.size() == 2); CHECK(outer[0].size() == 1); @@ -880,6 +913,7 @@ int main() { } } +#if !BEMAN_INPLACE_VECTOR_FREESTANDING_DELETED() { // insert init list { vector d(10, 1); @@ -1161,6 +1195,7 @@ int main() { } } } +#endif std::cerr << "TESTS PASSED" << std::endl; return 0; diff --git a/tests/beman/inplace_vector/size_n_data.test.cpp b/tests/beman/inplace_vector/size_n_data.test.cpp index 1d45fc8..874d3ea 100644 --- a/tests/beman/inplace_vector/size_n_data.test.cpp +++ b/tests/beman/inplace_vector/size_n_data.test.cpp @@ -22,73 +22,10 @@ TYPED_TEST(SizeNCapacity, Capacity) { EXPECT_EQ(device.max_size(), N); } -TYPED_TEST(SizeNCapacity, ResizeDown) { - // constexpr void resize(size_type sz); - // Preconditions: T is Cpp17DefaultInsertable into inplace_vector. - // Effects: If sz < size(), erases the last size() - sz elements from the - // sequence. Otherwise, appends sz - size() default-inserted elements to the - // sequence. Remarks: If an exception is thrown, there are no effects on - // *this. - - using IV = TestFixture::IV; - using T = TestFixture::T; - - auto device = this->unique(); - - auto mid_size = std::midpoint(0ul, device.size()); - device.resize(mid_size); - EXPECT_EQ(device, IV(device.begin(), device.begin() + mid_size)); - - device.resize(0); - EXPECT_EQ(device, IV{}); -} - -TYPED_TEST(SizeNCapacity, ResizeUp) { - // constexpr void resize(size_type sz); - // Preconditions: T is Cpp17DefaultInsertable into inplace_vector. - // Effects: If sz < size(), erases the last size() - sz elements from the - // sequence. Otherwise, appends sz - size() default-inserted elements to the - // sequence. Remarks: If an exception is thrown, there are no effects on - // *this. - - using IV = TestFixture::IV; - using T = TestFixture::T; - - IV device; - - SAFE_EXPECT_THROW(device.resize(device.capacity() + 1), std::bad_alloc); - EXPECT_EQ(device, IV{}); - - if (device.capacity() == 0) - return; - - // Trying to pollute device[0] - device.push_back(T{255}); - device.pop_back(); - EXPECT_TRUE(device.empty()); - - device.resize(1); - EXPECT_EQ(device.size(), 1); - if (std::is_same_v || - std::is_same_v) - EXPECT_EQ(device, IV{T{0}}); - - T front{341}; - device[0] = front; - device.resize(device.capacity()); - EXPECT_EQ(device[0], front); - - if (std::is_same_v || - std::is_same_v) { - IV expected(device.capacity(), T{0}); - expected[0] = front; - EXPECT_EQ(device, expected); - } - - IV before_resize(device); - SAFE_EXPECT_THROW(device.resize(device.capacity() + 1), std::bad_alloc); - EXPECT_EQ(device, before_resize); -} +// These functions are marked as freestand delete. +// See size_n_data_fs.test.cpp. +// +// constexpr void resize(size_type sz); // 23.3.14.4 Data [inplace.vector.data] diff --git a/tests/beman/inplace_vector/size_n_data_fs.test.cpp b/tests/beman/inplace_vector/size_n_data_fs.test.cpp new file mode 100644 index 0000000..df2262a --- /dev/null +++ b/tests/beman/inplace_vector/size_n_data_fs.test.cpp @@ -0,0 +1,80 @@ +#include +#include + +#include "gtest_setup.hpp" + +namespace { +// 23.3.14.3 Size and capacity [inplace.vector.capacity] + +template class SizeNCapacity : public IVBasicTest {}; +TYPED_TEST_SUITE(SizeNCapacity, IVAllTypes); + +TYPED_TEST(SizeNCapacity, ResizeDown) { + // constexpr void resize(size_type sz); + // Preconditions: T is Cpp17DefaultInsertable into inplace_vector. + // Effects: If sz < size(), erases the last size() - sz elements from the + // sequence. Otherwise, appends sz - size() default-inserted elements to the + // sequence. Remarks: If an exception is thrown, there are no effects on + // *this. + + using IV = TestFixture::IV; + using T = TestFixture::T; + + auto device = this->unique(); + + auto mid_size = std::midpoint(0ul, device.size()); + device.resize(mid_size); + EXPECT_EQ(device, IV(device.begin(), device.begin() + mid_size)); + + device.resize(0); + EXPECT_EQ(device, IV{}); +} + +TYPED_TEST(SizeNCapacity, ResizeUp) { + // constexpr void resize(size_type sz); + // Preconditions: T is Cpp17DefaultInsertable into inplace_vector. + // Effects: If sz < size(), erases the last size() - sz elements from the + // sequence. Otherwise, appends sz - size() default-inserted elements to the + // sequence. Remarks: If an exception is thrown, there are no effects on + // *this. + + using IV = TestFixture::IV; + using T = TestFixture::T; + + IV device; + + SAFE_EXPECT_THROW(device.resize(device.capacity() + 1), std::bad_alloc); + EXPECT_EQ(device, IV{}); + + if (device.capacity() == 0) + return; + + // Trying to pollute device[0] + device.push_back(T{255}); + device.pop_back(); + EXPECT_TRUE(device.empty()); + + device.resize(1); + EXPECT_EQ(device.size(), 1); + if (std::is_same_v || + std::is_same_v) + EXPECT_EQ(device, IV{T{0}}); + + T front{341}; + device[0] = front; + device.resize(device.capacity()); + EXPECT_EQ(device[0], front); + + if (std::is_same_v || + std::is_same_v) { + IV expected(device.capacity(), T{0}); + expected[0] = front; + EXPECT_EQ(device, expected); + } + + IV before_resize(device); + SAFE_EXPECT_THROW(device.resize(device.capacity() + 1), std::bad_alloc); + EXPECT_EQ(device, before_resize); +} + +}; // namespace