/* SIMPLE-ALLOCATOR.hpp - frontend for plain explicit allocations Copyright (C) Lumiera.org 2011, Hermann Vosseler 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file simple-allocator.hpp ** Frontend and marker interface for allocating small objects explicitly. ** Contrary to the TypedAllocationManager, the SimpleAllocator doesn't provide any ** ref-counting or tracking facilities, nor does he support bulk de-allocation. ** Each object needs to be allocated and released by explicit call. ** The advantage over using std::allocator directly is the shortcut for (placement) construction, ** and -- of course -- the ability to exchange the memory model at one central location. ** ** SimpleAllocator instances will be defined for a specific collection of types; for each of those ** types, there will be an embedded dedicated custom allocator (currently as of 9/2011, just ** implemented as std::allocator). Objects of these preconfigured types can be constructed ** and destroyed through this allocator instance. Each call needs to be done explicitly, with ** the precise, concrete type to be created or destroyed. This is especially important for ** the releasing of objects: there is \em no support for any kind of virtual destruction. ** ** @see engine::BufferMetadata ** @see TypedAllocationManager (another more elaborate custom allocation scheme) ** */ #ifndef LIB_SIMPLE_ALLOCATOR_H #define LIB_SIMPLE_ALLOCATOR_H #include "lib/error.hpp" #include "lib/meta/generator.hpp" #include "lib/meta/typelist-util.hpp" #include "lib/meta/util.hpp" #include "lib/typed-counter.hpp" #include "include/logging.h" #include #include namespace lib { using lib::meta::Types; using lib::meta::IsInList; using lib::meta::InstantiateForEach; /* === Policies for simple custom allocator === */ /** * Policy: use just plain heap allocations */ template class CustomAllocator : public std::allocator { }; /** * Policy: maintain explicit per type instance count * @note this imposes additional locking */ struct UseInstantiationCounting { template size_t allocationCount() const { return allocCnt_.get(); } template void incrementCount() { allocCnt_.inc(); } template void decrementCount() { allocCnt_.dec(); } private: lib::TypedCounter allocCnt_; }; /** * Policy: no additional instantiation accounting */ struct NoInstantiationCount { template size_t allocationCount() const { return 0; } template void incrementCount() { /* NOP */ } template void decrementCount() { /* NOP */ } }; /* === Allocator frontend === */ /** * Frontend for explicit allocations, using a custom allocator. * This template is to be instantiated for the collection of types * later to be allocated through this custom memory manager/model. * It provides convenience shortcuts for placement-construction * and releasing of target objects. * * @todo currently (as of 8/09) the low-level pooled allocator * isn't implemented; instead we do just heap allocations. * ////////////////////////////////////////////////////////////////////////////////////////////Ticket #835 */ template class SimpleAllocator : InstantiateForEach< typename TYPES::List // for each of those types... , CustomAllocator // ...mix in the custom allocator > , COUNTER // ...Instantiation accounting policy { /** forward plain memory allocation */ template XX * allocateSlot () { TRACE (memory, "allocate «%s»", util::typeStr().c_str()); XX * newStorage = CustomAllocator::allocate (1); COUNTER::template incrementCount(); return newStorage; } template void releaseSlot (XX* entry) { TRACE (memory, "release «%s»", util::typeStr().c_str()); CustomAllocator::deallocate (entry, 1); COUNTER::template decrementCount(); } template void ___assertSupportedType() { typedef typename TYPES::List PreconfiguredTypes; typedef IsInList IsSupportedType; BOOST_STATIC_ASSERT (IsSupportedType::value); } public: /* ==== build objects with managed allocation ==== */ #define _EXCEPTION_SAFE_INVOKE(_CTOR_) \ \ ___assertSupportedType(); \ XX* storage = allocateSlot(); \ try \ { \ return (new(storage) _CTOR_ ); \ } \ catch(...) \ { \ releaseSlot(storage); \ throw; \ } template< class XX> XX* //_____________________ create () ///< invoke default ctor { _EXCEPTION_SAFE_INVOKE ( XX() ) } template< class XX, typename P1> XX* //___________________ create (P1& p1) ///< invoke 1-arg ctor { _EXCEPTION_SAFE_INVOKE ( XX (p1) ) } template< class XX , typename P1 , typename P2 > XX* //___________________ create (P1& p1, P2& p2) ///< invoke 2-arg ctor { _EXCEPTION_SAFE_INVOKE ( XX (p1,p2) ) } template< class XX , typename P1 , typename P2 , typename P3 > XX* //___________________ create (P1& p1, P2& p2, P3& p3) ///< invoke 3-arg ctor { _EXCEPTION_SAFE_INVOKE ( XX (p1,p2,p3) ) } template< class XX , typename P1 , typename P2 , typename P3 , typename P4 > XX* //___________________ create (P1& p1, P2& p2, P3& p3, P4& p4) ///< invoke 4-arg ctor { _EXCEPTION_SAFE_INVOKE ( XX (p1,p2,p3,p4) ) } template< class XX , typename P1 , typename P2 , typename P3 , typename P4 , typename P5 > XX* //___________________ create (P1& p1, P2& p2, P3& p3, P4& p4, P5& p5) ///< invoke 5-arg ctor { _EXCEPTION_SAFE_INVOKE ( XX (p1,p2,p3,p4,p5) ) } #undef _EXCEPTION_SAFE_INVOKE template void destroy (XX* entry) { if (!entry) return; ___assertSupportedType(); try { entry->~XX(); } catch(...) { lumiera_err errorID = lumiera_error(); WARN (common_dbg, "dtor of «%s» failed: %s", util::typeStr(entry).c_str() , errorID ); } releaseSlot (entry); } /** diagnostics */ template size_t numSlots() const { return COUNTER::template allocationCount(); } }; } // namespace lib #endif