scummvm/common/memorypool.cpp
Bertrand Augereau a84d1ea78b The hashmap uses the memorypool for allocating/deallocating its Nodes
(It is faster and it saves approximately 70kB the DS or other small devices will appreciate having)

svn-id: r31321
2008-03-30 06:02:34 +00:00

98 lines
2.3 KiB
C++

#include "common/memorypool.h"
#include <algorithm>
namespace Common
{
static const size_t CHUNK_PAGE_SIZE = 32;
void* MemoryPool::allocPage() {
void* result = ::malloc(CHUNK_PAGE_SIZE * _chunkSize);
_pages.push_back(result);
void* current = result;
for(size_t i=1; i<CHUNK_PAGE_SIZE; ++i)
{
void* next = ((char*)current + _chunkSize);
*(void**)current = next;
current = next;
}
*(void**)current = NULL;
return result;
}
MemoryPool::MemoryPool(size_t chunkSize) {
// You must at least fit the pointer in the node (technically unneeded considering the next rounding statement)
_chunkSize = std::max(chunkSize, sizeof(void*));
// There might be an alignment problem on some platforms when trying to load a void* on a non natural boundary
// so we round to the next sizeof(void*)
_chunkSize = (_chunkSize + sizeof(void*) - 1) & (~(sizeof(void*) - 1));
_next = NULL;
}
MemoryPool::~MemoryPool() {
for(size_t i=0; i<_pages.size(); ++i)
::free(_pages[i]);
}
void* MemoryPool::malloc() {
#if 1
if(!_next)
_next = allocPage();
void* result = _next;
_next = *(void**)result;
return result;
#else
return ::malloc(_chunkSize);
#endif
}
void MemoryPool::free(void* ptr) {
#if 1
*(void**)ptr = _next;
_next = ptr;
#else
::free(ptr);
#endif
}
// Technically not compliant C++ to compare unrelated pointers. In practice...
bool MemoryPool::isPointerInPage(void* ptr, void* page) {
return (ptr >= page) && (ptr < (char*)page + CHUNK_PAGE_SIZE * _chunkSize);
}
void MemoryPool::freeUnusedPages() {
//std::sort(_pages.begin(), _pages.end());
Array<int> numberOfFreeChunksPerPage;
numberOfFreeChunksPerPage.resize(_pages.size());
for(size_t i=0; i<numberOfFreeChunksPerPage.size(); ++i) {
numberOfFreeChunksPerPage[i] = 0;
}
void* iterator = _next;
while(iterator) {
// This should be a binary search
for(size_t i=0; i<_pages.size(); ++i) {
if(isPointerInPage(iterator, _pages[i])) {
++numberOfFreeChunksPerPage[i];
break;
}
}
iterator = *(void**)iterator;
}
size_t freedPagesCount = 0;
for(size_t i=0; i<_pages.size(); ++i) {
if(numberOfFreeChunksPerPage[i] == CHUNK_PAGE_SIZE) {
::free(_pages[i]);
_pages[i] = NULL; // TODO : Remove NULL values
++freedPagesCount;
}
}
printf("%d freed pages\n", freedPagesCount);
}
}