WIP further refactorings.
Put nodeoperation.hpp and ConfigSelector in a sub namespace engine::config
This commit is contained in:
parent
847cc9c267
commit
cf7bd178de
9 changed files with 589 additions and 425 deletions
|
|
@ -25,12 +25,18 @@
|
|||
** Under some circumstances it is necessary to assemble functionality
|
||||
** out of elementary building blocks. Especially, this assembly can be
|
||||
** expressed as template specialisations directed by a configuration type.
|
||||
** Thus, the purpose of this header is to encode a flag-like configuraiton
|
||||
** Thus, the purpose of this header is to encode flag-like configuraitons
|
||||
** as distinct types, which can be used to select such specialisations.
|
||||
** Each possible configuration can be encoded as a list of flags, which allows
|
||||
** to generate, filter and process those configurations. The final goal is to
|
||||
** automatically generate a factory which will deliver objects configured
|
||||
** according to the configuration in question.
|
||||
** automatically generate a factory which is able to deliver objects
|
||||
** configured according to the situation encoded in the flags.
|
||||
**
|
||||
** @note currently there is an inherent limitation to configurations defined by
|
||||
** a maximum of 5 independant flags. While it is easy to increase this limit,
|
||||
** you should consider that the final goal is to genarate template instantiations,
|
||||
** which would lead to more and more code bloat with growing number of possible
|
||||
** combination.
|
||||
**
|
||||
** @see proc::engine::config::Strategy usage example
|
||||
** @see proc::engine::config::ConfigSelector
|
||||
|
|
|
|||
|
|
@ -27,15 +27,17 @@
|
|||
|
||||
|
||||
namespace lumiera {
|
||||
|
||||
|
||||
/* types for figuring out the overload resolution chosen by the compiler */
|
||||
|
||||
typedef char Yes_t;
|
||||
struct No_t { char padding[8]; };
|
||||
|
||||
|
||||
|
||||
namespace typelist {
|
||||
|
||||
|
||||
/* types for figuring out the overload resolution chosen by the compiler */
|
||||
|
||||
typedef char Yes_t;
|
||||
struct No_t { char padding[8]; };
|
||||
|
||||
|
||||
/** semi-automatic detection if an instantiation is possible.
|
||||
* Requires help by the template to be tested, which needs to define
|
||||
* a typedef member \c is_defined. The embedded metafunction Test can be used
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#define LUMIERA_VARIANT_H
|
||||
|
||||
|
||||
#include "common/meta/typelistutil.hpp"
|
||||
#include "common/meta/generator.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
|
|
|||
|
|
@ -63,243 +63,249 @@
|
|||
#include "proc/engine/bufftable.hpp"
|
||||
#include "proc/engine/nodeinvocation.hpp"
|
||||
|
||||
#include "common/meta/util.hpp"
|
||||
#include "common/meta/configflags.hpp"
|
||||
|
||||
|
||||
|
||||
|
||||
namespace engine {
|
||||
|
||||
|
||||
/**
|
||||
* Collection of functions used to build up the invocation sequence.
|
||||
*/
|
||||
class OperationBase
|
||||
{
|
||||
|
||||
};
|
||||
namespace config {
|
||||
|
||||
template<class NEXT>
|
||||
struct QueryCache : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
BuffHandle fetched = ivo.fetch (
|
||||
this->genFrameID (ivo));
|
||||
if (fetched)
|
||||
return fetched;
|
||||
else
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct AllocBufferTable : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
BuffTableChunk buffTab (ivo.wiring, ivo.getBuffTableStorage());
|
||||
ivo.setBuffTab(&buffTab);
|
||||
ASSERT (ivo.buffTab);
|
||||
ASSERT (ivo.buffTab_isConsistent());
|
||||
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct PullInput : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
BuffHandle * inH = ivo.buffTab->inHandle;
|
||||
BuffHandle::PBuff *inBuff = ivo.buffTab->inBuff;
|
||||
|
||||
for (uint i = 0; i < ivo.nrI(); ++i )
|
||||
{
|
||||
inBuff[i] =
|
||||
*(inH[i] = this->pullPredecessor(ivo,i)); // invoke predecessor
|
||||
// now Input #i is ready...
|
||||
}
|
||||
return NEXT::step (ivo); // note: passing down a ref to the ProcessInvocation
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct ReadSource : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
BuffHandle *inH = ivo.buffTab->inHandle;
|
||||
BuffHandle *outH = ivo.buffTab->outHandle;
|
||||
BuffHandle::PBuff *inBuff = ivo.buffTab->inBuff;
|
||||
BuffHandle::PBuff *outBuff = ivo.buffTab->outBuff;
|
||||
|
||||
ASSERT (ivo.nrO() == ivo.nrI() );
|
||||
|
||||
for (uint i = 0; i < ivo.nrI(); ++i )
|
||||
{
|
||||
inBuff[i] = outBuff[i] =
|
||||
*(inH[i] = outH[i] = this->getSource(ivo,i));
|
||||
// now Input #i is ready...
|
||||
}
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct AllocOutput : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
ASSERT (ivo.buffTab);
|
||||
ASSERT (ivo.nrO() < ivo.buffTabSize());
|
||||
BuffHandle *outH = ivo.buffTab->outHandle;
|
||||
BuffHandle::PBuff *outBuff = ivo.buffTab->outBuff;
|
||||
|
||||
for (uint i = 0; i < ivo.nrO(); ++i )
|
||||
{
|
||||
outBuff[i] =
|
||||
*(outH[i] = ivo.allocateBuffer (ivo.wiring.out[i].bufferType));
|
||||
// now Output buffer for channel #i is available...
|
||||
}
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct ProcessData : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
ASSERT (ivo.buffTab);
|
||||
ASSERT (ivo.buffTab_isConsistent());
|
||||
ASSERT (this->validateBuffers(ivo));
|
||||
|
||||
// Invoke our own process() function,
|
||||
// providing the array of outBuffer+inBuffer ptrs
|
||||
ivo.wiring.processFunction (ivo.buffTab->outBuff);
|
||||
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
template<class NEXT>
|
||||
struct FeedCache : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
for (uint i = 0; i < ivo.nrO(); ++i )
|
||||
{
|
||||
// declare all Outputs as finished
|
||||
ivo.is_calculated(ivo.buffTab->outHandle[i]);
|
||||
}
|
||||
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
template<class NEXT>
|
||||
struct ReleaseBuffers : NEXT /////////////////TODO: couldn't this be done automatically by BuffTab's dtor??
|
||||
{ ///////////////// this would require BuffHandle to be a smart ref....
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
// all buffers besides the required Output no longer needed
|
||||
this->releaseBuffers(ivo.buffTab->outHandle,
|
||||
ivo.buffTabSize(),
|
||||
ivo.outNr);
|
||||
|
||||
return ivo.buffTab->outHandle[ivo.outNr];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* === declare the possible Assembly of these elementary steps === */
|
||||
|
||||
enum Cases
|
||||
{
|
||||
CACHING = 1,
|
||||
PROCESS,
|
||||
INPLACE,
|
||||
|
||||
/**
|
||||
* Collection of functions used to build up the invocation sequence.
|
||||
*/
|
||||
class OperationBase
|
||||
{
|
||||
typedef lumiera::Yes_t is_defined;
|
||||
};
|
||||
|
||||
NOT_SET = 0,
|
||||
NUM_Cases = INPLACE
|
||||
};
|
||||
template<class NEXT>
|
||||
struct QueryCache : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
BuffHandle fetched = ivo.fetch (
|
||||
this->genFrameID (ivo));
|
||||
if (fetched)
|
||||
return fetched;
|
||||
else
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct AllocBufferTable : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
BuffTableChunk buffTab (ivo.wiring, ivo.getBuffTableStorage());
|
||||
ivo.setBuffTab(&buffTab);
|
||||
ASSERT (ivo.buffTab);
|
||||
ASSERT (ivo.buffTab_isConsistent());
|
||||
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct PullInput : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
BuffHandle * inH = ivo.buffTab->inHandle;
|
||||
BuffHandle::PBuff *inBuff = ivo.buffTab->inBuff;
|
||||
|
||||
for (uint i = 0; i < ivo.nrI(); ++i )
|
||||
{
|
||||
inBuff[i] =
|
||||
*(inH[i] = this->pullPredecessor(ivo,i)); // invoke predecessor
|
||||
// now Input #i is ready...
|
||||
}
|
||||
return NEXT::step (ivo); // note: passing down a ref to the ProcessInvocation
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct ReadSource : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
BuffHandle *inH = ivo.buffTab->inHandle;
|
||||
BuffHandle *outH = ivo.buffTab->outHandle;
|
||||
BuffHandle::PBuff *inBuff = ivo.buffTab->inBuff;
|
||||
BuffHandle::PBuff *outBuff = ivo.buffTab->outBuff;
|
||||
|
||||
ASSERT (ivo.nrO() == ivo.nrI() );
|
||||
|
||||
for (uint i = 0; i < ivo.nrI(); ++i )
|
||||
{
|
||||
inBuff[i] = outBuff[i] =
|
||||
*(inH[i] = outH[i] = this->getSource(ivo,i));
|
||||
// now Input #i is ready...
|
||||
}
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct AllocOutput : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
ASSERT (ivo.buffTab);
|
||||
ASSERT (ivo.nrO() < ivo.buffTabSize());
|
||||
BuffHandle *outH = ivo.buffTab->outHandle;
|
||||
BuffHandle::PBuff *outBuff = ivo.buffTab->outBuff;
|
||||
|
||||
for (uint i = 0; i < ivo.nrO(); ++i )
|
||||
{
|
||||
outBuff[i] =
|
||||
*(outH[i] = ivo.allocateBuffer (ivo.wiring.out[i].bufferType));
|
||||
// now Output buffer for channel #i is available...
|
||||
}
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<class NEXT>
|
||||
struct ProcessData : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
ASSERT (ivo.buffTab);
|
||||
ASSERT (ivo.buffTab_isConsistent());
|
||||
ASSERT (this->validateBuffers(ivo));
|
||||
|
||||
// Invoke our own process() function,
|
||||
// providing the array of outBuffer+inBuffer ptrs
|
||||
ivo.wiring.processFunction (ivo.buffTab->outBuff);
|
||||
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
template<class NEXT>
|
||||
struct FeedCache : NEXT
|
||||
{
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
for (uint i = 0; i < ivo.nrO(); ++i )
|
||||
{
|
||||
// declare all Outputs as finished
|
||||
ivo.is_calculated(ivo.buffTab->outHandle[i]);
|
||||
}
|
||||
|
||||
return NEXT::step (ivo);
|
||||
}
|
||||
};
|
||||
|
||||
template<class NEXT>
|
||||
struct ReleaseBuffers : NEXT /////////////////TODO: couldn't this be done automatically by BuffTab's dtor??
|
||||
{ ///////////////// this would require BuffHandle to be a smart ref....
|
||||
BuffHandle
|
||||
step (Invocation& ivo)
|
||||
{
|
||||
// all buffers besides the required Output no longer needed
|
||||
this->releaseBuffers(ivo.buffTab->outHandle,
|
||||
ivo.buffTabSize(),
|
||||
ivo.outNr);
|
||||
|
||||
return ivo.buffTab->outHandle[ivo.outNr];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* === declare the possible Assembly of these elementary steps === */
|
||||
|
||||
enum Cases
|
||||
{
|
||||
CACHING = 1,
|
||||
PROCESS,
|
||||
INPLACE,
|
||||
|
||||
NOT_SET = 0,
|
||||
NUM_Cases = INPLACE
|
||||
};
|
||||
|
||||
|
||||
|
||||
template<char CACHE_Fl=0, char INPLACE_Fl=0>
|
||||
struct SelectBuffProvider;
|
||||
|
||||
template<> struct SelectBuffProvider<CACHING> : AllocBufferFromCache { };
|
||||
template<> struct SelectBuffProvider<NOT_SET,INPLACE> : AllocBufferFromParent{ };
|
||||
template<> struct SelectBuffProvider<CACHING,INPLACE> : AllocBufferFromCache { };
|
||||
template<> struct SelectBuffProvider<> : AllocBufferFromParent{ };
|
||||
|
||||
|
||||
template<class Config>
|
||||
struct Strategy ;
|
||||
|
||||
|
||||
template<char CACHE_Fl=0, char INPLACE_Fl=0>
|
||||
struct SelectBuffProvider;
|
||||
|
||||
template<> struct SelectBuffProvider<CACHING> : AllocBufferFromCache { };
|
||||
template<> struct SelectBuffProvider<NOT_SET,INPLACE> : AllocBufferFromParent{ };
|
||||
template<> struct SelectBuffProvider<CACHING,INPLACE> : AllocBufferFromCache { };
|
||||
template<> struct SelectBuffProvider<> : AllocBufferFromParent{ };
|
||||
|
||||
|
||||
template<class Config>
|
||||
struct Strategy ;
|
||||
|
||||
using lumiera::typelist::Config;
|
||||
|
||||
template<char INPLACE>
|
||||
struct Strategy< Config<CACHING,PROCESS,INPLACE> >
|
||||
: QueryCache<
|
||||
AllocBufferTable<
|
||||
PullInput<
|
||||
AllocOutput<
|
||||
ProcessData<
|
||||
FeedCache<
|
||||
using lumiera::typelist::Config;
|
||||
|
||||
template<char INPLACE>
|
||||
struct Strategy< Config<CACHING,PROCESS,INPLACE> >
|
||||
: QueryCache<
|
||||
AllocBufferTable<
|
||||
PullInput<
|
||||
AllocOutput<
|
||||
ProcessData<
|
||||
FeedCache<
|
||||
ReleaseBuffers<
|
||||
OperationBase > > > > > > >
|
||||
{ };
|
||||
|
||||
template<char INPLACE>
|
||||
struct Strategy< Config<PROCESS,INPLACE> >
|
||||
: AllocBufferTable<
|
||||
PullInput<
|
||||
AllocOutput<
|
||||
ProcessData<
|
||||
ReleaseBuffers<
|
||||
OperationBase > > > > > > >
|
||||
{ };
|
||||
|
||||
template<char INPLACE>
|
||||
struct Strategy< Config<PROCESS,INPLACE> >
|
||||
: AllocBufferTable<
|
||||
PullInput<
|
||||
AllocOutput<
|
||||
ProcessData<
|
||||
OperationBase > > > > >
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct Strategy< Config<> >
|
||||
: AllocBufferTable<
|
||||
ReadSource<
|
||||
ReleaseBuffers<
|
||||
OperationBase > > > > >
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct Strategy< Config<> >
|
||||
: AllocBufferTable<
|
||||
ReadSource<
|
||||
ReleaseBuffers<
|
||||
OperationBase > > >
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct Strategy< Config<INPLACE> > : Strategy< Config<> > { };
|
||||
|
||||
template<>
|
||||
struct Strategy< Config<CACHING> >
|
||||
: AllocBufferTable<
|
||||
ReadSource<
|
||||
AllocOutput<
|
||||
ProcessData< // wiring_.processFunction is supposed to do just buffer copying here
|
||||
ReleaseBuffers<
|
||||
OperationBase > > > > >
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
OperationBase > > >
|
||||
{ };
|
||||
|
||||
template<>
|
||||
struct Strategy< Config<INPLACE> > : Strategy< Config<> > { };
|
||||
|
||||
template<>
|
||||
struct Strategy< Config<CACHING> >
|
||||
: AllocBufferTable<
|
||||
ReadSource<
|
||||
AllocOutput<
|
||||
ProcessData< // wiring_.processFunction is supposed to do just buffer copying here
|
||||
ReleaseBuffers<
|
||||
OperationBase > > > > >
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace config
|
||||
|
||||
} // namespace engine
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -26,9 +26,77 @@
|
|||
#include "proc/engine/nodeoperation.hpp"
|
||||
#include "proc/engine/nodewiringconfig.hpp"
|
||||
|
||||
#include "common/meta/typelistutil.hpp"
|
||||
|
||||
|
||||
namespace engine {
|
||||
|
||||
namespace { // internal: setting up a factory for each required configuration
|
||||
|
||||
using config::CACHING;
|
||||
using config::PROCESS;
|
||||
using config::INPLACE;
|
||||
|
||||
using config::ConfigSelector;
|
||||
using config::Strategy;
|
||||
|
||||
using lumiera::typelist::Flags;
|
||||
using lumiera::typelist::CombineFlags;
|
||||
using lumiera::typelist::DefineConfigByFlags;
|
||||
using lumiera::typelist::Instantiation;
|
||||
using lumiera::typelist::Apply;
|
||||
using lumiera::typelist::Filter;
|
||||
|
||||
|
||||
typedef Flags<CACHING,PROCESS,INPLACE>::Tuple AllFlags;
|
||||
|
||||
/** build the list of all possible flag combinations */
|
||||
typedef CombineFlags<AllFlags> AllFlagCombinations;
|
||||
|
||||
/** build a configuration type for each of those flag combinations */
|
||||
typedef Apply<AllFlagCombinations::List, DefineConfigByFlags> AllConfigs;
|
||||
|
||||
/** filter those configurations which actually define a wiring strategy */
|
||||
typedef Filter<AllConfigs::List, Instantiation<Strategy>::Test> PossibleConfigs;
|
||||
|
||||
|
||||
class Alloc {}; ///////////////TODO
|
||||
|
||||
|
||||
template<class CONF>
|
||||
class WiringDescriptorFactory
|
||||
{
|
||||
Alloc& alloc_;
|
||||
|
||||
public:
|
||||
WiringDescriptorFactory(Alloc& a)
|
||||
: alloc_(a) {}
|
||||
|
||||
WiringDescriptor&
|
||||
operator() ()
|
||||
{
|
||||
/////////////////////////////////////////////TODO
|
||||
//return offset_ + Maybe<CONF>::CODE;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef ConfigSelector<WiringDescriptorFactory, WiringDescriptor&, Alloc&> WiringSelector;
|
||||
|
||||
struct WiringFactoryImpl
|
||||
{
|
||||
// WiringSelector selector;
|
||||
|
||||
WiringFactoryImpl (Alloc& alloc)
|
||||
// : selector(PossibleConfigs::List(), alloc)
|
||||
{ }
|
||||
};
|
||||
|
||||
} // (END) internals
|
||||
|
||||
|
||||
/////////////////////////////TODO: define the ctor
|
||||
|
||||
|
||||
/** create and configure a concrete wiring descriptor to tie
|
||||
* a ProcNode to its predecessor nodes. This includes selecting
|
||||
|
|
@ -47,7 +115,8 @@ namespace engine {
|
|||
UNIMPLEMENTED ("build the actual wiring descriptor based on given operation options");
|
||||
|
||||
// Bits config (FlagInfo<Config>::CODE);
|
||||
// return selector(config);
|
||||
size_t config = 13; /////////////////////////////////////////TODO
|
||||
// return pImpl_->selector(config);
|
||||
}
|
||||
// BlockAlloc<NodeWiring< StateAdapter< Config<cache, process, inplace> > > >::fabricate();
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
|
||||
#include "proc/engine/procnode.hpp"
|
||||
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
|
||||
|
|
@ -36,6 +37,8 @@ namespace engine {
|
|||
|
||||
class WiringFactory;
|
||||
|
||||
namespace { class WiringFactoryImpl; }
|
||||
|
||||
|
||||
/**
|
||||
* Actual implementation of the link between nodes,
|
||||
|
|
@ -73,6 +76,8 @@ namespace engine {
|
|||
|
||||
class WiringFactory
|
||||
{
|
||||
boost::scoped_ptr<WiringFactoryImpl> pImpl_;
|
||||
|
||||
public:
|
||||
WiringDescriptor&
|
||||
operator() (uint nrOut, uint nrIn, bool cache);
|
||||
|
|
|
|||
|
|
@ -56,122 +56,125 @@
|
|||
|
||||
|
||||
namespace engine {
|
||||
|
||||
using lumiera::typelist::FlagInfo;
|
||||
namespace config {
|
||||
|
||||
using boost::lexical_cast;
|
||||
using util::contains;
|
||||
|
||||
|
||||
/**
|
||||
* Helper for fabricating ProcNode Wiring configurations.
|
||||
* This object builds a table of factories, holding one factory
|
||||
* for each possible node configuration. Provided with the desired
|
||||
* configuration encoded as bits, the related factory can be invoked,
|
||||
* thus producing a product object for the given configuration.
|
||||
*
|
||||
* \par implementation notes
|
||||
* The actual factory class is templated, so it will be defined
|
||||
* at the use site of ConfigSelector. Moreover, this factory
|
||||
* usually expects an ctor argument, which will be fed through
|
||||
* when creating the ConfigSelector instance. This is one of
|
||||
* the reasons why we go through all these complicated factory
|
||||
* building: this ctor argument usually brings in a reference
|
||||
* to the actual memory allocator. Thus we have to rebuild the
|
||||
* ConfigSelector each time we switch and rebuild the ProcNode
|
||||
* factories, which in turn happens each time we use a new
|
||||
* bulk allocation memory block -- typically for each separate
|
||||
* segment of the Timeline and processing node graph.
|
||||
*
|
||||
* Now the selection of the possible flag configurations, for which
|
||||
* Factory instances are created in the table, is governed by the
|
||||
* type parameter of the ConfigSelector ctor. This type parameter
|
||||
* needs to be a Typelist of Typelists, each representing a flag
|
||||
* configuration. The intention is to to drive this selection by
|
||||
* the use of template metaprogramming for extracting all
|
||||
* currently defined StateProxy object configurations.
|
||||
* @todo as the facories live only within the enclosed table (map)
|
||||
* we could allocate them in-place. Unfortunately this is
|
||||
* non-trivial, because the stl containers employ
|
||||
* value semantics and thus do a copy even on insert.
|
||||
* Thus, for now we use a shared_ptr to hold the factory
|
||||
* heap allocated.
|
||||
*/
|
||||
template< template<class CONF> class Factory
|
||||
, typename PAR ///< ctor parameter of the Factories
|
||||
, typename RET ///< common base class of the Factory's products
|
||||
>
|
||||
class ConfigSelector
|
||||
{
|
||||
|
||||
struct FacFunctor
|
||||
{
|
||||
virtual ~FacFunctor() {}
|
||||
virtual RET invoke() =0;
|
||||
};
|
||||
template<class FAC>
|
||||
struct FactoryHolder : FacFunctor
|
||||
{
|
||||
FAC factory_;
|
||||
FactoryHolder(PAR p) : factory_(p) {}
|
||||
|
||||
virtual RET invoke () { return factory_(); }
|
||||
};
|
||||
|
||||
|
||||
typedef std::tr1::shared_ptr<FacFunctor> PFunc;
|
||||
typedef std::map<size_t, PFunc> ConfigTable;
|
||||
|
||||
ConfigTable possibleConfig_; ///< Table of factories
|
||||
|
||||
/** Helper: a visitor usable with FlagInfo */
|
||||
struct FactoryTableBuilder
|
||||
{
|
||||
PAR ctor_param_;
|
||||
ConfigTable& factories_;
|
||||
|
||||
FactoryTableBuilder (ConfigTable& tab, PAR p)
|
||||
: ctor_param_(p),
|
||||
factories_(tab) { }
|
||||
|
||||
|
||||
/* === visitation interface === */
|
||||
|
||||
typedef void Ret;
|
||||
|
||||
template<class CONF>
|
||||
void
|
||||
visit (size_t code)
|
||||
{
|
||||
PFunc pFactory (new FactoryHolder<Factory<CONF> > (ctor_param_));
|
||||
factories_[code] = pFactory;
|
||||
}
|
||||
|
||||
void done() {}
|
||||
};
|
||||
|
||||
public:
|
||||
template<class CONFS>
|
||||
ConfigSelector(CONFS const&, PAR factory_ctor_param)
|
||||
{
|
||||
FactoryTableBuilder buildTable(this->possibleConfig_,
|
||||
factory_ctor_param );
|
||||
// store a new Factory instance
|
||||
// for each possible Flag-Configuration
|
||||
FlagInfo<CONFS>::accept (buildTable);
|
||||
}
|
||||
|
||||
RET
|
||||
operator() (size_t configFlags) ///< invoke the factory corresponding to the given config
|
||||
{
|
||||
if (contains (possibleConfig_, configFlags))
|
||||
return possibleConfig_[configFlags]->invoke();
|
||||
else
|
||||
throw lumiera::error::Invalid("ConfigSelector: No preconfigured factory for config-bits="+lexical_cast<std::string>(configFlags));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
using lumiera::typelist::FlagInfo;
|
||||
|
||||
using boost::lexical_cast;
|
||||
using util::contains;
|
||||
|
||||
|
||||
/**
|
||||
* Helper for fabricating ProcNode Wiring configurations.
|
||||
* This object builds a table of factories, holding one factory
|
||||
* for each possible node configuration. Provided with the desired
|
||||
* configuration encoded as bits, the related factory can be invoked,
|
||||
* thus producing a product object for the given configuration.
|
||||
*
|
||||
* \par implementation notes
|
||||
* The actual factory class is templated, so it will be defined
|
||||
* at the use site of ConfigSelector. Moreover, this factory
|
||||
* usually expects an ctor argument, which will be fed through
|
||||
* when creating the ConfigSelector instance. This is one of
|
||||
* the reasons why we go through all these complicated factory
|
||||
* building: this ctor argument usually brings in a reference
|
||||
* to the actual memory allocator. Thus we have to rebuild the
|
||||
* ConfigSelector each time we switch and rebuild the ProcNode
|
||||
* factories, which in turn happens each time we use a new
|
||||
* bulk allocation memory block -- typically for each separate
|
||||
* segment of the Timeline and processing node graph.
|
||||
*
|
||||
* Now the selection of the possible flag configurations, for which
|
||||
* Factory instances are created in the table, is governed by the
|
||||
* type parameter of the ConfigSelector ctor. This type parameter
|
||||
* needs to be a Typelist of Typelists, each representing a flag
|
||||
* configuration. The intention is to to drive this selection by
|
||||
* the use of template metaprogramming for extracting all
|
||||
* currently defined StateProxy object configurations.
|
||||
* @todo as the facories live only within the enclosed table (map)
|
||||
* we could allocate them in-place. Unfortunately this is
|
||||
* non-trivial, because the stl containers employ
|
||||
* value semantics and thus do a copy even on insert.
|
||||
* Thus, for now we use a shared_ptr to hold the factory
|
||||
* heap allocated.
|
||||
*/
|
||||
template< template<class CONF> class Factory
|
||||
, typename PAR ///< ctor parameter of the Factories
|
||||
, typename RET ///< common base class of the Factory's products
|
||||
>
|
||||
class ConfigSelector
|
||||
{
|
||||
|
||||
struct FacFunctor
|
||||
{
|
||||
virtual ~FacFunctor() {}
|
||||
virtual RET invoke() =0;
|
||||
};
|
||||
template<class FAC>
|
||||
struct FactoryHolder : FacFunctor
|
||||
{
|
||||
FAC factory_;
|
||||
FactoryHolder(PAR p) : factory_(p) {}
|
||||
|
||||
virtual RET invoke () { return factory_(); }
|
||||
};
|
||||
|
||||
|
||||
typedef std::tr1::shared_ptr<FacFunctor> PFunc;
|
||||
typedef std::map<size_t, PFunc> ConfigTable;
|
||||
|
||||
ConfigTable possibleConfig_; ///< Table of factories
|
||||
|
||||
/** Helper: a visitor usable with FlagInfo */
|
||||
struct FactoryTableBuilder
|
||||
{
|
||||
PAR ctor_param_;
|
||||
ConfigTable& factories_;
|
||||
|
||||
FactoryTableBuilder (ConfigTable& tab, PAR p)
|
||||
: ctor_param_(p),
|
||||
factories_(tab) { }
|
||||
|
||||
|
||||
/* === visitation interface === */
|
||||
|
||||
typedef void Ret;
|
||||
|
||||
template<class CONF>
|
||||
void
|
||||
visit (size_t code)
|
||||
{
|
||||
PFunc pFactory (new FactoryHolder<Factory<CONF> > (ctor_param_));
|
||||
factories_[code] = pFactory;
|
||||
}
|
||||
|
||||
void done() {}
|
||||
};
|
||||
|
||||
public:
|
||||
template<class CONFS>
|
||||
ConfigSelector(CONFS const&, PAR factory_ctor_param)
|
||||
{
|
||||
FactoryTableBuilder buildTable(this->possibleConfig_,
|
||||
factory_ctor_param );
|
||||
// store a new Factory instance
|
||||
// for each possible Flag-Configuration
|
||||
FlagInfo<CONFS>::accept (buildTable);
|
||||
}
|
||||
|
||||
RET
|
||||
operator() (size_t configFlags) ///< invoke the factory corresponding to the given config
|
||||
{
|
||||
if (contains (possibleConfig_, configFlags))
|
||||
return possibleConfig_[configFlags]->invoke();
|
||||
else
|
||||
throw lumiera::error::Invalid("ConfigSelector: No preconfigured factory for config-bits="+lexical_cast<std::string>(configFlags));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace config
|
||||
|
||||
} // namespace engine
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -38,8 +38,11 @@
|
|||
|
||||
|
||||
#include "common/test/run.hpp"
|
||||
#include "common/meta/util.hpp"
|
||||
#include "common/meta/generator.hpp"
|
||||
#include "common/meta/typelistutil.hpp"
|
||||
#include "common/meta/configflags.hpp"
|
||||
#include "meta/typelistdiagnostics.hpp"
|
||||
#include "proc/engine/nodewiringconfig.hpp"
|
||||
#include "common/util.hpp"
|
||||
|
||||
|
|
@ -69,77 +72,6 @@ namespace lumiera {
|
|||
, NOT_SET = 0
|
||||
};
|
||||
|
||||
format fmt ("-<%u>%s");
|
||||
|
||||
struct NullP
|
||||
{
|
||||
static string print () { return "-"; }
|
||||
};
|
||||
|
||||
/** debugging template,
|
||||
* printing the "number" used for intantiation on ctor call
|
||||
*/
|
||||
template<class NUM=NullType, class BASE=NullP>
|
||||
struct Printer;
|
||||
|
||||
template<class BASE>
|
||||
struct Printer<NullType, BASE>
|
||||
: BASE
|
||||
{
|
||||
static string print () { return str( fmt % "·" % BASE::print()); }
|
||||
};
|
||||
|
||||
template<class BASE, char Fl>
|
||||
struct Printer<Flag<Fl>, BASE>
|
||||
: BASE
|
||||
{
|
||||
static string print () { return str( fmt % uint(Fl) % BASE::print()); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** call the debug-print for a typelist
|
||||
* utilizing the Printer template */
|
||||
template<class L>
|
||||
string
|
||||
printSublist ()
|
||||
{
|
||||
typedef InstantiateChained<L, Printer, NullP> SubList;
|
||||
return SubList::print();
|
||||
}
|
||||
|
||||
/** Spezialisation for debug-printing of a nested sublist */
|
||||
template<class TY, class TYPES, class BASE>
|
||||
struct Printer<Node<TY,TYPES>, BASE>
|
||||
: BASE
|
||||
{
|
||||
static string print ()
|
||||
{
|
||||
typedef Node<TY,TYPES> List;
|
||||
return string("\n\t+--") + printSublist<List>()+"+"
|
||||
+ BASE::print();
|
||||
}
|
||||
};
|
||||
|
||||
template<char f1, char f2, char f3, char f4, char f5, class BASE>
|
||||
struct Printer<Config<f1,f2,f3,f4,f5>, BASE>
|
||||
: BASE
|
||||
{
|
||||
static string print ()
|
||||
{
|
||||
typedef typename Config<f1,f2,f3,f4,f5>::Flags FlagList;
|
||||
return string("\n\t+-Conf-[") + printSublist<FlagList>()+"]"
|
||||
+ BASE::print();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define DIAGNOSE(LIST) \
|
||||
typedef InstantiateChained<LIST::List, Printer, NullP> Contents_##LIST;
|
||||
|
||||
#define DISPLAY(NAME) \
|
||||
DIAGNOSE(NAME); cout << STRINGIFY(NAME) << "\t" << Contents_##NAME::print() << "\n";
|
||||
|
||||
|
||||
|
||||
/* === Test data === */
|
||||
|
|
@ -355,7 +287,7 @@ namespace lumiera {
|
|||
typedef Filter<ListAllConfigs::List,Instantiation<Maybe>::Test> Possible_Configs;
|
||||
DISPLAY (Possible_Configs);
|
||||
|
||||
typedef engine::ConfigSelector<TestFactory, long, uint> TestFactorySelector;
|
||||
typedef engine::config::ConfigSelector<TestFactory, long, uint> TestFactorySelector;
|
||||
|
||||
const long offset = 1000; // parameter fed to all TestFactory ctors
|
||||
TestFactorySelector testConfigSelector (Possible_Configs::List(), offset);
|
||||
|
|
|
|||
140
tests/common/meta/typelistdiagnostics.hpp
Normal file
140
tests/common/meta/typelistdiagnostics.hpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
TYPELISTDIAGNOSTICS - helper for testing the typelist based utilities
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, 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 typelistdiagnostics.hpp
|
||||
** a Printer template usable for debugging the structure of a typelist built
|
||||
** upon some simple debugging-style types. Examples being a Num<int> template,
|
||||
** or the Flag type. A Printer type generated from this template provides
|
||||
** a static \c print() function returing a string visualizing the structure
|
||||
** of the typelist provided as parameter to the Printer template.
|
||||
**
|
||||
** @see typelistmaniptest.cpp
|
||||
** @see configflagstest.cpp
|
||||
**
|
||||
*/
|
||||
#ifndef META_TYPELISTDIAGNOSTICS_H
|
||||
#define META_TYPELISTDIAGNOSTICS_H
|
||||
|
||||
|
||||
#include "common/meta/generator.hpp"
|
||||
//#include "common/meta/typelistutil.hpp"
|
||||
//#include "common/meta/util.hpp"
|
||||
//#include "common/util.hpp"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
using std::string;
|
||||
using boost::format;
|
||||
|
||||
|
||||
namespace lumiera {
|
||||
namespace typelist {
|
||||
namespace test {
|
||||
|
||||
|
||||
namespace { // internal definitions
|
||||
|
||||
|
||||
format fmt ("-<%u>%s");
|
||||
|
||||
struct NullP
|
||||
{
|
||||
static string print () { return "-"; }
|
||||
};
|
||||
|
||||
/** debugging template,
|
||||
* printing the "number" used for intantiation on ctor call
|
||||
*/
|
||||
template<class NUM=NullType, class BASE=NullP>
|
||||
struct Printer;
|
||||
|
||||
template<class BASE>
|
||||
struct Printer<NullType, BASE>
|
||||
: BASE
|
||||
{
|
||||
static string print () { return str( fmt % "·" % BASE::print()); }
|
||||
};
|
||||
|
||||
template<class BASE, char Fl>
|
||||
struct Printer<Flag<Fl>, BASE>
|
||||
: BASE
|
||||
{
|
||||
static string print () { return str( fmt % uint(Fl) % BASE::print()); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** call the debug-print for a typelist
|
||||
* utilizing the Printer template */
|
||||
template<class L>
|
||||
string
|
||||
printSublist ()
|
||||
{
|
||||
typedef InstantiateChained<L, Printer, NullP> SubList;
|
||||
return SubList::print();
|
||||
}
|
||||
|
||||
/** Spezialisation for debug-printing of a nested sublist */
|
||||
template<class TY, class TYPES, class BASE>
|
||||
struct Printer<Node<TY,TYPES>, BASE>
|
||||
: BASE
|
||||
{
|
||||
static string print ()
|
||||
{
|
||||
typedef Node<TY,TYPES> List;
|
||||
return string("\n\t+--") + printSublist<List>()+"+"
|
||||
+ BASE::print();
|
||||
}
|
||||
};
|
||||
|
||||
template<char f1, char f2, char f3, char f4, char f5, class BASE>
|
||||
struct Printer<Config<f1,f2,f3,f4,f5>, BASE>
|
||||
: BASE
|
||||
{
|
||||
static string print ()
|
||||
{
|
||||
typedef typename Config<f1,f2,f3,f4,f5>::Flags FlagList;
|
||||
return string("\n\t+-Conf-[") + printSublist<FlagList>()+"]"
|
||||
+ BASE::print();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define DIAGNOSE(LIST) \
|
||||
typedef InstantiateChained<LIST::List, Printer, NullP> Contents_##LIST;
|
||||
|
||||
#define DISPLAY(NAME) \
|
||||
DIAGNOSE(NAME); cout << STRINGIFY(NAME) << "\t" << Contents_##NAME::print() << "\n";
|
||||
|
||||
|
||||
|
||||
} // (End) internal defs
|
||||
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace typelist
|
||||
|
||||
} // namespace lumiera
|
||||
#endif
|
||||
Loading…
Reference in a new issue