From f3ace52884b87abb3729dccfbf0dfd74fb62f6d4 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 4 May 2020 13:32:19 +0100 Subject: [PATCH 01/18] Initial design --- include/etl/fsm.h | 38 +- include/etl/generators/fsm_generator.h | 4 +- .../etl/generators/message_packet_generator.h | 12 +- .../etl/generators/message_router_generator.h | 6 +- .../etl/generators/variant_pool_generator.h | 4 +- include/etl/generic_pool.h | 209 +++++++ include/etl/ipool.h | 495 +++++++++++++++ include/etl/list.h | 2 +- include/etl/memory.h | 10 + include/etl/message.h | 92 ++- include/etl/message_bus.h | 4 +- include/etl/message_packet.h | 96 +-- include/etl/message_pool.h | 258 ++++++++ include/etl/message_router.h | 34 +- include/etl/pool.h | 584 +----------------- include/etl/reference_counted_object.h | 51 ++ include/etl/shared_message.h | 137 ++++ include/etl/variant_pool.h | 252 +------- test/test_message_packet.cpp | 38 +- test/test_message_router.cpp | 10 +- test/test_pool_message.cpp | 127 ++++ test/test_variant_pool.cpp | 4 +- test/vs2019/etl.vcxproj | 5 + test/vs2019/etl.vcxproj.filters | 15 + 24 files changed, 1553 insertions(+), 934 deletions(-) create mode 100644 include/etl/generic_pool.h create mode 100644 include/etl/ipool.h create mode 100644 include/etl/message_pool.h create mode 100644 include/etl/reference_counted_object.h create mode 100644 include/etl/shared_message.h create mode 100644 test/test_pool_message.cpp diff --git a/include/etl/fsm.h b/include/etl/fsm.h index 7bc2eefd..cfde1a2b 100644 --- a/include/etl/fsm.h +++ b/include/etl/fsm.h @@ -211,8 +211,10 @@ namespace etl /// Constructor. //******************************************* fsm(etl::message_router_id_t id) - : imessage_router(id), - p_state(ETL_NULLPTR) + : imessage_router(id) + , p_state(ETL_NULLPTR) + , state_list(ETL_NULLPTR) + , number_of_states(0U) { } @@ -434,7 +436,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -499,7 +501,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -563,7 +565,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -626,7 +628,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -687,7 +689,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -747,7 +749,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -806,7 +808,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -864,7 +866,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -920,7 +922,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -975,7 +977,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -1029,7 +1031,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -1082,7 +1084,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -1133,7 +1135,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -1183,7 +1185,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -1232,7 +1234,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { @@ -1280,7 +1282,7 @@ namespace etl etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message) { etl::fsm_state_id_t new_state_id; - etl::message_id_t event_id = message.message_id; + etl::message_id_t event_id = message.get_message_id(); switch (event_id) { diff --git a/include/etl/generators/fsm_generator.h b/include/etl/generators/fsm_generator.h index 85552006..4d590025 100644 --- a/include/etl/generators/fsm_generator.h +++ b/include/etl/generators/fsm_generator.h @@ -454,7 +454,7 @@ namespace etl cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") cog.outl(" {") cog.outl(" etl::fsm_state_id_t new_state_id;") - cog.outl(" etl::message_id_t event_id = message.message_id;") + cog.outl(" etl::message_id_t event_id = message.get_message_id();") cog.outl("") cog.outl(" switch (event_id)") cog.outl(" {") @@ -531,7 +531,7 @@ namespace etl cog.outl(" etl::fsm_state_id_t process_event(etl::imessage_router& source, const etl::imessage& message)") cog.outl(" {") cog.outl(" etl::fsm_state_id_t new_state_id;") - cog.outl(" etl::message_id_t event_id = message.message_id;") + cog.outl(" etl::message_id_t event_id = message.get_message_id();") cog.outl("") cog.outl(" switch (event_id)") cog.outl(" {") diff --git a/include/etl/generators/message_packet_generator.h b/include/etl/generators/message_packet_generator.h index 9aa923e1..0661da8c 100644 --- a/include/etl/generators/message_packet_generator.h +++ b/include/etl/generators/message_packet_generator.h @@ -217,7 +217,7 @@ namespace etl cog.outl("#if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES)") cog.outl(" pmsg->~imessage();") cog.outl("#else") - cog.outl(" size_t id = pmsg->message_id;") + cog.outl(" size_t id = pmsg->get_message_id();") cog.outl("") cog.outl(" switch (id)") cog.outl(" {") @@ -232,7 +232,7 @@ namespace etl cog.outl(" //********************************************") cog.outl(" void add_new_message(const etl::imessage& msg)") cog.outl(" {") - cog.outl(" const size_t id = msg.message_id;") + cog.outl(" const size_t id = msg.get_message_id();") cog.outl(" void* p = data;") cog.outl("") cog.outl(" switch (id)") @@ -247,7 +247,7 @@ namespace etl cog.outl(" //********************************************") cog.outl(" void add_new_message(etl::imessage&& msg)") cog.outl(" {") - cog.outl(" const size_t id = msg.message_id;") + cog.outl(" const size_t id = msg.get_message_id();") cog.outl(" void* p = data;") cog.outl("") cog.outl(" switch (id)") @@ -416,7 +416,7 @@ namespace etl cog.outl("#if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES)") cog.outl(" pmsg->~imessage();") cog.outl("#else") - cog.outl(" size_t id = pmsg->message_id;") + cog.outl(" size_t id = pmsg->get_message_id();") cog.outl("") cog.outl(" switch (id)") cog.outl(" {") @@ -431,7 +431,7 @@ namespace etl cog.outl(" //********************************************") cog.outl(" void add_new_message(const etl::imessage& msg)") cog.outl(" {") - cog.outl(" const size_t id = msg.message_id;") + cog.outl(" const size_t id = msg.get_message_id();") cog.outl(" void* p = data;") cog.outl("") cog.outl(" switch (id)") @@ -446,7 +446,7 @@ namespace etl cog.outl(" //********************************************") cog.outl(" void add_new_message(etl::imessage&& msg)") cog.outl(" {") - cog.outl(" const size_t id = msg.message_id;") + cog.outl(" const size_t id = msg.get_message_id();") cog.outl(" void* p = data;") cog.outl("") cog.outl(" switch (id)") diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index 791b3297..4f0294b2 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -126,7 +126,7 @@ namespace etl //******************************************** bool accepts(const etl::imessage& msg) const { - return accepts(msg.message_id); + return accepts(msg.get_message_id()); } //******************************************** @@ -376,7 +376,7 @@ namespace etl cog.outl(" //**********************************************") cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE") cog.outl(" {") - cog.outl(" const etl::message_id_t id = msg.message_id;") + cog.outl(" const etl::message_id_t id = msg.get_message_id();") cog.outl("") cog.outl(" switch (id)") cog.outl(" {") @@ -509,7 +509,7 @@ namespace etl cog.outl(" //**********************************************") cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE") cog.outl(" {") - cog.outl(" const size_t id = msg.message_id;") + cog.outl(" const size_t id = msg.get_message_id();") cog.outl("") cog.outl(" switch (id)") cog.outl(" {") diff --git a/include/etl/generators/variant_pool_generator.h b/include/etl/generators/variant_pool_generator.h index cd9489d1..6cd00657 100644 --- a/include/etl/generators/variant_pool_generator.h +++ b/include/etl/generators/variant_pool_generator.h @@ -369,7 +369,7 @@ namespace etl /// Destroys the object. //************************************************************************* template - bool destroy(const T* const p) + void destroy(const T* const p) { /*[[[cog import cog @@ -395,12 +395,10 @@ namespace etl if (pool.is_in_pool(vp)) { pool.release(vp); - return true; } else { ETL_ASSERT(false, ETL_ERROR(variant_pool_did_not_create)); - return false; } } diff --git a/include/etl/generic_pool.h b/include/etl/generic_pool.h new file mode 100644 index 00000000..ac1fdbf1 --- /dev/null +++ b/include/etl/generic_pool.h @@ -0,0 +1,209 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_GENERIC_POOL_INCLUDED +#define ETL_GENERIC_POOL_INCLUDED + +#include "platform.h" +#include "ipool.h" +#include "type_traits.h" +#include "static_assert.h" +#include "alignment.h" + +#define ETL_POOL_CPP03_CODE 0 + +//***************************************************************************** +///\defgroup pool pool +/// A fixed capacity pool. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //************************************************************************* + /// A templated abstract pool implementation that uses a fixed size pool. + ///\ingroup pool + //************************************************************************* + template + class generic_pool : public etl::ipool + { + public: + + static const size_t SIZE = SIZE_; + static const size_t ALIGNMENT = ALIGNMENT_; + static const size_t TYPE_SIZE = TYPE_SIZE_; + + //************************************************************************* + /// Constructor + //************************************************************************* + generic_pool() + : etl::ipool(reinterpret_cast(&buffer[0]), ELEMENT_SIZE, SIZE) + { + } + + //************************************************************************* + /// Allocate an object from the pool. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. + /// Static asserts if the specified type is too large for the pool. + //************************************************************************* + template + U* allocate() + { + ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::allocate(); + } + +#if !ETL_CPP11_SUPPORTED || ETL_POOL_CPP03_CODE || defined(ETL_STLPORT) + //************************************************************************* + /// Allocate storage for an object from the pool and create with default. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. + //************************************************************************* + template + U* create() + { + ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 1 parameter. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. + //************************************************************************* + template + U* create(const T1& value1) + { + ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(value1); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 2 parameters. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. + //************************************************************************* + template + U* create(const T1& value1, const T2& value2) + { + ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(value1, value2); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 3 parameters. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. + //************************************************************************* + template + U* create(const T1& value1, const T2& value2, const T3& value3) + { + ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(value1, value2, value3); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 4 parameters. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. + //************************************************************************* + template + U* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(value1, value2, value3, value4); + } +#else + //************************************************************************* + /// Emplace with variadic constructor parameters. + //************************************************************************* + template + U* create(Args&&... args) + { + ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(etl::forward(args)...); + } +#endif + + //************************************************************************* + /// Releases the object. + /// \param p_object A pointer to the object to be destroyed. + //************************************************************************* + template + void release(const U* const p_object) + { + ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + ipool::release(p_object); + } + + //************************************************************************* + /// Destroys the object. + /// \param p_object A pointer to the object to be destroyed. + //************************************************************************* + template + void destroy(const U* const p_object) + { + ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + ipool::destroy(p_object); + } + + private: + + // The pool element. + union Element + { + char* next; ///< Pointer to the next free element. + char value[TYPE_SIZE_]; ///< Storage for value type. + typename etl::type_with_alignment::type dummy; ///< Dummy item to get correct alignment. + }; + + ///< The memory for the pool of objects. + typename etl::aligned_storage::value>::type buffer[SIZE]; + + static ETL_CONST_OR_CONSTEXPR uint32_t ELEMENT_SIZE = sizeof(Element); + + // Should not be copied. + generic_pool(const generic_pool&); + generic_pool& operator =(const generic_pool&); + }; +} + +#endif + diff --git a/include/etl/ipool.h b/include/etl/ipool.h new file mode 100644 index 00000000..018181ed --- /dev/null +++ b/include/etl/ipool.h @@ -0,0 +1,495 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2014 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_IPOOL_INCLUDED +#define ETL_IPOOL_INCLUDED + +#include "platform.h" +#include "error_handler.h" +#include "exception.h" +#include "static_assert.h" +#include "utility.h" +#include "memory.h" + +#include + +#undef ETL_FILE +#define ETL_FILE "11" + +#define ETL_POOL_CPP03_CODE 0 + +//***************************************************************************** +///\defgroup pool pool +/// A fixed capacity pool. +///\ingroup containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + /// The base class for pool exceptions. + ///\ingroup pool + //*************************************************************************** + class pool_exception : public exception + { + public: + + pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// The exception thrown when the pool has no more free items. + ///\ingroup pool + //*************************************************************************** + class pool_no_allocation : public pool_exception + { + public: + + explicit pool_no_allocation(string_type file_name_, numeric_type line_number_) + : pool_exception(ETL_ERROR_TEXT("pool:allocation", ETL_FILE"A"), file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// The exception thrown when an object is released which does not belong to the pool. + ///\ingroup pool + //*************************************************************************** + class pool_object_not_in_pool : public pool_exception + { + public: + + pool_object_not_in_pool(string_type file_name_, numeric_type line_number_) + : pool_exception(ETL_ERROR_TEXT("pool:not in pool", ETL_FILE"B"), file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// The exception thrown when an the type requested is larger than the element size. + ///\ingroup pool + //*************************************************************************** + class pool_element_size : public pool_exception + { + public: + + pool_element_size(string_type file_name_, numeric_type line_number_) + : pool_exception(ETL_ERROR_TEXT("pool:element size", ETL_FILE"C"), file_name_, line_number_) + {} + }; + + //*************************************************************************** + /// The base implementation of a pool. + /// Implements the imemory_block_pool interface. + //*************************************************************************** + class ipool : public imemory_block_pool + { + public: + + typedef size_t size_type; + + //************************************************************************* + /// Implementation of the low level imemory_block_pool interface. + //************************************************************************* + void* allocate_memory_block(size_t require_size) ETL_OVERRIDE + { + return allocate(); + } + + //************************************************************************* + /// Implementation of the low level imemory_block_pool interface. + //************************************************************************* + void release_memory_block(const void* const ptr) ETL_OVERRIDE + { + release(ptr); + } + + //************************************************************************* + /// Implementation of the low level imemory_block_pool interface. + //************************************************************************* + size_t get_memory_block_size() ETL_OVERRIDE + { + return ITEM_SIZE; + } + + //************************************************************************* + /// Allocate storage for an object from the pool. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. + //************************************************************************* + template + T* allocate() + { + if (sizeof(T) > ITEM_SIZE) + { + ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size)); + } + + return reinterpret_cast(allocate_item()); + } + +#if !ETL_CPP11_SUPPORTED || ETL_POOL_CPP03_CODE || defined(ETL_STLPORT) + //************************************************************************* + /// Allocate storage for an object from the pool and create default. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. + //************************************************************************* + template + T* create() + { + T* p = allocate(); + + if (p) + { + ::new (p) T(); + } + + return p; + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 1 parameter. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. + //************************************************************************* + template + T* create(const T1& value1) + { + T* p = allocate(); + + if (p) + { + ::new (p) T(value1); + } + + return p; + } + + template + T* create(const T1& value1, const T2& value2) + { + T* p = allocate(); + + if (p) + { + ::new (p) T(value1, value2); + } + + return p; + } + + template + T* create(const T1& value1, const T2& value2, const T3& value3) + { + T* p = allocate(); + + if (p) + { + ::new (p) T(value1, value2, value3); + } + + return p; + } + + template + T* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + T* p = allocate(); + + if (p) + { + ::new (p) T(value1, value2, value3, value4); + } + + return p; + } +#else + //************************************************************************* + /// Emplace with variadic constructor parameters. + //************************************************************************* + template + T* create(Args&&... args) + { + T* p = allocate(); + + if (p) + { + ::new (p) T(etl::forward(args)...); + } + + return p; + } +#endif + + //************************************************************************* + /// Destroys the object. + /// If asserts or exceptions are enabled and the object does not belong to this + /// pool then an etl::pool_object_not_in_pool is thrown. + /// Undefined behaviour if p_object is not a 'T' or derived from 'T'. + /// \param p_object A pointer to the object to be destroyed. + //************************************************************************* + template + void destroy(const T* const p_object) + { + // Does it belong to us? + if (is_in_pool(p_object)) + { + p_object->~T(); + release_item((char*)p_object); + } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(pool_object_not_in_pool)); + } + } + + //************************************************************************* + /// Release an object in the pool. + /// If asserts or exceptions are enabled and the object does not belong to this + /// pool then an etl::pool_object_not_in_pool is thrown. + /// \param p_object A pointer to the object to be released. + //************************************************************************* + void release(const void* const p_object) + { + // Does it belong to us? + if (is_in_pool(p_object)) + { + release_item((char*)p_object); + } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(pool_object_not_in_pool)); + } + } + + //************************************************************************* + /// Release all objects in the pool. + //************************************************************************* + void release_all() + { + items_allocated = 0; + items_initialised = 0; + p_next = p_buffer; + } + + //************************************************************************* + /// Check to see if the object belongs to the pool. + /// \param p_object A pointer to the object to be checked. + /// \return true<\b> if it does, otherwise false + //************************************************************************* + bool is_in_pool(const void* p_object) const + { + return is_item_in_pool((const char*)p_object); + } + + //************************************************************************* + /// Returns the maximum number of items in the pool. + //************************************************************************* + size_t max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns the maximum number of items in the pool. + //************************************************************************* + size_t capacity() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns the number of free items in the pool. + //************************************************************************* + size_t available() const + { + return MAX_SIZE - items_allocated; + } + + //************************************************************************* + /// Returns the number of allocated items in the pool. + //************************************************************************* + size_t size() const + { + return items_allocated; + } + + //************************************************************************* + /// Checks to see if there are no allocated items in the pool. + /// \return true if there are none allocated. + //************************************************************************* + bool empty() const + { + return items_allocated == 0; + } + + //************************************************************************* + /// Checks to see if there are no free items in the pool. + /// \return true if there are none free. + //************************************************************************* + bool full() const + { + return items_allocated == MAX_SIZE; + } + + protected: + + //************************************************************************* + /// Constructor + //************************************************************************* + ipool(char* p_buffer_, uint32_t item_size_, uint32_t max_size_) + : p_buffer(p_buffer_), + p_next(p_buffer_), + items_allocated(0), + items_initialised(0), + ITEM_SIZE(item_size_), + MAX_SIZE(max_size_) + { + } + + private: + + //************************************************************************* + /// Allocate an item from the pool. + //************************************************************************* + char* allocate_item() + { + char* p_value = ETL_NULLPTR; + + // Any free space left? + if (items_allocated < MAX_SIZE) + { + // Initialise another one if necessary. + if (items_initialised < MAX_SIZE) + { + char* p = p_buffer + (items_initialised * ITEM_SIZE); + char* np = p + ITEM_SIZE; + *reinterpret_cast(p) = np; + ++items_initialised; + } + + // Get the address of new allocated item. + p_value = p_next; + + ++items_allocated; + if (items_allocated != MAX_SIZE) + { + // Set up the pointer to the next free item + p_next = *reinterpret_cast(p_next); + } + else + { + // No more left! + p_next = ETL_NULLPTR; + } + } + else + { + ETL_ASSERT(false, ETL_ERROR(pool_no_allocation)); + } + + return p_value; + } + + //************************************************************************* + /// Release an item back to the pool. + //************************************************************************* + void release_item(char* p_value) + { + if (p_next != ETL_NULLPTR) + { + // Point it to the current free item. + *(uintptr_t*)p_value = reinterpret_cast(p_next); + } + else + { + // This is the only free item. + *((uintptr_t*)p_value) = 0; + } + + p_next = p_value; + + --items_allocated; + } + + //************************************************************************* + /// Check if the item belongs to this pool. + //************************************************************************* + bool is_item_in_pool(const char* p) const + { + // Within the range of the buffer? + intptr_t distance = p - p_buffer; + bool is_within_range = (distance >= 0) && (distance <= intptr_t((ITEM_SIZE * MAX_SIZE) - ITEM_SIZE)); + + // Modulus and division can be slow on some architectures, so only do this in debug. +#if defined(ETL_DEBUG) + // Is the address on a valid object boundary? + bool is_valid_address = ((distance % ITEM_SIZE) == 0); +#else + bool is_valid_address = true; +#endif + + return is_within_range && is_valid_address; + } + + // Disable copy construction and assignment. + ipool(const ipool&); + ipool& operator =(const ipool&); + + char* p_buffer; + char* p_next; + + uint32_t items_allocated; ///< The number of items allocated. + uint32_t items_initialised; ///< The number of items initialised. + + const uint32_t ITEM_SIZE; ///< The size of allocated items. + const uint32_t MAX_SIZE; ///< The maximum number of objects that can be allocated. + + //************************************************************************* + /// Destructor. + //************************************************************************* +#if defined(ETL_POLYMORPHIC_POOL) || defined(ETL_POLYMORPHIC_CONTAINERS) + public: + virtual ~ipool() + { + } +#else + protected: + ~ipool() + { + } +#endif + }; +} + +#undef ETL_FILE + +#endif + diff --git a/include/etl/list.h b/include/etl/list.h index c82b5cf7..c210d702 100644 --- a/include/etl/list.h +++ b/include/etl/list.h @@ -40,7 +40,6 @@ SOFTWARE. #include "algorithm.h" #include "iterator.h" #include "functional.h" - #include "container.h" #include "pool.h" #include "exception.h" @@ -51,6 +50,7 @@ SOFTWARE. #include "algorithm.h" #include "memory.h" #include "iterator.h" +#include "parameter_type.h" #if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) #include diff --git a/include/etl/memory.h b/include/etl/memory.h index 2d61360f..3787165f 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -1900,6 +1900,16 @@ namespace etl memory_clear(static_cast(*this)); } }; + + //************************************************************************* + /// The interface for a memory block pool. + //************************************************************************* + struct imemory_block_pool + { + virtual void* allocate_memory_block(size_t required_size) = 0; + virtual void release_memory_block(const void* const) = 0; + virtual size_t get_memory_block_size() = 0; + }; } #endif diff --git a/include/etl/message.h b/include/etl/message.h index 02baf2d5..c0e3dcaf 100644 --- a/include/etl/message.h +++ b/include/etl/message.h @@ -35,6 +35,7 @@ SOFTWARE. #include "error_handler.h" #include "exception.h" #include "message_types.h" +#include "reference_counted_object.h" #undef ETL_FILE #define ETL_FILE "38" @@ -68,39 +69,90 @@ namespace etl { public: - imessage(etl::message_id_t id) - : message_id(id) - { - } - - const etl::message_id_t message_id; - -#if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) virtual ~imessage() { } -#else - ~imessage() - { - } -#endif + + ETL_NODISCARD virtual etl::message_id_t get_message_id() const ETL_NOEXCEPT = 0; }; //*************************************************************************** - template - class message : public imessage + class ireference_counted_message : public etl::imessage, public etl::ireference_counted_object + { + }; + + //*************************************************************************** + template + class reference_counted_message : public etl::ireference_counted_message + { + private: + + //*************************************************************************** + void set_reference_count(uint32_t value) ETL_OVERRIDE + { + reference_count = value; + } + + //*************************************************************************** + void increment_reference_count() ETL_OVERRIDE + { + ++reference_count; + } + + //*************************************************************************** + ETL_NODISCARD uint32_t decrement_reference_count() ETL_OVERRIDE + { + return uint32_t(--reference_count); + } + + //*************************************************************************** + ETL_NODISCARD uint32_t get_reference_count() const ETL_OVERRIDE + { + return uint32_t(reference_count); + } + + private: + + /// The reference counter. + TCounter reference_count; + }; + + //*************************************************************************** + // Reference counted message. + //*************************************************************************** + template + class message : public reference_counted_message { public: - message() - : imessage(ID_) - { - } - enum { ID = ID_ }; + + ETL_NODISCARD etl::message_id_t get_message_id() const ETL_NOEXCEPT + { + return ID; + } + }; + + //*************************************************************************** + // Non-reference counted message. + //*************************************************************************** + template + class message : public imessage + { + public: + + enum + { + ID = ID_ + }; + + ETL_NODISCARD etl::message_id_t get_message_id() const ETL_NOEXCEPT + { + return ID; + } }; } diff --git a/include/etl/message_bus.h b/include/etl/message_bus.h index e981fe48..048ecc7e 100644 --- a/include/etl/message_bus.h +++ b/include/etl/message_bus.h @@ -187,7 +187,7 @@ namespace etl { etl::imessage_router& router = **irouter; - if (router.accepts(message.message_id)) + if (router.accepts(message.get_message_id())) { router.receive(source, message); } @@ -213,7 +213,7 @@ namespace etl // Call all of them. while (range.first != range.second) { - if ((*(range.first))->accepts(message.message_id)) + if ((*(range.first))->accepts(message.get_message_id())) { (*(range.first))->receive(source, message); } diff --git a/include/etl/message_packet.h b/include/etl/message_packet.h index eec72724..fa76295a 100644 --- a/include/etl/message_packet.h +++ b/include/etl/message_packet.h @@ -190,7 +190,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -219,7 +219,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -248,7 +248,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -403,7 +403,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -431,7 +431,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -459,7 +459,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -613,7 +613,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -640,7 +640,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -667,7 +667,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -820,7 +820,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -846,7 +846,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -872,7 +872,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1023,7 +1023,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -1048,7 +1048,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1073,7 +1073,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1223,7 +1223,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -1247,7 +1247,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1271,7 +1271,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1420,7 +1420,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -1443,7 +1443,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1466,7 +1466,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1614,7 +1614,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -1636,7 +1636,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1658,7 +1658,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1804,7 +1804,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -1825,7 +1825,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1846,7 +1846,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -1991,7 +1991,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -2011,7 +2011,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2031,7 +2031,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2175,7 +2175,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -2194,7 +2194,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2213,7 +2213,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2356,7 +2356,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -2374,7 +2374,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2392,7 +2392,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2533,7 +2533,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -2550,7 +2550,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2567,7 +2567,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2707,7 +2707,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -2723,7 +2723,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2739,7 +2739,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2878,7 +2878,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -2893,7 +2893,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -2908,7 +2908,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -3046,7 +3046,7 @@ namespace etl #if defined(ETL_MESSAGES_ARE_VIRTUAL) || defined(ETL_POLYMORPHIC_MESSAGES) pmsg->~imessage(); #else - size_t id = pmsg->message_id; + size_t id = pmsg->get_message_id(); switch (id) { @@ -3060,7 +3060,7 @@ namespace etl //******************************************** void add_new_message(const etl::imessage& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) @@ -3074,7 +3074,7 @@ namespace etl //******************************************** void add_new_message(etl::imessage&& msg) { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); void* p = data; switch (id) diff --git a/include/etl/message_pool.h b/include/etl/message_pool.h new file mode 100644 index 00000000..e1c19b3f --- /dev/null +++ b/include/etl/message_pool.h @@ -0,0 +1,258 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2020 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_MESSAGE_POOL_INCLUDED +#define ETL_MESSAGE_POOL_INCLUDED + +#include "platform.h" +#include "message.h" +#include "static_assert.h" +#include "error_handler.h" +#include "utility.h" + +namespace etl +{ + //*************************************************************************** + /// + //*************************************************************************** + class message_pool_allocation_exception : public etl::exception + { + public: + + message_pool_allocation_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// + //*************************************************************************** + class message_pool_allocation_failure : etl::message_pool_allocation_exception + { + public: + + message_pool_allocation_failure(string_type file_name_, numeric_type line_number_) + : message_pool_allocation_exception(ETL_ERROR_TEXT("message_pool:allocation failure", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// + //*************************************************************************** + class message_pool + { + public: + + //************************************************************************* + /// Constructor + //************************************************************************* + message_pool(imemory_block_pool& memory_block_pool_) + : memory_block_pool(memory_block_pool_) + { + } + +#if ETL_CPP11_SUPPORTED && !defined(ETL_MESSAGE_POOL_FORCE_CPP03) + //************************************************************************* + /// Create a message from the pool. + //************************************************************************* + template + TMessage* create(TArgs&&... args) + { + ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(etl::forward(args)...); + } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } + } + + return reinterpret_cast(p); + } +#else + //************************************************************************* + /// Create a message from the pool. No parameters. + //************************************************************************* + template + TMessage* create() + { + ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(); + } + } + + return reinterpret_cast(p); + } + + //************************************************************************* + /// Create a message from the pool. One parameter. + //************************************************************************* + template + TMessage* create(const T1& t1) + { + ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(t1); + } + } + + return reinterpret_cast(p); + } + + //************************************************************************* + /// Create a message from the pool. Two parameters. + //************************************************************************* + template + TMessage* create(const T1& t1, const T2& t2) + { + ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(t1, t2); + } + } + + return reinterpret_cast(p); + } + + //************************************************************************* + /// Create a message from the pool. Three parameters. + //************************************************************************* + template + TMessage* create(const T1& t1, const T2& t2, const T3& t3) + { + ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(t1, t2, t3); + } + } + + return reinterpret_cast(p); + } + + //************************************************************************* + /// Create a message from the pool. Four parameters. + //************************************************************************* + template + TMessage* create(const T1& t1, const T2& t2, const T3& t3, const T4& t4) + { + ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(t1, t2, t3, t4); + } + } + + return reinterpret_cast(p) + } +#endif + + //************************************************************************* + /// Destruct a message and send it back to the pool. + //************************************************************************* + void destroy(const etl::imessage* const pmsg) + { + pmsg->~imessage(); + memory_block_pool.release_memory_block(pmsg); + } + + //************************************************************************* + /// Destruct a message and send it back to the pool. + //************************************************************************* + void destroy(const etl::imessage& msg) + { + destroy(&msg); + } + + private: + + /// The raw memory block pool. + imemory_block_pool& memory_block_pool; + + // Should not be copied. + message_pool(const message_pool&) ETL_DELETE; + message_pool& operator =(const message_pool&) ETL_DELETE; + }; +} + +#undef ETL_FILE + +#endif + diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 761494c3..edc3900a 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -114,7 +114,7 @@ namespace etl //******************************************** bool accepts(const etl::imessage& msg) const { - return accepts(msg.message_id); + return accepts(msg.get_message_id()); } //******************************************** @@ -351,7 +351,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const etl::message_id_t id = msg.message_id; + const etl::message_id_t id = msg.get_message_id(); switch (id) { @@ -467,7 +467,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -582,7 +582,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -696,7 +696,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -808,7 +808,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -919,7 +919,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -1029,7 +1029,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -1138,7 +1138,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -1245,7 +1245,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -1351,7 +1351,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -1455,7 +1455,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -1558,7 +1558,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -1659,7 +1659,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -1759,7 +1759,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -1858,7 +1858,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { @@ -1956,7 +1956,7 @@ namespace etl //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { - const size_t id = msg.message_id; + const size_t id = msg.get_message_id(); switch (id) { diff --git a/include/etl/pool.h b/include/etl/pool.h index defe802f..af4f617a 100644 --- a/include/etl/pool.h +++ b/include/etl/pool.h @@ -32,24 +32,8 @@ SOFTWARE. #define ETL_POOL_INCLUDED #include "platform.h" - -#include - -#include "algorithm.h" -#include "iterator.h" -#include "utility.h" -#include "error_handler.h" -#include "alignment.h" -#include "array.h" -#include "container.h" -#include "integral_limits.h" -#include "nullptr.h" -#include "alignment.h" +#include "generic_pool.h" #include "static_assert.h" -#include "algorithm.h" - -#undef ETL_FILE -#define ETL_FILE "11" #define ETL_POOL_CPP03_CODE 0 @@ -61,553 +45,6 @@ SOFTWARE. namespace etl { - //*************************************************************************** - /// The base class for pool exceptions. - ///\ingroup pool - //*************************************************************************** - class pool_exception : public exception - { - public: - - pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_) - : exception(reason_, file_name_, line_number_) - {} - }; - - //*************************************************************************** - /// The exception thrown when the pool has no more free items. - ///\ingroup pool - //*************************************************************************** - class pool_no_allocation : public pool_exception - { - public: - - explicit pool_no_allocation(string_type file_name_, numeric_type line_number_) - : pool_exception(ETL_ERROR_TEXT("pool:allocation", ETL_FILE"A"), file_name_, line_number_) - {} - }; - - //*************************************************************************** - /// The exception thrown when an object is released which does not belong to the pool. - ///\ingroup pool - //*************************************************************************** - class pool_object_not_in_pool : public pool_exception - { - public: - - pool_object_not_in_pool(string_type file_name_, numeric_type line_number_) - : pool_exception(ETL_ERROR_TEXT("pool:not in pool", ETL_FILE"B"), file_name_, line_number_) - {} - }; - - //*************************************************************************** - /// The exception thrown when an the type requested is larger than the element size. - ///\ingroup pool - //*************************************************************************** - class pool_element_size : public pool_exception - { - public: - - pool_element_size(string_type file_name_, numeric_type line_number_) - : pool_exception(ETL_ERROR_TEXT("pool:element size", ETL_FILE"C"), file_name_, line_number_) - {} - }; - - //*************************************************************************** - ///\ingroup pool - //*************************************************************************** - class ipool - { - public: - - typedef size_t size_type; - - //************************************************************************* - /// Allocate storage for an object from the pool. - /// If asserts or exceptions are enabled and there are no more free items an - /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. - //************************************************************************* - template - T* allocate() - { - if (sizeof(T) > ITEM_SIZE) - { - ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size)); - } - - return reinterpret_cast(allocate_item()); - } - -#if !ETL_CPP11_SUPPORTED || ETL_POOL_CPP03_CODE || defined(ETL_STLPORT) - //************************************************************************* - /// Allocate storage for an object from the pool and create default. - /// If asserts or exceptions are enabled and there are no more free items an - /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. - //************************************************************************* - template - T* create() - { - T* p = allocate(); - - if (p) - { - ::new (p) T(); - } - - return p; - } - - //************************************************************************* - /// Allocate storage for an object from the pool and create with 1 parameter. - /// If asserts or exceptions are enabled and there are no more free items an - /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. - //************************************************************************* - template - T* create(const T1& value1) - { - T* p = allocate(); - - if (p) - { - ::new (p) T(value1); - } - - return p; - } - - template - T* create(const T1& value1, const T2& value2) - { - T* p = allocate(); - - if (p) - { - ::new (p) T(value1, value2); - } - - return p; - } - - template - T* create(const T1& value1, const T2& value2, const T3& value3) - { - T* p = allocate(); - - if (p) - { - ::new (p) T(value1, value2, value3); - } - - return p; - } - - template - T* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4) - { - T* p = allocate(); - - if (p) - { - ::new (p) T(value1, value2, value3, value4); - } - - return p; - } -#else - //************************************************************************* - /// Emplace with variadic constructor parameters. - //************************************************************************* - template - T* create(Args&&... args) - { - T* p = allocate(); - - if (p) - { - ::new (p) T(etl::forward(args)...); - } - - return p; - } -#endif - - //************************************************************************* - /// Destroys the object. - /// Undefined behaviour if the pool does not contain a 'T'. - /// \param p_object A pointer to the object to be destroyed. - //************************************************************************* - template - void destroy(const T* const p_object) - { - if (sizeof(T) > ITEM_SIZE) - { - ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size)); - } - - p_object->~T(); - release(p_object); - } - - //************************************************************************* - /// Release an object in the pool. - /// If asserts or exceptions are enabled and the object does not belong to this - /// pool then an etl::pool_object_not_in_pool is thrown. - /// \param p_object A pointer to the object to be released. - //************************************************************************* - void release(const void* const p_object) - { - release_item((char*)p_object); - } - - //************************************************************************* - /// Release all objects in the pool. - //************************************************************************* - void release_all() - { - items_allocated = 0; - items_initialised = 0; - p_next = p_buffer; - } - - //************************************************************************* - /// Check to see if the object belongs to the pool. - /// \param p_object A pointer to the object to be checked. - /// \return true<\b> if it does, otherwise false - //************************************************************************* - //template - bool is_in_pool(const void* p_object) const - { - return is_item_in_pool((const char*)p_object); - } - - //************************************************************************* - /// Returns the maximum number of items in the pool. - //************************************************************************* - size_t max_size() const - { - return MAX_SIZE; - } - - //************************************************************************* - /// Returns the maximum number of items in the pool. - //************************************************************************* - size_t capacity() const - { - return MAX_SIZE; - } - - //************************************************************************* - /// Returns the number of free items in the pool. - //************************************************************************* - size_t available() const - { - return MAX_SIZE - items_allocated; - } - - //************************************************************************* - /// Returns the number of allocated items in the pool. - //************************************************************************* - size_t size() const - { - return items_allocated; - } - - //************************************************************************* - /// Checks to see if there are no allocated items in the pool. - /// \return true if there are none allocated. - //************************************************************************* - bool empty() const - { - return items_allocated == 0; - } - - //************************************************************************* - /// Checks to see if there are no free items in the pool. - /// \return true if there are none free. - //************************************************************************* - bool full() const - { - return items_allocated == MAX_SIZE; - } - - protected: - - //************************************************************************* - /// Constructor - //************************************************************************* - ipool(char* p_buffer_, uint32_t item_size_, uint32_t max_size_) - : p_buffer(p_buffer_), - p_next(p_buffer_), - items_allocated(0), - items_initialised(0), - ITEM_SIZE(item_size_), - MAX_SIZE(max_size_) - { - } - - private: - - //************************************************************************* - /// Allocate an item from the pool. - //************************************************************************* - char* allocate_item() - { - char* p_value = ETL_NULLPTR; - - // Any free space left? - if (items_allocated < MAX_SIZE) - { - // Initialise another one if necessary. - if (items_initialised < MAX_SIZE) - { - char* p = p_buffer + (items_initialised * ITEM_SIZE); - char* np = p + ITEM_SIZE; - *reinterpret_cast(p) = np; - ++items_initialised; - } - - // Get the address of new allocated item. - p_value = p_next; - - ++items_allocated; - if (items_allocated != MAX_SIZE) - { - // Set up the pointer to the next free item - p_next = *reinterpret_cast(p_next); - } - else - { - // No more left! - p_next = ETL_NULLPTR; - } - } - else - { - ETL_ASSERT(false, ETL_ERROR(pool_no_allocation)); - } - - return p_value; - } - - //************************************************************************* - /// Release an item back to the pool. - //************************************************************************* - void release_item(char* p_value) - { - // Does it belong to us? - ETL_ASSERT(is_item_in_pool(p_value), ETL_ERROR(pool_object_not_in_pool)); - - if (p_next != ETL_NULLPTR) - { - // Point it to the current free item. - *(uintptr_t*)p_value = reinterpret_cast(p_next); - } - else - { - // This is the only free item. - *((uintptr_t*)p_value) = 0; - } - - p_next = p_value; - - --items_allocated; - } - - //************************************************************************* - /// Check if the item belongs to this pool. - //************************************************************************* - bool is_item_in_pool(const char* p) const - { - // Within the range of the buffer? - intptr_t distance = p - p_buffer; - bool is_within_range = (distance >= 0) && (distance <= intptr_t((ITEM_SIZE * MAX_SIZE) - ITEM_SIZE)); - - // Modulus and division can be slow on some architectures, so only do this in debug. -#if defined(ETL_DEBUG) - // Is the address on a valid object boundary? - bool is_valid_address = ((distance % ITEM_SIZE) == 0); -#else - bool is_valid_address = true; -#endif - - return is_within_range && is_valid_address; - } - - // Disable copy construction and assignment. - ipool(const ipool&); - ipool& operator =(const ipool&); - - char* p_buffer; - char* p_next; - - uint32_t items_allocated; ///< The number of items allocated. - uint32_t items_initialised; ///< The number of items initialised. - - const uint32_t ITEM_SIZE; ///< The size of allocated items. - const uint32_t MAX_SIZE; ///< The maximum number of objects that can be allocated. - - //************************************************************************* - /// Destructor. - //************************************************************************* -#if defined(ETL_POLYMORPHIC_POOL) || defined(ETL_POLYMORPHIC_CONTAINERS) - public: - virtual ~ipool() - { - } -#else - protected: - ~ipool() - { - } -#endif - }; - - //************************************************************************* - /// A templated abstract pool implementation that uses a fixed size pool. - ///\ingroup pool - //************************************************************************* - template - class generic_pool : public etl::ipool - { - public: - - static const size_t SIZE = SIZE_; - static const size_t ALIGNMENT = ALIGNMENT_; - static const size_t TYPE_SIZE = TYPE_SIZE_; - - //************************************************************************* - /// Constructor - //************************************************************************* - generic_pool() - : etl::ipool(reinterpret_cast(&buffer[0]), ELEMENT_SIZE, SIZE) - { - } - - //************************************************************************* - /// Allocate an object from the pool. - /// If asserts or exceptions are enabled and there are no more free items an - /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. - /// Static asserts if the specified type is too large for the pool. - //************************************************************************* - template - U* allocate() - { - ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); - ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); - return ipool::allocate(); - } - -#if !ETL_CPP11_SUPPORTED || ETL_POOL_CPP03_CODE || defined(ETL_STLPORT) - //************************************************************************* - /// Allocate storage for an object from the pool and create with default. - /// If asserts or exceptions are enabled and there are no more free items an - /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. - //************************************************************************* - template - U* create() - { - ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); - ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); - return ipool::create(); - } - - //************************************************************************* - /// Allocate storage for an object from the pool and create with 1 parameter. - /// If asserts or exceptions are enabled and there are no more free items an - /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. - //************************************************************************* - template - U* create(const T1& value1) - { - ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); - ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); - return ipool::create(value1); - } - - //************************************************************************* - /// Allocate storage for an object from the pool and create with 2 parameters. - /// If asserts or exceptions are enabled and there are no more free items an - /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. - //************************************************************************* - template - U* create(const T1& value1, const T2& value2) - { - ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); - ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); - return ipool::create(value1, value2); - } - - //************************************************************************* - /// Allocate storage for an object from the pool and create with 3 parameters. - /// If asserts or exceptions are enabled and there are no more free items an - /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. - //************************************************************************* - template - U* create(const T1& value1, const T2& value2, const T3& value3) - { - ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); - ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); - return ipool::create(value1, value2, value3); - } - - //************************************************************************* - /// Allocate storage for an object from the pool and create with 4 parameters. - /// If asserts or exceptions are enabled and there are no more free items an - /// etl::pool_no_allocation if thrown, otherwise a null pointer is returned. - //************************************************************************* - template - U* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4) - { - ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); - ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); - return ipool::create(value1, value2, value3, value4); - } -#else - //************************************************************************* - /// Emplace with variadic constructor parameters. - //************************************************************************* - template - U* create(Args&&... args) - { - ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); - ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); - return ipool::create(etl::forward(args)...); - } -#endif - - //************************************************************************* - /// Destroys the object. - /// Undefined behaviour if the pool does not contain a 'U'. - /// \param p_object A pointer to the object to be destroyed. - //************************************************************************* - template - void destroy(const U* const p_object) - { - ETL_STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); - ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); - p_object->~U(); - ipool::release(p_object); - } - - private: - - // The pool element. - union Element - { - char* next; ///< Pointer to the next free element. - char value[TYPE_SIZE_]; ///< Storage for value type. - typename etl::type_with_alignment::type dummy; ///< Dummy item to get correct alignment. - }; - - ///< The memory for the pool of objects. - typename etl::aligned_storage::value>::type buffer[SIZE]; - - static const uint32_t ELEMENT_SIZE = sizeof(Element); - - // Should not be copied. - generic_pool(const generic_pool&); - generic_pool& operator =(const generic_pool&); - }; //************************************************************************* /// A templated pool implementation that uses a fixed size pool. @@ -712,17 +149,28 @@ namespace etl } #endif + //************************************************************************* + /// Releases the object. + /// Undefined behaviour if the pool does not contain a 'U' object derived from 'U'. + /// \param p_object A pointer to the object to be destroyed. + //************************************************************************* + template + void release(const U* const p_object) + { + ETL_STATIC_ASSERT((etl::is_base_of::value), "Pool does not contain this type"); + base_t::template release(p_object); + } + //************************************************************************* /// Destroys the object. - /// Undefined behaviour if the pool does not contain a 'U'. + /// Undefined behaviour if the pool does not contain a 'U' object derived from 'U'. /// \param p_object A pointer to the object to be destroyed. //************************************************************************* template void destroy(const U* const p_object) { ETL_STATIC_ASSERT((etl::is_base_of::value), "Pool does not contain this type"); - p_object->~U(); - base_t::release(p_object); + base_t::template destroy(p_object); } private: @@ -733,7 +181,5 @@ namespace etl }; } -#undef ETL_FILE - #endif diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h new file mode 100644 index 00000000..fd3687e7 --- /dev/null +++ b/include/etl/reference_counted_object.h @@ -0,0 +1,51 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2020 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_REFERENCE_COUNTED_OBJECT_INCLUDED +#define ETL_REFERENCE_COUNTED_OBJECT_INCLUDED + +#include + +#include "platform.h" + +namespace etl +{ + //*************************************************************************** + class ireference_counted_object + { + public: + + virtual ~ireference_counted_object() {}; + virtual void set_reference_count(uint32_t value) = 0; + virtual void increment_reference_count() = 0; + ETL_NODISCARD virtual uint32_t decrement_reference_count() = 0; + ETL_NODISCARD virtual uint32_t get_reference_count() const = 0; + }; +} + +#endif diff --git a/include/etl/shared_message.h b/include/etl/shared_message.h new file mode 100644 index 00000000..030a666a --- /dev/null +++ b/include/etl/shared_message.h @@ -0,0 +1,137 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2020 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_SHARED_MESSAGE_INCLUDED +#define ETL_SHARED_MESSAGE_INCLUDED + +#include "platform.h" +#include "message_pool.h" +#include "message.h" + +//***************************************************************************** +/// A wrapper for reference countable messages. +/// Contains pointers to a pool owner and a message defined with a ref count type. +/// See etl::message template. +//***************************************************************************** +namespace etl +{ + class shared_message + { + public: + + //************************************************************************* + /// Constructor + /// \param owner_ A reference to the owner pool. + /// \param pmessage A reference to the message allocated from the pool. + //************************************************************************* + shared_message(etl::message_pool& owner_, etl::ireference_counted_message& message_) + : p_message_owner(&owner_) + , p_message(&message_) + { + p_message->set_reference_count(1U); + } + + //************************************************************************* + /// Copy constructor + //************************************************************************* + shared_message(const shared_message& other) + : p_message_owner(other.p_message_owner) + , p_message(other.p_message) + { + p_message->increment_reference_count(); + } + + //************************************************************************* + /// Copy assignment operator + //************************************************************************* + shared_message& operator =(const shared_message& other) + { + if (&other != this) + { + // Deal with the current message. + if (p_message->decrement_reference_count() == 0U) + { + p_message_owner->destroy(p_message); + } + + // Copy over the new one. + p_message_owner = other.p_message_owner; + p_message = other.p_message; + p_message->increment_reference_count(); + } + + return *this; + } + + //************************************************************************* + /// Destructor + /// Returns the message back to the pool it it is the last copy. + //************************************************************************* + ~shared_message() + { + if (p_message->decrement_reference_count() == 0U) + { + p_message_owner->destroy(p_message); + } + } + + //************************************************************************* + /// Get a reference to the contained message. + //************************************************************************* + etl::imessage& get_message() + { + return *p_message; + } + + //************************************************************************* + /// Get a const reference to the contained message. + //************************************************************************* + const etl::imessage& get_message() const + { + return *p_message; + } + + //************************************************************************* + /// Get the current reference count for this pool message. + //************************************************************************* + uint32_t get_reference_count() const + { + return p_message->get_reference_count(); + } + + private: + + etl::message_pool* p_message_owner; + etl::ireference_counted_message* p_message; + }; +} + +#endif + diff --git a/include/etl/variant_pool.h b/include/etl/variant_pool.h index a0dac60a..a5dc59dd 100644 --- a/include/etl/variant_pool.h +++ b/include/etl/variant_pool.h @@ -54,55 +54,13 @@ SOFTWARE. #include #include "platform.h" -#include "error_handler.h" -#include "exception.h" -#include "largest.h" +#include "generic_pool.h" #include "type_traits.h" -#include "alignment.h" #include "static_assert.h" -#include "type_lookup.h" -#include "pool.h" - -#include "utility.h" - -#undef ETL_FILE -#define ETL_FILE "40" +#include "largest.h" namespace etl { - //*************************************************************************** - class variant_pool_exception : public etl::exception - { - public: - - variant_pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_) - : exception(reason_, file_name_, line_number_) - { - } - }; - - //*************************************************************************** - class variant_pool_cannot_create : public etl::variant_pool_exception - { - public: - - variant_pool_cannot_create(string_type file_name_, numeric_type line_number_) - : variant_pool_exception(ETL_ERROR_TEXT("variant_pool:cannot create", ETL_FILE"A"), file_name_, line_number_) - { - } - }; - - //*************************************************************************** - class variant_pool_did_not_create : public etl::variant_pool_exception - { - public: - - variant_pool_did_not_create(string_type file_name_, numeric_type line_number_) - : variant_pool_exception(ETL_ERROR_TEXT("variant_pool:did not create", ETL_FILE"B"), file_name_, line_number_) - { - } - }; - //*************************************************************************** template - class variant_pool + class variant_pool : public etl::generic_pool::size, + etl::largest::alignment, + MAX_SIZE_> { public: + typedef etl::generic_pool::size, + etl::largest::alignment, + MAX_SIZE_> base_t; + static const size_t MAX_SIZE = MAX_SIZE_; //************************************************************************* @@ -143,23 +107,7 @@ namespace etl { ETL_STATIC_ASSERT((etl::is_one_of::value), "Unsupported type"); - T* p = ETL_NULLPTR; - - if (pool.full()) - { - ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); - } - else - { - p = pool.template allocate(); - - if (p != ETL_NULLPTR) - { - new (p) T(); - } - } - - return p; + return base_t::template create(); } //************************************************************************* @@ -170,23 +118,7 @@ namespace etl { ETL_STATIC_ASSERT((etl::is_one_of::value), "Unsupported type"); - T* p = ETL_NULLPTR; - - if (pool.full()) - { - ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); - } - else - { - p = pool.template allocate(); - - if (p != ETL_NULLPTR) - { - new (p) T(p1); - } - } - - return p; + return base_t::template create(p1); } //************************************************************************* @@ -197,23 +129,7 @@ namespace etl { ETL_STATIC_ASSERT((etl::is_one_of::value), "Unsupported type"); - T* p = ETL_NULLPTR; - - if (pool.full()) - { - ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); - } - else - { - p = pool.template allocate(); - - if (p != ETL_NULLPTR) - { - new (p) T(p1, p2); - } - } - - return p; + return base_t::template create(p1, p2); } //************************************************************************* @@ -224,23 +140,7 @@ namespace etl { ETL_STATIC_ASSERT((etl::is_one_of::value), "Unsupported type"); - T* p = ETL_NULLPTR; - - if (pool.full()) - { - ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); - } - else - { - p = pool.template allocate(); - - if (p != ETL_NULLPTR) - { - new (p) T(p1, p2, p3); - } - } - - return p; + return base_t::template create(p1, p2, p3); } //************************************************************************* @@ -251,23 +151,7 @@ namespace etl { ETL_STATIC_ASSERT((etl::is_one_of::value), "Unsupported type"); - T* p = ETL_NULLPTR; - - if (pool.full()) - { - ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); - } - else - { - p = pool.template allocate(); - - if (p != ETL_NULLPTR) - { - new (p) T(p1, p2, p3, p4); - } - } - - return p; + return base_t::template create(p1, p2, p3, p4); } #else //************************************************************************* @@ -278,23 +162,7 @@ namespace etl { ETL_STATIC_ASSERT((etl::is_one_of::value), "Unsupported type"); - T* p = ETL_NULLPTR; - - if (pool.full()) - { - ETL_ASSERT(false, ETL_ERROR(etl::variant_pool_cannot_create)); - } - else - { - p = pool.template allocate(); - - if (p != ETL_NULLPTR) - { - new (p) T(etl::forward(args)...); - } - } - - return p; + return base_t::template create(args...); } #endif @@ -302,40 +170,27 @@ namespace etl /// Destroys the object. //************************************************************************* template - bool destroy(const T* const p) + void destroy(const T* const p) { ETL_STATIC_ASSERT((etl::is_one_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value || - etl::is_base_of::value), "Invalid type"); + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value || + etl::is_base_of::value), "Invalid type"); - p->~T(); - - void* vp = reinterpret_cast(const_cast(p)); - - if (pool.is_in_pool(vp)) - { - pool.release(vp); - return true; - } - else - { - ETL_ASSERT(false, ETL_ERROR(variant_pool_did_not_create)); - return false; - } + base_t::destroy(p); } //************************************************************************* @@ -346,52 +201,11 @@ namespace etl return MAX_SIZE; } - //************************************************************************* - /// Returns the number of free items in the variant_pool. - //************************************************************************* - size_t available() const - { - return pool.available(); - } - - //************************************************************************* - /// Returns the number of allocated items in the variant_pool. - //************************************************************************* - size_t size() const - { - return pool.size(); - } - - //************************************************************************* - /// Checks to see if there are no allocated items in the variant_pool. - /// \return true if there are none allocated. - //************************************************************************* - bool empty() const - { - return pool.empty(); - } - - //************************************************************************* - /// Checks to see if there are no free items in the variant_pool. - /// \return true if there are none free. - //************************************************************************* - bool full() const - { - return pool.full(); - } - private: variant_pool(const variant_pool&); variant_pool& operator =(const variant_pool&); - - // The pool. - etl::generic_pool::size, - etl::largest::alignment, - MAX_SIZE> pool; }; } -#undef ETL_FILE - #endif diff --git a/test/test_message_packet.cpp b/test/test_message_packet.cpp index 54e90d5d..d5677937 100644 --- a/test/test_message_packet.cpp +++ b/test/test_message_packet.cpp @@ -199,9 +199,9 @@ namespace // The next line should result in a compile error. //Packet packet4(message4); - CHECK_EQUAL(MESSAGE1, packet1.get().message_id); - CHECK_EQUAL(MESSAGE2, packet2.get().message_id); - CHECK_EQUAL(MESSAGE3, packet3.get().message_id); + CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); + CHECK_EQUAL(MESSAGE2, packet2.get().get_message_id()); + CHECK_EQUAL(MESSAGE3, packet3.get().get_message_id()); CHECK(!static_cast(packet1.get()).moved); CHECK(!static_cast(packet2.get()).moved); @@ -225,8 +225,8 @@ namespace Packet packet1(message1); Packet packet2(std::move(message2)); - CHECK_EQUAL(MESSAGE1, packet1.get().message_id); - CHECK_EQUAL(MESSAGE2, packet2.get().message_id); + CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); + CHECK_EQUAL(MESSAGE2, packet2.get().get_message_id()); CHECK(!static_cast(packet1.get()).moved); CHECK(static_cast(packet2.get()).moved); @@ -253,9 +253,9 @@ namespace // The next line should result in a compile error. //Packet packet4(message4); - CHECK_EQUAL(MESSAGE1, packet1.get().message_id); - CHECK_EQUAL(MESSAGE2, packet2.get().message_id); - CHECK_EQUAL(MESSAGE3, packet3.get().message_id); + CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); + CHECK_EQUAL(MESSAGE2, packet2.get().get_message_id()); + CHECK_EQUAL(MESSAGE3, packet3.get().get_message_id()); CHECK_EQUAL(1, static_cast(packet1.get()).x); CHECK_EQUAL(2.2, static_cast(packet2.get()).x); @@ -276,9 +276,9 @@ namespace CHECK_THROW(Packet packet4(static_cast(message4)), etl::unhandled_message_exception); - CHECK_EQUAL(MESSAGE1, packet1.get().message_id); - CHECK_EQUAL(MESSAGE2, packet2.get().message_id); - CHECK_EQUAL(MESSAGE3, packet3.get().message_id); + CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); + CHECK_EQUAL(MESSAGE2, packet2.get().get_message_id()); + CHECK_EQUAL(MESSAGE3, packet3.get().get_message_id()); CHECK_EQUAL(1, static_cast(packet1.get()).x); CHECK_EQUAL(2.2, static_cast(packet2.get()).x); @@ -294,8 +294,8 @@ namespace Packet packet1(message1); Packet packet2(packet1); - CHECK_EQUAL(MESSAGE1, packet1.get().message_id); - CHECK_EQUAL(MESSAGE1, packet2.get().message_id); + CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); + CHECK_EQUAL(MESSAGE1, packet2.get().get_message_id()); CHECK(!static_cast(packet1.get()).moved); CHECK(!static_cast(packet2.get()).moved); @@ -316,8 +316,8 @@ namespace Packet packet1(message1); Packet packet2(std::move(Packet(message1))); - CHECK_EQUAL(MESSAGE1, packet1.get().message_id); - CHECK_EQUAL(MESSAGE1, packet2.get().message_id); + CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); + CHECK_EQUAL(MESSAGE1, packet2.get().get_message_id()); CHECK(!static_cast(packet1.get()).moved); CHECK(static_cast(packet2.get()).moved); @@ -340,8 +340,8 @@ namespace packet2 = packet1; - CHECK_EQUAL(MESSAGE1, packet1.get().message_id); - CHECK_EQUAL(MESSAGE1, packet2.get().message_id); + CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); + CHECK_EQUAL(MESSAGE1, packet2.get().get_message_id()); CHECK(!static_cast(packet1.get()).moved); CHECK(!static_cast(packet2.get()).moved); @@ -364,8 +364,8 @@ namespace packet2 = std::move(packet1); - CHECK_EQUAL(MESSAGE1, packet1.get().message_id); - CHECK_EQUAL(MESSAGE1, packet2.get().message_id); + CHECK_EQUAL(MESSAGE1, packet1.get().get_message_id()); + CHECK_EQUAL(MESSAGE1, packet2.get().get_message_id()); CHECK(!static_cast(packet1.get()).moved); CHECK(static_cast(packet2.get()).moved); diff --git a/test/test_message_router.cpp b/test/test_message_router.cpp index 9a9e9013..8f2ae9f9 100644 --- a/test/test_message_router.cpp +++ b/test/test_message_router.cpp @@ -416,19 +416,19 @@ namespace Router2 r2; CHECK(r2.accepts(message1)); - CHECK(r2.accepts(message1.message_id)); + CHECK(r2.accepts(message1.get_message_id())); CHECK(r2.accepts(message2)); - CHECK(r2.accepts(message2.message_id)); + CHECK(r2.accepts(message2.get_message_id())); CHECK(!r2.accepts(message3)); - CHECK(!r2.accepts(message3.message_id)); + CHECK(!r2.accepts(message3.get_message_id())); CHECK(r2.accepts(message4)); - CHECK(r2.accepts(message4.message_id)); + CHECK(r2.accepts(message4.get_message_id())); CHECK(r2.accepts(message5)); - CHECK(r2.accepts(message5.message_id)); + CHECK(r2.accepts(message5.get_message_id())); } //************************************************************************* diff --git a/test/test_pool_message.cpp b/test/test_pool_message.cpp new file mode 100644 index 00000000..21fccbca --- /dev/null +++ b/test/test_pool_message.cpp @@ -0,0 +1,127 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2020 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#include "UnitTest++/UnitTest++.h" + +#include "etl/pool.h" +#include "etl/shared_message.h" +#include "etl/message_pool.h" +#include "etl/variant_pool.h" +#include "etl/message.h" +#include "etl/atomic.h" + +namespace +{ + struct Message1 : public etl::message<1, uint32_t> + { + }; + + SUITE(test_shared_message) + { + constexpr size_t POOL_SIZE = 2; + + etl::variant_pool vpool; + + etl::message_pool mp(vpool); + + //************************************************************************* + TEST(test_buffered) + { + etl::message_pool& mpool = mp; + + { + etl::shared_message* pbuffered_sm = nullptr; + + { + etl::shared_message sm(mpool, *mpool.create()); + uint32_t count1 = sm.get_reference_count(); + + pbuffered_sm = new etl::shared_message(sm); + //uint32_t count2 = sm.get_reference_count(); + //uint32_t count3 = pbuffered_sm->get_reference_count(); + + etl::shared_message sm2 = etl::shared_message(mpool, *mpool.create()); + uint32_t count4 = sm2.get_reference_count(); + + pbuffered_sm = pbuffered_sm; + } + + size_t ps1 = vpool.size(); + + //{ + // uint32_t count = pbuffered_sm->get_reference_count(); + // etl::message_id_t id = pbuffered_sm->get_message().get_message_id(); + //} + + size_t ps2 = vpool.size(); + + delete pbuffered_sm; + } + + size_t ps3 = vpool.size(); + + vpool.size(); + } + } + + ////************************************************************************* + //TEST(test_construct_and_destruct) + //{ + // etl::pool pool; + // etl::pool_chain<1> pool_chain; + + // pool_chain.add(pool); + + // etl::shared_message buffered_sm(pool_chain); + + // { + // etl::shared_message sm1(pool_chain, pool.create()); + // CHECK_EQUAL(1, sm1.get_reference_count()); + // CHECK_EQUAL(1, pool.size()); + // { + // etl::shared_message sm2(sm1); + // CHECK_EQUAL(1, sm1.get_reference_count()); + // CHECK_EQUAL(2, sm2.get_reference_count()); + // CHECK_EQUAL(1, pool.size()); + // { + // etl::shared_message sm3(pool_chain); + // sm3 = sm2; + // CHECK_EQUAL(1, sm1.get_reference_count()); + // CHECK_EQUAL(2, sm2.get_reference_count()); + // CHECK_EQUAL(3, sm3.get_reference_count()); + // CHECK_EQUAL(1, pool.size()); + + // } + // CHECK_EQUAL(1, pool.size()); + // } + // CHECK_EQUAL(1, pool.size()); + // } + // CHECK_EQUAL(0, pool.size()); + //} + +} diff --git a/test/test_variant_pool.cpp b/test/test_variant_pool.cpp index b3ce2a03..8634cca9 100644 --- a/test/test_variant_pool.cpp +++ b/test/test_variant_pool.cpp @@ -202,7 +202,7 @@ namespace CHECK(!variant_pool.empty()); CHECK(variant_pool.full()); - CHECK_THROW(variant_pool.create(), etl::variant_pool_cannot_create); + CHECK_THROW(variant_pool.create(), etl::pool_no_allocation); } //************************************************************************* @@ -309,7 +309,7 @@ namespace CHECK_NO_THROW(variant_pool1.destroy(p)); p = variant_pool2.create(); - CHECK_THROW(variant_pool1.destroy(p), etl::variant_pool_did_not_create); + CHECK_THROW(variant_pool1.destroy(p), etl::pool_object_not_in_pool); } }; } diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 31526554..2c83fe22 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1045,11 +1045,14 @@ + + + @@ -1079,6 +1082,7 @@ + @@ -1586,6 +1590,7 @@ + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index 5200c57a..54827642 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -852,6 +852,18 @@ ETL\Containers\Generators + + ETL\Containers + + + ETL\Containers + + + ETL\Frameworks + + + ETL\Frameworks + @@ -1313,6 +1325,9 @@ Source Files + + Source Files + From 120d9b4eba575cc48f7245cc82f04a8fd75490b5 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 4 May 2020 13:32:19 +0100 Subject: [PATCH 02/18] Initial design --- include/etl/message_pool.h | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/include/etl/message_pool.h b/include/etl/message_pool.h index e1c19b3f..f5a46f84 100644 --- a/include/etl/message_pool.h +++ b/include/etl/message_pool.h @@ -126,6 +126,10 @@ namespace etl { ::new(p) TMessage(); } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } } return reinterpret_cast(p); @@ -149,6 +153,10 @@ namespace etl { ::new(p) TMessage(t1); } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } } return reinterpret_cast(p); @@ -172,6 +180,10 @@ namespace etl { ::new(p) TMessage(t1, t2); } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } } return reinterpret_cast(p); @@ -195,6 +207,10 @@ namespace etl { ::new(p) TMessage(t1, t2, t3); } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } } return reinterpret_cast(p); @@ -218,6 +234,10 @@ namespace etl { ::new(p) TMessage(t1, t2, t3, t4); } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } } return reinterpret_cast(p) @@ -229,8 +249,11 @@ namespace etl //************************************************************************* void destroy(const etl::imessage* const pmsg) { - pmsg->~imessage(); - memory_block_pool.release_memory_block(pmsg); + if (pmsg != ETL_NULLPTR) + { + pmsg->~imessage(); + memory_block_pool.release_memory_block(pmsg); + } } //************************************************************************* From 7d47be6d753468df7d46e6a2ff57d6d657a6b4cc Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 5 May 2020 10:12:50 +0100 Subject: [PATCH 03/18] Small changes --- include/etl/generic_pool.h | 4 ++-- include/etl/memory.h | 6 +++--- include/etl/pool.h | 4 ++-- include/etl/variant_pool.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/etl/generic_pool.h b/include/etl/generic_pool.h index ac1fdbf1..b5b59846 100644 --- a/include/etl/generic_pool.h +++ b/include/etl/generic_pool.h @@ -200,8 +200,8 @@ namespace etl static ETL_CONST_OR_CONSTEXPR uint32_t ELEMENT_SIZE = sizeof(Element); // Should not be copied. - generic_pool(const generic_pool&); - generic_pool& operator =(const generic_pool&); + generic_pool(const generic_pool&) ETL_DELETE; + generic_pool& operator =(const generic_pool&) ETL_DELETE; }; } diff --git a/include/etl/memory.h b/include/etl/memory.h index 3787165f..5bccbe87 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -1594,7 +1594,7 @@ namespace etl ///\ingroup memory //***************************************************************************** template - void create_value_at(T* p) + void create_value_at(T* p) { ::new (p) T(); } @@ -1604,7 +1604,7 @@ namespace etl ///\ingroup memory //***************************************************************************** template - void create_value_at(T* p, TCounter& count) + void create_value_at(T* p, TCounter& count) { ::new (p) T(); ++count; @@ -1615,7 +1615,7 @@ namespace etl ///\ingroup memory //***************************************************************************** template - void create_copy_at(T* p, const T& value) + void create_copy_at(T* p, const T& value) { ::new (p) T(value); } diff --git a/include/etl/pool.h b/include/etl/pool.h index af4f617a..b41575b1 100644 --- a/include/etl/pool.h +++ b/include/etl/pool.h @@ -176,8 +176,8 @@ namespace etl private: // Should not be copied. - pool(const pool&); - pool& operator =(const pool&); + pool(const pool&) ETL_DELETE; + pool& operator =(const pool&) ETL_DELETE; }; } diff --git a/include/etl/variant_pool.h b/include/etl/variant_pool.h index a5dc59dd..7ac3dbb3 100644 --- a/include/etl/variant_pool.h +++ b/include/etl/variant_pool.h @@ -203,8 +203,8 @@ namespace etl private: - variant_pool(const variant_pool&); - variant_pool& operator =(const variant_pool&); + variant_pool(const variant_pool&) ETL_DELETE; + variant_pool& operator =(const variant_pool&) ETL_DELETE; }; } From 013598da606a6ebebe42339bf4059db6d32675f6 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Tue, 5 May 2020 13:24:41 +0100 Subject: [PATCH 04/18] Added ishared_message_processor --- include/etl/ishared_message_processor.h | 51 ++++++++++++++++++ include/etl/message.h | 9 +++- test/test_pool_message.cpp | 72 +++++++++++++++++++++++++ test/vs2019/etl.vcxproj | 1 + test/vs2019/etl.vcxproj.filters | 3 ++ 5 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 include/etl/ishared_message_processor.h diff --git a/include/etl/ishared_message_processor.h b/include/etl/ishared_message_processor.h new file mode 100644 index 00000000..79261efb --- /dev/null +++ b/include/etl/ishared_message_processor.h @@ -0,0 +1,51 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2020 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_SHARED_MESSAGE_PROCESSOR_INCLUDED +#define ETL_SHARED_MESSAGE_PROCESSOR_INCLUDED + +#include "platform.h" +#include "shared_message.h" +#include "message_router.h" + +namespace etl +{ + //*************************************************************************** + /// This is the base of all shared message processors. + //*************************************************************************** + class ishared_message_processor + { + public: + + virtual ~ishared_message_processor() {} + virtual void receive(etl::shared_message message) = 0; + virtual void receive(imessage_router& source, etl::shared_message message) = 0; + }; +} + +#endif diff --git a/include/etl/message.h b/include/etl/message.h index c0e3dcaf..ce5d79d1 100644 --- a/include/etl/message.h +++ b/include/etl/message.h @@ -85,6 +85,13 @@ namespace etl template class reference_counted_message : public etl::ireference_counted_message { + public: + + reference_counted_message() + : reference_count(TCounter()) + { + } + private: //*************************************************************************** @@ -111,8 +118,6 @@ namespace etl return uint32_t(reference_count); } - private: - /// The reference counter. TCounter reference_count; }; diff --git a/test/test_pool_message.cpp b/test/test_pool_message.cpp index 21fccbca..cdf41d77 100644 --- a/test/test_pool_message.cpp +++ b/test/test_pool_message.cpp @@ -35,12 +35,76 @@ SOFTWARE. #include "etl/message.h" #include "etl/atomic.h" +#include "etl/queue.h" +#include "etl/ishared_message_processor.h" + namespace { + //************************************************************************* struct Message1 : public etl::message<1, uint32_t> { }; + //************************************************************************* + struct Router : public etl::message_router + { + Router() + : message_router(1) + { + + } + + void on_receive(const Message1& message) + { + + } + + void on_receive(etl::imessage_router& source, const Message1& message) + { + + } + + void on_receive_unknown(etl::imessage_router& source, const etl::imessage& message) + { + + } + }; + + //************************************************************************* + struct Processor : public etl::ishared_message_processor + { + Processor(etl::imessage_router& router_) + : router(router_) + { + } + + void receive(etl::shared_message message) + { + uint32_t count1 = message.get_reference_count(); + + smqueue.push(message); + + uint32_t count2 = message.get_reference_count(); + } + + void receive(etl::imessage_router& source, etl::shared_message message) + { + + } + + void Process() + { + router.receive(smqueue.front().get_message()); + smqueue.pop(); + } + + etl::imessage_router& router; + etl::queue smqueue; + }; + + Router router; + Processor processor(router); + SUITE(test_shared_message) { constexpr size_t POOL_SIZE = 2; @@ -61,6 +125,14 @@ namespace etl::shared_message sm(mpool, *mpool.create()); uint32_t count1 = sm.get_reference_count(); + processor.receive(sm); + + uint32_t count1b = sm.get_reference_count(); + + processor.Process(); + + uint32_t count1c = sm.get_reference_count(); + pbuffered_sm = new etl::shared_message(sm); //uint32_t count2 = sm.get_reference_count(); //uint32_t count3 = pbuffered_sm->get_reference_count(); diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 2c83fe22..3a42097c 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1083,6 +1083,7 @@ + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index 54827642..c91ead81 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -864,6 +864,9 @@ ETL\Frameworks + + ETL\Frameworks + From fdcc2c00d3cbba8719865f105a9e9b8f205ff7bf Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 5 Dec 2020 11:55:40 +0000 Subject: [PATCH 05/18] Minor changes --- ..._processor.h => shared_message_processor.h} | 18 ++++++++++++++++-- test/test_pool_message.cpp | 12 +++++------- test/vs2019/etl.vcxproj | 2 +- test/vs2019/etl.vcxproj.filters | 2 +- 4 files changed, 23 insertions(+), 11 deletions(-) rename include/etl/{ishared_message_processor.h => shared_message_processor.h} (86%) diff --git a/include/etl/ishared_message_processor.h b/include/etl/shared_message_processor.h similarity index 86% rename from include/etl/ishared_message_processor.h rename to include/etl/shared_message_processor.h index 79261efb..d0038f58 100644 --- a/include/etl/ishared_message_processor.h +++ b/include/etl/shared_message_processor.h @@ -38,13 +38,27 @@ namespace etl //*************************************************************************** /// This is the base of all shared message processors. //*************************************************************************** - class ishared_message_processor + class shared_message_processor { public: - virtual ~ishared_message_processor() {} + shared_message_processor(imessage_router& router_) + : router(router_) + { + } + + virtual ~shared_message_processor() {} virtual void receive(etl::shared_message message) = 0; virtual void receive(imessage_router& source, etl::shared_message message) = 0; + + imessage_router& get_router() const + { + return router; + } + + private: + + imessage_router& router; }; } diff --git a/test/test_pool_message.cpp b/test/test_pool_message.cpp index cdf41d77..12f7e6cc 100644 --- a/test/test_pool_message.cpp +++ b/test/test_pool_message.cpp @@ -36,7 +36,7 @@ SOFTWARE. #include "etl/atomic.h" #include "etl/queue.h" -#include "etl/ishared_message_processor.h" +#include "etl/shared_message_processor.h" namespace { @@ -71,10 +71,10 @@ namespace }; //************************************************************************* - struct Processor : public etl::ishared_message_processor + struct Processor : public etl::shared_message_processor { - Processor(etl::imessage_router& router_) - : router(router_) + Processor(Router& router_) + : shared_message_processor(router_) { } @@ -89,16 +89,14 @@ namespace void receive(etl::imessage_router& source, etl::shared_message message) { - } void Process() { - router.receive(smqueue.front().get_message()); + get_router().receive(smqueue.front().get_message()); smqueue.pop(); } - etl::imessage_router& router; etl::queue smqueue; }; diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 3a42097c..3966d4fa 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1083,7 +1083,7 @@ - + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index c91ead81..db18e69c 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -864,7 +864,7 @@ ETL\Frameworks - + ETL\Frameworks From eeb057a99dcbd7b9601f62c34c9a43739d259d9d Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 30 Dec 2020 10:02:12 +0000 Subject: [PATCH 06/18] Moved code lines --- include/etl/shared_message_processor.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/etl/shared_message_processor.h b/include/etl/shared_message_processor.h index d0038f58..9b372be3 100644 --- a/include/etl/shared_message_processor.h +++ b/include/etl/shared_message_processor.h @@ -47,15 +47,15 @@ namespace etl { } - virtual ~shared_message_processor() {} - virtual void receive(etl::shared_message message) = 0; - virtual void receive(imessage_router& source, etl::shared_message message) = 0; - imessage_router& get_router() const { return router; } + virtual ~shared_message_processor() {} + virtual void receive(etl::shared_message message) = 0; + virtual void receive(imessage_router& source, etl::shared_message message) = 0; + private: imessage_router& router; From 5abae28f1631fc5465412b1ca15eea5503ffa0b1 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 1 Jan 2021 17:07:53 +0000 Subject: [PATCH 07/18] Interim commit --- include/etl/message.h | 110 ++++--- include/etl/message_pool.h | 5 +- include/etl/reference_counted_message_pool.h | 322 +++++++++++++++++++ include/etl/reference_counted_object.h | 102 ++++-- include/etl/shared_message.h | 55 +++- include/etl/shared_message_processor.h | 309 +++++++++++++++++- 6 files changed, 795 insertions(+), 108 deletions(-) create mode 100644 include/etl/reference_counted_message_pool.h diff --git a/include/etl/message.h b/include/etl/message.h index ce5d79d1..1efd8c80 100644 --- a/include/etl/message.h +++ b/include/etl/message.h @@ -64,6 +64,8 @@ namespace etl } }; + //*************************************************************************** + // Message interface. //*************************************************************************** class imessage { @@ -77,87 +79,83 @@ namespace etl }; //*************************************************************************** - class ireference_counted_message : public etl::imessage, public etl::ireference_counted_object - { - }; - + // Message type. //*************************************************************************** - template - class reference_counted_message : public etl::ireference_counted_message + template + class message : public imessage { public: - reference_counted_message() - : reference_count(TCounter()) + enum { + ID = ID_ + }; + + ETL_NODISCARD etl::message_id_t get_message_id() const ETL_NOEXCEPT ETL_OVERRIDE + { + return ID; + } + }; + + class ireference_counted_message + { + public: + + virtual etl::imessage* get_message() = 0; + virtual const etl::imessage* get_message() const = 0; + virtual ~ireference_counted_message() {}; + virtual void set_reference_count(uint32_t value) = 0; + virtual void increment_reference_count() = 0; + ETL_NODISCARD virtual uint32_t decrement_reference_count() = 0; + ETL_NODISCARD virtual uint32_t get_reference_count() const = 0; + }; + + //******************************************************* + template + class reference_counted_message : virtual public ireference_counted_message + { + public: + + reference_counted_message(const TMessage& msg_) + : msg(msg_) + { + reference_count = 0; } - private: + virtual TMessage* get_message() ETL_OVERRIDE + { + return &msg; + } - //*************************************************************************** - void set_reference_count(uint32_t value) ETL_OVERRIDE + virtual const TMessage* get_message() const ETL_OVERRIDE + { + return &msg; + } + + virtual void set_reference_count(uint32_t value) ETL_OVERRIDE { reference_count = value; } - //*************************************************************************** - void increment_reference_count() ETL_OVERRIDE + virtual void increment_reference_count() ETL_OVERRIDE { ++reference_count; } - //*************************************************************************** - ETL_NODISCARD uint32_t decrement_reference_count() ETL_OVERRIDE + ETL_NODISCARD virtual uint32_t decrement_reference_count() ETL_OVERRIDE { return uint32_t(--reference_count); } - //*************************************************************************** - ETL_NODISCARD uint32_t get_reference_count() const ETL_OVERRIDE + ETL_NODISCARD virtual uint32_t get_reference_count() const ETL_OVERRIDE { return uint32_t(reference_count); } - /// The reference counter. + private: + TCounter reference_count; - }; - - //*************************************************************************** - // Reference counted message. - //*************************************************************************** - template - class message : public reference_counted_message - { - public: - - enum - { - ID = ID_ - }; - - ETL_NODISCARD etl::message_id_t get_message_id() const ETL_NOEXCEPT - { - return ID; - } - }; - - //*************************************************************************** - // Non-reference counted message. - //*************************************************************************** - template - class message : public imessage - { - public: - - enum - { - ID = ID_ - }; - - ETL_NODISCARD etl::message_id_t get_message_id() const ETL_NOEXCEPT - { - return ID; - } + TMessage msg; }; } diff --git a/include/etl/message_pool.h b/include/etl/message_pool.h index f5a46f84..e27312fa 100644 --- a/include/etl/message_pool.h +++ b/include/etl/message_pool.h @@ -36,6 +36,9 @@ SOFTWARE. #include "static_assert.h" #include "error_handler.h" #include "utility.h" +#include "memory.h" + +#define ETL_FILE "99" namespace etl { @@ -97,7 +100,7 @@ namespace etl if (p != ETL_NULLPTR) { - ::new(p) TMessage(etl::forward(args)...); + ::new(p) TMessage(etl::forward(args)...); } else { diff --git a/include/etl/reference_counted_message_pool.h b/include/etl/reference_counted_message_pool.h new file mode 100644 index 00000000..6032ab06 --- /dev/null +++ b/include/etl/reference_counted_message_pool.h @@ -0,0 +1,322 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2020 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_REFERENCE_COUNTED_MESSAGE_POOL_INCLUDED +#define ETL_REFERENCE_COUNTED_MESSAGE_POOL_INCLUDED + +#include "platform.h" +#include "message.h" +#include "static_assert.h" +#include "error_handler.h" +#include "utility.h" +#include "memory.h" + +#include + +#define ETL_FILE "99" + +namespace etl +{ + ////*************************************************************************** + ///// + ////*************************************************************************** + //class message_pool_allocation_exception : public etl::exception + //{ + //public: + + // message_pool_allocation_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + // : exception(reason_, file_name_, line_number_) + // { + // } + //}; + + ////*************************************************************************** + ///// + ////*************************************************************************** + //class message_pool_allocation_failure : etl::message_pool_allocation_exception + //{ + //public: + + // message_pool_allocation_failure(string_type file_name_, numeric_type line_number_) + // : message_pool_allocation_exception(ETL_ERROR_TEXT("message_pool:allocation failure", ETL_FILE"A"), file_name_, line_number_) + // { + // } + //}; + + //*************************************************************************** + /// + //*************************************************************************** + class ireference_counted_message_pool + { + public: + + virtual void destroy(const etl::ireference_counted_message* const pmsg) = 0; + virtual void destroy(const etl::ireference_counted_message& msg) = 0; + }; + + //*************************************************************************** + /// + //*************************************************************************** + class null_reference_counted_message_pool : public ireference_counted_message_pool + { + public: + + void destroy(const etl::ireference_counted_message* const pmsg) ETL_OVERRIDE + { + std::cout << "null_reference_counted_message_pool : destroy\n"; + } + + void destroy(const etl::ireference_counted_message& msg) ETL_OVERRIDE + { + std::cout << "null_reference_counted_message_pool : destroy\n"; + } + }; + + //*************************************************************************** + /// + //*************************************************************************** + template + class reference_counted_message_pool : public ireference_counted_message_pool + { + public: + + //************************************************************************* + /// Constructor + //************************************************************************* + //reference_counted_message_pool(imemory_block_pool& memory_block_pool_) + // : memory_block_pool(memory_block_pool_) + //{ + //} + +#if ETL_CPP11_SUPPORTED && !defined(ETL_MESSAGE_POOL_FORCE_CPP03) + //************************************************************************* + /// Create a message from the pool. + //************************************************************************* + template + etl::ireference_counted_message* create(TArgs&&... args) + { + //ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); + + using ref_message_t = etl::reference_counted_message; + + etl::ireference_counted_message* p = ETL_NULLPTR; + + //if (sizeof(ref_message_t) <= memory_block_pool.get_memory_block_size(ref_message_t)) + //{ + // p = memory_block_pool.allocate_memory_block(sizeof(ref_message_t)); + + // if (p != ETL_NULLPTR) + // { + // ::new(p) ref_message_t(TMessage(etl::forward(args)...)); + p = ::new ref_message_t(TMessage(etl::forward(args)...)); + // } + // else + // { + // ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + // } + //} + + return p; + } +#else + //************************************************************************* + /// Create a message from the pool. No parameters. + //************************************************************************* + template + TMessage* create() + { + ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(); + } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } + } + + return reinterpret_cast(p); + } + + //************************************************************************* + /// Create a message from the pool. One parameter. + //************************************************************************* + template + TMessage* create(const T1& t1) + { + ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(t1); + } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } + } + + return reinterpret_cast(p); + } + + //************************************************************************* + /// Create a message from the pool. Two parameters. + //************************************************************************* + template + TMessage* create(const T1& t1, const T2& t2) + { + ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(t1, t2); + } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } + } + + return reinterpret_cast(p); + } + + //************************************************************************* + /// Create a message from the pool. Three parameters. + //************************************************************************* + template + TMessage* create(const T1& t1, const T2& t2, const T3& t3) + { + ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(t1, t2, t3); + } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } + } + + return reinterpret_cast(p); + } + + //************************************************************************* + /// Create a message from the pool. Four parameters. + //************************************************************************* + template + TMessage* create(const T1& t1, const T2& t2, const T3& t3, const T4& t4) + { + ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); + + void* p = ETL_NULLPTR; + + if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) + { + p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); + + if (p != ETL_NULLPTR) + { + ::new(p) TMessage(t1, t2, t3, t4); + } + else + { + ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + } + } + + return reinterpret_cast(p) + } +#endif + + //************************************************************************* + /// Destruct a message and send it back to the pool. + //************************************************************************* + void destroy(const etl::ireference_counted_message* const pmsg) + { + std::cout << "reference_counted_message_pool : destroy\n"; + + if (pmsg != ETL_NULLPTR) + { +// pmsg->~ireference_counted_message(); + delete pmsg; + //memory_block_pool.release_memory_block(pmsg); + } + } + + //************************************************************************* + /// Destruct a message and send it back to the pool. + //************************************************************************* + void destroy(const etl::ireference_counted_message& msg) + { + destroy(&msg); + } + + private: + + /// The raw memory block pool. + //imemory_block_pool& memory_block_pool; + + //// Should not be copied. + //message_pool(const message_pool&) ETL_DELETE; + //message_pool& operator =(const message_pool&) ETL_DELETE; + }; +} + +#undef ETL_FILE + +#endif + diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h index fd3687e7..b3b7aa82 100644 --- a/include/etl/reference_counted_object.h +++ b/include/etl/reference_counted_object.h @@ -1,30 +1,30 @@ -/****************************************************************************** -The MIT License(MIT) - -Embedded Template Library. -https://github.com/ETLCPP/etl -https://www.etlcpp.com - -Copyright(c) 2020 jwellbelove - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -******************************************************************************/ +///****************************************************************************** +//The MIT License(MIT) +// +//Embedded Template Library. +//https://github.com/ETLCPP/etl +//https://www.etlcpp.com +// +//Copyright(c) 2020 jwellbelove +// +//Permission is hereby granted, free of charge, to any person obtaining a copy +//of this software and associated documentation files(the "Software"), to deal +//in the Software without restriction, including without limitation the rights +//to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +//copies of the Software, and to permit persons to whom the Software is +//furnished to do so, subject to the following conditions : +// +//The above copyright notice and this permission notice shall be included in all +//copies or substantial portions of the Software. +// +//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +//SOFTWARE. +//******************************************************************************/ #ifndef ETL_REFERENCE_COUNTED_OBJECT_INCLUDED #define ETL_REFERENCE_COUNTED_OBJECT_INCLUDED @@ -46,6 +46,54 @@ namespace etl ETL_NODISCARD virtual uint32_t decrement_reference_count() = 0; ETL_NODISCARD virtual uint32_t get_reference_count() const = 0; }; + + //*************************************************************************** + template + class reference_counted_object : public ireference_counted_object + { + public: + + reference_counted_object(const TObject& object_) + : object(object_) + { + reference_count = 0; + } + + TObject* get_object() + { + return &object; + } + + const TObject* get_object() const + { + return &object; + } + + virtual void set_reference_count(uint32_t value) ETL_OVERRIDE + { + reference_count = value; + } + + virtual void increment_reference_count() ETL_OVERRIDE + { + ++reference_count; + } + + ETL_NODISCARD virtual uint32_t decrement_reference_count() ETL_OVERRIDE + { + return uint32_t(--reference_count); + } + + ETL_NODISCARD virtual uint32_t get_reference_count() const ETL_OVERRIDE + { + return uint32_t(reference_count); + } + + private: + + TCounter reference_count; + TObject object; + }; } #endif diff --git a/include/etl/shared_message.h b/include/etl/shared_message.h index 030a666a..15852c12 100644 --- a/include/etl/shared_message.h +++ b/include/etl/shared_message.h @@ -31,14 +31,15 @@ SOFTWARE. #ifndef ETL_SHARED_MESSAGE_INCLUDED #define ETL_SHARED_MESSAGE_INCLUDED +#include + #include "platform.h" -#include "message_pool.h" +#include "reference_counted_message_pool.h" #include "message.h" //***************************************************************************** -/// A wrapper for reference countable messages. +/// A wrapper for reference counted messages. /// Contains pointers to a pool owner and a message defined with a ref count type. -/// See etl::message template. //***************************************************************************** namespace etl { @@ -51,11 +52,12 @@ namespace etl /// \param owner_ A reference to the owner pool. /// \param pmessage A reference to the message allocated from the pool. //************************************************************************* - shared_message(etl::message_pool& owner_, etl::ireference_counted_message& message_) + shared_message(etl::ireference_counted_message& message_, etl::ireference_counted_message_pool& owner_) : p_message_owner(&owner_) , p_message(&message_) { p_message->set_reference_count(1U); + std::cout << "shared_message C : Reference " << int(p_message->get_message()->get_message_id()) << " " << p_message->get_reference_count() << "\n"; } //************************************************************************* @@ -66,6 +68,7 @@ namespace etl , p_message(other.p_message) { p_message->increment_reference_count(); + std::cout << "shared_message CC : Reference " << int(p_message->get_message()->get_message_id()) << " " << p_message->get_reference_count() << "\n"; } //************************************************************************* @@ -75,9 +78,10 @@ namespace etl { if (&other != this) { - // Deal with the current message. + // Deal with the current message. if (p_message->decrement_reference_count() == 0U) { + std::cout << "shared_message =: Destroy reference counted message\n"; p_message_owner->destroy(p_message); } @@ -85,7 +89,8 @@ namespace etl p_message_owner = other.p_message_owner; p_message = other.p_message; p_message->increment_reference_count(); - } + std::cout << "shared_message =: Reference " << int(p_message->get_message()->get_message_id()) << " " << p_message->get_reference_count() << "\n"; + } return *this; } @@ -98,24 +103,44 @@ namespace etl { if (p_message->decrement_reference_count() == 0U) { + std::cout << "shared_message ~: Destroy reference counted message\n"; p_message_owner->destroy(p_message); } + else + { + std::cout << "shared_message ~: Reference " << int(p_message->get_message()->get_message_id()) << " " << p_message->get_reference_count() << "\n"; + } } //************************************************************************* - /// Get a reference to the contained message. + /// Get a pointer to the contained message. //************************************************************************* - etl::imessage& get_message() + etl::imessage* get_message() { - return *p_message; + return p_message->get_message(); } //************************************************************************* - /// Get a const reference to the contained message. + /// Get a const pointer to the contained message. //************************************************************************* - const etl::imessage& get_message() const + const etl::imessage* get_message() const { - return *p_message; + if (p_message != ETL_NULLPTR) + { + return p_message->get_message(); + } + else + { + return ETL_NULLPTR; + } + } + + //************************************************************************* + /// Returns true if the shared message is owned by a pool. + //************************************************************************* + bool is_owned() const + { + return (p_message_owner != ETL_NULLPTR); } //************************************************************************* @@ -128,8 +153,10 @@ namespace etl private: - etl::message_pool* p_message_owner; - etl::ireference_counted_message* p_message; + shared_message() ETL_DELETE; + + etl::ireference_counted_message_pool* p_message_owner; + etl::ireference_counted_message* p_message; }; } diff --git a/include/etl/shared_message_processor.h b/include/etl/shared_message_processor.h index 9b372be3..112a97e3 100644 --- a/include/etl/shared_message_processor.h +++ b/include/etl/shared_message_processor.h @@ -31,34 +31,323 @@ SOFTWARE. #include "platform.h" #include "shared_message.h" -#include "message_router.h" +#include "vector.h" + +#include namespace etl { + typedef uint_least8_t shared_message_processor_id_t; + //*************************************************************************** /// This is the base of all shared message processors. //*************************************************************************** - class shared_message_processor + class ishared_message_processor { public: - shared_message_processor(imessage_router& router_) - : router(router_) + //*************************************************************************** + /// + //*************************************************************************** + ishared_message_processor(etl::shared_message_processor_id_t id_ = etl::shared_message_processor_id_t()) + : id(id_) { } - imessage_router& get_router() const + virtual void receive(etl::shared_message shared_msg) = 0; + virtual void receive(shared_message_processor_id_t destination_processor_id, etl::shared_message shared_msg) = 0; + virtual bool accepts(etl::message_id_t id) const = 0; + + //*************************************************************************** + /// + //*************************************************************************** + bool accepts(etl::shared_message shared_msg) const { - return router; + return accepts(shared_msg.get_message()->get_message_id()); } - virtual ~shared_message_processor() {} - virtual void receive(etl::shared_message message) = 0; - virtual void receive(imessage_router& source, etl::shared_message message) = 0; + //*************************************************************************** + /// + //*************************************************************************** + shared_message_processor_id_t get_shared_message_processor_id() const + { + return id; + } + + enum + { + NULL_SHARED_MESSAGE_PROCESSOR = 255, + SHARED_MESSAGE_BUS = 254, + ALL_SHARED_MESSAGE_PROCESSORS = 253, + MAX_SHARED_MESSAGE_PROCESSOR = 249 + }; + + protected: + + etl::shared_message_processor_id_t id; + }; + + //*************************************************************************** + /// Derive user defined shared message processors from this. + //*************************************************************************** + class shared_message_processor : public ishared_message_processor + { + public: + + //*************************************************************************** + /// + //*************************************************************************** + shared_message_processor(etl::shared_message_processor_id_t id_ = etl::shared_message_processor_id_t()) + : ishared_message_processor(id_) + { + } + + etl::ishared_message_processor::receive; + + //*************************************************************************** + /// + //*************************************************************************** + void receive(etl::shared_message shared_msg) + { + on_receive(shared_msg); + } + + //*************************************************************************** + /// + //*************************************************************************** + void receive(shared_message_processor_id_t destination_processor_id, etl::shared_message shared_msg) + { + if (destination_processor_id == id) + { + on_receive(shared_msg); + } + } + + // User overridden. + virtual void on_receive(etl::shared_message shared_msg) = 0; + }; + + //*************************************************************************** + /// Interface for shared message bus + //*************************************************************************** + class ishared_message_bus : public etl::ishared_message_processor + { + private: + + typedef etl::ivector processor_list_t; + + public: + + using etl::ishared_message_processor::receive; + + //******************************************* + /// Subscribe to the bus. + //******************************************* + bool subscribe(etl::ishared_message_processor& processor) + { + bool ok = true; + + ok = !processor_list.full(); + + ETL_ASSERT(ok, ETL_ERROR(etl::shared_message_bus_too_many_subscribers)); + + if (ok) + { + processor_list_t::iterator iprocessor = etl::upper_bound(processor_list.begin(), + processor_list.end(), + processor.get_shared_message_processor_id(), + compare_processor_id()); + + processor_list.insert(iprocessor, &processor); + } + + return ok; + } + + //******************************************* + /// Unsubscribe from the bus. + //******************************************* + void unsubscribe(etl::shared_message_processor_id_t id) + { + if (id == etl::ishared_message_bus::ALL_SHARED_MESSAGE_PROCESSORS) + { + clear(); + } + else + { + ETL_OR_STD::pair range = etl::equal_range(processor_list.begin(), + processor_list.end(), + id, + compare_processor_id()); + + processor_list.erase(range.first, range.second); + } + } + + //******************************************* + void unsubscribe(etl::shared_message_processor& processor) + { + processor_list_t::iterator iprocessor = etl::find(processor_list.begin(), + processor_list.end(), + &processor); + + if (iprocessor != processor_list.end()) + { + processor_list.erase(iprocessor); + } + } + + //******************************************* + void receive(shared_message shared_msg) ETL_OVERRIDE + { + receive(etl::shared_message_processor::ALL_SHARED_MESSAGE_PROCESSORS, shared_msg); + } + + //******************************************* + void receive(etl::shared_message_processor_id_t destination_processor_id, + etl::shared_message shared_msg) ETL_OVERRIDE + { + switch (destination_processor_id) + { + //***************************** + // Broadcast to all processors. + case etl::shared_message_processor::ALL_SHARED_MESSAGE_PROCESSORS: + { + processor_list_t::iterator iprocessor = processor_list.begin(); + + // Broadcast to everyone. + while (iprocessor != processor_list.end()) + { + etl::ishared_message_processor& processor = **iprocessor; + + if (processor.accepts(shared_msg.get_message()->get_message_id())) + { + processor.receive(shared_msg); + } + + ++iprocessor; + } + + break; + } + + //***************************** + // Must be an addressed shared_msg. + default: + { + processor_list_t::iterator iprocessor = processor_list.begin(); + + // Find processors with the id. + ETL_OR_STD::pair range = etl::equal_range(processor_list.begin(), + processor_list.end(), + destination_processor_id, + compare_processor_id()); + + // Call all of them. + while (range.first != range.second) + { + if ((*(range.first))->accepts(shared_msg.get_message()->get_message_id())) + { + (*(range.first))->receive(shared_msg); + } + + ++range.first; + } + + // Do any message buses. + // These are always at the end of the list. + iprocessor = etl::lower_bound(processor_list.begin(), + processor_list.end(), + etl::ishared_message_bus::SHARED_MESSAGE_BUS, + compare_processor_id()); + + while (iprocessor != processor_list.end()) + { + // So pass it on. + (*iprocessor)->receive(destination_processor_id, shared_msg); + + ++iprocessor; + } + + break; + } + } + } + + using ishared_message_processor::accepts; + + //******************************************* + /// Does this message bus accept the message id? + /// Yes!, it accepts everything! + //******************************************* + bool accepts(etl::message_id_t) const ETL_OVERRIDE + { + return true; + } + + //******************************************* + size_t size() const + { + return processor_list.size(); + } + + //******************************************* + void clear() + { + return processor_list.clear(); + } + + protected: + + //******************************************* + /// Constructor. + //******************************************* + ishared_message_bus(processor_list_t& list) + : ishared_message_processor(etl::ishared_message_processor::SHARED_MESSAGE_BUS) + , processor_list(list) + { + } private: - imessage_router& router; + //******************************************* + // How to compare processors to processor ids. + //******************************************* + struct compare_processor_id + { + bool operator()(const etl::ishared_message_processor* prouter, etl::shared_message_processor_id_t id) const + { + return prouter->get_shared_message_processor_id() < id; + } + + bool operator()(etl::shared_message_processor_id_t id, const etl::ishared_message_processor* prouter) const + { + return id < prouter->get_shared_message_processor_id(); + } + }; + + processor_list_t& processor_list; + }; + + //*************************************************************************** + /// The message bus + //*************************************************************************** + template + class shared_message_bus : public etl::ishared_message_bus + { + public: + + //******************************************* + /// Constructor. + //******************************************* + shared_message_bus() + : ishared_message_bus(processor_list) + { + } + + private: + + etl::vector processor_list; }; } From 3cc95d6755ad12f6e704ee1336e6c3aa47d1685a Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 1 Jan 2021 20:26:01 +0000 Subject: [PATCH 08/18] Interim commit Refactor of reference counted types. --- include/etl/atomic.h | 1 + include/etl/message.h | 62 ------ include/etl/reference_counted_message.h | 205 +++++++++++++++++++ include/etl/reference_counted_message_pool.h | 29 +-- include/etl/reference_counted_object.h | 135 +++++++++++- include/etl/shared_message.h | 55 ++--- include/etl/shared_message_processor.h | 6 +- 7 files changed, 383 insertions(+), 110 deletions(-) create mode 100644 include/etl/reference_counted_message.h diff --git a/include/etl/atomic.h b/include/etl/atomic.h index 41996c07..f77049b8 100644 --- a/include/etl/atomic.h +++ b/include/etl/atomic.h @@ -45,6 +45,7 @@ SOFTWARE. #define ETL_HAS_ATOMIC 1 #else #define ETL_HAS_ATOMIC 0 + #pragma message "ETL atomics not supported" #endif #endif diff --git a/include/etl/message.h b/include/etl/message.h index 1efd8c80..d718be16 100644 --- a/include/etl/message.h +++ b/include/etl/message.h @@ -35,7 +35,6 @@ SOFTWARE. #include "error_handler.h" #include "exception.h" #include "message_types.h" -#include "reference_counted_object.h" #undef ETL_FILE #define ETL_FILE "38" @@ -96,67 +95,6 @@ namespace etl return ID; } }; - - class ireference_counted_message - { - public: - - virtual etl::imessage* get_message() = 0; - virtual const etl::imessage* get_message() const = 0; - virtual ~ireference_counted_message() {}; - virtual void set_reference_count(uint32_t value) = 0; - virtual void increment_reference_count() = 0; - ETL_NODISCARD virtual uint32_t decrement_reference_count() = 0; - ETL_NODISCARD virtual uint32_t get_reference_count() const = 0; - }; - - //******************************************************* - template - class reference_counted_message : virtual public ireference_counted_message - { - public: - - reference_counted_message(const TMessage& msg_) - : msg(msg_) - { - reference_count = 0; - } - - virtual TMessage* get_message() ETL_OVERRIDE - { - return &msg; - } - - virtual const TMessage* get_message() const ETL_OVERRIDE - { - return &msg; - } - - virtual void set_reference_count(uint32_t value) ETL_OVERRIDE - { - reference_count = value; - } - - virtual void increment_reference_count() ETL_OVERRIDE - { - ++reference_count; - } - - ETL_NODISCARD virtual uint32_t decrement_reference_count() ETL_OVERRIDE - { - return uint32_t(--reference_count); - } - - ETL_NODISCARD virtual uint32_t get_reference_count() const ETL_OVERRIDE - { - return uint32_t(reference_count); - } - - private: - - TCounter reference_count; - TMessage msg; - }; } #undef ETL_FILE diff --git a/include/etl/reference_counted_message.h b/include/etl/reference_counted_message.h new file mode 100644 index 00000000..d102a594 --- /dev/null +++ b/include/etl/reference_counted_message.h @@ -0,0 +1,205 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_REFERENCE_COUNTED_MESSAGE_INCLUDED +#define ETL_REFERENCE_COUNTED_MESSAGE_INCLUDED + +#include + +#include "platform.h" +#include "message.h" +#include "atomic.h" +#include "reference_counted_object.h" + +namespace etl +{ + //*************************************************************************** + // Base class for all reference counted messages. + //*************************************************************************** + class ireference_counted_message + { + public: + + virtual etl::imessage& get_message() = 0; ///< Get a reference to the message. + virtual const etl::imessage& get_message() const = 0; ///< Get a const reference to the message. + + virtual etl::ireference_counted_object& get_reference_counter() = 0; ///< Get a reference to the reference counter. + virtual const etl::ireference_counted_object& get_reference_counter() const = 0; ///< Get a const reference to the reference counter. + }; + + //*************************************************************************** + // Reference counted message type. + //*************************************************************************** + template + class reference_counted_message : virtual public etl::ireference_counted_message + { + public: + + typedef TMessage message_type; + typedef TCounter counter_type; + + //*************************************************************************** + /// Constructor + /// \param msg The message to count. + //*************************************************************************** + reference_counted_message(const TMessage& msg_) + : rc_object(msg_) + { + rc_object.set_reference_count(0); + } + + //*************************************************************************** + /// Get a reference to the message. + /// \return A reference to the message. + //*************************************************************************** + virtual TMessage& get_message() ETL_OVERRIDE + { + return rc_object.get_object(); + } + + //*************************************************************************** + /// Get a const reference to the message. + /// \return A const reference to the message. + //*************************************************************************** + virtual const TMessage& get_message() const ETL_OVERRIDE + { + return rc_object.get_object(); + } + + //*************************************************************************** + /// Get a reference to the reference counter. + /// \return A reference to the reference counter. + //*************************************************************************** + virtual etl::ireference_counted_object& get_reference_counter() ETL_OVERRIDE + { + return rc_object; + } + + //*************************************************************************** + /// Get a const reference to the reference counter. + /// \return A const reference to the reference counter. + //*************************************************************************** + virtual const etl::ireference_counted_object& get_reference_counter() const ETL_OVERRIDE + { + return rc_object; + } + + private: + + /// The reference counted object. + etl::reference_counted_object rc_object; + }; + +#if ETL_HAS_ATOMIC + //*************************************************************************** + /// Class for creating reference counted messages using an atomic counter. + /// \tparam TMessage The type to be reference counted. + //*************************************************************************** + template + class atomic_counted_message : virtual public etl::reference_counted_message + { + public: + + //*************************************************************************** + /// Constructor. + /// \param msg The message to count. + //*************************************************************************** + atomic_counted_message(const TMessage& msg_) + : reference_counted_message(msg_) + { + } + + typedef typename reference_counted_message::message_type message_type; + typedef typename reference_counted_message::counter_type counter_type; + }; +#endif + + //*************************************************************************** + // Uncounted message type. + //*************************************************************************** + template + class uncounted_message : virtual public etl::ireference_counted_message + { + public: + + typedef TMessage message_type; + typedef void counter_type; + + //*************************************************************************** + /// Constructor + /// \param msg The message to count. + //*************************************************************************** + uncounted_message(const TMessage& msg_) + : rc_object(msg_) + { + } + + //*************************************************************************** + /// Get a reference to the message. + /// \return A reference to the message. + //*************************************************************************** + virtual TMessage& get_message() ETL_OVERRIDE + { + return rc_object.get_object(); + } + + //*************************************************************************** + /// Get a const reference to the message. + /// \return A const reference to the message. + //*************************************************************************** + virtual const TMessage& get_message() const ETL_OVERRIDE + { + return rc_object.get_object(); + } + + //*************************************************************************** + /// Get a reference to the reference counter. + /// \return A reference to the reference counter. + //*************************************************************************** + virtual etl::ireference_counted_object& get_reference_counter() ETL_OVERRIDE + { + return rc_object; + } + + //*************************************************************************** + /// Get a const reference to the reference counter. + /// \return A const reference to the reference counter. + //*************************************************************************** + virtual const etl::ireference_counted_object& get_reference_counter() const ETL_OVERRIDE + { + return rc_object; + } + + private: + + /// The reference counted object. + etl::uncounted_object rc_object; + }; +} + +#endif diff --git a/include/etl/reference_counted_message_pool.h b/include/etl/reference_counted_message_pool.h index 6032ab06..c50b2037 100644 --- a/include/etl/reference_counted_message_pool.h +++ b/include/etl/reference_counted_message_pool.h @@ -33,6 +33,7 @@ SOFTWARE. #include "platform.h" #include "message.h" +#include "reference_counted_message.h" #include "static_assert.h" #include "error_handler.h" #include "utility.h" @@ -77,8 +78,8 @@ namespace etl { public: - virtual void destroy(const etl::ireference_counted_message* const pmsg) = 0; - virtual void destroy(const etl::ireference_counted_message& msg) = 0; + virtual void release(const etl::ireference_counted_message* const pmsg) = 0; + virtual void release(const etl::ireference_counted_message& msg) = 0; }; //*************************************************************************** @@ -88,12 +89,12 @@ namespace etl { public: - void destroy(const etl::ireference_counted_message* const pmsg) ETL_OVERRIDE + void release(const etl::ireference_counted_message* const pmsg) ETL_OVERRIDE { std::cout << "null_reference_counted_message_pool : destroy\n"; } - void destroy(const etl::ireference_counted_message& msg) ETL_OVERRIDE + void release(const etl::ireference_counted_message& msg) ETL_OVERRIDE { std::cout << "null_reference_counted_message_pool : destroy\n"; } @@ -115,12 +116,12 @@ namespace etl //{ //} -#if ETL_CPP11_SUPPORTED && !defined(ETL_MESSAGE_POOL_FORCE_CPP03) +#if ETL_CPP11_SUPPORTED && !defined(ETL_REFERENCE_COUNTED_MESSAGE_POOL_FORCE_CPP03) //************************************************************************* /// Create a message from the pool. //************************************************************************* template - etl::ireference_counted_message* create(TArgs&&... args) + etl::ireference_counted_message* allocate(TArgs&&... args) { //ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); @@ -150,7 +151,7 @@ namespace etl /// Create a message from the pool. No parameters. //************************************************************************* template - TMessage* create() + TMessage* allocate() { ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); @@ -177,7 +178,7 @@ namespace etl /// Create a message from the pool. One parameter. //************************************************************************* template - TMessage* create(const T1& t1) + TMessage* allocate(const T1& t1) { ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); @@ -204,7 +205,7 @@ namespace etl /// Create a message from the pool. Two parameters. //************************************************************************* template - TMessage* create(const T1& t1, const T2& t2) + TMessage* allocate(const T1& t1, const T2& t2) { ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); @@ -231,7 +232,7 @@ namespace etl /// Create a message from the pool. Three parameters. //************************************************************************* template - TMessage* create(const T1& t1, const T2& t2, const T3& t3) + TMessage* allocate(const T1& t1, const T2& t2, const T3& t3) { ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); @@ -258,7 +259,7 @@ namespace etl /// Create a message from the pool. Four parameters. //************************************************************************* template - TMessage* create(const T1& t1, const T2& t2, const T3& t3, const T4& t4) + TMessage* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4) { ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); @@ -285,7 +286,7 @@ namespace etl //************************************************************************* /// Destruct a message and send it back to the pool. //************************************************************************* - void destroy(const etl::ireference_counted_message* const pmsg) + void release(const etl::ireference_counted_message* const pmsg) { std::cout << "reference_counted_message_pool : destroy\n"; @@ -300,9 +301,9 @@ namespace etl //************************************************************************* /// Destruct a message and send it back to the pool. //************************************************************************* - void destroy(const etl::ireference_counted_message& msg) + void release(const etl::ireference_counted_message& msg) { - destroy(&msg); + release(&msg); } private: diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h index b3b7aa82..1f4967b6 100644 --- a/include/etl/reference_counted_object.h +++ b/include/etl/reference_counted_object.h @@ -32,9 +32,12 @@ #include #include "platform.h" +#include "atomic.h" namespace etl { + //*************************************************************************** + /// The base of all reference counted objects. //*************************************************************************** class ireference_counted_object { @@ -47,43 +50,71 @@ namespace etl ETL_NODISCARD virtual uint32_t get_reference_count() const = 0; }; + //*************************************************************************** + /// Class for creating reference counted objects. + /// \tparam TObject The type to be reference counted. + /// \tparam TCounter The type to use as the counter. //*************************************************************************** template - class reference_counted_object : public ireference_counted_object + class reference_counted_object : public etl::ireference_counted_object { public: + typedef TObject value_type; + typedef TCounter counter_type; + + //*************************************************************************** + /// Constructor. + //*************************************************************************** reference_counted_object(const TObject& object_) : object(object_) { reference_count = 0; } - TObject* get_object() + //*************************************************************************** + /// Get a reference to the counted object. + //*************************************************************************** + value_type& get_object() { - return &object; + return object; } - const TObject* get_object() const + //*************************************************************************** + /// Get a const reference to the counted object. + //*************************************************************************** + const value_type& get_object() const { - return &object; + return object; } + //*************************************************************************** + /// Set the reference count. + //*************************************************************************** virtual void set_reference_count(uint32_t value) ETL_OVERRIDE { reference_count = value; } + //*************************************************************************** + /// Increment the refernce count. + //*************************************************************************** virtual void increment_reference_count() ETL_OVERRIDE { ++reference_count; } + //*************************************************************************** + /// Decrement the refernce count. + //*************************************************************************** ETL_NODISCARD virtual uint32_t decrement_reference_count() ETL_OVERRIDE { return uint32_t(--reference_count); } + //*************************************************************************** + /// Get the current reference count. + //*************************************************************************** ETL_NODISCARD virtual uint32_t get_reference_count() const ETL_OVERRIDE { return uint32_t(reference_count); @@ -91,8 +122,98 @@ namespace etl private: - TCounter reference_count; - TObject object; + TCounter reference_count; // The reference counter + TObject object; // The object being reference counted. + }; + +#if ETL_HAS_ATOMIC + //*************************************************************************** + /// Class for creating reference counted objects using an atomic counter. + /// \tparam TObject The type to be reference counted. + //*************************************************************************** + template + class atomic_counted_object : public etl::reference_counted_object + { + public: + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + atomic_counted_object(const TObject& object_) + : reference_counted_object(object_) + { + } + + typedef typename reference_counted_object::value_type value_type; + typedef typename reference_counted_object::counter_type counter_type; + }; +#endif + + template + class uncounted_object : public etl::ireference_counted_object + { + public: + + typedef TObject value_type; + typedef void counter_type; + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + uncounted_object(const TObject& object_) + : object(object_) + { + } + + //*************************************************************************** + /// Get a reference to the counted object. + //*************************************************************************** + value_type& get_object() + { + return object; + } + + //*************************************************************************** + /// Get a const reference to the counted object. + //*************************************************************************** + const value_type& get_object() const + { + return object; + } + + //*************************************************************************** + /// Set the reference count. + //*************************************************************************** + virtual void set_reference_count(uint32_t value) ETL_OVERRIDE + { + } + + //*************************************************************************** + /// Increment the refernce count. + //*************************************************************************** + virtual void increment_reference_count() ETL_OVERRIDE + { + } + + //*************************************************************************** + /// Decrement the refernce count. + //*************************************************************************** + ETL_NODISCARD virtual uint32_t decrement_reference_count() ETL_OVERRIDE + { + return 1; + } + + //*************************************************************************** + /// Get the current reference count. + //*************************************************************************** + ETL_NODISCARD virtual uint32_t get_reference_count() const ETL_OVERRIDE + { + return 1; + } + + private: + + TObject object; // The object being reference counted. }; } diff --git a/include/etl/shared_message.h b/include/etl/shared_message.h index 15852c12..b8e90838 100644 --- a/include/etl/shared_message.h +++ b/include/etl/shared_message.h @@ -35,7 +35,7 @@ SOFTWARE. #include "platform.h" #include "reference_counted_message_pool.h" -#include "message.h" +#include "reference_counted_message.h" //***************************************************************************** /// A wrapper for reference counted messages. @@ -56,8 +56,16 @@ namespace etl : p_message_owner(&owner_) , p_message(&message_) { - p_message->set_reference_count(1U); - std::cout << "shared_message C : Reference " << int(p_message->get_message()->get_message_id()) << " " << p_message->get_reference_count() << "\n"; + p_message->get_reference_counter().set_reference_count(1U); + std::cout << "shared_message C : Reference " << int(p_message->get_message().get_message_id()) << " " << p_message->get_reference_counter().get_reference_count() << "\n"; + } + + shared_message(etl::ireference_counted_message& message_) + : p_message_owner(ETL_NULLPTR) + , p_message(&message_) + { + p_message->get_reference_counter().set_reference_count(1U); + std::cout << "shared_message C : Reference " << int(p_message->get_message().get_message_id()) << " No Owner\n"; } //************************************************************************* @@ -67,8 +75,8 @@ namespace etl : p_message_owner(other.p_message_owner) , p_message(other.p_message) { - p_message->increment_reference_count(); - std::cout << "shared_message CC : Reference " << int(p_message->get_message()->get_message_id()) << " " << p_message->get_reference_count() << "\n"; + p_message->get_reference_counter().increment_reference_count(); + std::cout << "shared_message CC : Reference " << int(p_message->get_message().get_message_id()) << " " << p_message->get_reference_counter().get_reference_count() << "\n"; } //************************************************************************* @@ -79,17 +87,20 @@ namespace etl if (&other != this) { // Deal with the current message. - if (p_message->decrement_reference_count() == 0U) + if (p_message->get_reference_counter().decrement_reference_count() == 0U) { std::cout << "shared_message =: Destroy reference counted message\n"; - p_message_owner->destroy(p_message); + if (p_message_owner != ETL_NULLPTR) + { + p_message_owner->release(p_message); + } } // Copy over the new one. p_message_owner = other.p_message_owner; p_message = other.p_message; - p_message->increment_reference_count(); - std::cout << "shared_message =: Reference " << int(p_message->get_message()->get_message_id()) << " " << p_message->get_reference_count() << "\n"; + p_message->get_reference_counter().increment_reference_count(); + std::cout << "shared_message =: Reference " << int(p_message->get_message().get_message_id()) << " " << p_message->get_reference_counter().get_reference_count() << "\n"; } return *this; @@ -101,21 +112,24 @@ namespace etl //************************************************************************* ~shared_message() { - if (p_message->decrement_reference_count() == 0U) + if (p_message->get_reference_counter().decrement_reference_count() == 0U) { std::cout << "shared_message ~: Destroy reference counted message\n"; - p_message_owner->destroy(p_message); + if (p_message_owner != ETL_NULLPTR) + { + p_message_owner->release(p_message); + } } else { - std::cout << "shared_message ~: Reference " << int(p_message->get_message()->get_message_id()) << " " << p_message->get_reference_count() << "\n"; + std::cout << "shared_message ~: Reference " << int(p_message->get_message().get_message_id()) << " " << p_message->get_reference_counter().get_reference_count() << "\n"; } } //************************************************************************* /// Get a pointer to the contained message. //************************************************************************* - etl::imessage* get_message() + etl::imessage& get_message() { return p_message->get_message(); } @@ -123,16 +137,9 @@ namespace etl //************************************************************************* /// Get a const pointer to the contained message. //************************************************************************* - const etl::imessage* get_message() const + const etl::imessage& get_message() const { - if (p_message != ETL_NULLPTR) - { - return p_message->get_message(); - } - else - { - return ETL_NULLPTR; - } + return p_message->get_message(); } //************************************************************************* @@ -144,11 +151,11 @@ namespace etl } //************************************************************************* - /// Get the current reference count for this pool message. + /// Get the current reference count for this shared message. //************************************************************************* uint32_t get_reference_count() const { - return p_message->get_reference_count(); + return p_message->get_reference_counter().get_reference_count(); } private: diff --git a/include/etl/shared_message_processor.h b/include/etl/shared_message_processor.h index 112a97e3..de913c24 100644 --- a/include/etl/shared_message_processor.h +++ b/include/etl/shared_message_processor.h @@ -63,7 +63,7 @@ namespace etl //*************************************************************************** bool accepts(etl::shared_message shared_msg) const { - return accepts(shared_msg.get_message()->get_message_id()); + return accepts(shared_msg.get_message().get_message_id()); } //*************************************************************************** @@ -220,7 +220,7 @@ namespace etl { etl::ishared_message_processor& processor = **iprocessor; - if (processor.accepts(shared_msg.get_message()->get_message_id())) + if (processor.accepts(shared_msg.get_message().get_message_id())) { processor.receive(shared_msg); } @@ -246,7 +246,7 @@ namespace etl // Call all of them. while (range.first != range.second) { - if ((*(range.first))->accepts(shared_msg.get_message()->get_message_id())) + if ((*(range.first))->accepts(shared_msg.get_message().get_message_id())) { (*(range.first))->receive(shared_msg); } From 920dcdf4b657d3914d02f06f0d1154727abacb8b Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 2 Jan 2021 12:35:13 +0000 Subject: [PATCH 09/18] Merged shared_message handlers into message_router --- include/etl/message_router.h | 313 ++++------------ include/etl/reference_counted_message.h | 22 +- include/etl/reference_counted_message_pool.h | 72 ++-- include/etl/reference_counted_object.h | 17 +- include/etl/shared_message.h | 104 +++--- include/etl/shared_message_processor.h | 354 ------------------- 6 files changed, 175 insertions(+), 707 deletions(-) delete mode 100644 include/etl/shared_message_processor.h diff --git a/include/etl/message_router.h b/include/etl/message_router.h index edc3900a..2790794e 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -56,6 +56,7 @@ SOFTWARE. #include "platform.h" #include "message.h" +#include "shared_message.h" #include "message_packet.h" #include "message_types.h" #include "alignment.h" @@ -95,6 +96,13 @@ namespace etl } }; + //*************************************************************************** + /// Forward declare null message router functionality. + //*************************************************************************** + class imessage_router; + + etl::imessage_router& get_null_message_router(); + //*************************************************************************** /// This is the base of all message routers. //*************************************************************************** @@ -103,14 +111,48 @@ namespace etl public: virtual ~imessage_router() {} - virtual void receive(const etl::imessage& message) = 0; virtual void receive(imessage_router& source, const etl::imessage& message) = 0; - virtual void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) = 0; virtual bool accepts(etl::message_id_t id) const = 0; virtual bool is_null_router() const = 0; virtual bool is_producer() const = 0; virtual bool is_consumer() const = 0; + //******************************************** + void receive(const etl::imessage& message) + { + receive(etl::get_null_message_router(), message); + } + + //******************************************** + void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) + { + if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) + { + receive(source, message); + } + } + + //******************************************** + virtual void receive(imessage_router& source, etl::shared_message shared_msg) + { + receive(source, shared_msg.get_message()); + } + + //******************************************** + void receive(etl::shared_message shared_msg) + { + receive(etl::get_null_message_router(), shared_msg); + } + + //******************************************** + void receive(imessage_router& source, etl::message_router_id_t destination_router_id, etl::shared_message shared_msg) + { + if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) + { + receive(source, shared_msg); + } + } + //******************************************** bool accepts(const etl::imessage& msg) const { @@ -187,21 +229,11 @@ namespace etl { } - //******************************************** - void receive(const etl::imessage&) ETL_OVERRIDE - { - } - //******************************************** void receive(etl::imessage_router&, const etl::imessage&) ETL_OVERRIDE { } - //******************************************** - void receive(imessage_router&, etl::message_router_id_t, const etl::imessage&) ETL_OVERRIDE - { - } - //******************************************** bool accepts(etl::message_id_t) const ETL_OVERRIDE { @@ -234,6 +266,13 @@ namespace etl } }; + //*********************************************** + /// null message router functionality. + inline etl::imessage_router& get_null_message_router() + { + return etl::null_message_router::instance(); + } + //*************************************************************************** /// This router can be used as a producer-only of messages, such an interrupt routine. //*************************************************************************** @@ -246,21 +285,11 @@ namespace etl { } - //******************************************** - void receive(const etl::imessage&) ETL_OVERRIDE - { - } - //******************************************** void receive(etl::imessage_router&, const etl::imessage&) ETL_OVERRIDE { } - //******************************************** - void receive(imessage_router&, etl::message_router_id_t, const etl::imessage&) ETL_OVERRIDE - { - } - //******************************************** bool accepts(etl::message_id_t) const ETL_OVERRIDE { @@ -334,21 +363,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const etl::message_id_t id = msg.get_message_id(); @@ -450,21 +466,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -565,21 +568,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -679,21 +669,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -791,21 +768,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -902,21 +866,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -1012,21 +963,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -1121,21 +1059,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -1228,21 +1153,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -1334,21 +1246,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -1438,21 +1337,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -1541,21 +1427,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -1642,21 +1515,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -1742,21 +1602,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -1841,21 +1688,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); @@ -1939,21 +1773,8 @@ namespace etl } //********************************************** - void receive(const etl::imessage& msg) ETL_OVERRIDE - { - receive(etl::null_message_router::instance(), msg); - } + using etl::imessage_router::receive; - //********************************************** - void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, msg); - } - } - - //********************************************** void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE { const size_t id = msg.get_message_id(); diff --git a/include/etl/reference_counted_message.h b/include/etl/reference_counted_message.h index d102a594..46e89771 100644 --- a/include/etl/reference_counted_message.h +++ b/include/etl/reference_counted_message.h @@ -45,7 +45,6 @@ namespace etl { public: - virtual etl::imessage& get_message() = 0; ///< Get a reference to the message. virtual const etl::imessage& get_message() const = 0; ///< Get a const reference to the message. virtual etl::ireference_counted_object& get_reference_counter() = 0; ///< Get a reference to the reference counter. @@ -56,7 +55,7 @@ namespace etl // Reference counted message type. //*************************************************************************** template - class reference_counted_message : virtual public etl::ireference_counted_message + class reference_counted_message : public etl::ireference_counted_message { public: @@ -70,16 +69,6 @@ namespace etl reference_counted_message(const TMessage& msg_) : rc_object(msg_) { - rc_object.set_reference_count(0); - } - - //*************************************************************************** - /// Get a reference to the message. - /// \return A reference to the message. - //*************************************************************************** - virtual TMessage& get_message() ETL_OVERRIDE - { - return rc_object.get_object(); } //*************************************************************************** @@ -159,15 +148,6 @@ namespace etl { } - //*************************************************************************** - /// Get a reference to the message. - /// \return A reference to the message. - //*************************************************************************** - virtual TMessage& get_message() ETL_OVERRIDE - { - return rc_object.get_object(); - } - //*************************************************************************** /// Get a const reference to the message. /// \return A const reference to the message. diff --git a/include/etl/reference_counted_message_pool.h b/include/etl/reference_counted_message_pool.h index c50b2037..b7a8f79b 100644 --- a/include/etl/reference_counted_message_pool.h +++ b/include/etl/reference_counted_message_pool.h @@ -82,24 +82,6 @@ namespace etl virtual void release(const etl::ireference_counted_message& msg) = 0; }; - //*************************************************************************** - /// - //*************************************************************************** - class null_reference_counted_message_pool : public ireference_counted_message_pool - { - public: - - void release(const etl::ireference_counted_message* const pmsg) ETL_OVERRIDE - { - std::cout << "null_reference_counted_message_pool : destroy\n"; - } - - void release(const etl::ireference_counted_message& msg) ETL_OVERRIDE - { - std::cout << "null_reference_counted_message_pool : destroy\n"; - } - }; - //*************************************************************************** /// //*************************************************************************** @@ -116,9 +98,39 @@ namespace etl //{ //} + //************************************************************************* + /// Allocate a reference counted message from the pool. + //************************************************************************* + template + etl::ireference_counted_message* allocate(const TMessage& message) + { + //ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); + + using ref_message_t = etl::reference_counted_message; + + etl::ireference_counted_message* p = ETL_NULLPTR; + + //if (sizeof(ref_message_t) <= memory_block_pool.get_memory_block_size(ref_message_t)) + //{ + // p = memory_block_pool.allocate_memory_block(sizeof(ref_message_t)); + + // if (p != ETL_NULLPTR) + // { + // ::new(p) ref_message_t(TMessage(etl::forward(args)...)); + p = ::new ref_message_t(message); + // } + // else + // { + // ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); + // } + //} + + return p; + } + #if ETL_CPP11_SUPPORTED && !defined(ETL_REFERENCE_COUNTED_MESSAGE_POOL_FORCE_CPP03) //************************************************************************* - /// Create a message from the pool. + /// Allocate a reference counted message from the pool. //************************************************************************* template etl::ireference_counted_message* allocate(TArgs&&... args) @@ -148,7 +160,7 @@ namespace etl } #else //************************************************************************* - /// Create a message from the pool. No parameters. + /// Allocate a reference counted message from the pool. No parameters. //************************************************************************* template TMessage* allocate() @@ -175,7 +187,7 @@ namespace etl } //************************************************************************* - /// Create a message from the pool. One parameter. + /// Allocate a reference counted message from the pool. One parameter. //************************************************************************* template TMessage* allocate(const T1& t1) @@ -202,7 +214,7 @@ namespace etl } //************************************************************************* - /// Create a message from the pool. Two parameters. + /// Allocate a reference counted message from the pool. Two parameters. //************************************************************************* template TMessage* allocate(const T1& t1, const T2& t2) @@ -229,7 +241,7 @@ namespace etl } //************************************************************************* - /// Create a message from the pool. Three parameters. + /// Allocate a reference counted message from the pool. Three parameters. //************************************************************************* template TMessage* allocate(const T1& t1, const T2& t2, const T3& t3) @@ -256,7 +268,7 @@ namespace etl } //************************************************************************* - /// Create a message from the pool. Four parameters. + /// Allocate a reference counted message from the pool. Four parameters. //************************************************************************* template TMessage* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4) @@ -286,15 +298,15 @@ namespace etl //************************************************************************* /// Destruct a message and send it back to the pool. //************************************************************************* - void release(const etl::ireference_counted_message* const pmsg) + void release(const etl::ireference_counted_message* const prcm) { - std::cout << "reference_counted_message_pool : destroy\n"; + std::cout << "reference_counted_message_pool : release\n"; - if (pmsg != ETL_NULLPTR) + if (prcm != ETL_NULLPTR) { -// pmsg->~ireference_counted_message(); - delete pmsg; - //memory_block_pool.release_memory_block(pmsg); +// prcm->~ireference_counted_message(); + delete prcm; + //memory_block_pool.release_memory_block(prcm); } } diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h index 1f4967b6..4b5fe33e 100644 --- a/include/etl/reference_counted_object.h +++ b/include/etl/reference_counted_object.h @@ -71,15 +71,7 @@ namespace etl { reference_count = 0; } - - //*************************************************************************** - /// Get a reference to the counted object. - //*************************************************************************** - value_type& get_object() - { - return object; - } - + //*************************************************************************** /// Get a const reference to the counted object. //*************************************************************************** @@ -122,8 +114,13 @@ namespace etl private: + // This class must not be default contructed, copy constructed or assigned. + reference_counted_object() ETL_DELETE; + reference_counted_object(const reference_counted_object&) ETL_DELETE; + reference_counted_object& operator =(const reference_counted_object&) ETL_DELETE; + TCounter reference_count; // The reference counter - TObject object; // The object being reference counted. + const TObject object; // The object being reference counted. }; #if ETL_HAS_ATOMIC diff --git a/include/etl/shared_message.h b/include/etl/shared_message.h index b8e90838..d4154087 100644 --- a/include/etl/shared_message.h +++ b/include/etl/shared_message.h @@ -53,30 +53,30 @@ namespace etl /// \param pmessage A reference to the message allocated from the pool. //************************************************************************* shared_message(etl::ireference_counted_message& message_, etl::ireference_counted_message_pool& owner_) - : p_message_owner(&owner_) - , p_message(&message_) + : p_rcmessage_owner(&owner_) + , p_rcmessage(&message_) { - p_message->get_reference_counter().set_reference_count(1U); - std::cout << "shared_message C : Reference " << int(p_message->get_message().get_message_id()) << " " << p_message->get_reference_counter().get_reference_count() << "\n"; + p_rcmessage->get_reference_counter().set_reference_count(1U); + std::cout << "shared_message C : ID = " << int(p_rcmessage->get_message().get_message_id()) << " : Count = " << p_rcmessage->get_reference_counter().get_reference_count() << "\n"; } shared_message(etl::ireference_counted_message& message_) - : p_message_owner(ETL_NULLPTR) - , p_message(&message_) + : p_rcmessage_owner(ETL_NULLPTR) + , p_rcmessage(&message_) { - p_message->get_reference_counter().set_reference_count(1U); - std::cout << "shared_message C : Reference " << int(p_message->get_message().get_message_id()) << " No Owner\n"; + p_rcmessage->get_reference_counter().set_reference_count(1U); + std::cout << "shared_message C : ID = " << int(p_rcmessage->get_message().get_message_id()) << " No Owner\n"; } //************************************************************************* /// Copy constructor //************************************************************************* shared_message(const shared_message& other) - : p_message_owner(other.p_message_owner) - , p_message(other.p_message) + : p_rcmessage_owner(other.p_rcmessage_owner) + , p_rcmessage(other.p_rcmessage) { - p_message->get_reference_counter().increment_reference_count(); - std::cout << "shared_message CC : Reference " << int(p_message->get_message().get_message_id()) << " " << p_message->get_reference_counter().get_reference_count() << "\n"; + p_rcmessage->get_reference_counter().increment_reference_count(); + std::cout << "shared_message CC : ID = " << int(p_rcmessage->get_message().get_message_id()) << " : Count = " << p_rcmessage->get_reference_counter().get_reference_count() << "\n"; } //************************************************************************* @@ -87,20 +87,20 @@ namespace etl if (&other != this) { // Deal with the current message. - if (p_message->get_reference_counter().decrement_reference_count() == 0U) + if (p_rcmessage->get_reference_counter().decrement_reference_count() == 0U) { std::cout << "shared_message =: Destroy reference counted message\n"; - if (p_message_owner != ETL_NULLPTR) + if (p_rcmessage_owner != ETL_NULLPTR) { - p_message_owner->release(p_message); + p_rcmessage_owner->release(p_rcmessage); } } // Copy over the new one. - p_message_owner = other.p_message_owner; - p_message = other.p_message; - p_message->get_reference_counter().increment_reference_count(); - std::cout << "shared_message =: Reference " << int(p_message->get_message().get_message_id()) << " " << p_message->get_reference_counter().get_reference_count() << "\n"; + p_rcmessage_owner = other.p_rcmessage_owner; + p_rcmessage = other.p_rcmessage; + p_rcmessage->get_reference_counter().increment_reference_count(); + std::cout << "shared_message =: ID = " << int(p_rcmessage->get_message().get_message_id()) << " : Count = " << p_rcmessage->get_reference_counter().get_reference_count() << "\n"; } return *this; @@ -112,42 +112,30 @@ namespace etl //************************************************************************* ~shared_message() { - if (p_message->get_reference_counter().decrement_reference_count() == 0U) - { - std::cout << "shared_message ~: Destroy reference counted message\n"; - if (p_message_owner != ETL_NULLPTR) + if (p_rcmessage->get_reference_counter().decrement_reference_count() == 0U) + { + if (is_owned()) { - p_message_owner->release(p_message); + std::cout << "shared_message ~: Destroy reference counted message\n"; + p_rcmessage_owner->release(p_rcmessage); + } + else + { + std::cout << "shared_message ~: Uncounted message\n"; } } else { - std::cout << "shared_message ~: Reference " << int(p_message->get_message().get_message_id()) << " " << p_message->get_reference_counter().get_reference_count() << "\n"; + std::cout << "shared_message ~ : ID = " << int(p_rcmessage->get_message().get_message_id()) << " : Count = " << p_rcmessage->get_reference_counter().get_reference_count() << "\n"; } } //************************************************************************* - /// Get a pointer to the contained message. - //************************************************************************* - etl::imessage& get_message() - { - return p_message->get_message(); - } - - //************************************************************************* - /// Get a const pointer to the contained message. + /// Get a const reference to the contained message. //************************************************************************* const etl::imessage& get_message() const { - return p_message->get_message(); - } - - //************************************************************************* - /// Returns true if the shared message is owned by a pool. - //************************************************************************* - bool is_owned() const - { - return (p_message_owner != ETL_NULLPTR); + return p_rcmessage->get_message(); } //************************************************************************* @@ -155,16 +143,40 @@ namespace etl //************************************************************************* uint32_t get_reference_count() const { - return p_message->get_reference_counter().get_reference_count(); + return p_rcmessage->get_reference_counter().get_reference_count(); } private: + //************************************************************************* + /// Returns true if the internal reference counted message is owned by a pool. + //************************************************************************* + bool is_owned() const + { + return (p_rcmessage_owner != ETL_NULLPTR); + } + shared_message() ETL_DELETE; - etl::ireference_counted_message_pool* p_message_owner; - etl::ireference_counted_message* p_message; + etl::ireference_counted_message_pool* p_rcmessage_owner; + etl::ireference_counted_message* p_rcmessage; }; + + template + etl::shared_message make_shared_message(TPool& owner, const TMessage& message) + { + etl::ireference_counted_message* prcm = owner.allocate(message); + return etl::shared_message(*prcm, owner); + } + +#if ETL_CPP11_SUPPORTED + template + etl::shared_message make_shared_message(TPool& owner, TArgs&&... args) + { + etl::ireference_counted_message* prcm = owner.allocate(etl::forward(args)...); + return etl::shared_message(*prcm, owner); + } +#endif } #endif diff --git a/include/etl/shared_message_processor.h b/include/etl/shared_message_processor.h deleted file mode 100644 index de913c24..00000000 --- a/include/etl/shared_message_processor.h +++ /dev/null @@ -1,354 +0,0 @@ -/****************************************************************************** -The MIT License(MIT) - -Embedded Template Library. -https://github.com/ETLCPP/etl -https://www.etlcpp.com - -Copyright(c) 2020 jwellbelove - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -******************************************************************************/ - -#ifndef ETL_SHARED_MESSAGE_PROCESSOR_INCLUDED -#define ETL_SHARED_MESSAGE_PROCESSOR_INCLUDED - -#include "platform.h" -#include "shared_message.h" -#include "vector.h" - -#include - -namespace etl -{ - typedef uint_least8_t shared_message_processor_id_t; - - //*************************************************************************** - /// This is the base of all shared message processors. - //*************************************************************************** - class ishared_message_processor - { - public: - - //*************************************************************************** - /// - //*************************************************************************** - ishared_message_processor(etl::shared_message_processor_id_t id_ = etl::shared_message_processor_id_t()) - : id(id_) - { - } - - virtual void receive(etl::shared_message shared_msg) = 0; - virtual void receive(shared_message_processor_id_t destination_processor_id, etl::shared_message shared_msg) = 0; - virtual bool accepts(etl::message_id_t id) const = 0; - - //*************************************************************************** - /// - //*************************************************************************** - bool accepts(etl::shared_message shared_msg) const - { - return accepts(shared_msg.get_message().get_message_id()); - } - - //*************************************************************************** - /// - //*************************************************************************** - shared_message_processor_id_t get_shared_message_processor_id() const - { - return id; - } - - enum - { - NULL_SHARED_MESSAGE_PROCESSOR = 255, - SHARED_MESSAGE_BUS = 254, - ALL_SHARED_MESSAGE_PROCESSORS = 253, - MAX_SHARED_MESSAGE_PROCESSOR = 249 - }; - - protected: - - etl::shared_message_processor_id_t id; - }; - - //*************************************************************************** - /// Derive user defined shared message processors from this. - //*************************************************************************** - class shared_message_processor : public ishared_message_processor - { - public: - - //*************************************************************************** - /// - //*************************************************************************** - shared_message_processor(etl::shared_message_processor_id_t id_ = etl::shared_message_processor_id_t()) - : ishared_message_processor(id_) - { - } - - etl::ishared_message_processor::receive; - - //*************************************************************************** - /// - //*************************************************************************** - void receive(etl::shared_message shared_msg) - { - on_receive(shared_msg); - } - - //*************************************************************************** - /// - //*************************************************************************** - void receive(shared_message_processor_id_t destination_processor_id, etl::shared_message shared_msg) - { - if (destination_processor_id == id) - { - on_receive(shared_msg); - } - } - - // User overridden. - virtual void on_receive(etl::shared_message shared_msg) = 0; - }; - - //*************************************************************************** - /// Interface for shared message bus - //*************************************************************************** - class ishared_message_bus : public etl::ishared_message_processor - { - private: - - typedef etl::ivector processor_list_t; - - public: - - using etl::ishared_message_processor::receive; - - //******************************************* - /// Subscribe to the bus. - //******************************************* - bool subscribe(etl::ishared_message_processor& processor) - { - bool ok = true; - - ok = !processor_list.full(); - - ETL_ASSERT(ok, ETL_ERROR(etl::shared_message_bus_too_many_subscribers)); - - if (ok) - { - processor_list_t::iterator iprocessor = etl::upper_bound(processor_list.begin(), - processor_list.end(), - processor.get_shared_message_processor_id(), - compare_processor_id()); - - processor_list.insert(iprocessor, &processor); - } - - return ok; - } - - //******************************************* - /// Unsubscribe from the bus. - //******************************************* - void unsubscribe(etl::shared_message_processor_id_t id) - { - if (id == etl::ishared_message_bus::ALL_SHARED_MESSAGE_PROCESSORS) - { - clear(); - } - else - { - ETL_OR_STD::pair range = etl::equal_range(processor_list.begin(), - processor_list.end(), - id, - compare_processor_id()); - - processor_list.erase(range.first, range.second); - } - } - - //******************************************* - void unsubscribe(etl::shared_message_processor& processor) - { - processor_list_t::iterator iprocessor = etl::find(processor_list.begin(), - processor_list.end(), - &processor); - - if (iprocessor != processor_list.end()) - { - processor_list.erase(iprocessor); - } - } - - //******************************************* - void receive(shared_message shared_msg) ETL_OVERRIDE - { - receive(etl::shared_message_processor::ALL_SHARED_MESSAGE_PROCESSORS, shared_msg); - } - - //******************************************* - void receive(etl::shared_message_processor_id_t destination_processor_id, - etl::shared_message shared_msg) ETL_OVERRIDE - { - switch (destination_processor_id) - { - //***************************** - // Broadcast to all processors. - case etl::shared_message_processor::ALL_SHARED_MESSAGE_PROCESSORS: - { - processor_list_t::iterator iprocessor = processor_list.begin(); - - // Broadcast to everyone. - while (iprocessor != processor_list.end()) - { - etl::ishared_message_processor& processor = **iprocessor; - - if (processor.accepts(shared_msg.get_message().get_message_id())) - { - processor.receive(shared_msg); - } - - ++iprocessor; - } - - break; - } - - //***************************** - // Must be an addressed shared_msg. - default: - { - processor_list_t::iterator iprocessor = processor_list.begin(); - - // Find processors with the id. - ETL_OR_STD::pair range = etl::equal_range(processor_list.begin(), - processor_list.end(), - destination_processor_id, - compare_processor_id()); - - // Call all of them. - while (range.first != range.second) - { - if ((*(range.first))->accepts(shared_msg.get_message().get_message_id())) - { - (*(range.first))->receive(shared_msg); - } - - ++range.first; - } - - // Do any message buses. - // These are always at the end of the list. - iprocessor = etl::lower_bound(processor_list.begin(), - processor_list.end(), - etl::ishared_message_bus::SHARED_MESSAGE_BUS, - compare_processor_id()); - - while (iprocessor != processor_list.end()) - { - // So pass it on. - (*iprocessor)->receive(destination_processor_id, shared_msg); - - ++iprocessor; - } - - break; - } - } - } - - using ishared_message_processor::accepts; - - //******************************************* - /// Does this message bus accept the message id? - /// Yes!, it accepts everything! - //******************************************* - bool accepts(etl::message_id_t) const ETL_OVERRIDE - { - return true; - } - - //******************************************* - size_t size() const - { - return processor_list.size(); - } - - //******************************************* - void clear() - { - return processor_list.clear(); - } - - protected: - - //******************************************* - /// Constructor. - //******************************************* - ishared_message_bus(processor_list_t& list) - : ishared_message_processor(etl::ishared_message_processor::SHARED_MESSAGE_BUS) - , processor_list(list) - { - } - - private: - - //******************************************* - // How to compare processors to processor ids. - //******************************************* - struct compare_processor_id - { - bool operator()(const etl::ishared_message_processor* prouter, etl::shared_message_processor_id_t id) const - { - return prouter->get_shared_message_processor_id() < id; - } - - bool operator()(etl::shared_message_processor_id_t id, const etl::ishared_message_processor* prouter) const - { - return id < prouter->get_shared_message_processor_id(); - } - }; - - processor_list_t& processor_list; - }; - - //*************************************************************************** - /// The message bus - //*************************************************************************** - template - class shared_message_bus : public etl::ishared_message_bus - { - public: - - //******************************************* - /// Constructor. - //******************************************* - shared_message_bus() - : ishared_message_bus(processor_list) - { - } - - private: - - etl::vector processor_list; - }; -} - -#endif From cbf07b053cc5e9de902034c32ad784629d55d325 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 2 Jan 2021 13:39:59 +0000 Subject: [PATCH 10/18] reference_counted_object and reference_counted_message specialisations --- .../etl/generators/message_router_generator.h | 113 ++++++++++-------- include/etl/reference_counted_message.h | 8 +- include/etl/reference_counted_object.h | 11 +- 3 files changed, 72 insertions(+), 60 deletions(-) diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index 4f0294b2..0ccd0bf7 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -68,6 +68,7 @@ cog.outl("//******************************************************************** #include "platform.h" #include "message.h" +#include "shared_message.h" #include "message_packet.h" #include "message_types.h" #include "alignment.h" @@ -107,6 +108,13 @@ namespace etl } }; + //*************************************************************************** + /// Forward declare null message router functionality. + //*************************************************************************** + class imessage_router; + + etl::imessage_router& get_null_message_router(); + //*************************************************************************** /// This is the base of all message routers. //*************************************************************************** @@ -115,14 +123,48 @@ namespace etl public: virtual ~imessage_router() {} - virtual void receive(const etl::imessage& message) = 0; virtual void receive(imessage_router& source, const etl::imessage& message) = 0; - virtual void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) = 0; virtual bool accepts(etl::message_id_t id) const = 0; virtual bool is_null_router() const = 0; virtual bool is_producer() const = 0; virtual bool is_consumer() const = 0; + //******************************************** + void receive(const etl::imessage& message) + { + receive(etl::get_null_message_router(), message); + } + + //******************************************** + void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) + { + if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) + { + receive(source, message); + } + } + + //******************************************** + virtual void receive(imessage_router& source, etl::shared_message shared_msg) + { + receive(source, shared_msg.get_message()); + } + + //******************************************** + void receive(etl::shared_message shared_msg) + { + receive(etl::get_null_message_router(), shared_msg); + } + + //******************************************** + void receive(imessage_router& source, etl::message_router_id_t destination_router_id, etl::shared_message shared_msg) + { + if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) + { + receive(source, shared_msg); + } + } + //******************************************** bool accepts(const etl::imessage& msg) const { @@ -156,23 +198,23 @@ namespace etl enum { NULL_MESSAGE_ROUTER = 255, - MESSAGE_BUS = 254, + MESSAGE_BUS = 254, ALL_MESSAGE_ROUTERS = 253, - MAX_MESSAGE_ROUTER = 249 + MAX_MESSAGE_ROUTER = 249 }; protected: imessage_router(etl::message_router_id_t id_) : successor(ETL_NULLPTR), - message_router_id(id_) + message_router_id(id_) { } imessage_router(etl::message_router_id_t id_, - imessage_router& successor_) + imessage_router& successor_) : successor(&successor_), - message_router_id(id_) + message_router_id(id_) { } @@ -199,21 +241,13 @@ namespace etl { } - //******************************************** - void receive(const etl::imessage&) ETL_OVERRIDE - { - } + using imessage_router::receive; //******************************************** void receive(etl::imessage_router&, const etl::imessage&) ETL_OVERRIDE { } - //******************************************** - void receive(imessage_router&, etl::message_router_id_t, const etl::imessage&) ETL_OVERRIDE - { - } - //******************************************** bool accepts(etl::message_id_t) const ETL_OVERRIDE { @@ -246,6 +280,13 @@ namespace etl } }; + //*********************************************** + /// null message router functionality. + inline etl::imessage_router& get_null_message_router() + { + return etl::null_message_router::instance(); + } + //*************************************************************************** /// This router can be used as a producer-only of messages, such an interrupt routine. //*************************************************************************** @@ -258,21 +299,13 @@ namespace etl { } - //******************************************** - void receive(const etl::imessage&) ETL_OVERRIDE - { - } + using imessage_router::receive; //******************************************** void receive(etl::imessage_router&, const etl::imessage&) ETL_OVERRIDE { } - //******************************************** - void receive(imessage_router&, etl::message_router_id_t, const etl::imessage&) ETL_OVERRIDE - { - } - //******************************************** bool accepts(etl::message_id_t) const ETL_OVERRIDE { @@ -358,20 +391,7 @@ namespace etl cog.outl(" ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") cog.outl(" }") cog.outl("") - cog.outl(" //**********************************************") - cog.outl(" void receive(const etl::imessage& msg) ETL_OVERRIDE") - cog.outl(" {") - cog.outl(" receive(etl::null_message_router::instance(), msg);") - cog.outl(" }") - cog.outl("") - cog.outl(" //**********************************************") - cog.outl(" void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE") - cog.outl(" {") - cog.outl(" if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS))") - cog.outl(" {") - cog.outl(" receive(source, msg);") - cog.outl(" }") - cog.outl(" }") + cog.outl(" using imessage_router::receive;") cog.outl("") cog.outl(" //**********************************************") cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE") @@ -491,20 +511,7 @@ namespace etl cog.outl(" ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") cog.outl(" }") cog.outl("") - cog.outl(" //**********************************************") - cog.outl(" void receive(const etl::imessage& msg) ETL_OVERRIDE") - cog.outl(" {") - cog.outl(" receive(etl::null_message_router::instance(), msg);") - cog.outl(" }") - cog.outl("") - cog.outl(" //**********************************************") - cog.outl(" void receive(etl::imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& msg) ETL_OVERRIDE") - cog.outl(" {") - cog.outl(" if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS))") - cog.outl(" {") - cog.outl(" receive(source, msg);") - cog.outl(" }") - cog.outl(" }") + cog.outl(" using imessage_router::receive;") cog.outl("") cog.outl(" //**********************************************") cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE") diff --git a/include/etl/reference_counted_message.h b/include/etl/reference_counted_message.h index 46e89771..c2426e39 100644 --- a/include/etl/reference_counted_message.h +++ b/include/etl/reference_counted_message.h @@ -54,7 +54,7 @@ namespace etl //*************************************************************************** // Reference counted message type. //*************************************************************************** - template + template class reference_counted_message : public etl::ireference_counted_message { public: @@ -132,7 +132,7 @@ namespace etl // Uncounted message type. //*************************************************************************** template - class uncounted_message : virtual public etl::ireference_counted_message + class reference_counted_message : virtual public etl::ireference_counted_message { public: @@ -143,7 +143,7 @@ namespace etl /// Constructor /// \param msg The message to count. //*************************************************************************** - uncounted_message(const TMessage& msg_) + reference_counted_message(const TMessage& msg_) : rc_object(msg_) { } @@ -178,7 +178,7 @@ namespace etl private: /// The reference counted object. - etl::uncounted_object rc_object; + etl::reference_counted_object rc_object; }; } diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h index 4b5fe33e..821ab449 100644 --- a/include/etl/reference_counted_object.h +++ b/include/etl/reference_counted_object.h @@ -55,7 +55,7 @@ namespace etl /// \tparam TObject The type to be reference counted. /// \tparam TCounter The type to use as the counter. //*************************************************************************** - template + template class reference_counted_object : public etl::ireference_counted_object { public: @@ -146,8 +146,13 @@ namespace etl }; #endif + //*************************************************************************** + /// Specialisation creating objects that have the ireference_counted_object interface + /// but do not actually count. + /// \tparam TObject The type stored in the object. + //*************************************************************************** template - class uncounted_object : public etl::ireference_counted_object + class reference_counted_object : public etl::ireference_counted_object { public: @@ -157,7 +162,7 @@ namespace etl //*************************************************************************** /// Constructor. //*************************************************************************** - uncounted_object(const TObject& object_) + reference_counted_object(const TObject& object_) : object(object_) { } From ecee02d41d75ecf6e62c5dd47809e1775e15b860 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 2 Jan 2021 14:09:36 +0000 Subject: [PATCH 11/18] reference_counted_object and reference_counted_message specialisations --- include/etl/reference_counted_message.h | 31 +++++++++++++++++++---- include/etl/reference_counted_object.h | 33 +++++++++++++++++++++---- 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/include/etl/reference_counted_message.h b/include/etl/reference_counted_message.h index c2426e39..3706a2e2 100644 --- a/include/etl/reference_counted_message.h +++ b/include/etl/reference_counted_message.h @@ -54,7 +54,7 @@ namespace etl //*************************************************************************** // Reference counted message type. //*************************************************************************** - template + template class reference_counted_message : public etl::ireference_counted_message { public: @@ -110,7 +110,7 @@ namespace etl /// \tparam TMessage The type to be reference counted. //*************************************************************************** template - class atomic_counted_message : virtual public etl::reference_counted_message + class atomic_counted_message : virtual public etl::reference_counted_message { public: @@ -119,12 +119,12 @@ namespace etl /// \param msg The message to count. //*************************************************************************** atomic_counted_message(const TMessage& msg_) - : reference_counted_message(msg_) + : reference_counted_message(msg_) { } - typedef typename reference_counted_message::message_type message_type; - typedef typename reference_counted_message::counter_type counter_type; + typedef typename reference_counted_message::message_type message_type; + typedef typename reference_counted_message::counter_type counter_type; }; #endif @@ -180,6 +180,27 @@ namespace etl /// The reference counted object. etl::reference_counted_object rc_object; }; + + //*************************************************************************** + /// Synonym for reference_counted_message + /// \tparam TObject The type stored in the object. + //*************************************************************************** + template + class uncounted_message : public etl::reference_counted_message + { + public: + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + uncounted_message(const TMessage& msg_) + : reference_counted_message(msg_) + { + } + + typedef typename reference_counted_message::message_type message_type; + typedef typename reference_counted_message::counter_type counter_type; + }; } #endif diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h index 821ab449..868ccf8e 100644 --- a/include/etl/reference_counted_object.h +++ b/include/etl/reference_counted_object.h @@ -55,7 +55,7 @@ namespace etl /// \tparam TObject The type to be reference counted. /// \tparam TCounter The type to use as the counter. //*************************************************************************** - template + template class reference_counted_object : public etl::ireference_counted_object { public: @@ -101,6 +101,8 @@ namespace etl //*************************************************************************** ETL_NODISCARD virtual uint32_t decrement_reference_count() ETL_OVERRIDE { + assert(reference_count > 0); + return uint32_t(--reference_count); } @@ -129,7 +131,7 @@ namespace etl /// \tparam TObject The type to be reference counted. //*************************************************************************** template - class atomic_counted_object : public etl::reference_counted_object + class atomic_counted_object : public etl::reference_counted_object { public: @@ -137,12 +139,12 @@ namespace etl /// Constructor. //*************************************************************************** atomic_counted_object(const TObject& object_) - : reference_counted_object(object_) + : reference_counted_object(object_) { } - typedef typename reference_counted_object::value_type value_type; - typedef typename reference_counted_object::counter_type counter_type; + typedef typename reference_counted_object::value_type value_type; + typedef typename reference_counted_object::counter_type counter_type; }; #endif @@ -217,6 +219,27 @@ namespace etl TObject object; // The object being reference counted. }; + + //*************************************************************************** + /// Synonym for reference_counted_object + /// \tparam TObject The type stored in the object. + //*************************************************************************** + template + class uncounted_object : public etl::reference_counted_object + { + public: + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + uncounted_object(const TObject& object_) + : reference_counted_object(object_) + { + } + + typedef typename reference_counted_object::value_type value_type; + typedef typename reference_counted_object::counter_type counter_type; + }; } #endif From dc25df16dbde78626db863e21d29c317ae21f355 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 2 Jan 2021 19:42:27 +0000 Subject: [PATCH 12/18] reference_counted_object and reference_counted_message specialisations --- include/etl/reference_counted_message.h | 62 ++++----------- include/etl/reference_counted_message_pool.h | 30 +++---- include/etl/reference_counted_object.h | 83 ++++++-------------- include/etl/shared_message.h | 37 ++++----- 4 files changed, 75 insertions(+), 137 deletions(-) diff --git a/include/etl/reference_counted_message.h b/include/etl/reference_counted_message.h index 3706a2e2..aa9ad05a 100644 --- a/include/etl/reference_counted_message.h +++ b/include/etl/reference_counted_message.h @@ -104,46 +104,23 @@ namespace etl etl::reference_counted_object rc_object; }; -#if ETL_HAS_ATOMIC //*************************************************************************** - /// Class for creating reference counted messages using an atomic counter. - /// \tparam TMessage The type to be reference counted. + /// Persistent message type. + /// The message type will always have a reference count of 1. + /// \tparam TMessage The message type stored. //*************************************************************************** template - class atomic_counted_message : virtual public etl::reference_counted_message - { - public: - - //*************************************************************************** - /// Constructor. - /// \param msg The message to count. - //*************************************************************************** - atomic_counted_message(const TMessage& msg_) - : reference_counted_message(msg_) - { - } - - typedef typename reference_counted_message::message_type message_type; - typedef typename reference_counted_message::counter_type counter_type; - }; -#endif - - //*************************************************************************** - // Uncounted message type. - //*************************************************************************** - template - class reference_counted_message : virtual public etl::ireference_counted_message + class persistent_message : virtual public etl::ireference_counted_message { public: typedef TMessage message_type; - typedef void counter_type; //*************************************************************************** /// Constructor /// \param msg The message to count. //*************************************************************************** - reference_counted_message(const TMessage& msg_) + persistent_message(const TMessage& msg_) : rc_object(msg_) { } @@ -177,30 +154,23 @@ namespace etl private: + // This class must not be default contructed, copy constructed or assigned. + persistent_message() ETL_DELETE; + persistent_message(const persistent_message&) ETL_DELETE; + persistent_message& operator =(const persistent_message&) ETL_DELETE; + /// The reference counted object. - etl::reference_counted_object rc_object; + etl::persistent_object rc_object; }; +#if ETL_CPP11_SUPPORTED && ETL_HAS_ATOMIC //*************************************************************************** - /// Synonym for reference_counted_message - /// \tparam TObject The type stored in the object. + /// Class for creating reference counted objects using an atomic counter. + /// \tparam TObject The type to be reference counted. //*************************************************************************** template - class uncounted_message : public etl::reference_counted_message - { - public: - - //*************************************************************************** - /// Constructor. - //*************************************************************************** - uncounted_message(const TMessage& msg_) - : reference_counted_message(msg_) - { - } - - typedef typename reference_counted_message::message_type message_type; - typedef typename reference_counted_message::counter_type counter_type; - }; + using atomic_counted_message = etl::reference_counted_message; +#endif } #endif diff --git a/include/etl/reference_counted_message_pool.h b/include/etl/reference_counted_message_pool.h index b7a8f79b..a044b8fc 100644 --- a/include/etl/reference_counted_message_pool.h +++ b/include/etl/reference_counted_message_pool.h @@ -72,7 +72,7 @@ namespace etl //}; //*************************************************************************** - /// + /// Iterface for a reference counted message pool. //*************************************************************************** class ireference_counted_message_pool { @@ -83,7 +83,7 @@ namespace etl }; //*************************************************************************** - /// + /// A pool for allocating reference counted messages. //*************************************************************************** template class reference_counted_message_pool : public ireference_counted_message_pool @@ -98,13 +98,17 @@ namespace etl //{ //} + reference_counted_message_pool() + { + } + //************************************************************************* /// Allocate a reference counted message from the pool. //************************************************************************* template etl::ireference_counted_message* allocate(const TMessage& message) { - //ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); + ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); using ref_message_t = etl::reference_counted_message; @@ -135,7 +139,7 @@ namespace etl template etl::ireference_counted_message* allocate(TArgs&&... args) { - //ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); + ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); using ref_message_t = etl::reference_counted_message; @@ -298,15 +302,13 @@ namespace etl //************************************************************************* /// Destruct a message and send it back to the pool. //************************************************************************* - void release(const etl::ireference_counted_message* const prcm) + void release(const etl::ireference_counted_message* const p_rcmessage) { - std::cout << "reference_counted_message_pool : release\n"; - - if (prcm != ETL_NULLPTR) + if (p_rcmessage != ETL_NULLPTR) { -// prcm->~ireference_counted_message(); - delete prcm; - //memory_block_pool.release_memory_block(prcm); +// p_rcmessage->~ireference_counted_message(); + delete p_rcmessage; + //memory_block_pool.release_memory_block(p_rcmessage); } } @@ -323,9 +325,9 @@ namespace etl /// The raw memory block pool. //imemory_block_pool& memory_block_pool; - //// Should not be copied. - //message_pool(const message_pool&) ETL_DELETE; - //message_pool& operator =(const message_pool&) ETL_DELETE; + // Should not be copied. + reference_counted_message_pool(const reference_counted_message_pool&) ETL_DELETE; + reference_counted_message_pool& operator =(const reference_counted_message_pool&) ETL_DELETE; }; } diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h index 868ccf8e..2b539480 100644 --- a/include/etl/reference_counted_object.h +++ b/include/etl/reference_counted_object.h @@ -44,10 +44,10 @@ namespace etl public: virtual ~ireference_counted_object() {}; - virtual void set_reference_count(uint32_t value) = 0; + virtual void set_reference_count(int32_t value) = 0; virtual void increment_reference_count() = 0; - ETL_NODISCARD virtual uint32_t decrement_reference_count() = 0; - ETL_NODISCARD virtual uint32_t get_reference_count() const = 0; + ETL_NODISCARD virtual int32_t decrement_reference_count() = 0; + ETL_NODISCARD virtual int32_t get_reference_count() const = 0; }; //*************************************************************************** @@ -83,7 +83,7 @@ namespace etl //*************************************************************************** /// Set the reference count. //*************************************************************************** - virtual void set_reference_count(uint32_t value) ETL_OVERRIDE + virtual void set_reference_count(int32_t value) ETL_OVERRIDE { reference_count = value; } @@ -99,19 +99,19 @@ namespace etl //*************************************************************************** /// Decrement the refernce count. //*************************************************************************** - ETL_NODISCARD virtual uint32_t decrement_reference_count() ETL_OVERRIDE + ETL_NODISCARD virtual int32_t decrement_reference_count() ETL_OVERRIDE { assert(reference_count > 0); - return uint32_t(--reference_count); + return int32_t(--reference_count); } //*************************************************************************** /// Get the current reference count. //*************************************************************************** - ETL_NODISCARD virtual uint32_t get_reference_count() const ETL_OVERRIDE + ETL_NODISCARD virtual int32_t get_reference_count() const ETL_OVERRIDE { - return uint32_t(reference_count); + return int32_t(reference_count); } private: @@ -125,46 +125,22 @@ namespace etl const TObject object; // The object being reference counted. }; -#if ETL_HAS_ATOMIC //*************************************************************************** - /// Class for creating reference counted objects using an atomic counter. - /// \tparam TObject The type to be reference counted. - //*************************************************************************** - template - class atomic_counted_object : public etl::reference_counted_object - { - public: - - //*************************************************************************** - /// Constructor. - //*************************************************************************** - atomic_counted_object(const TObject& object_) - : reference_counted_object(object_) - { - } - - typedef typename reference_counted_object::value_type value_type; - typedef typename reference_counted_object::counter_type counter_type; - }; -#endif - - //*************************************************************************** - /// Specialisation creating objects that have the ireference_counted_object interface - /// but do not actually count. + /// Persistent message type. + /// The message type will always have a reference count of 1. /// \tparam TObject The type stored in the object. //*************************************************************************** template - class reference_counted_object : public etl::ireference_counted_object + class persistent_object : public etl::ireference_counted_object { public: - typedef TObject value_type; - typedef void counter_type; + typedef TObject value_type; //*************************************************************************** /// Constructor. //*************************************************************************** - reference_counted_object(const TObject& object_) + persistent_object(const TObject& object_) : object(object_) { } @@ -188,7 +164,7 @@ namespace etl //*************************************************************************** /// Set the reference count. //*************************************************************************** - virtual void set_reference_count(uint32_t value) ETL_OVERRIDE + virtual void set_reference_count(int32_t) ETL_OVERRIDE { } @@ -202,7 +178,7 @@ namespace etl //*************************************************************************** /// Decrement the refernce count. //*************************************************************************** - ETL_NODISCARD virtual uint32_t decrement_reference_count() ETL_OVERRIDE + ETL_NODISCARD virtual int32_t decrement_reference_count() ETL_OVERRIDE { return 1; } @@ -210,36 +186,29 @@ namespace etl //*************************************************************************** /// Get the current reference count. //*************************************************************************** - ETL_NODISCARD virtual uint32_t get_reference_count() const ETL_OVERRIDE + ETL_NODISCARD virtual int32_t get_reference_count() const ETL_OVERRIDE { return 1; } private: + // This class must not be default contructed, copy constructed or assigned. + persistent_object() ETL_DELETE; + persistent_object(const persistent_object&) ETL_DELETE; + persistent_object& operator =(const persistent_object&) ETL_DELETE; + TObject object; // The object being reference counted. }; +#if ETL_CPP11_SUPPORTED && ETL_HAS_ATOMIC //*************************************************************************** - /// Synonym for reference_counted_object - /// \tparam TObject The type stored in the object. + /// Class for creating reference counted objects using an atomic counter. + /// \tparam TObject The type to be reference counted. //*************************************************************************** template - class uncounted_object : public etl::reference_counted_object - { - public: - - //*************************************************************************** - /// Constructor. - //*************************************************************************** - uncounted_object(const TObject& object_) - : reference_counted_object(object_) - { - } - - typedef typename reference_counted_object::value_type value_type; - typedef typename reference_counted_object::counter_type counter_type; - }; + using atomic_counted_object = etl::reference_counted_object; +#endif } #endif diff --git a/include/etl/shared_message.h b/include/etl/shared_message.h index d4154087..83fd2a98 100644 --- a/include/etl/shared_message.h +++ b/include/etl/shared_message.h @@ -31,8 +31,6 @@ SOFTWARE. #ifndef ETL_SHARED_MESSAGE_INCLUDED #define ETL_SHARED_MESSAGE_INCLUDED -#include - #include "platform.h" #include "reference_counted_message_pool.h" #include "reference_counted_message.h" @@ -57,15 +55,18 @@ namespace etl , p_rcmessage(&message_) { p_rcmessage->get_reference_counter().set_reference_count(1U); - std::cout << "shared_message C : ID = " << int(p_rcmessage->get_message().get_message_id()) << " : Count = " << p_rcmessage->get_reference_counter().get_reference_count() << "\n"; } + //************************************************************************* + /// Constructor + + /// \param pmessage A reference to the message allocated from the pool. + //************************************************************************* shared_message(etl::ireference_counted_message& message_) : p_rcmessage_owner(ETL_NULLPTR) , p_rcmessage(&message_) { p_rcmessage->get_reference_counter().set_reference_count(1U); - std::cout << "shared_message C : ID = " << int(p_rcmessage->get_message().get_message_id()) << " No Owner\n"; } //************************************************************************* @@ -76,7 +77,6 @@ namespace etl , p_rcmessage(other.p_rcmessage) { p_rcmessage->get_reference_counter().increment_reference_count(); - std::cout << "shared_message CC : ID = " << int(p_rcmessage->get_message().get_message_id()) << " : Count = " << p_rcmessage->get_reference_counter().get_reference_count() << "\n"; } //************************************************************************* @@ -89,7 +89,6 @@ namespace etl // Deal with the current message. if (p_rcmessage->get_reference_counter().decrement_reference_count() == 0U) { - std::cout << "shared_message =: Destroy reference counted message\n"; if (p_rcmessage_owner != ETL_NULLPTR) { p_rcmessage_owner->release(p_rcmessage); @@ -100,7 +99,6 @@ namespace etl p_rcmessage_owner = other.p_rcmessage_owner; p_rcmessage = other.p_rcmessage; p_rcmessage->get_reference_counter().increment_reference_count(); - std::cout << "shared_message =: ID = " << int(p_rcmessage->get_message().get_message_id()) << " : Count = " << p_rcmessage->get_reference_counter().get_reference_count() << "\n"; } return *this; @@ -116,17 +114,8 @@ namespace etl { if (is_owned()) { - std::cout << "shared_message ~: Destroy reference counted message\n"; p_rcmessage_owner->release(p_rcmessage); } - else - { - std::cout << "shared_message ~: Uncounted message\n"; - } - } - else - { - std::cout << "shared_message ~ : ID = " << int(p_rcmessage->get_message().get_message_id()) << " : Count = " << p_rcmessage->get_reference_counter().get_reference_count() << "\n"; } } @@ -162,19 +151,27 @@ namespace etl etl::ireference_counted_message* p_rcmessage; }; + //***************************************************************************** + /// A wrapper for reference counted messages. + /// Contains pointers to a pool owner and a message defined with a ref count type. + //***************************************************************************** template etl::shared_message make_shared_message(TPool& owner, const TMessage& message) { - etl::ireference_counted_message* prcm = owner.allocate(message); - return etl::shared_message(*prcm, owner); + etl::ireference_counted_message* p_rcmessage = owner.allocate(message); + return etl::shared_message(*p_rcmessage, owner); } #if ETL_CPP11_SUPPORTED + //***************************************************************************** + /// A wrapper for reference counted messages. + /// Contains pointers to a pool owner and a message defined with a ref count type. + //***************************************************************************** template etl::shared_message make_shared_message(TPool& owner, TArgs&&... args) { - etl::ireference_counted_message* prcm = owner.allocate(etl::forward(args)...); - return etl::shared_message(*prcm, owner); + etl::ireference_counted_message* p_rcmessage = owner.allocate(etl::forward(args)...); + return etl::shared_message(*p_rcmessage, owner); } #endif } From 3c2cb745249d1946e6c80246cc3a8813ec12c40e Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 3 Jan 2021 12:18:34 +0000 Subject: [PATCH 13/18] Refactored reference_counted_message now contains owner reference --- include/etl/ireference_counted_message_pool.h | 53 +++++ include/etl/reference_counted_message.h | 57 +++-- include/etl/reference_counted_message_pool.h | 16 +- include/etl/reference_counted_object.h | 197 ++++++++++++------ include/etl/shared_message.h | 62 ++---- 5 files changed, 241 insertions(+), 144 deletions(-) create mode 100644 include/etl/ireference_counted_message_pool.h diff --git a/include/etl/ireference_counted_message_pool.h b/include/etl/ireference_counted_message_pool.h new file mode 100644 index 00000000..ddacf969 --- /dev/null +++ b/include/etl/ireference_counted_message_pool.h @@ -0,0 +1,53 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2020 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_IREFERENCE_COUNTED_MESSAGE_POOL_INCLUDED +#define ETL_IREFERENCE_COUNTED_MESSAGE_POOL_INCLUDED + +#include "platform.h" + +namespace etl +{ + class ireference_counted_message; + + //*************************************************************************** + /// Interface for a reference counted message pool. + //*************************************************************************** + class ireference_counted_message_pool + { + public: + + virtual void release(const etl::ireference_counted_message* const pmsg) = 0; + virtual void release(const etl::ireference_counted_message& msg) = 0; + }; +} + +#endif + diff --git a/include/etl/reference_counted_message.h b/include/etl/reference_counted_message.h index aa9ad05a..94d15cd1 100644 --- a/include/etl/reference_counted_message.h +++ b/include/etl/reference_counted_message.h @@ -35,6 +35,7 @@ SOFTWARE. #include "message.h" #include "atomic.h" #include "reference_counted_object.h" +#include "ireference_counted_message_pool.h" namespace etl { @@ -45,10 +46,10 @@ namespace etl { public: - virtual const etl::imessage& get_message() const = 0; ///< Get a const reference to the message. - - virtual etl::ireference_counted_object& get_reference_counter() = 0; ///< Get a reference to the reference counter. - virtual const etl::ireference_counted_object& get_reference_counter() const = 0; ///< Get a const reference to the reference counter. + virtual ETL_NODISCARD const etl::imessage& get_message() const = 0; ///< Get a const reference to the message. + virtual ETL_NODISCARD etl::ireference_counter& get_reference_counter() = 0; ///< Get a reference to the reference counter. + virtual ETL_NODISCARD const etl::ireference_counter& get_reference_counter() const = 0; ///< Get a const reference to the reference counter. + virtual void release() = 0; ///< Release back to the owner. }; //*************************************************************************** @@ -66,8 +67,9 @@ namespace etl /// Constructor /// \param msg The message to count. //*************************************************************************** - reference_counted_message(const TMessage& msg_) + reference_counted_message(const TMessage& msg_, etl::ireference_counted_message_pool& owner_) : rc_object(msg_) + , owner(owner_) { } @@ -75,7 +77,7 @@ namespace etl /// Get a const reference to the message. /// \return A const reference to the message. //*************************************************************************** - virtual const TMessage& get_message() const ETL_OVERRIDE + virtual ETL_NODISCARD const TMessage& get_message() const ETL_OVERRIDE { return rc_object.get_object(); } @@ -84,24 +86,33 @@ namespace etl /// Get a reference to the reference counter. /// \return A reference to the reference counter. //*************************************************************************** - virtual etl::ireference_counted_object& get_reference_counter() ETL_OVERRIDE + virtual ETL_NODISCARD etl::ireference_counter& get_reference_counter() ETL_OVERRIDE { - return rc_object; + return rc_object.get_reference_counter(); } //*************************************************************************** /// Get a const reference to the reference counter. /// \return A const reference to the reference counter. //*************************************************************************** - virtual const etl::ireference_counted_object& get_reference_counter() const ETL_OVERRIDE + virtual ETL_NODISCARD const etl::ireference_counter& get_reference_counter() const ETL_OVERRIDE { - return rc_object; + return rc_object.get_reference_counter(); + } + + //*************************************************************************** + /// Release back to the owner pool. + /// \return A reference to the owner pool. + //*************************************************************************** + virtual void release() ETL_OVERRIDE + { + owner.release(*this); } private: - /// The reference counted object. - etl::reference_counted_object rc_object; + etl::reference_counted_object rc_object; ///< The reference counted object. + etl::ireference_counted_message_pool& owner; ///< The pool that owns this object. }; //*************************************************************************** @@ -129,7 +140,7 @@ namespace etl /// Get a const reference to the message. /// \return A const reference to the message. //*************************************************************************** - virtual const TMessage& get_message() const ETL_OVERRIDE + virtual ETL_NODISCARD const TMessage& get_message() const ETL_OVERRIDE { return rc_object.get_object(); } @@ -138,18 +149,27 @@ namespace etl /// Get a reference to the reference counter. /// \return A reference to the reference counter. //*************************************************************************** - virtual etl::ireference_counted_object& get_reference_counter() ETL_OVERRIDE + virtual ETL_NODISCARD etl::ireference_counter& get_reference_counter() ETL_OVERRIDE { - return rc_object; + return rc_object.get_reference_counter(); } //*************************************************************************** /// Get a const reference to the reference counter. /// \return A const reference to the reference counter. //*************************************************************************** - virtual const etl::ireference_counted_object& get_reference_counter() const ETL_OVERRIDE + virtual ETL_NODISCARD const etl::ireference_counter& get_reference_counter() const ETL_OVERRIDE { - return rc_object; + return rc_object.get_reference_counter(); + } + + //*************************************************************************** + /// Release back to the owner pool. + /// \return A reference to the owner pool. + //*************************************************************************** + virtual void release() ETL_OVERRIDE + { + // Do nothing. } private: @@ -159,8 +179,7 @@ namespace etl persistent_message(const persistent_message&) ETL_DELETE; persistent_message& operator =(const persistent_message&) ETL_DELETE; - /// The reference counted object. - etl::persistent_object rc_object; + etl::persistent_object rc_object; ///< The reference counted object. }; #if ETL_CPP11_SUPPORTED && ETL_HAS_ATOMIC diff --git a/include/etl/reference_counted_message_pool.h b/include/etl/reference_counted_message_pool.h index a044b8fc..95287774 100644 --- a/include/etl/reference_counted_message_pool.h +++ b/include/etl/reference_counted_message_pool.h @@ -33,6 +33,7 @@ SOFTWARE. #include "platform.h" #include "message.h" +#include "ireference_counted_message_pool.h" #include "reference_counted_message.h" #include "static_assert.h" #include "error_handler.h" @@ -71,17 +72,6 @@ namespace etl // } //}; - //*************************************************************************** - /// Iterface for a reference counted message pool. - //*************************************************************************** - class ireference_counted_message_pool - { - public: - - virtual void release(const etl::ireference_counted_message* const pmsg) = 0; - virtual void release(const etl::ireference_counted_message& msg) = 0; - }; - //*************************************************************************** /// A pool for allocating reference counted messages. //*************************************************************************** @@ -121,7 +111,7 @@ namespace etl // if (p != ETL_NULLPTR) // { // ::new(p) ref_message_t(TMessage(etl::forward(args)...)); - p = ::new ref_message_t(message); + p = ::new ref_message_t(message, *this); // } // else // { @@ -152,7 +142,7 @@ namespace etl // if (p != ETL_NULLPTR) // { // ::new(p) ref_message_t(TMessage(etl::forward(args)...)); - p = ::new ref_message_t(TMessage(etl::forward(args)...)); + p = ::new ref_message_t(TMessage(etl::forward(args)...), *this); // } // else // { diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h index 2b539480..36792082 100644 --- a/include/etl/reference_counted_object.h +++ b/include/etl/reference_counted_object.h @@ -37,17 +37,122 @@ namespace etl { //*************************************************************************** - /// The base of all reference counted objects. + /// The base of all reference counters. + //*************************************************************************** + class ireference_counter + { + public: + + virtual ~ireference_counter() {}; + virtual void set_reference_count(int32_t value) = 0; + virtual void increment_reference_count() = 0; + ETL_NODISCARD virtual int32_t decrement_reference_count() = 0; + ETL_NODISCARD virtual int32_t get_reference_count() const = 0; + }; + + //*************************************************************************** + /// A specific type of reference counter. + //*************************************************************************** + template + class reference_counter : public ireference_counter + { + public: + + //*************************************************************************** + /// Constructor. + //*************************************************************************** + reference_counter() + : reference_count(0) + { + } + + //*************************************************************************** + /// Set the reference count. + //*************************************************************************** + virtual void set_reference_count(int32_t value) ETL_OVERRIDE + { + reference_count = value; + } + + //*************************************************************************** + /// Increment the reference count. + //*************************************************************************** + virtual void increment_reference_count() ETL_OVERRIDE + { + ++reference_count; + } + + //*************************************************************************** + /// Decrement the reference count. + //*************************************************************************** + ETL_NODISCARD virtual int32_t decrement_reference_count() ETL_OVERRIDE + { + assert(reference_count > 0); + + return int32_t(--reference_count); + } + + //*************************************************************************** + /// Get the current reference count. + //*************************************************************************** + ETL_NODISCARD virtual int32_t get_reference_count() const ETL_OVERRIDE + { + return int32_t(reference_count); + } + + private: + + TCounter reference_count; // The reference count object. + }; + + //*************************************************************************** + /// A null reference counter. + /// Always returns the reference count as 1, for persistent objects. + //*************************************************************************** + class null_reference_counter : public ireference_counter + { + public: + + //*************************************************************************** + /// Set the reference count. + //*************************************************************************** + virtual void set_reference_count(int32_t value) ETL_OVERRIDE + { + } + + //*************************************************************************** + /// Increment the reference count. + //*************************************************************************** + virtual void increment_reference_count() ETL_OVERRIDE + { + } + + //*************************************************************************** + /// Decrement the reference count. + //*************************************************************************** + ETL_NODISCARD virtual int32_t decrement_reference_count() ETL_OVERRIDE + { + return int32_t(1); + } + + //*************************************************************************** + /// Get the current reference count. + //*************************************************************************** + ETL_NODISCARD virtual int32_t get_reference_count() const ETL_OVERRIDE + { + return int32_t(1); + } + }; + + //*************************************************************************** + /// Base for all reference counted objects. //*************************************************************************** class ireference_counted_object { public: - virtual ~ireference_counted_object() {}; - virtual void set_reference_count(int32_t value) = 0; - virtual void increment_reference_count() = 0; - ETL_NODISCARD virtual int32_t decrement_reference_count() = 0; - ETL_NODISCARD virtual int32_t get_reference_count() const = 0; + ETL_NODISCARD virtual ireference_counter& get_reference_counter() = 0; + ETL_NODISCARD virtual const ireference_counter& get_reference_counter() const = 0; }; //*************************************************************************** @@ -69,49 +174,30 @@ namespace etl reference_counted_object(const TObject& object_) : object(object_) { - reference_count = 0; } - + //*************************************************************************** /// Get a const reference to the counted object. //*************************************************************************** - const value_type& get_object() const + ETL_NODISCARD const value_type& get_object() const { return object; } //*************************************************************************** - /// Set the reference count. + /// Get a reference to the reference counter. //*************************************************************************** - virtual void set_reference_count(int32_t value) ETL_OVERRIDE + virtual ETL_NODISCARD ireference_counter& get_reference_counter() ETL_OVERRIDE { - reference_count = value; + return reference_counter; } //*************************************************************************** - /// Increment the refernce count. + /// Get a const reference to the reference counter. //*************************************************************************** - virtual void increment_reference_count() ETL_OVERRIDE + virtual ETL_NODISCARD const ireference_counter& get_reference_counter() const ETL_OVERRIDE { - ++reference_count; - } - - //*************************************************************************** - /// Decrement the refernce count. - //*************************************************************************** - ETL_NODISCARD virtual int32_t decrement_reference_count() ETL_OVERRIDE - { - assert(reference_count > 0); - - return int32_t(--reference_count); - } - - //*************************************************************************** - /// Get the current reference count. - //*************************************************************************** - ETL_NODISCARD virtual int32_t get_reference_count() const ETL_OVERRIDE - { - return int32_t(reference_count); + return reference_counter; } private: @@ -120,9 +206,9 @@ namespace etl reference_counted_object() ETL_DELETE; reference_counted_object(const reference_counted_object&) ETL_DELETE; reference_counted_object& operator =(const reference_counted_object&) ETL_DELETE; - - TCounter reference_count; // The reference counter - const TObject object; // The object being reference counted. + + const TObject object; ///< The object being reference counted. + etl::reference_counter reference_counter; ///< The reference counter. }; //*************************************************************************** @@ -145,50 +231,28 @@ namespace etl { } - //*************************************************************************** - /// Get a reference to the counted object. - //*************************************************************************** - value_type& get_object() - { - return object; - } - //*************************************************************************** /// Get a const reference to the counted object. //*************************************************************************** - const value_type& get_object() const + ETL_NODISCARD const value_type& get_object() const { return object; } //*************************************************************************** - /// Set the reference count. + /// Get a reference to the reference counter. //*************************************************************************** - virtual void set_reference_count(int32_t) ETL_OVERRIDE + virtual ETL_NODISCARD ireference_counter& get_reference_counter() ETL_OVERRIDE { + return reference_counter; } //*************************************************************************** - /// Increment the refernce count. + /// Get a const reference to the reference counter. //*************************************************************************** - virtual void increment_reference_count() ETL_OVERRIDE + virtual ETL_NODISCARD const ireference_counter& get_reference_counter() const ETL_OVERRIDE { - } - - //*************************************************************************** - /// Decrement the refernce count. - //*************************************************************************** - ETL_NODISCARD virtual int32_t decrement_reference_count() ETL_OVERRIDE - { - return 1; - } - - //*************************************************************************** - /// Get the current reference count. - //*************************************************************************** - ETL_NODISCARD virtual int32_t get_reference_count() const ETL_OVERRIDE - { - return 1; + return reference_counter; } private: @@ -198,7 +262,8 @@ namespace etl persistent_object(const persistent_object&) ETL_DELETE; persistent_object& operator =(const persistent_object&) ETL_DELETE; - TObject object; // The object being reference counted. + TObject object; ///< The object being reference counted. + etl::null_reference_counter reference_counter; ///< The reference counter. }; #if ETL_CPP11_SUPPORTED && ETL_HAS_ATOMIC diff --git a/include/etl/shared_message.h b/include/etl/shared_message.h index 83fd2a98..61f68e4a 100644 --- a/include/etl/shared_message.h +++ b/include/etl/shared_message.h @@ -32,7 +32,6 @@ SOFTWARE. #define ETL_SHARED_MESSAGE_INCLUDED #include "platform.h" -#include "reference_counted_message_pool.h" #include "reference_counted_message.h" //***************************************************************************** @@ -47,24 +46,10 @@ namespace etl //************************************************************************* /// Constructor - /// \param owner_ A reference to the owner pool. - /// \param pmessage A reference to the message allocated from the pool. + /// \param message A reference to the message allocated from the pool. //************************************************************************* - shared_message(etl::ireference_counted_message& message_, etl::ireference_counted_message_pool& owner_) - : p_rcmessage_owner(&owner_) - , p_rcmessage(&message_) - { - p_rcmessage->get_reference_counter().set_reference_count(1U); - } - - //************************************************************************* - /// Constructor - - /// \param pmessage A reference to the message allocated from the pool. - //************************************************************************* - shared_message(etl::ireference_counted_message& message_) - : p_rcmessage_owner(ETL_NULLPTR) - , p_rcmessage(&message_) + shared_message(etl::ireference_counted_message& rcmessage_) + : p_rcmessage(&rcmessage_) { p_rcmessage->get_reference_counter().set_reference_count(1U); } @@ -73,8 +58,7 @@ namespace etl /// Copy constructor //************************************************************************* shared_message(const shared_message& other) - : p_rcmessage_owner(other.p_rcmessage_owner) - , p_rcmessage(other.p_rcmessage) + : p_rcmessage(other.p_rcmessage) { p_rcmessage->get_reference_counter().increment_reference_count(); } @@ -89,15 +73,11 @@ namespace etl // Deal with the current message. if (p_rcmessage->get_reference_counter().decrement_reference_count() == 0U) { - if (p_rcmessage_owner != ETL_NULLPTR) - { - p_rcmessage_owner->release(p_rcmessage); - } + p_rcmessage->release(); } // Copy over the new one. - p_rcmessage_owner = other.p_rcmessage_owner; - p_rcmessage = other.p_rcmessage; + p_rcmessage = other.p_rcmessage; p_rcmessage->get_reference_counter().increment_reference_count(); } @@ -112,10 +92,7 @@ namespace etl { if (p_rcmessage->get_reference_counter().decrement_reference_count() == 0U) { - if (is_owned()) - { - p_rcmessage_owner->release(p_rcmessage); - } + p_rcmessage->release(); } } @@ -137,41 +114,34 @@ namespace etl private: - //************************************************************************* - /// Returns true if the internal reference counted message is owned by a pool. - //************************************************************************* - bool is_owned() const - { - return (p_rcmessage_owner != ETL_NULLPTR); - } - shared_message() ETL_DELETE; - etl::ireference_counted_message_pool* p_rcmessage_owner; - etl::ireference_counted_message* p_rcmessage; + etl::ireference_counted_message* p_rcmessage; }; //***************************************************************************** - /// A wrapper for reference counted messages. - /// Contains pointers to a pool owner and a message defined with a ref count type. + /// Make a shared_message from a pool. + /// \param owner The pool to allocate the reference counted message from. + /// \param message The message to reference count. //***************************************************************************** template etl::shared_message make_shared_message(TPool& owner, const TMessage& message) { etl::ireference_counted_message* p_rcmessage = owner.allocate(message); - return etl::shared_message(*p_rcmessage, owner); + return etl::shared_message(*p_rcmessage); } #if ETL_CPP11_SUPPORTED //***************************************************************************** - /// A wrapper for reference counted messages. - /// Contains pointers to a pool owner and a message defined with a ref count type. + /// Make a shared_message from a pool. + /// \param owner The pool to allocate the reference counted message from. + /// \param args The arguments to pass to the message constructor. //***************************************************************************** template etl::shared_message make_shared_message(TPool& owner, TArgs&&... args) { etl::ireference_counted_message* p_rcmessage = owner.allocate(etl::forward(args)...); - return etl::shared_message(*p_rcmessage, owner); + return etl::shared_message(*p_rcmessage); } #endif } From 6e71e05877e3189abc9c3e6dc97d7f3af2de61bb Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 3 Jan 2021 20:11:16 +0000 Subject: [PATCH 14/18] Added fixed_sized_memory_block_pool and restored imemory_block_pool interface --- .gitignore | 2 + include/etl/atomic.h | 2 +- include/etl/file_error_numbers.txt | 2 + include/etl/fixed_sized_memory_block_pool.h | 65 +++++ include/etl/message_pool.h | 284 ------------------- include/etl/reference_counted_message_pool.h | 259 +++-------------- include/etl/shared_message.h | 3 +- test/vs2019/etl.vcxproj | 2 +- test/vs2019/etl.vcxproj.filters | 6 +- 9 files changed, 117 insertions(+), 508 deletions(-) create mode 100644 include/etl/fixed_sized_memory_block_pool.h delete mode 100644 include/etl/message_pool.h diff --git a/.gitignore b/.gitignore index edea7414..7060c8fc 100644 --- a/.gitignore +++ b/.gitignore @@ -252,3 +252,5 @@ cmake-build-*/ unittest-cpp *.opendb build-test-Desktop_x86_windows_msvc2017_pe_32bit-Debug +*.db-shm +test/vs2019/.vs/etl/v16/Browse.VC.db-wal diff --git a/include/etl/atomic.h b/include/etl/atomic.h index f77049b8..35b7e82e 100644 --- a/include/etl/atomic.h +++ b/include/etl/atomic.h @@ -45,7 +45,7 @@ SOFTWARE. #define ETL_HAS_ATOMIC 1 #else #define ETL_HAS_ATOMIC 0 - #pragma message "ETL atomics not supported" + #pragma message ("ETL atomics not supported") #endif #endif diff --git a/include/etl/file_error_numbers.txt b/include/etl/file_error_numbers.txt index 89cfc5e1..31eb6ffd 100644 --- a/include/etl/file_error_numbers.txt +++ b/include/etl/file_error_numbers.txt @@ -53,3 +53,5 @@ 53 indirect_vector 54 queue_spsc_locked 55 message_packet +56 multi_range +57 reference_counted_message_pool diff --git a/include/etl/fixed_sized_memory_block_pool.h b/include/etl/fixed_sized_memory_block_pool.h new file mode 100644 index 00000000..6e35e5f6 --- /dev/null +++ b/include/etl/fixed_sized_memory_block_pool.h @@ -0,0 +1,65 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2017 jwellbelove + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files(the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions : + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +******************************************************************************/ + +#ifndef ETL_FIXED_MEMORY_BLOCK_POOL_INCLUDED +#define ETL_FIXED_MEMORY_BLOCK_POOL_INCLUDED + +#include "platform.h" +#include "memory.h" +#include "pool.h" +#include "alignment.h" + +namespace etl +{ + //************************************************************************* + /// The fixed sized memory block pool. + /// The allocated memory blocks are all the same size. + //************************************************************************* + template + struct fixed_sized_memory_block_pool : public etl::ipool + { + public: + + fixed_sized_memory_block_pool() + : ipool(buffer.get_address(), BLOCK_SIZE, SIZE) + { + } + + private: + + // No copying allowed. + fixed_sized_memory_block_pool(const etl::fixed_sized_memory_block_pool&) ETL_DELETE; + fixed_sized_memory_block_pool& operator =(const etl::fixed_sized_memory_block_pool&) ETL_DELETE; + + typename etl::aligned_storage::type buffer; + }; +} + +#endif diff --git a/include/etl/message_pool.h b/include/etl/message_pool.h deleted file mode 100644 index e27312fa..00000000 --- a/include/etl/message_pool.h +++ /dev/null @@ -1,284 +0,0 @@ -///\file - -/****************************************************************************** -The MIT License(MIT) - -Embedded Template Library. -https://github.com/ETLCPP/etl -https://www.etlcpp.com - -Copyright(c) 2020 jwellbelove - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -******************************************************************************/ - -#ifndef ETL_MESSAGE_POOL_INCLUDED -#define ETL_MESSAGE_POOL_INCLUDED - -#include "platform.h" -#include "message.h" -#include "static_assert.h" -#include "error_handler.h" -#include "utility.h" -#include "memory.h" - -#define ETL_FILE "99" - -namespace etl -{ - //*************************************************************************** - /// - //*************************************************************************** - class message_pool_allocation_exception : public etl::exception - { - public: - - message_pool_allocation_exception(string_type reason_, string_type file_name_, numeric_type line_number_) - : exception(reason_, file_name_, line_number_) - { - } - }; - - //*************************************************************************** - /// - //*************************************************************************** - class message_pool_allocation_failure : etl::message_pool_allocation_exception - { - public: - - message_pool_allocation_failure(string_type file_name_, numeric_type line_number_) - : message_pool_allocation_exception(ETL_ERROR_TEXT("message_pool:allocation failure", ETL_FILE"A"), file_name_, line_number_) - { - } - }; - - //*************************************************************************** - /// - //*************************************************************************** - class message_pool - { - public: - - //************************************************************************* - /// Constructor - //************************************************************************* - message_pool(imemory_block_pool& memory_block_pool_) - : memory_block_pool(memory_block_pool_) - { - } - -#if ETL_CPP11_SUPPORTED && !defined(ETL_MESSAGE_POOL_FORCE_CPP03) - //************************************************************************* - /// Create a message from the pool. - //************************************************************************* - template - TMessage* create(TArgs&&... args) - { - ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(etl::forward(args)...); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p); - } -#else - //************************************************************************* - /// Create a message from the pool. No parameters. - //************************************************************************* - template - TMessage* create() - { - ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p); - } - - //************************************************************************* - /// Create a message from the pool. One parameter. - //************************************************************************* - template - TMessage* create(const T1& t1) - { - ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(t1); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p); - } - - //************************************************************************* - /// Create a message from the pool. Two parameters. - //************************************************************************* - template - TMessage* create(const T1& t1, const T2& t2) - { - ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(t1, t2); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p); - } - - //************************************************************************* - /// Create a message from the pool. Three parameters. - //************************************************************************* - template - TMessage* create(const T1& t1, const T2& t2, const T3& t3) - { - ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(t1, t2, t3); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p); - } - - //************************************************************************* - /// Create a message from the pool. Four parameters. - //************************************************************************* - template - TMessage* create(const T1& t1, const T2& t2, const T3& t3, const T4& t4) - { - ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(t1, t2, t3, t4); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p) - } -#endif - - //************************************************************************* - /// Destruct a message and send it back to the pool. - //************************************************************************* - void destroy(const etl::imessage* const pmsg) - { - if (pmsg != ETL_NULLPTR) - { - pmsg->~imessage(); - memory_block_pool.release_memory_block(pmsg); - } - } - - //************************************************************************* - /// Destruct a message and send it back to the pool. - //************************************************************************* - void destroy(const etl::imessage& msg) - { - destroy(&msg); - } - - private: - - /// The raw memory block pool. - imemory_block_pool& memory_block_pool; - - // Should not be copied. - message_pool(const message_pool&) ETL_DELETE; - message_pool& operator =(const message_pool&) ETL_DELETE; - }; -} - -#undef ETL_FILE - -#endif - diff --git a/include/etl/reference_counted_message_pool.h b/include/etl/reference_counted_message_pool.h index 95287774..c5b2acc8 100644 --- a/include/etl/reference_counted_message_pool.h +++ b/include/etl/reference_counted_message_pool.h @@ -40,37 +40,35 @@ SOFTWARE. #include "utility.h" #include "memory.h" -#include - -#define ETL_FILE "99" +#define ETL_FILE "57" namespace etl { - ////*************************************************************************** - ///// - ////*************************************************************************** - //class message_pool_allocation_exception : public etl::exception - //{ - //public: + //*************************************************************************** + /// + //*************************************************************************** + class reference_counted_message_pool_allocation_exception : public etl::exception + { + public: - // message_pool_allocation_exception(string_type reason_, string_type file_name_, numeric_type line_number_) - // : exception(reason_, file_name_, line_number_) - // { - // } - //}; + reference_counted_message_pool_allocation_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; - ////*************************************************************************** - ///// - ////*************************************************************************** - //class message_pool_allocation_failure : etl::message_pool_allocation_exception - //{ - //public: + //*************************************************************************** + /// + //*************************************************************************** + class reference_counted_message_pool_allocation_failure : etl::reference_counted_message_pool_allocation_exception + { + public: - // message_pool_allocation_failure(string_type file_name_, numeric_type line_number_) - // : message_pool_allocation_exception(ETL_ERROR_TEXT("message_pool:allocation failure", ETL_FILE"A"), file_name_, line_number_) - // { - // } - //}; + reference_counted_message_pool_allocation_failure(string_type file_name_, numeric_type line_number_) + : reference_counted_message_pool_allocation_exception(ETL_ERROR_TEXT("reference_counted_message_pool:allocation failure", ETL_FILE"A"), file_name_, line_number_) + { + } + }; //*************************************************************************** /// A pool for allocating reference counted messages. @@ -83,12 +81,8 @@ namespace etl //************************************************************************* /// Constructor //************************************************************************* - //reference_counted_message_pool(imemory_block_pool& memory_block_pool_) - // : memory_block_pool(memory_block_pool_) - //{ - //} - - reference_counted_message_pool() + reference_counted_message_pool(imemory_block_pool& memory_block_pool_) + : memory_block_pool(memory_block_pool_) { } @@ -100,195 +94,26 @@ namespace etl { ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); - using ref_message_t = etl::reference_counted_message; + typedef etl::reference_counted_message rcm_t; + typedef rcm_t* prcm_t; - etl::ireference_counted_message* p = ETL_NULLPTR; + prcm_t p = ETL_NULLPTR; - //if (sizeof(ref_message_t) <= memory_block_pool.get_memory_block_size(ref_message_t)) - //{ - // p = memory_block_pool.allocate_memory_block(sizeof(ref_message_t)); + if (sizeof(rcm_t) <= memory_block_pool.get_memory_block_size()) + { + p = static_cast(memory_block_pool.allocate_memory_block(sizeof(rcm_t))); - // if (p != ETL_NULLPTR) - // { - // ::new(p) ref_message_t(TMessage(etl::forward(args)...)); - p = ::new ref_message_t(message, *this); - // } - // else - // { - // ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - // } - //} + if (p != ETL_NULLPTR) + { + ::new(p) rcm_t(message, *this); + } + } + + ETL_ASSERT((p != ETL_NULLPTR), ETL_ERROR(etl::message_pool_allocation_failure)); return p; } -#if ETL_CPP11_SUPPORTED && !defined(ETL_REFERENCE_COUNTED_MESSAGE_POOL_FORCE_CPP03) - //************************************************************************* - /// Allocate a reference counted message from the pool. - //************************************************************************* - template - etl::ireference_counted_message* allocate(TArgs&&... args) - { - ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); - - using ref_message_t = etl::reference_counted_message; - - etl::ireference_counted_message* p = ETL_NULLPTR; - - //if (sizeof(ref_message_t) <= memory_block_pool.get_memory_block_size(ref_message_t)) - //{ - // p = memory_block_pool.allocate_memory_block(sizeof(ref_message_t)); - - // if (p != ETL_NULLPTR) - // { - // ::new(p) ref_message_t(TMessage(etl::forward(args)...)); - p = ::new ref_message_t(TMessage(etl::forward(args)...), *this); - // } - // else - // { - // ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - // } - //} - - return p; - } -#else - //************************************************************************* - /// Allocate a reference counted message from the pool. No parameters. - //************************************************************************* - template - TMessage* allocate() - { - ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p); - } - - //************************************************************************* - /// Allocate a reference counted message from the pool. One parameter. - //************************************************************************* - template - TMessage* allocate(const T1& t1) - { - ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(t1); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p); - } - - //************************************************************************* - /// Allocate a reference counted message from the pool. Two parameters. - //************************************************************************* - template - TMessage* allocate(const T1& t1, const T2& t2) - { - ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(t1, t2); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p); - } - - //************************************************************************* - /// Allocate a reference counted message from the pool. Three parameters. - //************************************************************************* - template - TMessage* allocate(const T1& t1, const T2& t2, const T3& t3) - { - ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(t1, t2, t3); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p); - } - - //************************************************************************* - /// Allocate a reference counted message from the pool. Four parameters. - //************************************************************************* - template - TMessage* allocate(const T1& t1, const T2& t2, const T3& t3, const T4& t4) - { - ETL_STATIC_ASSERT(etl::is_base_of::value, "Not a message type"); - - void* p = ETL_NULLPTR; - - if (sizeof(TMessage) <= memory_block_pool.get_memory_block_size()) - { - p = memory_block_pool.allocate_memory_block(sizeof(TMessage)); - - if (p != ETL_NULLPTR) - { - ::new(p) TMessage(t1, t2, t3, t4); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(etl::message_pool_allocation_failure)); - } - } - - return reinterpret_cast(p) - } -#endif - //************************************************************************* /// Destruct a message and send it back to the pool. //************************************************************************* @@ -296,9 +121,8 @@ namespace etl { if (p_rcmessage != ETL_NULLPTR) { -// p_rcmessage->~ireference_counted_message(); - delete p_rcmessage; - //memory_block_pool.release_memory_block(p_rcmessage); + p_rcmessage->~ireference_counted_message(); + memory_block_pool.release_memory_block(p_rcmessage); } } @@ -313,7 +137,7 @@ namespace etl private: /// The raw memory block pool. - //imemory_block_pool& memory_block_pool; + imemory_block_pool& memory_block_pool; // Should not be copied. reference_counted_message_pool(const reference_counted_message_pool&) ETL_DELETE; @@ -324,4 +148,3 @@ namespace etl #undef ETL_FILE #endif - diff --git a/include/etl/shared_message.h b/include/etl/shared_message.h index 61f68e4a..82b29b87 100644 --- a/include/etl/shared_message.h +++ b/include/etl/shared_message.h @@ -32,6 +32,7 @@ SOFTWARE. #define ETL_SHARED_MESSAGE_INCLUDED #include "platform.h" +#include "utility.h" #include "reference_counted_message.h" //***************************************************************************** @@ -140,7 +141,7 @@ namespace etl template etl::shared_message make_shared_message(TPool& owner, TArgs&&... args) { - etl::ireference_counted_message* p_rcmessage = owner.allocate(etl::forward(args)...); + etl::ireference_counted_message* p_rcmessage = owner.allocate(TMessage(etl::forward(args)...)); return etl::shared_message(*p_rcmessage); } #endif diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 3966d4fa..5aed148d 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1051,6 +1051,7 @@ + @@ -1591,7 +1592,6 @@ - diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index db18e69c..ffcccca8 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -867,6 +867,9 @@ ETL\Frameworks + + ETL\Utilities + @@ -1328,9 +1331,6 @@ Source Files - - Source Files - From fc4802184982eff28daa77e481c8ebb83a7c3f87 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 3 Jan 2021 20:24:38 +0000 Subject: [PATCH 15/18] message router changes --- include/etl/fsm.h | 20 ------------------- .../etl/generators/message_router_generator.h | 15 +++++++------- include/etl/message_bus.h | 7 ------- include/etl/message_router.h | 17 ++++++++-------- 4 files changed, 16 insertions(+), 43 deletions(-) diff --git a/include/etl/fsm.h b/include/etl/fsm.h index cfde1a2b..6347bd74 100644 --- a/include/etl/fsm.h +++ b/include/etl/fsm.h @@ -266,26 +266,6 @@ namespace etl } } - //******************************************* - /// Top level message handler for the FSM. - //******************************************* - void receive(const etl::imessage& message) ETL_OVERRIDE - { - static etl::null_message_router nmr; - receive(nmr, message); - } - - //******************************************* - /// Top level message handler for the FSM. - //******************************************* - void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) ETL_OVERRIDE - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, message); - } - } - //******************************************* /// Top level message handler for the FSM. //******************************************* diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index 0ccd0bf7..1a5a059e 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -129,14 +129,7 @@ namespace etl virtual bool is_producer() const = 0; virtual bool is_consumer() const = 0; - //******************************************** - void receive(const etl::imessage& message) - { - receive(etl::get_null_message_router(), message); - } - - //******************************************** - void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) + virtual void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) { if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) { @@ -144,6 +137,12 @@ namespace etl } } + //******************************************** + void receive(const etl::imessage& message) + { + receive(etl::get_null_message_router(), message); + } + //******************************************** virtual void receive(imessage_router& source, etl::shared_message shared_msg) { diff --git a/include/etl/message_bus.h b/include/etl/message_bus.h index 048ecc7e..6254b702 100644 --- a/include/etl/message_bus.h +++ b/include/etl/message_bus.h @@ -147,13 +147,6 @@ namespace etl } } - //******************************************* - void receive(const etl::imessage& message) ETL_OVERRIDE - { - etl::null_message_router nmr; - receive(nmr, etl::imessage_router::ALL_MESSAGE_ROUTERS, message); - } - //******************************************* void receive(etl::message_router_id_t destination_router_id, const etl::imessage& message) diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 2790794e..1d379c32 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -118,20 +118,21 @@ namespace etl virtual bool is_consumer() const = 0; //******************************************** - void receive(const etl::imessage& message) - { - receive(etl::get_null_message_router(), message); - } - - //******************************************** - void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) + virtual void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) { if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) { receive(source, message); } } - + + //******************************************** + void receive(const etl::imessage& message) + { + receive(etl::get_null_message_router(), message); + } + + //******************************************** virtual void receive(imessage_router& source, etl::shared_message shared_msg) { From 3e8c2ca44807479bbd0bcf0e8cd7aa4473336424 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 4 Jan 2021 11:21:57 +0000 Subject: [PATCH 16/18] Fixed LGT8F macro name clash --- include/etl/memory.h | 20 ++++++++++---------- include/etl/multi_array.h | 18 +++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/etl/memory.h b/include/etl/memory.h index 5bccbe87..aa78e8e7 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -1509,36 +1509,36 @@ namespace etl //***************************************************************************** // Global functions for unique_ptr //***************************************************************************** -template -bool operator ==(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) +template +bool operator ==(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) { return lhs.get() == rhs.get(); } //********************************* -template -bool operator <(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) +template +bool operator <(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) { return reinterpret_cast(lhs.get()) < reinterpret_cast(rhs.get()); } //********************************* -template -bool operator <=(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) +template +bool operator <=(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) { return !(rhs < lhs); } //********************************* -template -bool operator >(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) +template +bool operator >(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) { return (rhs < lhs); } //********************************* -template -bool operator >=(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) +template +bool operator >=(const etl::unique_ptr&lhs, const etl::unique_ptr& rhs) { return !(lhs < rhs); } diff --git a/include/etl/multi_array.h b/include/etl/multi_array.h index 0c1f9f06..cc0d84be 100644 --- a/include/etl/multi_array.h +++ b/include/etl/multi_array.h @@ -44,23 +44,23 @@ namespace etl namespace private_multi_array { - template + template struct multi_array_t { - using type = etl::array::type, D1>; - static constexpr size_t SIZE = D1; + using type = etl::array::type, TD1>; + static constexpr size_t SIZE = TD1; }; - template - struct multi_array_t + template + struct multi_array_t { - using type = etl::array; - static constexpr size_t SIZE = D1; + using type = etl::array; + static constexpr size_t SIZE = TD1; }; } - template - using multi_array = typename private_multi_array::multi_array_t::type; + template + using multi_array = typename private_multi_array::multi_array_t::type; #endif } From f02a99cc0ed3d9ade180226e55798410782e2df5 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 4 Jan 2021 12:21:40 +0000 Subject: [PATCH 17/18] Updated generators --- include/etl/generators/fsm_generator.h | 30 +++-------- .../etl/generators/message_router_generator.h | 36 +++++++------ include/etl/generators/smallest_generator.h | 6 +-- include/etl/message_router.h | 54 ++++++++++--------- include/etl/smallest.h | 6 +-- 5 files changed, 62 insertions(+), 70 deletions(-) diff --git a/include/etl/generators/fsm_generator.h b/include/etl/generators/fsm_generator.h index 4d590025..c01fe39d 100644 --- a/include/etl/generators/fsm_generator.h +++ b/include/etl/generators/fsm_generator.h @@ -223,8 +223,10 @@ namespace etl /// Constructor. //******************************************* fsm(etl::message_router_id_t id) - : imessage_router(id), - p_state(ETL_NULLPTR) + : imessage_router(id) + , p_state(ETL_NULLPTR) + , state_list(ETL_NULLPTR) + , number_of_states(0U) { } @@ -279,27 +281,7 @@ namespace etl //******************************************* /// Top level message handler for the FSM. //******************************************* - void receive(const etl::imessage& message) - { - static etl::null_message_router nmr; - receive(nmr, message); - } - - //******************************************* - /// Top level message handler for the FSM. - //******************************************* - void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) - { - if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) - { - receive(source, message); - } - } - - //******************************************* - /// Top level message handler for the FSM. - //******************************************* - void receive(etl::imessage_router& source, const etl::imessage& message) + void receive(etl::imessage_router& source, const etl::imessage& message) ETL_OVERRIDE { etl::fsm_state_id_t next_state_id = p_state->process_event(source, message); ETL_ASSERT(next_state_id < number_of_states, ETL_ERROR(etl::fsm_state_id_exception)); @@ -329,7 +311,7 @@ namespace etl /// Does this FSM accept the message id? /// Yes, it accepts everything! //******************************************* - bool accepts(etl::message_id_t) const + bool accepts(etl::message_id_t) const ETL_OVERRIDE { return true; } diff --git a/include/etl/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index 1a5a059e..de69c429 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -197,23 +197,23 @@ namespace etl enum { NULL_MESSAGE_ROUTER = 255, - MESSAGE_BUS = 254, + MESSAGE_BUS = 254, ALL_MESSAGE_ROUTERS = 253, - MAX_MESSAGE_ROUTER = 249 + MAX_MESSAGE_ROUTER = 249 }; protected: imessage_router(etl::message_router_id_t id_) - : successor(ETL_NULLPTR), - message_router_id(id_) + : successor(ETL_NULLPTR) + , message_router_id(id_) { } imessage_router(etl::message_router_id_t id_, imessage_router& successor_) - : successor(&successor_), - message_router_id(id_) + : successor(&successor_) + , message_router_id(id_) { } @@ -240,14 +240,16 @@ namespace etl { } - using imessage_router::receive; - //******************************************** + using etl::imessage_router::receive; + void receive(etl::imessage_router&, const etl::imessage&) ETL_OVERRIDE { } //******************************************** + using etl::imessage_router::accepts; + bool accepts(etl::message_id_t) const ETL_OVERRIDE { return false; @@ -298,14 +300,16 @@ namespace etl { } - using imessage_router::receive; - //******************************************** + using etl::imessage_router::receive; + void receive(etl::imessage_router&, const etl::imessage&) ETL_OVERRIDE { } //******************************************** + using etl::imessage_router::accepts; + bool accepts(etl::message_id_t) const ETL_OVERRIDE { return false; @@ -390,9 +394,9 @@ namespace etl cog.outl(" ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") cog.outl(" }") cog.outl("") - cog.outl(" using imessage_router::receive;") - cog.outl("") cog.outl(" //**********************************************") + cog.outl(" using etl::imessage_router::receive;") + cog.outl("") cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE") cog.outl(" {") cog.outl(" const etl::message_id_t id = msg.get_message_id();") @@ -418,9 +422,9 @@ namespace etl cog.outl(" }") cog.outl(" }") cog.outl("") + cog.outl(" //**********************************************") cog.outl(" using imessage_router::accepts;") cog.outl("") - cog.outl(" //**********************************************") cog.outl(" bool accepts(etl::message_id_t id) const ETL_OVERRIDE") cog.outl(" {") cog.outl(" switch (id)") @@ -510,9 +514,9 @@ namespace etl cog.outl(" ETL_ASSERT(id_ <= etl::imessage_router::MAX_MESSAGE_ROUTER, ETL_ERROR(etl::message_router_illegal_id));") cog.outl(" }") cog.outl("") - cog.outl(" using imessage_router::receive;") - cog.outl("") cog.outl(" //**********************************************") + cog.outl(" using etl::imessage_router::receive;") + cog.outl("") cog.outl(" void receive(etl::imessage_router& source, const etl::imessage& msg) ETL_OVERRIDE") cog.outl(" {") cog.outl(" const size_t id = msg.get_message_id();") @@ -538,9 +542,9 @@ namespace etl cog.outl(" }") cog.outl(" }") cog.outl("") + cog.outl(" //**********************************************") cog.outl(" using imessage_router::accepts;") cog.outl("") - cog.outl(" //**********************************************") cog.outl(" bool accepts(etl::message_id_t id) const ETL_OVERRIDE") cog.outl(" {") cog.outl(" switch (id)") diff --git a/include/etl/generators/smallest_generator.h b/include/etl/generators/smallest_generator.h index 6290b65d..db07270a 100644 --- a/include/etl/generators/smallest_generator.h +++ b/include/etl/generators/smallest_generator.h @@ -372,9 +372,9 @@ namespace etl private: // Determines the index of the best signed type for the required value. - static const int TYPE_INDEX = (((VALUE > INT_LEAST8_MAX) || (VALUE < INT_LEAST8_MIN)) ? 1 : 0) + - (((VALUE > INT16_MAX) || (VALUE < INT16_MIN)) ? 1 : 0) + - (((VALUE > INT32_MAX) || (VALUE < INT32_MIN)) ? 1 : 0); + static const int TYPE_INDEX = (((VALUE > intmax_t(INT_LEAST8_MAX)) || (VALUE < intmax_t(INT_LEAST8_MIN))) ? 1 : 0) + + (((VALUE > intmax_t(INT16_MAX)) || (VALUE < intmax_t(INT16_MIN))) ? 1 : 0) + + (((VALUE > intmax_t(INT32_MAX)) || (VALUE < intmax_t(INT32_MIN))) ? 1 : 0); public: diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 1d379c32..e26463e6 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -100,7 +100,7 @@ namespace etl /// Forward declare null message router functionality. //*************************************************************************** class imessage_router; - + etl::imessage_router& get_null_message_router(); //*************************************************************************** @@ -117,7 +117,6 @@ namespace etl virtual bool is_producer() const = 0; virtual bool is_consumer() const = 0; - //******************************************** virtual void receive(imessage_router& source, etl::message_router_id_t destination_router_id, const etl::imessage& message) { if ((destination_router_id == get_message_router_id()) || (destination_router_id == imessage_router::ALL_MESSAGE_ROUTERS)) @@ -132,7 +131,6 @@ namespace etl receive(etl::get_null_message_router(), message); } - //******************************************** virtual void receive(imessage_router& source, etl::shared_message shared_msg) { @@ -195,15 +193,15 @@ namespace etl protected: imessage_router(etl::message_router_id_t id_) - : successor(ETL_NULLPTR), - message_router_id(id_) + : successor(ETL_NULLPTR) + , message_router_id(id_) { } imessage_router(etl::message_router_id_t id_, - imessage_router& successor_) - : successor(&successor_), - message_router_id(id_) + imessage_router& successor_) + : successor(&successor_) + , message_router_id(id_) { } @@ -231,11 +229,15 @@ namespace etl } //******************************************** + using etl::imessage_router::receive; + void receive(etl::imessage_router&, const etl::imessage&) ETL_OVERRIDE { } //******************************************** + using etl::imessage_router::accepts; + bool accepts(etl::message_id_t) const ETL_OVERRIDE { return false; @@ -287,11 +289,15 @@ namespace etl } //******************************************** + using etl::imessage_router::receive; + void receive(etl::imessage_router&, const etl::imessage&) ETL_OVERRIDE { } //******************************************** + using etl::imessage_router::accepts; + bool accepts(etl::message_id_t) const ETL_OVERRIDE { return false; @@ -403,9 +409,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -505,9 +511,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -606,9 +612,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -706,9 +712,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -804,9 +810,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -901,9 +907,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -997,9 +1003,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -1092,9 +1098,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -1185,9 +1191,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -1277,9 +1283,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -1367,9 +1373,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -1456,9 +1462,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -1543,9 +1549,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -1629,9 +1635,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -1714,9 +1720,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) @@ -1798,9 +1804,9 @@ namespace etl } } + //********************************************** using imessage_router::accepts; - //********************************************** bool accepts(etl::message_id_t id) const ETL_OVERRIDE { switch (id) diff --git a/include/etl/smallest.h b/include/etl/smallest.h index 92f34a80..ca446781 100644 --- a/include/etl/smallest.h +++ b/include/etl/smallest.h @@ -342,9 +342,9 @@ namespace etl private: // Determines the index of the best signed type for the required value. - static const int TYPE_INDEX = (((VALUE > intmax_t(INT_LEAST8_MAX)) || (VALUE < intmax_t(INT_LEAST8_MIN))) ? 1 : 0) + - (((VALUE > intmax_t(INT16_MAX)) || (VALUE < intmax_t(INT16_MIN))) ? 1 : 0) + - (((VALUE > intmax_t(INT32_MAX)) || (VALUE < intmax_t(INT32_MIN))) ? 1 : 0); + static const int TYPE_INDEX = (((VALUE > intmax_t(INT_LEAST8_MAX)) || (VALUE < intmax_t(INT_LEAST8_MIN))) ? 1 : 0) + + (((VALUE > intmax_t(INT16_MAX)) || (VALUE < intmax_t(INT16_MIN))) ? 1 : 0) + + (((VALUE > intmax_t(INT32_MAX)) || (VALUE < intmax_t(INT32_MIN))) ? 1 : 0); public: From 5a274578bb1ddbd0886070e9ddd5b5451b667757 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Mon, 4 Jan 2021 12:40:43 +0000 Subject: [PATCH 18/18] Updated deque from development --- include/etl/deque.h | 238 +++++++++++++++++++++++++++++--------------- 1 file changed, 155 insertions(+), 83 deletions(-) diff --git a/include/etl/deque.h b/include/etl/deque.h index ed64b7e8..5525c105 100644 --- a/include/etl/deque.h +++ b/include/etl/deque.h @@ -34,17 +34,11 @@ SOFTWARE. #include #include -#include - #include "platform.h" - #include "algorithm.h" #include "iterator.h" #include "utility.h" - #include "container.h" -#include "alignment.h" -#include "array.h" #include "memory.h" #include "exception.h" #include "error_handler.h" @@ -52,9 +46,10 @@ SOFTWARE. #include "algorithm.h" #include "type_traits.h" #include "iterator.h" +#include "placement_new.h" -#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) - #include +#if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL +#include #endif #include "private/minmax_push.h" @@ -186,6 +181,15 @@ namespace etl return CAPACITY; } + //************************************************************************* + /// Returns the maximum possible size of the deque. + ///\return The maximum size of the deque. + //************************************************************************* + size_type capacity() const + { + return CAPACITY; + } + //************************************************************************* /// Returns the remaining capacity. ///\return The remaining capacity. @@ -202,8 +206,8 @@ namespace etl //************************************************************************* deque_base(size_t max_size_, size_t buffer_size_) : current_size(0), - CAPACITY(max_size_), - BUFFER_SIZE(buffer_size_) + CAPACITY(max_size_), + BUFFER_SIZE(buffer_size_) { } @@ -232,12 +236,12 @@ namespace etl typedef T value_type; typedef size_t size_type; - typedef T& reference; + typedef T& reference; typedef const T& const_reference; #if ETL_CPP11_SUPPORTED - typedef T&& rvalue_reference; + typedef T&& rvalue_reference; #endif - typedef T* pointer; + typedef T* pointer; typedef const T* const_pointer; typedef typename etl::iterator_traits::difference_type difference_type; @@ -280,8 +284,8 @@ namespace etl //*************************************************** iterator& operator =(const iterator& other) { - index = other.index; - p_deque = other.p_deque; + index = other.index; + p_deque = other.p_deque; p_buffer = other.p_buffer; return *this; @@ -377,12 +381,6 @@ namespace etl return &p_buffer[index]; } - //*************************************************** - bool operator <(const iterator& other) const - { - return ideque::distance(*this, other) > 0; - } - //*************************************************** friend iterator operator +(const iterator& lhs, difference_type offset) { @@ -411,6 +409,38 @@ namespace etl return !(lhs == rhs); } + //*************************************************** + friend bool operator < (const iterator& lhs, const iterator& rhs) + { + const difference_type lhs_index = lhs.get_index(); + const difference_type rhs_index = rhs.get_index(); + const difference_type reference_index = lhs.container().begin().get_index(); + const size_t buffer_size = lhs.container().max_size() + 1; + + const difference_type lhs_distance = (lhs_index < reference_index) ? buffer_size + lhs_index - reference_index : lhs_index - reference_index; + const difference_type rhs_distance = (rhs_index < reference_index) ? buffer_size + rhs_index - reference_index : rhs_index - reference_index; + + return lhs_distance < rhs_distance; + } + + //*************************************************** + friend bool operator <= (const iterator& lhs, const iterator& rhs) + { + return !(lhs > rhs); + } + + //*************************************************** + friend bool operator > (const iterator& lhs, const iterator& rhs) + { + return (rhs < lhs); + } + + //*************************************************** + friend bool operator >= (const iterator& lhs, const iterator& rhs) + { + return !(lhs < rhs); + } + //*************************************************** difference_type get_index() const { @@ -418,7 +448,7 @@ namespace etl } //*************************************************** - ideque& get_deque() const + ideque& container() const { return *p_deque; } @@ -439,6 +469,19 @@ namespace etl private: + //*************************************************** + difference_type distance(difference_type firstIndex, difference_type index_) const + { + if (index_ < firstIndex) + { + return p_deque->BUFFER_SIZE + index_ - firstIndex; + } + else + { + return index_ - firstIndex; + } + } + //*************************************************** iterator(difference_type index_, ideque& the_deque, pointer p_buffer_) : index(index_) @@ -448,7 +491,7 @@ namespace etl } difference_type index; - ideque* p_deque; + ideque* p_deque; pointer p_buffer; }; @@ -486,8 +529,8 @@ namespace etl //*************************************************** const_iterator& operator =(const const_iterator& other) { - index = other.index; - p_deque = other.p_deque; + index = other.index; + p_deque = other.p_deque; p_buffer = other.p_buffer; return *this; @@ -495,8 +538,8 @@ namespace etl const_iterator& operator =(const typename ideque::iterator& other) { - index = other.index; - p_deque = other.p_deque; + index = other.index; + p_deque = other.p_deque; p_buffer = other.p_buffer; return *this; @@ -580,11 +623,7 @@ namespace etl return &p_buffer[index]; } - //*************************************************** - bool operator <(const const_iterator& other) const - { - return ideque::distance(*this, other) > 0; - } + //*************************************************** friend const_iterator operator +(const const_iterator& lhs, difference_type offset) @@ -614,6 +653,38 @@ namespace etl return !(lhs == rhs); } + //*************************************************** + friend bool operator < (const const_iterator& lhs, const const_iterator& rhs) + { + const difference_type lhs_index = lhs.get_index(); + const difference_type rhs_index = rhs.get_index(); + const difference_type reference_index = lhs.container().begin().get_index(); + const size_t buffer_size = lhs.container().max_size() + 1; + + const difference_type lhs_distance = (lhs_index < reference_index) ? buffer_size + lhs_index - reference_index : lhs_index - reference_index; + const difference_type rhs_distance = (rhs_index < reference_index) ? buffer_size + rhs_index - reference_index : rhs_index - reference_index; + + return lhs_distance < rhs_distance; + } + + //*************************************************** + friend bool operator <= (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs > rhs); + } + + //*************************************************** + friend bool operator > (const const_iterator& lhs, const const_iterator& rhs) + { + return (rhs < lhs); + } + + //*************************************************** + friend bool operator >= (const const_iterator& lhs, const const_iterator& rhs) + { + return !(lhs < rhs); + } + //*************************************************** difference_type get_index() const { @@ -621,7 +692,7 @@ namespace etl } //*************************************************** - ideque& get_deque() const + ideque& container() const { return *p_deque; } @@ -641,7 +712,7 @@ namespace etl private: //*************************************************** - difference_type distance(difference_type firstIndex, difference_type index_) + difference_type distance(difference_type firstIndex, difference_type index_) const { if (index_ < firstIndex) { @@ -662,7 +733,7 @@ namespace etl } difference_type index; - ideque* p_deque; + ideque* p_deque; pointer p_buffer; }; @@ -696,9 +767,6 @@ namespace etl initialise(); - _begin.index = 0; - _end.index = 0; - while (n > 0) { create_element_back(value); @@ -1011,7 +1079,7 @@ namespace etl /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is full. ///\param insert_position>The insert position. //************************************************************************* -#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) +#if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT template iterator emplace(const_iterator insert_position, Args && ... args) { @@ -1027,7 +1095,7 @@ namespace etl p = etl::addressof(*_begin); ++current_size; ETL_INCREMENT_DEBUG_COUNT - position = _begin; + position = _begin; } else if (insert_position == end()) { @@ -1035,7 +1103,7 @@ namespace etl ++_end; ++current_size; ETL_INCREMENT_DEBUG_COUNT - position = _end - 1; + position = _end - 1; } else { @@ -1094,7 +1162,7 @@ namespace etl p = etl::addressof(*_begin); ++current_size; ETL_INCREMENT_DEBUG_COUNT - position = _begin; + position = _begin; } else if (insert_position == end()) { @@ -1102,7 +1170,7 @@ namespace etl ++_end; ++current_size; ETL_INCREMENT_DEBUG_COUNT - position = _end - 1; + position = _end - 1; } else { @@ -1159,7 +1227,7 @@ namespace etl p = etl::addressof(*_begin); ++current_size; ETL_INCREMENT_DEBUG_COUNT - position = _begin; + position = _begin; } else if (insert_position == end()) { @@ -1167,7 +1235,7 @@ namespace etl ++_end; ++current_size; ETL_INCREMENT_DEBUG_COUNT - position = _end - 1; + position = _end - 1; } else { @@ -1224,7 +1292,7 @@ namespace etl p = etl::addressof(*_begin); ++current_size; ETL_INCREMENT_DEBUG_COUNT - position = _begin; + position = _begin; } else if (insert_position == end()) { @@ -1232,7 +1300,7 @@ namespace etl ++_end; ++current_size; ETL_INCREMENT_DEBUG_COUNT - position = _end - 1; + position = _end - 1; } else { @@ -1289,7 +1357,7 @@ namespace etl p = etl::addressof(*_begin); ++current_size; ETL_INCREMENT_DEBUG_COUNT - position = _begin; + position = _begin; } else if (insert_position == end()) { @@ -1297,7 +1365,7 @@ namespace etl ++_end; ++current_size; ETL_INCREMENT_DEBUG_COUNT - position = _end - 1; + position = _end - 1; } else { @@ -1682,7 +1750,7 @@ namespace etl } #endif -#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) +#if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT //************************************************************************* /// Emplaces an item to the back of the deque. /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. @@ -1810,7 +1878,7 @@ namespace etl } #endif -#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) +#if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT //************************************************************************* /// Emplaces an item to the front of the deque. /// If asserts or exceptions are enabled, throws an etl::deque_full if the deque is already full. @@ -2022,7 +2090,7 @@ namespace etl //************************************************************************* ideque(pointer p_buffer_, size_t max_size_, size_t buffer_size_) : deque_base(max_size_, buffer_size_), - p_buffer(p_buffer_) + p_buffer(p_buffer_) { } @@ -2033,7 +2101,7 @@ namespace etl { if ETL_IF_CONSTEXPR(etl::is_trivially_destructible::value) { - current_size = 0; + current_size = 0; ETL_RESET_DEBUG_COUNT } else @@ -2045,7 +2113,7 @@ namespace etl } _begin = iterator(0, *this, p_buffer); - _end = iterator(0, *this, p_buffer); + _end = iterator(0, *this, p_buffer); } //************************************************************************* @@ -2056,7 +2124,7 @@ namespace etl p_buffer = p_buffer_; _begin = iterator(_begin.index, *this, p_buffer); - _end = iterator(_end.index, *this, p_buffer); + _end = iterator(_end.index, *this, p_buffer); } iterator _begin; ///Iterator to the _begin item in the deque. @@ -2087,12 +2155,7 @@ namespace etl return; } - if (!empty()) - { - --_begin; - } - - _begin -= n - 1; + _begin -= n; iterator item = _begin; @@ -2170,7 +2233,7 @@ namespace etl (*_begin).~T(); --current_size; ETL_DECREMENT_DEBUG_COUNT - ++_begin; + ++_begin; } //********************************************************************* @@ -2203,8 +2266,8 @@ namespace etl static difference_type distance(const TIterator& other) { const difference_type index = other.get_index(); - const difference_type reference_index = other.get_deque()._begin.index; - const size_t buffer_size = other.get_deque().BUFFER_SIZE; + const difference_type reference_index = other.container()._begin.index; + const size_t buffer_size = other.container().BUFFER_SIZE; if (index < reference_index) { @@ -2247,18 +2310,18 @@ namespace etl { public: - static const size_t MAX_SIZE = MAX_SIZE_; + static ETL_CONSTANT size_t MAX_SIZE = MAX_SIZE_; private: - static const size_t BUFFER_SIZE = MAX_SIZE + 1; + static ETL_CONSTANT size_t BUFFER_SIZE = MAX_SIZE + 1; public: typedef T value_type; - typedef T* pointer; + typedef T* pointer; typedef const T* const_pointer; - typedef T& reference; + typedef T& reference; typedef const T& const_reference; typedef size_t size_type; typedef typename etl::iterator_traits::difference_type difference_type; @@ -2267,7 +2330,7 @@ namespace etl /// Default constructor. //************************************************************************* deque() - : etl::ideque(reinterpret_cast(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + : etl::ideque(reinterpret_cast(buffer.raw), MAX_SIZE, BUFFER_SIZE) { this->initialise(); } @@ -2284,7 +2347,7 @@ namespace etl /// Copy constructor. //************************************************************************* deque(const deque& other) - : etl::ideque(reinterpret_cast(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + : etl::ideque(reinterpret_cast(buffer.raw), MAX_SIZE, BUFFER_SIZE) { if (this != &other) { @@ -2297,7 +2360,7 @@ namespace etl /// Move constructor. //************************************************************************* deque(deque&& other) - : etl::ideque(reinterpret_cast(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + : etl::ideque(reinterpret_cast(buffer.raw), MAX_SIZE, BUFFER_SIZE) { if (this != &other) { @@ -2318,7 +2381,7 @@ namespace etl //************************************************************************* template deque(TIterator begin_, TIterator end_) - : etl::ideque(reinterpret_cast(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + : etl::ideque(reinterpret_cast(buffer.raw), MAX_SIZE, BUFFER_SIZE) { this->assign(begin_, end_); } @@ -2327,17 +2390,17 @@ namespace etl /// Assigns data to the deque. //************************************************************************* explicit deque(size_t n, const_reference value = value_type()) - : etl::ideque(reinterpret_cast(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + : etl::ideque(reinterpret_cast(buffer.raw), MAX_SIZE, BUFFER_SIZE) { this->assign(n, value); } -#if ETL_CPP11_SUPPORTED && !defined(ETL_STLPORT) && !defined(ETL_NO_STL) +#if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL //************************************************************************* /// Construct from initializer_list. //************************************************************************* deque(std::initializer_list init) - : ideque(reinterpret_cast(&buffer[0]), MAX_SIZE, BUFFER_SIZE) + : ideque(reinterpret_cast(buffer.raw), MAX_SIZE, BUFFER_SIZE) { this->assign(init.begin(), init.end()); } @@ -2380,24 +2443,33 @@ namespace etl //************************************************************************* /// Fix the internal pointers after a low level memory copy. //************************************************************************* -#ifdef ETL_IDEQUE_REPAIR_ENABLE - virtual -#endif void repair() +#ifdef ETL_ISTRING_REPAIR_ENABLE + ETL_OVERRIDE +#endif { #if ETL_CPP11_TYPE_TRAITS_IS_TRIVIAL_SUPPORTED ETL_ASSERT(etl::is_trivially_copyable::value, ETL_ERROR(etl::deque_incompatible_type)); #endif - etl::ideque::repair_buffer(reinterpret_cast(&buffer[0])); + etl::ideque::repair_buffer(reinterpret_cast(buffer.raw)); } private: /// The uninitialised buffer of T used in the deque. - typename etl::aligned_storage::value>::type buffer[BUFFER_SIZE]; + etl::uninitialized_buffer_of buffer; }; + //************************************************************************* + /// Template deduction guides. + //************************************************************************* +#if ETL_CPP17_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL + template + deque(T, Ts...) + ->deque && ...), T>, 1U + sizeof...(Ts)>; +#endif + //*************************************************************************** /// Equal operator. ///\param lhs Reference to the _begin deque. @@ -2435,9 +2507,9 @@ namespace etl bool operator <(const etl::ideque& lhs, const etl::ideque& rhs) { return etl::lexicographical_compare(lhs.begin(), - lhs.end(), - rhs.begin(), - rhs.end()); + lhs.end(), + rhs.begin(), + rhs.end()); } //***************************************************************************