Updates to pools and memory allocators

This commit is contained in:
John Wellbelove 2021-01-06 17:56:24 +00:00
parent b40349ca9d
commit db8841ff0d
23 changed files with 854 additions and 1164 deletions

View File

@ -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

View File

@ -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

View File

@ -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 <size_t Block_Size, size_t Alignment, size_t Size>
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<block>();
}
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<const block* const>(pblock));
return true;
}
else
{
return false;
}
}
/// The generic pool from which allocate memory blocks.
etl::generic_pool<Block_Size, Alignment, Size> pool;
// No copying allowed.
fixed_sized_memory_block_allocator(const etl::fixed_sized_memory_block_allocator<Block_Size, Alignment, Size>&) ETL_DELETE;
fixed_sized_memory_block_allocator& operator =(const etl::fixed_sized_memory_block_allocator<Block_Size, Alignment, Size>&) ETL_DELETE;
};
}
#endif

View File

@ -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 <size_t BLOCK_SIZE, size_t ALIGNMENT, size_t SIZE>
struct fixed_sized_memory_block_pool : public etl::ipool
{
public:
fixed_sized_memory_block_pool()
: ipool(buffer.get_address<char>(), BLOCK_SIZE, SIZE)
{
}
private:
// No copying allowed.
fixed_sized_memory_block_pool(const etl::fixed_sized_memory_block_pool<BLOCK_SIZE, ALIGNMENT, SIZE>&) ETL_DELETE;
fixed_sized_memory_block_pool& operator =(const etl::fixed_sized_memory_block_pool<BLOCK_SIZE, ALIGNMENT, SIZE>&) ETL_DELETE;
typename etl::aligned_storage<SIZE * BLOCK_SIZE, ALIGNMENT>::type buffer;
};
}
#endif

View File

@ -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))

View File

@ -51,20 +51,20 @@ namespace etl
/// A templated abstract pool implementation that uses a fixed size pool.
///\ingroup pool
//*************************************************************************
template <const size_t TYPE_SIZE_, const size_t ALIGNMENT_, const size_t SIZE_>
template <const size_t VTypeSize, const size_t VAlignment, const size_t VSize>
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<char*>(&buffer[0]), ELEMENT_SIZE, SIZE)
: etl::ipool(reinterpret_cast<char*>(&buffer[0]), Element_Size, VSize)
{
}
@ -77,12 +77,12 @@ namespace etl
template <typename U>
U* allocate()
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool");
return ipool::allocate<U>();
}
#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 <typename U>
U* create()
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool");
return ipool::create<U>();
}
@ -104,8 +104,8 @@ namespace etl
template <typename U, typename T1>
U* create(const T1& value1)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool");
return ipool::create<U>(value1);
}
@ -117,8 +117,8 @@ namespace etl
template <typename U, typename T1, typename T2>
U* create(const T1& value1, const T2& value2)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool");
return ipool::create<U>(value1, value2);
}
@ -130,8 +130,8 @@ namespace etl
template <typename U, typename T1, typename T2, typename T3>
U* create(const T1& value1, const T2& value2, const T3& value3)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool");
return ipool::create<U>(value1, value2, value3);
}
@ -143,8 +143,8 @@ namespace etl
template <typename U, typename T1, typename T2, typename T3, typename T4>
U* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool");
return ipool::create<U>(value1, value2, value3, value4);
}
#else
@ -154,34 +154,24 @@ namespace etl
template <typename U, typename... Args>
U* create(Args&&... args)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool");
return ipool::create<U>(etl::forward<Args>(args)...);
}
#endif
//*************************************************************************
/// Releases the object.
/// \param p_object A pointer to the object to be destroyed.
//*************************************************************************
template <typename U>
void release(const U* const p_object)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::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 <typename U>
void destroy(const U* const p_object)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::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<U>::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<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<VAlignment>::type dummy; ///< Dummy item to get correct alignment.
};
///< The memory for the pool of objects.
typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::value>::type buffer[SIZE];
typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::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

