wip
This commit is contained in:
parent
f57d69f91e
commit
208cee69eb
|
@ -0,0 +1,179 @@
|
|||
#ifndef AllocatorH
|
||||
#define AllocatorH
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace Moya
|
||||
{
|
||||
|
||||
template <class T, std::size_t growSize = 1024>
|
||||
class MemoryPool
|
||||
{
|
||||
struct Block
|
||||
{
|
||||
Block* next;
|
||||
};
|
||||
|
||||
class Buffer
|
||||
{
|
||||
static const std::size_t blockSize = sizeof(T) > sizeof(Block) ? sizeof(T) : sizeof(Block);
|
||||
uint8_t data[blockSize * growSize];
|
||||
|
||||
public:
|
||||
|
||||
Buffer* const next;
|
||||
|
||||
Buffer(Buffer* next) :
|
||||
next(next)
|
||||
{
|
||||
}
|
||||
|
||||
T* getBlock(std::size_t index)
|
||||
{
|
||||
return reinterpret_cast<T*>(&data[blockSize * index]);
|
||||
}
|
||||
};
|
||||
|
||||
Block* firstFreeBlock = nullptr;
|
||||
Buffer* firstBuffer = nullptr;
|
||||
std::size_t bufferedBlocks = growSize;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
MemoryPool() = default;
|
||||
MemoryPool(MemoryPool && memoryPool) = delete;
|
||||
MemoryPool(const MemoryPool & memoryPool) = delete;
|
||||
MemoryPool operator =(MemoryPool && memoryPool) = delete;
|
||||
MemoryPool operator =(const MemoryPool & memoryPool) = delete;
|
||||
|
||||
~MemoryPool()
|
||||
{
|
||||
while(firstBuffer)
|
||||
{
|
||||
Buffer* buffer = firstBuffer;
|
||||
firstBuffer = buffer->next;
|
||||
delete buffer;
|
||||
}
|
||||
}
|
||||
|
||||
T* allocate()
|
||||
{
|
||||
if(firstFreeBlock)
|
||||
{
|
||||
Block* block = firstFreeBlock;
|
||||
firstFreeBlock = block->next;
|
||||
return reinterpret_cast<T*>(block);
|
||||
}
|
||||
|
||||
if(bufferedBlocks >= growSize)
|
||||
{
|
||||
firstBuffer = new Buffer(firstBuffer);
|
||||
bufferedBlocks = 0;
|
||||
}
|
||||
|
||||
return firstBuffer->getBlock(bufferedBlocks++);
|
||||
}
|
||||
|
||||
void deallocate(T* pointer)
|
||||
{
|
||||
Block* block = reinterpret_cast<Block*>(pointer);
|
||||
block->next = firstFreeBlock;
|
||||
firstFreeBlock = block;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, std::size_t growSize = 1024>
|
||||
class Allocator : private MemoryPool<T, growSize>
|
||||
{
|
||||
#ifdef _WIN32
|
||||
Allocator* copyAllocator;
|
||||
std::allocator<T>* rebindAllocator = nullptr;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef T* pointer;
|
||||
typedef const T* const_pointer;
|
||||
typedef T & reference;
|
||||
typedef const T & const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
template <class U>
|
||||
struct rebind
|
||||
{
|
||||
typedef Allocator<U, growSize> other;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
Allocator() = default;
|
||||
|
||||
Allocator(Allocator & allocator) :
|
||||
copyAllocator(&allocator)
|
||||
{
|
||||
}
|
||||
|
||||
template <class U>
|
||||
Allocator(const Allocator<U, growSize> & other)
|
||||
{
|
||||
if(!std::is_same<T, U>::value)
|
||||
rebindAllocator = new std::allocator<T>();
|
||||
}
|
||||
|
||||
~Allocator()
|
||||
{
|
||||
delete rebindAllocator;
|
||||
}
|
||||
#endif
|
||||
|
||||
pointer allocate(size_type n, const void* hint = 0)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if(copyAllocator)
|
||||
return copyAllocator->allocate(n, hint);
|
||||
|
||||
if(rebindAllocator)
|
||||
return rebindAllocator->allocate(n, hint);
|
||||
#endif
|
||||
|
||||
if(n != 1 || hint)
|
||||
throw std::bad_alloc();
|
||||
|
||||
return MemoryPool<T, growSize>::allocate();
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type n)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if(copyAllocator)
|
||||
{
|
||||
copyAllocator->deallocate(p, n);
|
||||
return;
|
||||
}
|
||||
|
||||
if(rebindAllocator)
|
||||
{
|
||||
rebindAllocator->deallocate(p, n);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
MemoryPool<T, growSize>::deallocate(p);
|
||||
}
|
||||
|
||||
void construct(pointer p, const_reference val)
|
||||
{
|
||||
new(p) T(val);
|
||||
}
|
||||
|
||||
void destroy(pointer p)
|
||||
{
|
||||
p->~T();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,886 @@
|
|||
/*===========================================================================
|
||||
This library is released under the MIT license. See FSBAllocator.html
|
||||
for further information and documentation.
|
||||
|
||||
Copyright (c) 2008-2011 Juha Nieminen
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
=============================================================================*/
|
||||
|
||||
#ifndef INCLUDE_FSBALLOCATOR_HH
|
||||
#define INCLUDE_FSBALLOCATOR_HH
|
||||
|
||||
#include <new>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_BOOST
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OPENMP
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_PTHREAD
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_GCC
|
||||
#define FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
#include <boost/thread.hpp>
|
||||
typedef boost::mutex FSBAllocator_Mutex;
|
||||
#endif
|
||||
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OPENMP
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_BOOST
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_PTHREAD
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_GCC
|
||||
#define FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
#include <omp.h>
|
||||
|
||||
class FSBAllocator_Mutex
|
||||
{
|
||||
omp_lock_t mutex;
|
||||
|
||||
public:
|
||||
FSBAllocator_Mutex() { omp_init_lock(&mutex); }
|
||||
~FSBAllocator_Mutex() { omp_destroy_lock(&mutex); }
|
||||
void lock() { omp_set_lock(&mutex); }
|
||||
void unlock() { omp_unset_lock(&mutex); }
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_PTHREAD
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_BOOST
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OPENMP
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_GCC
|
||||
#define FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
#include <pthread.h>
|
||||
|
||||
class FSBAllocator_Mutex
|
||||
{
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
public:
|
||||
FSBAllocator_Mutex() { pthread_mutex_init(&mutex, NULL); }
|
||||
~FSBAllocator_Mutex() { pthread_mutex_destroy(&mutex); }
|
||||
void lock() { pthread_mutex_lock(&mutex); }
|
||||
void unlock() { pthread_mutex_unlock(&mutex); }
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_GCC) || defined(FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_GCC_WITH_SCHED)
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_BOOST
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OPENMP
|
||||
#undef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_PTHREAD
|
||||
#define FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_GCC_WITH_SCHED
|
||||
#include <sched.h>
|
||||
#endif
|
||||
class FSBAllocator_Mutex
|
||||
{
|
||||
volatile int lockFlag;
|
||||
|
||||
public:
|
||||
FSBAllocator_Mutex(): lockFlag(0) {}
|
||||
void lock()
|
||||
{
|
||||
while(!__sync_bool_compare_and_swap(&lockFlag, 0, 1))
|
||||
{
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_GCC_WITH_SCHED
|
||||
sched_yield();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
void unlock() { lockFlag = 0; }
|
||||
};
|
||||
#endif
|
||||
|
||||
template<unsigned ElemSize>
|
||||
class FSBAllocator_ElemAllocator
|
||||
{
|
||||
typedef std::size_t Data_t;
|
||||
static const Data_t BlockElements = 512;
|
||||
|
||||
static const Data_t DSize = sizeof(Data_t);
|
||||
static const Data_t ElemSizeInDSize = (ElemSize + (DSize-1)) / DSize;
|
||||
static const Data_t UnitSizeInDSize = ElemSizeInDSize + 1;
|
||||
static const Data_t BlockSize = BlockElements*UnitSizeInDSize;
|
||||
|
||||
class MemBlock
|
||||
{
|
||||
Data_t* block;
|
||||
Data_t firstFreeUnitIndex, allocatedElementsAmount, endIndex;
|
||||
|
||||
public:
|
||||
MemBlock():
|
||||
block(0),
|
||||
firstFreeUnitIndex(Data_t(-1)),
|
||||
allocatedElementsAmount(0)
|
||||
{}
|
||||
|
||||
bool isFull() const
|
||||
{
|
||||
return allocatedElementsAmount == BlockElements;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
delete[] block;
|
||||
block = 0;
|
||||
firstFreeUnitIndex = Data_t(-1);
|
||||
}
|
||||
|
||||
void* allocate(Data_t vectorIndex)
|
||||
{
|
||||
if(firstFreeUnitIndex == Data_t(-1))
|
||||
{
|
||||
if(!block)
|
||||
{
|
||||
block = new Data_t[BlockSize];
|
||||
if(!block) return 0;
|
||||
endIndex = 0;
|
||||
}
|
||||
|
||||
Data_t* retval = block + endIndex;
|
||||
endIndex += UnitSizeInDSize;
|
||||
retval[ElemSizeInDSize] = vectorIndex;
|
||||
++allocatedElementsAmount;
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
Data_t* retval = block + firstFreeUnitIndex;
|
||||
firstFreeUnitIndex = *retval;
|
||||
++allocatedElementsAmount;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
void deallocate(Data_t* ptr)
|
||||
{
|
||||
*ptr = firstFreeUnitIndex;
|
||||
firstFreeUnitIndex = ptr - block;
|
||||
|
||||
if(--allocatedElementsAmount == 0)
|
||||
clear();
|
||||
}
|
||||
};
|
||||
|
||||
struct BlocksVector
|
||||
{
|
||||
std::vector<MemBlock> data;
|
||||
|
||||
BlocksVector() { data.reserve(1024); }
|
||||
|
||||
~BlocksVector()
|
||||
{
|
||||
for(std::size_t i = 0; i < data.size(); ++i)
|
||||
data[i].clear();
|
||||
}
|
||||
};
|
||||
|
||||
static BlocksVector blocksVector;
|
||||
static std::vector<Data_t> blocksWithFree;
|
||||
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
static FSBAllocator_Mutex mutex;
|
||||
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_BOOST
|
||||
struct Lock: boost::mutex::scoped_lock
|
||||
{
|
||||
Lock(): boost::mutex::scoped_lock(mutex) {}
|
||||
};
|
||||
#else
|
||||
struct Lock
|
||||
{
|
||||
Lock() { mutex.lock(); }
|
||||
~Lock() { mutex.unlock(); }
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public:
|
||||
static void* allocate()
|
||||
{
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
Lock lock;
|
||||
#endif
|
||||
|
||||
if(blocksWithFree.empty())
|
||||
{
|
||||
blocksWithFree.push_back(blocksVector.data.size());
|
||||
blocksVector.data.push_back(MemBlock());
|
||||
}
|
||||
|
||||
const Data_t index = blocksWithFree.back();
|
||||
MemBlock& block = blocksVector.data[index];
|
||||
void* retval = block.allocate(index);
|
||||
|
||||
if(block.isFull())
|
||||
blocksWithFree.pop_back();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void deallocate(void* ptr)
|
||||
{
|
||||
if(!ptr) return;
|
||||
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
Lock lock;
|
||||
#endif
|
||||
|
||||
Data_t* unitPtr = (Data_t*)ptr;
|
||||
const Data_t blockIndex = unitPtr[ElemSizeInDSize];
|
||||
MemBlock& block = blocksVector.data[blockIndex];
|
||||
|
||||
if(block.isFull())
|
||||
blocksWithFree.push_back(blockIndex);
|
||||
block.deallocate(unitPtr);
|
||||
}
|
||||
};
|
||||
|
||||
template<unsigned ElemSize>
|
||||
typename FSBAllocator_ElemAllocator<ElemSize>::BlocksVector
|
||||
FSBAllocator_ElemAllocator<ElemSize>::blocksVector;
|
||||
|
||||
template<unsigned ElemSize>
|
||||
std::vector<typename FSBAllocator_ElemAllocator<ElemSize>::Data_t>
|
||||
FSBAllocator_ElemAllocator<ElemSize>::blocksWithFree;
|
||||
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
template<unsigned ElemSize>
|
||||
FSBAllocator_Mutex FSBAllocator_ElemAllocator<ElemSize>::mutex;
|
||||
#endif
|
||||
|
||||
|
||||
template<unsigned ElemSize>
|
||||
class FSBAllocator2_ElemAllocator
|
||||
{
|
||||
static const std::size_t BlockElements = 1024;
|
||||
|
||||
static const std::size_t DSize = sizeof(std::size_t);
|
||||
static const std::size_t ElemSizeInDSize = (ElemSize + (DSize-1)) / DSize;
|
||||
static const std::size_t BlockSize = BlockElements*ElemSizeInDSize;
|
||||
|
||||
struct Blocks
|
||||
{
|
||||
std::vector<std::size_t*> ptrs;
|
||||
|
||||
Blocks()
|
||||
{
|
||||
ptrs.reserve(256);
|
||||
ptrs.push_back(new std::size_t[BlockSize]);
|
||||
}
|
||||
|
||||
~Blocks()
|
||||
{
|
||||
for(std::size_t i = 0; i < ptrs.size(); ++i)
|
||||
delete[] ptrs[i];
|
||||
}
|
||||
};
|
||||
|
||||
static Blocks blocks;
|
||||
static std::size_t headIndex;
|
||||
static std::size_t* freeList;
|
||||
static std::size_t allocatedElementsAmount;
|
||||
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
static FSBAllocator_Mutex mutex;
|
||||
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_BOOST
|
||||
struct Lock: boost::mutex::scoped_lock
|
||||
{
|
||||
Lock(): boost::mutex::scoped_lock(mutex) {}
|
||||
};
|
||||
#else
|
||||
struct Lock
|
||||
{
|
||||
Lock() { mutex.lock(); }
|
||||
~Lock() { mutex.unlock(); }
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void freeAll()
|
||||
{
|
||||
for(std::size_t i = 1; i < blocks.ptrs.size(); ++i)
|
||||
delete[] blocks.ptrs[i];
|
||||
blocks.ptrs.resize(1);
|
||||
headIndex = 0;
|
||||
freeList = 0;
|
||||
}
|
||||
|
||||
public:
|
||||
static void* allocate()
|
||||
{
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
Lock lock;
|
||||
#endif
|
||||
|
||||
++allocatedElementsAmount;
|
||||
|
||||
if(freeList)
|
||||
{
|
||||
std::size_t* retval = freeList;
|
||||
freeList = reinterpret_cast<std::size_t*>(*freeList);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if(headIndex == BlockSize)
|
||||
{
|
||||
blocks.ptrs.push_back(new std::size_t[BlockSize]);
|
||||
headIndex = 0;
|
||||
}
|
||||
|
||||
std::size_t* retval = &(blocks.ptrs.back()[headIndex]);
|
||||
headIndex += ElemSizeInDSize;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void deallocate(void* ptr)
|
||||
{
|
||||
if(ptr)
|
||||
{
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
Lock lock;
|
||||
#endif
|
||||
|
||||
std::size_t* sPtr = (std::size_t*)ptr;
|
||||
*sPtr = reinterpret_cast<std::size_t>(freeList);
|
||||
freeList = sPtr;
|
||||
|
||||
if(--allocatedElementsAmount == 0)
|
||||
freeAll();
|
||||
}
|
||||
}
|
||||
|
||||
static void cleanSweep(std::size_t unusedValue = std::size_t(-1))
|
||||
{
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
Lock lock;
|
||||
#endif
|
||||
|
||||
while(freeList)
|
||||
{
|
||||
std::size_t* current = freeList;
|
||||
freeList = reinterpret_cast<std::size_t*>(*freeList);
|
||||
*current = unusedValue;
|
||||
}
|
||||
|
||||
for(std::size_t i = headIndex; i < BlockSize; i += ElemSizeInDSize)
|
||||
blocks.ptrs.back()[i] = unusedValue;
|
||||
|
||||
for(std::size_t blockInd = 1; blockInd < blocks.ptrs.size();)
|
||||
{
|
||||
std::size_t* block = blocks.ptrs[blockInd];
|
||||
std::size_t freeAmount = 0;
|
||||
for(std::size_t i = 0; i < BlockSize; i += ElemSizeInDSize)
|
||||
if(block[i] == unusedValue)
|
||||
++freeAmount;
|
||||
|
||||
if(freeAmount == BlockElements)
|
||||
{
|
||||
delete[] block;
|
||||
blocks.ptrs[blockInd] = blocks.ptrs.back();
|
||||
blocks.ptrs.pop_back();
|
||||
}
|
||||
else ++blockInd;
|
||||
}
|
||||
|
||||
const std::size_t* lastBlock = blocks.ptrs.back();
|
||||
for(headIndex = BlockSize; headIndex > 0; headIndex -= ElemSizeInDSize)
|
||||
if(lastBlock[headIndex-ElemSizeInDSize] != unusedValue)
|
||||
break;
|
||||
|
||||
const std::size_t lastBlockIndex = blocks.ptrs.size() - 1;
|
||||
for(std::size_t blockInd = 0; blockInd <= lastBlockIndex; ++blockInd)
|
||||
{
|
||||
std::size_t* block = blocks.ptrs[blockInd];
|
||||
for(std::size_t i = 0; i < BlockSize; i += ElemSizeInDSize)
|
||||
{
|
||||
if(blockInd == lastBlockIndex && i == headIndex)
|
||||
break;
|
||||
|
||||
if(block[i] == unusedValue)
|
||||
deallocate(block + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<unsigned ElemSize>
|
||||
typename FSBAllocator2_ElemAllocator<ElemSize>::Blocks
|
||||
FSBAllocator2_ElemAllocator<ElemSize>::blocks;
|
||||
|
||||
template<unsigned ElemSize>
|
||||
std::size_t FSBAllocator2_ElemAllocator<ElemSize>::headIndex = 0;
|
||||
|
||||
template<unsigned ElemSize>
|
||||
std::size_t* FSBAllocator2_ElemAllocator<ElemSize>::freeList = 0;
|
||||
|
||||
template<unsigned ElemSize>
|
||||
std::size_t FSBAllocator2_ElemAllocator<ElemSize>::allocatedElementsAmount = 0;
|
||||
|
||||
#ifdef FSBALLOCATOR_USE_THREAD_SAFE_LOCKING_OBJECT
|
||||
template<unsigned ElemSize>
|
||||
FSBAllocator_Mutex FSBAllocator2_ElemAllocator<ElemSize>::mutex;
|
||||
#endif
|
||||
|
||||
|
||||
template<typename Ty>
|
||||
class FSBAllocator
|
||||
{
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef Ty *pointer;
|
||||
typedef const Ty *const_pointer;
|
||||
typedef Ty& reference;
|
||||
typedef const Ty& const_reference;
|
||||
typedef Ty value_type;
|
||||
|
||||
pointer address(reference val) const { return &val; }
|
||||
const_pointer address(const_reference val) const { return &val; }
|
||||
|
||||
template<class Other>
|
||||
struct rebind
|
||||
{
|
||||
typedef FSBAllocator<Other> other;
|
||||
};
|
||||
|
||||
FSBAllocator() throw() {}
|
||||
|
||||
template<class Other>
|
||||
FSBAllocator(const FSBAllocator<Other>&) throw() {}
|
||||
|
||||
template<class Other>
|
||||
FSBAllocator& operator=(const FSBAllocator<Other>&) { return *this; }
|
||||
|
||||
pointer allocate(size_type count, const void* = 0)
|
||||
{
|
||||
assert(count == 1);
|
||||
return static_cast<pointer>
|
||||
(FSBAllocator_ElemAllocator<sizeof(Ty)>::allocate());
|
||||
}
|
||||
|
||||
void deallocate(pointer ptr, size_type)
|
||||
{
|
||||
FSBAllocator_ElemAllocator<sizeof(Ty)>::deallocate(ptr);
|
||||
}
|
||||
|
||||
void construct(pointer ptr, const Ty& val)
|
||||
{
|
||||
new ((void *)ptr) Ty(val);
|
||||
}
|
||||
|
||||
void destroy(pointer ptr)
|
||||
{
|
||||
ptr->Ty::~Ty();
|
||||
}
|
||||
|
||||
size_type max_size() const throw() { return 1; }
|
||||
};
|
||||
|
||||
|
||||
template<typename Ty>
|
||||
class FSBAllocator2
|
||||
{
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef Ty *pointer;
|
||||
typedef const Ty *const_pointer;
|
||||
typedef Ty& reference;
|
||||
typedef const Ty& const_reference;
|
||||
typedef Ty value_type;
|
||||
|
||||
pointer address(reference val) const { return &val; }
|
||||
const_pointer address(const_reference val) const { return &val; }
|
||||
|
||||
template<class Other>
|
||||
struct rebind
|
||||
{
|
||||
typedef FSBAllocator2<Other> other;
|
||||
};
|
||||
|
||||
FSBAllocator2() throw() {}
|
||||
|
||||
template<class Other>
|
||||
FSBAllocator2(const FSBAllocator2<Other>&) throw() {}
|
||||
|
||||
template<class Other>
|
||||
FSBAllocator2& operator=(const FSBAllocator2<Other>&) { return *this; }
|
||||
|
||||
pointer allocate(size_type count, const void* = 0)
|
||||
{
|
||||
assert(count == 1);
|
||||
return static_cast<pointer>
|
||||
(FSBAllocator2_ElemAllocator<sizeof(Ty)>::allocate());
|
||||
}
|
||||
|
||||
void deallocate(pointer ptr, size_type)
|
||||
{
|
||||
FSBAllocator2_ElemAllocator<sizeof(Ty)>::deallocate(ptr);
|
||||
}
|
||||
|
||||
void construct(pointer ptr, const Ty& val)
|
||||
{
|
||||
new ((void *)ptr) Ty(val);
|
||||
}
|
||||
|
||||
void destroy(pointer ptr)
|
||||
{
|
||||
ptr->Ty::~Ty();
|
||||
}
|
||||
|
||||
size_type max_size() const throw() { return 1; }
|
||||
|
||||
void cleanSweep(std::size_t unusedValue = std::size_t(-1))
|
||||
{
|
||||
FSBAllocator2_ElemAllocator<sizeof(Ty)>::cleanSweep(unusedValue);
|
||||
}
|
||||
};
|
||||
|
||||
typedef FSBAllocator2<std::size_t> FSBRefCountAllocator;
|
||||
|
||||
// <MyCustomAlloc>
|
||||
|
||||
|
||||
|
||||
extern long g_nCnt; // total # blocks allocated
|
||||
|
||||
extern long g_nTot; // total allocated
|
||||
|
||||
template <class T>
|
||||
|
||||
class MyCustomAlloc
|
||||
|
||||
/*
|
||||
|
||||
A custom allocator: given a pool of memory to start, just dole out consecutive memory blocks.
|
||||
|
||||
this could be faster than a general purpose allocator.
|
||||
|
||||
E.G. it could take advantage of constant sized requests (as in a RedBlack tree)
|
||||
|
||||
*/
|
||||
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef T value_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;
|
||||
|
||||
|
||||
|
||||
MyCustomAlloc(byte *pool, int nPoolSize)
|
||||
|
||||
{
|
||||
|
||||
Init();
|
||||
|
||||
m_pool = pool;
|
||||
|
||||
m_nPoolSize = nPoolSize;
|
||||
|
||||
}
|
||||
|
||||
MyCustomAlloc(int n)
|
||||
|
||||
{
|
||||
|
||||
Init();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
MyCustomAlloc()
|
||||
|
||||
{
|
||||
|
||||
Init();
|
||||
|
||||
}
|
||||
|
||||
void Init()
|
||||
|
||||
{
|
||||
|
||||
m_pool = 0;
|
||||
|
||||
m_nPoolSize = 0;
|
||||
|
||||
g_nCnt = 0;
|
||||
|
||||
g_nTot = 0;
|
||||
|
||||
}
|
||||
|
||||
MyCustomAlloc(const MyCustomAlloc &obj) // copy constructor
|
||||
|
||||
{
|
||||
|
||||
Init();
|
||||
|
||||
m_pool = obj.m_pool;
|
||||
|
||||
m_nPoolSize = obj.m_nPoolSize;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void operator =(const MyCustomAlloc &);
|
||||
|
||||
public:
|
||||
|
||||
byte *m_pool;
|
||||
|
||||
unsigned m_nPoolSize;
|
||||
|
||||
|
||||
|
||||
template <class _Other>
|
||||
|
||||
MyCustomAlloc(const MyCustomAlloc<_Other> &other)
|
||||
|
||||
{
|
||||
|
||||
Init();
|
||||
|
||||
m_pool = other.m_pool;
|
||||
|
||||
m_nPoolSize = other.m_nPoolSize;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
~MyCustomAlloc()
|
||||
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class U>
|
||||
|
||||
struct rebind
|
||||
|
||||
{
|
||||
|
||||
typedef MyCustomAlloc<U> other;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
pointer
|
||||
|
||||
address(reference r) const
|
||||
|
||||
{
|
||||
|
||||
return &r;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
const_pointer
|
||||
|
||||
address(const_reference r) const
|
||||
|
||||
{
|
||||
|
||||
return &r;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
pointer
|
||||
|
||||
allocate(size_type n, const void* /*hint*/ = 0)
|
||||
|
||||
{
|
||||
|
||||
pointer p;
|
||||
|
||||
unsigned nSize = n * sizeof(T);
|
||||
|
||||
if (m_pool) // if we have a mem pool from which to allocated
|
||||
|
||||
{
|
||||
|
||||
p = (pointer)m_pool;// just return the next available mem in the pool
|
||||
|
||||
if (g_nTot + nSize > m_nPoolSize)
|
||||
|
||||
{
|
||||
|
||||
_ASSERT(0);//,"out of mem pool");
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
m_pool += nSize; // and bump the pointer
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
|
||||
{
|
||||
|
||||
p = (pointer)malloc(nSize);// no pool: just use malloc
|
||||
|
||||
}
|
||||
|
||||
g_nCnt += 1;
|
||||
|
||||
g_nTot += nSize;
|
||||
|
||||
_ASSERTE(p);
|
||||
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
|
||||
deallocate(pointer p, size_type /*n*/)
|
||||
|
||||
{
|
||||
|
||||
if (!m_pool)// if there's a pool, nothing to do
|
||||
|
||||
{
|
||||
|
||||
free(p);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
|
||||
construct(pointer p, const T& val)
|
||||
|
||||
{
|
||||
|
||||
new (p) T(val);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
|
||||
destroy(pointer p)
|
||||
|
||||
{
|
||||
|
||||
p->~T();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_type
|
||||
|
||||
max_size() const
|
||||
|
||||
{
|
||||
|
||||
return ULONG_MAX / sizeof(T);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
|
||||
bool
|
||||
|
||||
operator==(const MyCustomAlloc<T>& left, const MyCustomAlloc<T>& right)
|
||||
|
||||
{
|
||||
|
||||
if (left.m_pool == right.m_pool)
|
||||
|
||||
{
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class T>
|
||||
|
||||
bool
|
||||
|
||||
operator!=(const MyCustomAlloc<T>& left, const MyCustomAlloc<T>& right)
|
||||
|
||||
{
|
||||
|
||||
if (left.m_pool != right.m_pool)
|
||||
|
||||
{
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// </MyCustomAlloc>
|
||||
|
||||
#endif
|
|
@ -0,0 +1,141 @@
|
|||
#include "Allocator.h"
|
||||
#include "DataTypes.h"
|
||||
#include <new>
|
||||
#include <assert.h>
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Constructor
|
||||
//------------------------------------------------------------------------------
|
||||
Allocator::Allocator(size_t size, UINT objects, CHAR* memory, const CHAR* name) :
|
||||
m_blockSize(size < sizeof(long*) ? sizeof(long*) : size),
|
||||
m_objectSize(size),
|
||||
m_maxObjects(objects),
|
||||
m_pHead(NULL),
|
||||
m_poolIndex(0),
|
||||
m_blockCnt(0),
|
||||
m_blocksInUse(0),
|
||||
m_allocations(0),
|
||||
m_deallocations(0),
|
||||
m_name(name)
|
||||
{
|
||||
// If using a fixed memory pool
|
||||
if(m_maxObjects)
|
||||
{
|
||||
// If caller provided an external memory pool
|
||||
if(memory)
|
||||
{
|
||||
m_pPool = memory;
|
||||
m_allocatorMode = STATIC_POOL;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pPool = (CHAR*)new CHAR[m_blockSize * m_maxObjects];
|
||||
m_allocatorMode = HEAP_POOL;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_allocatorMode = HEAP_BLOCKS;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Destructor
|
||||
//------------------------------------------------------------------------------
|
||||
Allocator::~Allocator()
|
||||
{
|
||||
// If using pool then destroy it, otherwise traverse free-list and
|
||||
// destroy each individual block
|
||||
if(m_allocatorMode == HEAP_POOL)
|
||||
delete [] m_pPool;
|
||||
else if(m_allocatorMode == HEAP_BLOCKS)
|
||||
{
|
||||
while(m_pHead)
|
||||
delete [](CHAR*)Pop();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Allocate
|
||||
//------------------------------------------------------------------------------
|
||||
void* Allocator::Allocate(size_t size)
|
||||
{
|
||||
assert(size <= m_objectSize);
|
||||
|
||||
// If can't obtain existing block then get a new one
|
||||
void* pBlock = Pop();
|
||||
if(!pBlock)
|
||||
{
|
||||
// If using a pool method then get block from pool,
|
||||
// otherwise using dynamic so get block from heap
|
||||
if(m_maxObjects)
|
||||
{
|
||||
// If we have not exceeded the pool maximum
|
||||
if(m_poolIndex < m_maxObjects)
|
||||
{
|
||||
pBlock = (void*)(m_pPool + (m_poolIndex++ * m_blockSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the pointer to the new handler
|
||||
std::new_handler handler = std::set_new_handler(0);
|
||||
std::set_new_handler(handler);
|
||||
|
||||
// If a new handler is defined, call it
|
||||
if(handler)
|
||||
(*handler)();
|
||||
else
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_blockCnt++;
|
||||
pBlock = (void*)new CHAR[m_blockSize];
|
||||
}
|
||||
}
|
||||
|
||||
m_blocksInUse++;
|
||||
m_allocations++;
|
||||
|
||||
return pBlock;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Deallocate
|
||||
//------------------------------------------------------------------------------
|
||||
void Allocator::Deallocate(void* pBlock)
|
||||
{
|
||||
Push(pBlock);
|
||||
m_blocksInUse--;
|
||||
m_deallocations++;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Push
|
||||
//------------------------------------------------------------------------------
|
||||
void Allocator::Push(void* pMemory)
|
||||
{
|
||||
Block* pBlock = (Block*)pMemory;
|
||||
pBlock->pNext = m_pHead;
|
||||
m_pHead = pBlock;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Pop
|
||||
//------------------------------------------------------------------------------
|
||||
void* Allocator::Pop()
|
||||
{
|
||||
Block* pBlock = NULL;
|
||||
|
||||
if(m_pHead)
|
||||
{
|
||||
pBlock = m_pHead;
|
||||
m_pHead = m_pHead->pNext;
|
||||
}
|
||||
|
||||
return (void*)pBlock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
#ifndef __ALLOCATOR_H
|
||||
#define __ALLOCATOR_H
|
||||
|
||||
#include "DataTypes.h"
|
||||
#include <stddef.h>
|
||||
|
||||
/// See http://www.codeproject.com/Articles/1083210/An-efficient-Cplusplus-fixed-block-memory-allocato
|
||||
class Allocator
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
/// @param[in] size - size of the fixed blocks
|
||||
/// @param[in] objects - maximum number of object. If 0, new blocks are
|
||||
/// created off the heap as necessary.
|
||||
/// @param[in] memory - pointer to a block of static memory for allocator or NULL
|
||||
/// to obtain memory from global heap. If not NULL, the objects argument
|
||||
/// defines the size of the memory block (size x objects = memory size in bytes).
|
||||
/// @param[in] name - optional allocator name string.
|
||||
Allocator(size_t size, UINT objects = 0, CHAR* memory = NULL, const CHAR* name = NULL);
|
||||
|
||||
/// Destructor
|
||||
~Allocator();
|
||||
|
||||
/// Get a pointer to a memory block.
|
||||
/// @param[in] size - size of the block to allocate
|
||||
/// @return Returns pointer to the block. Otherwise NULL if unsuccessful.
|
||||
void* Allocate(size_t size);
|
||||
|
||||
/// Return a pointer to the memory pool.
|
||||
/// @param[in] pBlock - block of memory deallocate (i.e push onto free-list)
|
||||
void Deallocate(void* pBlock);
|
||||
|
||||
/// Get the allocator name string.
|
||||
/// @return A pointer to the allocator name or NULL if none was assigned.
|
||||
const CHAR* GetName() { return m_name; }
|
||||
|
||||
/// Gets the fixed block memory size, in bytes, handled by the allocator.
|
||||
/// @return The fixed block size in bytes.
|
||||
size_t GetBlockSize() { return m_blockSize; }
|
||||
|
||||
/// Gets the maximum number of blocks created by the allocator.
|
||||
/// @return The number of fixed memory blocks created.
|
||||
UINT GetBlockCount() { return m_blockCnt; }
|
||||
|
||||
/// Gets the number of blocks in use.
|
||||
/// @return The number of blocks in use by the application.
|
||||
UINT GetBlocksInUse() { return m_blocksInUse; }
|
||||
|
||||
/// Gets the total number of allocations for this allocator instance.
|
||||
/// @return The total number of allocations.
|
||||
UINT GetAllocations() { return m_allocations; }
|
||||
|
||||
/// Gets the total number of deallocations for this allocator instance.
|
||||
/// @return The total number of deallocations.
|
||||
UINT GetDeallocations() { return m_deallocations; }
|
||||
|
||||
private:
|
||||
/// Push a memory block onto head of free-list.
|
||||
/// @param[in] pMemory - block of memory to push onto free-list
|
||||
void Push(void* pMemory);
|
||||
|
||||
/// Pop a memory block from head of free-list.
|
||||
/// @return Returns pointer to the block. Otherwise NULL if unsuccessful.
|
||||
void* Pop();
|
||||
|
||||
struct Block
|
||||
{
|
||||
Block* pNext;
|
||||
};
|
||||
|
||||
enum AllocatorMode { HEAP_BLOCKS, HEAP_POOL, STATIC_POOL };
|
||||
|
||||
const size_t m_blockSize;
|
||||
const size_t m_objectSize;
|
||||
const UINT m_maxObjects;
|
||||
AllocatorMode m_allocatorMode;
|
||||
Block* m_pHead;
|
||||
CHAR* m_pPool;
|
||||
UINT m_poolIndex;
|
||||
UINT m_blockCnt;
|
||||
UINT m_blocksInUse;
|
||||
UINT m_allocations;
|
||||
UINT m_deallocations;
|
||||
const CHAR* m_name;
|
||||
};
|
||||
|
||||
// Template class to create external memory pool
|
||||
template <class T, UINT Objects>
|
||||
class AllocatorPool : public Allocator
|
||||
{
|
||||
public:
|
||||
AllocatorPool() : Allocator(sizeof(T), Objects, m_memory)
|
||||
{
|
||||
}
|
||||
private:
|
||||
CHAR m_memory[sizeof(T) * Objects];
|
||||
};
|
||||
|
||||
// macro to provide header file interface
|
||||
#define DECLARE_ALLOCATOR \
|
||||
public: \
|
||||
void* operator new(size_t size) { \
|
||||
return _allocator.Allocate(size); \
|
||||
} \
|
||||
void operator delete(void* pObject) { \
|
||||
_allocator.Deallocate(pObject); \
|
||||
} \
|
||||
private: \
|
||||
static Allocator _allocator;
|
||||
|
||||
// macro to provide source file interface
|
||||
#define IMPLEMENT_ALLOCATOR(class, objects, memory) \
|
||||
Allocator class::_allocator(sizeof(class), objects, memory, #class);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef _DATA_TYPES_H
|
||||
#define _DATA_TYPES_H
|
||||
|
||||
#if WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
typedef signed char INT8;
|
||||
typedef unsigned char UINT8;
|
||||
typedef signed short INT16;
|
||||
typedef unsigned short UINT16;
|
||||
typedef unsigned int UINT32;
|
||||
typedef int INT32;
|
||||
typedef char CHAR;
|
||||
typedef short SHORT;
|
||||
typedef long LONG;
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
typedef unsigned long DWORD;
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short WORD;
|
||||
typedef float FLOAT;
|
||||
typedef double DOUBLE;
|
||||
typedef int BOOL;
|
||||
|
||||
#ifndef NULL
|
||||
#ifdef __cplusplus
|
||||
#define NULL 0
|
||||
#else
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,16 @@
|
|||
#include "Fault.h"
|
||||
#include "DataTypes.h"
|
||||
#include <assert.h>
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// FaultHandler
|
||||
//----------------------------------------------------------------------------
|
||||
void FaultHandler(const char* file, unsigned short line)
|
||||
{
|
||||
#if WIN32
|
||||
// If you hit this line, it means one of the ASSERT macros failed.
|
||||
DebugBreak();
|
||||
#endif
|
||||
|
||||
assert(0);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef _FAULT_H
|
||||
#define _FAULT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ASSERT() \
|
||||
FaultHandler(__FILE__, (unsigned short) __LINE__)
|
||||
|
||||
#define ASSERT_TRUE(condition) \
|
||||
do {if (!(condition)) FaultHandler(__FILE__, (unsigned short) __LINE__);} while (0)
|
||||
|
||||
/// Handles all software assertions in the system.
|
||||
/// @param[in] file - the file name that the software assertion occurred on
|
||||
/// @param[in] line - the line number that the software assertion occurred on
|
||||
void FaultHandler(const char* file, unsigned short line);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,194 @@
|
|||
#include "stdafx.h"
|
||||
#include <new>
|
||||
#include <iostream>
|
||||
#include "xlist.h"
|
||||
#include "xmap.h"
|
||||
#include "xqueue.h"
|
||||
#include "xset.h"
|
||||
#include "xsstream.h"
|
||||
#include "xstring.h"
|
||||
|
||||
// On VisualStudio, to disable the debug heap for faster performance when using
|
||||
// the debugger use this option:
|
||||
// Debugging > Environment _NO_DEBUG_HEAP=1
|
||||
|
||||
using namespace std;
|
||||
|
||||
static int MAX_BENCHMARK = 10000;
|
||||
|
||||
typedef void (*TestFunc)();
|
||||
void ListGlobalHeapTest();
|
||||
void MapGlobalHeapTest();
|
||||
void StringGlobalHeapTest();
|
||||
void ListFixedBlockTest();
|
||||
void MapFixedBlockTest();
|
||||
void StringFixedBlockTest();
|
||||
void Benchmark(const char* name, TestFunc testFunc);
|
||||
|
||||
static void out_of_memory()
|
||||
{
|
||||
// new-handler function called by Allocator when pool is out of memory
|
||||
ASSERT();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// main
|
||||
//------------------------------------------------------------------------------
|
||||
int main(void)
|
||||
{
|
||||
std::set_new_handler(out_of_memory);
|
||||
|
||||
xlist<int> myList;
|
||||
myList.push_back(123);
|
||||
|
||||
xmap<char, int> myMap;
|
||||
myMap['a'] = 10;
|
||||
|
||||
xqueue<int> myQueue;
|
||||
myQueue.push(123);
|
||||
|
||||
xset<xstring> mySet;
|
||||
mySet.insert("hello");
|
||||
mySet.insert("world");
|
||||
|
||||
xstringstream myStringStream;
|
||||
myStringStream << "hello world " << 2016 << ends;
|
||||
|
||||
xwstringstream myWStringStream;
|
||||
myWStringStream << L"hello world " << 2016 << ends;
|
||||
|
||||
xstring myString("hello world");
|
||||
|
||||
Benchmark("std::list Global Heap (Run 1)", ListGlobalHeapTest);
|
||||
Benchmark("std::list Global Heap (Run 2)", ListGlobalHeapTest);
|
||||
Benchmark("std::list Global Heap (Run 3)", ListGlobalHeapTest);
|
||||
|
||||
Benchmark("xlist Fixed Block (Run 1)", ListFixedBlockTest);
|
||||
Benchmark("xlist Fixed Block (Run 2)", ListFixedBlockTest);
|
||||
Benchmark("xlist Fixed Block (Run 3)", ListFixedBlockTest);
|
||||
|
||||
Benchmark("std::map Global Heap (Run 1)", MapGlobalHeapTest);
|
||||
Benchmark("std::map Global Heap (Run 2)", MapGlobalHeapTest);
|
||||
Benchmark("std::map Global Heap (Run 3)", MapGlobalHeapTest);
|
||||
|
||||
Benchmark("xmap Fixed Block (Run 1)", MapFixedBlockTest);
|
||||
Benchmark("xmap Fixed Block (Run 2)", MapFixedBlockTest);
|
||||
Benchmark("xmap Fixed Block (Run 3)", MapFixedBlockTest);
|
||||
|
||||
Benchmark("std::string Global Heap (Run 1)", StringGlobalHeapTest);
|
||||
Benchmark("std::string Global Heap (Run 2)", StringGlobalHeapTest);
|
||||
Benchmark("std::string Global Heap (Run 3)", StringGlobalHeapTest);
|
||||
|
||||
Benchmark("xstring Fixed Block (Run 1)", StringFixedBlockTest);
|
||||
Benchmark("xstring Fixed Block (Run 2)", StringFixedBlockTest);
|
||||
Benchmark("xstring Fixed Block (Run 3)", StringFixedBlockTest);
|
||||
|
||||
xalloc_stats();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// MapGlobalHeapTest
|
||||
//------------------------------------------------------------------------------
|
||||
void MapGlobalHeapTest()
|
||||
{
|
||||
map<int, char> myMap;
|
||||
for(int i = 0; i < MAX_BENCHMARK; i++)
|
||||
myMap[i] = 'a';
|
||||
myMap.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// MapFixedBlockTest
|
||||
//------------------------------------------------------------------------------
|
||||
void MapFixedBlockTest()
|
||||
{
|
||||
xmap<int, char> myMap;
|
||||
for(int i = 0; i < MAX_BENCHMARK; i++)
|
||||
myMap[i] = 'a';
|
||||
myMap.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// ListGlobalHeapTest
|
||||
//------------------------------------------------------------------------------
|
||||
void ListGlobalHeapTest()
|
||||
{
|
||||
list<int> myList;
|
||||
for(int i = 0; i < MAX_BENCHMARK; i++)
|
||||
myList.push_back(123);
|
||||
myList.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// ListFixedBlockTest
|
||||
//------------------------------------------------------------------------------
|
||||
void ListFixedBlockTest()
|
||||
{
|
||||
xlist<int> myList;
|
||||
for(int i = 0; i < MAX_BENCHMARK; i++)
|
||||
myList.push_back(123);
|
||||
myList.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// StringGlobalHeapTest
|
||||
//------------------------------------------------------------------------------
|
||||
void StringGlobalHeapTest()
|
||||
{
|
||||
list<string> myList;
|
||||
for(int i = 0; i < MAX_BENCHMARK; i++)
|
||||
{
|
||||
string myString("benchmark");
|
||||
myString += "benchmark test benchmark test benchmark test benchmark test benchmark test benchmark test benchmark test "
|
||||
"benchmark test benchmark test benchmark test benchmark test benchmark test benchmark test benchmark test";
|
||||
myList.push_back(myString);
|
||||
}
|
||||
myList.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// StringFixedBlockTest
|
||||
//------------------------------------------------------------------------------
|
||||
void StringFixedBlockTest()
|
||||
{
|
||||
xlist<xstring> myList;
|
||||
for(int i = 0; i < MAX_BENCHMARK; i++)
|
||||
{
|
||||
xstring myString("benchmark");
|
||||
myString += "benchmark test benchmark test benchmark test benchmark test benchmark test benchmark test benchmark test "
|
||||
"benchmark test benchmark test benchmark test benchmark test benchmark test benchmark test benchmark test";
|
||||
myList.push_back(myString);
|
||||
}
|
||||
myList.clear();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Benchmark
|
||||
//------------------------------------------------------------------------------
|
||||
void Benchmark(const char* name, TestFunc testFunc)
|
||||
{
|
||||
#if WIN32
|
||||
LARGE_INTEGER StartingTime, EndingTime, ElapsedMicroseconds = {0};
|
||||
LARGE_INTEGER Frequency;
|
||||
|
||||
SetProcessPriorityBoost(GetCurrentProcess(), true);
|
||||
|
||||
QueryPerformanceFrequency(&Frequency);
|
||||
QueryPerformanceCounter(&StartingTime);
|
||||
|
||||
// Call test function
|
||||
testFunc();
|
||||
|
||||
QueryPerformanceCounter(&EndingTime);
|
||||
|
||||
ElapsedMicroseconds.QuadPart = EndingTime.QuadPart - StartingTime.QuadPart;
|
||||
ElapsedMicroseconds.QuadPart *= 1000000;
|
||||
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;
|
||||
std::cout << name << " Elapsed time: " << ElapsedMicroseconds.QuadPart << std::endl;
|
||||
|
||||
SetProcessPriorityBoost(GetCurrentProcess(), false);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// Allocator.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
|
@ -0,0 +1,14 @@
|
|||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
|
@ -0,0 +1,138 @@
|
|||
#ifndef _STL_ALLOCATOR_H
|
||||
#define _STL_ALLOCATOR_H
|
||||
|
||||
// See http://www.codeproject.com/Articles/1089905/A-Custom-STL-std-allocator-Replacement-Improves-Performance-
|
||||
|
||||
#include "xallocator.h"
|
||||
#include "Fault.h"
|
||||
|
||||
template <typename T> class stl_allocator;
|
||||
template <> class stl_allocator<void>
|
||||
{
|
||||
public:
|
||||
typedef void* pointer;
|
||||
typedef const void* const_pointer;
|
||||
// reference to void members are impossible.
|
||||
typedef void value_type;
|
||||
|
||||
template <class U>
|
||||
struct rebind { typedef stl_allocator<U> other; };
|
||||
};
|
||||
|
||||
/// @brief stl_allocator is STL-compatible allocator used to provide fixed
|
||||
/// block allocations.
|
||||
/// @details The default allocator for the STL is the global heap. The
|
||||
/// stl_allocator is custom allocator where xmalloc/xfree is used to obtain
|
||||
/// and release memory.
|
||||
template <typename T>
|
||||
class stl_allocator
|
||||
{
|
||||
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;
|
||||
|
||||
/// Constructor
|
||||
stl_allocator() {}
|
||||
|
||||
/// Destructor
|
||||
~stl_allocator() {}
|
||||
|
||||
/// Copy constructor
|
||||
template <class U> stl_allocator(const stl_allocator<U> &) {}
|
||||
|
||||
template <class U>
|
||||
struct rebind { typedef stl_allocator<U> other; };
|
||||
|
||||
/// Return reference address.
|
||||
/// @return Pointer to T memory.
|
||||
pointer address(reference x) const {return &x;}
|
||||
|
||||
/// Return reference address.
|
||||
/// @return Const pointer to T memory.
|
||||
const_pointer address(const_reference x) const {return &x;}
|
||||
|
||||
/// Get the maximum size of memory.
|
||||
/// @return Max memory size in bytes.
|
||||
size_type max_size() const throw() {return size_t(-1) / sizeof(value_type);}
|
||||
|
||||
/// Allocates a fixed block of memory
|
||||
/// @param[in] n - size of memory to allocate in bytes
|
||||
/// @param[in] hint
|
||||
/// @return Pointer to the allocated memory.
|
||||
pointer allocate(size_type n, stl_allocator<void>::const_pointer hint = 0)
|
||||
{
|
||||
return static_cast<pointer>(xmalloc(n * sizeof(T)));
|
||||
}
|
||||
|
||||
/// Deallocate a previously allocated fixed memory block.
|
||||
/// @param[in] p - pointer to the memory block
|
||||
/// @param[in] n - size of memory in bytes
|
||||
void deallocate(pointer p, size_type n)
|
||||
{
|
||||
xfree(p);
|
||||
}
|
||||
|
||||
/// Constructs a new instance.
|
||||
/// @param[in] p - pointer to the memory where the instance is constructed
|
||||
/// using placement new.
|
||||
/// @param[in] val - instance of object to copy construct.
|
||||
void construct(pointer p, const T & val)
|
||||
{
|
||||
new(static_cast<void*>(p)) T(val);
|
||||
}
|
||||
|
||||
/// Create a new object instance using placement new.
|
||||
/// @param[in] p - pointer to the memory where the instance is constructed
|
||||
/// using placement new.
|
||||
void construct(pointer p)
|
||||
{
|
||||
new(static_cast<void*>(p)) T();
|
||||
}
|
||||
|
||||
/// Destroys an instance. Objects created with placement new must
|
||||
/// explicitly call the destructor.
|
||||
/// @param[in] p - pointer to object instance.
|
||||
void destroy(pointer p)
|
||||
{
|
||||
p->~T();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
inline bool operator==(const stl_allocator<T> &, const stl_allocator<U>) {return true;}
|
||||
|
||||
template <typename T, typename U>
|
||||
inline bool operator!=(const stl_allocator<T> &, const stl_allocator<U>) {return false;}
|
||||
|
||||
// For VC6/STLPort 4-5-3 see /stl/_alloc.h, line 464
|
||||
// "If custom allocators are being used without member template classes support :
|
||||
// user (on purpose) is forced to define rebind/get operations !!!"
|
||||
#ifdef _WIN32
|
||||
#define STD_ALLOC_CDECL __cdecl
|
||||
#else
|
||||
#define STD_ALLOC_CDECL
|
||||
#endif
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <class _Tp1, class _Tp2>
|
||||
inline stl_allocator<_Tp2> & STD_ALLOC_CDECL
|
||||
__stl_alloc_rebind(stl_allocator<_Tp1> & __a, const _Tp2*)
|
||||
{
|
||||
return (stl_allocator<_Tp2> &)(__a);
|
||||
}
|
||||
|
||||
template <class _Tp1, class _Tp2>
|
||||
inline stl_allocator<_Tp2> STD_ALLOC_CDECL
|
||||
__stl_alloc_create(const stl_allocator<_Tp1> &, const _Tp2*)
|
||||
{
|
||||
return stl_allocator<_Tp2>();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
// The following macros define the minimum required platform. The minimum required platform
|
||||
// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
|
||||
// your application. The macros work by enabling all features available on platform versions up to and
|
||||
// including the version specified.
|
||||
|
||||
// Modify the following defines if you have to target a platform prior to the ones specified below.
|
||||
// Refer to MSDN for the latest info on corresponding values for different platforms.
|
||||
#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
|
||||
#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
|
||||
#endif
|
||||
|
|
@ -0,0 +1,404 @@
|
|||
#include "xallocator.h"
|
||||
#include "Allocator.h"
|
||||
#include "Fault.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifndef CHAR_BIT
|
||||
#define CHAR_BIT 8
|
||||
#endif
|
||||
|
||||
static CRITICAL_SECTION _criticalSection;
|
||||
static BOOL _xallocInitialized = FALSE;
|
||||
|
||||
// Define STATIC_POOLS to switch from heap blocks mode to static pools mode
|
||||
//#define STATIC_POOLS
|
||||
#ifdef STATIC_POOLS
|
||||
// Update this section as necessary if you want to use static memory pools.
|
||||
// See also xalloc_init() and xalloc_destroy() for additional updates required.
|
||||
#define MAX_ALLOCATORS 12
|
||||
#define MAX_BLOCKS 32
|
||||
|
||||
// Create static storage for each static allocator instance
|
||||
CHAR* _allocator8 [sizeof(AllocatorPool<CHAR[8], MAX_BLOCKS>)];
|
||||
CHAR* _allocator16 [sizeof(AllocatorPool<CHAR[16], MAX_BLOCKS>)];
|
||||
CHAR* _allocator32 [sizeof(AllocatorPool<CHAR[32], MAX_BLOCKS>)];
|
||||
CHAR* _allocator64 [sizeof(AllocatorPool<CHAR[64], MAX_BLOCKS>)];
|
||||
CHAR* _allocator128 [sizeof(AllocatorPool<CHAR[128], MAX_BLOCKS>)];
|
||||
CHAR* _allocator256 [sizeof(AllocatorPool<CHAR[256], MAX_BLOCKS>)];
|
||||
CHAR* _allocator396 [sizeof(AllocatorPool<CHAR[396], MAX_BLOCKS>)];
|
||||
CHAR* _allocator512 [sizeof(AllocatorPool<CHAR[512], MAX_BLOCKS>)];
|
||||
CHAR* _allocator768 [sizeof(AllocatorPool<CHAR[768], MAX_BLOCKS>)];
|
||||
CHAR* _allocator1024 [sizeof(AllocatorPool<CHAR[1024], MAX_BLOCKS>)];
|
||||
CHAR* _allocator2048 [sizeof(AllocatorPool<CHAR[2048], MAX_BLOCKS>)];
|
||||
CHAR* _allocator4096 [sizeof(AllocatorPool<CHAR[4096], MAX_BLOCKS>)];
|
||||
|
||||
// Array of pointers to all allocator instances
|
||||
static Allocator* _allocators[MAX_ALLOCATORS];
|
||||
|
||||
#else
|
||||
#define MAX_ALLOCATORS 15
|
||||
static Allocator* _allocators[MAX_ALLOCATORS];
|
||||
#endif // STATIC_POOLS
|
||||
|
||||
// For C++ applications, must define AUTOMATIC_XALLOCATOR_INIT_DESTROY to
|
||||
// correctly ensure allocators are initialized before any static user C++
|
||||
// construtor/destructor executes which might call into the xallocator API.
|
||||
// This feature costs 1-byte of RAM per C++ translation unit. This feature
|
||||
// can be disabled only under the following circumstances:
|
||||
//
|
||||
// 1) The xallocator is only used within C files.
|
||||
// 2) STATIC_POOLS is undefined and the application never exits main (e.g.
|
||||
// an embedded system).
|
||||
//
|
||||
// In either of the two cases above, call xalloc_init() in main at startup,
|
||||
// and xalloc_destroy() before main exits. In all other situations
|
||||
// XallocInitDestroy must be used to call xalloc_init() and xalloc_destroy().
|
||||
#ifdef AUTOMATIC_XALLOCATOR_INIT_DESTROY
|
||||
INT XallocInitDestroy::refCount = 0;
|
||||
XallocInitDestroy::XallocInitDestroy()
|
||||
{
|
||||
// Track how many static instances of XallocInitDestroy are created
|
||||
if(refCount++ == 0)
|
||||
xalloc_init();
|
||||
}
|
||||
|
||||
XallocInitDestroy::~XallocInitDestroy()
|
||||
{
|
||||
// Last static instance to have destructor called?
|
||||
if(--refCount == 0)
|
||||
xalloc_destroy();
|
||||
}
|
||||
#endif // AUTOMATIC_XALLOCATOR_INIT_DESTROY
|
||||
|
||||
/// Returns the next higher powers of two. For instance, pass in 12 and
|
||||
/// the value returned would be 16.
|
||||
/// @param[in] k - numeric value to compute the next higher power of two.
|
||||
/// @return The next higher power of two based on the input k.
|
||||
template <class T>
|
||||
T nexthigher(T k)
|
||||
{
|
||||
k--;
|
||||
for(size_t i = 1; i < sizeof(T)*CHAR_BIT; i <<= 1)
|
||||
k |= (k >> i);
|
||||
return k + 1;
|
||||
}
|
||||
|
||||
/// Create the xallocator lock. Call only one time at startup.
|
||||
static void lock_init()
|
||||
{
|
||||
BOOL success = InitializeCriticalSectionAndSpinCount(&_criticalSection, 0x00000400);
|
||||
ASSERT_TRUE(success != 0);
|
||||
_xallocInitialized = TRUE;
|
||||
}
|
||||
|
||||
/// Destroy the xallocator lock.
|
||||
static void lock_destroy()
|
||||
{
|
||||
DeleteCriticalSection(&_criticalSection);
|
||||
_xallocInitialized = FALSE;
|
||||
}
|
||||
|
||||
/// Lock the shared resource.
|
||||
static inline void lock_get()
|
||||
{
|
||||
if(_xallocInitialized == FALSE)
|
||||
return;
|
||||
|
||||
EnterCriticalSection(&_criticalSection);
|
||||
}
|
||||
|
||||
/// Unlock the shared resource.
|
||||
static inline void lock_release()
|
||||
{
|
||||
if(_xallocInitialized == FALSE)
|
||||
return;
|
||||
|
||||
LeaveCriticalSection(&_criticalSection);
|
||||
}
|
||||
|
||||
/// Stored a pointer to the allocator instance within the block region.
|
||||
/// a pointer to the client's area within the block.
|
||||
/// @param[in] block - a pointer to the raw memory block.
|
||||
/// @param[in] size - the client requested size of the memory block.
|
||||
/// @return A pointer to the client's address within the raw memory block.
|
||||
static inline void* set_block_allocator(void* block, Allocator* allocator)
|
||||
{
|
||||
// Cast the raw block memory to a Allocator pointer
|
||||
Allocator** pAllocatorInBlock = static_cast<Allocator**>(block);
|
||||
|
||||
// Write the size into the memory block
|
||||
*pAllocatorInBlock = allocator;
|
||||
|
||||
// Advance the pointer past the Allocator* block size and return a pointer to
|
||||
// the client's memory region
|
||||
return ++pAllocatorInBlock;
|
||||
}
|
||||
|
||||
/// Gets the size of the memory block stored within the block.
|
||||
/// @param[in] block - a pointer to the client's memory block.
|
||||
/// @return The original allocator instance stored in the memory block.
|
||||
static inline Allocator* get_block_allocator(void* block)
|
||||
{
|
||||
// Cast the client memory to a Allocator pointer
|
||||
Allocator** pAllocatorInBlock = static_cast<Allocator**>(block);
|
||||
|
||||
// Back up one Allocator* position to get the stored allocator instance
|
||||
pAllocatorInBlock--;
|
||||
|
||||
// Return the allocator instance stored within the memory block
|
||||
return *pAllocatorInBlock;
|
||||
}
|
||||
|
||||
/// Returns the raw memory block pointer given a client memory pointer.
|
||||
/// @param[in] block - a pointer to the client memory block.
|
||||
/// @return A pointer to the original raw memory block address.
|
||||
static inline void* get_block_ptr(void* block)
|
||||
{
|
||||
// Cast the client memory to a Allocator* pointer
|
||||
Allocator** pAllocatorInBlock = static_cast<Allocator**>(block);
|
||||
|
||||
// Back up one Allocator* position and return the original raw memory block pointer
|
||||
return --pAllocatorInBlock;
|
||||
}
|
||||
|
||||
/// Returns an allocator instance matching the size provided
|
||||
/// @param[in] size - allocator block size
|
||||
/// @return Allocator instance handling requested block size or NULL
|
||||
/// if no allocator exists.
|
||||
static inline Allocator* find_allocator(size_t size)
|
||||
{
|
||||
for(INT i = 0; i < MAX_ALLOCATORS; i++)
|
||||
{
|
||||
if(_allocators[i] == 0)
|
||||
break;
|
||||
|
||||
if(_allocators[i]->GetBlockSize() == size)
|
||||
return _allocators[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/// Insert an allocator instance into the array
|
||||
/// @param[in] allocator - An allocator instance
|
||||
static inline void insert_allocator(Allocator* allocator)
|
||||
{
|
||||
for(INT i = 0; i < MAX_ALLOCATORS; i++)
|
||||
{
|
||||
if(_allocators[i] == 0)
|
||||
{
|
||||
_allocators[i] = allocator;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT();
|
||||
}
|
||||
|
||||
/// This function must be called exactly one time *before* any other xallocator
|
||||
/// API is called. XallocInitDestroy constructor calls this function automatically.
|
||||
extern "C" void xalloc_init()
|
||||
{
|
||||
lock_init();
|
||||
|
||||
#ifdef STATIC_POOLS
|
||||
// For STATIC_POOLS mode, the allocators must be initialized before any other
|
||||
// static user class constructor is run. Therefore, use placement new to initialize
|
||||
// each allocator into the previously reserved static memory locations.
|
||||
new(&_allocator8) AllocatorPool<CHAR[8], MAX_BLOCKS>();
|
||||
new(&_allocator16) AllocatorPool<CHAR[16], MAX_BLOCKS>();
|
||||
new(&_allocator32) AllocatorPool<CHAR[32], MAX_BLOCKS>();
|
||||
new(&_allocator64) AllocatorPool<CHAR[64], MAX_BLOCKS>();
|
||||
new(&_allocator128) AllocatorPool<CHAR[128], MAX_BLOCKS>();
|
||||
new(&_allocator256) AllocatorPool<CHAR[256], MAX_BLOCKS>();
|
||||
new(&_allocator396) AllocatorPool<CHAR[396], MAX_BLOCKS>();
|
||||
new(&_allocator512) AllocatorPool<CHAR[512], MAX_BLOCKS>();
|
||||
new(&_allocator768) AllocatorPool<CHAR[768], MAX_BLOCKS>();
|
||||
new(&_allocator1024) AllocatorPool<CHAR[1024], MAX_BLOCKS>();
|
||||
new(&_allocator2048) AllocatorPool<CHAR[2048], MAX_BLOCKS>();
|
||||
new(&_allocator4096) AllocatorPool<CHAR[4096], MAX_BLOCKS>();
|
||||
|
||||
// Populate allocator array with all instances
|
||||
_allocators[0] = (Allocator*)&_allocator8;
|
||||
_allocators[1] = (Allocator*)&_allocator16;
|
||||
_allocators[2] = (Allocator*)&_allocator32;
|
||||
_allocators[3] = (Allocator*)&_allocator64;
|
||||
_allocators[4] = (Allocator*)&_allocator128;
|
||||
_allocators[5] = (Allocator*)&_allocator256;
|
||||
_allocators[6] = (Allocator*)&_allocator396;
|
||||
_allocators[7] = (Allocator*)&_allocator512;
|
||||
_allocators[8] = (Allocator*)&_allocator768;
|
||||
_allocators[9] = (Allocator*)&_allocator1024;
|
||||
_allocators[10] = (Allocator*)&_allocator2048;
|
||||
_allocators[11] = (Allocator*)&_allocator4096;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Called one time when the application exits to cleanup any allocated memory.
|
||||
/// ~XallocInitDestroy destructor calls this function automatically.
|
||||
extern "C" void xalloc_destroy()
|
||||
{
|
||||
lock_get();
|
||||
|
||||
#ifdef STATIC_POOLS
|
||||
for(INT i = 0; i < MAX_ALLOCATORS; i++)
|
||||
{
|
||||
_allocators[i]->~Allocator();
|
||||
_allocators[i] = 0;
|
||||
}
|
||||
#else
|
||||
for(INT i = 0; i < MAX_ALLOCATORS; i++)
|
||||
{
|
||||
if(_allocators[i] == 0)
|
||||
break;
|
||||
delete _allocators[i];
|
||||
_allocators[i] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
lock_release();
|
||||
|
||||
lock_destroy();
|
||||
}
|
||||
|
||||
/// Get an Allocator instance based upon the client's requested block size.
|
||||
/// If a Allocator instance is not currently available to handle the size,
|
||||
/// then a new Allocator instance is create.
|
||||
/// @param[in] size - the client's requested block size.
|
||||
/// @return An Allocator instance that handles blocks of the requested
|
||||
/// size.
|
||||
extern "C" Allocator* xallocator_get_allocator(size_t size)
|
||||
{
|
||||
// Based on the size, find the next higher powers of two value.
|
||||
// Add sizeof(Allocator*) to the requested block size to hold the size
|
||||
// within the block memory region. Most blocks are powers of two,
|
||||
// however some common allocator block sizes can be explicitly defined
|
||||
// to minimize wasted storage. This offers application specific tuning.
|
||||
size_t blockSize = size + sizeof(Allocator*);
|
||||
if(blockSize > 256 && blockSize <= 396)
|
||||
blockSize = 396;
|
||||
else if(blockSize > 512 && blockSize <= 768)
|
||||
blockSize = 768;
|
||||
else
|
||||
blockSize = nexthigher<size_t>(blockSize);
|
||||
|
||||
Allocator* allocator = find_allocator(blockSize);
|
||||
|
||||
#ifdef STATIC_POOLS
|
||||
ASSERT_TRUE(allocator != NULL);
|
||||
#else
|
||||
// If there is not an allocator already created to handle this block size
|
||||
if(allocator == NULL)
|
||||
{
|
||||
// Create a new allocator to handle blocks of the size required
|
||||
allocator = new Allocator(blockSize, 0, 0, "xallocator");
|
||||
|
||||
// Insert allocator into array
|
||||
insert_allocator(allocator);
|
||||
}
|
||||
#endif
|
||||
|
||||
return allocator;
|
||||
}
|
||||
|
||||
/// Allocates a memory block of the requested size. The blocks are created from
|
||||
/// the fixed block allocators.
|
||||
/// @param[in] size - the client requested size of the block.
|
||||
/// @return A pointer to the client's memory block.
|
||||
extern "C" void* xmalloc(size_t size)
|
||||
{
|
||||
lock_get();
|
||||
|
||||
// Allocate a raw memory block
|
||||
Allocator* allocator = xallocator_get_allocator(size);
|
||||
void* blockMemoryPtr = allocator->Allocate(sizeof(Allocator*) + size);
|
||||
|
||||
lock_release();
|
||||
|
||||
// Set the block Allocator* within the raw memory block region
|
||||
void* clientsMemoryPtr = set_block_allocator(blockMemoryPtr, allocator);
|
||||
return clientsMemoryPtr;
|
||||
}
|
||||
|
||||
/// Frees a memory block previously allocated with xalloc. The blocks are returned
|
||||
/// to the fixed block allocator that originally created it.
|
||||
/// @param[in] ptr - a pointer to a block created with xalloc.
|
||||
extern "C" void xfree(void* ptr)
|
||||
{
|
||||
if(ptr == 0)
|
||||
return;
|
||||
|
||||
// Extract the original allocator instance from the caller's block pointer
|
||||
Allocator* allocator = get_block_allocator(ptr);
|
||||
|
||||
// Convert the client pointer into the original raw block pointer
|
||||
void* blockPtr = get_block_ptr(ptr);
|
||||
|
||||
lock_get();
|
||||
|
||||
// Deallocate the block
|
||||
allocator->Deallocate(blockPtr);
|
||||
|
||||
lock_release();
|
||||
}
|
||||
|
||||
/// Reallocates a memory block previously allocated with xalloc.
|
||||
/// @param[in] ptr - a pointer to a block created with xalloc.
|
||||
/// @param[in] size - the client requested block size to create.
|
||||
extern "C" void* xrealloc(void* oldMem, size_t size)
|
||||
{
|
||||
if(oldMem == 0)
|
||||
return xmalloc(size);
|
||||
|
||||
if(size == 0)
|
||||
{
|
||||
xfree(oldMem);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new memory block
|
||||
void* newMem = xmalloc(size);
|
||||
if(newMem != 0)
|
||||
{
|
||||
// Get the original allocator instance from the old memory block
|
||||
Allocator* oldAllocator = get_block_allocator(oldMem);
|
||||
size_t oldSize = oldAllocator->GetBlockSize() - sizeof(Allocator*);
|
||||
|
||||
// Copy the bytes from the old memory block into the new (as much as will fit)
|
||||
memcpy(newMem, oldMem, (oldSize < size) ? oldSize : size);
|
||||
|
||||
// Free the old memory block
|
||||
xfree(oldMem);
|
||||
|
||||
// Return the client pointer to the new memory block
|
||||
return newMem;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Output xallocator usage statistics
|
||||
extern "C" void xalloc_stats()
|
||||
{
|
||||
lock_get();
|
||||
|
||||
for(INT i = 0; i < MAX_ALLOCATORS; i++)
|
||||
{
|
||||
if(_allocators[i] == 0)
|
||||
break;
|
||||
|
||||
if(_allocators[i]->GetName() != NULL)
|
||||
cout << _allocators[i]->GetName();
|
||||
cout << " Block Size: " << _allocators[i]->GetBlockSize();
|
||||
cout << " Block Count: " << _allocators[i]->GetBlockCount();
|
||||
cout << " Blocks In Use: " << _allocators[i]->GetBlocksInUse();
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
lock_release();
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
#ifndef _XALLOCATOR_H
|
||||
#define _XALLOCATOR_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "DataTypes.h"
|
||||
|
||||
// See http://www.codeproject.com/Articles/1084801/Replace-malloc-free-with-a-Fast-Fixed-Block-Memory
|
||||
|
||||
#ifdef __cplusplus
|
||||
// Define AUTOMATIC_XALLOCATOR_INIT_DESTROY to automatically call xalloc_init() and
|
||||
// xalloc_destroy() when using xallocator in C++ projects. On embedded systems that
|
||||
// never exit, you can save 1-byte of RAM storage per translation unit by undefining
|
||||
// AUTOMATIC_XALLOCATOR_INIT_DESTROY and calling xalloc_init() manually before the OS
|
||||
// starts.
|
||||
#define AUTOMATIC_XALLOCATOR_INIT_DESTROY
|
||||
#ifdef AUTOMATIC_XALLOCATOR_INIT_DESTROY
|
||||
/// If a C++ translation unit, create a static instance of XallocInitDestroy. Any C++
|
||||
/// file including xallocator.h will have the xallocDestroy instance declared first
|
||||
/// within the translation unit and thus will be constructed first. Destruction
|
||||
/// will occur in the reverse order so xallocInitDestroy is called last. This way,
|
||||
/// any static user objects relying on xallocator will be destroyed first before
|
||||
/// xalloc_destroy() is called.
|
||||
class XallocInitDestroy
|
||||
{
|
||||
public:
|
||||
XallocInitDestroy();
|
||||
~XallocInitDestroy();
|
||||
private:
|
||||
static INT refCount;
|
||||
};
|
||||
static XallocInitDestroy xallocInitDestroy;
|
||||
#endif // AUTOMATIC_XALLOCATOR_INIT_DESTROY
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// This function must be called exactly one time before the operating system
|
||||
/// threading starts. If using xallocator exclusively in C files within your application
|
||||
/// code, you must call this function before the OS starts. If using C++, client code
|
||||
/// does not call xalloc_init. Let XallocInitDestroy() call xalloc_init automatically.
|
||||
/// Embedded systems that never exit can call xalloc_init() manually at startup
|
||||
/// and eliminate XallocInitDestroy usage. When the system is still single threaded at
|
||||
/// startup, the xallocator API does not need mutex protection.
|
||||
void xalloc_init();
|
||||
|
||||
/// This function must be called once when the application exits. Never call xalloc_destroy()
|
||||
/// manually except if using xallocator in a C-only application. If using xallocator
|
||||
/// exclusively in C files within your application code, you must call this function before
|
||||
/// the program exits. If using C++, ~XallocInitDestroy() must call xalloc_destroy automatically.
|
||||
/// Embedded systems that never exit need not call this function at all.
|
||||
void xalloc_destroy();
|
||||
|
||||
/// Allocate a block of memory
|
||||
/// @param[in] size - the size of the block to allocate.
|
||||
void* xmalloc(size_t size);
|
||||
|
||||
/// Frees a previously xalloc allocated block
|
||||
/// @param[in] ptr - a pointer to a previously allocated memory using xalloc.
|
||||
void xfree(void* ptr);
|
||||
|
||||
/// Reallocates an existing xalloc block to a new size
|
||||
/// @param[in] ptr - a pointer to a previously allocated memory using xalloc.
|
||||
/// @param[in] size - the size of the new block
|
||||
void* xrealloc(void* ptr, size_t size);
|
||||
|
||||
/// Output allocator statistics to the standard output
|
||||
void xalloc_stats();
|
||||
|
||||
// Macro to overload new/delete with xalloc/xfree
|
||||
#define XALLOCATOR \
|
||||
public: \
|
||||
void* operator new(size_t size) { \
|
||||
return xmalloc(size); \
|
||||
} \
|
||||
void operator delete(void* pObject) { \
|
||||
xfree(pObject); \
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef _XLIST_H
|
||||
#define _XLIST_H
|
||||
|
||||
#include "stl_allocator.h"
|
||||
#include <list>
|
||||
|
||||
template<class _Ty,
|
||||
class _Ax = stl_allocator<_Ty>>
|
||||
class xlist
|
||||
: public std::list<_Ty, _Ax>
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef _XMAP_H
|
||||
#define _XMAP_H
|
||||
|
||||
#include "stl_allocator.h"
|
||||
#include <map>
|
||||
|
||||
template<class _Kty,
|
||||
class _Ty,
|
||||
class _Pr = std::less<_Kty>,
|
||||
class _Alloc = stl_allocator<std::pair<const _Kty, _Ty>>>
|
||||
class xmap
|
||||
: public std::map<_Kty, _Ty, _Pr, _Alloc>
|
||||
{
|
||||
};
|
||||
|
||||
template<class _Kty,
|
||||
class _Ty,
|
||||
class _Pr = std::less<_Kty>,
|
||||
class _Alloc = stl_allocator<std::pair<const _Kty, _Ty>>>
|
||||
class xmultimap
|
||||
: public std::multimap<_Kty, _Ty, _Pr, _Alloc>
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _XQUEUE_H
|
||||
#define _XQUEUE_H
|
||||
|
||||
#include "stl_allocator.h"
|
||||
#include <queue>
|
||||
#include <list>
|
||||
|
||||
template<class _Tp,
|
||||
class _Sequence = std::list<_Tp, stl_allocator<_Tp>>>
|
||||
class xqueue
|
||||
: public std::queue<_Tp, _Sequence>
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef _XSET_H
|
||||
#define _XSET_H
|
||||
|
||||
#include "stl_allocator.h"
|
||||
#include <set>
|
||||
|
||||
template<class _Kty,
|
||||
class _Pr = std::less<_Kty>,
|
||||
class _Alloc = stl_allocator<_Kty>>
|
||||
class xset
|
||||
: public std::set<_Kty, _Pr, _Alloc>
|
||||
{
|
||||
};
|
||||
|
||||
/// @see xset
|
||||
template<class _Kty,
|
||||
class _Pr = std::less<_Kty>,
|
||||
class _Alloc = stl_allocator<_Kty>>
|
||||
class xmultiset
|
||||
: public std::multiset<_Kty, _Pr, _Alloc>
|
||||
{
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef _XSSTREAM_H
|
||||
#define _XSSTREAM_H
|
||||
|
||||
#include "stl_allocator.h"
|
||||
#include <sstream>
|
||||
|
||||
typedef std::basic_stringstream<char, std::char_traits<char>, stl_allocator<char>> xstringstream;
|
||||
typedef std::basic_ostringstream<char, std::char_traits<char>, stl_allocator<char>> xostringstream;
|
||||
|
||||
typedef std::basic_stringstream<wchar_t, std::char_traits<wchar_t>, stl_allocator<wchar_t>> xwstringstream;
|
||||
typedef std::basic_ostringstream<wchar_t, std::char_traits<wchar_t>, stl_allocator<wchar_t>> xwostringstream;
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef _XSTRING_H
|
||||
#define _XSTRING_H
|
||||
|
||||
#include "stl_allocator.h"
|
||||
#include <string>
|
||||
|
||||
typedef std::basic_string<char, std::char_traits<char>, stl_allocator<char>> xstring;
|
||||
typedef std::basic_string<wchar_t, std::char_traits<wchar_t>, stl_allocator<wchar_t>> xwstring;
|
||||
|
||||
#endif
|
||||
|
|
@ -97,6 +97,9 @@
|
|||
<ClCompile Include="reference.cpp" />
|
||||
<ClCompile Include="simplescript.cpp" />
|
||||
<ClCompile Include="stackinfo.cpp" />
|
||||
<ClCompile Include="stl_allocator\Allocator.cpp" />
|
||||
<ClCompile Include="stl_allocator\Fault.cpp" />
|
||||
<ClCompile Include="stl_allocator\xallocator.cpp" />
|
||||
<ClCompile Include="stringformat.cpp" />
|
||||
<ClCompile Include="stringutils.cpp" />
|
||||
<ClCompile Include="symbolinfo.cpp" />
|
||||
|
|
|
@ -458,6 +458,15 @@
|
|||
<ClCompile Include="symbolsourcebase.cpp">
|
||||
<Filter>Source Files\Symbols</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stl_allocator\Allocator.cpp">
|
||||
<Filter>Source Files\Symbols</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stl_allocator\Fault.cpp">
|
||||
<Filter>Source Files\Symbols</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stl_allocator\xallocator.cpp">
|
||||
<Filter>Source Files\Symbols</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="dbghelp\dbghelp.h">
|
||||
|
|
Loading…
Reference in New Issue