#ifndef _KOK_MEMORYPOOL_H_
#define _KOK_MEMORYPOOL_H_
#pragma once
#include <cstddef>
#include "StaticAssert.h"
#include <new>
#define NULL 0
namespace KOK
{
typedef void (*FnDestroy)(void* p);
struct ArrayHeader
{
size_t nArrayCount;
};
template <class T, bool b = TypeTraits::IsClass<T>::value>
struct FnTrait
{
static void Destory(void* p)
{
((T*)p)->~T();
}
static void DestoryArray(void* p)
{
ArrayHeader* pHeader = (ArrayHeader*)p;
T* pElem = (T*)(pHeader + 1);
while(pHeader->nArrayCount)
{
pElem->~T();
pElem++;
pHeader->nArrayCount--;
}
}
};
template <class T>
struct FnTrait<T, false>
{
static FnDestroy Destory;
static FnDestroy DestoryArray;
};
template <class T>
FnDestroy FnTrait<T, false>::Destory = NULL;
template <class T>
FnDestroy FnTrait<T, false>::DestoryArray = NULL;
class MemoryPool
{
struct DestroyNode
{
FnDestroy fnDestroy;
DestroyNode* pNodePrev;
};
struct MemPage
{
void* pPos;
void* pLast;
MemPage* pPagePrev;
};
protected:
inline void* AllocAux(size_t nSize) const { return malloc(nSize); }
inline void FreeAux(void* p) const { return free(p); }
MemPage* AllocNewPage(size_t nSize);
public:
void* Alloc(size_t nSize, FnDestroy fnDestroy);
void* AllocArray(size_t nSize, size_t nArrayCount, FnDestroy fnDestroy);
inline MemoryPool() { m_nMaxSize_ = PAGE_MAX_SIZE; m_nAlign_ = sizeof(char*); m_pCurPage_ = NULL; m_pCurDestroyNode_ = NULL; }
inline MemoryPool(size_t nSize, size_t nAlign = sizeof(char*)) { m_nMaxSize_ = nSize; m_nAlign_ = nAlign; m_pCurPage_ = NULL; m_pCurDestroyNode_ = NULL; }
void Reset();
void Clear();
inline ~MemoryPool() { Clear(); }
private:
static const unsigned int PAGE_MAX_SIZE = 1*1024*1024;
size_t m_nMaxSize_;
MemPage* m_pCurPage_;
DestroyNode* m_pCurDestroyNode_;
size_t m_nAlign_;
};
void* MemoryPool::Alloc(size_t nSize, FnDestroy fnDestroy)
{
if(fnDestroy != NULL)
nSize += sizeof(DestroyNode);
void* pTemp;
nSize = (nSize + (m_nAlign_ - 1)) & ~(m_nAlign_ - 1); // align
if(m_pCurPage_ == NULL)
{
m_pCurPage_ = AllocNewPage(nSize);
pTemp = m_pCurPage_->pPos;
m_pCurPage_->pPos = (void*)((char*)m_pCurPage_->pPos + nSize);
}
else if(nSize <= (char*)m_pCurPage_->pLast - (char*)m_pCurPage_->pPos)
{
pTemp = m_pCurPage_->pPos;
m_pCurPage_->pPos = (void*)((char*)m_pCurPage_->pPos + nSize);
}
else if(nSize <= (char*)m_pCurPage_->pPagePrev->pLast - (char*)m_pCurPage_->pPagePrev->pPos)
{
pTemp = m_pCurPage_->pPagePrev->pPos;
m_pCurPage_->pPagePrev->pPos = (void*)((char*)m_pCurPage_->pPagePrev->pPos + nSize);
}
else
{
MemPage* pNewPage = AllocNewPage(nSize);
pNewPage->pPagePrev = m_pCurPage_;
m_pCurPage_ = pNewPage;
pTemp = m_pCurPage_->pPos;
m_pCurPage_->pPos = (void*)((char*)m_pCurPage_->pPos + nSize);
}
if(fnDestroy != NULL)
{
DestroyNode* pDesTemp = (DestroyNode*)pTemp;
pTemp = pDesTemp + 1;
pDesTemp->fnDestroy = fnDestroy;
pDesTemp->pNodePrev = m_pCurDestroyNode_;
m_pCurDestroyNode_ = pDesTemp;
}
return pTemp;
}
void* MemoryPool::AllocArray(size_t nSize, size_t nArrayCount, FnDestroy fnDestroy)
{
if(fnDestroy != NULL)
{
nSize += sizeof(DestroyNode);
nSize += sizeof(ArrayHeader);
}
void* pTemp;
nSize = (nSize + (m_nAlign_ - 1)) & ~(m_nAlign_ - 1); // align
if(m_pCurPage_ == NULL)
{
m_pCurPage_ = AllocNewPage(nSize);
pTemp = m_pCurPage_->pPos;
m_pCurPage_->pPos = (void*)((char*)m_pCurPage_->pPos + nSize);
}
else if(nSize <= (char*)m_pCurPage_->pLast - (char*)m_pCurPage_->pPos)
{
pTemp = m_pCurPage_->pPos;
m_pCurPage_->pPos = (void*)((char*)m_pCurPage_->pPos + nSize);
}
else if(nSize <= (char*)m_pCurPage_->pPagePrev->pLast - (char*)m_pCurPage_->pPagePrev->pPos)
{
pTemp = m_pCurPage_->pPagePrev->pPos;
m_pCurPage_->pPagePrev->pPos = (void*)((char*)m_pCurPage_->pPagePrev->pPos + nSize);
}
else
{
MemPage* pNewPage = AllocNewPage(nSize);
pNewPage->pPagePrev = m_pCurPage_;
m_pCurPage_ = pNewPage;
pTemp = m_pCurPage_->pPos;
m_pCurPage_->pPos = (void*)((char*)m_pCurPage_->pPos + nSize);
}
if(fnDestroy != NULL)
{
DestroyNode* pDesTemp = (DestroyNode*)pTemp;
pTemp = pDesTemp + 1;
pDesTemp->fnDestroy = fnDestroy;
pDesTemp->pNodePrev = m_pCurDestroyNode_;
m_pCurDestroyNode_ = pDesTemp;
}
return pTemp;
}
MemoryPool::MemPage* MemoryPool::AllocNewPage(size_t nSize)
{
nSize = nSize > m_nMaxSize_ ? (nSize + sizeof(MemPage)) : (m_nMaxSize_ + sizeof(MemPage));
MemPage* pPageTemp = (MemPage*)AllocAux(nSize);
pPageTemp->pPagePrev = NULL;
pPageTemp->pPos = pPageTemp + sizeof(MemPage);
pPageTemp->pLast = pPageTemp + nSize;
return pPageTemp;
}
void MemoryPool::Reset()
{
char* pStart;
while(m_pCurDestroyNode_ != NULL)
{
m_pCurDestroyNode_->fnDestroy(m_pCurDestroyNode_ + 1);
m_pCurDestroyNode_ = m_pCurDestroyNode_->pNodePrev;
}
while(m_pCurPage_ != NULL)
{
pStart = (char*)m_pCurPage_;
memset(pStart + sizeof(MemPage), 0, (char*)(m_pCurPage_->pLast) - pStart);
m_pCurPage_->pPos = pStart + sizeof(MemPage);
m_pCurPage_ = m_pCurPage_->pPagePrev;
}
}
void MemoryPool::Clear()
{
char* pStart;
while(m_pCurDestroyNode_ != NULL)
{
m_pCurDestroyNode_->fnDestroy(m_pCurDestroyNode_ + 1);
m_pCurDestroyNode_ = m_pCurDestroyNode_->pNodePrev;
}
while(m_pCurPage_ != NULL)
{
MemPage* pPageTemp = m_pCurPage_->pPagePrev;
FreeAux(m_pCurPage_);
m_pCurPage_ = pPageTemp;
}
}
//
// Global Function
//
template <class T>
inline T* NewType(MemoryPool* memPool)
{
T* pAlloc = (T*)memPool->Alloc(sizeof(T), FnTrait<T>::Destory);
return new(pAlloc) T;
}
template <class T>
inline T* NewArray(MemoryPool* memPool, const size_t n)
{
if(n == 0)
return NULL;
T* pAlloc = (T*)memPool->AllocArray(sizeof(T), n, FnTrait<T>::DestoryArray);
return new(pAlloc) T[n];
}
#define NEW(PMEMPOOL, T) new((PMEMPOOL)->Alloc(sizeof(T), FnTrait<T>::Destory)) T
#define NEWARRAY(PMEMPOOL, T, N) (N) == 0 ? NULL : new((PMEMPOOL)->AllocArray(sizeof(T)*(N), (N), FnTrait<T>::DestoryArray)) T[(N)]
}
#endif
#ifndef _KOK_STATICASSERT_H_
#define _KOK_STATICASSERT_H_
#pragma once
namespace KOK
{
struct TypeTraits
{
template<typename T> struct IsArray { static const bool value = false; };
template<typename T, int N> struct IsArray<T[N]> { static const bool value = true; };
template<typename T> struct IsPointer { static const bool value = false; };
template<typename T> struct IsPointer<T*> { static const bool value = true; };
template<typename T> struct IsRef { static const bool value = false; };
template<typename T> struct IsRef<T&> { static const bool value = true; };
template<typename T> struct IsConst { static const bool value = false; };
template<typename T> struct IsConst<const T> { static const bool value = true; };
template<typename T> struct IsConstRef { static const bool value = false; };
template<typename T> struct IsConstRef<const T&> { static const bool value = true; };
template<typename T> struct IsConstPointer { static const bool value = false; };
template<typename T> struct IsConstPointer<const T*> { static const bool value = true; };
template<typename T> struct IsInteger { static const bool value = false; };
template<> struct IsInteger<int> { static const bool value = true; };
template<typename T> struct IsFloat { static const bool value = false; };
template<> struct IsFloat<float> { static const bool value = true; };
template<typename T> struct IsLong { static const bool value = false; };
template<> struct IsLong<long> { static const bool value = true; };
template<typename T> struct IsDouble { static const bool value = false; };
template<> struct IsDouble<double> { static const bool value = true; };
template<typename T> struct IsClass
{
private:
template<typename U> struct IsClassImpl
{
struct RightType { char store; };
struct WrongType { char store[2]; };
template<typename K> //in order to explict template so add it
static WrongType Func(...);
template<typename K>
static RightType Func(void (K::*)(void));
static const bool value = (sizeof(Func<U>(0)) == sizeof(RightType));
};
public:
static const bool value = IsClassImpl<T>::value;
};
/* template<typename T> struct is_enum
{
private:
template<typename U> struct is_enum_impl
{
struct right_type { char store; };
struct wrong_type { char store[2]; };
template<typename K>
static wrong_type func(...);
template<typename K>
static right_type func(K::);
static const bool value = (sizeof(func<U>(0)) == sizeof(right_type));
};
public:
static const bool value = is_class_impl<T>::value;
};*/
template<typename T> struct is_union
{};
};
}
#endif