Skip to content

Commit d6d78eb

Browse files
rolandreichweinbmwJohn Wellbelovedrewr95jwellbelove
authored
Fix etl::typed_storage by supporting omitted destructors (#1182)
* Added coderabbitai configuration * Added builtin mem function tests * Modified etl::typed_storage * Modified etl::typed_storage # Conflicts: # include/etl/alignment.h * Added ETL_NOEXCEPT and ETL_NOEXCEPT_IF_NO_THROW * Added etl::typed_storage_ext and swap for same * Added etl::typed_storage_ext and swap for same # Conflicts: # include/etl/alignment.h * Added release notes * Fixes to GCC -O2 errors * Changed char* parameters to value_type* parameters * Fixed compilation issues for const containers unit tests * Added automatic selection of __builtin_memxxx functions for GCC and clang * Added enhanced coderabbit configuration * Updated version and release notes * Disabled constexpr const container tests for C++11 * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Attempted fixes for MacOS compilation * Updated version and release notes * feat: removed unreachable break statements (#1169) * Updated version and release notes * Modified etl::typed_storage # Conflicts: # include/etl/alignment.h * Fix etl::typed_storage by supporting omitted destructors In a recent change to alignment.h, the etl::typed_storage was changed in a way that in case of an already constructed object, the object is created via assignment. However, this contradicts the original use case that led to etl::typed_storage in the first place: #1023 The goal is to omit destructors (and at the same time support classes with deleted assignment operators), so they can be optimized out at link time. This change reverts commit ac7b268 to restore the original functionality and changes the test to reflect the original use case. * Fix missing create() in non-C++11 typed_storage_ext constructor * Typo fix --------- Co-authored-by: John Wellbelove <[email protected]> Co-authored-by: Drew Rife <[email protected]> Co-authored-by: John Wellbelove <[email protected]>
1 parent 75606fc commit d6d78eb

File tree

2 files changed

+47
-66
lines changed

2 files changed

+47
-66
lines changed

include/etl/alignment.h

Lines changed: 36 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -450,17 +450,10 @@ namespace etl
450450
template <typename... TArgs>
451451
reference create(TArgs&&... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS)
452452
{
453-
if (has_value())
454-
{
455-
storage.value = T(args...);
456-
}
457-
else
458-
{
459-
valid = true;
460-
::new (&storage.value) value_type(etl::forward<TArgs>(args)...);
461-
}
462-
463-
return storage.value;
453+
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
454+
pointer p = ::new (&storage.value) value_type(etl::forward<TArgs>(args)...);
455+
valid = true;
456+
return *p;
464457
}
465458
#else
466459
//***************************************************************************
@@ -470,17 +463,10 @@ namespace etl
470463
template <typename T1>
471464
reference create(const T1& t1)
472465
{
473-
if (has_value())
474-
{
475-
storage.value = T(t1);
476-
}
477-
else
478-
{
479-
valid = true;
480-
::new (&storage.value) value_type(t1);
481-
}
482-
483-
return storage.value;
466+
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
467+
pointer p = ::new (&storage.value) value_type(t1);
468+
valid = true;
469+
return *p;
484470
}
485471

486472
//***************************************************************************
@@ -490,17 +476,10 @@ namespace etl
490476
template <typename T1, typename T2>
491477
reference create(const T1& t1, const T2& t2)
492478
{
493-
if (has_value())
494-
{
495-
storage.value = T(t1, t2);
496-
}
497-
else
498-
{
499-
valid = true;
500-
::new (&storage.value) value_type(t1, t2);
501-
}
502-
503-
return storage.value;
479+
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
480+
pointer p = ::new (&storage.value) value_type(t1, t2);
481+
valid = true;
482+
return *p;
504483
}
505484

506485
//***************************************************************************
@@ -510,17 +489,10 @@ namespace etl
510489
template <typename T1, typename T2, typename T3>
511490
reference create(const T1& t1, const T2& t2, const T3& t3)
512491
{
513-
if (has_value())
514-
{
515-
storage.value = T(t1, t2, t3);
516-
}
517-
else
518-
{
519-
valid = true;
520-
::new (&storage.value) value_type(t1, t2, t3);
521-
}
522-
523-
return storage.value;
492+
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
493+
pointer p = ::new (&storage.value) value_type(t1, t2, t3);
494+
valid = true;
495+
return *p;
524496
}
525497

526498
//***************************************************************************
@@ -530,17 +502,10 @@ namespace etl
530502
template <typename T1, typename T2, typename T3, typename T4>
531503
reference create(const T1& t1, const T2& t2, const T3& t3, const T4& t4)
532504
{
533-
if (has_value())
534-
{
535-
storage.value = T(t1, t2, t3, t4);
536-
}
537-
else
538-
{
539-
valid = true;
540-
::new (&storage.value) value_type(t1, t2, t3, t4);
541-
}
542-
543-
return storage.value;
505+
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
506+
pointer p = ::new (&storage.value) value_type(t1, t2, t3, t4);
507+
valid = true;
508+
return *p;
544509
}
545510
#endif
546511

@@ -684,6 +649,7 @@ namespace etl
684649
, valid(false)
685650
{
686651
ETL_ASSERT(etl::is_aligned(pbuffer_, etl::alignment_of<T>::value), ETL_ERROR(etl::alignment_error));
652+
create(t1);
687653
}
688654

689655
//***************************************************************************
@@ -744,62 +710,67 @@ namespace etl
744710
#if ETL_USING_CPP11
745711
//***************************************************************************
746712
/// Constructs the instance of T forwarding the given \p args to its constructor.
747-
/// \returns the instance of T which has been constructed in the internal byte array.
713+
/// \returns the instance of T which has been constructed in the external buffer.
748714
//***************************************************************************
749715
template <typename... TArgs>
750716
reference create(TArgs&&... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS)
751717
{
752718
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
719+
pointer p = ::new (pbuffer) value_type(etl::forward<TArgs>(args)...);
753720
valid = true;
754-
return *::new (pbuffer) value_type(etl::forward<TArgs>(args)...);
721+
return *p;
755722
}
756723
#else
757724
//***************************************************************************
758725
/// Constructs the instance of T with type T1
759-
/// \returns the instance of T which has been constructed in the internal byte array.
726+
/// \returns the instance of T which has been constructed in the external buffer.
760727
//***************************************************************************
761728
template <typename T1>
762729
reference create(const T1& t1)
763730
{
764731
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
732+
pointer p = ::new (pbuffer) value_type(t1);
765733
valid = true;
766-
return *::new (pbuffer) value_type(t1);
734+
return *p;
767735
}
768736

769737
//***************************************************************************
770738
/// Constructs the instance of T with types T1, T2
771-
/// \returns the instance of T which has been constructed in the internal byte array.
739+
/// \returns the instance of T which has been constructed in the external buffer.
772740
//***************************************************************************
773741
template <typename T1, typename T2>
774742
reference create(const T1& t1, const T2& t2)
775743
{
776744
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
745+
pointer p = ::new (pbuffer) value_type(t1, t2);
777746
valid = true;
778-
return *::new (pbuffer) value_type(t1, t2);
747+
return *p;
779748
}
780749

781750
//***************************************************************************
782751
/// Constructs the instance of T with types T1, T2, T3
783-
/// \returns the instance of T which has been constructed in the internal byte array.
752+
/// \returns the instance of T which has been constructed in the external buffer.
784753
//***************************************************************************
785754
template <typename T1, typename T2, typename T3>
786755
reference create(const T1& t1, const T2& t2, const T3& t3)
787756
{
788757
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
758+
pointer p = ::new (pbuffer) value_type(t1, t2, t3);
789759
valid = true;
790-
return *::new (pbuffer) value_type(t1, t2, t3);
760+
return *p;
791761
}
792762

793763
//***************************************************************************
794764
/// Constructs the instance of T with types T1, T2, T3, T4
795-
/// \returns the instance of T which has been constructed in the internal byte array.
765+
/// \returns the instance of T which has been constructed in the external buffer.
796766
//***************************************************************************
797767
template <typename T1, typename T2, typename T3, typename T4>
798768
reference create(const T1& t1, const T2& t2, const T3& t3, const T4& t4)
799769
{
800770
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
771+
pointer p = ::new (pbuffer) value_type(t1, t2, t3, t4);
801772
valid = true;
802-
return *::new (pbuffer) value_type(t1, t2, t3, t4);
773+
return *p;
803774
}
804775
#endif
805776

test/test_alignment.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ void f(int)
4848
{
4949
}
5050

51+
// Demonstrator class for etl::typed_storage tests
5152
struct A_t
5253
{
5354
A_t(uint32_t v_x, uint8_t v_y)
@@ -56,13 +57,22 @@ struct A_t
5657
{
5758
}
5859

60+
// Just for test purpose. In production code, etl::typed_storage
61+
// actually supports the use case of destructors being optimized
62+
// away since they are not necessary for global objects that are
63+
// never destroyed
5964
~A_t()
6065
{
6166
x = 0;
6267
y = 0;
6368
}
6469

65-
bool operator==(A_t& other)
70+
// etl::typed_storage helps implementing the use case of becoming
71+
// independent of the destructor. By deleting the assignment operator,
72+
// we make sure that the destructor is not linked
73+
A_t& operator=(const A_t&) = delete;
74+
75+
bool operator==(const A_t& other) const
6676
{
6777
return other.x == x && other.y == y;
6878
}

0 commit comments

Comments
 (0)