Merge remote-tracking branch 'origin/feature/pool_emplace' into development

This commit is contained in:
John Wellbelove 2018-02-11 18:39:24 +00:00
commit 611b6cf011
2 changed files with 536 additions and 59 deletions

View File

@ -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 <iterator>
@ -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<T*>(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 <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 nullptr is returned.
//*************************************************************************
template <typename T, typename T1>
T* create(const T1& value1)
{
T* p = allocate<T>();
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 <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;
}
//*************************************************************************
/// 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 <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;
}
//*************************************************************************
/// 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 <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(std::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 void* const p_object)
{
if (sizeof(T) > ITEM_SIZE)
{
ETL_ASSERT(false, ETL_ERROR(etl::pool_element_size));
}
reinterpret_cast<T*>((const_cast<void*>(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 <typename T, const size_t SIZE_>
class pool : public etl::ipool
{
public:
static const size_t SIZE = SIZE_;
//*************************************************************************
/// Constructor
//*************************************************************************
pool()
: etl::ipool(reinterpret_cast<char*>(&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 <typename U>
U* allocate()
{
STATIC_ASSERT(sizeof(U) <= ELEMENT_SIZE, "Type too large for pool");
return ipool::allocate<U>();
}
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<etl::alignment_of<T>::value>::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.
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<U>::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<U>();
}
#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 <typename U>
U* create()
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
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 nullptr is returned.
//*************************************************************************
template <typename U, typename T1>
U* create(const T1& value1)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
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 nullptr is returned.
//*************************************************************************
template <typename U, typename T1, typename T2>
U* create(const T1& value1, const T2& value2)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
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 nullptr is returned.
//*************************************************************************
template <typename U, typename T1, typename T2, typename T3>
U* create(const T1& value1, const T2& value2, const T3& value3)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
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 nullptr 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)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
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)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return ipool::create<U>(std::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 void* const p_object)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT_, "Type has incompatible alignment");
STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
reinterpret_cast<U*>((const_cast<void*>(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 <typename T, const size_t SIZE_>
class pool : public etl::generic_pool<sizeof(T), etl::alignment_of<T>::value, SIZE_>
{
private:
typedef etl::generic_pool<sizeof(T), etl::alignment_of<T>::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 <typename U>
U* allocate()
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT, "Type has incompatible alignment");
STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return base_t::template allocate<U>();
}
#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 <typename U>
U* create()
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT, "Type has incompatible alignment");
STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return base_t::template 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 nullptr is returned.
//*************************************************************************
template <typename U, typename T1>
U* create(const T1& value1)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT, "Type has incompatible alignment");
STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return base_t::template 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 nullptr is returned.
//*************************************************************************
template <typename U, typename T1, typename T2>
U* create(const T1& value1, const T2& value2)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT, "Type has incompatible alignment");
STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return base_t::template 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 nullptr is returned.
//*************************************************************************
template <typename U, typename T1, typename T2, typename T3>
U* create(const T1& value1, const T2& value2, const T3& value3)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT, "Type has incompatible alignment");
STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return base_t::template 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 nullptr 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)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT, "Type has incompatible alignment");
STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return base_t::template create<U>(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 <typename U, typename... Args>
U* create(Args&&... args)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT, "Type has incompatible alignment");
STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
return base_t::template create<U>(std::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 void* const p_object)
{
STATIC_ASSERT(etl::alignment_of<U>::value <= ALIGNMENT, "Type has incompatible alignment");
STATIC_ASSERT(sizeof(U) <= TYPE_SIZE, "Type too large for pool");
reinterpret_cast<U*>((const_cast<void*>(p_object)))->~U();
base_t::release(p_object);
}
private:
// Should not be copied.
pool(const pool&);
pool& operator =(const pool&);
};
}
#undef ETL_FILE

View File

@ -33,6 +33,7 @@ SOFTWARE.
#include <set>
#include <vector>
#include <string>
#include "pool.h"
#include "largest.h"
@ -47,6 +48,119 @@ 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& 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_Data>());
}
};
//*************************************************************************
TEST(test_create_destroy)
{
etl::pool<D0, 4> pool0;
etl::pool<D1, 4> pool1;
etl::pool<D2, 4> pool2;
etl::pool<D3, 4> pool3;
etl::pool<D4, 4> pool4;
D0* p0 = pool0.create<D0>();
D1* p1 = pool1.create<D1>("1");
D2* p2 = pool2.create<D2>("1", "2");
D3* p3 = pool3.create<D3>("1", "2", "3");
D4* p4 = pool4.create<D4>("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<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(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)