From bde0d7d58488fec83c2ec56368030d9c489c17b0 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 14 Dec 2024 20:10:33 +0000 Subject: [PATCH] Changed etl::mem_cast to support bidirectional iterators --- include/etl/mem_cast.h | 92 +++++++++++++++++++++----------------- test/test_mem_cast.cpp | 75 ++++++++++++++++++++++++------- test/test_mem_cast_ptr.cpp | 81 ++++++++++++++++++++++++++------- 3 files changed, 177 insertions(+), 71 deletions(-) diff --git a/include/etl/mem_cast.h b/include/etl/mem_cast.h index 33b79021..c45b99af 100644 --- a/include/etl/mem_cast.h +++ b/include/etl/mem_cast.h @@ -139,7 +139,7 @@ namespace etl { ETL_STATIC_ASSERT(Size >= sizeof(T), "Type size is too large"); - ::new (static_cast(buffer)) T(value); + ::new (static_cast(buffer.raw)) T(value); } //*********************************** @@ -148,7 +148,7 @@ namespace etl template void assign_at_offset(size_t offset, const T& value) { - char* p = static_cast(buffer) + offset; + char* p = static_cast(buffer.raw) + offset; ETL_ASSERT(sizeof(T) <= (Size - offset), ETL_ERROR(etl::mem_cast_size_exception)); ::new (p) T(value); @@ -160,7 +160,7 @@ namespace etl template void assign_at_offset(const T& value) { - char* p = static_cast(buffer) + Offset; + char* p = static_cast(buffer.raw) + Offset; ETL_STATIC_ASSERT(sizeof(T) <= (Size - Offset), "Type size is too large"); ::new (p) T(value); @@ -171,35 +171,41 @@ namespace etl /// Emplace from parameters //*********************************** template - void emplace(TArgs... args) + T& emplace(TArgs... args) { ETL_STATIC_ASSERT(Size >= sizeof(T), "Type size is too large"); - ::new (static_cast(buffer)) T(etl::forward(args)...); + ::new (static_cast(buffer.raw)) T(etl::forward(args)...); + + return ref(); } //*********************************** /// Emplace from parameters at offset //*********************************** template - void emplace_at_offset(size_t offset, TArgs... args) + T& emplace_at_offset(size_t offset, TArgs... args) { - char* p = static_cast(buffer) + offset; + char* p = static_cast(buffer.raw) + offset; ETL_ASSERT(sizeof(T) <= (Size - offset), ETL_ERROR(etl::mem_cast_size_exception)); ::new (p) T(etl::forward(args)...); + + return ref_at_offset(offset); } //*********************************** /// Emplace from parameters at offset //*********************************** template - void emplace_at_offset(TArgs... args) + T& emplace_at_offset(TArgs... args) { - char* p = static_cast(buffer) + Offset; + char* p = static_cast(buffer.raw) + Offset; ETL_STATIC_ASSERT(sizeof(T) <= (Size - Offset), "Type size is too large"); ::new (p) T(etl::forward(args)...); + + return ref_at_offset(); } #endif @@ -209,9 +215,9 @@ namespace etl template ETL_NODISCARD T& ref() { - ETL_STATIC_ASSERT(sizeof(T) <= Size, "Size of T is too large"); + ETL_STATIC_ASSERT(sizeof(T) <= Size, "Size of type too large for storage"); - return *static_cast(buffer); + return *reinterpret_cast(buffer.raw); } //*********************************** @@ -220,9 +226,9 @@ namespace etl template ETL_NODISCARD const T& ref() const { - ETL_STATIC_ASSERT(sizeof(T) <= Size, "Size of T is too large"); + ETL_STATIC_ASSERT(sizeof(T) <= Size, "Size of type too large for storage"); - return *static_cast(buffer); + return *reinterpret_cast(buffer.raw); } //*********************************** @@ -233,9 +239,7 @@ namespace etl { ETL_ASSERT(sizeof(T) <= (Size - offset), ETL_ERROR(etl::mem_cast_size_exception)); - char* p = buffer + offset; - - return *static_cast(p); + return *reinterpret_cast(buffer.raw + offset); } //*********************************** @@ -246,9 +250,7 @@ namespace etl { ETL_ASSERT(sizeof(T) <= (Size - offset), ETL_ERROR(etl::mem_cast_size_exception)); - char* p = buffer + offset; - - return *static_cast(p); + return *reinterpret_cast(buffer.raw + offset); } //*********************************** @@ -257,11 +259,9 @@ namespace etl template ETL_NODISCARD T& ref_at_offset() { - ETL_STATIC_ASSERT(sizeof(T) <= (Size - Offset), "Size of T is too large"); + ETL_STATIC_ASSERT(sizeof(T) <= (Size - Offset), "Size of type too large for storage"); - char* p = buffer + Offset; - - return *static_cast(p); + return *reinterpret_cast(buffer.raw + Offset); } //*********************************** @@ -270,11 +270,9 @@ namespace etl template ETL_NODISCARD const T& ref_at_offset() const { - ETL_STATIC_ASSERT(sizeof(T) <= (Size - Offset), "Size of T is too large"); + ETL_STATIC_ASSERT(sizeof(T) <= (Size - Offset), "Size of type too large for storage"); - char* p = buffer + Offset; - - return *static_cast(p); + return *reinterpret_cast(buffer.raw + Offset); } //*********************************** @@ -411,38 +409,44 @@ namespace etl /// Emplace from parameters //*********************************** template - void emplace(TArgs... args) + T& emplace(TArgs... args) { ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception)); ETL_ASSERT(sizeof(T) <= buffer_size, ETL_ERROR(etl::mem_cast_size_exception)); ::new (pbuffer) T(etl::forward(args)...); + + return ref(); } //*********************************** /// Emplace from parameters at offset //*********************************** template - void emplace_at_offset(size_t offset, TArgs... args) + T& emplace_at_offset(size_t offset, TArgs... args) { ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception)); char* p = pbuffer + offset; ETL_ASSERT(sizeof(T) <= (buffer_size - offset), ETL_ERROR(etl::mem_cast_size_exception)); ::new (p) T(etl::forward(args)...); + + return ref_at_offset(offset); } //*********************************** /// Emplace from parameters at offset //*********************************** template - void emplace_at_offset(TArgs... args) + T& emplace_at_offset(TArgs... args) { ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception)); char* p = pbuffer + Offset; ETL_ASSERT(sizeof(T) <= (buffer_size - Offset), ETL_ERROR(etl::mem_cast_size_exception)); ::new (p) T(etl::forward(args)...); + + return ref_at_offset(); } #endif @@ -455,7 +459,9 @@ namespace etl ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception)); ETL_ASSERT(sizeof(T) <= buffer_size, ETL_ERROR(etl::mem_cast_size_exception)); - return *reinterpret_cast(pbuffer); + T* p = reinterpret_cast(pbuffer); + + return *p; } //*********************************** @@ -467,7 +473,9 @@ namespace etl ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception)); ETL_ASSERT(sizeof(T) <= buffer_size, ETL_ERROR(etl::mem_cast_size_exception)); - return *reinterpret_cast(pbuffer); + const T* p = reinterpret_cast(pbuffer); + + return *p; } //*********************************** @@ -477,10 +485,11 @@ namespace etl ETL_NODISCARD T& ref_at_offset(size_t offset) { ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception)); - char* p = pbuffer + offset; ETL_ASSERT(sizeof(T) <= (buffer_size - offset), ETL_ERROR(etl::mem_cast_size_exception)); - return *reinterpret_cast(p); + T* p = reinterpret_cast(pbuffer + offset); + + return *p; } //*********************************** @@ -490,10 +499,11 @@ namespace etl ETL_NODISCARD const T& ref_at_offset(size_t offset) const { ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception)); - char* p = pbuffer + offset; ETL_ASSERT(sizeof(T) <= (buffer_size - offset), ETL_ERROR(etl::mem_cast_size_exception)); - return *reinterpret_cast(p); + const T* p = reinterpret_cast(pbuffer + offset); + + return *p; } //*********************************** @@ -503,10 +513,11 @@ namespace etl ETL_NODISCARD T& ref_at_offset() { ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception)); - char* p = pbuffer + Offset; ETL_ASSERT(sizeof(T) <= (buffer_size - Offset), ETL_ERROR(etl::mem_cast_size_exception)); - return *reinterpret_cast(p); + T* p = reinterpret_cast(pbuffer + Offset); + + return *p; } //*********************************** @@ -516,10 +527,11 @@ namespace etl ETL_NODISCARD const T& ref_at_offset() const { ETL_ASSERT((pbuffer != ETL_NULLPTR), ETL_ERROR(etl::mem_cast_nullptr_exception)); - char* p = pbuffer + Offset; ETL_ASSERT(sizeof(T) <= (buffer_size - Offset), ETL_ERROR(etl::mem_cast_size_exception)); - return *reinterpret_cast(p); + const T* p = reinterpret_cast(pbuffer + Offset); + + return *p; } //*********************************** diff --git a/test/test_mem_cast.cpp b/test/test_mem_cast.cpp index e8f5d986..406231e9 100644 --- a/test/test_mem_cast.cpp +++ b/test/test_mem_cast.cpp @@ -189,13 +189,22 @@ namespace { MemCast memCast; - memCast.emplace(123); + char mc1 = memCast.emplace(123); CHECK_EQUAL(123, memCast.ref()); + CHECK_EQUAL(123, mc1); - memCast.emplace(1.23); + double mc2 = memCast.emplace(1.23); CHECK_EQUAL(1.23, memCast.ref()); + CHECK_EQUAL(1.23, mc2); + + Data& mc3 = memCast.emplace(123, 1.23, std::array{ 1, 2, 3 }); + + CHECK_EQUAL(123, mc3.c); + CHECK_EQUAL(1.23, mc3.d); + CHECK_EQUAL(1, mc3.a[0]); + CHECK_EQUAL(2, mc3.a[1]); + CHECK_EQUAL(3, mc3.a[2]); - memCast.emplace(123, 1.23, std::array{ 1, 2, 3 }); CHECK_EQUAL(123, memCast.ref().c); CHECK_EQUAL(1.23, memCast.ref().d); CHECK_EQUAL(1, memCast.ref().a[0]); @@ -209,14 +218,32 @@ namespace MemCast memCast; using Array = std::array; - Array a{ 1, 2, 3 }; + Array compare{ 4, 5, 6 }; - size_t offset = offsetof(Data, a); + constexpr size_t ArrayOffset = offsetof(Data, a); - memCast.emplace_at_offset(offset, a); - CHECK_EQUAL(a[0], memCast.ref().a[0]); - CHECK_EQUAL(a[1], memCast.ref().a[1]); - CHECK_EQUAL(a[2], memCast.ref().a[2]); + Array& data = memCast.emplace_at_offset(ArrayOffset, compare); + const MemCast& constMemCastRef = memCast; + + CHECK_EQUAL(compare[0], memCast.ref().a[0]); + CHECK_EQUAL(compare[1], memCast.ref().a[1]); + CHECK_EQUAL(compare[2], memCast.ref().a[2]); + + CHECK_EQUAL(compare[0], (memCast.ref_at_offset(ArrayOffset)[0])); + CHECK_EQUAL(compare[1], (memCast.ref_at_offset(ArrayOffset)[1])); + CHECK_EQUAL(compare[2], (memCast.ref_at_offset(ArrayOffset)[2])); + + CHECK_EQUAL(compare[0], constMemCastRef.ref().a[0]); + CHECK_EQUAL(compare[1], constMemCastRef.ref().a[1]); + CHECK_EQUAL(compare[2], constMemCastRef.ref().a[2]); + + CHECK_EQUAL(compare[0], (constMemCastRef.ref_at_offset(ArrayOffset)[0])); + CHECK_EQUAL(compare[1], (constMemCastRef.ref_at_offset(ArrayOffset)[1])); + CHECK_EQUAL(compare[2], (constMemCastRef.ref_at_offset(ArrayOffset)[2])); + + CHECK_EQUAL(compare[0], data[0]); + CHECK_EQUAL(compare[1], data[1]); + CHECK_EQUAL(compare[2], data[2]); } //************************************************************************* @@ -225,14 +252,32 @@ namespace MemCast memCast; using Array = std::array; - Array a{ 1, 2, 3 }; + Array compare{ 4, 5, 6 }; - constexpr size_t Offset = offsetof(Data, a); + constexpr size_t ArrayOffset = offsetof(Data, a); - memCast.emplace_at_offset(a); - CHECK_EQUAL(a[0], memCast.ref().a[0]); - CHECK_EQUAL(a[1], memCast.ref().a[1]); - CHECK_EQUAL(a[2], memCast.ref().a[2]); + Array& data = memCast.emplace_at_offset(compare); + const MemCast& constMemCastRef = memCast; + + CHECK_EQUAL(compare[0], memCast.ref().a[0]); + CHECK_EQUAL(compare[1], memCast.ref().a[1]); + CHECK_EQUAL(compare[2], memCast.ref().a[2]); + + CHECK_EQUAL(compare[0], (memCast.ref_at_offset()[0])); + CHECK_EQUAL(compare[1], (memCast.ref_at_offset()[1])); + CHECK_EQUAL(compare[2], (memCast.ref_at_offset()[2])); + + CHECK_EQUAL(compare[0], constMemCastRef.ref().a[0]); + CHECK_EQUAL(compare[1], constMemCastRef.ref().a[1]); + CHECK_EQUAL(compare[2], constMemCastRef.ref().a[2]); + + CHECK_EQUAL(compare[0], (constMemCastRef.ref_at_offset()[0])); + CHECK_EQUAL(compare[1], (constMemCastRef.ref_at_offset()[1])); + CHECK_EQUAL(compare[2], (constMemCastRef.ref_at_offset()[2])); + + CHECK_EQUAL(compare[0], data[0]); + CHECK_EQUAL(compare[1], data[1]); + CHECK_EQUAL(compare[2], data[2]); } //************************************************************************* diff --git a/test/test_mem_cast_ptr.cpp b/test/test_mem_cast_ptr.cpp index ec8eadef..e22c4322 100644 --- a/test/test_mem_cast_ptr.cpp +++ b/test/test_mem_cast_ptr.cpp @@ -237,20 +237,29 @@ namespace { char* pbuffer = reinterpret_cast(&buffer); - using Array = std::array; - MemCast memCast(pbuffer); - memCast.emplace(123); + char mc1 = memCast.emplace(123); CHECK_EQUAL(123, memCast.ref()); + CHECK_EQUAL(123, mc1); - memCast.emplace(1.23); + double mc2 = memCast.emplace(1.23); CHECK_EQUAL(1.23, memCast.ref()); + CHECK_EQUAL(1.23, mc2); - memCast.emplace(123, 1.23, std::array{ 1, 2, 3 }); - CHECK_EQUAL(123, memCast.ref().c); + Data& mc3 = memCast.emplace(123, 1.23, std::array{ 1, 2, 3 }); + + CHECK_EQUAL(123, mc3.c); + CHECK_EQUAL(1.23, mc3.d); + CHECK_EQUAL(1, mc3.a[0]); + CHECK_EQUAL(2, mc3.a[1]); + CHECK_EQUAL(3, mc3.a[2]); + + CHECK_EQUAL(123, memCast.ref().c); CHECK_EQUAL(1.23, memCast.ref().d); - CHECK((Array{ 1, 2, 3 }) == memCast.ref().a); + CHECK_EQUAL(1, memCast.ref().a[0]); + CHECK_EQUAL(2, memCast.ref().a[1]); + CHECK_EQUAL(3, memCast.ref().a[2]); } //************************************************************************* @@ -261,12 +270,32 @@ namespace MemCast memCast(pbuffer); using Array = std::array; - Array a{ 1, 2, 3 }; + Array compare{ 4, 5, 6 }; - size_t offset = offsetof(Data, a); + constexpr size_t ArrayOffset = offsetof(Data, a); - memCast.emplace_at_offset(offset, a); - CHECK(a == memCast.ref().a); + Array& data = memCast.emplace_at_offset(ArrayOffset, compare); + const MemCast& constMemCastRef = memCast; + + CHECK_EQUAL(compare[0], memCast.ref().a[0]); + CHECK_EQUAL(compare[1], memCast.ref().a[1]); + CHECK_EQUAL(compare[2], memCast.ref().a[2]); + + CHECK_EQUAL(compare[0], (memCast.ref_at_offset(ArrayOffset)[0])); + CHECK_EQUAL(compare[1], (memCast.ref_at_offset(ArrayOffset)[1])); + CHECK_EQUAL(compare[2], (memCast.ref_at_offset(ArrayOffset)[2])); + + CHECK_EQUAL(compare[0], constMemCastRef.ref().a[0]); + CHECK_EQUAL(compare[1], constMemCastRef.ref().a[1]); + CHECK_EQUAL(compare[2], constMemCastRef.ref().a[2]); + + CHECK_EQUAL(compare[0], (constMemCastRef.ref_at_offset(ArrayOffset)[0])); + CHECK_EQUAL(compare[1], (constMemCastRef.ref_at_offset(ArrayOffset)[1])); + CHECK_EQUAL(compare[2], (constMemCastRef.ref_at_offset(ArrayOffset)[2])); + + CHECK_EQUAL(compare[0], data[0]); + CHECK_EQUAL(compare[1], data[1]); + CHECK_EQUAL(compare[2], data[2]); } //************************************************************************* @@ -274,15 +303,35 @@ namespace { char* pbuffer = reinterpret_cast(&buffer); - MemCast memCast(pbuffer); + MemCast memCast(pbuffer); using Array = std::array; - Array a{ 1, 2, 3 }; + Array compare{ 4, 5, 6 }; - constexpr size_t Offset = offsetof(Data, a); + constexpr size_t ArrayOffset = offsetof(Data, a); - memCast.emplace_at_offset(a); - CHECK(a == memCast.ref().a); + Array& data = memCast.emplace_at_offset(compare); + const MemCast& constMemCastRef = memCast; + + CHECK_EQUAL(compare[0], memCast.ref().a[0]); + CHECK_EQUAL(compare[1], memCast.ref().a[1]); + CHECK_EQUAL(compare[2], memCast.ref().a[2]); + + CHECK_EQUAL(compare[0], (memCast.ref_at_offset()[0])); + CHECK_EQUAL(compare[1], (memCast.ref_at_offset()[1])); + CHECK_EQUAL(compare[2], (memCast.ref_at_offset()[2])); + + CHECK_EQUAL(compare[0], constMemCastRef.ref().a[0]); + CHECK_EQUAL(compare[1], constMemCastRef.ref().a[1]); + CHECK_EQUAL(compare[2], constMemCastRef.ref().a[2]); + + CHECK_EQUAL(compare[0], (constMemCastRef.ref_at_offset()[0])); + CHECK_EQUAL(compare[1], (constMemCastRef.ref_at_offset()[1])); + CHECK_EQUAL(compare[2], (constMemCastRef.ref_at_offset()[2])); + + CHECK_EQUAL(compare[0], data[0]); + CHECK_EQUAL(compare[1], data[1]); + CHECK_EQUAL(compare[2], data[2]); } //*************************************************************************