Skip to content

Commit 1cbbc22

Browse files
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: ETLCPP#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.
1 parent 7324388 commit 1cbbc22

File tree

2 files changed

+41
-61
lines changed

2 files changed

+41
-61
lines changed

include/etl/alignment.h

Lines changed: 30 additions & 60 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

@@ -750,8 +715,9 @@ namespace etl
750715
reference create(TArgs&&... args) ETL_NOEXCEPT_EXPR(ETL_NOT_USING_EXCEPTIONS)
751716
{
752717
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
718+
pointer p = ::new (pbuffer) value_type(etl::forward<TArgs>(args)...);
753719
valid = true;
754-
return *::new (pbuffer) value_type(etl::forward<TArgs>(args)...);
720+
return *p;
755721
}
756722
#else
757723
//***************************************************************************
@@ -762,8 +728,9 @@ namespace etl
762728
reference create(const T1& t1)
763729
{
764730
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
731+
pointer p = ::new (pbuffer) value_type(t1);
765732
valid = true;
766-
return *::new (pbuffer) value_type(t1);
733+
return *p;
767734
}
768735

769736
//***************************************************************************
@@ -774,8 +741,9 @@ namespace etl
774741
reference create(const T1& t1, const T2& t2)
775742
{
776743
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
744+
pointer p = ::new (pbuffer) value_type(t1, t2);
777745
valid = true;
778-
return *::new (pbuffer) value_type(t1, t2);
746+
return *p;
779747
}
780748

781749
//***************************************************************************
@@ -786,8 +754,9 @@ namespace etl
786754
reference create(const T1& t1, const T2& t2, const T3& t3)
787755
{
788756
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
757+
pointer p = ::new (pbuffer) value_type(t1, t2, t3);
789758
valid = true;
790-
return *::new (pbuffer) value_type(t1, t2, t3);
759+
return *p;
791760
}
792761

793762
//***************************************************************************
@@ -798,8 +767,9 @@ namespace etl
798767
reference create(const T1& t1, const T2& t2, const T3& t3, const T4& t4)
799768
{
800769
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
770+
pointer p = ::new (pbuffer) value_type(t1, t2, t3, t4);
801771
valid = true;
802-
return *::new (pbuffer) value_type(t1, t2, t3, t4);
772+
return *p;
803773
}
804774
#endif
805775

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)