#pragma once #include #include #include #include #include #include "../common/compat.hpp" #include "../threading/mutex.hpp" #ifndef SPRAWL_MEMORY_NO_FREE # define SPRAWL_MEMORY__RELEASE_EMPTY_BLOCKS 0 #endif namespace sprawl { 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::threading::Mutex ms_allocMutex; #endif }; template MemoryBit* DynamicPoolAllocator::ms_firstBit = nullptr; #if SPRAWL_MULTITHREADED template sprawl::threading::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 sprawl::threading::ScopedLock lock(ms_allocMutex); #endif MemoryBit* bit = ms_firstBit; if(bit) { ms_firstBit = bit->next; 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; return newBits[0].data; } template void DynamicPoolAllocator::free(void* addr) { void* allocType = reinterpret_cast(reinterpret_cast(addr)[-2]); if(allocType == 0) { #if SPRAWL_MULTITHREADED sprawl::threading::ScopedLock lock(ms_allocMutex); #endif MemoryBit* bit = reinterpret_cast*>(reinterpret_cast(addr)-2); bit->next = ms_firstBit; ms_firstBit = bit; } 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::threading::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::threading::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 sprawl::threading::ScopedLock lock(ms_allocMutex); #endif MemoryBit* bit = ms_firstBit; if(bit) { ms_firstBit = bit->next; return bit->data; } MemoryBit* newBit = &ms_blockPool[++ms_highestBitUsed]; newBit->allocType = 0; return newBit->data; } template void StaticPoolAllocator::free(void* addr) { void* allocType = reinterpret_cast(reinterpret_cast(addr)[-2]); if(allocType == 0) { #if SPRAWL_MULTITHREADED sprawl::threading::ScopedLock lock(ms_allocMutex); #endif MemoryBit* bit = reinterpret_cast*>(reinterpret_cast(addr)-2); bit->next = ms_firstBit; ms_firstBit = bit; } else { ::free(reinterpret_cast(addr)-2); } } } }