Skip to content

Commit

Permalink
Add support for in-place instantiation of a shared message in the mes…
Browse files Browse the repository at this point in the history
…sage pool
  • Loading branch information
SanderSmeenkInspiro committed Mar 3, 2024
1 parent a98d387 commit 0d02eca
Show file tree
Hide file tree
Showing 5 changed files with 147 additions and 8 deletions.
7 changes: 5 additions & 2 deletions include/etl/reference_counted_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_)
{
}

Expand Down
27 changes: 27 additions & 0 deletions include/etl/reference_counted_message_pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//*************************************************************************
Expand Down
9 changes: 9 additions & 0 deletions include/etl/reference_counted_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//***************************************************************************
Expand Down
29 changes: 28 additions & 1 deletion include/etl/shared_message.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
//*************************************************************************
Expand All @@ -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);
Expand Down
83 changes: 78 additions & 5 deletions test/test_shared_message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,20 +44,41 @@ namespace
constexpr etl::message_router_id_t RouterId1 = 1U;
constexpr etl::message_router_id_t RouterId2 = 2U;

int_least_8_t 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()
{

}

int i;
int_least_8_t i;
};

//*************************************************************************
Expand Down Expand Up @@ -157,7 +178,22 @@ namespace
pool_message_parameters::max_alignment,
4U> memory_allocator;

etl::atomic_counted_message_pool message_pool(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
Expand All @@ -180,12 +216,49 @@ namespace
};

//*************************************************************************
TEST(test_move_constructor)
TEST(test_move_constructor_with_default_constructed_message)
{
#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);
}

//*************************************************************************
Expand Down

0 comments on commit 0d02eca

Please sign in to comment.