Added etl::contruct_object_at, etl::get_object_at and etl::destroy_object_at

This commit is contained in:
John Wellbelove 2023-02-19 10:43:13 +00:00
parent 2c15062c1b
commit 7316c07045
3 changed files with 272 additions and 0 deletions

View File

@ -100,5 +100,6 @@ SOFTWARE.
#define ETL_BIP_BUFFER_SPSC_ATOMIC_FILE_ID "67"
#define ETL_REFERENCE_COUNTED_OBJECT_FILE_ID "68"
#define ETL_TO_ARITHMETIC_FILE_ID "69"
#define ETL_ALIGNMENT_FILE_ID "70"
#endif

View File

@ -2446,6 +2446,103 @@ namespace etl
return (result == 0U) ? reinterpret_cast<const char*>(sb + n) : reinterpret_cast<const char*>(result);
}
#if ETL_USING_CPP11
//*****************************************************************************
/// Move construct the container at 'p'.
//*****************************************************************************
template <typename TObject>
TObject& construct_object_at(void* p, TObject&& other)
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(is_aligned<TObject>(p), ETL_ERROR(alignment_error));
#endif
return *etl::construct_at(reinterpret_cast<typename etl::remove_reference<TObject>::type*>(p), etl::forward<TObject>(other));
}
//*****************************************************************************
/// Construct the container at 'p' from arguments.
//*****************************************************************************
template <typename TObject, typename... TArgs>
TObject& construct_object_at(void* p, TArgs&&... args)
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(is_aligned<TObject>(p), ETL_ERROR(alignment_error));
#endif
return *etl::construct_at(reinterpret_cast<TObject*>(p), etl::forward<TArgs>(args)...);
}
#else
//*****************************************************************************
/// Default construct the container at 'p'.
//*****************************************************************************
template <typename TObject>
TObject& construct_object_at(void* p)
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(is_aligned<TObject>(p), ETL_ERROR(alignment_error));
#endif
return *etl::construct_at(reinterpret_cast<TObject*>(p));
}
//*****************************************************************************
/// Copy construct the container at 'p'.
//*****************************************************************************
template <typename TObject>
TObject& construct_object_at(void* p, const TObject& other)
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(is_aligned<TObject>(p), ETL_ERROR(alignment_error));
#endif
return *etl::construct_at(reinterpret_cast<TObject*>(p), other);
}
//*****************************************************************************
/// Construct the container at 'p' from argument.
//*****************************************************************************
template <typename TObject, typename TArg>
TObject& construct_object_at(void* p, const TArg& arg)
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(is_aligned<TObject>(p), ETL_ERROR(alignment_error));
#endif
return *etl::construct_at(reinterpret_cast<TObject*>(p), arg);
}
#endif
//*****************************************************************************
/// Get the container at 'p'.
//*****************************************************************************
template <typename TObject>
TObject& get_object_at(void* p)
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(is_aligned<TObject>(p), ETL_ERROR(alignment_error));
#endif
TObject& v = *reinterpret_cast<TObject*>(p);
return v;
}
//*****************************************************************************
/// Destroy the container at 'p'.
/// For a container that contains a type that is not trivially destructible.
//*****************************************************************************
template <typename TObject>
void destroy_object_at(void* p)
{
#if ETL_IS_DEBUG_BUILD
ETL_ASSERT(is_aligned<TObject>(p), ETL_ERROR(alignment_error));
#endif
TObject& v = get_object_at<TObject>(p);
v.~TObject();
}
}
#endif

View File

