#pragma once #include #include #include #include #include #include "../common/compat.hpp" #include "../threading/threadlocal.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; #if SPRAWL_MULTITHREADED static sprawl::threading::ThreadLocal*> ms_firstBit; #else static MemoryBit* ms_firstBit; #endif }; #if SPRAWL_MULTITHREADED template sprawl::threading::ThreadLocal*> DynamicPoolAllocator::ms_firstBit; #else template MemoryBit* DynamicPoolAllocator::ms_firstBit = nullptr; #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 MemoryBit* bit = *ms_firstBit; #else MemoryBit* bit = ms_firstBit; #endif if(bit) { ms_firstBit = bit->next; return bit->data; } MemoryBit* newBits = (MemoryBit*)malloc(sizeof(MemoryBit) * adjustedBlockSize); for(size_t i = 1; i < adjustedBlockSize-1; ++i) { newBits[i].next = &newBits[i+1]; newBits[i].allocType = 0; } newBits[adjustedBlockSize-1].next = nullptr; newBits[adjustedBlockSize-1].allocType = 0; newBits[0].allocType = 0; ms_firstBit = &newBits[1]; return newBits[0].data; } template void DynamicPoolAllocator::free(void* addr) { void* allocType = reinterpret_cast(reinterpret_cast(addr)[-2]); if(allocType == 0) { MemoryBit* bit = reinterpret_cast*>(reinterpret_cast(addr)-2); #if SPRAWL_MULTITHREADED bit->next = *ms_firstBit; #else bit->next = ms_firstBit; #endif 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: #if SPRAWL_MULTITHREADED static sprawl::threading::ThreadLocal*> ms_firstBit; static sprawl::threading::ThreadLocal*> ms_blockPool; static sprawl::threading::ThreadLocal ms_highestBitUsed; #else static MemoryBit* ms_firstBit; static MemoryBit ms_blockPool[staticBufferSize]; static size_t ms_highestBitUsed; #endif }; #if SPRAWL_MULTITHREADED template sprawl::threading::ThreadLocal*> StaticPoolAllocator::ms_firstBit = nullptr; template sprawl::threading::ThreadLocal*> StaticPoolAllocator::ms_blockPool = (MemoryBit*)malloc(sizeof(MemoryBit) * staticBufferSize); template sprawl::threading::ThreadLocal StaticPoolAllocator::ms_highestBitUsed = 0; #else template MemoryBit* StaticPoolAllocator::ms_firstBit = nullptr; template MemoryBit StaticPoolAllocator::ms_blockPool[staticBufferSize]; template size_t StaticPoolAllocator::ms_highestBitUsed = 0; #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 MemoryBit* bit = *ms_firstBit; #else MemoryBit* bit = ms_firstBit; #endif if(bit) { ms_firstBit = bit->next; return bit->data; } #if SPRAWL_MULTITHREADED MemoryBit* newBit = &(*ms_blockPool)[++(*ms_highestBitUsed)]; #else MemoryBit* newBit = &ms_blockPool[++ms_highestBitUsed]; #endif newBit->allocType = 0; return newBit->data; } template void StaticPoolAllocator::free(void* addr) { void* allocType = reinterpret_cast(reinterpret_cast(addr)[-2]); if(allocType == 0) { MemoryBit* bit = reinterpret_cast*>(reinterpret_cast(addr)-2); #if SPRAWL_MULTITHREADED bit->next = *ms_firstBit; #else bit->next = ms_firstBit; #endif ms_firstBit = bit; } else { ::free(reinterpret_cast(addr)-2); } } } }