LUMIERA.clone/src/lib/simple-allocator.hpp
Ichthyostega 806db414dd Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
 * there is no entity "Lumiera.org" which holds any copyrights
 * Lumiera source code is provided under the GPL Version 2+

== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''

The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!

The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00

295 lines
9.2 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
SIMPLE-ALLOCATOR.hpp - frontend for plain explicit allocations
Copyright (C)
2011, Hermann Vosseler <Ichthyostega@web.de>
  **Lumiera** 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. See the file COPYING for further details.
*/
/** @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<TY>). 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 <boost/static_assert.hpp>
#include <memory>
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
* @waring whenever you define a specialisation,
* _you_ are responsible for proper alignment
* @see TICKET #1204
*/
template<typename TY>
class CustomAllocator
: public std::allocator<TY>
{ };
/**
* Policy: maintain explicit per type instance count
* @note this imposes additional locking
*/
struct UseInstantiationCounting
{
template<class XX>
size_t
allocationCount() const
{
return allocCnt_.get<XX>();
}
template<class XX>
void
incrementCount()
{
allocCnt_.inc<XX>();
}
template<class XX>
void
decrementCount()
{
allocCnt_.dec<XX>();
}
private:
lib::TypedCounter allocCnt_;
};
/**
* Policy: no additional instantiation accounting
*/
struct NoInstantiationCount
{
template<class XX> size_t allocationCount() const { return 0; }
template<class XX> void incrementCount() { /* NOP */ }
template<class XX> 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<typename TYPES
,class COUNTER = NoInstantiationCount ///< Policy: support instance accounting?
>
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<class XX>
XX *
allocateSlot ()
{
TRACE (memory, "allocate «%s»", util::typeStr<XX>().c_str());
XX * newStorage = CustomAllocator<XX>::allocate (1);
COUNTER::template incrementCount<XX>();
return newStorage;
}
template<class XX>
void
releaseSlot (XX* entry)
{
TRACE (memory, "release «%s»", util::typeStr<XX>().c_str());
CustomAllocator<XX>::deallocate (entry, 1);
COUNTER::template decrementCount<XX>();
}
template<class XX>
void
___assertSupportedType()
{
typedef typename TYPES::List PreconfiguredTypes;
typedef IsInList<XX, PreconfiguredTypes> IsSupportedType;
BOOST_STATIC_ASSERT (IsSupportedType::value);
}
public: /* ==== build objects with managed allocation ==== */
#define _EXCEPTION_SAFE_INVOKE(_CTOR_) \
\
___assertSupportedType<XX>(); \
XX* storage = allocateSlot<XX>(); \
try \
{ \
return (new(storage) _CTOR_ ); \
} \
catch(...) \
{ \
releaseSlot<XX>(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<class XX>
void
destroy (XX* entry)
{
if (!entry) return;
___assertSupportedType<XX>();
try
{
entry->~XX();
}
catch(...)
{
lumiera_err errorID = lumiera_error();
WARN (common_dbg, "dtor of «%s» failed: %s", util::typeStr(entry).c_str()
, errorID );
}
releaseSlot<XX> (entry);
}
/** diagnostics */
template<class XX>
size_t
numSlots() const
{
return COUNTER::template allocationCount<XX>();
}
};
} // namespace lib
#endif