From 3e4f6c4666e1bdb0728eb9d13b87ba5038d5f4d7 Mon Sep 17 00:00:00 2001 From: Scott Dixon Date: Tue, 15 Aug 2023 15:19:50 -0700 Subject: [PATCH] \#55 adding assign to VLA --- .vscode/settings.json | 3 +- .../test_variable_length_array_bool.cpp | 16 ++++ .../test_variable_length_array_compat.cpp | 89 ++++++++++++++++++- include/cetl/variable_length_array.hpp | 63 ++++++++++++- 4 files changed, 166 insertions(+), 5 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 677f32d1..dff984b3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -179,6 +179,7 @@ "strstream": "cpp", "typeindex": "cpp", "charconv": "cpp", - "csignal": "cpp" + "csignal": "cpp", + "format": "cpp" } } diff --git a/cetlvast/suites/unittest/test_variable_length_array_bool.cpp b/cetlvast/suites/unittest/test_variable_length_array_bool.cpp index 9e57d746..7534642f 100644 --- a/cetlvast/suites/unittest/test_variable_length_array_bool.cpp +++ b/cetlvast/suites/unittest/test_variable_length_array_bool.cpp @@ -232,3 +232,19 @@ TYPED_TEST(VLABoolTests, TestBoolIterator) ASSERT_EQ(true, *(foo.cend() - 1)); ASSERT_EQ(true, foo.cbegin()[2]); } + +TYPED_TEST(VLABoolTests, TestBoolResize) +{ + auto array = TypeParam::make_bool_container(); + array.resize(15); + ASSERT_EQ(15, array.size()); + ASSERT_EQ(false, array[8]); +} + +TYPED_TEST(VLABoolTests, TestBoolResizeWithDefault) +{ + auto array = TypeParam::make_bool_container(); + array.resize(22, true); + ASSERT_EQ(22, array.size()); + ASSERT_EQ(true, array[8]); +} diff --git a/cetlvast/suites/unittest/test_variable_length_array_compat.cpp b/cetlvast/suites/unittest/test_variable_length_array_compat.cpp index 6f9719b8..9bc34a5a 100644 --- a/cetlvast/suites/unittest/test_variable_length_array_compat.cpp +++ b/cetlvast/suites/unittest/test_variable_length_array_compat.cpp @@ -255,7 +255,7 @@ class CetlUnsynchronizedArrayMemoryResourceFactory return delegate_.reallocate(p, old_size_bytes, new_size_bytes, alignment); } - std::array memory_; + std::array memory_; cetl::pmr::UnsynchronizedBufferMemoryResourceDelegate delegate_; }; @@ -662,6 +662,62 @@ TYPED_TEST(VLATestsGeneric, TestOverMaxSize) #endif } +// +-------------------------------------------------------------------------------------------------------------------+ + +TYPED_TEST(VLATestsGeneric, TestResize) +{ + typename TestFixture::SubjectType subject{TestFixture::make_allocator()}; + + std::size_t clamped_max = std::min(this->get_expected_max_size(), 10UL); + ASSERT_GT(this->get_expected_max_size(), 0) << "This test is only valid if get_expected_max_size() > 0"; + ASSERT_GT(clamped_max, subject.size()); + subject.resize(clamped_max); + ASSERT_EQ(clamped_max, subject.size()); + + typename TestFixture::SubjectType::value_type default_constructed_value{}; + ASSERT_EQ(subject[subject.size() - 1], default_constructed_value); +} + +// +-------------------------------------------------------------------------------------------------------------------+ + +TYPED_TEST(VLATestsGeneric, TestResizeWithCopy) +{ + if (std::is_same::value) + { + GTEST_SKIP() << "Skipping test that requires CETL reallocation support."; + } + + typename TestFixture::SubjectType subject{TestFixture::make_allocator()}; + + std::size_t clamped_max = std::min(this->get_expected_max_size(), 10UL); + ASSERT_GT(this->get_expected_max_size(), 1) << "This test is only valid if get_expected_max_size() > 1"; + ASSERT_GT(clamped_max, subject.size()); + + subject.push_back(1); + + const typename TestFixture::SubjectType::value_type copy_from_value{2}; + subject.resize(clamped_max, copy_from_value); + ASSERT_EQ(clamped_max, subject.size()); + ASSERT_EQ(1, subject[0]); + + for (std::size_t i = 1; i < subject.size(); ++i) + { + ASSERT_EQ(subject[i], copy_from_value); + } +} + +// +----------------------------------------------------------------------+ + +#ifdef __cpp_exceptions + +TYPED_TEST(VLATestsGeneric, TestResizeExceptionLengthError) +{ + typename TestFixture::SubjectType subject{TestFixture::make_allocator()}; + ASSERT_THROW(subject.resize(subject.max_size() + 1), std::length_error); +} + +#endif // __cpp_exceptions + // +----------------------------------------------------------------------+ /** * Test suite to ensure non-trivial objects are properly handled. This one is both for bool and non-bool spec. @@ -1036,3 +1092,34 @@ TEST(VLATestsNonTrivialSpecific, TestMoveAssignment) ASSERT_NE(lhs, rhs); ASSERT_EQ(std::string("three"), lhs[0]); } + +#ifdef __cpp_exceptions + +struct GrenadeError : public std::runtime_error +{ + GrenadeError(const char* message) + : std::runtime_error(message) + { + } +}; + +struct Grenade +{ + Grenade(int value) + { + if (value == 2) + { + throw GrenadeError(""); + } + } +}; + +TYPED_TEST(VLATestsGeneric, TestResizeExceptionFromCtorOnResize) +{ + std::allocator allocator{}; + cetl::VariableLengthArray> subject{{Grenade{1}}, allocator}; + ASSERT_EQ(1, subject.size()); + ASSERT_THROW(subject.resize(2, Grenade{2}), GrenadeError); +} + +#endif // __cpp_exceptions diff --git a/include/cetl/variable_length_array.hpp b/include/cetl/variable_length_array.hpp index 77fcece8..b5e95fd4 100644 --- a/include/cetl/variable_length_array.hpp +++ b/include/cetl/variable_length_array.hpp @@ -6,7 +6,7 @@ /// Copyright Amazon.com Inc. or its affiliates. /// SPDX-License-Identifier: MIT /// -/// cSpell:ignore cend cbegin rnext rend lnext lbegin pocca pocma +/// cSpell:ignore cend cbegin rnext rend lnext lbegin pocca pocma urvo #ifndef CETL_VARIABLE_LENGTH_ARRAY_HPP_INCLUDED #define CETL_VARIABLE_LENGTH_ARRAY_HPP_INCLUDED @@ -1394,8 +1394,6 @@ class VariableLengthArray : protected VariableLengthArrayBase data_[--size_].~value_type(); } } - - /// /// Like push_back but constructs the object directly in uninitialized memory. /// @throw throw std::length_error if there was not enough storage for an additional element. /// If exceptions are disabled then the caller must check the array size before and @@ -1415,6 +1413,35 @@ class VariableLengthArray : protected VariableLengthArrayBase size_++; } + /// Resizes internal storage to count elements default initializing any added elements over the + /// current size() and deleting any elements under the current size(). If size() == `count` then + /// this method has no effect. + /// + /// @param count The new size to set for this container. + /// @throw * If exceptions are enabled then any exceptions that `value_type` constructors or destructors + /// throw will escape this call + /// @throw std::length_error if the size requested is greater than `max_size()`. + /// @throw std::bad_alloc if the container cannot obtain enough memory to size up to `count`. + constexpr void resize(size_type count) + { + Base::resize(count, max_size()); + } + + /// Resizes internal storage to count elements copy-initializing any added elements over the + /// current size() and deleting any elements under the current size(). If size() == `count` then + /// this method has no effect. + /// + /// @param count The new size to set for this container. + /// @param value The value to copy into any new elements created by the operation. + /// @throw * If exceptions are enabled then any exceptions that `value_type` constructors or destructors + /// throw will escape this call + /// @throw std::length_error if the size requested is greater than `max_size()`. + /// @throw std::bad_alloc if the container cannot obtain enough memory to size up to `count`. + constexpr void resize(size_type count, const value_type& value) + { + Base::resize(count, max_size(), value); + } + private: // +----------------------------------------------------------------------+ @@ -2117,6 +2144,36 @@ class VariableLengthArray : protected VariableLengthArrayBase