From 43d3f0e89ca54e860b993f03e569f490695b7bb8 Mon Sep 17 00:00:00 2001 From: Filipe Cuim <87344176+filipe-cuim@users.noreply.github.com> Date: Tue, 11 Nov 2025 19:12:39 +0000 Subject: [PATCH] Add const specialization for etl::get_object_at (#1217) Signed-off-by: Filipe Cuim --- include/etl/memory.h | 63 ++++++++++++++++++++++++++------------------ test/test_memory.cpp | 51 ++++++++++++++++++++++++++--------- 2 files changed, 76 insertions(+), 38 deletions(-) diff --git a/include/etl/memory.h b/include/etl/memory.h index c2e162bd..ffe7b7ef 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -60,8 +60,8 @@ namespace etl //***************************************************************************** template ETL_CONSTEXPR T* to_address(T* p) ETL_NOEXCEPT - { - return p; + { + return p; } //***************************************************************************** @@ -837,7 +837,7 @@ namespace etl std::uninitialized_value_construct(o_begin, o_end); } -#else +#else //***************************************************************************** /// Default initialises a range of objects to uninitialised memory. /// https://en.cppreference.com/w/cpp/memory/uninitialized_value_construct @@ -1264,7 +1264,7 @@ namespace etl //********************************* template - default_delete(const default_delete&) ETL_NOEXCEPT + default_delete(const default_delete&) ETL_NOEXCEPT { } @@ -1353,8 +1353,8 @@ namespace etl #endif //********************************* - unique_ptr(pointer p_, typename etl::conditional::value, - TDeleter, + unique_ptr(pointer p_, typename etl::conditional::value, + TDeleter, typename etl::add_lvalue_reference::type>::type deleter_) ETL_NOEXCEPT : p(p_) , deleter(deleter_) @@ -1557,7 +1557,7 @@ namespace etl #endif //********************************* - unique_ptr(pointer p_, + unique_ptr(pointer p_, typename etl::conditional::value, TDeleter, typename etl::add_lvalue_reference::type>::type deleter_) ETL_NOEXCEPT @@ -1614,7 +1614,7 @@ namespace etl { pointer value = p; p = ETL_NULLPTR; - return value; + return value; } //********************************* @@ -1709,7 +1709,7 @@ namespace etl unique_ptr(const unique_ptr&) ETL_DELETE; unique_ptr& operator =(const unique_ptr&) ETL_DELETE; - pointer p; + pointer p; TDeleter deleter; }; } @@ -2324,7 +2324,7 @@ namespace etl reinterpret_cast(sb), sizeof(T) * n); #endif - + return db; } @@ -2374,7 +2374,7 @@ namespace etl reinterpret_cast(sb), sizeof(T) * n); #endif - + return db; } @@ -2438,7 +2438,7 @@ namespace etl /// \return The destination //*************************************************************************** template - typename etl::enable_if::value && + typename etl::enable_if::value && !etl::is_const::value && etl::is_integral::value && sizeof(T) == 1, TPointer>::type @@ -2447,11 +2447,11 @@ namespace etl ETL_STATIC_ASSERT(etl::is_trivially_copyable::value_type>::value, "Cannot mem_set a non trivially copyable type"); #if ETL_USING_BUILTIN_MEMSET - __builtin_memset(reinterpret_cast(db), + __builtin_memset(reinterpret_cast(db), static_cast(value), sizeof(typename etl::iterator_traits::value_type) * static_cast(de - db)); #else - ::memset(reinterpret_cast(db), + ::memset(reinterpret_cast(db), static_cast(value), sizeof(typename etl::iterator_traits::value_type) * static_cast(de - db)); #endif @@ -2504,13 +2504,13 @@ namespace etl mem_char(TPointer sb, TPointer se, T value) ETL_NOEXCEPT { #if ETL_USING_BUILTIN_MEMCHR - void* result = __builtin_memchr(reinterpret_cast(sb), + void* result = __builtin_memchr(reinterpret_cast(sb), static_cast(value), sizeof(typename etl::iterator_traits::value_type) * static_cast(se - sb)); return (result == 0U) ? reinterpret_cast(se) : reinterpret_cast(result); #else - void* result = ::memchr(reinterpret_cast(sb), + void* result = ::memchr(reinterpret_cast(sb), static_cast(value), sizeof(typename etl::iterator_traits::value_type) * static_cast(se - sb)); @@ -2527,7 +2527,7 @@ namespace etl //*************************************************************************** template ETL_NODISCARD - typename etl::enable_if::value && + typename etl::enable_if::value && etl::is_const::type>::value && etl::is_integral::value && sizeof(T) == 1, const char*>::type @@ -2545,7 +2545,7 @@ namespace etl sizeof(typename etl::iterator_traits::value_type) * static_cast(se - sb)); return (result == 0U) ? reinterpret_cast(se) : reinterpret_cast(result); -#endif +#endif } //*************************************************************************** @@ -2557,25 +2557,25 @@ namespace etl //*************************************************************************** template ETL_NODISCARD - typename etl::enable_if::value && + typename etl::enable_if::value && !etl::is_const::type>::value && etl::is_integral::value && sizeof(T) == 1, char*>::type mem_char(TPointer sb, size_t n, T value) ETL_NOEXCEPT { #if ETL_USING_BUILTIN_MEMCHR - void* result = __builtin_memchr(reinterpret_cast(sb), + void* result = __builtin_memchr(reinterpret_cast(sb), static_cast(value), sizeof(typename etl::iterator_traits::value_type) * n); return (result == 0U) ? reinterpret_cast(sb + n) : reinterpret_cast(result); #else - void* result = ::memchr(reinterpret_cast(sb), + void* result = ::memchr(reinterpret_cast(sb), static_cast(value), sizeof(typename etl::iterator_traits::value_type) * n); return (result == 0U) ? reinterpret_cast(sb + n) : reinterpret_cast(result); -#endif +#endif } //*************************************************************************** @@ -2587,7 +2587,7 @@ namespace etl //*************************************************************************** template ETL_NODISCARD - typename etl::enable_if::value && + typename etl::enable_if::value && etl::is_const::type>::value && etl::is_integral::value && sizeof(T) == 1, const char*>::type @@ -2607,7 +2607,7 @@ namespace etl return (result == 0U) ? reinterpret_cast(sb + n) : reinterpret_cast(result); #endif - + } #if ETL_USING_CPP11 @@ -2687,9 +2687,20 @@ namespace etl ETL_ASSERT(is_aligned(p), ETL_ERROR(alignment_error)); #endif - TObject& v = *reinterpret_cast(p); + return *reinterpret_cast(p); + } - return v; + //***************************************************************************** + /// Get the container at const 'p'. + //***************************************************************************** + template + const TObject& get_object_at(const void* p) + { +#if ETL_IS_DEBUG_BUILD + ETL_ASSERT(is_aligned(p), ETL_ERROR(alignment_error)); +#endif + + return *reinterpret_cast(p); } //***************************************************************************** diff --git a/test/test_memory.cpp b/test/test_memory.cpp index 4b70f3fe..1b88c8a5 100644 --- a/test/test_memory.cpp +++ b/test/test_memory.cpp @@ -1256,7 +1256,7 @@ namespace uint32_t expected[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 }; uint32_t data[12] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201, 0, 0, 0, 0 }; const uint32_t* data_begin = &data[0]; - + uint32_t* result = etl::mem_move(data_begin, 8, data + 4); CHECK(std::equal(expected, expected + 8, data + 4)); CHECK(result == data + 4); @@ -1269,7 +1269,7 @@ namespace uint32_t same[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67234501, 0x45016723, 0x01324576, 0x76453201 }; uint32_t grtr[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67235501, 0x45016723, 0x01324576, 0x76453201 }; uint32_t less[8] = { 0x12345678, 0x76543210, 0x01452367, 0x23670145, 0x67134501, 0x45016723, 0x01324576, 0x76453201 }; - + CHECK(etl::mem_compare(data, data + 8, same) == 0); CHECK(etl::mem_compare(data, data + 8, grtr) > 0); CHECK(etl::mem_compare(data, data + 8, less) < 0); @@ -1443,7 +1443,7 @@ namespace } //************************************************************************* - class Base + class Base { public: virtual ~Base() {}; @@ -1452,21 +1452,21 @@ namespace static bool function_was_called = false; - class Derived : public Base + class Derived : public Base { public: - Derived() + Derived() { function_was_called = false; } - void function() + void function() { function_was_called = true; } }; - void call(etl::unique_ptr ptr) + void call(etl::unique_ptr ptr) { ptr->function(); } @@ -1477,13 +1477,13 @@ namespace etl::unique_ptr ptr(new Derived()); CHECK(ptr.get() != ETL_NULLPTR); - + call(etl::move(ptr)); CHECK(function_was_called); CHECK(ptr.get() == ETL_NULLPTR); } - + struct Flags { Flags() @@ -1530,7 +1530,7 @@ namespace int a; int b; }; - + alignas(Data) char buffer1[sizeof(Data)]; char* pbuffer1 = buffer1; @@ -1581,14 +1581,14 @@ namespace CHECK_FALSE(flags.destructed); CHECK_EQUAL(1, rdata1b.a); CHECK_EQUAL(2, rdata1b.b); - + flags.Clear(); Data& rdata2b = etl::get_object_at(pbuffer2b); CHECK_FALSE(flags.constructed); CHECK_FALSE(flags.destructed); CHECK_EQUAL(data2.a, rdata2b.a); CHECK_EQUAL(data2.b, rdata2b.b); - + flags.Clear(); Data& rdata3b = etl::get_object_at(pbuffer3b); CHECK_FALSE(flags.constructed); @@ -1612,6 +1612,33 @@ namespace CHECK_TRUE(flags.destructed); } + TEST(test_get_object_at_const_specialization) + { + struct Data + { + Data() + : a(1) + , b(2) + { + flags.constructed = true; + } + + ~Data() = default; + + int a; + int b; + }; + + std::array buffer{}; + etl::construct_object_at(buffer.data(), Data()); + const void* bufferPointer = buffer.data(); + + const Data& rdata = etl::get_object_at(bufferPointer); + CHECK_TRUE(flags.constructed); + CHECK_TRUE(rdata.a == 1); + CHECK_TRUE(rdata.b == 2); + } + TEST(test_construct_get_destroy_object_misaligned) { struct Data