Created
June 14, 2017 03:07
-
-
Save zz-jason/4a8a8ee90745b4e526587f8644115a6b to your computer and use it in GitHub Desktop.
a memory manager copy from LevelDB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
class MemoryManager | |
{ | |
public: | |
MemoryManager(); | |
~MemoryManager(); | |
char* Allocate(size_t bytes); | |
char* AllocateAligned(size_t bytes); | |
size_t GetTotal() const { return mTotal; } | |
size_t GetUsed() const { return mUsed; } | |
private: | |
MemoryManager(const MemoryManager&); | |
MemoryManager& operator =(const MemoryManager&); | |
char* AllocateFallback(size_t bytes); | |
char* AllocateNewBlock(size_t bytes); | |
private: | |
struct BlockNode; | |
private: | |
const static size_t BLOCK_SIZE = 4096; | |
size_t mTotal; | |
size_t mUsed; | |
BlockNode* mBlockNode; | |
size_t mRemaining; | |
char* mAllocPtr; | |
}; | |
struct MemoryManager::BlockNode | |
{ | |
BlockNode() : mBlock(NULL), mNext(this), mPrev(this) {} | |
BlockNode(size_t bytes) : | |
mBlock(new char[bytes]), mNext(this), mPrev(this) {} | |
~BlockNode() { if (mBlock != NULL) delete[] mBlock; } | |
char* mBlock; | |
BlockNode* mNext; | |
BlockNode* mPrev; | |
}; | |
MemoryManager::MemoryManager() : | |
mTotal(0), mUsed(0), | |
mBlockNode(new BlockNode), mRemaining(0), mAllocPtr(NULL) | |
{ | |
} | |
MemoryManager::~MemoryManager() | |
{ | |
BlockNode* tail(mBlockNode->mPrev); | |
for (BlockNode* i(mBlockNode); i != tail; ) { | |
BlockNode* cur(i); | |
i = i->mNext; | |
delete cur; | |
} | |
delete tail; | |
} | |
char* MemoryManager::Allocate(size_t bytes) | |
{ | |
assert(bytes > 0); | |
if (bytes <= mRemaining) { | |
char* res(mAllocPtr); | |
mUsed += bytes; | |
mAllocPtr += bytes; | |
mRemaining -= bytes; | |
return res; | |
} else { | |
return AllocateFallback(bytes); | |
} | |
} | |
char* MemoryManager::AllocateAligned(size_t bytes) | |
{ | |
const size_t align(sizeof(void*)); | |
assert((align & (align - 1)) == 0); | |
size_t currMod(reinterpret_cast<uintptr_t>(mAllocPtr) & (align - 1)); | |
size_t slop(currMod == 0 ? 0 : align - currMod); | |
size_t needed(bytes + slop); | |
if (needed <= mRemaining) { | |
char* res = mAllocPtr + slop; | |
mUsed += needed; | |
mAllocPtr += needed; | |
mRemaining -= needed; | |
assert((reinterpret_cast<uintptr_t>(res) & (align - 1)) == 0); | |
return res; | |
} else { | |
char* res = AllocateFallback(bytes); | |
assert((reinterpret_cast<uintptr_t>(res) & (align - 1)) == 0); | |
return res; | |
} | |
} | |
char* MemoryManager::AllocateFallback(size_t bytes) | |
{ | |
if (bytes > BLOCK_SIZE / 4) { | |
return AllocateNewBlock(bytes); | |
} | |
mAllocPtr = AllocateNewBlock(BLOCK_SIZE); | |
mRemaining = BLOCK_SIZE; | |
char* res(mAllocPtr); | |
mUsed += bytes; | |
mAllocPtr += bytes; | |
mRemaining -= bytes; | |
return res; | |
} | |
char* MemoryManager::AllocateNewBlock(size_t bytes) | |
{ | |
mTotal += bytes; | |
BlockNode* block(new BlockNode(bytes)); | |
block->mPrev = mBlockNode->mPrev; | |
block->mNext = mBlockNode; | |
mBlockNode->mPrev->mNext = block; | |
mBlockNode->mPrev = block; | |
return block->mBlock; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment