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 (#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 <[email protected]>
Co-authored-by: John Wellbelove <[email protected]>
  • Loading branch information
3 people authored Mar 8, 2024
1 parent 1e1ce38 commit 268ca4e
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 6 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
85 changes: 82 additions & 3 deletions test/test_shared_message.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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
{
Expand All @@ -174,17 +216,54 @@ 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;

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);
}

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

0 comments on commit 268ca4e

Please sign in to comment.