scummvm/common/memorypool.cpp
Max Horn 595be54083 cleanup
svn-id: r31391
2008-04-04 21:00:58 +00:00

122 lines
3.2 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
#include "common/memorypool.h"
#include "common/util.h"
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 = 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<size_t> 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);
}
} // End of namespace Common