Add support for in-place instantiation of a shared message in the message pool (#854)

* #850 Fixed names according to Arduino's guidelines

* #850 Fixed names according to Arduino's guidelines

* Add support for in-place instantiation of a shared message in the message pool

---------

Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com>
Co-authored-by: John Wellbelove <jwellbelove@users.noreply.github.com>
This commit is contained in:
SanderSmeenkInspiro 2024-03-08 11:02:47 +01:00 committed by GitHub
parent 1e1ce38113
commit 268ca4e04b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 151 additions and 6 deletions

View File

@ -72,9 +72,12 @@ namespace etl
//***************************************************************************
/// Constructor
/// \param owner The message owner.
/// \param args The constructor arguments.
//***************************************************************************
reference_counted_message(etl::ireference_counted_message_pool& owner_)
: owner(owner_)
template <typename... Args>
reference_counted_message(etl::ireference_counted_message_pool& owner_, Args&&... args)
: rc_object(etl::forward<Args>(args)...)
, owner(owner_)
{
}

View File

@ -100,6 +100,33 @@ namespace etl
{
}
//*************************************************************************
/// Allocate a reference counted message from the pool.
//*************************************************************************
template <typename TMessage, typename... Args>
etl::reference_counted_message<TMessage, TCounter>* allocate(const TMessage*, Args&&... args)
{
ETL_STATIC_ASSERT((etl::is_base_of<etl::imessage, TMessage>::value), "Not a message type");
typedef etl::reference_counted_message<TMessage, TCounter> rcm_t;
typedef rcm_t* prcm_t;
prcm_t p = ETL_NULLPTR;
lock();
p = static_cast<prcm_t>(memory_block_allocator.allocate(sizeof(rcm_t), etl::alignment_of<rcm_t>::value));
unlock();
if (p != ETL_NULLPTR)
{
::new(p) rcm_t(*this, etl::forward<Args>(args)...);
}
ETL_ASSERT((p != ETL_NULLPTR), ETL_ERROR(etl::reference_counted_message_pool_allocation_failure));
return p;
}
//*************************************************************************
/// Allocate a reference counted message from the pool.
//*************************************************************************

View File

@ -223,6 +223,15 @@ namespace etl
{
}
//***************************************************************************
/// Constructor.
//***************************************************************************
template <typename... Args>
reference_counted_object(Args&&... args)
: object(etl::forward<Args>(args)...)
{
}
//***************************************************************************
/// Get a reference to the counted object.
//***************************************************************************

View File

@ -49,6 +49,16 @@ namespace etl
{
public:
//*************************************************************************
/// Creator for in-place instantiation
//*************************************************************************
template <typename TMessage, typename TPool, typename... Args>
static shared_message create(TPool& owner, Args&&... args)
{
const TMessage* msg = nullptr;
return shared_message(owner, msg, etl::forward<Args>(args)...);
}
//*************************************************************************
/// Constructor
//*************************************************************************
@ -59,7 +69,24 @@ namespace etl
ETL_STATIC_ASSERT((etl::is_base_of<etl::imessage, TMessage>::value), "TMessage not derived from etl::imessage");
p_rcmessage = owner.allocate(message);
if (p_rcmessage != ETL_NULLPTR)
{
p_rcmessage->get_reference_counter().set_reference_count(1U);
}
}
//*************************************************************************
/// Constructor
//*************************************************************************
template <typename TPool, typename TMessage, typename... Args>
shared_message(TPool& owner, const TMessage* message, Args&&... args)
{
ETL_STATIC_ASSERT((etl::is_base_of<etl::ireference_counted_message_pool, TPool>::value), "TPool not derived from etl::ireference_counted_message_pool");
ETL_STATIC_ASSERT((etl::is_base_of<etl::imessage, TMessage>::value), "TMessage not derived from etl::imessage");
p_rcmessage = owner.allocate(message, etl::forward<Args>(args)...);
if (p_rcmessage != ETL_NULLPTR)
{
p_rcmessage->get_reference_counter().set_reference_count(1U);

View File

@ -44,12 +44,33 @@ namespace
constexpr etl::message_router_id_t RouterId1 = 1U;
constexpr etl::message_router_id_t RouterId2 = 2U;
int message_1_instantiations = 0;
//*************************************************************************
struct Message1 : public etl::message<MessageId1>
{
Message1()
: i(0)
{
++message_1_instantiations;
}
Message1(int i_)
: i(i_)
{
++message_1_instantiations;
}
Message1(const Message1& msg)
: i(msg.i)
{
++message_1_instantiations;
}
Message1(Message1&& msg)
: i(msg.i)
{
++message_1_instantiations;
}
~Message1()
@ -153,6 +174,27 @@ namespace
using pool_message_parameters = etl::atomic_counted_message_pool::pool_message_parameters<Message1, Message2>;
etl::fixed_sized_memory_block_allocator<pool_message_parameters::max_size,
pool_message_parameters::max_alignment,
4U> memory_allocator;
class atomic_counted_message_factory : public etl::atomic_counted_message_pool
{
public:
atomic_counted_message_factory(etl::imemory_block_allocator& memory_block_allocator_)
: etl::atomic_counted_message_pool(memory_block_allocator_)
{
}
template <typename TMessage, typename... Args>
etl::shared_message create_message(Args&&... args)
{
return etl::shared_message::create<TMessage>(*this, etl::forward<Args>(args)...);
}
};
atomic_counted_message_factory message_pool(memory_allocator);
//*************************************************************************
class Message2Allocator : public etl::ireference_counted_message_pool
{
@ -174,7 +216,7 @@ namespace
};
//*************************************************************************
TEST(test_move_constructor)
TEST(test_move_constructor_with_default_constructed_message)
{
etl::fixed_sized_memory_block_allocator<pool_message_parameters::max_size,
pool_message_parameters::max_alignment, 4U> memory_allocator;
@ -182,9 +224,46 @@ namespace
etl::atomic_counted_message_pool message_pool(memory_allocator);
#include "etl/private/diagnostic_pessimizing_move_push.h"
etl::shared_message sm1(std::move(etl::shared_message(message_pool, Message1(1))));
etl::shared_message sm(std::move(etl::shared_message(message_pool, Message1())));
#include "etl/private/diagnostic_pop.h"
CHECK_EQUAL(1, sm1.get_reference_count());
CHECK_EQUAL(1, sm.get_reference_count());
}
//*************************************************************************
TEST(test_move_constructor_with_default_constructed_message_inplace_in_message_pool)
{
message_1_instantiations = 0;
#include "etl/private/diagnostic_pessimizing_move_push.h"
etl::shared_message sm (std::move(message_pool.create_message<Message1>()));
#include "etl/private/diagnostic_pop.h"
CHECK_EQUAL(1, sm.get_reference_count());
CHECK_EQUAL(1, message_1_instantiations);
}
//*************************************************************************
TEST(test_move_constructor_with_parametrized_constructed_message)
{
#include "etl/private/diagnostic_pessimizing_move_push.h"
etl::shared_message sm(std::move(etl::shared_message(message_pool, Message1(1))));
#include "etl/private/diagnostic_pop.h"
CHECK_EQUAL(1, sm.get_reference_count());
}
//*************************************************************************
TEST(test_move_constructor_with_parametrized_constructed_message_inplace_in_message_pool)
{
message_1_instantiations = 0;
#include "etl/private/diagnostic_pessimizing_move_push.h"
etl::shared_message sm (std::move(message_pool.create_message<Message1>(1)));
#include "etl/private/diagnostic_pop.h"
CHECK_EQUAL(1, sm.get_reference_count());
CHECK_EQUAL(1, message_1_instantiations);
}
//*************************************************************************