Feature/pool ext variant pool ext (#433)

* added threads dependency to meson build because of pthread linkage problems (gcc version Debian 8.3.0-6)

* initial version of generic_pool_ext, pool_ext and variant_pool_ext (extended unit tests)

* format code

* fix test_call_if_and_not_valid_returning_void by moving SetupFixture into namespace (to ensure correct test setup)

Co-authored-by: Daniel B <daniel-brosche@users.noreply.github.com>
This commit is contained in:
Daniel B 2021-10-01 19:46:52 +02:00 committed by GitHub
parent a6d8a6d1ef
commit 494059fd6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 1210 additions and 13 deletions

View File

@ -194,7 +194,140 @@ namespace etl
generic_pool& operator =(const generic_pool&);
};
template <const size_t VTypeSize, const size_t VAlignment>
class generic_pool_ext : public etl::ipool {
private:
// The pool element.
union element_internal {
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.
};
static const size_t ELEMENT_INTERNAL_SIZE = sizeof(element_internal);
public:
static ETL_CONSTANT size_t ALIGNMENT = VAlignment;
static ETL_CONSTANT size_t TYPE_SIZE = VTypeSize;
using element = typename etl::aligned_storage<sizeof(element_internal), etl::alignment_of<element_internal>::value>::type;
//*************************************************************************
/// Constructor
//*************************************************************************
generic_pool_ext(element* buffer, size_t size) : etl::ipool(reinterpret_cast<char*>(&buffer[0]), ELEMENT_INTERNAL_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 <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "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 <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "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 <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "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 <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "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 <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "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 <= 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
//*************************************************************************
/// Emplace with variadic constructor parameters.
//*************************************************************************
template <typename U, typename... Args>
U* create(Args&&... args)
{
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
//*************************************************************************
/// 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 <= VAlignment, "Type has incompatible alignment");
ETL_STATIC_ASSERT(sizeof(U) <= VTypeSize, "Type too large for pool");
p_object->~U();
ipool::release(p_object);
}
private:
// Should not be copied.
generic_pool_ext(const generic_pool_ext&);
generic_pool_ext& operator=(const generic_pool_ext&);
};
}
#endif

View File

