diff --git a/README.md b/README.md index 77c4889..2d39643 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Contributions are welcome. #include -using namespace beman; +using namespace beman::inplace_vector; /** * Generates fibonacci sequence using inplace_vector. @@ -93,21 +93,21 @@ Note this is not part of the standard Library and should not be relied on once `constexpr` requirement stabilize. Example Usage: -`static_assert(beman::has_constexpr_support>)`. +`static_assert(beman::has_constexpr_support>)`. ### Freestanding -`beman::freestanding::inplace_vector` implements a minimal freestanding version of the specification, +`beman::inplace_vector::freestanding::inplace_vector` implements a minimal freestanding version of the specification, which marks all potentially throwing functions as `= deleted`. This is useful for platforms without exception support, as it will generate a compile-time error instead of a potential runtime error when trying to use a throwing function. ``` C++ -beman::inplace_vector iv; +beman::inplace_vector::inplace_vector iv; iv.resize(0); // OK iv.resize(10); // will throw or abort -beman::freestanding::inplace_vector fs_iv; +beman::inplace_vector::freestanding::inplace_vector fs_iv; fs_iv.resize(0); // will generate a compile-time error fs_iv.resize(10); // will generate a compile-time error ``` diff --git a/examples/fibonacci.cpp b/examples/fibonacci.cpp index b2d1e17..c06bf44 100644 --- a/examples/fibonacci.cpp +++ b/examples/fibonacci.cpp @@ -4,7 +4,7 @@ #include -using namespace beman; +using namespace beman::inplace_vector; /** * Generates fibonacci sequence using inplace_vector. diff --git a/include/beman/inplace_vector/inplace_vector.hpp b/include/beman/inplace_vector/inplace_vector.hpp index cb1adf8..6341d0b 100644 --- a/include/beman/inplace_vector/inplace_vector.hpp +++ b/include/beman/inplace_vector/inplace_vector.hpp @@ -37,14 +37,11 @@ #endif #endif -// beman::from_range_t -namespace beman { +// Private utilities +namespace beman::inplace_vector::details { + struct from_range_t {}; inline constexpr from_range_t from_range; -}; // namespace beman - -// Private utilities -namespace beman::details::inplace_vector { // clang-format off // Smallest unsigned integer that can represent values in [0, N]. @@ -80,10 +77,7 @@ concept lessthan_comparable = requires(const T &a, const T &b) { { a < b } -> std::convertible_to; }; -} // namespace beman::details::inplace_vector - // Types implementing the `inplace_vector`'s storage -namespace beman::details::inplace_vector { namespace storage { // Storage for zero elements. @@ -271,22 +265,20 @@ struct inplace_vector_base : private storage::storage_for { // element access constexpr reference operator[](size_type n) { - return details::inplace_vector::index(*this, n); + return details::index(*this, n); } constexpr const_reference operator[](size_type n) const { - return details::inplace_vector::index(*this, n); - } - constexpr reference front() { - return details::inplace_vector::index(*this, size_type(0)); + return details::index(*this, n); } + constexpr reference front() { return details::index(*this, size_type(0)); } constexpr const_reference front() const { - return details::inplace_vector::index(*this, size_type(0)); + return details::index(*this, size_type(0)); } constexpr reference back() { - return details::inplace_vector::index(*this, size() - size_type(1)); + return details::index(*this, size() - size_type(1)); } constexpr const_reference back() const { - return details::inplace_vector::index(*this, size() - size_type(1)); + return details::index(*this, size() - size_type(1)); } // [containers.sequences.inplace_vector.data], data access @@ -361,7 +353,7 @@ struct inplace_vector_base : private storage::storage_for { return unchecked_emplace_back(std::forward(x)); } - template R> + template R> constexpr std::ranges::borrowed_iterator_t try_append_range(R &&rg) requires(std::constructible_from>) { @@ -428,7 +420,7 @@ struct inplace_vector_base : private storage::storage_for { constexpr friend auto operator<=>(const inplace_vector_base &x, const inplace_vector_base &y) - requires(beman::details::inplace_vector::lessthan_comparable) + requires(details::lessthan_comparable) { if constexpr (std::three_way_comparable) { return std::lexicographical_compare_three_way(x.begin(), x.end(), @@ -514,19 +506,17 @@ struct inplace_vector_base : private storage::storage_for { } }; -} // namespace beman::details::inplace_vector +} // namespace beman::inplace_vector::details -namespace beman { +namespace beman::inplace_vector { template concept has_constexpr_support = - details::inplace_vector::satify_constexpr; + details::satify_constexpr; /// Dynamically-resizable fixed-N vector with inplace storage. template -struct inplace_vector - : public details::inplace_vector::inplace_vector_base { +struct inplace_vector : public details::inplace_vector_base { using value_type = T; using pointer = T *; using const_pointer = const T *; @@ -563,7 +553,7 @@ struct inplace_vector return this->back(); } - template R> + template R> constexpr void append_range(R &&rg) requires(std::constructible_from>) { @@ -614,7 +604,7 @@ struct inplace_vector return pos; } - template R> + template R> constexpr iterator insert_range(const_iterator position, R &&rg) requires(std::constructible_from> && std::movable) @@ -672,7 +662,7 @@ struct inplace_vector this->clear(); insert(this->begin(), first, last); } - template R> + template R> constexpr void assign_range(R &&rg) requires(std::constructible_from> && std::movable) @@ -738,13 +728,13 @@ struct inplace_vector if (pos >= this->size()) [[unlikely]] { BEMAN_IV_THROW_OR_ABORT(std::out_of_range("inplace_vector::at")); } - return details::inplace_vector::index(*this, pos); + return details::index(*this, pos); } constexpr const_reference at(size_type pos) const { if (pos >= this->size()) [[unlikely]] { BEMAN_IV_THROW_OR_ABORT(std::out_of_range("inplace_vector::at")); } - return details::inplace_vector::index(*this, pos); + return details::index(*this, pos); } // [containers.sequences.inplace_vector.cons], construct/copy/destroy @@ -780,8 +770,8 @@ struct inplace_vector insert(this->begin(), first, last); } - template R> - constexpr inplace_vector(beman::from_range_t, R &&rg) + template R> + constexpr inplace_vector(details::from_range_t, R &&rg) requires(std::constructible_from> && std::movable) { @@ -791,8 +781,7 @@ struct inplace_vector namespace freestanding { template -struct inplace_vector - : public details::inplace_vector::inplace_vector_base { +struct inplace_vector : public details::inplace_vector_base { using value_type = T; using pointer = T *; using const_pointer = const T *; @@ -818,7 +807,7 @@ struct inplace_vector requires(std::constructible_from) = delete; - template R> + template R> constexpr void append_range(R &&rg) requires(std::constructible_from>) = delete; @@ -835,7 +824,7 @@ struct inplace_vector std::movable) = delete; - template R> + template R> constexpr iterator insert_range(const_iterator position, R &&rg) requires(std::constructible_from> && std::movable) @@ -871,7 +860,7 @@ struct inplace_vector requires(std::constructible_from> && std::movable) = delete; - template R> + template R> constexpr void assign_range(R &&rg) requires(std::constructible_from> && std::movable) @@ -925,8 +914,8 @@ struct inplace_vector std::movable) = delete; - template R> - constexpr inplace_vector(beman::from_range_t, R &&rg) + template R> + constexpr inplace_vector(beman::inplace_vector::details::from_range_t, R &&rg) requires(std::constructible_from> && std::movable) = delete; @@ -935,8 +924,8 @@ struct inplace_vector } // namespace freestanding template -constexpr std::size_t -erase(details::inplace_vector::inplace_vector_base &c, const U &value) { +constexpr std::size_t erase(details::inplace_vector_base &c, + const U &value) { auto it = std::remove(c.begin(), c.end(), value); auto r = std::distance(it, c.end()); c.erase(it, c.end()); @@ -944,16 +933,15 @@ erase(details::inplace_vector::inplace_vector_base &c, const U &value) { } template -constexpr std::size_t -erase_if(details::inplace_vector::inplace_vector_base &c, - Predicate pred) { +constexpr std::size_t erase_if(details::inplace_vector_base &c, + Predicate pred) { auto it = std::remove_if(c.begin(), c.end(), pred); auto r = std::distance(it, c.end()); c.erase(it, c.end()); return r; } -} // namespace beman +} // namespace beman::inplace_vector #undef IV_EXPECT diff --git a/tests/beman/inplace_vector/compare.test.cpp b/tests/beman/inplace_vector/compare.test.cpp index cdaa458..61178fe 100644 --- a/tests/beman/inplace_vector/compare.test.cpp +++ b/tests/beman/inplace_vector/compare.test.cpp @@ -4,7 +4,7 @@ #include #include -using namespace beman; +using namespace beman::inplace_vector; template concept has_threeway = requires(const T &t) { @@ -13,7 +13,7 @@ concept has_threeway = requires(const T &t) { template concept lessthan_comparable = - beman::details::inplace_vector::lessthan_comparable; + beman::inplace_vector::details::lessthan_comparable; template struct vec_list { T empty; diff --git a/tests/beman/inplace_vector/constexpr.test.cpp b/tests/beman/inplace_vector/constexpr.test.cpp index 965b4ec..4fce8a6 100644 --- a/tests/beman/inplace_vector/constexpr.test.cpp +++ b/tests/beman/inplace_vector/constexpr.test.cpp @@ -31,8 +31,8 @@ struct Some { }; static_assert(std::is_trivial_v); -using beman::has_constexpr_support; -using beman::inplace_vector; +using beman::inplace_vector::has_constexpr_support; +using beman::inplace_vector::inplace_vector; static_assert(has_constexpr_support>); static_assert(has_constexpr_support>); @@ -45,8 +45,8 @@ static_assert(!has_constexpr_support, 50>>); #define TEST(NAME) \ static_assert(std::invoke([]() { \ - NAME>(); \ - NAME>(); \ + NAME>(); \ + NAME>(); \ return true; \ }), \ "##NAME"); @@ -70,7 +70,7 @@ template constexpr void test_constructors() { IV v(arr.begin(), arr.end()); } { - IV v(beman::from_range_t{}, arr); + IV v(beman::inplace_vector::details::from_range_t{}, arr); } { IV other{0, 1}; @@ -269,8 +269,8 @@ TEST(test_op_comp); template constexpr void test_erase() { IV v{0, 1, 2, 3, 3, 5}; - (void)beman::erase(v, 3); - (void)beman::erase_if(v, [](auto v) { return v < 3; }); + (void)beman::inplace_vector::erase(v, 3); + (void)beman::inplace_vector::erase_if(v, [](auto v) { return v < 3; }); } TEST(test_erase) @@ -298,7 +298,7 @@ static_assert(!has_constexpr_support>); template constexpr void speical_test_empty() { static_assert(!std::is_trivially_default_constructible_v); - using IV = beman::inplace_vector; + using IV = beman::inplace_vector::inplace_vector; std::array arr; arr.fill(T{50}); diff --git a/tests/beman/inplace_vector/constructors.test.cpp b/tests/beman/inplace_vector/constructors.test.cpp index 98fc55c..12cd04d 100644 --- a/tests/beman/inplace_vector/constructors.test.cpp +++ b/tests/beman/inplace_vector/constructors.test.cpp @@ -115,7 +115,7 @@ TYPED_TEST(Constructors, CopyRanges) { auto reference = this->unique(); { - IV device(beman::from_range, reference); + IV device(beman::inplace_vector::details::from_range, reference); EXPECT_EQ(device, reference); } @@ -123,13 +123,15 @@ TYPED_TEST(Constructors, CopyRanges) { return; { - IV device(beman::from_range, reference | std::ranges::views::take(1)); + IV device(beman::inplace_vector::details::from_range, + reference | std::ranges::views::take(1)); EXPECT_EQ(device, IV{reference.front()}); } { auto mid = std::midpoint(0ul, reference.size()); - IV device(beman::from_range, reference | std::ranges::views::take(mid)); + IV device(beman::inplace_vector::details::from_range, + reference | std::ranges::views::take(mid)); EXPECT_EQ(device, IV(reference.begin(), reference.begin() + mid)); } } @@ -137,8 +139,8 @@ TYPED_TEST(Constructors, CopyRanges) { TYPED_TEST(Constructors, freestandingConversion) { using T = TestFixture::T; - using IV = beman::inplace_vector; - using FS = beman::freestanding::inplace_vector; + using IV = beman::inplace_vector::inplace_vector; + using FS = beman::inplace_vector::freestanding::inplace_vector; static_assert(std::is_constructible_v); static_assert(std::is_constructible_v); diff --git a/tests/beman/inplace_vector/erasure.test.cpp b/tests/beman/inplace_vector/erasure.test.cpp index d446458..072e257 100644 --- a/tests/beman/inplace_vector/erasure.test.cpp +++ b/tests/beman/inplace_vector/erasure.test.cpp @@ -35,7 +35,7 @@ TYPED_TEST(Erasure, ByValue) { device.push_back(duplicates); } - beman::erase(device, duplicates); + beman::inplace_vector::erase(device, duplicates); EXPECT_EQ(uniques, device); } @@ -59,8 +59,8 @@ TYPED_TEST(Erasure, ByPred) { for (auto i = 0; i < static_cast(device.capacity()); ++i) device.push_back(T{i}); - beman::erase_if(device, - [&](auto &v) { return v.value > (device.capacity() / 2); }); + beman::inplace_vector::erase_if( + device, [&](auto &v) { return v.value > (device.capacity() / 2); }); EXPECT_TRUE(std::all_of(device.begin(), device.end(), [&](auto val) { return val.value <= (device.capacity() / 2); })); diff --git a/tests/beman/inplace_vector/freestanding.test.cpp b/tests/beman/inplace_vector/freestanding.test.cpp index 9975ea2..89f2de8 100644 --- a/tests/beman/inplace_vector/freestanding.test.cpp +++ b/tests/beman/inplace_vector/freestanding.test.cpp @@ -137,8 +137,8 @@ concept has_insert_initializer = TEST(Freestanding, deleted) { - using IV = beman::inplace_vector; - using FIV = beman::freestanding::inplace_vector; + using IV = beman::inplace_vector::inplace_vector; + using FIV = beman::inplace_vector::freestanding::inplace_vector; using range = std::array; using input_iterator = std::istream_iterator; @@ -160,8 +160,11 @@ TEST(Freestanding, deleted) { static_assert(!std::is_constructible_v); // constexpr inplace_vector(from_range_t, R&& rg); - static_assert(std::is_constructible_v); - static_assert(!std::is_constructible_v); + static_assert( + std::is_constructible_v); + static_assert(!std::is_constructible_v< + FIV, beman::inplace_vector::details::from_range_t, range>); // constexpr inplace_vector(initializer_list il); static_assert(std::is_constructible_v); @@ -256,7 +259,7 @@ TEST(Freestanding, deleted) { } TEST(Freestanding, usage) { - using IV = beman::freestanding::inplace_vector; + using IV = beman::inplace_vector::freestanding::inplace_vector; using T = IV::value_type; IV device; diff --git a/tests/beman/inplace_vector/gtest_setup.hpp b/tests/beman/inplace_vector/gtest_setup.hpp index 1517492..6c9b2c0 100644 --- a/tests/beman/inplace_vector/gtest_setup.hpp +++ b/tests/beman/inplace_vector/gtest_setup.hpp @@ -348,7 +348,7 @@ template class IVBasicTest : public ::testing::Test { public: using T = Param::value_type; inline static constexpr std::size_t N = Param::capacity; - using X = beman::inplace_vector; + using X = beman::inplace_vector::inplace_vector; using IV = X; // Returns IV of size n with unique values diff --git a/tests/beman/inplace_vector/inplace_vector.test.cpp b/tests/beman/inplace_vector/inplace_vector.test.cpp index cfb1d9c..4d3d795 100644 --- a/tests/beman/inplace_vector/inplace_vector.test.cpp +++ b/tests/beman/inplace_vector/inplace_vector.test.cpp @@ -2,7 +2,7 @@ #include #include -using namespace beman; +using namespace beman::inplace_vector; template constexpr void test() { using vec = inplace_vector; diff --git a/tests/beman/inplace_vector/ref_impl.test.cpp b/tests/beman/inplace_vector/ref_impl.test.cpp index 83c0564..553af98 100644 --- a/tests/beman/inplace_vector/ref_impl.test.cpp +++ b/tests/beman/inplace_vector/ref_impl.test.cpp @@ -65,31 +65,32 @@ static constexpr void __assert_failure(char const *__file, int __line, } #endif -template struct beman::details::inplace_vector::storage::zero_sized; -template struct beman::details::inplace_vector::storage::trivial; -template struct beman::details::inplace_vector::storage::non_trivial< +template struct beman::inplace_vector::details::storage::zero_sized; +template struct beman::inplace_vector::details::storage::trivial; +template struct beman::inplace_vector::details::storage::non_trivial< std::unique_ptr, 10>; -template struct beman::details::inplace_vector::storage::zero_sized; -template struct beman::details::inplace_vector::storage::trivial; -template struct beman::details::inplace_vector::storage::non_trivial< +template struct beman::inplace_vector::details::storage::zero_sized; +template struct beman::inplace_vector::details::storage::trivial; +template struct beman::inplace_vector::details::storage::non_trivial< const std::unique_ptr, 10>; // empty: -template struct beman::inplace_vector; +template struct beman::inplace_vector::inplace_vector; // trivial non-empty: -template struct beman::inplace_vector; -template struct beman::inplace_vector; -template struct beman::inplace_vector; +template struct beman::inplace_vector::inplace_vector; +template struct beman::inplace_vector::inplace_vector; +template struct beman::inplace_vector::inplace_vector; // non-trivial -template struct beman::inplace_vector; -template struct beman::inplace_vector; +template struct beman::inplace_vector::inplace_vector; +template struct beman::inplace_vector::inplace_vector; // move-only: -template struct beman::inplace_vector, 3>; -template struct beman::inplace_vector, 3>; +template struct beman::inplace_vector::inplace_vector, 3>; +template struct beman::inplace_vector::inplace_vector< + const std::unique_ptr, 3>; struct tint { std::size_t i; @@ -110,10 +111,13 @@ static_assert(std::is_trivial{} && std::is_copy_constructible{} && ""); // Explicit instantiations -template struct beman::inplace_vector; // trivial empty -template struct beman::inplace_vector; // trivial non-empty -template struct beman::inplace_vector; // trivial non-empty -template struct beman::inplace_vector; // trivial non-empty +template struct beman::inplace_vector::inplace_vector; // trivial empty +template struct beman::inplace_vector::inplace_vector; // trivial non-empty +template struct beman::inplace_vector::inplace_vector; // trivial non-empty +template struct beman::inplace_vector::inplace_vector; // trivial non-empty struct moint final { std::size_t i = 0; @@ -144,7 +148,8 @@ static_assert(!std::is_trivial{} and // template struct std::inplace_vector; // template struct std::inplace_vector; -template using vector = beman::inplace_vector; +template +using vector = beman::inplace_vector::inplace_vector; class non_copyable { int i_; @@ -353,10 +358,10 @@ template void test_all() { int main() { { // storage - using beman::details::inplace_vector::storage::non_trivial; - using beman::details::inplace_vector::storage::storage_for; - using beman::details::inplace_vector::storage::trivial; - using beman::details::inplace_vector::storage::zero_sized; + using beman::inplace_vector::details::storage::non_trivial; + using beman::inplace_vector::details::storage::storage_for; + using beman::inplace_vector::details::storage::trivial; + using beman::inplace_vector::details::storage::zero_sized; static_assert(std::is_same, zero_sized>{}); static_assert(std::is_same, trivial>{}); diff --git a/tests/beman/inplace_vector/size_n_data.test.cpp b/tests/beman/inplace_vector/size_n_data.test.cpp index 1d45fc8..a3595be 100644 --- a/tests/beman/inplace_vector/size_n_data.test.cpp +++ b/tests/beman/inplace_vector/size_n_data.test.cpp @@ -43,6 +43,27 @@ TYPED_TEST(SizeNCapacity, ResizeDown) { EXPECT_EQ(device, IV{}); } +TYPED_TEST(SizeNCapacity, ResizeDownWValue) { + // constexpr void resize(size_type sz, const T& value); + // 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, T{}); + EXPECT_EQ(device, IV(device.begin(), device.begin() + mid_size)); + + device.resize(0, T{}); + EXPECT_EQ(device, IV{}); +} + TYPED_TEST(SizeNCapacity, ResizeUp) { // constexpr void resize(size_type sz); // Preconditions: T is Cpp17DefaultInsertable into inplace_vector. @@ -90,6 +111,52 @@ TYPED_TEST(SizeNCapacity, ResizeUp) { EXPECT_EQ(device, before_resize); } +TYPED_TEST(SizeNCapacity, ResizeUpWValue) { + // constexpr void resize(size_type sz, const T& value); + // 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, T{}), 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, T{0}); + 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(), front); + EXPECT_EQ(device[0], front); + + if (std::is_same_v || + std::is_same_v) { + IV expected(device.capacity(), T{341}); + EXPECT_EQ(device, expected); + } + + IV before_resize(device); + SAFE_EXPECT_THROW(device.resize(device.capacity() + 1, T{}), std::bad_alloc); + EXPECT_EQ(device, before_resize); +} + // 23.3.14.4 Data [inplace.vector.data] template class Data : public IVBasicTest {};