wip
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
|
||||
|
||||