Modified factory to use pool instead of custom internal allocator.

This commit is contained in:
John Wellbelove 2017-12-15 13:11:08 +00:00
parent 5752151b54
commit 1d6058ffac

View File

@ -39,6 +39,7 @@ SOFTWARE.
#include "alignment.h"
#include "static_assert.h"
#include "type_lookup.h"
#include <pool.h>
#undef ETL_FILE
#define ETL_FILE "40"
@ -125,12 +126,9 @@ namespace etl
static const size_t MAX_SIZE = MAX_SIZE_;
//*************************************************************************
/// Constructor
/// Default constructor.
//*************************************************************************
factory()
: p_next(reinterpret_cast<char*>(&buffer[0])),
items_allocated(0),
items_initialised(0)
{
}
@ -142,11 +140,20 @@ namespace etl
{
STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
T* p = reinterpret_cast<T*>(allocate_item());
T* p = nullptr;
if (p != nullptr)
if (pool.full())
{
new (p) T();
ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
}
else
{
p = pool.allocate<T>();
if (p != nullptr)
{
new (p) T();
}
}
return p;
@ -160,11 +167,20 @@ namespace etl
{
STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
T* p = reinterpret_cast<T*>(allocate_item());
T* p = nullptr;
if (p != nullptr)
if (pool.full())
{
new (p) T(p1);
ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
}
else
{
p = pool.allocate<T>();
if (p != nullptr)
{
new (p) T(p1);
}
}
return p;
@ -178,11 +194,20 @@ namespace etl
{
STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
T* p = reinterpret_cast<T*>(allocate_item());
T* p = nullptr;
if (p != nullptr)
if (pool.full())
{
new (p) T(p1, p2);
ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
}
else
{
p = pool.allocate<T>();
if (p != nullptr)
{
new (p) T(p1, p2);
}
}
return p;
@ -196,11 +221,20 @@ namespace etl
{
STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
T* p = reinterpret_cast<T*>(allocate_item());
T* p = nullptr;
if (p != nullptr)
if (pool.full())
{
new (p) T(p1, p2, p3);
ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
}
else
{
p = pool.allocate<T>();
if (p != nullptr)
{
new (p) T(p1, p2, p3);
}
}
return p;
@ -214,11 +248,20 @@ namespace etl
{
STATIC_ASSERT((etl::is_one_of<T, TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::value), "Unsupported type");
T* p = reinterpret_cast<T*>(allocate_item());
T* p = nullptr;
if (p != nullptr)
if (pool.full())
{
new (p) T(p1, p2, p3, p4);
ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
}
else
{
p = pool.allocate<T>();
if (p != nullptr)
{
new (p) T(p1, p2, p3, p4);
}
}
return p;
@ -305,7 +348,18 @@ namespace etl
p->~T();
return release_item(reinterpret_cast<char*>(const_cast<T*>(p)));
void* vp = reinterpret_cast<char*>(const_cast<T*>(p));
if (pool.is_in_pool(vp))
{
pool.release(reinterpret_cast<char*>(const_cast<T*>(p)));
return true;
}
else
{
ETL_ASSERT(false, ETL_ERROR(factory_did_not_create));
return false;
}
}
//*************************************************************************
@ -321,7 +375,7 @@ namespace etl
//*************************************************************************
size_t available() const
{
return MAX_SIZE - items_allocated;
return pool.available();
}
//*************************************************************************
@ -329,7 +383,7 @@ namespace etl
//*************************************************************************
size_t size() const
{
return items_allocated;
return pool.size();
}
//*************************************************************************
@ -338,7 +392,7 @@ namespace etl
//*************************************************************************
bool empty() const
{
return items_allocated == 0;
return pool.empty();
}
//*************************************************************************
@ -347,7 +401,7 @@ namespace etl
//*************************************************************************
bool full() const
{
return items_allocated == MAX_SIZE;;
return pool.full();
}
private:
@ -355,121 +409,10 @@ namespace etl
factory(const factory&);
factory& operator =(const factory&);
//*************************************************************************
/// Allocate an item from the pool.
//*************************************************************************
char* allocate_item()
{
char* p_value = nullptr;
// Any free space left?
if (items_allocated < MAX_SIZE)
{
// Initialise another one if necessary.
if (items_initialised < MAX_SIZE)
{
uintptr_t p = reinterpret_cast<uintptr_t>(reinterpret_cast<char*>(&buffer[0]) + (items_initialised * ITEM_SIZE));
*reinterpret_cast<uintptr_t*>(p) = p + ITEM_SIZE;
++items_initialised;
}
// Get the address of new allocated item.
p_value = p_next;
++items_allocated;
if (items_allocated != MAX_SIZE)
{
// Set up the pointer to the next free item
p_next = *reinterpret_cast<char**>(p_next);
}
else
{
// No more left!
p_next = nullptr;
}
}
else
{
ETL_ASSERT(false, ETL_ERROR(etl::factory_cannot_create));
}
return p_value;
}
//*************************************************************************
/// Release an item back to the pool.
//*************************************************************************
bool release_item(char* p_value)
{
if (is_item_in_pool(p_value))
{
if (p_next != nullptr)
{
// Point it to the current free item.
*(uintptr_t*)p_value = reinterpret_cast<uintptr_t>(p_next);
}
else
{
// This is the only free item.
*((uintptr_t*)p_value) = 0;
}
p_next = p_value;
--items_allocated;
return true;
}
else
{
ETL_ASSERT(false, ETL_ERROR(factory_did_not_create));
}
return false;
}
//*************************************************************************
/// Check if the item belongs to this pool.
//*************************************************************************
bool is_item_in_pool(char* p) const
{
if (empty() || (p == nullptr))
{
return false;
}
// Within the range of the buffer?
intptr_t distance = p - reinterpret_cast<const char*>(&buffer[0]);
bool is_within_range = (distance >= 0) && (distance <= intptr_t((ITEM_SIZE * MAX_SIZE) - ITEM_SIZE));
// Modulus and division can be slow on some architectures, so only do this in debug.
#if defined(ETL_DEBUG)
// Is the address on a valid object boundary?
bool is_valid_address = ((distance % ITEM_SIZE) == 0);
#else
bool is_valid_address = true;
#endif
return is_within_range && is_valid_address;
}
// The pool element.
union Element
{
uintptr_t next; ///< Pointer to the next free element.
char value[etl::largest<TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::size]; ///< Storage for value type.
typename etl::type_with_alignment<etl::largest<TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::alignment>::type dummy; ///< Dummy item to get correct alignment.
};
///< The memory for the pool of objects.
typename etl::aligned_storage<sizeof(Element), etl::alignment_of<Element>::value>::type buffer[MAX_SIZE];
static const uint32_t ITEM_SIZE = sizeof(Element);
char* p_next;
uint32_t items_allocated; ///< The number of items allocated.
uint32_t items_initialised; ///< The number of items initialised.
// The pool.
etl::generic_pool<etl::largest<TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::size,
etl::largest<TT1, TT2, TT3, TT4, TT5, TT6, TT7, TT8, TT9, TT10, TT11, TT12, TT13, TT14, TT15, TT16>::alignment,
MAX_SIZE> pool;
};
}