@ -178,6 +178,123 @@ namespace etl
pool(const pool&) ETL_DELETE;
pool& operator =(const pool&) ETL_DELETE;
};
template <typename T>
class pool_ext : public etl::generic_pool_ext<sizeof(T), etl::alignment_of<T>::value> {
private:
typedef etl::generic_pool_ext<sizeof(T), etl::alignment_of<T>::value> base_t;
public:
using base_t::ALIGNMENT;
using base_t::TYPE_SIZE;
//*************************************************************************
/// Constructor
//*************************************************************************
pool_ext(typename base_t::element* buffer, size_t size) : base_t(buffer, 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 null pointer is returned.
/// Static asserts if the specified type is too large for the pool.
//*************************************************************************
T* allocate() { return base_t::template allocate<T>(); }
#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.
//*************************************************************************
T* create() { return base_t::template create<T>(); }
//*************************************************************************
/// 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 T1>
T* create(const T1& value1)
{
return base_t::template create<T>(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 T1, typename T2>
T* create(const T1& value1, const T2& value2)
{
return base_t::template create<T>(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 T1, typename T2, typename T3>
T* create(const T1& value1, const T2& value2, const T3& value3)
{
return base_t::template create<T>(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 T1, typename T2, typename T3, typename T4>
T* create(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
{
return base_t::template create<T>(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 null pointer is returned.
//*************************************************************************
template <typename... Args>
T* create(Args&&... args)
{
return base_t::template create<T>(etl::forward<Args>(args)...);
}
#endif
//*************************************************************************
/// Releases the object.
/// Undefined behaviour if the pool does not contain a 'U' object derived from 'U'.
/// \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::is_same<U, T>::value || etl::is_base_of<U, T>::value), "Pool does not contain this type");
base_t::release(p_object);
}
//*************************************************************************
/// Destroys the object.
/// Undefined behaviour if the pool does not contain a 'U' object derived from '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::is_base_of<U, T>::value), "Pool does not contain this type");
base_t::destroy(p_object);
}
private:
// Should not be copied.
pool_ext(const pool_ext&) ETL_DELETE;
pool_ext& operator=(const pool_ext&) ETL_DELETE;
};
}
#endif

View File

@ -206,6 +206,132 @@ namespace etl
variant_pool(const variant_pool&) ETL_DELETE;
variant_pool& operator =(const variant_pool&) ETL_DELETE;
};
//***************************************************************************
template <typename T1,
typename T2 = void,
typename T3 = void,
typename T4 = void,
typename T5 = void,
typename T6 = void,
typename T7 = void,
typename T8 = void,
typename T9 = void,
typename T10 = void,
typename T11 = void,
typename T12 = void,
typename T13 = void,
typename T14 = void,
typename T15 = void,
typename T16 = void>
class variant_pool_ext
: public etl::generic_pool_ext<etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::size,
etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::alignment> {
public:
typedef etl::generic_pool_ext<etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::size,
etl::largest<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::alignment>
base_t;
//*************************************************************************
/// Default constructor.
//*************************************************************************
variant_pool_ext(typename base_t::element* buffer, size_t size) : base_t(buffer, size) {}
#if ETL_CPP11_NOT_SUPPORTED || ETL_USING_STLPORT
//*************************************************************************
/// Creates the object. Default constructor.
//*************************************************************************
template <typename T>
T* create()
{
ETL_STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
return base_t::template create<T>();
}
//*************************************************************************
/// Creates the object. One parameter constructor.
//*************************************************************************
template <typename T, typename TP1>
T* create(const TP1& p1)
{
ETL_STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
return base_t::template create<T>(p1);
}
//*************************************************************************
/// Creates the object. Two parameter constructor.
//*************************************************************************
template <typename T, typename TP1, typename TP2>
T* create(const TP1& p1, const TP2& p2)
{
ETL_STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
return base_t::template create<T>(p1, p2);
}
//*************************************************************************
/// Creates the object. Three parameter constructor.
//*************************************************************************
template <typename T, typename TP1, typename TP2, typename TP3>
T* create(const TP1& p1, const TP2& p2, const TP3& p3)
{
ETL_STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
return base_t::template create<T>(p1, p2, p3);
}
//*************************************************************************
/// Creates the object. Four parameter constructor.
//*************************************************************************
template <typename T, typename TP1, typename TP2, typename TP3, typename TP4>
T* create(const TP1& p1, const TP2& p2, const TP3& p3, const TP4& p4)
{
ETL_STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
return base_t::template create<T>(p1, p2, p3, p4);
}
#else
//*************************************************************************
/// Creates the object from a type. Variadic parameter constructor.
//*************************************************************************
template <typename T, typename... Args>
T* create(Args&&... args)
{
ETL_STATIC_ASSERT((etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value), "Unsupported type");
return base_t::template create<T>(args...);
}
#endif
//*************************************************************************
/// Destroys the object.
//*************************************************************************
template <typename T>
void destroy(const T* const p)
{
ETL_STATIC_ASSERT(
(etl::is_one_of<T, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16>::value || etl::is_base_of<T, T1>::value ||
etl::is_base_of<T, T2>::value || etl::is_base_of<T, T3>::value || etl::is_base_of<T, T4>::value || etl::is_base_of<T, T5>::value ||
etl::is_base_of<T, T6>::value || etl::is_base_of<T, T7>::value || etl::is_base_of<T, T8>::value || etl::is_base_of<T, T9>::value ||
etl::is_base_of<T, T10>::value || etl::is_base_of<T, T11>::value || etl::is_base_of<T, T12>::value || etl::is_base_of<T, T13>::value ||
etl::is_base_of<T, T14>::value || etl::is_base_of<T, T15>::value || etl::is_base_of<T, T16>::value),
"Invalid type");
base_t::destroy(p);
}
//*************************************************************************
/// Returns the maximum number of items in the variant_pool.
//*************************************************************************
// redundant also declared in ipool::max_size()
size_t max_size() const { return base_t::max_size(); }
private:
variant_pool_ext(const variant_pool_ext&) ETL_DELETE;
variant_pool_ext& operator=(const variant_pool_ext&) ETL_DELETE;
};
}
#endif

View File

@ -85,6 +85,7 @@ etl_test_sources = files(
'test/test_parameter_type.cpp',
'test/test_parity_checksum.cpp',
'test/test_pool.cpp',
'test/test_pool_external_buffer.cpp',
'test/test_priority_queue.cpp',
'test/test_queue.cpp',
'test/test_queue_memory_model_small.cpp',
@ -114,6 +115,7 @@ etl_test_sources = files(
'test/test_variant_legacy.cpp',
'test/test_variant_variadic.cpp',
'test/test_variant_pool.cpp',
'test/test_variant_pool_external_buffer.cpp',
'test/test_variant_variadic.cpp',
'test/test_vector.cpp',
'test/test_vector_non_trivial.cpp',
@ -179,6 +181,8 @@ unittestcpp_dep = dependency('UnitTest++',
disabler: true,
)
threads_dep = dependency('threads')
etl_unit_tests = executable('etl_unit_tests',
include_directories: [
include_directories('test'),
@ -187,7 +191,7 @@ etl_unit_tests = executable('etl_unit_tests',
include_directories('include')
],
sources: etl_test_sources,
dependencies: unittestcpp_dep,
dependencies: [unittestcpp_dep, threads_dep],
cpp_args: [
'-fexceptions',
'-DENABLE_ETL_UNIT_TESTS',

View File

@ -185,6 +185,7 @@ set(TEST_SOURCE_FILES
test_parity_checksum.cpp
test_pearson.cpp
test_pool.cpp
test_pool_external_buffer.cpp
test_priority_queue.cpp
test_quantize.cpp
test_queue.cpp
@ -257,6 +258,7 @@ set(TEST_SOURCE_FILES
test_variant_legacy.cpp
test_variant_variadic.cpp
test_variant_pool.cpp
test_variant_pool_external_buffer.cpp
test_vector.cpp
test_vector_external_buffer.cpp
test_vector_non_trivial.cpp

View File

@ -222,20 +222,20 @@ namespace
const Test const_test_static;
}
//*****************************************************************************
// Initialises the test results.
//*****************************************************************************
struct SetupFixture
{
SetupFixture()
{
function_called = false;
parameter_correct = false;
}
};
namespace
{
//*****************************************************************************
// Initialises the test results.
//*****************************************************************************
struct SetupFixture
{
SetupFixture()
{
function_called = false;
parameter_correct = false;
}
};
SUITE(test_delegate)
{
//*************************************************************************

View File

@ -0,0 +1,496 @@
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2014 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 "unit_test_framework.h"
#include "data.h"
#include <set>
#include <vector>
#include <string>
#include "etl/pool.h"
#include "etl/largest.h"
#if defined(ETL_COMPILER_GCC)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#endif
typedef TestDataDC<std::string> Test_Data;
typedef TestDataNDC<std::string> 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&, const D0&)
{
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&)
{
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_external_buffer)
{
//*************************************************************************
TEST(test_allocate)
{
const size_t SIZE = 4;
auto* buffer = new etl::pool_ext<Test_Data>::element[SIZE];
etl::pool_ext<Test_Data> pool(buffer, SIZE);
Test_Data* p1 = nullptr;
Test_Data* p2 = nullptr;
Test_Data* p3 = nullptr;
Test_Data* p4 = nullptr;
CHECK_NO_THROW(p1 = pool.allocate());
CHECK_NO_THROW(p2 = pool.allocate());
CHECK_NO_THROW(p3 = pool.allocate());
CHECK_NO_THROW(p4 = pool.allocate());
CHECK(p1 != p2);
CHECK(p1 != p3);
CHECK(p1 != p4);
CHECK(p2 != p3);
CHECK(p2 != p4);
CHECK(p3 != p4);
CHECK_THROW(pool.allocate(), etl::pool_no_allocation);
}
//*************************************************************************
TEST(test_release)
{
const size_t SIZE = 4;
auto* buffer = new etl::pool_ext<Test_Data>::element[SIZE];
etl::pool_ext<Test_Data> pool(buffer, SIZE);
Test_Data* p1 = pool.allocate();
Test_Data* p2 = pool.allocate();
Test_Data* p3 = pool.allocate();
Test_Data* p4 = pool.allocate();
CHECK_NO_THROW(pool.release(p2));
CHECK_NO_THROW(pool.release(p3));
CHECK_NO_THROW(pool.release(p1));
CHECK_NO_THROW(pool.release(p4));
CHECK_EQUAL(4U, pool.available());
Test_Data not_in_pool;
CHECK_THROW(pool.release(&not_in_pool), etl::pool_object_not_in_pool);
}
//*************************************************************************
TEST(test_allocate_release)
{
const size_t SIZE = 4;
auto* buffer = new etl::pool_ext<Test_Data>::element[SIZE];
etl::pool_ext<Test_Data> pool(buffer, SIZE);
Test_Data* p1 = pool.allocate();
Test_Data* p2 = pool.allocate();
Test_Data* p3 = pool.allocate();
Test_Data* p4 = pool.allocate();
// Allocated p1, p2, p3, p4
CHECK_EQUAL(0U, pool.available());
CHECK_NO_THROW(pool.release(p2));
CHECK_NO_THROW(pool.release(p3));
// Allocated p1, p4
CHECK_EQUAL(2U, pool.available());
Test_Data* p5 = pool.allocate();
Test_Data* p6 = pool.allocate();
// Allocated p1, p4, p5, p6
CHECK_EQUAL(0U, pool.available());
CHECK(p5 != p1);
CHECK(p5 != p4);
CHECK(p6 != p1);
CHECK(p6 != p4);
CHECK_NO_THROW(pool.release(p5));
// Allocated p1, p4, p6
CHECK_EQUAL(1U, pool.available());
Test_Data* p7 = pool.allocate();
// Allocated p1, p4, p6, p7
CHECK(p7 != p1);
CHECK(p7 != p4);
CHECK(p7 != p6);
CHECK(pool.full());
}
//*************************************************************************
TEST(test_available)
{
const size_t SIZE = 4;
auto* buffer = new etl::pool_ext<Test_Data>::element[SIZE];
etl::pool_ext<Test_Data> pool(buffer, SIZE);
CHECK_EQUAL(4U, pool.available());
Test_Data* p;
p = pool.allocate();
CHECK_EQUAL(3U, pool.available());
p = pool.allocate();
CHECK_EQUAL(2U, pool.available());
p = pool.allocate();
CHECK_EQUAL(1U, pool.available());
p = pool.allocate();
CHECK_EQUAL(0U, pool.available());
}
//*************************************************************************
TEST(test_max_size)
{
const size_t SIZE = 4;
auto* buffer = new etl::pool_ext<Test_Data>::element[SIZE];
etl::pool_ext<Test_Data> pool(buffer, SIZE);
CHECK(pool.max_size() == 4U);
}
//*************************************************************************
TEST(test_size)
{
const size_t SIZE = 4;
auto* buffer = new etl::pool_ext<Test_Data>::element[SIZE];
etl::pool_ext<Test_Data> pool(buffer, SIZE);
CHECK_EQUAL(0U, pool.size());
Test_Data* p;
p = pool.allocate();
CHECK_EQUAL(1U, pool.size());
p = pool.allocate();
CHECK_EQUAL(2U, pool.size());
p = pool.allocate();
CHECK_EQUAL(3U, pool.size());
p = pool.allocate();
CHECK_EQUAL(4U, pool.size());
}
//*************************************************************************
TEST(test_empty_full)
{
const size_t SIZE = 4;
auto* buffer = new etl::pool_ext<Test_Data>::element[SIZE];
etl::pool_ext<Test_Data> pool(buffer, SIZE);
CHECK(pool.empty());
CHECK(!pool.full());
Test_Data* p;
p = pool.allocate();
CHECK(!pool.empty());
CHECK(!pool.full());
p = pool.allocate();
CHECK(!pool.empty());
CHECK(!pool.full());
p = pool.allocate();
CHECK(!pool.empty());
CHECK(!pool.full());
p = pool.allocate();
CHECK(!pool.empty());
CHECK(pool.full());
}
//*************************************************************************
TEST(test_is_in_pool)
{
const size_t SIZE = 4;
auto* buffer = new etl::pool_ext<Test_Data>::element[SIZE];
etl::pool_ext<Test_Data> pool(buffer, SIZE);
Test_Data not_in_pool;
Test_Data* p1 = pool.allocate();
CHECK(pool.is_in_pool(p1));
CHECK(!pool.is_in_pool(&not_in_pool));
}
//*************************************************************************
TEST(test_type_error)
{
struct Test
{
uint64_t a;
uint64_t b;
};
const size_t SIZE = 4;
auto* buffer = new etl::pool_ext<uint32_t>::element[SIZE];
etl::pool_ext<uint32_t> pool(buffer, SIZE);
etl::ipool& ip = pool;
CHECK_THROW(ip.allocate<Test>(), etl::pool_element_size);
}
//*************************************************************************
TEST(test_create_destroy)
{
const size_t SIZE = 4;
auto* buffer0 = new etl::pool_ext<D0>::element[SIZE];
etl::pool_ext<D0> pool0(buffer0, SIZE);
auto* buffer1 = new etl::pool_ext<D1>::element[SIZE];
etl::pool_ext<D1> pool1(buffer1, SIZE);
auto* buffer2 = new etl::pool_ext<D2>::element[SIZE];
etl::pool_ext<D2> pool2(buffer2, SIZE);
auto* buffer3 = new etl::pool_ext<D3>::element[SIZE];
etl::pool_ext<D3> pool3(buffer3, SIZE);
auto* buffer4 = new etl::pool_ext<D4>::element[SIZE];
etl::pool_ext<D4> pool4(buffer4, SIZE);
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(1U, pool0.size());
CHECK_EQUAL(pool1.max_size() - 1, pool1.available());
CHECK_EQUAL(1U, pool1.size());
CHECK_EQUAL(pool2.max_size() - 1, pool2.available());
CHECK_EQUAL(1U, pool2.size());
CHECK_EQUAL(pool3.max_size() - 1, pool3.available());
CHECK_EQUAL(1U, pool3.size());
CHECK_EQUAL(pool4.max_size() - 1, pool4.available());
CHECK_EQUAL(1U, 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<D0>(p0);
pool1.destroy<D1>(p1);
pool2.destroy<D2>(p2);
pool3.destroy<D3>(p3);
pool4.destroy<D4>(p4);
CHECK_EQUAL(pool0.max_size(), pool0.available());
CHECK_EQUAL(0U, pool0.size());
CHECK_EQUAL(pool1.max_size(), pool1.available());
CHECK_EQUAL(0U, pool1.size());
CHECK_EQUAL(pool2.max_size(), pool2.available());
CHECK_EQUAL(0U, pool2.size());
CHECK_EQUAL(pool3.max_size(), pool3.available());
CHECK_EQUAL(0U, pool3.size());
CHECK_EQUAL(pool4.max_size(), pool4.available());
CHECK_EQUAL(0U, pool4.size());
}
//*************************************************************************
TEST(test_allocate_release_non_class)
{
const size_t SIZE = 4;
auto* buffer = new etl::pool_ext<int>::element[SIZE];
etl::pool_ext<int> pool(buffer, SIZE);
int* i = pool.allocate();
pool.release(i);
}
//*************************************************************************
TEST(test_issue_406_pool_of_c_array)
{
using elem_type = uint8_t[10];
const size_t SIZE = 3;
auto* buffer = new etl::pool_ext<elem_type>::element[SIZE];
etl::pool_ext<elem_type> memPool(buffer, SIZE);
CHECK_EQUAL(3, memPool.available());
CHECK_EQUAL(0, memPool.size());
elem_type* memory = memPool.allocate();
CHECK_EQUAL(2, memPool.available());
CHECK_EQUAL(1, memPool.size());
memPool.release(memory);
CHECK_EQUAL(3, memPool.available());
CHECK_EQUAL(0, memPool.size());
}
}
}
#if defined(ETL_COMPILER_GCC)
#pragma GCC diagnostic pop
#endif

View File

@ -0,0 +1,319 @@
/******************************************************************************
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.
******************************************************************************/
#include "unit_test_framework.h"
#include "etl/variant_pool.h"
#include <string>
#include <type_traits>
namespace
{
bool destructor;
//***********************************
struct Base
{
Base()
{
destructor = false;
}
virtual ~Base()
{
}
virtual void Set() = 0;
};
//***********************************
struct Derived1 : public Base
{
int i;
Derived1()
: i(0)
{
}
~Derived1()
{
destructor = true;
}
void Set()
{
i = 1;
}
};
//***********************************
struct Derived2 : public Base
{
double d;
Derived2()
: d(0.0)
{
}
~Derived2()
{
destructor = true;
}
void Set()
{
d = 1.2;
}
};
//***********************************
struct Derived3 : public Base
{
std::string s;
Derived3()
: s("constructed")
{
}
Derived3(const char* p1)
: s("constructed")
{
s.append(p1);
}
Derived3(const char* p1, const std::string& p2)
: s("constructed")
{
s.append(p1);
s.append(p2);
}
Derived3(const char* p1, const std::string& p2, const char* p3)
: s("constructed")
{
s.append(p1);
s.append(p2);
s.append(p3);
}
Derived3(const char* p1, const std::string& p2, const char* p3, const std::string& p4)
: s("constructed")
{
s.append(p1);
s.append(p2);
s.append(p3);
s.append(p4);
}
~Derived3()
{
destructor = true;
}
void Set()
{
s = "set";
}
};
//***********************************
struct NonDerived
{
NonDerived()
: s("constructed")
{
}
~NonDerived()
{
destructor = true;
}
void Set()
{
s = "set";
}
std::string s;
};
const size_t SIZE = 5;
// Notice that the type declaration order is not important.
typedef etl::variant_pool_ext<Derived1, NonDerived, Derived3, Derived2, int> Factory;
SUITE(test_variant_pool_external_buffer)
{
//*************************************************************************
TEST(test_sizes)
{
auto* buffer = new Factory::element[SIZE];
Factory variant_pool(buffer, SIZE);
size_t ms = variant_pool.max_size();
CHECK_EQUAL(SIZE, ms);
CHECK_EQUAL(SIZE, variant_pool.available());
CHECK_EQUAL(0U, variant_pool.size());
CHECK(variant_pool.empty());
CHECK(!variant_pool.full());
variant_pool.create<Derived1>();
CHECK_EQUAL(SIZE - 1U, variant_pool.available());
CHECK_EQUAL(1U, variant_pool.size());
CHECK(!variant_pool.empty());
CHECK(!variant_pool.full());
variant_pool.create<Derived1>();
variant_pool.create<Derived1>();
variant_pool.create<Derived1>();
variant_pool.create<Derived1>();
CHECK_EQUAL(0U, variant_pool.available());
CHECK_EQUAL(SIZE, variant_pool.size());
CHECK(!variant_pool.empty());
CHECK(variant_pool.full());
CHECK_THROW(variant_pool.create<Derived1>(), etl::pool_no_allocation);
}
//*************************************************************************
TEST(test_create_release)
{
auto* buffer = new Factory::element[SIZE];
Factory variant_pool(buffer, SIZE);
Base* p;
// Derived 1
p = variant_pool.create<Derived1>();
Derived1* pd1 = static_cast<Derived1*>(p);
CHECK_EQUAL(0, pd1->i);
p->Set();
CHECK_EQUAL(1, pd1->i);
variant_pool.destroy(p);
CHECK(destructor);
// Derived 2
destructor = false;
p = variant_pool.create<Derived2>();
Derived2* pd2 = static_cast<Derived2*>(p);
CHECK_EQUAL(0.0, pd2->d);
p->Set();
CHECK_EQUAL(1.2, pd2->d);
variant_pool.destroy(p);
CHECK(destructor);
// Derived 3
destructor = false;
p = variant_pool.create<Derived3>();
Derived3* pd3 = static_cast<Derived3*>(p);
CHECK_EQUAL("constructed", pd3->s);
p->Set();
CHECK_EQUAL("set", pd3->s);
variant_pool.destroy(p);
CHECK(destructor);
// Non Derived
destructor = false;
NonDerived* pnd = variant_pool.create<NonDerived>();
CHECK_EQUAL("constructed", pnd->s);
pnd->Set();
CHECK_EQUAL("set", pnd->s);
variant_pool.destroy(pnd);
CHECK(destructor);
// Integral
int* pi = variant_pool.create<int>();
variant_pool.destroy(pi);
}
//*************************************************************************
TEST(test_create_release_const)
{
auto* buffer = new Factory::element[SIZE];
Factory variant_pool(buffer, SIZE);
const Derived1& d = *variant_pool.create<Derived1>();
CHECK_EQUAL(0, d.i);
variant_pool.destroy(&d);
CHECK(destructor);
}
//*************************************************************************
TEST(test_create_emplace)
{
auto* buffer = new Factory::element[SIZE];
Factory variant_pool(buffer, SIZE);
Base* p;
Derived3* pd3;
p = variant_pool.create<Derived3>("1");
pd3 = static_cast<Derived3*>(p);
CHECK_EQUAL("constructed1", pd3->s);
variant_pool.destroy(p);
p = variant_pool.create<Derived3>("1", "2");
pd3 = static_cast<Derived3*>(p);
CHECK_EQUAL("constructed12", pd3->s);
variant_pool.destroy(p);
p = variant_pool.create<Derived3>("1", "2", "3");
pd3 = static_cast<Derived3*>(p);
CHECK_EQUAL("constructed123", pd3->s);
variant_pool.destroy(p);
p = variant_pool.create<Derived3>("1", "2", "3", "4");
pd3 = static_cast<Derived3*>(p);
CHECK_EQUAL("constructed1234", pd3->s);
variant_pool.destroy(p);
}
//*************************************************************************
TEST(test_did_not_create)
{
auto* buffer1 = new Factory::element[SIZE];
Factory variant_pool1(buffer1, SIZE);
auto* buffer2 = new Factory::element[SIZE];
Factory variant_pool2(buffer2, SIZE);
Base* p;
p = variant_pool1.create<Derived1>();
CHECK_NO_THROW(variant_pool1.destroy(p));
p = variant_pool2.create<Derived1>();
CHECK_THROW(variant_pool1.destroy(p), etl::pool_object_not_in_pool);
}
};
}