diff --git a/include/etl/fixed_sized_memory_block_allocator.h b/include/etl/fixed_sized_memory_block_allocator.h index 93b97836..0c37666e 100644 --- a/include/etl/fixed_sized_memory_block_allocator.h +++ b/include/etl/fixed_sized_memory_block_allocator.h @@ -7,7 +7,7 @@ Embedded Template Library. https://github.com/ETLCPP/etl https://www.etlcpp.com -Copyright(c) 2017 jwellbelove +Copyright(c) 2021 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 @@ -32,7 +32,7 @@ SOFTWARE. #define ETL_FIXED_MEMORY_BLOCK_POOL_INCLUDED #include "platform.h" -#include "memory.h" +#include "imemory_block_allocator.h" #include "generic_pool.h" #include "alignment.h" @@ -42,23 +42,19 @@ namespace etl /// The fixed sized memory block pool. /// The allocated memory blocks are all the same size. //************************************************************************* - template + template class fixed_sized_memory_block_allocator : public imemory_block_allocator { public: - //************************************************************************* - /// Default contsrcutor - //************************************************************************* - fixed_sized_memory_block_allocator() - { - } + static ETL_CONSTANT size_t Block_Size = VBlock_Size; + static ETL_CONSTANT size_t Alignment = VAlignment; + static ETL_CONSTANT size_t Size = VSize; //************************************************************************* - /// Construct with a successor allocator. + /// Default constructor //************************************************************************* - fixed_sized_memory_block_allocator(etl::imemory_block_allocator& successor) - : imemory_block_allocator(successor) + fixed_sized_memory_block_allocator() { } @@ -75,7 +71,7 @@ namespace etl //************************************************************************* virtual void* allocate_block(size_t required_size) ETL_OVERRIDE { - if (required_size <= Block_Size) + if ((required_size <= Block_Size) && !pool.full()) { return pool.template allocate(); } diff --git a/include/etl/imemory_block_allocator.h b/include/etl/imemory_block_allocator.h new file mode 100644 index 00000000..f717e3e2 --- /dev/null +++ b/include/etl/imemory_block_allocator.h @@ -0,0 +1,134 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +https://www.etlcpp.com + +Copyright(c) 2021 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_MEMORY_BLOCK_ALLOCATOR_INCLUDED +#define ETL_MEMORY_BLOCK_ALLOCATOR_INCLUDED + +#include "platform.h" +#include "nullptr.h" + +namespace etl +{ + //***************************************************************************** + /// The interface for a memory block pool. + //***************************************************************************** + class imemory_block_allocator + { + public: + + //***************************************************************************** + /// Default constructor. + //***************************************************************************** + imemory_block_allocator() + : p_successor(ETL_NULLPTR) + { + } + + //***************************************************************************** + /// 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) + { + bool successful = release_block(p); + + // Call the derived implementation to try to release. + if (!successful) + { + // If it failed and we have a successor... + if (has_successor()) + { + // Try to release from the next one in the chain. + successful = get_successor().release(p); + } + } + + return successful; + } + + //***************************************************************************** + /// 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; + }; +} + +#endif diff --git a/include/etl/memory.h b/include/etl/memory.h index 54bb70fd..72bf2a92 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -1900,106 +1900,6 @@ namespace etl } }; - //***************************************************************************** - /// The interface for a memory block pool. - //***************************************************************************** - class imemory_block_allocator - { - 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. ///\ingroup alignment diff --git a/include/etl/reference_counted_message.h b/include/etl/reference_counted_message.h index 535b8d05..38efed9f 100644 --- a/include/etl/reference_counted_message.h +++ b/include/etl/reference_counted_message.h @@ -5,7 +5,7 @@ Embedded Template Library. https://github.com/ETLCPP/etl https://www.etlcpp.com -Copyright(c) 2017 jwellbelove +Copyright(c) 2021 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 diff --git a/include/etl/reference_counted_object.h b/include/etl/reference_counted_object.h index 9eef59e1..103306ba 100644 --- a/include/etl/reference_counted_object.h +++ b/include/etl/reference_counted_object.h @@ -5,7 +5,7 @@ //https://github.com/ETLCPP/etl //https://www.etlcpp.com // -//Copyright(c) 2020 jwellbelove +//Copyright(c) 2021 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 diff --git a/test/test_fixed_sized_memory_block_allocator.cpp b/test/test_fixed_sized_memory_block_allocator.cpp new file mode 100644 index 00000000..b99421bd --- /dev/null +++ b/test/test_fixed_sized_memory_block_allocator.cpp @@ -0,0 +1,144 @@ +/****************************************************************************** +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/fixed_sized_memory_block_allocator.h" + +namespace +{ + using Allocator8 = etl::fixed_sized_memory_block_allocator; + using Allocator16 = etl::fixed_sized_memory_block_allocator; + using Allocator32 = etl::fixed_sized_memory_block_allocator; + + SUITE(test_fixed_sized_memory_block_allocator) + { + //************************************************************************* + TEST(test_allocator_no_successor_use_all_allocation) + { + Allocator16 allocator16; + + int16_t* p1 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p2 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p3 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p4 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p5 = static_cast(allocator16.allocate(sizeof(int16_t))); + + CHECK(p1 != nullptr); + CHECK(p2 != nullptr); + CHECK(p3 != nullptr); + CHECK(p4 != nullptr); + CHECK(p5 == nullptr); + + CHECK(allocator16.release(p1)); + CHECK(allocator16.release(p2)); + CHECK(allocator16.release(p3)); + CHECK(allocator16.release(p4)); + CHECK(!allocator16.release(p5)); + } + + //************************************************************************* + TEST(test_allocator_has_successors) + { + Allocator16 allocator16; + Allocator16 allocator16s; + Allocator16 allocator16ss; + + allocator16.set_successor(allocator16s); + allocator16s.set_successor(allocator16ss); + + CHECK(allocator16.has_successor() == true); + CHECK(allocator16s.has_successor() == true); + CHECK(allocator16ss.has_successor() == false); + } + + //************************************************************************* + TEST(test_allocator_with_successors_use_all_allocation) + { + Allocator16 allocator16; + Allocator16 allocator16s; + Allocator16 allocator16ss; + + allocator16.set_successor(allocator16s); + allocator16s.set_successor(allocator16ss); + + int16_t* p1 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p2 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p3 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p4 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p5 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p6 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p7 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p8 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p9 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p10 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p11 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p12 = static_cast(allocator16.allocate(sizeof(int16_t))); + int16_t* p13 = static_cast(allocator16.allocate(sizeof(int16_t))); + + CHECK(p1 != nullptr); + CHECK(p2 != nullptr); + CHECK(p3 != nullptr); + CHECK(p4 != nullptr); + CHECK(p5 != nullptr); + CHECK(p6 != nullptr); + CHECK(p7 != nullptr); + CHECK(p8 != nullptr); + CHECK(p9 != nullptr); + CHECK(p10 != nullptr); + CHECK(p11 != nullptr); + CHECK(p12 != nullptr); + CHECK(p13 == nullptr); + + CHECK(allocator16.release(p1)); + CHECK(allocator16.release(p2)); + CHECK(allocator16.release(p3)); + CHECK(allocator16.release(p4)); + CHECK(allocator16.release(p5)); + CHECK(allocator16.release(p6)); + CHECK(allocator16.release(p7)); + CHECK(allocator16.release(p8)); + CHECK(allocator16.release(p9)); + CHECK(allocator16.release(p10)); + CHECK(allocator16.release(p11)); + CHECK(allocator16.release(p12)); + CHECK(!allocator16.release(p13)); + } + + //************************************************************************* + TEST(test_allocator_with_different_block_sized_successors_use_all_allocation) + { + Allocator8 allocator8; + Allocator16 allocator16; + Allocator32 allocator32; + + allocator8.set_successor(allocator16); + allocator16.set_successor(allocator32); + } + } +} diff --git a/test/vs2019/etl.vcxproj b/test/vs2019/etl.vcxproj index 9e2c1fb4..8cf2cfd6 100644 --- a/test/vs2019/etl.vcxproj +++ b/test/vs2019/etl.vcxproj @@ -1528,6 +1528,7 @@ + diff --git a/test/vs2019/etl.vcxproj.filters b/test/vs2019/etl.vcxproj.filters index 0e2e86fb..3c9c1d47 100644 --- a/test/vs2019/etl.vcxproj.filters +++ b/test/vs2019/etl.vcxproj.filters @@ -1478,6 +1478,9 @@ Source Files + + Source Files +