///
/// Copyright (c) xseekerj 2014,All Rights Reserved.
///
#ifndef _OBJECT_POOL_H_
#define _OBJECT_POOL_H_
#ifndef _POLITE_SZ_ALIGN
#define _POLITE_SZ_ALIGN
#define sz_align(d,a) (((d) + (a - 1)) & ~(a - 1))
#endif
template<typename _Ty, size_t _ElemCount = 1024>
class object_pool
{
typedef struct free_link_node
{
free_link_node* next;
} *free_link;
typedef struct chunk_link_node
{
char data[sz_align(sizeof(_Ty), sizeof(void*)) * _ElemCount];
chunk_link_node* next;
} *chunk_link;
object_pool(const object_pool&);
void operator= (const object_pool&);
public:
object_pool(void) : _Myhead(nullptr), _Mychunk(nullptr), _Mycount(0)
{
this->_Enlarge();
}
~object_pool(void)
{
this->purge();
}
void cleanup(void)
{
if(this->_Mychunk = nullptr) {
return;
}
free_link_node* prev = nullptr;
chunk_link_node* chunk = this->_Mychunk;
for (; chunk != nullptr; chunk = chunk->next)
{
char* begin = chunk->data;
char* rbegin = begin + (_ElemCount - 1) * sz_align(sizeof(_Ty), sizeof(void*));
if(prev != nullptr)
prev->next = reinterpret_cast<free_link>(begin);
for (char* ptr = begin; ptr < rbegin; ptr += sz_align(sizeof(_Ty), sizeof(void*)) )
{
reinterpret_cast<free_link_node*>(ptr)->next = reinterpret_cast<free_link_node*>(ptr + sz_align(sizeof(_Ty), sizeof(void*)));
}
prev = reinterpret_cast <free_link_node*>(rbegin);
}
this->_Myhead = reinterpret_cast<free_link_node*>(this->_Mychunk->data);
this->_Mycount = 0;
}
void purge(void)
{
chunk_link_node* ptr = this->_Mychunk;
while (ptr != nullptr)
{
chunk_link_node* deleting = ptr;
ptr = ptr->next;
free(deleting);
}
_Myhead = nullptr;
_Mychunk = nullptr;
_Mycount = 0;
}
size_t count(void) const
{
return _Mycount;
}
// if the type is not pod, you may be use placement new to call the constructor,
// for example: _Ty* obj = new(pool.get()) _Ty(arg1,arg2,...);
void* get(void)
{
if (nullptr == this->_Myhead)
{
this->_Enlarge();
}
free_link_node* ptr = this->_Myhead;
this->_Myhead = ptr->next;
++_Mycount;
return reinterpret_cast<void*>(ptr);
}
void release(void* _Ptr)
{
( (_Ty*)_Ptr)->~_Ty(); // call the destructor
#ifdef _DEBUG
::memset(_Ptr, 0x00, sizeof(_Ty));
#endif
free_link_node* ptr = reinterpret_cast<free_link_node*>(_Ptr);
ptr->next = this->_Myhead;
this->_Myhead = ptr;
--_Mycount;
}
private:
void _Enlarge(void)
{
static_assert(_ElemCount > 0, "Invalid Element Count");
chunk_link new_chunk = (chunk_link)malloc(sizeof(chunk_link_node));
#ifdef _DEBUG
::memset(new_chunk, 0x00, sizeof(chunk_link_node));
#endif
new_chunk->next = this->_Mychunk;
this->_Mychunk = new_chunk;
char* begin = this->_Mychunk->data;
char* rbegin = begin + (_ElemCount - 1) * sz_align(sizeof(_Ty), sizeof(void*));
for (char* ptr = begin; ptr < rbegin; ptr += sz_align(sizeof(_Ty), sizeof(void*)))
{
reinterpret_cast<free_link_node*>(ptr)->next = reinterpret_cast<free_link_node*>(ptr + sz_align(sizeof(_Ty), sizeof(void*)));
}
reinterpret_cast <free_link_node*>(rbegin)->next = nullptr;
this->_Myhead = reinterpret_cast<free_link_node*>(begin);
}
private:
free_link _Myhead; // link to free head
chunk_link _Mychunk; // chunk link
size_t _Mycount; // allocated count
};
#endif