//================================================================================================== // S t a n d a r d Interface // M e m o r y // By Bruno Bachelet //================================================================================================== // Copyright (c) 1999-2016 // Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net // // This file is part of the B++ Library. This library is free software; you can redistribute it // and/or modify it under the terms of the GNU Library General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your option) any later // version. // // This library 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 Library General Public License for more details (http://www.gnu.org).
/*DESCRIPTION*/ /* This module provides facilities to manage the memory allocation and deallocation. */
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "standard/memory.hpp"
// Guardian //-------------------------------------------------------------------------------------- #ifndef guStandardMemory #define guStandardMemory
// Headers //--------------------------------------------------------------------------------------- #include <new> /*INCLUDE*/ #include <bpp/standard/class.hpp> /*INCLUDE*/ #include <bpp/standard/stream.hpp> /*INCLUDE*/
namespace bpp {
// Importation/Exportation //----------------------------------------------------------------------- #ifdef STANDARD_DLL #define dll_export DLL_EXPORT #else #define dll_export DLL_IMPORT #endif
// Namespaces //------------------------------------------------------------------------------------ #define public_area standardMemory #define private_area standardMemory_private
namespace public_area { /*NAMESPACE*/ using namespace standardClass; /*NAMESPACE*/ using namespace standardStream; }
namespace private_area { using namespace public_area; }
extern_module_name;
// Initialization //-------------------------------------------------------------------------------- #define iniStandardMemory has_initializer;
// Macrocommands //--------------------------------------------------------------------------------- #ifdef MEMORY_SPY_MODE /*MACROCOMMAND*/ /* The expression <CODE>prLine</CODE> is integrated into the source code if <CODE>MEMORY_SPY_MODE</CODE> is defined. */ #define memory_spy_mode(prLine) prLine
/*MACROCOMMAND*/ /* Allocates a new object. */ #define new_object(prCommand) \ ( standardMemory_private::registerPointer(new prCommand,#prCommand, \ __FILE__ ,__LINE__,false,nil) ) \
/*MACROCOMMAND*/ /* Allocates an array of objects. */ #define new_array(prCommand,prSize) \ ( standardMemory_private::registerPointer(new prCommand[prSize],#prCommand " x " #prSize, \ __FILE__,__LINE__,true,nil) ) \
/*MACROCOMMAND*/ /* Deallocates an object. */ #define delete_object(prPointer) \ ( delete standardMemory_private::unregisterPointer(prPointer,false,nil) ) \
/*MACROCOMMAND*/ /* Deallocates an array of objects. */ #define delete_array(prPointer) \ ( delete [] standardMemory_private::unregisterPointer(prPointer,true,nil) ) \
/*MACROCOMMAND*/ /* Allocates a new object using a pool. */ #define new_pool_object(prPool,prCommand) \ ( standardMemory_private::registerPointer(new((prPool).allocateObject()) prCommand, \ #prCommand,__FILE__ ,__LINE__,false,&(prPool)) ) \
/*MACROCOMMAND*/ /* Deallocates an object using a pool. */ #define delete_pool_object(prPool,prPointer) \ ( (prPool).deleteObject(standardMemory_private::unregisterPointer(prPointer,false,&(prPool))) ) \
#else #define memory_spy_mode(prLine)
#define new_object(prCommand) ( new prCommand ) #define new_array(prCommand,prSize) ( new prCommand[prSize] ) #define new_pool_object(prPool,prCommand) ( new((prPool).allocateObject()) prCommand ) #define delete_object(prPointer) ( delete (prPointer) ) #define delete_array(prPointer) ( delete [] (prPointer) ) #define delete_pool_object(prPool,prPointer) ( (prPool).deleteObject(prPointer) ) #endif
// Types & Classes //------------------------------------------------------------------------------- namespace public_area { //------------------------------------------------------------------------------------------Classes class clAbstractPool;
template <class prType> class clPool; //-----------------------------------------------------------------------------------Constant Types typedef const clAbstractPool ctAbstractPool; }
namespace private_area { memory_spy_mode ( class clPointerInformation;
typedef std_map(tyPointer,clPointerInformation *) clPointerRegister;
typedef const clPointerRegister ctPointerRegister; typedef const clPointerInformation ctPointerInformation; ) }
// Functions Interface //--------------------------------------------------------------------------- namespace public_area { memory_spy_mode ( function void outPointerRegister(clOutStream &); ) }
namespace private_area { memory_spy_mode ( template <class prType> prType * registerPointer(prType *,tcString,tcString,tyCardinal,tyBoolean,clAbstractPool *);
template <class prType> prType * unregisterPointer(prType *,tyBoolean,clAbstractPool *); )
function void throwError(void);
testing_mode ( function void test(void); ) }
// Errors //---------------------------------------------------------------------------------------- namespace public_area { /*ERROR*/ extern_error erMemory; /* Not enough memory. */
memory_spy_mode ( /*ERROR*/ extern_error erPointerAlreadyRegistered; /* The pointer is already registered. */
/*ERROR*/ extern_error erPointerNotRegistered; /* The pointer is not registered. That means the area you try to deallocate has not been allocated. */
/*ERROR*/ extern_error erWrongDestructionMode; /* Wrong way to destroy an array or a single object. */
/*ERROR*/ extern_error erWrongDestructionPool; /* Wrong pool used to destroy an object. */ ) }
// Constants & Variables //------------------------------------------------------------------------- memory_spy_mode ( /*VARIABLE*/ /* List of the pointers to the dynamically allocated objects and arrays of objects. */ extern_dynamic_constant(public,clPointerRegister,goPointerRegister,pointerRegister);
extern_static_constant(private,tcString,goPointerFileName,?); extern_static_constant(private,clMutex,goMutex,?); )
// A b s t r a c t P o o l Interface //------------------------------------------------------------ namespace public_area { /*CLASS clAbstractPool */ /* Represents a pool of objects. Instead of allocating memory for several objects separately, a pool allocates continuous blocks of memory (that can contain several objects) and manages then the assignment of this memory to each object. It is an abstract class. */ class clAbstractPool : public clBaseObject { //-----------------------------------------------------------------------------------------Private private_property constructor clAbstractPool(ctAbstractPool &); private_property clAbstractPool & operator = (ctAbstractPool &); //------------------------------------------------------------------------------------------Public public_property constructor clAbstractPool(void); public_property virtual destructor clAbstractPool(void);
/*AMETHOD clAbstractPool */ /* Allocates memory for an object (no constructor is called). Abstract method. */ public_property virtual tyPointer allocateObject(void) = 0;
/*AMETHOD clAbstractPool */ /* Destructs an object (its destructor is called). Abstract method. */ public_property virtual void deleteObject(tyPointer) = 0; }; }
// P o o l Interface //---------------------------------------------------------------------------- namespace public_area { /*CLASS clPool */ /* Represents a pool of <CODE>prType</CODE> objects. */ template <class prType> class clPool : public clAbstractPool { //-----------------------------------------------------------------------------------------Private private_property typedef struct _cpBlock_ { prType element; _cpBlock_ * next; } cpBlock;
private_property std_vector(cpBlock *) atBlockS; private_property tyCardinal atBlockSize; private_property tyCardinal atCounter; private_property cpBlock * atHead;
private_property constructor clPool(const clPool &); private_property clPool & operator = (const clPool &); //------------------------------------------------------------------------------------------Public public_property constructor clPool(tyCardinal=1024); public_property destructor clPool(void);
public_property tyPointer allocateObject(void); public_property void deleteObject(tyPointer); }; }
// P o i n t e r I n f o r m a t i o n Interface //------------------------------------------------ namespace private_area { memory_spy_mode ( class clPointerInformation { //----------------------------------------------------------------------------------------Private private_property typedef clAbstractPool * tyPool;
private_property constructor clPointerInformation(ctPointerInformation &); private_property clPointerInformation & operator = (ctPointerInformation &); //-----------------------------------------------------------------------------------------Public read_only_attribute(tcString,atCommand,command); read_only_attribute(tcString,atType,type); read_only_attribute(tcString,atFile,file); read_only_attribute(tyCardinal,atLine,line); read_only_attribute(tyBoolean,atArray,array); read_only_attribute(tyPool,atPool,pool);
public_property constructor clPointerInformation(tcString,tcString,tcString, tyCardinal,tyBoolean,tyPool);
public_property destructor clPointerInformation(void) {} }; ) }
// Functions Inline //------------------------------------------------------------------------------ namespace public_area {} namespace private_area {}
// A b s t r a c t P o o l Inline //--------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clAbstractPool */ /* Builds a pool. */ inline clAbstractPool::clAbstractPool(void) : clBaseObject() {} }
// P o o l Inline //------------------------------------------------------------------------------- namespace public_area { //--------------------------------------------------------------------------------------Constructor /*METHOD clPool */ /* Builds a new pool. The size, i.e. the number of <CODE>prType</CODE> objects, of a block can be provided (default is 1024). */ template <class prType> inline clPool<prType>::clPool(tyCardinal agBlockSize) : clAbstractPool(),atBlockS(),atBlockSize(agBlockSize),atCounter(0),atHead(nil) {} }
// P o i n t e r I n f o r m a t i o n Inline //--------------------------------------------------- #ifdef MEMORY_SPY_MODE namespace private_area { //--------------------------------------------------------------------------------------Constructor inline clPointerInformation::clPointerInformation(tcString agCommand,tcString agType, tcString agFile,tyCardinal agLine, tyBoolean agArray,tyPool agPool) : atCommand(agCommand),atType(agType),atFile(agFile),atLine(agLine),atArray(agArray), atPool(agPool) {} } #endif
// Functions Implementation //---------------------------------------------------------------------- namespace private_area { memory_spy_mode ( //---------------------------------------------------------------------------------RegisterPointer template <class prType> prType * registerPointer(prType * agPointer,tcString agCommand,tcString agFile, tyCardinal agLine,tyBoolean agArray,clAbstractPool * agPool) { method_name("registerPointer");
safe_yes ( private_area::goMutex.lock(); )
if (goPointerRegister->count(agPointer) == 1) { safe_yes ( private_area::goMutex.release(); ) send_error(erPointerAlreadyRegistered); }
private_area::goPointerRegister->insert(std_make_pair(agPointer, new clPointerInformation(agCommand,typeid(*agPointer).name(),agFile,agLine+1,agArray,agPool)));
safe_yes ( private_area::goMutex.release(); ) return (agPointer); } //-------------------------------------------------------------------------------UnregisterPointer template <class prType> prType * unregisterPointer(prType * agPointer,tyBoolean agArray,clAbstractPool * agPool) { method_name("unregisterPointer");
clPointerInformation * lcPointerInformation;
safe_yes ( private_area::goMutex.lock(); )
if (goPointerRegister->count(agPointer) == 0) { safe_yes ( private_area::goMutex.release(); ) send_error(erPointerNotRegistered); }
lcPointerInformation=(*(private_area::goPointerRegister->find(agPointer))).second;
if (agArray!=lcPointerInformation->array()) { safe_yes ( private_area::goMutex.release(); ) send_error(erWrongDestructionMode); }
if (agPool!=lcPointerInformation->pool()) { safe_yes ( private_area::goMutex.release(); ) send_error(erWrongDestructionPool); }
delete lcPointerInformation; private_area::goPointerRegister->erase(agPointer); safe_yes ( private_area::goMutex.release(); ) return (agPointer); } ) }
namespace private_area {}
// P o o l Implementation //----------------------------------------------------------------------- namespace public_area { //---------------------------------------------------------------------------------------Destructor /*METHOD clPool */ /* Destructs the pool. */ template <class prType> clPool<prType>::~clPool(void) { tyCardinal lcCounter = atBlockS.size();
while (lcCounter>0) { --lcCounter; delete_array(reinterpret_cast<tyByte *>(atBlockS[lcCounter])-1); } } //-----------------------------------------------------------------------------------AllocateObject /*METHOD clPool */ /* Allocates memory for an object (no constructor is called). */ template <class prType> tyPointer clPool<prType>::allocateObject(void) { tyByte * lcPointer;
if (atHead==nil) { if (atCounter==0) { lcPointer=new_array(tyByte,1+atBlockSize*sizeof(cpBlock))+1; atBlockS.push_back(reinterpret_cast<cpBlock *>(lcPointer)); atCounter=atBlockSize-1; atHead=nil; return (atBlockS.back()+atCounter); } else return (atBlockS.back()+(--atCounter)); }
lcPointer=reinterpret_cast<tyByte *>(atHead); atHead=atHead->next; return (lcPointer); } //-------------------------------------------------------------------------------------DeleteObject /*METHOD clPool */ /* Destructs an object (its destructor is called). */ template <class prType> void clPool<prType>::deleteObject(tyPointer agPointer) { cpBlock * lcBlock = reinterpret_cast<cpBlock *>(agPointer);
reinterpret_cast<prType *>(agPointer)->~prType(); lcBlock->next=atHead; atHead=lcBlock; } }
// End //------------------------------------------------------------------------------------------- } #undef dll_export #undef public_area #undef private_area #endif |
//================================================================================================== // S t a n d a r d Implementation // M e m o r y // By Bruno Bachelet //================================================================================================== // Copyright (c) 1999-2016 // Bruno Bachelet - bruno@nawouak.net - http://www.nawouak.net // // This file is part of the B++ Library. This library is free software; you can redistribute it // and/or modify it under the terms of the GNU Library General Public License as published by the // Free Software Foundation; either version 2 of the License, or (at your option) any later // version. // // This library 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 Library General Public License for more details (http://www.gnu.org).
// File Name //------------------------------------------------------------------------------------- #line __LINE__ "standard/memory.cpp"
// DLL Belonging //--------------------------------------------------------------------------------- #define STANDARD_DLL
// Headers //--------------------------------------------------------------------------------------- #include <bpp/file_name.hpp> /*NEED*/ #include <bpp/standard/memory.hpp> /*INTERFACE*/
namespace bpp {
// Namespaces //------------------------------------------------------------------------------------ #define public_area standardMemory #define private_area standardMemory_private #define dll_export DLL_EXPORT
namespace public_area {} namespace private_area {}
static_module_name("Standard/Memory");
// Initialization //-------------------------------------------------------------------------------- #undef iniStandardMemory static_constant(private_area::clInitializer,goInitializer);
// Errors //---------------------------------------------------------------------------------------- namespace public_area { static_error erMemory;
memory_spy_mode ( static_error erPointerAlreadyRegistered; static_error erPointerNotRegistered; static_error erWrongDestructionMode; static_error erWrongDestructionPool; ) }
// Constants & Variables //------------------------------------------------------------------------- memory_spy_mode ( dynamic_constant(clPointerRegister,goPointerRegister); static_constant(tcString,goPointerRegisterFileName); static_constant(clMutex,goMutex);
namespace public_area { function void (* outPointerContent)(clOutStream &,tyPointer); } )
// Static Members //-------------------------------------------------------------------------------- namespace public_area {} namespace private_area {}
// Functions Implementation //---------------------------------------------------------------------- namespace public_area { memory_spy_mode ( //------------------------------------------------------------------------------OutPointerRegister /*FUNCTION*/ /* Writes into a stream the current list of dynamically allocated objects and arrays of objects. */ function void outPointerRegister(clOutStream & agStream) { method_name("outPointerRegister");
using namespace private_area;
safe_yes ( private_area::goMutex.lock(); )
clPointerRegister::const_iterator lcCurrentRegistration = goPointerRegister->begin(); clPointerRegister::const_iterator lcLastRegistration = goPointerRegister->end();
while (lcCurrentRegistration!=lcLastRegistration) { agStream << end_line; agStream << " Address = " << (*lcCurrentRegistration).first << end_line; agStream << " Command = " << (*lcCurrentRegistration).second->command() << end_line; agStream << " Type = " << demangleType((*lcCurrentRegistration).second->type()) << end_line; agStream << " File = " << (*lcCurrentRegistration).second->file() << end_line; agStream << " Line = " << (*lcCurrentRegistration).second->line() << end_line;
if ((*lcCurrentRegistration).second->pool()!=nil) agStream << " Pool = " << (*lcCurrentRegistration).second->pool() << end_line;
if (outPointerContent!=nil) { agStream << " Content =" << end_line; outPointerContent(agStream,(*lcCurrentRegistration).first); }
lcCurrentRegistration++; }
safe_yes ( private_area::goMutex.release(); ) if (agStream.fail()) send_error(erStreamWriting); } ) }
namespace private_area { //---------------------------------------------------------------------------------------ThrowError function void throwError(void) { method_name("new");
send_error(erMemory); } }
// A b s t r a c t P o o l Implementation //------------------------------------------------------- namespace public_area { //---------------------------------------------------------------------------------------Destructor /*METHOD clAbstractPool */ /* Destructs the pool. */ clAbstractPool::~clAbstractPool(void) {} }
// I n i t i a l i z e r Implementation //--------------------------------------------------------- namespace private_area { //--------------------------------------------------------------------------------------------Start property void clInitializer::start(void) { if (atCounter++ == 0) { try { #include <bpp/modules.hpp> /*NEED*/ registerStop(this); environment::informInitialization(goModuleName);
erMemory.create("Not enough memory.");
memory_spy_mode ( erPointerAlreadyRegistered.create("The pointer is already registered."); erPointerNotRegistered.create("The pointer isn't registered."); erWrongDestructionMode.create("Wrong way to destroy an array or a single object."); erWrongDestructionPool.create("Wrong pool used to destroy an object."); )
std::set_new_handler((std::new_handler)throwError);
memory_spy_mode ( goPointerRegister = new clPointerRegister; goPointerRegisterFileName = POINTER_REGISTER_FILE;
outPointerContent = nil; ) }
initializer_catch; } } //---------------------------------------------------------------------------------------------Stop property void clInitializer::stop(void) { clOutFile lcFout;
try { environment::informTermination(goModuleName);
memory_spy_mode ( method_name("initializer::destructor");
if (not goPointerRegister->empty()) { using namespace environment;
nextLine(); out("[!] Warning: Some of the memory has been lost.",true,true); out("For more details, see the '",false,true); out(goPointerRegisterFileName); out("' file.",true); nextLine();
open(lcFout,goPointerRegisterFileName,ios::out|ios::trunc); lcFout << "===============================================================================" << end_line; lcFout << " P o i n t e r s R e g i s t e r Debugging Information" << end_line; lcFout << "===============================================================================" << end_line; lcFout << end_line; environment::outInformation(lcFout); lcFout << end_line; environment::outContext(lcFout); lcFout << end_line; lcFout << "[>] Lost Memory Blocks:" << end_line; outPointerRegister(lcFout); lcFout << end_line; lcFout << "===============================================================================" << end_line; close(lcFout); if (lcFout.fail()) send_error(erFileWriting); }
delete goPointerRegister; ) }
initializer_catch; } }
// End //------------------------------------------------------------------------------------------- } |
|