WIP: correct indentation, add some comments...

This commit is contained in:
Fischlurch 2009-08-30 14:11:14 +02:00
parent 99310dc0af
commit 209765def5
5 changed files with 405 additions and 398 deletions

View file

@ -31,12 +31,12 @@
** to generate, filter and process those configurations. The final goal is to
** 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 independent flags. While it is easy to increase this limit,
** you should consider that the final goal is to generate template instantiations,
** which would lead to more and more code bloat with growing number of possible
** combination.
** combinations.
**
** @see proc::engine::config::Strategy usage example
** @see proc::engine::config::ConfigSelector
@ -53,153 +53,151 @@
namespace lumiera {
namespace typelist {
const size_t CONFIG_FLAGS_MAX = 5;
template<char bit> struct Flag { typedef Flag ID; };
template<> struct Flag<0> { typedef NullType ID; };
template< char f1=0
, char f2=0
, char f3=0
, char f4=0
, char f5=0
>
struct Flags
{
typedef typename Types< typename Flag<f1>::ID
, typename Flag<f2>::ID
, typename Flag<f3>::ID
, typename Flag<f4>::ID
, typename Flag<f5>::ID
>::List
Tuple;
typedef Tuple List;
};
template< char f1=0
, char f2=0
, char f3=0
, char f4=0
, char f5=0
>
struct Config ///< distinct type representing a configuration
{
typedef typename Flags<f1,f2,f3,f4,f5>::Tuple Flags;
typedef Flags List;
};
template<char Fl, class CONF>
struct ConfigSetFlag; ///< set (prepend) the Flag to the given config
template< char Fl
, char f1
, char f2
, char f3
, char f4
, char IGN
>
struct ConfigSetFlag<Fl, Config<f1,f2,f3,f4,IGN> >
{
typedef typelist::Config<Fl,f1,f2,f3,f4> Config;
};
/** build a configuration type from a list-of-flags */
template<class FLAGS, class CONF=typelist::Config<> >
struct BuildConfigFromFlags
{
typedef CONF Config;
typedef Config Type;
};
template<char Fl, class FLAGS, class CONF>
struct BuildConfigFromFlags< Node<Flag<Fl>,FLAGS>, CONF>
{
typedef typename ConfigSetFlag< Fl
, typename BuildConfigFromFlags<FLAGS,CONF>::Config
>::Config Config;
typedef Config Type;
};
/** create a configuration type for the given list-of-flags */
template<class FLAGS>
struct DefineConfigByFlags : BuildConfigFromFlags<FLAGS> { };
namespace {
/** helper comparing enum values and chars (flags) */
template<char ii, char jj>
struct maxC
{
enum{ VAL = ii < jj? jj : ii };
};
}
/**
* Helper for calculating values and for
* invoking runtime code based on a given FlagTuple.
* Can also be used on a Typelist of several Configs.
* The latter case is typically used to invoke an operation
* while enumerating all Flag-Configurations defined in Code.
* An example would be to build (at runtime) an dispatcher table.
* Explanation: For the Case covering a List of Configs, we provide
* a templated visitation function, which can accept a functor object
* to be invoked on each Configuration.
*/
template<class FLAGS>
struct FlagInfo;
template<char ff, class FLAGS>
struct FlagInfo<Node<Flag<ff>, FLAGS> >
{
enum{ BITS = maxC< ff, FlagInfo<FLAGS>::BITS> ::VAL
, CODE = (1<<ff) | FlagInfo<FLAGS>::CODE
};
};
template<>
struct FlagInfo<NullType>
{
enum{ BITS = 0
, CODE = 0
};
template<class FUNC>
static typename FUNC::Ret
accept (FUNC& functor)
{
return functor.done();
}
};
template<class CONF, class TAIL>
struct FlagInfo<Node<CONF, TAIL> >
{
typedef typename CONF::Flags ThisFlags;
enum{
BITS = maxC< FlagInfo<ThisFlags>::BITS, FlagInfo<TAIL>::BITS > ::VAL
};
template<class FUNC>
static typename FUNC::Ret
accept (FUNC& functor)
{
functor.template visit<CONF>(FlagInfo<ThisFlags>::CODE);
return FlagInfo<TAIL>::accept (functor);
}
};
} // namespace typelist
namespace typelist{
} // namespace lumiera
const size_t CONFIG_FLAGS_MAX = 5;
template<char bit> struct Flag { typedef Flag ID; };
template<> struct Flag<0> { typedef NullType ID; };
template< char f1=0
, char f2=0
, char f3=0
, char f4=0
, char f5=0
>
struct Flags
{
typedef typename Types< typename Flag<f1>::ID
, typename Flag<f2>::ID
, typename Flag<f3>::ID
, typename Flag<f4>::ID
, typename Flag<f5>::ID
>::List
Tuple;
typedef Tuple List;
};
template< char f1=0
, char f2=0
, char f3=0
, char f4=0
, char f5=0
>
struct Config ///< distinct type representing a configuration
{
typedef typename Flags<f1,f2,f3,f4,f5>::Tuple Flags;
typedef Flags List;
};
template<char Fl, class CONF>
struct ConfigSetFlag; ///< set (prepend) the Flag to the given config
template< char Fl
, char f1
, char f2
, char f3
, char f4
, char IGN
>
struct ConfigSetFlag<Fl, Config<f1,f2,f3,f4,IGN> >
{
typedef typelist::Config<Fl,f1,f2,f3,f4> Config;
};
/** build a configuration type from a list-of-flags */
template<class FLAGS, class CONF=typelist::Config<> >
struct BuildConfigFromFlags
{
typedef CONF Config;
typedef Config Type;
};
template<char Fl, class FLAGS, class CONF>
struct BuildConfigFromFlags< Node<Flag<Fl>,FLAGS>, CONF>
{
typedef typename ConfigSetFlag< Fl
, typename BuildConfigFromFlags<FLAGS,CONF>::Config
>::Config Config;
typedef Config Type;
};
/** create a configuration type for the given list-of-flags */
template<class FLAGS>
struct DefineConfigByFlags : BuildConfigFromFlags<FLAGS> { };
namespace {
/** helper comparing enum values and chars (flags) */
template<char ii, char jj>
struct maxC
{
enum{ VAL = ii < jj? jj : ii };
};
}
/**
* Helper for calculating values and for
* invoking runtime code based on a given FlagTuple.
* Can also be used on a Typelist of several Configs.
* The latter case is typically used to invoke an operation
* while enumerating all Flag-Configurations defined in Code.
* An example would be to build (at runtime) an dispatcher table.
* Explanation: For the Case covering a List of Configs, we provide
* a templated visitation function, which can accept a functor object
* to be invoked on each Configuration.
*/
template<class FLAGS>
struct FlagInfo;
template<char ff, class FLAGS>
struct FlagInfo<Node<Flag<ff>, FLAGS> >
{
enum{ BITS = maxC< ff, FlagInfo<FLAGS>::BITS> ::VAL
, CODE = (1<<ff) | FlagInfo<FLAGS>::CODE
};
};
template<>
struct FlagInfo<NullType>
{
enum{ BITS = 0
, CODE = 0
};
template<class FUNC>
static typename FUNC::Ret
accept (FUNC& functor)
{
return functor.done();
}
};
template<class CONF, class TAIL>
struct FlagInfo<Node<CONF, TAIL> >
{
typedef typename CONF::Flags ThisFlags;
enum{
BITS = maxC< FlagInfo<ThisFlags>::BITS, FlagInfo<TAIL>::BITS > ::VAL
};
template<class FUNC>
static typename FUNC::Ret
accept (FUNC& functor)
{
functor.template visit<CONF>(FlagInfo<ThisFlags>::CODE);
return FlagInfo<TAIL>::accept (functor);
}
};
}} // namespace lumiera::typelist
#endif

