1.Allocate an object from pre-allocate memory, when free an object just put it back to pool.
2.Call object's contructor at pool memory allocating or get object from pool, or do nothing.
3.Call object's deconstructor when "delete" object if constructor's been calling at "new" object
3.Call object's deconstructor when destroy objectpool if constructor's been calling at memory allocating
4.Can pass an function object to be invoke when "new" object, this can be used as a constructor if object's constructor don't be invokded when "new" object
There are several tasks need to do, like the allnodesset can be generated at callring of foreach. Delegate memory allocating to allocator, etc..
Is there any comments?
Thanks
//////////////////////////////////////////////////////////////////////////////////////
#include <istream>
#include <list>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <set>
#include <algorithm>
#include <boost/type_traits.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/thread/pthread/mutex.hpp>
namespace maxutility {
enum InitialType {None,ObjInitial,PoolAllocate};
template <typename T>
class DummyCallableObj
{
public:
void operator ()(boost::shared_ptr<T> &ptr)
{
//do nothing
}
};
template<bool isthreadsafe>
class obthreadlock;
template<>
class obthreadlock<true>
{
public:
void lock(){obmutex.lock();}
bool try_lock(){return obmutex.try_lock();}
void unlock(){obmutex.unlock();}
private:
boost::mutex obmutex;
};
template<>
class obthreadlock<false>
{
public:
void lock(){};
bool try_lock(){return true;};
void unlock(){};
};
template <typename T,bool isthreadsafe=false,typename InitalFunction=DummyCallableObj<T> >
class ObjectPool
{
#define LOCAL_LOCK boost::lock_guard<obthreadlock<isthreadsafe> > lg(obthreadlock_);
protected:
/**
* @brief Declaration for furture usage
**/
typedef T Node;
typedef std::list<char *> FRAGMENTTYPE;
typedef std::list<Node *> NODELIST;
public:
ObjectPool(InitialType initialtype=ObjInitial,size_t initialsize=512,size_t maxsize=0)
{
busyCount=0;
this->poolsize=0;
this->initialtype=initialtype;
this->maxsize=maxsize;
extend(initialsize);
}
ObjectPool(InitalFunction initalFunction=DummyCallableObj<T>(),
InitialType initialtype=PoolAllocate,
size_t initialsize=512,
size_t maxsize=0) //:ObjectPool(initialtype,initialsize,maxsize) //Delegating constructors, c++11 only
{
busyCount=0;
this->poolsize=0;
this->initialtype=initialtype;
this->maxsize=maxsize;
this->initalFunction=initalFunction;
extend(initialsize);
}
~ObjectPool()
{
if(0!=busyCount)
throw new std::exception();
if(PoolAllocate==initialtype)
for(Node *p:allnodes)
p->~Node();
for(char *pFragment:fragments)
delete pFragment;
}
virtual boost::shared_ptr<T> create()
{
LOCAL_LOCK;
boost::shared_ptr<T> ptr(static_cast<T*>(getFreeNode()),boost::bind(&ObjectPool<T,isthreadsafe,InitalFunction>::free,this,_1));
initalFunction(ptr);
return ptr;
}
bool empty()
{
return !busyCount;
}
size_t size()
{
return busyCount;
}
size_t capacity()
{
return poolsize;
}
template <typename FUNCTION>
void foreach(FUNCTION f)
{
LOCAL_LOCK;
NODELIST freenodes=this->freenodes; //make a local copy
freenodes.sort();
NODELIST busynodes(allnodes.size());
typename NODELIST::iterator busynodesend=std::set_difference(
allnodes.begin(),allnodes.end(),freenodes.begin(),freenodes.end(),busynodes.begin()
);
for(typename NODELIST::iterator iter=busynodes.begin();
iter!=busynodesend;
iter++)
{
invokeFunction<FUNCTION,Node,
boost::is_base_of<boost::enable_shared_from_this<Node>,Node >::value >()(f,*iter);
}
}
protected:
template<typename _Function,typename N,bool isuseshareptr>
class invokeFunction;
template<typename _Function,typename N>
class invokeFunction<_Function,N,false>
{
public:
void operator ()(_Function __f,N *p)
{
__f(p);
}
};
template<typename _Function,typename N>
class invokeFunction<_Function,N,true>
{
public:
void operator ()(_Function __f,N *p)
{
boost::shared_ptr<N> ptr=p->shared_from_this();
__f(ptr);
}
};
protected:
void free(T *p)
{
LOCAL_LOCK;
if(!p)
return;
destroyObj(static_cast<Node*>(p),ObjInitial);
//removeBusyNode(static_cast<Node*>(p));
freenodes.push_back(static_cast<Node*>(p));
busyCount--;
}
Node *getFreeNode()
{
Node *ptr=nullptr;
if(freenodes.empty()) //no new free node
if(!extend()) //try to extend
return ptr; //false
ptr=freenodes.front(); //now it must contain free node
freenodes.pop_front();
constructObj(ptr,ObjInitial);
busyCount++;
return ptr;
}
bool extend(size_t size=0)
{
if((0!=maxsize&&poolsize>=maxsize&&poolsize!=0)
)
return false; //we reach the maximum size
//poolsize=0 first allocation
//size=0 extend twice size of current size
//poolsize=size=0 we got a problem
size_t extSize=((0==poolsize)?size:2*poolsize);
char *pFragment=new char[extSize*sizeof(Node)];
if(!pFragment)
return false;
fragments.push_back(pFragment);
poolsize+=extSize;
for(Node *p=(Node*)pFragment; extSize--; p++)
{
constructObj(p,PoolAllocate);
freenodes.push_back(p);
allnodes.push_back(p);
}
allnodes.sort();
return true;
}
void constructObj(Node *p,InitialType phase)
{
if(phase==initialtype)
::new(p)Node;
}
void destroyObj(Node *p,InitialType phase)
{
if(phase==initialtype)
p->~Node();
}
size_t poolsize;
InitialType initialtype;
size_t maxsize;
FRAGMENTTYPE fragments;
NODELIST freenodes;
NODELIST allnodes;
size_t busyCount;
InitalFunction initalFunction;
obthreadlock<isthreadsafe> obthreadlock_;
};
};