mirror of
https://github.com/ETLCPP/etl.git
synced 2026-06-28 13:28:43 +08:00
Added etl::typed_storage_ext and swap for same
This commit is contained in:
parent
aea6e7da8b
commit
33302790ba
@ -37,6 +37,7 @@ SOFTWARE.
|
||||
#include "error_handler.h"
|
||||
#include "exception.h"
|
||||
#include "utility.h"
|
||||
#include "algorithm.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -245,11 +246,6 @@ namespace etl
|
||||
{
|
||||
struct type
|
||||
{
|
||||
//type()
|
||||
// : data()
|
||||
//{
|
||||
//}
|
||||
|
||||
/// Convert to T reference.
|
||||
template <typename T>
|
||||
operator T& ()
|
||||
@ -382,6 +378,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
template <typename... TArgs>
|
||||
typed_storage(TArgs&&... args) ETL_NOEXCEPT_IF_NO_THROW
|
||||
: valid(false)
|
||||
{
|
||||
create(etl::forward<TArgs>(args)...);
|
||||
}
|
||||
@ -390,6 +387,7 @@ namespace etl
|
||||
/// Constructs the instance of T with type T1
|
||||
//***************************************************************************
|
||||
typed_storage(const T1& t1)
|
||||
: valid(false)
|
||||
{
|
||||
create(t1);
|
||||
}
|
||||
@ -398,6 +396,7 @@ namespace etl
|
||||
/// Constructs the instance of T with types T1, T2
|
||||
//***************************************************************************
|
||||
typed_storage(const T1& t1, const T2& t2)
|
||||
: valid(false)
|
||||
{
|
||||
create(t1, t2);
|
||||
}
|
||||
@ -406,6 +405,7 @@ namespace etl
|
||||
/// Constructs the instance of T with types T1, T2, T3
|
||||
//***************************************************************************
|
||||
typed_storage(const T1& t1, const T2& t2, const T3& t3)
|
||||
: valid(false)
|
||||
{
|
||||
create(t1, t2, t3);
|
||||
}
|
||||
@ -414,6 +414,7 @@ namespace etl
|
||||
/// 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)
|
||||
: valid(false)
|
||||
{
|
||||
create(t1, t2, t3, t4);
|
||||
}
|
||||
@ -554,7 +555,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
/// \returns a pointer of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
pointer operator->()
|
||||
pointer operator->() ETL_NOEXCEPT_IF_NO_THROW
|
||||
{
|
||||
ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error));
|
||||
|
||||
@ -564,7 +565,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
/// \returns a const pointer of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
const_pointer operator->() const
|
||||
const_pointer operator->() const ETL_NOEXCEPT_IF_NO_THROW
|
||||
{
|
||||
ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error));
|
||||
|
||||
@ -574,7 +575,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
/// \returns reference of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
reference operator*()
|
||||
reference operator*() ETL_NOEXCEPT_IF_NO_THROW
|
||||
{
|
||||
return *operator->();
|
||||
}
|
||||
@ -582,7 +583,7 @@ namespace etl
|
||||
//***************************************************************************
|
||||
/// \returns const_reference of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
const_reference operator*() const
|
||||
const_reference operator*() const ETL_NOEXCEPT_IF_NO_THROW
|
||||
{
|
||||
return *operator->();
|
||||
}
|
||||
@ -612,6 +613,256 @@ namespace etl
|
||||
|
||||
bool valid;
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Wrapper class that provides a memory area and lets the user create an
|
||||
/// 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_ext
|
||||
{
|
||||
public:
|
||||
|
||||
typedef T value_type;
|
||||
typedef T& reference;
|
||||
typedef const T& const_reference;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
|
||||
template <typename U>
|
||||
friend ETL_CONSTEXPR14 void swap(typed_storage_ext<U>& lhs, typed_storage_ext<U>& rhs) ETL_NOEXCEPT;
|
||||
|
||||
//***************************************************************************
|
||||
/// Constructor.
|
||||
//***************************************************************************
|
||||
template <typename... TArgs>
|
||||
typed_storage_ext(void* pbuffer_) ETL_NOEXCEPT_IF_NO_THROW
|
||||
: pbuffer(reinterpret_cast<T*>(pbuffer_)),
|
||||
valid(false)
|
||||
{
|
||||
ETL_ASSERT(etl::is_aligned(pbuffer_, etl::alignment_of<T>::value), ETL_ERROR(etl::alignment_error));
|
||||
}
|
||||
|
||||
#if ETL_USING_CPP11
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T forwarding the given \p args to its constructor.
|
||||
//***************************************************************************
|
||||
template <typename... TArgs>
|
||||
typed_storage_ext(void* pbuffer_, TArgs&&... args) ETL_NOEXCEPT_IF_NO_THROW
|
||||
: pbuffer(reinterpret_cast<T*>(pbuffer_))
|
||||
, valid(false)
|
||||
{
|
||||
ETL_ASSERT(etl::is_aligned(pbuffer_, etl::alignment_of<T>::value), ETL_ERROR(etl::alignment_error));
|
||||
create(etl::forward<TArgs>(args)...);
|
||||
}
|
||||
#else
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T with type T1
|
||||
//***************************************************************************
|
||||
typed_storage_ext(void* pbuffer_, const T1& t1)
|
||||
: pbuffer(reinterpret_cast<T*>(pbuffer_))
|
||||
, valid(false)
|
||||
{
|
||||
ETL_ASSERT(etl::is_aligned(pbuffer_, etl::alignment_of<T>::value), ETL_ERROR(etl::alignment_error));
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T with type T1
|
||||
//***************************************************************************
|
||||
typed_storage_ext(void* pbuffer_, const T1& t1)
|
||||
: pbuffer(reinterpret_cast<T*>(pbuffer_))
|
||||
, valid(false)
|
||||
{
|
||||
ETL_ASSERT(etl::is_aligned(pbuffer_, etl::alignment_of<T>::value), ETL_ERROR(etl::alignment_error));
|
||||
create(t1);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T with types T1, T2
|
||||
//***************************************************************************
|
||||
typed_storage_ext(void* pbuffer_, const T1& t1, const T2& t2)
|
||||
: pbuffer(reinterpret_cast<T*>(pbuffer_))
|
||||
, valid(false)
|
||||
{
|
||||
ETL_ASSERT(etl::is_aligned(pbuffer_, etl::alignment_of<T>::value), ETL_ERROR(etl::alignment_error));
|
||||
create(t1, t2);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T with types T1, T2, T3
|
||||
//***************************************************************************
|
||||
typed_storage_ext(void* pbuffer_, const T1& t1, const T2& t2, const T3& t3)
|
||||
: pbuffer(reinterpret_cast<T*>(pbuffer_))
|
||||
, valid(false)
|
||||
{
|
||||
ETL_ASSERT(etl::is_aligned(pbuffer_, etl::alignment_of<T>::value), ETL_ERROR(etl::alignment_error));
|
||||
create(t1, t2, t3);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T with types T1, T2, T3, T4
|
||||
//***************************************************************************
|
||||
typed_storage_ext(void* pbuffer_, const T1& t1, const T2& t2, const T3& t3, const T4& t4)
|
||||
: pbuffer(reinterpret_cast<T*>(pbuffer_))
|
||||
, valid(false)
|
||||
{
|
||||
ETL_ASSERT(etl::is_aligned(pbuffer_, etl::alignment_of<T>::value), ETL_ERROR(etl::alignment_error));
|
||||
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_ext() ETL_NOEXCEPT
|
||||
{
|
||||
// Intentionally empty.
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// \returns <b>true</b> if object has been constructed using create().
|
||||
/// \returns <b>false</b> otherwise.
|
||||
//***************************************************************************
|
||||
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.
|
||||
/// \returns the instance of T which has been constructed in the internal byte array.
|
||||
//***************************************************************************
|
||||
template <typename... TArgs>
|
||||
reference create(TArgs&&... args) ETL_NOEXCEPT_IF_NO_THROW
|
||||
{
|
||||
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
|
||||
valid = true;
|
||||
return *::new (pbuffer) value_type(etl::forward<TArgs>(args)...);
|
||||
}
|
||||
#else
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T with type T1
|
||||
/// \returns the instance of T which has been constructed in the internal byte array.
|
||||
//***************************************************************************
|
||||
template <typename T1>
|
||||
reference create(const T1& t1)
|
||||
{
|
||||
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
|
||||
valid = true;
|
||||
return *::new (pbuffer) value_type(t1);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T with types T1, T2
|
||||
/// \returns the instance of T which has been constructed in the internal byte array.
|
||||
//***************************************************************************
|
||||
template <typename T1, typename T2>
|
||||
reference create(const T1& t1, const T2& t2)
|
||||
{
|
||||
ETL_ASSERT(!has_value(), ETL_ERROR(etl::typed_storage_error));
|
||||
valid = true;
|
||||
return *::new (pbuffer) value_type(t1, t2);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T with types T1, T2, T3
|
||||
/// \returns the instance of T which has been constructed in the internal byte array.
|
||||
//***************************************************************************
|
||||
template <typename T1, typename T2, typename T3>
|
||||
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 (pbuffer) value_type(t1, t2, t3);
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// Constructs the instance of T with types T1, T2, T3, T4
|
||||
/// \returns the instance of T which has been constructed in the internal byte array.
|
||||
//***************************************************************************
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
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 (pbuffer) value_type(t1, t2, t3, t4);
|
||||
}
|
||||
#endif
|
||||
|
||||
//***************************************************************************
|
||||
/// Calls the destructor of the stored object, if created.
|
||||
//***************************************************************************
|
||||
void destroy() ETL_NOEXCEPT
|
||||
{
|
||||
if (has_value())
|
||||
{
|
||||
pbuffer->~T();
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// \returns a pointer of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
pointer operator->() ETL_NOEXCEPT_IF_NO_THROW
|
||||
{
|
||||
ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error));
|
||||
|
||||
return pbuffer;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// \returns a const pointer of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
const_pointer operator->() const ETL_NOEXCEPT_IF_NO_THROW
|
||||
{
|
||||
ETL_ASSERT(has_value(), ETL_ERROR(etl::typed_storage_error));
|
||||
|
||||
return pbuffer;
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// \returns reference of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
reference operator*() ETL_NOEXCEPT_IF_NO_THROW
|
||||
{
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
//***************************************************************************
|
||||
/// \returns const_reference of type T and asserts if has_value() is false.
|
||||
//***************************************************************************
|
||||
const_reference operator*() const ETL_NOEXCEPT_IF_NO_THROW
|
||||
{
|
||||
return *operator->();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
typed_storage_ext(etl::typed_storage_ext<T>&) ETL_DELETE;
|
||||
typed_storage_ext& operator =(etl::typed_storage_ext<T>&) ETL_DELETE;
|
||||
|
||||
T* pbuffer;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
//***************************************************************************
|
||||
/// Swap two etl::typed_storage_ext
|
||||
//***************************************************************************
|
||||
template <typename T>
|
||||
ETL_CONSTEXPR14 void swap(etl::typed_storage_ext<T>& lhs, etl::typed_storage_ext<T>& rhs) ETL_NOEXCEPT
|
||||
{
|
||||
using ETL_OR_STD::swap;
|
||||
|
||||
swap(lhs.pbuffer, rhs.pbuffer);
|
||||
swap(lhs.valid, rhs.valid);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -196,7 +196,7 @@ namespace
|
||||
etl::typed_storage<A_t> a;
|
||||
CHECK_FALSE(a.has_value());
|
||||
|
||||
etl::typed_storage<A_t> b(789, 10); // Construct in place.
|
||||
etl::typed_storage<A_t> b(789, 10); // Construct in place.
|
||||
CHECK_TRUE(b.has_value());
|
||||
CHECK_EQUAL(b->x, 789);
|
||||
CHECK_EQUAL(b->y, 10);
|
||||
@ -212,10 +212,45 @@ namespace
|
||||
|
||||
CHECK_TRUE(*a == ref);
|
||||
|
||||
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_FALSE(a.has_value());
|
||||
}
|
||||
|
||||
//*************************************************************************
|
||||
TEST(test_typed_storage_ext)
|
||||
{
|
||||
alignas(A_t) char buffer1[sizeof(A_t)] = {0};
|
||||
alignas(A_t) char buffer2[sizeof(A_t)] = {0};
|
||||
|
||||
etl::typed_storage_ext<A_t> a(buffer1);
|
||||
CHECK_FALSE(a.has_value());
|
||||
|
||||
etl::typed_storage_ext<A_t> b(buffer2, 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_EQUAL(ref.x, 123);
|
||||
CHECK_EQUAL(ref.y, 4);
|
||||
|
||||
CHECK_TRUE(a.has_value());
|
||||
CHECK_EQUAL(a->x, 123);
|
||||
CHECK_EQUAL(a->y, 4);
|
||||
CHECK_TRUE(*a == ref);
|
||||
|
||||
// Swap
|
||||
etl::swap(a, b);
|
||||
CHECK_TRUE(a.has_value());
|
||||
CHECK_EQUAL(a->x, 789);
|
||||
CHECK_EQUAL(a->y, 10);
|
||||
|
||||
CHECK_TRUE(b.has_value());
|
||||
CHECK_EQUAL(b->x, 123);
|
||||
CHECK_EQUAL(b->y, 4);
|
||||
|
||||
// Destroy
|
||||
CHECK_TRUE(a.has_value());
|
||||
a.destroy();
|
||||
CHECK_FALSE(a.has_value());
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user