From 1c4f0596a93c4f6ce790d603cd8753230f1c5ea8 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sun, 11 Feb 2018 17:25:40 +0000 Subject: [PATCH] Added 'create' and 'destroy' functions --- src/pool.h | 423 ++++++++++++++++++++++++++++++++++++++------- test/test_pool.cpp | 172 ++++++++++++++++++ 2 files changed, 536 insertions(+), 59 deletions(-) diff --git a/src/pool.h b/src/pool.h index 01ff1a13..36bf99b6 100644 --- a/src/pool.h +++ b/src/pool.h @@ -32,13 +32,13 @@ SOFTWARE. #define __ETL_POOL__ #include "platform.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 "error_handler.h" #include "static_assert.h" #include @@ -47,6 +47,8 @@ SOFTWARE. #undef ETL_FILE #define ETL_FILE "11" +#define ETL_POOL_CPP03_CODE 0 + //***************************************************************************** ///\defgroup pool pool /// A fixed capacity pool. @@ -117,8 +119,7 @@ namespace etl typedef size_t size_type; //************************************************************************* - /// Allocate an object from the pool. - /// Uses the default constructor. + /// 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 nullptr is returned. //************************************************************************* @@ -133,13 +134,138 @@ namespace etl return reinterpret_cast(allocate_item()); } +#if !ETL_CPP11_SUPPORTED || ETL_POOL_CPP03_CODE + //************************************************************************* + /// 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 nullptr is returned. + //************************************************************************* + template + T* create() + { + T* p = allocate(); + + if (p) + { + ::new (p) T(); + } + + return p; + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 1 parameter. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template + T* create(const T1& value1) + { + T* p = allocate(); + + if (p) + { + ::new (p) T(value1); + } + + return p; + } + + //************************************************************************* + /// 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 nullptr is returned. + //************************************************************************* + template + T* create(const T1& value1, const T2& value2) + { + T* p = allocate(); + + if (p) + { + ::new (p) T(value1, value2); + } + + return p; + } + + //************************************************************************* + /// 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 nullptr is returned. + //************************************************************************* + template + T* create(const T1& value1, const T2& value2, const T3& value3) + { + T* p = allocate(); + + if (p) + { + ::new (p) T(value1, value2, value3); + } + + return p; + } + + //************************************************************************* + /// 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 nullptr is returned. + //************************************************************************* + template + T* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + T* p = allocate(); + + if (p) + { + ::new (p) T(value1, value2, value3, value4); + } + + return p; + } +#else + //************************************************************************* + /// Emplace with variadic constructor parameters. + //************************************************************************* + template + T* create(Args&&... args) + { + T* p = allocate(); + + if (p) + { + ::new (p) T(std::forward(args)...); + } + + return p; + } +#endif + + //************************************************************************* + /// Destroys the object. + /// Undefined behaviour if the pool does not contain a 'T'. + /// \param p_object A pointer to the object to be destroyed. + //************************************************************************* + template + void destroy(const void* const p_object) + { + if (sizeof(T) > ITEM_SIZE) + { + ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size)); + } + + reinterpret_cast((const_cast(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* p_object) + void release(const void* const p_object) { release_item((char*)p_object); } @@ -259,7 +385,7 @@ namespace etl } else { - ETL_ASSERT(false, ETL_ERROR(etl::pool_no_allocation)); + ETL_ASSERT(false, ETL_ERROR(pool_no_allocation)); } return p_value; @@ -338,59 +464,6 @@ namespace etl #endif }; - //************************************************************************* - /// A templated pool implementation that uses a fixed size pool. - ///\ingroup pool - //************************************************************************* - template - class pool : public etl::ipool - { - public: - - static const size_t SIZE = SIZE_; - - //************************************************************************* - /// Constructor - //************************************************************************* - pool() - : etl::ipool(reinterpret_cast(&buffer[0]), ELEMENT_SIZE, SIZE) - { - } - - //************************************************************************* - /// Allocate an object from the pool. - /// Uses the default constructor. - /// If asserts or exceptions are enabled and there are no more free items an - /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. - /// Static asserts if the specified type is too large for the pool. - //************************************************************************* - template - U* allocate() - { - STATIC_ASSERT(sizeof(U) <= ELEMENT_SIZE, "Type too large for pool"); - return ipool::allocate(); - } - - private: - - // The pool element. - union Element - { - uintptr_t next; ///< Pointer to the next free element. - char value[sizeof(T)]; ///< Storage for value type. - typename etl::type_with_alignment::value>::type dummy; ///< Dummy item to get correct alignment. - }; - - ///< The memory for the pool of objects. - typename etl::aligned_storage::value>::type buffer[SIZE]; - - static const uint32_t ELEMENT_SIZE = sizeof(Element); - - // Should not be copied. - pool(const pool&); - pool& operator =(const pool&); - }; - //************************************************************************* /// A templated abstract pool implementation that uses a fixed size pool. ///\ingroup pool @@ -422,10 +495,102 @@ namespace etl U* allocate() { STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); - STATIC_ASSERT(sizeof(U) <= ELEMENT_SIZE, "Type too large for pool"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); return ipool::allocate(); } +#if !ETL_CPP11_SUPPORTED || ETL_POOL_CPP03_CODE + //************************************************************************* + /// 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 nullptr is returned. + //************************************************************************* + template + U* create() + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 1 parameter. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template + U* create(const T1& value1) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(value1); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 2 parameters. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template + U* create(const T1& value1, const T2& value2) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(value1, value2); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 3 parameters. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template + U* create(const T1& value1, const T2& value2, const T3& value3) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(value1, value2, value3); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 4 parameters. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template + U* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(value1, value2, value3, value4); + } +#else + //************************************************************************* + /// Emplace with variadic constructor parameters. + //************************************************************************* + template + U* create(Args&&... args) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return ipool::create(std::forward(args)...); + } +#endif + + //************************************************************************* + /// Destroys the object. + /// Undefined behaviour if the pool does not contain a 'U'. + /// \param p_object A pointer to the object to be destroyed. + //************************************************************************* + template + void destroy(const void* const p_object) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT_, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + reinterpret_cast((const_cast(p_object)))->~U(); + ipool::release(p_object); + } + private: // The pool element. @@ -445,6 +610,146 @@ namespace etl generic_pool(const generic_pool&); generic_pool& operator =(const generic_pool&); }; + + //************************************************************************* + /// A templated pool implementation that uses a fixed size pool. + ///\ingroup pool + //************************************************************************* + template + class pool : public etl::generic_pool::value, SIZE_> + { + private: + + typedef etl::generic_pool::value, SIZE_> base_t; + + public: + + static const size_t SIZE = base_t::SIZE; + static const size_t ALIGNMENT = base_t::ALIGNMENT; + static const size_t TYPE_SIZE = base_t::TYPE_SIZE; + + //************************************************************************* + /// Constructor + //************************************************************************* + pool() + { + } + + //************************************************************************* + /// Allocate an object from the pool. + /// Uses the default constructor. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + /// Static asserts if the specified type is too large for the pool. + //************************************************************************* + template + U* allocate() + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return base_t::template allocate(); + } + +#if !ETL_CPP11_SUPPORTED || ETL_POOL_CPP03_CODE + //************************************************************************* + /// 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 nullptr is returned. + //************************************************************************* + template + U* create() + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return base_t::template create(); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 1 parameter. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template + U* create(const T1& value1) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return base_t::template create(value1); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 2 parameters. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template + U* create(const T1& value1, const T2& value2) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return base_t::template create(value1, value2); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 3 parameters. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template + U* create(const T1& value1, const T2& value2, const T3& value3) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return base_t::template create(value1, value2, value3); + } + + //************************************************************************* + /// Allocate storage for an object from the pool and create with 4 parameters. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template + U* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return base_t::template create(value1, value2, value3, value4); + } +#else + //************************************************************************* + /// Allocate storage for an object from the pool and create with variadic parameters. + /// If asserts or exceptions are enabled and there are no more free items an + /// etl::pool_no_allocation if thrown, otherwise a nullptr is returned. + //************************************************************************* + template + U* create(Args&&... args) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + return base_t::template create(std::forward(args)...); + } +#endif + + //************************************************************************* + /// Destroys the object. + /// Undefined behaviour if the pool does not contain a 'U'. + /// \param p_object A pointer to the object to be destroyed. + //************************************************************************* + template + void destroy(const void* const p_object) + { + STATIC_ASSERT(etl::alignment_of::value <= ALIGNMENT, "Type has incompatible alignment"); + STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool"); + reinterpret_cast((const_cast(p_object)))->~U(); + base_t::release(p_object); + } + + private: + + // Should not be copied. + pool(const pool&); + pool& operator =(const pool&); + }; } #undef ETL_FILE diff --git a/test/test_pool.cpp b/test/test_pool.cpp index ecb15282..d4fd49e5 100644 --- a/test/test_pool.cpp +++ b/test/test_pool.cpp @@ -33,6 +33,7 @@ SOFTWARE. #include #include +#include #include "pool.h" #include "largest.h" @@ -47,6 +48,119 @@ typedef TestDataNDC Test_Data2; namespace { + struct D0 + { + D0() + { + } + }; + + struct D1 + { + D1(const std::string& a_) + : a(a_) + { + } + + std::string a; + }; + + struct D2 + { + D2(const std::string& a_, const std::string& b_) + : a(a_), + b(b_) + { + } + + std::string a; + std::string b; + }; + + struct D3 + { + D3(const std::string& a_, const std::string& b_, const std::string& c_) + : a(a_), + b(b_), + c(c_) + { + } + + std::string a; + std::string b; + std::string c; + }; + + struct D4 + { + D4(const std::string& a_, const std::string& b_, const std::string& c_, const std::string& d_) + : a(a_), + b(b_), + c(c_), + d(d_) + { + } + + std::string a; + std::string b; + std::string c; + std::string d; + }; + + bool operator == (const D0& lhs, const D0& rhs) + { + return true; + } + + bool operator == (const D1& lhs, const D1& rhs) + { + return (lhs.a == rhs.a); + } + + bool operator == (const D2& lhs, const D2& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b); + } + + bool operator == (const D3& lhs, const D3& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c); + } + + bool operator == (const D4& lhs, const D4& rhs) + { + return (lhs.a == rhs.a) && (lhs.b == rhs.b) && (lhs.c == rhs.c) && (lhs.d == rhs.d); + } + + std::ostream& operator <<(std::ostream& os, const D0& d) + { + return os; + } + + std::ostream& operator <<(std::ostream& os, const D1& d) + { + os << d.a; + return os; + } + + std::ostream& operator <<(std::ostream& os, const D2& d) + { + os << d.a << " " << d.b; + return os; + } + + std::ostream& operator <<(std::ostream& os, const D3& d) + { + os << d.a << " " << d.b << " " << d.c; + return os; + } + + std::ostream& operator <<(std::ostream& os, const D4& d) + { + os << d.a << " " << d.b << " " << d.c << " " << d.d; + return os; + } + SUITE(test_pool) { //************************************************************************* @@ -294,6 +408,64 @@ namespace CHECK_NO_THROW(p4 = pool.allocate()); } }; + + //************************************************************************* + TEST(test_create_destroy) + { + etl::pool pool0; + etl::pool pool1; + etl::pool pool2; + etl::pool pool3; + etl::pool pool4; + + D0* p0 = pool0.create(); + D1* p1 = pool1.create("1"); + D2* p2 = pool2.create("1", "2"); + D3* p3 = pool3.create("1", "2", "3"); + D4* p4 = pool4.create("1", "2", "3", "4"); + + CHECK_EQUAL(pool0.max_size() - 1, pool0.available()); + CHECK_EQUAL(1, pool0.size()); + + CHECK_EQUAL(pool1.max_size() - 1, pool1.available()); + CHECK_EQUAL(1, pool1.size()); + + CHECK_EQUAL(pool2.max_size() - 1, pool2.available()); + CHECK_EQUAL(1, pool2.size()); + + CHECK_EQUAL(pool3.max_size() - 1, pool3.available()); + CHECK_EQUAL(1, pool3.size()); + + CHECK_EQUAL(pool4.max_size() - 1, pool4.available()); + CHECK_EQUAL(1, pool4.size()); + + CHECK_EQUAL(D0(), *p0); + CHECK_EQUAL(D1("1"), *p1); + CHECK_EQUAL(D2("1", "2"), *p2); + CHECK_EQUAL(D3("1", "2", "3"), *p3); + CHECK_EQUAL(D4("1", "2", "3", "4"), *p4); + + pool0.destroy(p0); + pool1.destroy(p1); + pool2.destroy(p2); + pool3.destroy(p3); + pool4.destroy(p4); + + CHECK_EQUAL(pool0.max_size(), pool0.available()); + CHECK_EQUAL(0, pool0.size()); + + CHECK_EQUAL(pool1.max_size(), pool1.available()); + CHECK_EQUAL(0, pool1.size()); + + CHECK_EQUAL(pool2.max_size(), pool2.available()); + CHECK_EQUAL(0, pool2.size()); + + CHECK_EQUAL(pool3.max_size(), pool3.available()); + CHECK_EQUAL(0, pool3.size()); + + CHECK_EQUAL(pool4.max_size(), pool4.available()); + CHECK_EQUAL(0, pool4.size()); + } } #if defined(ETL_COMPILER_GCC)