Skip to content

Commit 9bbd476

Browse files
author
John Wellbelove
committed
Merge branch 'pull-request/#1023-Alignment-typed-storage' of https://github.com/ETLCPP/etl into pull-request/#1023-Alignment-typed-storage
2 parents 409dae2 + 7d91e1f commit 9bbd476

File tree

2 files changed

+160
-0
lines changed

2 files changed

+160
-0
lines changed

include/etl/alignment.h

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ SOFTWARE.
3636
#include "static_assert.h"
3737
#include "error_handler.h"
3838
#include "exception.h"
39+
#include "utility.h"
3940

4041
#include <stdint.h>
4142

@@ -71,6 +72,19 @@ namespace etl
7172
}
7273
};
7374

75+
//***************************************************************************
76+
/// Typed storage exception.
77+
//***************************************************************************
78+
class typed_storage_error : public alignment_exception
79+
{
80+
public:
81+
82+
typed_storage_error(string_type file_name_, numeric_type line_number_)
83+
: alignment_exception(ETL_ERROR_TEXT("typed_storage:error", ETL_ALIGNMENT_FILE_ID"B"), file_name_, line_number_)
84+
{
85+
}
86+
};
87+
7488
//*****************************************************************************
7589
/// Check that 'p' has 'required_alignment'.
7690
//*****************************************************************************
@@ -333,6 +347,109 @@ namespace etl
333347
#if ETL_USING_CPP11
334348
template <size_t Length, typename T>
335349
using aligned_storage_as_t = typename aligned_storage_as<Length, T>::type;
350+
351+
//***************************************************************************
352+
/// Wrapper class that provides a memory area and lets the user emplace and
353+
/// instance of T in this memory at runtime. This class also erases the
354+
/// destructor call of T, i.e. if typed_storage goes out of scope, the
355+
/// destructor if the wrapped type will not be called. This can be done
356+
/// explicitly by calling destroy().
357+
/// \tparam T Type of element stored in this instance of typed_storage.
358+
//***************************************************************************
359+
template <typename T>
360+
class typed_storage
361+
{
362+
public:
363+
364+
using value_type = T;
365+
using reference = T&;
366+
using const_reference = T const&;
367+
using pointer = T*;
368+
using const_pointer = T const*;
369+
370+
// Constructor
371+
typed_storage()
372+
: valid(false)
373+
{
374+
}
375+
376+
//***************************************************************************
377+
/// Default destructor which will NOT call the destructor of the object which
378+
/// was created by calling emplace().
379+
//***************************************************************************
380+
~typed_storage() = default;
381+
382+
//***************************************************************************
383+
/// Calls the destructor of the wrapped object and asserts if has_value() is false.
384+
//***************************************************************************
385+
void destroy()
386+
{
387+
ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error));
388+
data.template get_reference<T>().~T();
389+
valid = false;
390+
}
391+
392+
//***************************************************************************
393+
/// \returns true if object has been constructed using emplace().
394+
/// \returns false otherwise.
395+
//***************************************************************************
396+
bool has_value() const
397+
{
398+
return valid;
399+
}
400+
401+
//***************************************************************************
402+
/// Constructs the instance of T forwarding the given \p args to its constructor and
403+
/// asserts if has_value() is true before calling emplace().
404+
///
405+
/// \returns the instance of T which has been constructed in the internal byte array.
406+
//***************************************************************************
407+
template<typename... Args>
408+
reference create(Args&&... args)
409+
{
410+
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
411+
valid = true;
412+
return *::new (data.template get_address<char>()) value_type(etl::forward<Args>(args)...);
413+
}
414+
415+
//***************************************************************************
416+
/// \returns a pointer of type T and asserts if has_value() is false.
417+
//***************************************************************************
418+
pointer operator->()
419+
{
420+
ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error));
421+
return data.template get_address<value_type>();
422+
}
423+
424+
//***************************************************************************
425+
/// \returns a const pointer of type T and asserts if has_value() is false.
426+
//***************************************************************************
427+
const_pointer operator->() const
428+
{
429+
return operator->();
430+
}
431+
432+
//***************************************************************************
433+
/// \returns reference of type T and asserts if has_value() is false.
434+
//***************************************************************************
435+
reference operator*()
436+
{
437+
return *operator->();
438+
}
439+
440+
//***************************************************************************
441+
/// \returns const reference of type T and asserts if has_value() is false.
442+
//***************************************************************************
443+
const_reference operator*() const
444+
{
445+
return *operator->();
446+
}
447+
448+
private:
449+
450+
typename aligned_storage_as<sizeof(value_type), value_type>::type data;
451+
bool valid;
452+
};
336453
#endif
337454
}
338455

test/test_alignment.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,23 @@ void f(int)
4848
{
4949
}
5050

51+
struct A_t
52+
{
53+
A_t(uint32_t v_x, uint8_t v_y)
54+
: x(v_x)
55+
, y(v_y)
56+
{
57+
}
58+
59+
bool operator==(A_t& other)
60+
{
61+
return other.x == x && other.y == y;
62+
}
63+
64+
uint32_t x;
65+
uint8_t y;
66+
};
67+
5168
namespace
5269
{
5370
SUITE(test_alignment)
@@ -155,5 +172,31 @@ namespace
155172
CHECK_EQUAL(32, alignof(etl::type_with_alignment_t<32>));
156173
CHECK_EQUAL(64, alignof(etl::type_with_alignment_t<64>));
157174
}
175+
176+
//*************************************************************************
177+
#if ETL_USING_CPP11
178+
TEST(test_typed_storage)
179+
{
180+
etl::typed_storage<A_t> a;
181+
182+
CHECK_EQUAL(false, a.has_value());
183+
184+
auto& b = a.create(123, 4);
185+
186+
CHECK_EQUAL(true, a.has_value());
187+
188+
CHECK_EQUAL(a->x, 123);
189+
CHECK_EQUAL(a->y, 4);
190+
191+
CHECK_EQUAL(b.x, 123);
192+
CHECK_EQUAL(b.y, 4);
193+
194+
CHECK_TRUE(*a == b);
195+
196+
CHECK_EQUAL(true, a.has_value());
197+
a.destroy();
198+
CHECK_EQUAL(false, a.has_value());
199+
}
200+
#endif
158201
};
159202
}

0 commit comments

Comments
 (0)