View File

@ -37,20 +37,13 @@ SOFTWARE.
#include "static_assert.h"
#include "utility.h"
#include "memory.h"
#include <new>
#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<void*>();
}
//*************************************************************************
/// 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 <typename T>
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<T*>(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 <typename T>
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 <b>true<\b> if it does, otherwise <b>false</b>
//*************************************************************************
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<char**>(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<char**>(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.

View File

@ -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;
};
}

View File

@ -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

View File

@ -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 <size_t OBJECT_SIZE_, size_t N_OBJECTS_, size_t ALIGNMENT_>
template <size_t VObject_Size, size_t VN_Objects, size_t VAlignment>
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 <typename T>
operator T& ()
{
ETL_STATIC_ASSERT((etl::is_same<T*, void*>::value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
ETL_STATIC_ASSERT((etl::is_same<T*, void*>::value || ((Alignment % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
return *reinterpret_cast<T*>(raw);
}
@ -1935,7 +2025,7 @@ namespace etl
template <typename T>
operator const T& () const
{
ETL_STATIC_ASSERT((etl::is_same<T*, void*>::value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
ETL_STATIC_ASSERT((etl::is_same<T*, void*>::value || ((Alignment % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
return *reinterpret_cast<const T*>(raw);
}
@ -1943,7 +2033,7 @@ namespace etl
template <typename T>
operator T* ()
{
ETL_STATIC_ASSERT((etl::is_same<T*, void*>::value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
ETL_STATIC_ASSERT((etl::is_same<T*, void*>::value || ((Alignment % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
return reinterpret_cast<T*>(raw);
}
@ -1951,26 +2041,26 @@ namespace etl
template <typename T>
operator const T* () const
{
ETL_STATIC_ASSERT((etl::is_same<T*, void*>::value || ((ALIGNMENT % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
ETL_STATIC_ASSERT((etl::is_same<T*, void*>::value || ((Alignment % etl::alignment_of<T>::value) == 0)), "Incompatible alignment");
return reinterpret_cast<const T*>(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<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<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 <typename T, size_t N_OBJECTS_>
template <typename T, size_t VN_Objects>
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<T>::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<T>::value;
/// Index operator.
T& operator [](int i)
@ -2036,28 +2126,28 @@ namespace etl
T* end()
{
return reinterpret_cast<const T*>(raw + (sizeof(T) * N_OBJECTS));
return reinterpret_cast<const T*>(raw + (sizeof(T) * N_Objects));
}
const T* end() const
{
return reinterpret_cast<const T*>(raw + (sizeof(T) * N_OBJECTS));
return reinterpret_cast<const T*>(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<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<Alignment>::type etl_alignment_type; // A POD type that has the same alignment as Alignment.
};
#endif
};
#if ETL_CPP14_SUPPORTED
template <typename T, size_t N_OBJECTS>
using uninitialized_buffer_of_v = typename uninitialized_buffer_of<T, N_OBJECTS>::buffer;
template <typename T, size_t N_Objects>
using uninitialized_buffer_of_v = typename uninitialized_buffer_of<T, N_Objects>::buffer;
#endif
}

View File

@ -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<router_list_t::iterator, router_list_t::iterator> 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)
{

View File

@ -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
{

View File

@ -34,6 +34,8 @@ SOFTWARE.
#include <stdint.h>
#include <limits.h>
#include "file_error_numbers.h"
// Define a debug macro
#if (defined(_DEBUG) || defined(DEBUG)) && !defined(ETL_DEBUG)
#define ETL_DEBUG

View File

@ -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 <typename T>
T* allocate()
{
if (sizeof(T) > ITEM_SIZE)
{
ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size));
}
return reinterpret_cast<T*>(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 <typename T>
T* create()
{
T* p = allocate<T>();
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 <typename T, typename T1>
T* create(const T1& value1)
{
T* p = allocate<T>();
if (p)
{
::new (p) T(value1);
}
return p;
}
template <typename T, typename T1, typename T2>
T* create(const T1& value1, const T2& value2)
{
T* p = allocate<T>();
if (p)
{
::new (p) T(value1, value2);
}
return p;
}
template <typename T, typename T1, typename T2, typename T3>
T* create(const T1& value1, const T2& value2, const T3& value3)
{
T* p = allocate<T>();
if (p)
{
::new (p) T(value1, value2, value3);
}
return p;
}
template <typename T, typename T1, typename T2, typename T3, typename T4>
T* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
{
T* p = allocate<T>();
if (p)
{
::new (p) T(value1, value2, value3, value4);
}
return p;
}
#else
//*************************************************************************
/// Emplace with variadic constructor parameters.
//*************************************************************************
template <typename T, typename... Args>
T* create(Args&&... args)
{
T* p = allocate<T>();
if (p)
{
::new (p) T(etl::forward<Args>(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 <typename T>
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 <b>true<\b> if it does, otherwise <b>false</b>
//*************************************************************************
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 <b>true</b> 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 <b>true</b> 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<char**>(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<char**>(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<uintptr_t>(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 <const size_t TYPE_SIZE_, const size_t ALIGNMENT_, const size_t SIZE_>
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<char*>(&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 <typename U>
U* allocate()
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return ipool::allocate<U>();
}
#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 <typename U>
U* create()
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return ipool::create<U>();
}
//*************************************************************************
/// 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 <typename U, typename T1>
U* create(const T1& value1)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return ipool::create<U>(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 <typename U, typename T1, typename T2>
U* create(const T1& value1, const T2& value2)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return ipool::create<U>(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 <typename U, typename T1, typename T2, typename T3>
U* create(const T1& value1, const T2& value2, const T3& value3)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return ipool::create<U>(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 <typename U, typename T1, typename T2, typename T3, typename T4>
U* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return ipool::create<U>(value1, value2, value3, value4);
}
#else
//*************************************************************************
/// Emplace with variadic constructor parameters.
//*************************************************************************
template <typename U, typename... Args>
U* create(Args&&... args)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return ipool::create<U>(etl::forward<Args>(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 <typename U>
void destroy(const U* const p_object)
{
ETL_STATIC_ASSERT(etl::alignment_of<U>::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<ALIGNMENT_>::type dummy; ///< Dummy item to get correct alignment.
};
///< The memory for the pool of objects.
typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::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 <typename T, const size_t SIZE_>
class pool : public etl::generic_pool<sizeof(T), etl::alignment_of<T>::value, SIZE_>
template <typename T, const size_t VSize>
class pool : public etl::generic_pool<sizeof(T), etl::alignment_of<T>::value, VSize>
{
private:
typedef etl::generic_pool<sizeof(T), etl::alignment_of<T>::value, SIZE_> base_t;
typedef etl::generic_pool<sizeof(T), etl::alignment_of<T>::value, VSize> base_t;
public:

View File

@ -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 <typename TMessage, typename TCounter>
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<TMessage, TCounter> 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 <typename TMessage>
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<TMessage> rc_object; ///< The reference counted object.
};
@ -188,7 +197,7 @@ namespace etl
/// \tparam TObject The type to be reference counted.
//***************************************************************************
template <typename TMessage>
using atomic_counted_message = etl::reference_counted_message<TMessage, etl::atomic_int32_t>;
using atomic_counted_message = etl::pool_message<TMessage, etl::atomic_int32_t>;
#endif
}

View File

@ -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 <typename TMessage>
etl::ireference_counted_message* allocate(const TMessage& message)
etl::ipool_message* allocate(const TMessage& message)
{
ETL_STATIC_ASSERT((etl::is_base_of<etl::imessage, TMessage>::value), "Not a message type");
typedef etl::reference_counted_message<TMessage, TCounter> rcm_t;
typedef etl::pool_message<TMessage, TCounter> 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<prcm_t>(memory_block_pool.allocate_memory_block(sizeof(rcm_t)));
p = static_cast<prcm_t>(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 <typename TMessage1, typename... TMessages>
struct pool_message_size
{
release(&msg);
}
private:
// Size of the first pool message type.
static constexpr size_t size1 = sizeof(etl::pool_message<TMessage1, TCounter>);
// Maximum size of the the rest of the pool message types.
static constexpr size_t size2 = pool_message_size<TMessages...>::size;
// Size of the first pool message type.
static constexpr size_t alignment1 = etl::alignment_of<etl::pool_message<TMessage1, TCounter>>::value;
// Maximum size of the the rest of the pool message types.
static constexpr size_t alignment2 = pool_message_size<TMessages...>::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 <typename TMessage1>
struct pool_message_size<TMessage1>
{
public:
ETL_STATIC_ASSERT((etl::is_base_of<etl::imessage, TMessage1>::value), "TMessage not derived from etl::imessage");
// The size of this pool message type.
static constexpr size_t size = sizeof(etl::pool_message<TMessage1, TCounter>);
// The maximum alignment.
static constexpr size_t alignment = etl::alignment_of<etl::pool_message<TMessage1, TCounter>>::value;
};
#else
template <typename TMessage>
struct pool_message_size
{
static const size_t size = sizeof(etl::pool_message<TMessage, TCounter>);
static const size_t alignment = etl::alignment_of<etl::pool_message<TMessage, TCounter> >::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<etl::atomic_int>;
#endif
}
#undef ETL_FILE

View File

@ -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;
};

View File

@ -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 <typename TPool, typename TMessage>
shared_message(TPool& owner, const TMessage& message)
{
ETL_STATIC_ASSERT((etl::is_base_of<etl::ireference_counted_message_pool, TPool>::value), "TPool not derived from etl::ireference_counted_message_pool");
ETL_STATIC_ASSERT((etl::is_base_of<etl::imessage, TMessage>::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 <typename TPool, typename TMessage>
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 <typename TMessage, typename TPool, typename... TArgs>
etl::shared_message make_shared_message(TPool& owner, TArgs&&... args)
{
etl::ireference_counted_message* p_rcmessage = owner.allocate(TMessage(etl::forward<TArgs>(args)...));
return etl::shared_message(*p_rcmessage);
}
#endif
}
#endif

View File

@ -54,7 +54,7 @@ SOFTWARE.
#include <stdint.h>
#include "platform.h"
#include "generic_pool.h"
#include "pool.h"
#include "type_traits.h"
#include "static_assert.h"
#include "largest.h"

View File

@ -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<MESSAGE1>
{
};
//*************************************************************************
struct Message2 : public etl::message<MESSAGE2>
{
};
//*************************************************************************
struct Router1 : public etl::message_router<Router1, Message1, Message2>
{
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, Message1, Message2>
{
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<etl::shared_message, 10> smqueue;
};
Router router;
Processor processor(router);
SUITE(test_shared_message)
{
constexpr size_t POOL_SIZE = 2;
etl::variant_pool<POOL_SIZE, Message1> 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<Message1>());
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<Message1>());
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<Message1, 2> 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());
//}
}

View File

@ -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<MessageId1>
{
Message1(int i_)
: i(i_)
{
}
~Message1()
{
}
int i;
};
//*************************************************************************
struct Message2 : public etl::message<MessageId2>
{
~Message2()
{
}
};
//*************************************************************************
struct Router1 : public etl::message_router<Router1, Message1, Message2>
{
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, Message1>
{
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<Message1, Message2>;
etl::fixed_sized_memory_block_allocator<pool_message_parameters::size,
pool_message_parameters::alignment,
4U> 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<Message2> 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);
}
}
}

View File

@ -1272,6 +1272,7 @@
<ClInclude Include="..\..\include\etl\cumulative_moving_average.h" />
<ClInclude Include="..\..\include\etl\delegate.h" />
<ClInclude Include="..\..\include\etl\delegate_service.h" />
<ClInclude Include="..\..\include\etl\file_error_numbers.h" />
<ClInclude Include="..\..\include\etl\flags.h" />
<ClInclude Include="..\..\include\etl\format_spec.h" />
<ClInclude Include="..\..\include\etl\frame_check_sequence.h" />
@ -1293,7 +1294,7 @@
<ClInclude Include="..\..\include\etl\ireference_counted_message_pool.h" />
<ClInclude Include="..\..\include\etl\limits.h" />
<ClInclude Include="..\..\include\etl\macros.h" />
<ClInclude Include="..\..\include\etl\fixed_sized_memory_block_pool.h" />
<ClInclude Include="..\..\include\etl\fixed_sized_memory_block_allocator.h" />
<ClInclude Include="..\..\include\etl\message_packet.h" />
<ClInclude Include="..\..\include\etl\message_pool.h" />
<ClInclude Include="..\..\include\etl\multi_array.h" />
@ -1333,7 +1334,6 @@
<ClInclude Include="..\..\include\etl\reference_counted_object.h" />
<ClInclude Include="..\..\include\etl\scaled_rounding.h" />
<ClInclude Include="..\..\include\etl\shared_message.h" />
<ClInclude Include="..\..\include\etl\shared_message_processor.h" />
<ClInclude Include="..\..\include\etl\span.h" />
<ClInclude Include="..\..\include\etl\state_chart.h" />
<ClInclude Include="..\..\include\etl\math_constants.h" />
@ -1915,7 +1915,7 @@
<ClCompile Include="..\test_parity_checksum.cpp" />
<ClCompile Include="..\test_pearson.cpp" />
<ClCompile Include="..\test_pool.cpp" />
<ClCompile Include="..\test_pool_message.cpp" />
<ClCompile Include="..\test_shared_message.cpp" />
<ClCompile Include="..\test_priority_queue.cpp" />
<ClCompile Include="..\test_queue.cpp" />
<ClCompile Include="..\test_queue_memory_model_small.cpp" />
@ -2021,7 +2021,6 @@
</ItemGroup>
<ItemGroup>
<Text Include="..\..\CMakeLists.txt" />
<Text Include="..\..\include\etl\file_error_numbers.txt" />
<Text Include="..\..\support\Release notes.txt" />
<Text Include="..\..\todo.txt" />
<Text Include="..\CMakeLists.txt" />

View File

@ -909,18 +909,9 @@
<ClInclude Include="..\..\include\etl\multi_range.h">
<Filter>ETL\Utilities</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\ipool.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\message_pool.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\shared_message.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\shared_message_processor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\ireference_counted_message_pool.h">
<Filter>ETL\Frameworks</Filter>
</ClInclude>
@ -930,13 +921,22 @@
<ClInclude Include="..\..\include\etl\reference_counted_message_pool.h">
<Filter>ETL\Frameworks</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\reference_counted_object.h">
<Filter>ETL\Frameworks</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\fixed_sized_memory_block_pool.h">
<ClInclude Include="..\..\include\etl\generic_pool.h">
<Filter>ETL\Containers</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\generic_pool.h">
<ClInclude Include="..\..\include\etl\ipool.h">
<Filter>ETL\Containers</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\file_error_numbers.h">
<Filter>ETL\Utilities</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\shared_message.h">
<Filter>ETL\Frameworks</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\reference_counted_object.h">
<Filter>ETL\Utilities</Filter>
</ClInclude>
<ClInclude Include="..\..\include\etl\fixed_sized_memory_block_allocator.h">
<Filter>ETL\Containers</Filter>
</ClInclude>
</ItemGroup>
@ -1475,7 +1475,7 @@
<ClCompile Include="..\test_multi_range.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\test_pool_message.cpp">
<ClCompile Include="..\test_shared_message.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
@ -1560,9 +1560,6 @@
</None>
</ItemGroup>
<ItemGroup>
<Text Include="..\..\include\etl\file_error_numbers.txt">
<Filter>Resource Files</Filter>
</Text>
<Text Include="..\..\support\Release notes.txt">
<Filter>Resource Files</Filter>
</Text>