From 3c2cb745249d1946e6c80246cc3a8813ec12c40e Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 3 Jan 2021 12:18:34 +0000 Subject: [PATCH] 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 }