2009-08-07 17:13:21 +02:00
/*
TYPED - ALLOCATION - MANAGER . hpp - abstract backbone to build custom memory managers
2010-12-17 23:28:49 +01:00
2009-08-07 17:13:21 +02:00
Copyright ( C ) Lumiera . org
2009 , Hermann Vosseler < Ichthyostega @ web . de >
2010-12-17 23:28:49 +01:00
2009-08-07 17:13:21 +02:00
This program is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License as
2010-12-17 23:28:49 +01:00
published by the Free Software Foundation ; either version 2 of
the License , or ( at your option ) any later version .
2009-08-07 17:13:21 +02:00
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 .
2010-12-17 23:28:49 +01:00
2009-08-07 17:13:21 +02:00
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 . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
2010-12-17 23:28:49 +01:00
2009-08-07 17:13:21 +02:00
*/
/** @file typed-allocation-manager.hpp
* * Abstract foundation for building custom allocation managers .
* * Currently ( as of 8 / 09 ) this is a draft , factored out of the command - registry .
* * The expectation is that we ' ll face several similar situations , and thus it
* * would be good to build up a common set of operations and behaviour .
* * @ todo WIP WIP .
* *
* * \ par Concept Summary
* * The idea is rather to tie the memory manager to a very specific usage situation ,
* * then to provide a general - purpose allocator to be used by any instance of a given
* * type . Typically , the goal is to handle memory management for an index or registry ,
* * holding implementation objects to be shielded from the client code . Moreover , we ' ll
2009-09-26 17:52:26 +02:00
* * have to deal with families of types rather then with individual types ; usually
2009-08-07 17:13:21 +02:00
* * there will be some common or combined handling for all family members .
* *
* * The intention is for this TypedAllocationManager template to be used both as a base
* * class providing the implementation skeleton for the actual custom allocation manager ,
* * and as an abstract interface , which can be forwarded to the \ em implementation classes
* * in case there is some cooperation required to get the allocation done ( for example ,
* * there might be some type erasure involved , leaving the ( otherwise opaque ) implementation
* * class as the only entity with a limited knowledge about the actual memory layout , and
* * thus the only way of creating a clone properly would be to forward down into this
2009-09-07 03:25:00 +02:00
* * implementation class ) .
2009-08-07 17:13:21 +02:00
* *
* * Thus , TypedAllocationManager provides the classical operations of an allocator
* * - allocate
* * - construct
* * - deallocate
* * But each of these operations is to be invoked in a \ em typed context . Besides ,
* * there is a facility allowing to create ref - counting handles and smart - pointers ,
* * which are internally tied to this memory manager through a deleter function .
* *
2009-08-29 02:16:28 +02:00
* * @ todo using a quick - n - dirty heap allocation implementation for now ( 8 / 09 ) ,
* * but should write a custom allocator based on cehteh ' s mpool !
* *
2009-08-07 17:13:21 +02:00
* * @ see CommandRegistry
* * @ see AllocationCluster ( another custom allocation scheme , which could be united )
* *
*/
2011-09-25 04:07:30 +02:00
# ifndef LIB_TYPED_ALLOCATION_MANAGER_H
# define LIB_TYPED_ALLOCATION_MANAGER_H
2009-08-07 17:13:21 +02:00
# include "lib/error.hpp"
2016-01-08 08:20:59 +01:00
# include "lib/meta/util.hpp"
2009-09-26 23:00:55 +02:00
# include "lib/typed-counter.hpp"
2009-08-07 17:13:21 +02:00
# include "include/logging.h"
2016-02-06 22:17:48 +01:00
# include <utility>
2014-04-03 22:42:48 +02:00
# include <memory>
2009-08-07 17:13:21 +02:00
2009-10-02 23:12:36 +02:00
namespace lib {
2009-08-07 17:13:21 +02:00
2014-04-03 22:42:48 +02:00
using std : : shared_ptr ;
2009-08-07 17:13:21 +02:00
/**
2009-08-29 02:16:28 +02:00
* Foundation for a custom allocation manager ,
* tracking the created objects by smart - ptrs .
* The public interface provides forwarding functions
* to invoke the ctor of the objects to be created , thereby
* placing them into the storage maintained by a low - level
* allocator or pooled storage manager . The created smart - ptr
* owns the new object and is wired internally to # releaseSlot .
* Subclasses may also directly allocate and de - allocate
* such a ( typed ) storage slot .
*
* @ todo currently ( as of 8 / 09 ) the low - level pooled allocator
* isn ' t implemented ; instead we do just heap allocations .
* see Ticket 231
2009-08-07 17:13:21 +02:00
*/
class TypedAllocationManager
{
typedef TypedAllocationManager _TheManager ;
public :
2009-09-26 17:52:26 +02:00
template < class XX >
size_t numSlots ( ) const ;
2009-08-07 17:13:21 +02:00
2009-08-09 03:47:32 +02:00
/* ======= managing the created objects ============= */
2009-08-07 17:13:21 +02:00
2009-08-09 03:47:32 +02:00
/** opaque link to the manager, to be used by handles and
* smart - ptrs to trigger preconfigured destruction . */
template < class XOX >
class Killer
{
_TheManager * manager_ ;
public :
void
operator ( ) ( XOX * victim )
{
REQUIRE ( manager_ ) ;
///////////////////////////////////////////////TODO: clean behaviour while in App shutdown (Ticket #196)
manager_ - > destroyElement ( victim ) ;
}
protected :
Killer ( _TheManager * m )
: manager_ ( m )
{ }
} ;
/** a token representing a newly opened slot
* capable for holding an object of type XOX .
* The receiver is responsible for
* - either calling releaseSlot
* - or building a smart - ptr / handle wired to
* the \ link # getDeleter deleter function \ endlink
*/
2009-08-07 17:13:21 +02:00
template < class XOX >
struct Slot
2009-08-09 03:47:32 +02:00
: private Killer < XOX >
2009-08-07 17:13:21 +02:00
{
2009-08-09 03:47:32 +02:00
/** pointer to the allocated storage
* with \ c sizeof ( XOX ) bytes */
void * const storage_ ;
2009-08-07 17:13:21 +02:00
2009-08-09 03:47:32 +02:00
/** build a refcounting smart-ptr,
* complete with back - link to the manager
* for de - allocation */
shared_ptr < XOX >
build ( XOX * toTrack )
{
return shared_ptr < XOX > ( toTrack , getDeleter ( ) ) ;
}
Killer < XOX > const &
getDeleter ( )
{
return * this ;
}
2009-08-07 17:13:21 +02:00
protected :
2009-08-09 03:47:32 +02:00
Slot ( _TheManager * don , void * mem )
: Killer < XOX > ( don )
, storage_ ( mem )
2009-08-07 17:13:21 +02:00
{ }
2009-08-09 03:47:32 +02:00
friend class TypedAllocationManager ;
2009-08-07 17:13:21 +02:00
} ;
2009-08-09 03:47:32 +02:00
2016-02-06 22:17:48 +01:00
/* ==== build objects with managed allocation ==== */
2009-08-09 03:47:32 +02:00
2016-02-06 22:17:48 +01:00
template < class XX , typename . . . ARGS >
shared_ptr < XX >
create ( ARGS & & . . . args )
2009-08-09 03:47:32 +02:00
{
2016-02-06 22:17:48 +01:00
Slot < XX > slot = allocateSlot < XX > ( ) ;
try {
return slot . build ( new ( slot . storage_ ) XX ( std : : forward < ARGS > ( args ) . . . ) ) ;
}
catch ( . . . )
{
releaseSlot < XX > ( slot . storage_ ) ;
throw ;
}
2009-08-09 03:47:32 +02:00
}
protected : /* ======= Managed Allocation Implementation ========== */
2009-08-07 17:13:21 +02:00
template < class XX >
Slot < XX >
allocateSlot ( )
{
2009-10-06 05:11:30 +02:00
////////////////////////////////////////////////TICKET #231 :redirect to the corresponding pool allocator
2016-01-08 08:20:59 +01:00
TRACE ( memory , " allocate «%s» " , util : : typeStr < XX > ( ) . c_str ( ) ) ;
2009-08-29 02:16:28 +02:00
void * space = new char [ sizeof ( XX ) ] ;
2009-09-26 17:52:26 +02:00
allocCnt_ . inc < XX > ( ) ;
2009-08-09 03:47:32 +02:00
return Slot < XX > ( this , space ) ;
2009-08-07 17:13:21 +02:00
}
template < class XX >
void
releaseSlot ( void * entry )
{
2009-10-06 05:11:30 +02:00
////////////////////////////////////////////////TICKET #231 :redirect to the corresponding pool allocator
2016-01-08 08:20:59 +01:00
TRACE ( memory , " release «%s» " , util : : typeStr < XX > ( ) . c_str ( ) ) ;
2009-08-29 02:16:28 +02:00
typedef char Storage [ sizeof ( XX ) ] ;
delete [ ] reinterpret_cast < Storage * > ( entry ) ;
2009-09-26 17:52:26 +02:00
allocCnt_ . dec < XX > ( ) ;
2009-08-07 17:13:21 +02:00
}
template < class XX >
void
destroyElement ( XX * entry )
{
if ( ! entry ) return ;
2009-09-07 03:25:00 +02:00
////////////////////////////////////////////////TODO: when actually implementing a custom allocation, please assert here that the entry is indeed managed by us
2009-08-07 17:13:21 +02:00
try
{
2009-08-09 03:47:32 +02:00
entry - > ~ XX ( ) ;
2009-08-07 17:13:21 +02:00
}
catch ( . . . )
{
2009-09-26 17:52:26 +02:00
lumiera_err errorID = lumiera_error ( ) ;
2016-01-08 08:20:59 +01:00
WARN ( command_dbg , " dtor of «%s» failed: %s " , util : : typeStr ( entry ) . c_str ( )
, errorID ) ;
2009-08-07 17:13:21 +02:00
}
releaseSlot < XX > ( entry ) ;
}
2009-09-07 03:25:00 +02:00
template < class >
friend class Killer ; ///< especially all Killers are entitled to desroyElement()
2009-09-26 17:52:26 +02:00
private :
2009-09-26 23:00:55 +02:00
lib : : TypedCounter allocCnt_ ;
2009-08-07 17:13:21 +02:00
} ;
2009-09-26 17:52:26 +02:00
template < class XX >
size_t
TypedAllocationManager : : numSlots ( ) const
{
return allocCnt_ . get < XX > ( ) ;
}
2009-10-02 23:12:36 +02:00
} // namespace lib
2009-08-07 17:13:21 +02:00
# endif