From 5abae28f1631fc5465412b1ca15eea5503ffa0b1 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Fri, 1 Jan 2021 17:07:53 +0000 Subject: [PATCH] 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; }; }