define a front-end for explicit allocations
...currently just defined by forwarding to std::allocator
This commit is contained in:
parent
bc756e42d9
commit
db2b02f0c5
10 changed files with 440 additions and 12 deletions
|
|
@ -24,9 +24,9 @@
|
|||
/** @file result.hpp
|
||||
** Intermediary value object to represent the result of an operation.
|
||||
** This operation might have produced a value result or failed with an exception.
|
||||
** Typically, the Result token used \em inline -- immediately either invoking one
|
||||
** of the member function or employing the built-in result type conversion. It
|
||||
** will be copyable iff the result value is copyable. There is an implicit
|
||||
** Typically, the Result token is used \em inline -- immediately either invoking
|
||||
** one of the member function or employing the built-in result type conversion.
|
||||
** It will be copyable iff the result value is copyable. There is an implicit
|
||||
** valid or failure state, which can be tested. Any attempt to get the value
|
||||
** of an invalid result token will cause in an exception to be thrown.
|
||||
**
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ namespace lib {
|
|||
pointer address(reference r) const { return par_.address(r); }
|
||||
const_pointer address(const_reference cr) const { return par_.address(cr); }
|
||||
pointer allocate(size_type n, const void *p=0){ return par_.allocate(n,p); }
|
||||
void deallocate(pointer p, size_type n) { return par_.deallocate(p,n); }
|
||||
void destroy(pointer p) { return par_.destroy(p); }
|
||||
void deallocate(pointer p, size_type n) { par_.deallocate(p,n); }
|
||||
void destroy(pointer p) { par_.destroy(p); }
|
||||
|
||||
|
||||
void
|
||||
|
|
|
|||
262
src/lib/simple-allocator.hpp
Normal file
262
src/lib/simple-allocator.hpp
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
SIMPLE-ALLOCATOR.hpp - frontend for plain explicit allocations
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2011, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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<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 "pre.hpp"
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/meta/generator.hpp"
|
||||
#include "lib/format.hpp"
|
||||
//#include "lib/typed-counter.hpp"
|
||||
#include "include/logging.h"
|
||||
|
||||
|
||||
//#include <tr1/memory>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <memory>
|
||||
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
||||
// using std::tr1::shared_ptr;
|
||||
using lumiera::typelist::InstantiateForEach;
|
||||
using lumiera::typelist::Types;
|
||||
|
||||
namespace {
|
||||
using lumiera::typelist::Node;
|
||||
using lumiera::typelist::NullType;
|
||||
|
||||
template<typename TYPES, typename TY>
|
||||
struct IsInList
|
||||
{
|
||||
enum{ value = false };
|
||||
};
|
||||
|
||||
template<typename TY, typename TYPES>
|
||||
struct IsInList<Node<TY,TYPES>, TY>
|
||||
{
|
||||
enum{ value = true };
|
||||
};
|
||||
|
||||
template<typename XX, typename TYPES, typename TY>
|
||||
struct IsInList<Node<XX,TYPES>, TY>
|
||||
{
|
||||
enum{ value = IsInList<TYPES,TY>::value };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename TY>
|
||||
class CustomAllocator
|
||||
: public std::allocator<TY>
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* see Ticket #835
|
||||
*/
|
||||
template<typename TYPES>
|
||||
class SimpleAllocator
|
||||
: InstantiateForEach< typename TYPES::List // for each of those types...
|
||||
, CustomAllocator // ...mix in the custom allocator
|
||||
>
|
||||
{
|
||||
|
||||
/** forward plain memory allocation */
|
||||
template<class XX>
|
||||
XX *
|
||||
allocateSlot ()
|
||||
{
|
||||
TRACE (memory, "allocate %s", util::tyStr<XX>().c_str());
|
||||
return CustomAllocator<XX>::allocate (1);
|
||||
}
|
||||
|
||||
template<class XX>
|
||||
void
|
||||
releaseSlot (XX* entry)
|
||||
{
|
||||
TRACE (memory, "release %s", util::tyStr<XX>().c_str());
|
||||
CustomAllocator<XX>::deallocate (entry, 1);
|
||||
}
|
||||
|
||||
|
||||
template<class XX>
|
||||
void
|
||||
___assertSupportedType()
|
||||
{
|
||||
typedef typename TYPES::List PreconfiguredTypes;
|
||||
typedef IsInList<PreconfiguredTypes,XX> IsPreconfiguredType;
|
||||
|
||||
BOOST_STATIC_ASSERT (IsPreconfiguredType::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::tyStr(entry).c_str()
|
||||
, errorID );
|
||||
}
|
||||
releaseSlot<XX> (entry);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace lib
|
||||
#endif
|
||||
|
|
@ -63,8 +63,8 @@
|
|||
|
||||
|
||||
|
||||
#ifndef CONTROL_TYPED_ALLOCATION_MANAGER_H
|
||||
#define CONTROL_TYPED_ALLOCATION_MANAGER_H
|
||||
#ifndef LIB_TYPED_ALLOCATION_MANAGER_H
|
||||
#define LIB_TYPED_ALLOCATION_MANAGER_H
|
||||
|
||||
//#include "pre.hpp"
|
||||
#include "lib/error.hpp"
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@
|
|||
|
||||
namespace control {
|
||||
|
||||
using lib::TypedAllocationManager;
|
||||
using lib::InPlaceBuffer;
|
||||
using std::string;
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,6 @@
|
|||
|
||||
namespace control {
|
||||
|
||||
using lib::TypedAllocationManager;
|
||||
using std::tr1::function;
|
||||
using std::tr1::shared_ptr;
|
||||
|
||||
|
|
|
|||
|
|
@ -104,8 +104,11 @@ namespace engine {
|
|||
class Metadata
|
||||
{
|
||||
public:
|
||||
struct Entry
|
||||
class Entry
|
||||
{
|
||||
|
||||
|
||||
public:
|
||||
BufferState state() const;
|
||||
HashVal parentKey() const;
|
||||
Entry& mark (BufferState newState);
|
||||
|
|
|
|||
|
|
@ -1136,7 +1136,12 @@ return: 0
|
|||
END
|
||||
|
||||
|
||||
TEST "TypedAllocationManager" TypedAllocationManager_test <<END
|
||||
PLANNED "custom allocator(I)" SimpleAllocator_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "custom allocator(II)" TypedAllocationManager_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
|
|
@ -87,10 +87,10 @@ namespace test {
|
|||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
UNIMPLEMENTED ("cover all metadata properties");
|
||||
CHECK (ensure_proper_fixture());
|
||||
verifyBasicProperties();
|
||||
verifyStandardCase();
|
||||
UNIMPLEMENTED ("cover all metadata properties");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
160
tests/lib/simple-allocator-test.cpp
Normal file
160
tests/lib/simple-allocator-test.cpp
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
SimpleAllocator(Test) - check interface for simple custom allocations
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2011, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/simple-allocator.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
||||
//#include <tr1/memory>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace test{
|
||||
|
||||
|
||||
using util::isSameObject;
|
||||
// using std::tr1::shared_ptr;
|
||||
using std::string;
|
||||
using std::rand;
|
||||
|
||||
|
||||
|
||||
namespace { // test data and helpers...
|
||||
|
||||
long checksum_ = 0;
|
||||
|
||||
/**
|
||||
* Yet-another ctor/dtor-tracking test dummy object....
|
||||
*/
|
||||
template<uint siz>
|
||||
class DummyObj
|
||||
{
|
||||
char crap_[siz];
|
||||
|
||||
public:
|
||||
DummyObj()
|
||||
{
|
||||
REQUIRE (siz);
|
||||
for (uint i=0; i<siz; ++i)
|
||||
checksum_ += (crap_[i] = rand() % 128);
|
||||
}
|
||||
|
||||
~DummyObj()
|
||||
{
|
||||
for (uint i=0; i<siz; ++i)
|
||||
checksum_ -= crap_[i];
|
||||
}
|
||||
};
|
||||
|
||||
typedef SimpleAllocator<Types<DummyObj<1>,DummyObj<23>,string> > TestAllocator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************
|
||||
* @test cover the basic operations of a custom allocator, delegating to mpool.
|
||||
* The SimpleAllocator doesn't provide any ref-counting or tracking facilities,
|
||||
* nor does he support bulk de-allocation. 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.
|
||||
*
|
||||
* @todo as of 9/11 we do heap allocation, but we should use mpool -- see also Ticket #835
|
||||
*
|
||||
* @see engine::BufferMetadata
|
||||
* @see TypedAllocationManager_test
|
||||
*/
|
||||
class SimpleAllocator_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
CHECK (0 == checksum_);
|
||||
|
||||
TestAllocator allocator;
|
||||
|
||||
typedef string * PS;
|
||||
typedef DummyObj<1> * PD1;
|
||||
typedef DummyObj<23> * PD23;
|
||||
CHECK (sizeof(DummyObj<1>) != sizeof(DummyObj<23>));
|
||||
|
||||
PD1 pD11 = allocator.create<DummyObj<1> >();
|
||||
PD1 pD12 = allocator.create<DummyObj<1> >();
|
||||
PD23 pD21 = allocator.create<DummyObj<23> >();
|
||||
PD23 pD22 = allocator.create<DummyObj<23> >();
|
||||
PS pS11 = allocator.create<string> ("Lumiera");
|
||||
PS pS12 = allocator.create<string> ("the paradox");
|
||||
|
||||
CHECK (pD11);
|
||||
CHECK (pD12);
|
||||
CHECK (pD21);
|
||||
CHECK (pD22);
|
||||
CHECK (pS11);
|
||||
CHECK (pS12);
|
||||
CHECK (!isSameObject (*pD11, *pD12));
|
||||
CHECK (!isSameObject (*pD11, *pD21));
|
||||
CHECK (!isSameObject (*pD11, *pD22));
|
||||
CHECK (!isSameObject (*pD11, *pS11));
|
||||
CHECK (!isSameObject (*pD11, *pS12));
|
||||
CHECK (!isSameObject (*pD12, *pD21));
|
||||
CHECK (!isSameObject (*pD12, *pD22));
|
||||
CHECK (!isSameObject (*pD12, *pS11));
|
||||
CHECK (!isSameObject (*pD12, *pS12));
|
||||
CHECK (!isSameObject (*pD21, *pD22));
|
||||
CHECK (!isSameObject (*pD21, *pS11));
|
||||
CHECK (!isSameObject (*pD21, *pS12));
|
||||
CHECK (!isSameObject (*pD22, *pS11));
|
||||
CHECK (!isSameObject (*pD22, *pS12));
|
||||
CHECK (!isSameObject (*pS11, *pS12));
|
||||
|
||||
CHECK (*pS11 == "Lumiera");
|
||||
CHECK (*pS12 == "the paradox");
|
||||
|
||||
PD23 pDxx = allocator.create<DummyObj<23> > (*pD21);
|
||||
PS pSxx = allocator.create<string> (*pS12);
|
||||
|
||||
CHECK (*pS12 == *pSxx);
|
||||
CHECK (!isSameObject (*pS12, *pSxx));
|
||||
|
||||
allocator.destroy (pD11);
|
||||
allocator.destroy (pD12);
|
||||
allocator.destroy (pD21);
|
||||
allocator.destroy (pD22);
|
||||
allocator.destroy (pS11);
|
||||
allocator.destroy (pS12);
|
||||
allocator.destroy (pDxx);
|
||||
allocator.destroy (pSxx);
|
||||
|
||||
CHECK (0 == checksum_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (SimpleAllocator_test, "unit common");
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
Loading…
Reference in a new issue