diff --git a/.vscode/settings.json b/.vscode/settings.json index 879390ca..053790b9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -40,44 +40,49 @@ "sonar.cfamily.reportingCppStandardOverride": "c++14" }, "cSpell.words": [ + "arity", + "AUTOSAR", + "builddir", "cetl", - "DCETL_", - "cetlvast", - "DCETLVAST_", - "DCYPHAL", - "cyphal", - "opencyphal", "cetlpf", - "AUTOSAR", - "tparam", - "unsynchronized", + "cetlvast", + "COMPILETEST_PRECHECK", "copydoc", - "trimleft", - "Pavel", - "Kirienko", - "gtest", - "gmock", - "DSDL", - "rend", - "rbegin", - "builddir", - "sonarqube", - "sonarcloud", - "doxygen", - "googletest", - "googlemock", - "DCMAKE_", "ctest", + "cyphal", + "DCETL_", + "DCETLVAST_", + "DCMAKE_", "DCTEST_", - "pushd", - "popd", - "gcovr", + "DCYPHAL", "devcontainer", "DFETCHCONTENT_FULLY_DISCONNECTED", - "COMPILETEST_PRECHECK", - "arity", + "doxygen", + "DSDL", + "endforeach", + "endfunction", + "gcovr", + "gmock", + "googlemock", + "googletest", + "gtest", + "insertable", + "Kirienko", "mainpage", - "subpage" + "NOTFOUND", + "opencyphal", + "Pavel", + "popd", + "pushd", + "rbegin", + "rend", + "sonarcloud", + "sonarqube", + "STREQUAL", + "subpage", + "tparam", + "trimleft", + "unsynchronized" ], "files.associations": { "memory_resource": "cpp", @@ -180,7 +185,9 @@ "typeindex": "cpp", "charconv": "cpp", "csignal": "cpp", - "format": "cpp" + "format": "cpp", + "execution": "cpp", + "filesystem": "cpp" }, "git-blame.gitWebUrl": "" } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 869c952f..a4c6f335 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,7 +67,7 @@ cd CETL docker run --rm -it -v ${PWD}:/repo ghcr.io/opencyphal/toolshed:ts22.4.x ``` 3. run the verify script to configure cetlvast. By including `-vv` you can see -the exact cmake commands verify.py is executing and you and use `--dry-run` +the exact cmake commands verify.py is executing and you can use `--dry-run` if you really hate my python script so much that you want to do all the typing yourself (It's not like I spent a ton of time documenting all of these options for you. No no. It's fine. Don't try to apologize now...): diff --git a/cetlvast/cmake/modules/Findgcovr.cmake b/cetlvast/cmake/modules/Findgcovr.cmake index 7657f3e6..9d1fc8d1 100644 --- a/cetlvast/cmake/modules/Findgcovr.cmake +++ b/cetlvast/cmake/modules/Findgcovr.cmake @@ -3,6 +3,7 @@ # Copyright Amazon.com Inc. or its affiliates. # SPDX-License-Identifier: MIT # +# cSpell: words fprofile fcoverage gcov tracefile objdir gcno gcda objlib tracefiles find_program(GCOVR gcovr) @@ -22,7 +23,7 @@ define_property(DIRECTORY ) # function: enable_instrumentation -# Sets well-known compiler flags for gcc and/or clang to insert intrumentations +# Sets well-known compiler flags for gcc and/or clang to insert instrumentations # into binaries that generate coverage data. # # param: TARGET target - The target to set compile and link options on. @@ -199,12 +200,12 @@ endfunction(define_gcovr_tracefile_target) # # param: COVERAGE_REPORT_FORMATS - Supports html or sonarqube # param: ROOT_DIRECTORY string - The root directory of the source to be covered. -# param: OUT_REPORT_INDICIES list[string] - The name of a variable to set to a list of index files of the reports. +# param: OUT_REPORT_INDICES list[string] - The name of a variable to set to a list of index files of the reports. # function (enable_coverage_report) #+-[input]----------------------------------------------------------------+ set(options "") - set(singleValueArgs OUT_REPORT_INDICIES ROOT_DIRECTORY) + set(singleValueArgs OUT_REPORT_INDICES ROOT_DIRECTORY) set(multiValueArgs COVERAGE_REPORT_FORMATS) cmake_parse_arguments(PARSE_ARGV 0 ARG "${options}" "${singleValueArgs}" "${multiValueArgs}") @@ -241,7 +242,7 @@ function (enable_coverage_report) else() message(FATAL_ERROR "${LOCAL_REPORT_FORMAT} is not a supported coverage report format.") endif() - list(APPEND LOCAL_REPORT_INDICIES ${LOCAL_REPORT_INDEX}) + list(APPEND LOCAL_REPORT_INDICES ${LOCAL_REPORT_INDEX}) add_custom_command( OUTPUT ${LOCAL_REPORT_INDEX} @@ -263,8 +264,8 @@ function (enable_coverage_report) #+-[output]---------------------------------------------------------------+ - if (NOT ARG_OUT_REPORT_INDICIES STREQUAL "") - set(${ARG_OUT_REPORT_INDICIES} "${LOCAL_REPORT_INDICIES}" PARENT_SCOPE) + if (NOT ARG_OUT_REPORT_INDICES STREQUAL "") + set(${ARG_OUT_REPORT_INDICES} "${LOCAL_REPORT_INDICES}" PARENT_SCOPE) endif() endfunction(enable_coverage_report) diff --git a/cetlvast/suites/unittest/CMakeLists.txt b/cetlvast/suites/unittest/CMakeLists.txt index c32ccc60..3ec901c5 100644 --- a/cetlvast/suites/unittest/CMakeLists.txt +++ b/cetlvast/suites/unittest/CMakeLists.txt @@ -89,7 +89,7 @@ set_directory_properties(PROPERTIES if (CMAKE_BUILD_TYPE STREQUAL "Coverage") enable_coverage_report(COVERAGE_REPORT_FORMATS html sonarqube ROOT_DIRECTORY ${CETL_ROOT} - OUT_REPORT_INDICIES LOCAL_COVERAGE_REPORT_INDICIES + OUT_REPORT_INDICES LOCAL_COVERAGE_REPORT_INDICIES ) endif() diff --git a/cetlvast/suites/unittest/test_variable_length_array_compat.cpp b/cetlvast/suites/unittest/test_variable_length_array_compat.cpp index c09919be..07a04edb 100644 --- a/cetlvast/suites/unittest/test_variable_length_array_compat.cpp +++ b/cetlvast/suites/unittest/test_variable_length_array_compat.cpp @@ -137,10 +137,10 @@ TYPED_TEST(VLATestsCompatPrimitiveTypes, SelfAssignment) TYPED_TEST(VLATestsCompatPrimitiveTypes, TestAssignCountItems) { - std::allocator allocator{}; + std::allocator allocator{}; cetl::VariableLengthArray> subject{allocator}; - const TypeParam value0 = std::numeric_limits::max(); - const TypeParam value1 = std::numeric_limits::min(); + const TypeParam value0 = std::numeric_limits::max(); + const TypeParam value1 = std::numeric_limits::min(); subject.assign(16, value0); ASSERT_EQ(16, subject.size()); for (auto i = subject.begin(), e = subject.end(); i != e; ++i) @@ -157,30 +157,50 @@ TYPED_TEST(VLATestsCompatPrimitiveTypes, TestAssignCountItems) // +-------------------------------------------------------------------------------------------------------------------+ // | ANY TYPE -// | These are just the rest of the tests. All ad-hoc and simple. +// | Various type handling across implementations. // +-------------------------------------------------------------------------------------------------------------------+ +template +class VLATestsCompatAnyType : public ::testing::Test +{ +protected: + void SetUp() override + { + cetlvast::InstrumentedAllocatorStatistics::reset(); + } + + template + using TestSubjectType = std::conditional_t::value, + cetl::VariableLengthArray, + std::vector>; +}; +using VLATestsCompatAnyTypeTypes = ::testing::Types; +TYPED_TEST_SUITE(VLATestsCompatAnyType, VLATestsCompatAnyTypeTypes, ); -TEST(VLATestsCompatAnyType, TestDeallocSizeNonBool) +TYPED_TEST(VLATestsCompatAnyType, TestDeallocSizeNonBool) { - cetlvast::InstrumentedAllocatorStatistics& stats = cetlvast::InstrumentedAllocatorStatistics::get(); - cetlvast::InstrumentedNewDeleteAllocator allocator; - cetl::VariableLengthArray subject{allocator}; + cetlvast::InstrumentedAllocatorStatistics& stats = cetlvast::InstrumentedAllocatorStatistics::get(); + cetlvast::InstrumentedNewDeleteAllocator allocator; + typename TestFixture::template TestSubjectType subject{allocator}; subject.reserve(10U); ASSERT_EQ(10U, subject.capacity()); ASSERT_EQ(1U, stats.allocations); ASSERT_EQ(10U * sizeof(int), stats.last_allocation_size_bytes); ASSERT_EQ(0U, stats.last_deallocation_size_bytes); - subject.pop_back(); subject.shrink_to_fit(); - ASSERT_EQ(10U * sizeof(int), stats.last_deallocation_size_bytes); + if (std::is_same::value) + { + /// STL says that any effect shrink_to_fit has is optional and implementation specific. + /// For CETL we requires specific behaviors. + ASSERT_EQ(10U * sizeof(int), stats.last_deallocation_size_bytes); + } } -TEST(VLATestsCompatAnyType, TestPush) +TYPED_TEST(VLATestsCompatAnyType, TestPush) { cetlvast::InstrumentedAllocatorStatistics& stats = cetlvast::InstrumentedAllocatorStatistics::get(); cetlvast::InstrumentedNewDeleteAllocator allocator; - cetl::VariableLengthArray subject{allocator}; + typename TestFixture::template TestSubjectType subject{allocator}; ASSERT_EQ(nullptr, subject.data()); ASSERT_EQ(0U, subject.size()); std::size_t x = 0; @@ -199,8 +219,13 @@ TEST(VLATestsCompatAnyType, TestPush) ASSERT_EQ(0U, subject.size()); ASSERT_GE(subject.capacity(), 1024U); subject.shrink_to_fit(); - ASSERT_EQ(0U, subject.capacity()); - ASSERT_EQ(0U, stats.outstanding_allocated_memory); + if (std::is_same::value) + { + /// STL says that any effect shrink_to_fit has is optional and implementation specific. + /// For CETL we requires specific behaviors. + ASSERT_EQ(0U, subject.capacity()); + ASSERT_EQ(0U, stats.outstanding_allocated_memory); + } } /** @@ -237,12 +262,11 @@ class Doomed bool moved_; }; -TEST(VLATestsCompatAnyType, TestDestroy) +TYPED_TEST(VLATestsCompatAnyType, TestDestroy) { - int dtor_called = 0; - - auto subject = - std::make_shared>>(std::allocator{}); + int dtor_called = 0; + using TestDestroySubjectType = typename TestFixture::template TestSubjectType>; + auto subject = std::make_shared(std::allocator{}); subject->reserve(10); ASSERT_EQ(10U, subject->capacity()); @@ -255,11 +279,11 @@ TEST(VLATestsCompatAnyType, TestDestroy) ASSERT_EQ(2, dtor_called); } -TEST(VLATestsCompatAnyType, TestNonFundamental) +TYPED_TEST(VLATestsCompatAnyType, TestNonFundamental) { int dtor_called = 0; - cetl::VariableLengthArray> subject(std::allocator{}); + typename TestFixture::template TestSubjectType> subject(std::allocator{}); subject.reserve(10U); ASSERT_EQ(10U, subject.capacity()); @@ -269,7 +293,11 @@ TEST(VLATestsCompatAnyType, TestNonFundamental) ASSERT_EQ(1, dtor_called); } -TEST(VLATestsCompatAnyType, TestNotMovable) +#if !defined(__clang__) +/// Clang seems to have a different opinion about this. It statically asserts that a type must be move insertable +/// to use reserve or the internal memory reallocation logic shared by many of the vector routines. GCC and CETL +/// allow degraded behaviour instead where the type is copied if it cannot be moved. +TYPED_TEST(VLATestsCompatAnyType, TestNotMovable) { class NotMovable { @@ -280,8 +308,14 @@ TEST(VLATestsCompatAnyType, TestNotMovable) { (void) rhs; } + NotMovable& operator=(const NotMovable& rhs) noexcept + { + (void) rhs; + return *this; + } }; - cetl::VariableLengthArray> subject(std::allocator{}); + typename TestFixture::template TestSubjectType> subject( + std::allocator{}); subject.reserve(10U); ASSERT_EQ(10U, subject.capacity()); @@ -289,8 +323,9 @@ TEST(VLATestsCompatAnyType, TestNotMovable) subject.push_back(source); ASSERT_EQ(1U, subject.size()); } +#endif -TEST(VLATestsCompatAnyType, TestMovable) +TYPED_TEST(VLATestsCompatAnyType, TestMovable) { class Movable { @@ -313,7 +348,7 @@ TEST(VLATestsCompatAnyType, TestMovable) private: int data_; }; - cetl::VariableLengthArray> subject(std::allocator{}); + typename TestFixture::template TestSubjectType> subject(std::allocator{}); subject.reserve(10U); ASSERT_EQ(10U, subject.capacity()); subject.push_back(Movable(1)); @@ -323,10 +358,10 @@ TEST(VLATestsCompatAnyType, TestMovable) ASSERT_EQ(1, pushed->get_data()); } -TEST(VLATestsCompatAnyType, TestInitializerArray) +TYPED_TEST(VLATestsCompatAnyType, TestInitializerArray) { - cetl::VariableLengthArray> subject{{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - std::allocator{}}; + typename TestFixture::template TestSubjectType> + subject{{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, std::allocator{}}; ASSERT_EQ(10U, subject.size()); for (std::size_t i = 0; i < subject.size(); ++i) { @@ -334,12 +369,12 @@ TEST(VLATestsCompatAnyType, TestInitializerArray) } } -TEST(VLATestsCompatAnyType, TestCopyConstructor) +TYPED_TEST(VLATestsCompatAnyType, TestCopyConstructor) { - cetl::VariableLengthArray> fixture{{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - std::allocator{}}; + typename TestFixture::template TestSubjectType> + fixture{{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, std::allocator{}}; - cetl::VariableLengthArray> subject(fixture); + typename TestFixture::template TestSubjectType> subject(fixture); ASSERT_EQ(10U, subject.size()); for (std::size_t i = 0; i < subject.size(); ++i) { @@ -347,12 +382,13 @@ TEST(VLATestsCompatAnyType, TestCopyConstructor) } } -TEST(VLATestsCompatAnyType, TestMoveConstructor) +TYPED_TEST(VLATestsCompatAnyType, TestMoveConstructor) { - cetl::VariableLengthArray> fixture{{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, - std::allocator{}}; + typename TestFixture::template TestSubjectType> + fixture{{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, std::allocator{}}; - cetl::VariableLengthArray> subject(std::move(fixture)); + typename TestFixture::template TestSubjectType> subject( + std::move(fixture)); ASSERT_EQ(10U, subject.size()); for (std::size_t i = 0; i < subject.size(); ++i) { @@ -362,46 +398,49 @@ TEST(VLATestsCompatAnyType, TestMoveConstructor) ASSERT_EQ(0U, fixture.capacity()); } -TEST(VLATestsCompatAnyType, TestCompare) +TYPED_TEST(VLATestsCompatAnyType, TestCompare) { - std::allocator allocator{}; - cetl::VariableLengthArray> one{{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, allocator}; - cetl::VariableLengthArray> two{{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, allocator}; - cetl::VariableLengthArray> three{{9, 8, 7, 6, 5, 4, 3, 2, 1}, allocator}; + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> + one{{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, allocator}; + typename TestFixture::template TestSubjectType> + two{{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, allocator}; + typename TestFixture::template TestSubjectType> + three{{9, 8, 7, 6, 5, 4, 3, 2, 1}, allocator}; ASSERT_EQ(one, one); ASSERT_EQ(one, two); ASSERT_NE(one, three); } -TEST(VLATestsCompatAnyType, TestFPCompare) +TYPED_TEST(VLATestsCompatAnyType, TestFPCompare) { - std::allocator allocator{}; - cetl::VariableLengthArray> one{{1.00, 2.00}, allocator}; - cetl::VariableLengthArray> two{{1.00, 2.00}, allocator}; + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> one{{1.00, 2.00}, allocator}; + typename TestFixture::template TestSubjectType> two{{1.00, 2.00}, allocator}; const double epsilon_for_two_comparison = std::nextafter(4.00, INFINITY) - 4.00; - cetl::VariableLengthArray> + typename TestFixture::template TestSubjectType> three{{1.00, std::nextafter(2.00 + epsilon_for_two_comparison, INFINITY)}, allocator}; ASSERT_EQ(one, one); ASSERT_EQ(one, two); ASSERT_NE(one, three); } -TEST(VLATestsCompatAnyType, TestCompareBool) +TYPED_TEST(VLATestsCompatAnyType, TestCompareBool) { - std::allocator allocator{}; - cetl::VariableLengthArray> one{{true, false, true}, allocator}; - cetl::VariableLengthArray> two{{true, false, true}, allocator}; - cetl::VariableLengthArray> three{{true, true, false}, allocator}; + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> one{{true, false, true}, allocator}; + typename TestFixture::template TestSubjectType> two{{true, false, true}, allocator}; + typename TestFixture::template TestSubjectType> three{{true, true, false}, allocator}; ASSERT_EQ(one, one); ASSERT_EQ(one, two); ASSERT_NE(one, three); } -TEST(VLATestsCompatAnyType, TestCopyAssignment) +TYPED_TEST(VLATestsCompatAnyType, TestCopyAssignment) { - std::allocator allocator{}; - cetl::VariableLengthArray> lhs{{1.00}, allocator}; - cetl::VariableLengthArray> rhs{{2.00, 3.00}, allocator}; + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> lhs{{1.00}, allocator}; + typename TestFixture::template TestSubjectType> rhs{{2.00, 3.00}, allocator}; ASSERT_EQ(1U, lhs.size()); ASSERT_EQ(2U, rhs.size()); ASSERT_NE(lhs, rhs); @@ -411,15 +450,16 @@ TEST(VLATestsCompatAnyType, TestCopyAssignment) ASSERT_EQ(lhs, rhs); } -TEST(VLATestsCompatAnyType, TestMoveAssignment) +TYPED_TEST(VLATestsCompatAnyType, TestMoveAssignment) { - std::allocator allocator{}; - cetl::VariableLengthArray> lhs{{std::string("one"), std::string("two")}, - allocator}; - cetl::VariableLengthArray> rhs{{std::string("three"), - std::string("four"), - std::string("five")}, - allocator}; + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> lhs{{std::string("one"), + std::string("two")}, + allocator}; + typename TestFixture::template TestSubjectType> rhs{{std::string("three"), + std::string("four"), + std::string("five")}, + allocator}; ASSERT_EQ(2U, lhs.size()); ASSERT_EQ(3U, rhs.size()); ASSERT_NE(lhs, rhs); @@ -451,10 +491,11 @@ struct NoDefault int data_; }; -TEST(VLATestsCompatAnyType, TestResizeWithNoDefaultCtorData) +TYPED_TEST(VLATestsCompatAnyType, TestResizeWithNoDefaultCtorData) { - std::allocator allocator{}; - cetl::VariableLengthArray> subject{{NoDefault{1}}, allocator}; + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> subject{{NoDefault{1}}, + allocator}; ASSERT_EQ(1, subject.size()); subject.resize(10, NoDefault{2}); ASSERT_EQ(10, subject.size()); @@ -490,24 +531,66 @@ struct Grenade throw GrenadeError("Kaboom!"); } } + + Grenade& operator=(const Grenade& rhs) + { + value_ = rhs.value_; + return *this; + } + + int value() const + { + return value_; + } + private: int value_; }; -TEST(VLATestsCompatAnyType, TestResizeExceptionFromCtorOnResize) +TYPED_TEST(VLATestsCompatAnyType, TestResizeExceptionFromCtorOnResize) { - std::allocator allocator{}; - cetl::VariableLengthArray> subject{{Grenade{1}}, allocator}; + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> subject{{Grenade{1}}, allocator}; ASSERT_EQ(1, subject.size()); ASSERT_THROW(subject.resize(2, Grenade{2}), GrenadeError); } +TYPED_TEST(VLATestsCompatAnyType, TestAt) +{ + // Grenade shouldn't explode if we are just accessing a reference value using at() + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> subject{{Grenade{1}}, allocator}; + ASSERT_EQ(1, subject.size()); + ASSERT_EQ(1, subject.at(0).value()); + ASSERT_EQ(1, reinterpret_cast(&subject)->at(0).value()); +} + +TYPED_TEST(VLATestsCompatAnyType, TestAtThrows) +{ + // Grenade shouldn't explode if we are just accessing a reference value using at() + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> subject{{5}, allocator}; + ASSERT_EQ(1, subject.size()); + ASSERT_THROW(subject.at(1), std::out_of_range); + ASSERT_THROW(subject.at(2), std::out_of_range); +} + +TYPED_TEST(VLATestsCompatAnyType, TestConstAtThrows) +{ + // Grenade shouldn't explode if we are just accessing a reference value using at() + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> subject{{2}, allocator}; + ASSERT_EQ(1, subject.size()); + ASSERT_THROW(reinterpret_cast(&subject)->at(1), std::out_of_range); + ASSERT_THROW(reinterpret_cast(&subject)->at(2), std::out_of_range); +} + #endif // __cpp_exceptions -TEST(VLATestsCompatAnyType, TestAssignCountItems) +TYPED_TEST(VLATestsCompatAnyType, TestAssignCountItems) { - std::allocator allocator{}; - cetl::VariableLengthArray> subject{allocator}; + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> subject{allocator}; subject.assign(25, "Hi müm"); ASSERT_EQ(25, subject.size()); for (auto i = subject.begin(), e = subject.end(); i != e; ++i) @@ -522,3 +605,16 @@ TEST(VLATestsCompatAnyType, TestAssignCountItems) ASSERT_EQ(*i, "ciao"); } } + +TYPED_TEST(VLATestsCompatAnyType, TestInitFromString) +{ + std::string data = "stuff."; + std::allocator allocator{}; + typename TestFixture::template TestSubjectType> + subject{data.begin(), data.end(), allocator}; + + ASSERT_GT(subject.size(), 0u); + ASSERT_EQ(data.size(), subject.size()); + ASSERT_EQ('s', subject[0]); + ASSERT_EQ('.', subject[subject.size() - 1]); +} diff --git a/cetlvast/suites/unittest/test_variable_length_array_debug_asserts.cpp b/cetlvast/suites/unittest/test_variable_length_array_debug_asserts.cpp index 1f48368f..0d0c191a 100644 --- a/cetlvast/suites/unittest/test_variable_length_array_debug_asserts.cpp +++ b/cetlvast/suites/unittest/test_variable_length_array_debug_asserts.cpp @@ -112,7 +112,7 @@ static void TestConstFrontOnEmpty() { flush_coverage_on_death(); const cetl::VariableLengthArray > vla{std::allocator()}; - (void)vla.front(); + (void)reinterpret_cast(&vla)->front(); } TEST(DeathTestVLAAssertions, TestConstFrontOnEmpty) @@ -144,7 +144,7 @@ static void TestConstFrontOnEmptyBool() { flush_coverage_on_death(); const cetl::VariableLengthArray > vla{std::allocator()}; - (void)vla.front(); + (void)reinterpret_cast(&vla)->front(); } TEST(DeathTestVLAAssertions, TestConstFrontOnEmptyBool) @@ -176,7 +176,7 @@ static void TestConstBackOnEmpty() { flush_coverage_on_death(); const cetl::VariableLengthArray > vla{std::allocator()}; - (void)vla.back(); + (void)reinterpret_cast(&vla)->back(); } TEST(DeathTestVLAAssertions, TestConstBackOnEmpty) @@ -208,7 +208,7 @@ static void TestConstBackOnEmptyBool() { flush_coverage_on_death(); const cetl::VariableLengthArray > vla{std::allocator()}; - (void)vla.back(); + (void)reinterpret_cast(&vla)->back(); } TEST(DeathTestVLAAssertions, TestConstBackOnEmptyBool) diff --git a/include/cetl/variable_length_array.hpp b/include/cetl/variable_length_array.hpp index f0bf21a3..ae403cba 100644 --- a/include/cetl/variable_length_array.hpp +++ b/include/cetl/variable_length_array.hpp @@ -259,11 +259,9 @@ class VariableLengthArrayBase /// Copy from src to dst. /// @return the number of elements copied. /// - template - static constexpr size_type fast_copy_assign( - DstType* const dst, - size_type dst_capacity_count, - const SrcType& src) noexcept(noexcept(std::is_nothrow_assignable::value)) + template + static constexpr size_type fast_copy_assign(value_type* dst, size_type dst_capacity_count, InputIt src) noexcept( + noexcept(std::is_nothrow_assignable>::value)) { if (nullptr == dst) { @@ -277,12 +275,13 @@ class VariableLengthArrayBase /// Copy from src to dst. /// @return the number of elements copied. /// - template + template static constexpr size_type fast_copy_assign( - DstType* const dst, - size_type dst_capacity_count, - const SrcType* const src, - size_type src_len_count) noexcept(noexcept(std::is_nothrow_assignable::value)) + value_type* dst, + size_type dst_capacity_count, + InputIt src, + size_type src_len_count) noexcept(noexcept(std::is_nothrow_assignable>::value)) { if (nullptr == dst || nullptr == src) { @@ -301,14 +300,15 @@ class VariableLengthArrayBase /// Copy from src to dst. /// @return the number of elements copied. /// - template + template static constexpr size_type fast_copy_construct( - DstType* const dst, - size_type dst_capacity_count, - const SrcType* const src, - size_type src_len_count, - allocator_type& alloc, - typename std::enable_if_t::value>* = nullptr) noexcept + value_type* const dst, + size_type dst_capacity_count, + const InputIt src, + size_type src_len_count, + allocator_type& alloc, + typename std::enable_if_t< + is_array_of_type_trivially_copyable, InputIt>::value>* = nullptr) noexcept { (void) alloc; // for trivial copyable assignment is the same as construction: @@ -319,27 +319,27 @@ class VariableLengthArrayBase /// Copy from src to dst. /// @return the number of elements copied. /// - template + template static constexpr size_type fast_copy_construct( - DstType* const dst, - size_type dst_capacity_count, - const SrcType* const src, - size_type src_len_count, - allocator_type& alloc, - typename std::enable_if_t::value>* = + value_type* const dst, + size_type dst_capacity_count, + const InputIt src, + size_type src_len_count, + allocator_type& alloc, + typename std::enable_if_t< + !is_array_of_type_trivially_copyable, InputIt>::value>* = nullptr) noexcept(noexcept(std::allocator_traits:: construct(std::declval>(), - std::declval>(), - std::declval>()))) + std::declval>(), + std::declval()[0])>>()))) { - if (nullptr == dst || nullptr == src) - { - return 0; - } const size_type max_copy_size = std::min(dst_capacity_count, src_len_count); for (size_type i = 0; i < max_copy_size; ++i) { - std::allocator_traits::construct(alloc, &dst[i], src[i]); + std::allocator_traits::construct(alloc, + &dst[static_cast(i)], + src[static_cast(i)]); } return max_copy_size; } @@ -347,33 +347,31 @@ class VariableLengthArrayBase // +----------------------------------------------------------------------+ // | FORWARD CONSTRUCTION // +----------------------------------------------------------------------+ - template + template static constexpr size_type fast_forward_construct( - DstType* const dst, - size_type dst_capacity_count, - SrcType* const src, - size_type src_len_count, - allocator_type& alloc, - typename std::enable_if_t::value>* = nullptr) + value_type* const dst, + size_type dst_capacity_count, + InputIt src, + size_type src_len_count, + allocator_type& alloc, + typename std::enable_if_t< + is_array_of_type_trivially_copyable, InputIt>::value>* = nullptr) { (void) alloc; // for trivial copyable assignment move is the same as copy: return fast_copy_assign(dst, dst_capacity_count, src, src_len_count); } - template + template static constexpr size_type fast_forward_construct( - DstType* const dst, - size_type dst_capacity_count, - SrcType* const src, - size_type src_len_count, - allocator_type& alloc, - typename std::enable_if_t::value>* = nullptr) + value_type* const dst, + size_type dst_capacity_count, + InputIt src, + size_type src_len_count, + allocator_type& alloc, + typename std::enable_if_t< + !is_array_of_type_trivially_copyable, InputIt>::value>* = nullptr) { - if (nullptr == dst || nullptr == src) - { - return 0; - } const size_type max_copy_size = std::min(dst_capacity_count, src_len_count); for (size_type i = 0; i < max_copy_size; ++i) { @@ -385,30 +383,28 @@ class VariableLengthArrayBase // +----------------------------------------------------------------------+ // | FORWARD ASSIGNMENT // +----------------------------------------------------------------------+ - template + template static constexpr size_type fast_forward_assign( - DstType* const dst, - size_type dst_capacity_count, - SrcType* const src, - size_type src_len_count, - typename std::enable_if_t::value>* = nullptr) + value_type* const dst, + size_type dst_capacity_count, + InputIt src, + size_type src_len_count, + typename std::enable_if_t< + is_array_of_type_trivially_copyable, InputIt>::value>* = nullptr) { // for trivial copyable move and copy is the same. return fast_copy_assign(dst, dst_capacity_count, src, src_len_count); } - template + template static constexpr size_type fast_forward_assign( - DstType* const dst, - size_type dst_capacity_count, - SrcType* const src, - size_type src_len_count, - typename std::enable_if_t::value>* = nullptr) + value_type* const dst, + size_type dst_capacity_count, + InputIt src, + size_type src_len_count, + typename std::enable_if_t< + !is_array_of_type_trivially_copyable, InputIt>::value>* = nullptr) { - if (nullptr == dst || nullptr == src) - { - return 0; - } const size_type max_copy_size = std::min(dst_capacity_count, src_len_count); for (size_type i = 0; i < max_copy_size; ++i) { @@ -932,7 +928,7 @@ class VariableLengthArray : protected VariableLengthArrayBase /// /// STL-like declaration of constant-reference type. /// - using const_reference = typename std::add_const_t>; + using const_reference = typename std::add_lvalue_reference_t>; // +----------------------------------------------------------------------+ // | CONSTRUCTORS @@ -1215,7 +1211,7 @@ class VariableLengthArray : protected VariableLengthArrayBase { throw std::out_of_range("at position argument is outside of container size."); } - return this->operator[][pos]; + return this->operator[](pos); } /// Returns a const reference to the element at specified location pos, with bounds checking. @@ -1232,7 +1228,7 @@ class VariableLengthArray : protected VariableLengthArrayBase { throw std::out_of_range("at position argument is outside of container size."); } - return this->operator[][pos]; + return this->operator[](pos); } #endif