From 0ca68938ff831054ab7dd951c894aea0c080c44a Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 26 Aug 2025 16:43:33 +0100 Subject: [PATCH] Modified etl::typed_storage --- include/etl/alignment.h | 185 +++++++++++++++++++++++++++++++--------- test/test_alignment.cpp | 27 +++--- 2 files changed, 160 insertions(+), 52 deletions(-) diff --git a/include/etl/alignment.h b/include/etl/alignment.h index 1115aa92..686a2f46 100644 --- a/include/etl/alignment.h +++ b/include/etl/alignment.h @@ -368,109 +368,187 @@ namespace etl typedef T* pointer; typedef const T* const_pointer; - // Constructor + //*************************************************************************** + // Default constructor + //*************************************************************************** typed_storage() : valid(false) { } +#if ETL_USING_CPP11 + //*************************************************************************** + /// Constructs the instance of T forwarding the given \p args to its constructor. + //*************************************************************************** + template + typed_storage(TArgs&&... args) + { + create(etl::forward(args)...); + } +#else + //*************************************************************************** + /// Constructs the instance of T with type T1 + //*************************************************************************** + typed_storage(const T1& t1) + { + create(t1); + } + + //*************************************************************************** + /// Constructs the instance of T with types T1, T2 + //*************************************************************************** + typed_storage(const T1& t1, const T2& t2) + { + create(t1, t2); + } + + //*************************************************************************** + /// Constructs the instance of T with types T1, T2, T3 + //*************************************************************************** + typed_storage(const T1& t1, const T2& t2, const T3& t3) + { + create(t1, t2, t3); + } + + //*************************************************************************** + /// Constructs the instance of T with types T1, T2, T3, T4 + //*************************************************************************** + typed_storage(const T1& t1, const T2& t2, const T3& t3, const T4& t4) + { + create(t1, t2, t3, t4); + } +#endif + //*************************************************************************** /// Default destructor which will NOT call the destructor of the object which /// was created by calling create(). //*************************************************************************** ~typed_storage() { + // Intentionally empty. } //*************************************************************************** /// \returns true if object has been constructed using create(). /// \returns false otherwise. //*************************************************************************** - bool has_value() const + bool has_value() const ETL_NOEXCEPT { return valid; } #if ETL_USING_CPP11 //*************************************************************************** - /// Constructs the instance of T forwarding the given \p args to its constructor and - /// asserts if has_value() is false. - /// + /// Constructs the instance of T forwarding the given \p args to its constructor. /// \returns the instance of T which has been constructed in the internal byte array. //*************************************************************************** - template - reference create(Args&&... args) + template + reference create(TArgs&&... args) { - ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); - valid = true; - return *::new (data.template get_address()) value_type(etl::forward(args)...); + if (has_value()) + { + storage.value = T(args...); + } + else + { + valid = true; + ::new (&storage.value) value_type(etl::forward(args)...); + } + + return storage.value; } #else //*************************************************************************** /// Constructs the instance of T with type T1 - /// asserts if has_value() is false. - /// /// \returns the instance of T which has been constructed in the internal byte array. //*************************************************************************** - template + template reference create(const T1& t1) { - ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); - valid = true; - return *::new (data.template get_address()) value_type(t1); + if (has_value()) + { + storage.value = T(t1); + } + else + { + valid = true; + ::new (&storage.value) value_type(t1); + } + + return storage.value; } //*************************************************************************** /// Constructs the instance of T with types T1, T2 - /// asserts if has_value() is false. - /// /// \returns the instance of T which has been constructed in the internal byte array. //*************************************************************************** - template + template reference create(const T1& t1, const T2& t2) { - ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); - valid = true; - return *::new (data.template get_address()) value_type(t1, t2); + if (has_value()) + { + storage.value = T(t1, t2); + } + else + { + valid = true; + ::new (&storage.value) value_type(t1, t2); + } + + return storage.value; } //*************************************************************************** /// Constructs the instance of T with types T1, T2, T3 - /// asserts if has_value() is false. - /// /// \returns the instance of T which has been constructed in the internal byte array. //*************************************************************************** - template + template reference create(const T1& t1, const T2& t2, const T3& t3) { - ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); - valid = true; - return *::new (data.template get_address()) value_type(t1, t2, t3); + if (has_value()) + { + storage.value = T(t1, t2, t3); + } + else + { + valid = true; + ::new (&storage.value) value_type(t1, t2, t3); + } + + return storage.value; } //*************************************************************************** /// Constructs the instance of T with types T1, T2, T3, T4 - /// asserts if has_value() is false. - /// /// \returns the instance of T which has been constructed in the internal byte array. //*************************************************************************** - template + template reference create(const T1& t1, const T2& t2, const T3& t3, const T4& t4) { - ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error)); - valid = true; - return *::new (data.template get_address()) value_type(t1, t2, t3, t4); + if (has_value()) + { + storage.value = T(t1, t2, t3, t4); + } + else + { + valid = true; + ::new (&storage.value) value_type(t1, t2, t3, t4); + } + + return storage.value; } #endif //*************************************************************************** - /// Calls the destructor of the wrapped object and asserts if has_value() is false. + /// Calls the destructor of the stored object, if created. //*************************************************************************** void destroy() { - ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error)); - data.template get_reference().~T(); - valid = false; + if (has_value()) + { + storage.value.~T(); + valid = false; + } } //*************************************************************************** @@ -479,7 +557,8 @@ namespace etl pointer operator->() { ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error)); - return data.template get_address(); + + return &storage.value; } //*************************************************************************** @@ -487,7 +566,9 @@ namespace etl //*************************************************************************** const_pointer operator->() const { - return operator->(); + ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error)); + + return &storage.value; } //*************************************************************************** @@ -499,7 +580,7 @@ namespace etl } //*************************************************************************** - /// \returns const reference of type T and asserts if has_value() is false. + /// \returns const_reference of type T and asserts if has_value() is false. //*************************************************************************** const_reference operator*() const { @@ -508,7 +589,27 @@ namespace etl private: - typename aligned_storage_as::type data; + typed_storage(etl::typed_storage&) ETL_DELETE; + typed_storage& operator =(etl::typed_storage&) ETL_DELETE; + + struct dummy_t {}; + + //******************************* + union union_type + { + union_type() + : dummy() + { + } + + ~union_type() + { + } + + dummy_t dummy; + T value; + } storage; + bool valid; }; } diff --git a/test/test_alignment.cpp b/test/test_alignment.cpp index 73c1f00f..ee4b589e 100644 --- a/test/test_alignment.cpp +++ b/test/test_alignment.cpp @@ -194,24 +194,31 @@ namespace TEST(test_typed_storage) { etl::typed_storage a; + CHECK_FALSE(a.has_value()); - CHECK_EQUAL(false, a.has_value()); - - auto& b = a.create(123, 4); - - CHECK_EQUAL(true, a.has_value()); + etl::typed_storage b(789, 10); // Construct in place. + CHECK_TRUE(b.has_value()); + CHECK_EQUAL(b->x, 789); + CHECK_EQUAL(b->y, 10); + + auto& ref = a.create(123, 4); // Create in place. + CHECK_TRUE(a.has_value()); CHECK_EQUAL(a->x, 123); CHECK_EQUAL(a->y, 4); - CHECK_EQUAL(b.x, 123); - CHECK_EQUAL(b.y, 4); + CHECK_EQUAL(ref.x, 123); + CHECK_EQUAL(ref.y, 4); - CHECK_TRUE(*a == b); + CHECK_TRUE(*a == ref); - CHECK_EQUAL(true, a.has_value()); + a.create(456, 7); // Calling create again is not an error. + CHECK_EQUAL(a->x, 456); + CHECK_EQUAL(a->y, 7); + + CHECK_TRUE(a.has_value()); a.destroy(); - CHECK_EQUAL(false, a.has_value()); + CHECK_FALSE(a.has_value()); } }; }