@ -1344,5 +1344,179 @@ namespace
CHECK(function_was_called);
CHECK(ptr.get() == ETL_NULLPTR);
}
//*************************************************************************
struct Flags
{
Flags()
: constructed(false)
, destructed(false)
{
}
void Clear()
{
constructed = false;
destructed = false;
}
bool constructed;
bool destructed;
};
static Flags flags;
TEST(test_construct_get_destroy_object_aligned)
{
struct Data
{
Data()
: a(1)
, b(2)
{
flags.constructed = true;
}
Data(int a_, int b_)
: a(a_)
, b(b_)
{
flags.constructed = true;
}
~Data()
{
flags.destructed = true;
}
int a;
int b;
};
alignas(Data) char buffer1[sizeof(Data)];
char* pbuffer1 = buffer1;
alignas(Data) char buffer1b[sizeof(Data)];
char* pbuffer1b = buffer1b;
alignas(Data) char buffer2[sizeof(Data)];
char* pbuffer2 = buffer2;
alignas(Data) char buffer2b[sizeof(Data)];
char* pbuffer2b = buffer2b;
alignas(Data) char buffer3[sizeof(Data)];
char* pbuffer3 = buffer3;
alignas(Data) char buffer3b[sizeof(Data)];
char* pbuffer3b = buffer3b;
flags.Clear();
Data& rdata1 = etl::construct_object_at<Data>(pbuffer1);
CHECK_TRUE(flags.constructed);
CHECK_FALSE(flags.destructed);
CHECK_EQUAL(1, rdata1.a);
CHECK_EQUAL(2, rdata1.b);
flags.Clear();
Data data2(3, 4);
Data& rdata2 = etl::construct_object_at(pbuffer2, data2);
CHECK_TRUE(flags.constructed);
CHECK_FALSE(flags.destructed);
CHECK_EQUAL(data2.a, rdata2.a);
CHECK_EQUAL(data2.b, rdata2.b);
flags.Clear();
Data& rdata3 = etl::construct_object_at<Data>(pbuffer3, 5, 6);
CHECK_TRUE(flags.constructed);
CHECK_FALSE(flags.destructed);
CHECK_EQUAL(5, rdata3.a);
CHECK_EQUAL(6, rdata3.b);
memcpy(buffer1b, buffer1, sizeof(Data));
memcpy(buffer2b, buffer2, sizeof(Data));
memcpy(buffer3b, buffer3, sizeof(Data));
flags.Clear();
Data& rdata1b = etl::get_object_at<Data>(pbuffer1b);
CHECK_FALSE(flags.constructed);
CHECK_FALSE(flags.destructed);
CHECK_EQUAL(1, rdata1.a);
CHECK_EQUAL(2, rdata1.b);
flags.Clear();
Data& rdata2b = etl::get_object_at<Data>(pbuffer2b);
CHECK_FALSE(flags.constructed);
CHECK_FALSE(flags.destructed);
CHECK_EQUAL(data2.a, rdata2.a);
CHECK_EQUAL(data2.b, rdata2.b);
flags.Clear();
Data& rdata3b = etl::get_object_at<Data>(pbuffer3b);
CHECK_FALSE(flags.constructed);
CHECK_FALSE(flags.destructed);
CHECK_EQUAL(5, rdata3.a);
CHECK_EQUAL(6, rdata3.b);
flags.Clear();
etl::destroy_object_at<Data>(pbuffer1b);
CHECK_FALSE(flags.constructed);
CHECK_TRUE(flags.destructed);
flags.Clear();
etl::destroy_object_at<Data>(pbuffer2b);
CHECK_FALSE(flags.constructed);
CHECK_TRUE(flags.destructed);
flags.Clear();
etl::destroy_object_at<Data>(pbuffer3b);
CHECK_FALSE(flags.constructed);
CHECK_TRUE(flags.destructed);
}
TEST(test_construct_get_destroy_object_misaligned)
{
struct Data
{
Data()
: a(1)
, b(2)
{
}
Data(int a_, int b_)
: a(a_)
, b(b_)
{
}
~Data()
{
}
int a;
int b;
};
alignas(Data) char buffer1[sizeof(Data)];
char* pbuffer1 = buffer1 + 1;
alignas(Data) char buffer2[sizeof(Data)];
char* pbuffer2 = buffer2 + 1;
alignas(Data) char buffer3[sizeof(Data)];
char* pbuffer3 = buffer3 + 1;
CHECK_THROW(etl::construct_object_at<Data>(pbuffer1), etl::alignment_error);
Data data2(3, 4);
CHECK_THROW(etl::construct_object_at(pbuffer2, data2), etl::alignment_error);
CHECK_THROW(etl::construct_object_at<Data>(pbuffer3, 5, 6), etl::alignment_error);
CHECK_THROW(etl::get_object_at<Data>(pbuffer1), etl::alignment_error);
CHECK_THROW(etl::destroy_object_at<Data>(pbuffer1), etl::alignment_error);
}
};
}