diff --git a/include/etl/reference_counted_message.h b/include/etl/reference_counted_message.h index 69c35e2f..76c1a102 100644 --- a/include/etl/reference_counted_message.h +++ b/include/etl/reference_counted_message.h @@ -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 + reference_counted_message(etl::ireference_counted_message_pool& owner_, Args&&... args) + : rc_object(etl::forward(args)...) + , owner(owner_) { } diff --git a/include/etl/reference_counted_message_pool.h b/include/etl/reference_counted_message_pool.h index d678f9fe..a0c8779a 100644 --- a/include/etl/reference_counted_message_pool.h +++ b/include/etl/reference_counted_message_pool.h @@ -100,6 +100,33 @@ namespace etl { } + //************************************************************************* + /// Allocate a reference counted message from the pool. + //************************************************************************* + template + etl::reference_counted_message* allocate(const TMessage*, Args&&... args) + { + ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); + + typedef etl::reference_counted_message rcm_t; + typedef rcm_t* prcm_t; + + prcm_t p = ETL_NULLPTR; + + lock(); + p = static_cast(memory_block_allocator.allocate(sizeof(rcm_t), etl::alignment_of::value)); + unlock(); + + if (p != ETL_NULLPTR) + { + ::new(p) rcm_t(*this, etl::forward(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. //************************************************************************* diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h index e3458611..82f0af56 100644 --- a/include/etl/reference_counted_object.h +++ b/include/etl/reference_counted_object.h @@ -223,6 +223,15 @@ namespace etl { } + //*************************************************************************** + /// Constructor. + //*************************************************************************** + template + reference_counted_object(Args&&... args) + : object(etl::forward(args)...) + { + } + //*************************************************************************** /// Get a reference to the counted object. //*************************************************************************** diff --git a/include/etl/shared_message.h b/include/etl/shared_message.h index 013ea887..dbfce236 100644 --- a/include/etl/shared_message.h +++ b/include/etl/shared_message.h @@ -49,6 +49,16 @@ namespace etl { public: + //************************************************************************* + /// Creator for in-place instantiation + //************************************************************************* + template + static shared_message create(TPool& owner, Args&&... args) + { + const TMessage* msg = nullptr; + return shared_message(owner, msg, etl::forward(args)...); + } + //************************************************************************* /// Constructor //************************************************************************* @@ -59,7 +69,24 @@ namespace etl ETL_STATIC_ASSERT((etl::is_base_of::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 + shared_message(TPool& owner, const TMessage* message, Args&&... args) + { + ETL_STATIC_ASSERT((etl::is_base_of::value), "TPool not derived from etl::ireference_counted_message_pool"); + ETL_STATIC_ASSERT((etl::is_base_of::value), "TMessage not derived from etl::imessage"); + + p_rcmessage = owner.allocate(message, etl::forward(args)...); + if (p_rcmessage != ETL_NULLPTR) { p_rcmessage->get_reference_counter().set_reference_count(1U); diff --git a/test/test_shared_message.cpp b/test/test_shared_message.cpp index f84eb6e2..da4e4db7 100644 --- a/test/test_shared_message.cpp +++ b/test/test_shared_message.cpp @@ -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 { + 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; + etl::fixed_sized_memory_block_allocator 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 + etl::shared_message create_message(Args&&... args) + { + return etl::shared_message::create(*this, etl::forward(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 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())); +#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(1))); +#include "etl/private/diagnostic_pop.h" + + CHECK_EQUAL(1, sm.get_reference_count()); + CHECK_EQUAL(1, message_1_instantiations); } //*************************************************************************