From db8841ff0d3e214b9db419645d913d0d583cd151 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Wed, 6 Jan 2021 17:56:24 +0000 Subject: [PATCH] Updates to pools and memory allocators --- include/etl/file_error_numbers.h | 93 +++ include/etl/file_error_numbers.txt | 57 -- .../etl/fixed_sized_memory_block_allocator.h | 113 ++++ include/etl/fixed_sized_memory_block_pool.h | 65 -- .../etl/generators/message_router_generator.h | 1 + include/etl/generic_pool.h | 76 ++- include/etl/ipool.h | 120 ++-- include/etl/ireference_counted_message_pool.h | 6 +- include/etl/list.h | 1 + include/etl/memory.h | 150 ++++- include/etl/message_bus.h | 78 ++- include/etl/message_router.h | 9 +- include/etl/platform.h | 2 + include/etl/pool.h | 573 +----------------- include/etl/reference_counted_message.h | 27 +- include/etl/reference_counted_message_pool.h | 122 +++- include/etl/reference_counted_object.h | 1 + include/etl/shared_message.h | 64 +- include/etl/variant_pool.h | 2 +- test/test_pool_message.cpp | 221 ------- test/test_shared_message.cpp | 197 ++++++ test/vs2019/etl.vcxproj | 7 +- test/vs2019/etl.vcxproj.filters | 33 +- 23 files changed, 854 insertions(+), 1164 deletions(-) create mode 100644 include/etl/file_error_numbers.h delete mode 100644 include/etl/file_error_numbers.txt create mode 100644 include/etl/fixed_sized_memory_block_allocator.h delete mode 100644 include/etl/fixed_sized_memory_block_pool.h delete mode 100644 test/test_pool_message.cpp create mode 100644 test/test_shared_message.cpp diff --git a/include/etl/file_error_numbers.h b/include/etl/file_error_numbers.h new file mode 100644 index 00000000..c7407c29 --- /dev/null +++ b/include/etl/file_error_numbers.h @@ -0,0 +1,93 @@ +///\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_FILE_ERROR_NUMBERS +#define ETL_FILE_ERROR_NUMBERS + +#define ETL_DEQUE_ID "1" +#define ETL_FLAT_MAP_ID "2" +#define ETL_FLAT_MULTIMAP_ID "3" +#define ETL_FLAT_MULTISET_ID "4" +#define ETL_FLAT_SET_ID "5" +#define ETL_FORWARD_LIST_ID "6" +#define ETL_LIST_ID "7" +#define ETL_MAP_ID "8" +#define ETL_MULTIMAP_ID "9" +#define ETL_MULTISET_ID "10" +#define ETL_POOL_ID "11" +#define ETL_PRIORITY_QUEUE_ID "12" +#define ETL_QUEUE_ID "13" +#define ETL_SET_ID "14" +#define ETL_STACK_ID "15" +#define ETL_UNORDERED_MAP_ID "16" +#define ETL_VECTOR_ID "17" +#define ETL_OBSERVER_ID "18" +#define ETL_IHASH_ID "19" +#define ETL_INTRUSIVE_FORWARD_LIST_ID "20" +#define ETL_INTRUSIVE_LIST_ID "21" +#define ETL_INTRUSIVE_LINKS_ID "22" +#define ETL_UNORDERED_SET_ID "23" +#define ETL_VARIANT_ID "24" +#define ETL_UNORDERED_MULTIMAP_ID "25" +#define ETL_UNORDERED_MULTISET_ID "26" +#define ETL_BASIC_STRING_ID "27" +#define ETL_INTRUSIVE_STACK_ID "28" +#define ETL_INTRUSIVE_QUEUE_ID "29" +#define ETL_REFERENCE_FLAT_MAP_ID "30" +#define ETL_REFERENCE_FLAT_MULTIMAP_ID "31" +#define ETL_REFERENCE_FLAT_SET_ID "32" +#define ETL_REFERENCE_FLAT_MULTISET_ID "33" +#define ETL_FSM_ID "34" +#define ETL_MESSAGE_ROUTER_ID "35" +#define ETL_SCHEDULER_ID "36" +#define ETL_TASK_ID "37" +#define ETL_MESSAGE_ID "38" +#define ETL_MESSAGE_BUS_ID "39" +#define ETL_VARIANT_POOL_ID "40" +#define ETL_ARRAY_VIEW_ID "41" +#define ETL_STRING_VIEW_ID "42" +#define ETL_CALLBACK_TIMER_ID "43" +#define ETL_MESSAGE_TIMER_ID "44" +#define ETL_TYPE_LOOKUP_ID "45" +#define ETL_QUEUE_SPSC_ISR_ID "46" +#define ETL_QUEUE_SPSC_ATOMIC_ID "47" +#define ETL_QUEUE_MPMC_MUTEX_ID "48" +#define ETL_TYPE_SELECT_ID "49" +#define ETL_BINARY_ID "50" +#define ETL_DELEGATE_ID "51" +#define ETL_BITSET_ID "52" +#define ETL_INDIRECT_VECTOR_ID "53" +#define ETL_QUEUE_SPSC_LOCKED_ID "54" +#define ETL_MESSAGE_PACKET_ID "55" +#define ETL_CIRCULAR_BUFFER_ID "56" +#define ETL_MULTI_LOOP_ID "57" +#define ETL_REFERENCE_COUNTER_MESSAGE_POOL_ID "58" + +#endif diff --git a/include/etl/file_error_numbers.txt b/include/etl/file_error_numbers.txt deleted file mode 100644 index 31eb6ffd..00000000 --- a/include/etl/file_error_numbers.txt +++ /dev/null @@ -1,57 +0,0 @@ - 1 deque - 2 flat_map - 3 flat_multimap - 4 flat_multiset - 5 flat_set - 6 forward_list - 7 list - 8 map - 9 multimap -10 multiset -11 pool -12 priority_queue -13 queue -14 set -15 stack -16 unordered_map -17 vector -18 observer -19 ihash -20 intrusive_forward_list -21 intrusive_list -22 intrusive_links -23 unordered_set -24 variant -25 unordered_multimap -26 unordered_multiset -27 basic_string -28 intrusive_stack -29 intrusive_queue -30 reference_flat_map -31 reference_flat_multimap -32 reference_flat_set -33 reference_flat_multiset -34 fsm -35 message_router -36 scheduler -37 task -38 message -39 message_bus -40 factory / variant_pool -41 array_view -42 string_view -43 callback_timer -44 message_timer -45 type_lookup -46 queue_spsc_isr -47 queue_spsc_atomic -48 queue_mpmc_mutex -49 type_select -50 binary -51 delegate -52 bitset -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_allocator.h b/include/etl/fixed_sized_memory_block_allocator.h new file mode 100644 index 00000000..30cafc75 --- /dev/null +++ b/include/etl/fixed_sized_memory_block_allocator.h @@ -0,0 +1,113 @@ +///\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 "generic_pool.h" +#include "alignment.h" + +namespace etl +{ + //************************************************************************* + /// The fixed sized memory block pool. + /// The allocated memory blocks are all the same size. + //************************************************************************* + template + class fixed_sized_memory_block_allocator : public imemory_block_allocator + { + public: + + //************************************************************************* + /// Default contsrcutor + //************************************************************************* + fixed_sized_memory_block_allocator() + { + } + + //************************************************************************* + /// Construct with a successor allocator. + //************************************************************************* + fixed_sized_memory_block_allocator(etl::imemory_block_allocator& successor) + : imemory_block_allocator(successor) + { + } + + private: + + /// A structure that has the size Block_Size. + struct block + { + char data[Block_Size]; + }; + + //************************************************************************* + /// The overridden virtual function to allocate a block. + //************************************************************************* + virtual void* allocate_block(size_t required_size) ETL_OVERRIDE + { + if (required_size <= Block_Size) + { + return pool.allocate(); + } + else + { + return ETL_NULLPTR; + } + } + + //************************************************************************* + /// The overridden virtual function to release a block. + //************************************************************************* + virtual bool release_block(const void* const pblock) ETL_OVERRIDE + { + if (pool.is_in_pool(pblock)) + { + pool.release(static_cast(pblock)); + return true; + } + else + { + return false; + } + } + + /// The generic pool from which allocate memory blocks. + etl::generic_pool pool; + + // No copying allowed. + fixed_sized_memory_block_allocator(const etl::fixed_sized_memory_block_allocator&) ETL_DELETE; + fixed_sized_memory_block_allocator& operator =(const etl::fixed_sized_memory_block_allocator&) ETL_DELETE; + }; +} + +#endif diff --git a/include/etl/fixed_sized_memory_block_pool.h b/include/etl/fixed_sized_memory_block_pool.h deleted file mode 100644 index 6e35e5f6..00000000 --- a/include/etl/fixed_sized_memory_block_pool.h +++ /dev/null @@ -1,65 +0,0 @@ -///\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/generators/message_router_generator.h b/include/etl/generators/message_router_generator.h index f08f4292..2c997360 100644 --- a/include/etl/generators/message_router_generator.h +++ b/include/etl/generators/message_router_generator.h @@ -129,6 +129,7 @@ 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)) diff --git a/include/etl/generic_pool.h b/include/etl/generic_pool.h index 91659e1a..b8aa9a8a 100644 --- a/include/etl/generic_pool.h +++ b/include/etl/generic_pool.h @@ -51,20 +51,20 @@ namespace etl /// A templated abstract pool implementation that uses a fixed size pool. ///\ingroup pool //************************************************************************* - template + 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_; + static ETL_CONSTANT size_t SIZE = VSize; + static ETL_CONSTANT size_t ALIGNMENT = VAlignment; + static ETL_CONSTANT size_t TYPE_SIZE = VTypeSize; //************************************************************************* /// Constructor //************************************************************************* generic_pool() - : etl::ipool(reinterpret_cast(&buffer[0]), ELEMENT_SIZE, SIZE) + : etl::ipool(reinterpret_cast(&buffer[0]), Element_Size, VSize) { } @@ -77,12 +77,12 @@ namespace etl 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"); + ETL_STATIC_ASSERT(etl::alignment_of::value <= VAlignment, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool"); return ipool::allocate(); } -#if !ETL_CPP11_SUPPORTED || ETL_POOL_CPP03_CODE || defined(ETL_STLPORT) +#if ETL_CPP11_NOT_SUPPORTED || ETL_POOL_CPP03_CODE || ETL_USING_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 @@ -91,8 +91,8 @@ namespace etl 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"); + ETL_STATIC_ASSERT(etl::alignment_of::value <= VAlignment, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool"); return ipool::create(); } @@ -104,8 +104,8 @@ namespace etl 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"); + ETL_STATIC_ASSERT(etl::alignment_of::value <= VAlignment, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool"); return ipool::create(value1); } @@ -117,8 +117,8 @@ namespace etl 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"); + ETL_STATIC_ASSERT(etl::alignment_of::value <= VAlignment, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool"); return ipool::create(value1, value2); } @@ -130,8 +130,8 @@ namespace etl 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"); + ETL_STATIC_ASSERT(etl::alignment_of::value <= VAlignment, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool"); return ipool::create(value1, value2, value3); } @@ -143,8 +143,8 @@ namespace etl 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"); + ETL_STATIC_ASSERT(etl::alignment_of::value <= VAlignment, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool"); return ipool::create(value1, value2, value3, value4); } #else @@ -154,34 +154,24 @@ namespace etl 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"); + ETL_STATIC_ASSERT(etl::alignment_of::value <= VAlignment, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "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. + /// 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"); - ipool::destroy(p_object); + ETL_STATIC_ASSERT(etl::alignment_of::value <= VAlignment, "Type has incompatible alignment"); + ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool"); + p_object->~U(); + ipool::release(p_object); } private: @@ -189,20 +179,22 @@ namespace etl // 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. + char* next; ///< Pointer to the next free element. + char value[VTypeSize]; ///< 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]; + typename etl::aligned_storage::value>::type buffer[VSize]; - static ETL_CONSTANT uint32_t ELEMENT_SIZE = sizeof(Element); + static const uint32_t Element_Size = sizeof(Element); // Should not be copied. - generic_pool(const generic_pool&) ETL_DELETE; - generic_pool& operator =(const generic_pool&) ETL_DELETE; + generic_pool(const generic_pool&); + generic_pool& operator =(const generic_pool&); }; + + } #endif diff --git a/include/etl/ipool.h b/include/etl/ipool.h index 018181ed..19e038f4 100644 --- a/include/etl/ipool.h +++ b/include/etl/ipool.h @@ -37,20 +37,13 @@ SOFTWARE. #include "static_assert.h" #include "utility.h" #include "memory.h" - -#include +#include "placement_new.h" #undef ETL_FILE -#define ETL_FILE "11" +#define ETL_FILE ETL_POOL_ID #define ETL_POOL_CPP03_CODE 0 -//***************************************************************************** -///\defgroup pool pool -/// A fixed capacity pool. -///\ingroup containers -//***************************************************************************** - namespace etl { //*************************************************************************** @@ -106,39 +99,14 @@ namespace etl }; //*************************************************************************** - /// The base implementation of a pool. - /// Implements the imemory_block_pool interface. + ///\ingroup pool //*************************************************************************** - class ipool : public imemory_block_pool + class ipool { 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 @@ -147,7 +115,7 @@ namespace etl template T* allocate() { - if (sizeof(T) > ITEM_SIZE) + if (sizeof(T) > Item_Size) { ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size)); } @@ -155,7 +123,7 @@ namespace etl return reinterpret_cast(allocate_item()); } -#if !ETL_CPP11_SUPPORTED || ETL_POOL_CPP03_CODE || defined(ETL_STLPORT) +#if ETL_CPP11_NOT_SUPPORTED || ETL_POOL_CPP03_CODE || ETL_USING_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 @@ -250,24 +218,19 @@ namespace etl //************************************************************************* /// 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'. + /// 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) { - // Does it belong to us? - if (is_in_pool(p_object)) + if (sizeof(T) > Item_Size) { - p_object->~T(); - release_item((char*)p_object); - } - else - { - ETL_ALWAYS_ASSERT(ETL_ERROR(pool_object_not_in_pool)); + ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size)); } + + p_object->~T(); + release(p_object); } //************************************************************************* @@ -278,15 +241,8 @@ namespace etl //************************************************************************* 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)); - } + const uintptr_t p = uintptr_t(p_object); + release_item((char*)p); } //************************************************************************* @@ -294,9 +250,9 @@ namespace etl //************************************************************************* void release_all() { - items_allocated = 0; + items_allocated = 0; items_initialised = 0; - p_next = p_buffer; + p_next = p_buffer; } //************************************************************************* @@ -304,9 +260,10 @@ namespace etl /// \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 + bool is_in_pool(const void* const p_object) const { - return is_item_in_pool((const char*)p_object); + const uintptr_t p = uintptr_t(p_object); + return is_item_in_pool((const char*)p); } //************************************************************************* @@ -314,7 +271,7 @@ namespace etl //************************************************************************* size_t max_size() const { - return MAX_SIZE; + return Max_Size; } //************************************************************************* @@ -322,7 +279,7 @@ namespace etl //************************************************************************* size_t capacity() const { - return MAX_SIZE; + return Max_Size; } //************************************************************************* @@ -330,7 +287,7 @@ namespace etl //************************************************************************* size_t available() const { - return MAX_SIZE - items_allocated; + return Max_Size - items_allocated; } //************************************************************************* @@ -356,7 +313,7 @@ namespace etl //************************************************************************* bool full() const { - return items_allocated == MAX_SIZE; + return items_allocated == Max_Size; } protected: @@ -366,11 +323,11 @@ namespace etl //************************************************************************* 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_) + p_next(p_buffer_), + items_allocated(0), + items_initialised(0), + Item_Size(item_size_), + Max_Size(max_size_) { } @@ -384,13 +341,13 @@ namespace etl char* p_value = ETL_NULLPTR; // Any free space left? - if (items_allocated < MAX_SIZE) + if (items_allocated < Max_Size) { // Initialise another one if necessary. - if (items_initialised < MAX_SIZE) + if (items_initialised < Max_Size) { - char* p = p_buffer + (items_initialised * ITEM_SIZE); - char* np = p + ITEM_SIZE; + char* p = p_buffer + (items_initialised * Item_Size); + char* np = p + Item_Size; *reinterpret_cast(p) = np; ++items_initialised; } @@ -399,7 +356,7 @@ namespace etl p_value = p_next; ++items_allocated; - if (items_allocated != MAX_SIZE) + if (items_allocated != Max_Size) { // Set up the pointer to the next free item p_next = *reinterpret_cast(p_next); @@ -423,6 +380,9 @@ namespace etl //************************************************************************* 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. @@ -446,12 +406,12 @@ namespace etl { // 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)); + 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); + bool is_valid_address = ((distance % Item_Size) == 0); #else bool is_valid_address = true; #endif @@ -469,8 +429,8 @@ namespace etl 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. + 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. diff --git a/include/etl/ireference_counted_message_pool.h b/include/etl/ireference_counted_message_pool.h index ddacf969..fe9c5500 100644 --- a/include/etl/ireference_counted_message_pool.h +++ b/include/etl/ireference_counted_message_pool.h @@ -35,7 +35,7 @@ SOFTWARE. namespace etl { - class ireference_counted_message; + class ipool_message; //*************************************************************************** /// Interface for a reference counted message pool. @@ -44,8 +44,8 @@ namespace etl { public: - virtual void release(const etl::ireference_counted_message* const pmsg) = 0; - virtual void release(const etl::ireference_counted_message& msg) = 0; + virtual ~ireference_counted_message_pool() {} + virtual void release(const etl::ipool_message& msg) = 0; }; } diff --git a/include/etl/list.h b/include/etl/list.h index 155e62b2..da80f0ce 100644 --- a/include/etl/list.h +++ b/include/etl/list.h @@ -48,6 +48,7 @@ SOFTWARE. #include "memory.h" #include "iterator.h" #include "static_assert.h" +#include "parameter_type.h" #include "placement_new.h" #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && ETL_USING_STL diff --git a/include/etl/memory.h b/include/etl/memory.h index bb1aca2f..54bb70fd 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -1900,34 +1900,124 @@ namespace etl } }; - //************************************************************************* + //***************************************************************************** /// The interface for a memory block pool. - //************************************************************************* - struct imemory_block_pool + //***************************************************************************** + class imemory_block_allocator { - 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() const = 0; + public: + + //***************************************************************************** + /// Default constructor. + //***************************************************************************** + imemory_block_allocator() + : p_successor(ETL_NULLPTR) + { + } + + //***************************************************************************** + /// Construct with a successor. + //***************************************************************************** + explicit imemory_block_allocator(imemory_block_allocator& successor) + : p_successor(&successor) + { + } + + //***************************************************************************** + /// Try to allocate a memory block of the required size. + /// If this allocator cannot, then pass the request on the the successor, if configured. + //***************************************************************************** + void* allocate(size_t required_size) + { + // Call the derived implementation. + void* p = allocate_block(required_size); + + // If that failed... + if (p == ETL_NULLPTR) + { + /// ...and we have a successor... + if (has_successor()) + { + // Try to allocate from the next one in the chain. + return get_successor().allocate(required_size); + } + } + + return p; + } + + //***************************************************************************** + /// Try to release a memory block of the required size. + /// If this allocator cannot, then pass the request on the the successor, if configured. + //***************************************************************************** + bool release(const void* const p) + { + // Call the derived implementation to try to release. + if (!release_block(p)) + { + // If it failed and we have a successor... + if (has_successor()) + { + // Try to release from the next one in the chain. + return get_successor().release(p); + } + } + + return true; + } + + //***************************************************************************** + /// Set the sucessor allocator. + //***************************************************************************** + void set_successor(etl::imemory_block_allocator& successor) + { + p_successor = &successor; + } + + //***************************************************************************** + /// Get the sucessor allocator. + //***************************************************************************** + etl::imemory_block_allocator& get_successor() const + { + return *p_successor; + } + + //***************************************************************************** + /// Do we have a successor allocator. + //***************************************************************************** + bool has_successor() const + { + return (p_successor != ETL_NULLPTR); + } + + protected: + + virtual void* allocate_block(size_t required_size) = 0; + virtual bool release_block(const void* const) = 0; + + private: + + etl::imemory_block_allocator* p_successor; }; //*************************************************************************** - /// Declares an aligned buffer of N_OBJECTS x of size OBJECT_SIZE at alignment ALIGNMENT. + /// Declares an aligned buffer of N_Objects x of size Object_Size at alignment Alignment. ///\ingroup alignment //*************************************************************************** - template + template class uninitialized_buffer { public: - static ETL_CONSTANT size_t OBJECT_SIZE = OBJECT_SIZE_; - static ETL_CONSTANT size_t N_OBJECTS = N_OBJECTS_; - static ETL_CONSTANT size_t ALIGNMENT = ALIGNMENT_; + static ETL_CONSTANT size_t Object_Size = VObject_Size; + static ETL_CONSTANT size_t N_Objects = VN_Objects; + static ETL_CONSTANT size_t Alignment = VAlignment; /// Convert to T reference. template operator T& () { - ETL_STATIC_ASSERT((etl::is_same::value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); + ETL_STATIC_ASSERT((etl::is_same::value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); return *reinterpret_cast(raw); } @@ -1935,7 +2025,7 @@ namespace etl template operator const T& () const { - ETL_STATIC_ASSERT((etl::is_same::value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); + ETL_STATIC_ASSERT((etl::is_same::value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); return *reinterpret_cast(raw); } @@ -1943,7 +2033,7 @@ namespace etl template operator T* () { - ETL_STATIC_ASSERT((etl::is_same::value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); + ETL_STATIC_ASSERT((etl::is_same::value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(raw); } @@ -1951,26 +2041,26 @@ namespace etl template operator const T* () const { - ETL_STATIC_ASSERT((etl::is_same::value || ((ALIGNMENT % etl::alignment_of::value) == 0)), "Incompatible alignment"); + ETL_STATIC_ASSERT((etl::is_same::value || ((Alignment % etl::alignment_of::value) == 0)), "Incompatible alignment"); return reinterpret_cast(raw); } #if ETL_CPP11_SUPPORTED && !defined(ETL_COMPILER_ARM5) && !defined(ETL_UNINITIALIZED_BUFFER_FORCE_CPP03) - alignas(ALIGNMENT) char raw[OBJECT_SIZE * N_OBJECTS]; + alignas(VAlignment) char raw[Object_Size * N_Objects]; #else union { - char raw[OBJECT_SIZE * N_OBJECTS]; - typename etl::type_with_alignment::type etl_alignment_type; // A POD type that has the same alignment as ALIGNMENT. + char raw[VObject_Size * VN_Objects]; + typename etl::type_with_alignment::type etl_alignment_type; // A POD type that has the same alignment as VAlignment. }; #endif }; //*************************************************************************** - /// Declares an aligned buffer of N_OBJECTS as if they were type T. + /// Declares an aligned buffer of VN_Objects as if they were type T. ///\ingroup alignment //*************************************************************************** - template + template class uninitialized_buffer_of { public: @@ -1983,9 +2073,9 @@ namespace etl typedef T* iterator; typedef const T* const_iterator; - static ETL_CONSTANT size_t OBJECT_SIZE = sizeof(T); - static ETL_CONSTANT size_t N_OBJECTS = N_OBJECTS_; - static ETL_CONSTANT size_t ALIGNMENT = etl::alignment_of::value; + static ETL_CONSTANT size_t Object_Size = sizeof(T); + static ETL_CONSTANT size_t N_Objects = VN_Objects; + static ETL_CONSTANT size_t Alignment = etl::alignment_of::value; /// Index operator. T& operator [](int i) @@ -2036,28 +2126,28 @@ namespace etl T* end() { - return reinterpret_cast(raw + (sizeof(T) * N_OBJECTS)); + return reinterpret_cast(raw + (sizeof(T) * N_Objects)); } const T* end() const { - return reinterpret_cast(raw + (sizeof(T) * N_OBJECTS)); + return reinterpret_cast(raw + (sizeof(T) * N_Objects)); } #if ETL_CPP11_SUPPORTED && !defined(ETL_COMPILER_ARM5) && !defined(ETL_UNINITIALIZED_BUFFER_FORCE_CPP03) - alignas(ALIGNMENT) char raw[sizeof(T) * N_OBJECTS]; + alignas(Alignment) char raw[sizeof(T) * N_Objects]; #else union { - char raw[sizeof(T) * N_OBJECTS]; - typename etl::type_with_alignment::type etl_alignment_type; // A POD type that has the same alignment as ALIGNMENT. + char raw[sizeof(T) * N_Objects]; + typename etl::type_with_alignment::type etl_alignment_type; // A POD type that has the same alignment as Alignment. }; #endif }; #if ETL_CPP14_SUPPORTED - template - using uninitialized_buffer_of_v = typename uninitialized_buffer_of::buffer; + template + using uninitialized_buffer_of_v = typename uninitialized_buffer_of::buffer; #endif } diff --git a/include/etl/message_bus.h b/include/etl/message_bus.h index 6254b702..a8be50e5 100644 --- a/include/etl/message_bus.h +++ b/include/etl/message_bus.h @@ -162,10 +162,82 @@ namespace etl receive(source, etl::imessage_router::ALL_MESSAGE_ROUTERS, message); } + //******************************************** + virtual void receive(etl::imessage_router& source, + etl::message_router_id_t destination_router_id, + etl::shared_message shared_msg) ETL_OVERRIDE + { + switch (destination_router_id) + { + //***************************** + // Broadcast to all routers. + case etl::imessage_router::ALL_MESSAGE_ROUTERS: + { + router_list_t::iterator irouter = router_list.begin(); + + // Broadcast to everyone. + while (irouter != router_list.end()) + { + etl::imessage_router& router = **irouter; + + if (router.accepts(shared_msg.get_message().get_message_id())) + { + router.receive(source, shared_msg); + } + + ++irouter; + } + + break; + } + + //***************************** + // Must be an addressed message. + default: + { + router_list_t::iterator irouter = router_list.begin(); + + // Find routers with the id. + ETL_OR_STD::pair range = etl::equal_range(router_list.begin(), + router_list.end(), + destination_router_id, + compare_router_id()); + + // Call all of them. + while (range.first != range.second) + { + if ((*(range.first))->accepts(shared_msg.get_message().get_message_id())) + { + (*(range.first))->receive(source, shared_msg); + } + + ++range.first; + } + + // Do any message buses. + // These are always at the end of the list. + irouter = etl::lower_bound(router_list.begin(), + router_list.end(), + etl::imessage_bus::MESSAGE_BUS, + compare_router_id()); + + while (irouter != router_list.end()) + { + // So pass it on. + (*irouter)->receive(source, destination_router_id, shared_msg); + + ++irouter; + } + + break; + } + } + } + //******************************************* - void receive(etl::imessage_router& source, - etl::message_router_id_t destination_router_id, - const etl::imessage& message) ETL_OVERRIDE + virtual void receive(etl::imessage_router& source, + etl::message_router_id_t destination_router_id, + const etl::imessage& message) ETL_OVERRIDE { switch (destination_router_id) { diff --git a/include/etl/message_router.h b/include/etl/message_router.h index 955ee8ea..572588e6 100644 --- a/include/etl/message_router.h +++ b/include/etl/message_router.h @@ -117,6 +117,7 @@ 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)) @@ -144,7 +145,7 @@ namespace etl } //******************************************** - void receive(imessage_router& source, etl::message_router_id_t destination_router_id, etl::shared_message shared_msg) + virtual 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)) { @@ -152,6 +153,12 @@ namespace etl } } + //******************************************** + void receive(etl::message_router_id_t destination_router_id, etl::shared_message shared_msg) + { + receive(etl::get_null_message_router(), destination_router_id, shared_msg); + } + //******************************************** bool accepts(const etl::imessage& msg) const { diff --git a/include/etl/platform.h b/include/etl/platform.h index 3912aa68..f043515c 100644 --- a/include/etl/platform.h +++ b/include/etl/platform.h @@ -34,6 +34,8 @@ SOFTWARE. #include #include +#include "file_error_numbers.h" + // Define a debug macro #if (defined(_DEBUG) || defined(DEBUG)) && !defined(ETL_DEBUG) #define ETL_DEBUG diff --git a/include/etl/pool.h b/include/etl/pool.h index 547937c5..588c1db1 100644 --- a/include/etl/pool.h +++ b/include/etl/pool.h @@ -32,22 +32,8 @@ SOFTWARE. #define ETL_POOL_INCLUDED #include "platform.h" -#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 "static_assert.h" -#include "algorithm.h" -#include "placement_new.h" - -#undef ETL_FILE -#define ETL_FILE "11" +#include "ipool.h" +#include "generic_pool.h" #define ETL_POOL_CPP03_CODE 0 @@ -59,565 +45,16 @@ 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_NOT_SUPPORTED || ETL_POOL_CPP03_CODE || ETL_USING_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) - { - const uintptr_t p = uintptr_t(p_object); - release_item((char*)p); - } - - //************************************************************************* - /// 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 - { - const uintptr_t p = uintptr_t(p_object); - return is_item_in_pool((const char*)p); - } - - //************************************************************************* - /// 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_NOT_SUPPORTED || ETL_POOL_CPP03_CODE || ETL_USING_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. ///\ingroup pool //************************************************************************* - template - class pool : public etl::generic_pool::value, SIZE_> + template + class pool : public etl::generic_pool::value, VSize> { private: - typedef etl::generic_pool::value, SIZE_> base_t; + typedef etl::generic_pool::value, VSize> base_t; public: diff --git a/include/etl/reference_counted_message.h b/include/etl/reference_counted_message.h index 94d15cd1..094fc3ac 100644 --- a/include/etl/reference_counted_message.h +++ b/include/etl/reference_counted_message.h @@ -46,6 +46,7 @@ namespace etl { public: + virtual ~ireference_counted_message() {} 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. @@ -55,8 +56,12 @@ namespace etl //*************************************************************************** // Reference counted message type. //*************************************************************************** + class ipool_message : public etl::ireference_counted_message + { + }; + template - class reference_counted_message : public etl::ireference_counted_message + class pool_message : public etl::ipool_message { public: @@ -67,7 +72,7 @@ namespace etl /// Constructor /// \param msg The message to count. //*************************************************************************** - reference_counted_message(const TMessage& msg_, etl::ireference_counted_message_pool& owner_) + pool_message(const TMessage& msg_, etl::ireference_counted_message_pool& owner_) : rc_object(msg_) , owner(owner_) { @@ -112,7 +117,7 @@ namespace etl private: etl::reference_counted_object rc_object; ///< The reference counted object. - etl::ireference_counted_message_pool& owner; ///< The pool that owns this object. + etl::ireference_counted_message_pool& owner; ///< The pool that owns this object. }; //*************************************************************************** @@ -120,8 +125,12 @@ namespace etl /// The message type will always have a reference count of 1. /// \tparam TMessage The message type stored. //*************************************************************************** + class inon_pool_message : public etl::ireference_counted_message + { + }; + template - class persistent_message : virtual public etl::ireference_counted_message + class non_pool_message : public etl::inon_pool_message { public: @@ -131,7 +140,7 @@ namespace etl /// Constructor /// \param msg The message to count. //*************************************************************************** - persistent_message(const TMessage& msg_) + explicit non_pool_message(const TMessage& msg_) : rc_object(msg_) { } @@ -175,9 +184,9 @@ 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; + non_pool_message() ETL_DELETE; + non_pool_message(const non_pool_message&) ETL_DELETE; + non_pool_message& operator =(const non_pool_message&) ETL_DELETE; etl::persistent_object rc_object; ///< The reference counted object. }; @@ -188,7 +197,7 @@ namespace etl /// \tparam TObject The type to be reference counted. //*************************************************************************** template - using atomic_counted_message = etl::reference_counted_message; + using atomic_counted_message = etl::pool_message; #endif } diff --git a/include/etl/reference_counted_message_pool.h b/include/etl/reference_counted_message_pool.h index c5b2acc8..d5973d5c 100644 --- a/include/etl/reference_counted_message_pool.h +++ b/include/etl/reference_counted_message_pool.h @@ -38,34 +38,49 @@ SOFTWARE. #include "static_assert.h" #include "error_handler.h" #include "utility.h" +#include "atomic.h" #include "memory.h" -#define ETL_FILE "57" +#undef ETL_FILE +#define ETL_FILE ETL_REFERENCE_COUNTER_MESSAGE_POOL_ID namespace etl { //*************************************************************************** - /// + /// Exception type for etl::reference_counted_message_pool //*************************************************************************** - class reference_counted_message_pool_allocation_exception : public etl::exception + class reference_counted_message_pool_exception : public etl::exception { public: - reference_counted_message_pool_allocation_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + reference_counted_message_pool_exception(string_type reason_, string_type file_name_, numeric_type line_number_) : exception(reason_, file_name_, line_number_) { } }; //*************************************************************************** - /// + /// Exception if the allocation failed. //*************************************************************************** - class reference_counted_message_pool_allocation_failure : etl::reference_counted_message_pool_allocation_exception + class reference_counted_message_pool_allocation_failure : etl::reference_counted_message_pool_exception { public: 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_) + : reference_counted_message_pool_exception(ETL_ERROR_TEXT("reference_counted_message_pool:allocation failure", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// Exception if the release failed. + //*************************************************************************** + class reference_counted_message_pool_release_failure : etl::reference_counted_message_pool_exception + { + public: + + reference_counted_message_pool_release_failure(string_type file_name_, numeric_type line_number_) + : reference_counted_message_pool_exception(ETL_ERROR_TEXT("reference_counted_message_pool:release failure", ETL_FILE"B"), file_name_, line_number_) { } }; @@ -81,8 +96,8 @@ namespace etl //************************************************************************* /// Constructor //************************************************************************* - reference_counted_message_pool(imemory_block_pool& memory_block_pool_) - : memory_block_pool(memory_block_pool_) + reference_counted_message_pool(imemory_block_allocator& memory_block_allocator_) + : memory_block_allocator(memory_block_allocator_) { } @@ -90,26 +105,23 @@ namespace etl /// Allocate a reference counted message from the pool. //************************************************************************* template - etl::ireference_counted_message* allocate(const TMessage& message) + etl::ipool_message* allocate(const TMessage& message) { ETL_STATIC_ASSERT((etl::is_base_of::value), "Not a message type"); - typedef etl::reference_counted_message rcm_t; + typedef etl::pool_message rcm_t; typedef rcm_t* prcm_t; prcm_t p = ETL_NULLPTR; - if (sizeof(rcm_t) <= memory_block_pool.get_memory_block_size()) - { - p = static_cast(memory_block_pool.allocate_memory_block(sizeof(rcm_t))); + p = static_cast(memory_block_allocator.allocate(sizeof(rcm_t))); - if (p != ETL_NULLPTR) - { - ::new(p) rcm_t(message, *this); - } + if (p != ETL_NULLPTR) + { + ::new(p) rcm_t(message, *this); } - ETL_ASSERT((p != ETL_NULLPTR), ETL_ERROR(etl::message_pool_allocation_failure)); + ETL_ASSERT((p != ETL_NULLPTR), ETL_ERROR(etl::reference_counted_message_pool_allocation_failure)); return p; } @@ -117,32 +129,78 @@ namespace etl //************************************************************************* /// Destruct a message and send it back to the pool. //************************************************************************* - void release(const etl::ireference_counted_message* const p_rcmessage) + void release(const etl::ipool_message& rcmessage) { - if (p_rcmessage != ETL_NULLPTR) - { - p_rcmessage->~ireference_counted_message(); - memory_block_pool.release_memory_block(p_rcmessage); - } + rcmessage.~ipool_message(); + bool released = memory_block_allocator.release(&rcmessage); + + ETL_ASSERT(released, ETL_ERROR(etl::reference_counted_message_pool_release_failure)); } - //************************************************************************* - /// Destruct a message and send it back to the pool. - //************************************************************************* - void release(const etl::ireference_counted_message& msg) +#if ETL_CPP11_SUPPORTED + //***************************************************** + template + struct pool_message_size { - release(&msg); - } + private: + + // Size of the first pool message type. + static constexpr size_t size1 = sizeof(etl::pool_message); + + // Maximum size of the the rest of the pool message types. + static constexpr size_t size2 = pool_message_size::size; + + // Size of the first pool message type. + static constexpr size_t alignment1 = etl::alignment_of>::value; + + // Maximum size of the the rest of the pool message types. + static constexpr size_t alignment2 = pool_message_size::alignment; + + public: + + // The maximum size. + static constexpr size_t size = (size1 < size2) ? size2 : size1; + + // The maximum alignment. + static constexpr size_t alignment = (alignment1 < alignment2) ? alignment2 : alignment1; + }; + + //***************************************************** + template + struct pool_message_size + { + public: + + ETL_STATIC_ASSERT((etl::is_base_of::value), "TMessage not derived from etl::imessage"); + + // The size of this pool message type. + static constexpr size_t size = sizeof(etl::pool_message); + + // The maximum alignment. + static constexpr size_t alignment = etl::alignment_of>::value; + }; +#else + template + struct pool_message_size + { + static const size_t size = sizeof(etl::pool_message); + static const size_t alignment = etl::alignment_of >::value; + }; +#endif private: /// The raw memory block pool. - imemory_block_pool& memory_block_pool; + imemory_block_allocator& memory_block_allocator; // 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; }; + +#if ETL_CPP11_SUPPORTED && ETL_HAS_ATOMIC + using atomic_counted_message_pool = reference_counted_message_pool; +#endif } #undef ETL_FILE diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h index 36792082..20ac006f 100644 --- a/include/etl/reference_counted_object.h +++ b/include/etl/reference_counted_object.h @@ -151,6 +151,7 @@ namespace etl { public: + virtual ~ireference_counted_object() {} ETL_NODISCARD virtual ireference_counter& get_reference_counter() = 0; ETL_NODISCARD virtual const ireference_counter& get_reference_counter() const = 0; }; diff --git a/include/etl/shared_message.h b/include/etl/shared_message.h index 82b29b87..c72fcd67 100644 --- a/include/etl/shared_message.h +++ b/include/etl/shared_message.h @@ -34,6 +34,10 @@ SOFTWARE. #include "platform.h" #include "utility.h" #include "reference_counted_message.h" +#include "ireference_counted_message_pool.h" +#include "message.h" +#include "type_traits.h" +#include "static_assert.h" //***************************************************************************** /// A wrapper for reference counted messages. @@ -45,11 +49,37 @@ namespace etl { public: + //************************************************************************* + /// Constructor + //************************************************************************* + template + shared_message(TPool& owner, const TMessage& message) + { + ETL_STATIC_ASSERT((etl::is_base_of::value), "TPool not derived from etl::ireference_counted_message_pool"); + ETL_STATIC_ASSERT((etl::is_base_of::value), "TMessage not derived from etl::imessage"); + + p_rcmessage = owner.allocate(message); + + if (p_rcmessage != ETL_NULLPTR) + { + p_rcmessage->get_reference_counter().set_reference_count(1U); + } + } + + //************************************************************************* + /// Constructor + /// \param np_message A reference to a message not controlled by a pool. + //************************************************************************* + explicit shared_message(etl::inon_pool_message& np_message) + : p_rcmessage(&np_message) + { + } + //************************************************************************* /// Constructor /// \param message A reference to the message allocated from the pool. //************************************************************************* - shared_message(etl::ireference_counted_message& rcmessage_) + explicit shared_message(etl::ipool_message& rcmessage_) : p_rcmessage(&rcmessage_) { p_rcmessage->get_reference_counter().set_reference_count(1U); @@ -100,7 +130,7 @@ namespace etl //************************************************************************* /// Get a const reference to the contained message. //************************************************************************* - const etl::imessage& get_message() const + ETL_NODISCARD const etl::imessage& get_message() const { return p_rcmessage->get_message(); } @@ -108,7 +138,7 @@ namespace etl //************************************************************************* /// Get the current reference count for this shared message. //************************************************************************* - uint32_t get_reference_count() const + ETL_NODISCARD uint32_t get_reference_count() const { return p_rcmessage->get_reference_counter().get_reference_count(); } @@ -117,34 +147,8 @@ namespace etl shared_message() ETL_DELETE; - etl::ireference_counted_message* p_rcmessage; + etl::ireference_counted_message* p_rcmessage; ///< A pointer to the reference counted message. }; - - //***************************************************************************** - /// 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); - } - -#if ETL_CPP11_SUPPORTED - //***************************************************************************** - /// 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(TMessage(etl::forward(args)...)); - return etl::shared_message(*p_rcmessage); - } -#endif } #endif diff --git a/include/etl/variant_pool.h b/include/etl/variant_pool.h index c572580c..4d448673 100644 --- a/include/etl/variant_pool.h +++ b/include/etl/variant_pool.h @@ -54,7 +54,7 @@ SOFTWARE. #include #include "platform.h" -#include "generic_pool.h" +#include "pool.h" #include "type_traits.h" #include "static_assert.h" #include "largest.h" diff --git a/test/test_pool_message.cpp b/test/test_pool_message.cpp deleted file mode 100644 index bfdb635d..00000000 --- a/test/test_pool_message.cpp +++ /dev/null @@ -1,221 +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. -******************************************************************************/ - -#include "UnitTest++/UnitTest++.h" - -#include "etl/pool.h" -#include "etl/shared_message.h" -#include "etl/message.h" -#include "etl/message_router.h" -#include "etl/atomic.h" -#include "etl/queue.h" -#include "etl/reference_counted_message_pool.h" - -namespace -{ - constexpr etl::message_id_t MESSAGE1 = 1U; - constexpr etl::message_id_t MESSAGE2 = 2U; - - constexpr etl::message_router_id_t ROUTER1 = 1U; - constexpr etl::message_router_id_t ROUTER2 = 2U; - - //************************************************************************* - struct Message1 : public etl::message - { - }; - - //************************************************************************* - struct Message2 : public etl::message - { - }; - - //************************************************************************* - struct Router1 : public etl::message_router - { - Router1() - : message_router(1) - { - - } - - void on_receive(etl::imessage_router& source, const Message1& message) - { - - } - - void on_receive_unknown(etl::imessage_router& source, const etl::imessage& message) - { - - } - }; - - //************************************************************************* - struct Router2 : public etl::message_router - { - Router2() - : message_router(2) - { - - } - - 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::shared_message_processor - { - Processor(Router& router_) - : shared_message_processor(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() - { - get_router().receive(smqueue.front().get_message()); - smqueue.pop(); - } - - etl::queue smqueue; - }; - - Router router; - Processor processor(router); - - 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(); - - 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(); - - 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_shared_message.cpp b/test/test_shared_message.cpp new file mode 100644 index 00000000..33a96486 --- /dev/null +++ b/test/test_shared_message.cpp @@ -0,0 +1,197 @@ +/****************************************************************************** +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/shared_message.h" +#include "etl/message.h" +#include "etl/message_router.h" +#include "etl/message_bus.h" +#include "etl/queue.h" +#include "etl/fixed_sized_memory_block_allocator.h" +#include "etl/reference_counted_message_pool.h" + +namespace +{ + constexpr etl::message_id_t MessageId1 = 1U; + constexpr etl::message_id_t MessageId2 = 2U; + + constexpr etl::message_router_id_t RouterId1 = 1U; + constexpr etl::message_router_id_t RouterId2 = 2U; + + //************************************************************************* + struct Message1 : public etl::message + { + Message1(int i_) + : i(i_) + { + } + + ~Message1() + { + + } + + int i; + }; + + //************************************************************************* + struct Message2 : public etl::message + { + ~Message2() + { + + } + }; + + //************************************************************************* + struct Router1 : public etl::message_router + { + Router1() + : message_router(RouterId1) + , count_message1(0) + , count_message2(0) + , count_unknown_message(0) + { + } + + void on_receive(etl::imessage_router& source, const Message1& message) + { + ++count_message1; + } + + void on_receive(etl::imessage_router& source, const Message2& message) + { + ++count_message2; + } + + void on_receive_unknown(etl::imessage_router& source, const etl::imessage& message) + { + + } + + void clear() + { + count_message1 = 0; + count_message2 = 0; + count_unknown_message = 0; + } + + int count_message1; + int count_message2; + int count_unknown_message; + }; + + //************************************************************************* + struct Router2 : public etl::message_router + { + Router2() + : message_router(RouterId2) + , count_message1(0) + , count_message2(0) + , count_unknown_message(0) + { + } + + void on_receive(etl::imessage_router& source, const Message1& message) + { + ++count_message1; + } + + void on_receive_unknown(etl::imessage_router& source, const etl::imessage& message) + { + ++count_unknown_message; + } + + void clear() + { + count_message1 = 0; + count_message2 = 0; + count_unknown_message = 0; + } + + int count_message1; + int count_message2; + int count_unknown_message; + }; + + //************************************************************************* + struct Bus : public etl::message_bus<2U> + { + }; + + SUITE(test_shared_message) + { + Router1 router1; + Router2 router2; + Bus bus; + + using pool_message_parameters = etl::atomic_counted_message_pool::pool_message_size; + + etl::fixed_sized_memory_block_allocator memory_allocator; + + etl::atomic_counted_message_pool message_pool(memory_allocator); + + //************************************************************************* + TEST(test_send_to_routers) + { + bus.clear(); + bus.subscribe(router1); + bus.subscribe(router2); + router1.clear(); + router2.clear(); + + etl::non_pool_message npm((Message2())); // npm is not owned by any pool. Extra parentheses to fix 'vexing parse'. + + etl::shared_message sm1(message_pool, Message1(1)); // sm1 holds a Message1 that is owned by message_pool. + etl::shared_message sm2(message_pool, Message2()); // sm2 holds a Message2 that is owned by message_pool. + etl::shared_message sm3(npm); // sm3 holds a Message2 that is not owned by a message pool. + etl::shared_message sm4(sm1); // sm4 is a copy of sm1. + + bus.receive(sm1); + bus.receive(sm2); + bus.receive(sm1); + bus.receive(sm3); + bus.receive(sm4); // sm4 is a copy of sm1 + bus.receive(RouterId2, sm1); // Only send sm1 to Router2 + + CHECK_EQUAL(2, sm1.get_reference_count()); + CHECK_EQUAL(1, sm2.get_reference_count()); + CHECK_EQUAL(1, sm3.get_reference_count()); + CHECK_EQUAL(2, sm4.get_reference_count()); + CHECK_EQUAL(3, router1.count_message1); + CHECK_EQUAL(2, router1.count_message2); + CHECK_EQUAL(0, router1.count_unknown_message); + CHECK_EQUAL(4, router2.count_message1); + CHECK_EQUAL(0, router2.count_message2); + CHECK_EQUAL(0, router2.count_unknown_message); + } + } +} diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index d57ad7b4..9e2c1fb4 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1272,6 +1272,7 @@ + @@ -1293,7 +1294,7 @@ - + @@ -1333,7 +1334,6 @@ - @@ -1915,7 +1915,7 @@ - + @@ -2021,7 +2021,6 @@ - diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index b47d81ae..0e2e86fb 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -909,18 +909,9 @@ ETL\Utilities - - Header Files - Header Files - - Header Files - - - Header Files - ETL\Frameworks @@ -930,13 +921,22 @@ ETL\Frameworks - - ETL\Frameworks - - + ETL\Containers - + + ETL\Containers + + + ETL\Utilities + + + ETL\Frameworks + + + ETL\Utilities + + ETL\Containers @@ -1475,7 +1475,7 @@ Source Files - + Source Files @@ -1560,9 +1560,6 @@ - - Resource Files - Resource Files