mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-12 03:56:20 +00:00
ec24687ce4
Adding @defgroup and @ingroup doxygen tags into all headers in the common folder that contain doxygen blocks. This improves the structure, readability, and findability of information in the resulting output. This commit targets purely structure and does not deal with the content of the currently existing doxygen documentation.
174 lines
4.9 KiB
C++
174 lines
4.9 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.
|
|
*
|
|
*/
|
|
|
|
#ifndef COMMON_MEMORYPOOL_H
|
|
#define COMMON_MEMORYPOOL_H
|
|
|
|
#include "common/scummsys.h"
|
|
#include "common/array.h"
|
|
|
|
|
|
namespace Common {
|
|
|
|
/**
|
|
* @defgroup common_memory_pool Memory pool
|
|
* @ingroup common_memory
|
|
*
|
|
* @brief API for managing the memory pool.
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* This class provides a pool of memory 'chunks' of identical size.
|
|
* The size of a chunk is determined when creating the memory pool.
|
|
*
|
|
* Using a memory pool may yield better performance and memory usage
|
|
* when allocating and deallocating many memory blocks of equal size.
|
|
* E.g. the Common::String class uses a memory pool for the refCount
|
|
* variables (each the size of an int) it allocates for each string
|
|
* instance.
|
|
*/
|
|
class MemoryPool {
|
|
protected:
|
|
MemoryPool(const MemoryPool&);
|
|
MemoryPool& operator=(const MemoryPool&);
|
|
|
|
struct Page {
|
|
void *start;
|
|
size_t numChunks;
|
|
};
|
|
|
|
const size_t _chunkSize;
|
|
Array<Page> _pages;
|
|
void *_next;
|
|
size_t _chunksPerPage;
|
|
|
|
void allocPage();
|
|
void addPageToPool(const Page &page);
|
|
bool isPointerInPage(void *ptr, const Page &page);
|
|
|
|
public:
|
|
/**
|
|
* Constructor for a memory pool with the given chunk size.
|
|
* @param chunkSize the chunk size of this memory pool
|
|
*/
|
|
explicit MemoryPool(size_t chunkSize);
|
|
~MemoryPool();
|
|
|
|
/**
|
|
* Allocate a new chunk from the memory pool.
|
|
*/
|
|
void *allocChunk();
|
|
/**
|
|
* Return a chunk to the memory pool. The given pointer must have
|
|
* been obtained from calling the allocChunk() method of the very
|
|
* same MemoryPool instance. Passing any other pointer (e.g. to
|
|
* a chunk from another MemoryPool, or a malloc'ed memory block)
|
|
* will lead to undefined behavior and may result in a crash (if
|
|
* you are lucky) or in silent data corruption.
|
|
*/
|
|
void freeChunk(void *ptr);
|
|
|
|
/**
|
|
* Perform garbage collection. The memory pool stores all the
|
|
* chunks it manages in memory 'pages' obtained via the classic
|
|
* memory allocation APIs (i.e. malloc/free). Ordinarily, once
|
|
* a page has been allocated, it won't be released again during
|
|
* the life time of the memory pool. The exception is when this
|
|
* method is called.
|
|
*/
|
|
void freeUnusedPages();
|
|
|
|
/**
|
|
* Return the chunk size used by this memory pool.
|
|
*/
|
|
size_t getChunkSize() const { return _chunkSize; }
|
|
};
|
|
|
|
/**
|
|
* This is a memory pool which already contains in itself some storage
|
|
* space for a fixed number of chunks. Thus if the memory pool is only
|
|
* lightly used, no malloc() calls have to be made at all.
|
|
*/
|
|
template<size_t CHUNK_SIZE, size_t NUM_INTERNAL_CHUNKS = 32>
|
|
class FixedSizeMemoryPool : public MemoryPool {
|
|
private:
|
|
enum {
|
|
REAL_CHUNK_SIZE = (CHUNK_SIZE + sizeof(void *) - 1) & (~(sizeof(void *) - 1))
|
|
};
|
|
|
|
byte _storage[NUM_INTERNAL_CHUNKS * REAL_CHUNK_SIZE];
|
|
public:
|
|
FixedSizeMemoryPool() : MemoryPool(CHUNK_SIZE) {
|
|
assert(REAL_CHUNK_SIZE == _chunkSize);
|
|
// Insert some static storage
|
|
Page internalPage = { _storage, NUM_INTERNAL_CHUNKS };
|
|
addPageToPool(internalPage);
|
|
}
|
|
};
|
|
|
|
// Ensure NUM_INTERNAL_CHUNKS == 0 results in a compile error
|
|
template<size_t CHUNK_SIZE>
|
|
class FixedSizeMemoryPool<CHUNK_SIZE,0> : public MemoryPool {
|
|
public:
|
|
FixedSizeMemoryPool() : MemoryPool(CHUNK_SIZE) {}
|
|
};
|
|
|
|
/**
|
|
* A memory pool for C++ objects.
|
|
*/
|
|
template<class T, size_t NUM_INTERNAL_CHUNKS = 32>
|
|
class ObjectPool : public FixedSizeMemoryPool<sizeof(T), NUM_INTERNAL_CHUNKS> {
|
|
public:
|
|
/**
|
|
* Return the memory chunk used as storage for the given object back
|
|
* to the pool, after calling its destructor.
|
|
*/
|
|
void deleteChunk(T *ptr) {
|
|
ptr->~T();
|
|
this->freeChunk(ptr);
|
|
}
|
|
};
|
|
|
|
/** @} */
|
|
|
|
} // End of namespace Common
|
|
|
|
/**
|
|
* A custom placement new operator, using an arbitrary MemoryPool.
|
|
*
|
|
* This *should* work with all C++ implementations, but may not.
|
|
*
|
|
* For details on using placement new for custom allocators, see e.g.
|
|
* <http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.14>
|
|
*/
|
|
inline void *operator new(size_t nbytes, Common::MemoryPool &pool) {
|
|
assert(nbytes <= pool.getChunkSize());
|
|
return pool.allocChunk();
|
|
}
|
|
|
|
inline void operator delete(void *p, Common::MemoryPool &pool) {
|
|
pool.freeChunk(p);
|
|
}
|
|
|
|
#endif
|