Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

memorypool.h

/* 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$
 *
 */

#ifndef COMMON_MEMORYPOOL_H
#define COMMON_MEMORYPOOL_H

#include "common/scummsys.h"
#include "common/array.h"


namespace Common {

/**
 * 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.
 */
00045 class MemoryPool {
protected:
      MemoryPool(const MemoryPool&);
      MemoryPool& operator=(const MemoryPool&);

00050       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.
       */
00099       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>
00108 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>
00126 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>
00135 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.
       */
00141       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

Generated by  Doxygen 1.6.0   Back to index