View file

@ -26,7 +26,7 @@
** and enables to pull a result frames from the nodes. Especially, the aspect of
** buffer management and cache query is covered here. Each node has been preconfigured by
** the builder with a WiringDescriptor and a concrete type of a StateAdapter, including
** a specific Configuration, because the node can be built to
** a specific Configuration, because the node can be built to
** - participate in the Caching or ignore the cache
** - actually process a result or just pull frames from a source
** - employ in-Place calculations or use separate in/out buffers
@ -42,15 +42,15 @@
** configurations are pre-built while compiling (it's a small number below 32 configuration instance).
** To be able to select the Strategy for each configuration, we need a Factory (ConfigSelector defined in
** nodewiring-config.hpp). which is actually instantiated and used in nodewiring.cpp, which is the object
** file holding all those instantiations.
**
** file holding all those instantiations.
**
** @see engine::ProcNode
** @see engine::Invocation
** @see engine::State
** @see engine::NodeFactory
** @see nodewiring-config.hpp
** @see nodewiring.hpp interface for building/wiring the nodes
**
**
*/
#ifndef ENGINE_NODEOPERATION_H
@ -71,249 +71,249 @@
namespace engine {
namespace config {
/**
* Base class of all concrete invocation sequences.
* Could contain a collection of functions used to build up the invocation sequence.
* Currently contains just a marker used to detect the existence of an concrete
* definition/specialisation for a given specific configuration.
*/
class OperationBase
{
typedef lumiera::Yes_t is_defined;
};
template<class NEXT>
struct QueryCache : NEXT
{
BuffHandle
step (Invocation& ivo)
{
BuffHandle fetched = ivo.fetch (ivo.genFrameID());
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);
}
};
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.procFunction (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> { typedef AllocBufferFromCache Type; };
template<> struct SelectBuffProvider<NOT_SET,INPLACE> { typedef AllocBufferFromParent Type; };
template<> struct SelectBuffProvider<CACHING,INPLACE> { typedef AllocBufferFromCache Type; };
template<> struct SelectBuffProvider<> { typedef AllocBufferFromParent Type; };
namespace config {
template<class Config>
struct Strategy ;
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<
/**
* Base class of all concrete invocation sequences.
* Could contain a collection of functions used to build up the invocation sequence.
* Currently contains just a marker used to detect the existence of an concrete
* definition/specialisation for a given specific configuration.
*/
class OperationBase
{
typedef lumiera::Yes_t is_defined;
};
template<class NEXT>
struct QueryCache : NEXT
{
BuffHandle
step (Invocation& ivo)
{
BuffHandle fetched = ivo.fetch (ivo.genFrameID());
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);
}
};
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.procFunction (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 =NOT_SET
, char INPLACE_Fl =NOT_SET
>
struct SelectBuffProvider;
template<> struct SelectBuffProvider<CACHING> { typedef AllocBufferFromCache Type; };
template<> struct SelectBuffProvider<NOT_SET,INPLACE> { typedef AllocBufferFromParent Type; };
template<> struct SelectBuffProvider<CACHING,INPLACE> { typedef AllocBufferFromCache Type; };
template<> struct SelectBuffProvider<> { typedef AllocBufferFromParent Type; };
template<class Config>
struct Strategy ;
using lumiera::typelist::Config;
template<char INPLACE>
struct Strategy< Config<CACHING,PROCESS,INPLACE> >
: QueryCache<
AllocBufferTable<
PullInput<
AllocOutput<
ProcessData<
FeedCache<
ReleaseBuffers<
OperationBase > > > > >
{ };
template<>
struct Strategy< Config<> >
: AllocBufferTable<
ReadSource<
OperationBase > > > > > > >
{ };
template<char INPLACE>
struct Strategy< Config<PROCESS,INPLACE> >
: AllocBufferTable<
PullInput<
AllocOutput<
ProcessData<
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 > > > > >
{ };
} // namespace config
OperationBase > > > > >
{ };
} // namespace engine
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 > > > > >
{ };
}} // namespace engine::config
#endif

