#pragma once #include #include #include #include #include #include "../common/compat.hpp" #ifdef _WIN32 # include #else # include #endif #ifndef SPRAWL_MEMORY_NO_FREE # define SPRAWL_MEMORY__RELEASE_EMPTY_BLOCKS 0 #endif namespace sprawl { //TODO: Put this in separate threading library class Mutex { public: inline void lock() { #ifdef _WIN32 EnterCriticalSection(&m_mutexImpl); #else pthread_mutex_lock(&m_mutexImpl); #endif } inline void unlock() { #ifdef _WIN32 LeaveCriticalSection(&m_mutexImpl); #else pthread_mutex_unlock(&m_mutexImpl); #endif } Mutex() #ifdef _WIN32 : m_mutexImpl() { InitializeCriticalSection(&m_mutexImpl); #else : m_mutexImpl(PTHREAD_MUTEX_INITIALIZER) { #endif } ~Mutex() #ifdef _WIN32 { DeleteCriticalSection(&m_mutexImpl); #else { pthread_mutex_destroy(&m_mutexImpl); #endif } private: #ifdef _WIN32 CRITICAL_SECTION m_mutexImpl; #else pthread_mutex_t m_mutexImpl; #endif }; namespace memory { template struct MemoryBit { void* allocType; MemoryBit* next; unsigned char data[sizeOfType]; }; template class DynamicPoolAllocator { public: static void* alloc(); static void* alloc(size_t count); static void free(void* addr); template struct rebind { typedef DynamicPoolAllocator otherAllocator; }; private: static SPRAWL_CONSTEXPR size_t adjustedBlockSize = (blockSize+7) & ~7; static MemoryBit* ms_firstBit; #if SPRAWL_MULTITHREADED static sprawl::Mutex ms_allocMutex; #endif }; template MemoryBit* DynamicPoolAllocator::ms_firstBit = nullptr; #if SPRAWL_MULTITHREADED template sprawl::Mutex DynamicPoolAllocator::ms_allocMutex; #endif template void* DynamicPoolAllocator::alloc(size_t count) { void* ret = malloc(count*sizeOfType + (sizeof(intptr_t) * 2)); memset(ret, 1, sizeof(intptr_t) * 2); return reinterpret_cast(ret) + (sizeof(intptr_t) * 2); } template void* DynamicPoolAllocator::alloc() { #if SPRAWL_MULTITHREADED ms_allocMutex.lock(); #endif MemoryBit* bit = ms_firstBit; if(bit) { ms_firstBit = bit->next; #if SPRAWL_MULTITHREADED ms_allocMutex.unlock(); #endif return bit->data; } MemoryBit* newBits = (MemoryBit*)malloc(sizeof(MemoryBit) * adjustedBlockSize); for(size_t i = 1; i < adjustedBlockSize; ++i) { newBits[i].next = ms_firstBit; newBits[i].allocType = 0; ms_firstBit = &newBits[i]; } newBits[0].allocType = 0; #if SPRAWL_MULTITHREADED ms_allocMutex.unlock(); #endif return newBits[0].data; } template void DynamicPoolAllocator::free(void* addr) { void* allocType = reinterpret_cast(reinterpret_cast(addr)[-2]); if(allocType == 0) { #if SPRAWL_MULTITHREADED ms_allocMutex.lock(); #endif MemoryBit* bit = reinterpret_cast*>(reinterpret_cast(addr)-2); bit->next = ms_firstBit; ms_firstBit = bit; #if SPRAWL_MULTITHREADED ms_allocMutex.unlock(); #endif } else { ::free(reinterpret_cast(addr)-2); } } template class StaticPoolAllocator { public: static void* alloc(); static void* alloc(size_t count); static void free(void* addr); template struct rebind { typedef StaticPoolAllocator otherAllocator; }; private: static MemoryBit* ms_firstBit; static MemoryBit ms_blockPool[staticBufferSize]; static size_t ms_highestBitUsed; #if SPRAWL_MULTITHREADED static sprawl::Mutex ms_allocMutex; #endif }; template MemoryBit* StaticPoolAllocator::ms_firstBit = nullptr; template MemoryBit StaticPoolAllocator::ms_blockPool[staticBufferSize]; template size_t StaticPoolAllocator::ms_highestBitUsed = 0; #if SPRAWL_MULTITHREADED template sprawl::Mutex StaticPoolAllocator::ms_allocMutex; #endif template void* StaticPoolAllocator::alloc(size_t count) { void* ret = malloc(count*sizeOfType + (sizeof(intptr_t) * 2)); memset(ret, 1, sizeof(intptr_t) * 2); return reinterpret_cast(ret) + (sizeof(intptr_t) * 2); } template void* StaticPoolAllocator::alloc() { #if SPRAWL_MULTITHREADED ms_allocMutex.lock(); #endif MemoryBit* bit = ms_firstBit; if(bit) { ms_firstBit = bit->next; #if SPRAWL_MULTITHREADED ms_allocMutex.unlock(); #endif return bit->data; } MemoryBit* newBit = &ms_blockPool[++ms_highestBitUsed]; newBit->allocType = 0; #if SPRAWL_MULTITHREADED ms_allocMutex.unlock(); #endif return newBit->data; } template void StaticPoolAllocator::free(void* addr) { void* allocType = reinterpret_cast(reinterpret_cast(addr)[-2]); if(allocType == 0) { #if SPRAWL_MULTITHREADED ms_allocMutex.lock(); #endif MemoryBit* bit = reinterpret_cast*>(reinterpret_cast(addr)-2); bit->next = ms_firstBit; ms_firstBit = bit; #if SPRAWL_MULTITHREADED ms_allocMutex.unlock(); #endif } else { ::free(reinterpret_cast(addr)-2); } } } }