/*
* $Revision: 2523 $
*
* last checkin:
* $Author: gutwenger $
* $Date: 2012-07-02 20:59:27 +0200 (Mon, 02 Jul 2012) $
***************************************************************/
/** \file
* \brief Declaration of memory manager for allocating small
* pieces of memory
*
* \author Carsten Gutwenger
*
* \par License:
* This file is part of the Open Graph Drawing Framework (OGDF).
*
* \par
* Copyright (C)
* See README.txt in the root directory of the OGDF installation for details.
*
* \par
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* Version 2 or 3 as published by the Free Software Foundation;
* see the file LICENSE.txt included in the packaging of this file
* for details.
*
* \par
* 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.
*
* \par
* 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.
*
* \see http://www.gnu.org/copyleft/gpl.html
***************************************************************/
#ifdef _MSC_VER
#pragma once
#endif
#ifndef OGDF_POOL_MEMORY_ALLOCATOR_H
#define OGDF_POOL_MEMORY_ALLOCATOR_H
#ifndef OGDF_MEMORY_POOL_NTS
#include "../../basic/CriticalSection.h"
#else
#include "../../basic/System.h"
#endif
namespace ogdf {
//! The class \a PoolAllocator represents ogdf's pool memory allocator.
/**
*
Usage:
*
* Adding the macro \c #OGDF_NEW_DELETE in a class declaration overloads
* new and delete operators of that class such that they use this
* memory allocator. This is useful if the size of a class is less than
* \c PoolAllocator::eTableSize bytes.
*
* Another benefit from the OGDF memory-manager is that it throws an
* InsufficientMemoryException if no more memory is available. Hence
* it is legal to omit checking if new returned 0 as long as stack-
* unwinding frees all memory allocated so far.
* It is also possible to make the usual \c new operator behave the same
* way (throwing an InsufficientMemoryException) by defining the
* macro \c #OGDF_MALLOC_NEW_DELETE in a class declaration.
*/
class PoolMemoryAllocator
{
struct MemElem {
MemElem *m_next;
};
struct MemElemEx {
MemElemEx *m_next;
MemElemEx *m_down;
};
typedef MemElem *MemElemPtr;
typedef MemElemEx *MemElemExPtr;
struct PoolVector;
struct PoolElement;
struct BlockChain;
typedef BlockChain *BlockChainPtr;
public:
enum {
eMinBytes = sizeof(MemElemPtr),
eTableSize = 256,
eBlockSize = 8192,
ePoolVectorLength = 15
};
PoolMemoryAllocator() { }
~PoolMemoryAllocator() { }
//! Initializes the memory manager.
static OGDF_EXPORT void init();
static OGDF_EXPORT void initThread();
//! Frees all memory blocks allocated by the memory manager.
static OGDF_EXPORT void cleanup();
static OGDF_EXPORT bool checkSize(size_t nBytes);
//! Allocates memory of size \a nBytes.
static OGDF_EXPORT void *allocate(size_t nBytes);
//! Deallocates memory at address \a p which is of size \a nBytes.
static OGDF_EXPORT void deallocate(size_t nBytes, void *p);
//! Deallocate a complete list starting at \a pHead and ending at \a pTail.
/**
* The elements are assumed to be chained using the first word of each element and
* elements are of size \a nBytes. This is much more efficient the deallocating
* each element separately, since the whole chain can be concatenated with the
* free list, requiring only constant effort.
*/
static OGDF_EXPORT void deallocateList(size_t nBytes, void *pHead, void *pTail);
static OGDF_EXPORT void flushPool();
static OGDF_EXPORT void flushPool(__uint16 nBytes);
//! Returns the total amount of memory (in bytes) allocated from the system.
static OGDF_EXPORT size_t memoryAllocatedInBlocks();
//! Returns the total amount of memory (in bytes) available in the global free lists.
static OGDF_EXPORT size_t memoryInGlobalFreeList();
//! Returns the total amount of memory (in bytes) available in the thread's free lists.
static OGDF_EXPORT size_t memoryInThreadFreeList();
private:
static int slicesPerBlock(__uint16 nBytes) {
int nWords;
return slicesPerBlock(nBytes,nWords);
}
static int slicesPerBlock(__uint16 nBytes, int &nWords) {
nWords = (nBytes+sizeof(MemElemPtr)-1)/sizeof(MemElemPtr);
return (eBlockSize-sizeof(MemElemPtr))/(nWords*sizeof(MemElemPtr));
}
static void incVectorSlot(PoolElement &pe);
static void flushPoolSmall(__uint16 nBytes);
static MemElemExPtr collectGroups(
__uint16 nBytes,
MemElemPtr &pRestHead,
MemElemPtr &pRestTail,
int &nRest);
static void *fillPool(MemElemPtr &pFreeBytes, __uint16 nBytes);
static MemElemPtr allocateBlock(__uint16 nBytes);
static PoolElement s_pool[eTableSize];
static MemElemPtr s_freeVectors;
static BlockChainPtr s_blocks;
#ifdef OGDF_MEMORY_POOL_NTS
static MemElemPtr s_tp[eTableSize];
#elif defined(OGDF_NO_COMPILER_TLS)
static CriticalSection *s_criticalSection;
static pthread_key_t s_tpKey;
#else
static CriticalSection *s_criticalSection;
static OGDF_DECL_THREAD MemElemPtr s_tp[eTableSize];
#endif
};
}
#endif