/**
@brief メモリプール（malloc new より速くメモリ確保できる）

@note
http://d.hatena.ne.jp/studiokingyo/20041212

- boost::pool は5120byteのような大きめのデータに向いている 
- MemoryPool,object_pool(私のライブラリ)は16byteくらいの小さいデータに向いている 

*/
#ifndef DKUTIL_MEMORY_OBJECT_POOL_HPP
#define DKUTIL_MEMORY_OBJECT_POOL_HPP

#include <dkutil/policy/allocate.hpp>
#include <dkutil/memory/interface.hpp>


namespace dkutil{

template<class T,size_t MAX_NUM__=1024,
typename ALP__ = policy::allocate_policy_malloc_uninitialize_block>
class object_pool{
public:
	typedef ALP__ allocator_type;

	typedef size_t    size_type;
  typedef ptrdiff_t difference_type;
  typedef T*        pointer;
  typedef const T*  const_pointer;
  typedef T&        reference;
  typedef const T&  const_reference;
  typedef T         value_type;
	typedef object_pool<T,MAX_NUM__,ALP__> self_type;

	BOOST_STATIC_CONSTANT(size_t,max_num = MAX_NUM__);
	BOOST_STATIC_CONSTANT(size_t,object_size = sizeof(T));


	object_pool(){
		mp = NULL;
		construct__();
	}
	~object_pool(){
		dkcFreeSameObjectPool(&mp);
	}

  pointer allocate() {
		return (pointer)dkcSameObjectPoolAlloc(mp);
	}
  void deallocate(pointer p) {
		//if(p==NULL) return;
    dkcSameObjectPoolFree(p);
  }
	///リサイクル領域を入れる (非奨励）
	void recycle(pointer p){
		dkcSameObjectPoolRecycle(mp,p);
	}
	///足りないメモリを補充
	void reserve(){
		dkcSameObjectPoolReserve(mp);
	}
private:
	DKC_SAME_OBJECT_POOL *mp;
	
	void check__(){
		dkcmFORCE_NOT_ASSERT(NULL==mp);
	}
	void construct__(){
		mp = dkcAllocSameObjectPool(sizeof(T),max_num,
			allocator_type::malloc,
			allocator_type::free
		);
	}
};

/**
object_poolの少しだけ速い版
*/
template<class T,size_t MAX_NUM__=5120>
class fast_object_pool{
public:

	typedef size_t    size_type;
  typedef ptrdiff_t difference_type;
  typedef T*        pointer;
  typedef const T*  const_pointer;
  typedef T&        reference;
  typedef const T&  const_reference;
  typedef T         value_type;
	typedef fast_object_pool<T,MAX_NUM__> self_type;

	BOOST_STATIC_CONSTANT(size_t,max_num = MAX_NUM__);
	BOOST_STATIC_CONSTANT(size_t,object_size = sizeof(T));


	fast_object_pool(){
		mp = NULL;
		construct__();
	}
	~fast_object_pool(){
		dkcFreeSameObjectPool(&mp);
	}

  pointer allocate() {
		return (pointer)dkcSameObjectPoolAlloc(mp);
	}
  void deallocate(pointer p) {
		//if(p==NULL) return;
    dkcSameObjectPoolFree(p);
  }
	///リサイクル領域を入れる (非奨励）
	void recycle(pointer p){
		dkcSameObjectPoolRecycle(mp,p);
	}
	///足りないメモリを補充
	void reserve(){
		dkcSameObjectPoolReserve(mp);
	}
private:
	DKC_SAME_OBJECT_POOL *mp;
	
	void check__(){
		dkcmFORCE_NOT_ASSERT(NULL==mp);
	}
	void construct__(){
		mp = dkcAllocSameObjectPool(sizeof(T),max_num,
			NULL,NULL
		);
	}
};


}//end of namespace




#endif