View file

@ -117,7 +117,7 @@ namespace config {
{
FactoryHolder(PAR p)
: FAC(p),
FacFunction( static_cast<FAC&>(*this))
FacFunction (static_cast<FAC&> (*this))
{ }
};
@ -127,7 +127,9 @@ namespace config {
ConfigTable possibleConfig_; ///< Table of factories
/** Helper: a visitor usable with FlagInfo */
/** Helper: a visitor usable with FlagInfo.
* Used to create a factory for each config */
struct FactoryTableBuilder
{
PAR ctor_param_;
@ -153,6 +155,7 @@ namespace config {
void done() {}
};
public:
template<class CONFS>
ConfigSelector(CONFS const&, PAR factory_ctor_param)

View file

@ -61,6 +61,10 @@ namespace engine {
/**
* Fabricating a WiringDescriptor
* tailored for a specific node wiring situation.
*/
template<class CONF>
class WiringDescriptorFactory
{
@ -138,3 +142,4 @@ namespace engine {
} // namespace engine
/** preconfigured table of all possible factories */

View file

@ -230,7 +230,8 @@ namespace test {
struct TestVisitor
{
string result;
string result; ///< metafunction result
TestVisitor() : result ("TestVisitor application:\n") {}
/* === visitation interface === */
@ -319,7 +320,7 @@ namespace test {
catch (lumiera::error::Invalid& err)
{
cout << err.what() << "\n";
lumiera_error (); // reset errorflag
lumiera_error (); // reset error flag
}
}