mirror of
https://github.com/ETLCPP/etl.git
synced 2026-05-01 03:19:10 +08:00
Merge branch 'pull-request/#1023-Alignment-typed-storage' of https://github.com/ETLCPP/etl into pull-request/#1023-Alignment-typed-storage
This commit is contained in:
commit
9bbd4763b0
@ -36,6 +36,7 @@ SOFTWARE.
|
||||
#include "static_assert.h"
|
||||
#include "error_handler.h"
|
||||
#include "exception.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -71,6 +72,19 @@ namespace etl
|
||||
}
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Typed storage exception.
|
||||
//***************************************************************************
|
||||
class typed_storage_error : public alignment_exception
|
||||
{
|
||||
public:
|
||||
|
||||
typed_storage_error(string_type file_name_, numeric_type line_number_)
|
||||
: alignment_exception(ETL_ERROR_TEXT("typed_storage:error", ETL_ALIGNMENT_FILE_ID"B"), file_name_, line_number_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//*****************************************************************************
|
||||
/// Check that 'p' has 'required_alignment'.
|
||||
//*****************************************************************************
|
||||
@ -333,6 +347,109 @@ namespace etl
|
||||
#if ETL_USING_CPP11
|
||||
template <size_t Length, typename T>
|
||||
using aligned_storage_as_t = typename aligned_storage_as<Length, T>::type;
|
||||
|
||||
//***************************************************************************
|
||||
/// Wrapper class that provides a memory area and lets the user emplace and
|
||||
/// instance of T in this memory at runtime. This class also erases the
|
||||
/// destructor call of T, i.e. if typed_storage goes out of scope, the
|
||||
/// destructor if the wrapped type will not be called. This can be done
|
||||
/// explicitly by calling destroy().
|
||||
/// \tparam T Type of element stored in this instance of typed_storage.
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
class typed_storage
|
||||
{
|
||||
public:
|
||||
|
||||
using value_type = T;
|
||||
using reference = T&;
|
||||
using const_reference = T const&;
|
||||
using pointer = T*;
|
||||
using const_pointer = T const*;
|
||||
|
||||
// Constructor
|
||||
typed_storage()
|
||||
: valid(false)
|
||||
{
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Default destructor which will NOT call the destructor of the object which
|
||||
/// was created by calling emplace().
|
||||
//***************************************************************************
|
||||
~typed_storage() = default;
|
||||
|
||||
//***************************************************************************
|
||||
/// Calls the destructor of the wrapped object and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
void destroy()
|
||||
{
|
||||
ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error));
|
||||
data.template get_reference<T>().~T();
|
||||
valid = false;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// \returns true if object has been constructed using emplace().
|
||||
/// \returns false otherwise.
|
||||
//***************************************************************************
|
||||
bool has_value() const
|
||||
{
|
||||
return valid;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T forwarding the given \p args to its constructor and
|
||||
/// asserts if has_value() is true before calling emplace().
|
||||
///
|
||||
/// \returns the instance of T which has been constructed in the internal byte array.
|
||||
//***************************************************************************
|
||||
template<typename... Args>
|
||||
reference create(Args&&... args)
|
||||
{
|
||||
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
|
||||
valid = true;
|
||||
return *::new (data.template get_address<char>()) value_type(etl::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// \returns a pointer of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
pointer operator->()
|
||||
{
|
||||
ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error));
|
||||
return data.template get_address<value_type>();
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// \returns a const pointer of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
const_pointer operator->() const
|
||||
{
|
||||
return operator->();
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// \returns reference of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
reference operator*()
|
||||
{
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// \returns const reference of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
const_reference operator*() const
|
||||
{
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typename aligned_storage_as<sizeof(value_type), value_type>::type data;
|
||||
bool valid;
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -48,6 +48,23 @@ void f(int)
|
||||
{
|
||||
}
|
||||
|
||||
struct A_t
|
||||
{
|
||||
A_t(uint32_t v_x, uint8_t v_y)
|
||||
: x(v_x)
|
||||
, y(v_y)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(A_t& other)
|
||||
{
|
||||
return other.x == x && other.y == y;
|
||||
}
|
||||
|
||||
uint32_t x;
|
||||
uint8_t y;
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
SUITE(test_alignment)
|
||||
@ -155,5 +172,31 @@ namespace
|
||||
CHECK_EQUAL(32, alignof(etl::type_with_alignment_t<32>));
|
||||
CHECK_EQUAL(64, alignof(etl::type_with_alignment_t<64>));
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
#if ETL_USING_CPP11
|
||||
TEST(test_typed_storage)
|
||||
{
|
||||
etl::typed_storage<A_t> a;
|
||||
|
||||
CHECK_EQUAL(false, a.has_value());
|
||||
|
||||
auto& b = a.create(123, 4);
|
||||
|
||||
CHECK_EQUAL(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_TRUE(*a == b);
|
||||
|
||||
CHECK_EQUAL(true, a.has_value());
|
||||
a.destroy();
|
||||
CHECK_EQUAL(false, a.has_value());
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user