diff --git a/src/common/meta/configflags.hpp b/src/common/meta/configflags.hpp index daf8917de..7ffb79a70 100644 --- a/src/common/meta/configflags.hpp +++ b/src/common/meta/configflags.hpp @@ -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 diff --git a/src/common/meta/util.hpp b/src/common/meta/util.hpp index 3c2d985f2..b01a412fa 100644 --- a/src/common/meta/util.hpp +++ b/src/common/meta/util.hpp @@ -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 diff --git a/src/common/variant.hpp b/src/common/variant.hpp index 48f813e19..751c2d9fc 100644 --- a/src/common/variant.hpp +++ b/src/common/variant.hpp @@ -41,6 +41,7 @@ #define LUMIERA_VARIANT_H +#include "common/meta/typelistutil.hpp" #include "common/meta/generator.hpp" #include diff --git a/src/proc/engine/nodeoperation.hpp b/src/proc/engine/nodeoperation.hpp index 40be62c35..b413c15bb 100644 --- a/src/proc/engine/nodeoperation.hpp +++ b/src/proc/engine/nodeoperation.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 - struct QueryCache : NEXT - { - BuffHandle - step (Invocation& ivo) - { - BuffHandle fetched = ivo.fetch ( - this->genFrameID (ivo)); - if (fetched) - return fetched; - else - return NEXT::step (ivo); - } - }; - - - template - 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 - 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 - 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 - 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 - 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 - 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 - 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 + struct QueryCache : NEXT + { + BuffHandle + step (Invocation& ivo) + { + BuffHandle fetched = ivo.fetch ( + this->genFrameID (ivo)); + if (fetched) + return fetched; + else + return NEXT::step (ivo); + } + }; + + + template + 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 + 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 + 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 + 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 + 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 + 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 + 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 + struct SelectBuffProvider; + + template<> struct SelectBuffProvider : AllocBufferFromCache { }; + template<> struct SelectBuffProvider : AllocBufferFromParent{ }; + template<> struct SelectBuffProvider : AllocBufferFromCache { }; + template<> struct SelectBuffProvider<> : AllocBufferFromParent{ }; + + template + struct Strategy ; - - template - struct SelectBuffProvider; - - template<> struct SelectBuffProvider : AllocBufferFromCache { }; - template<> struct SelectBuffProvider : AllocBufferFromParent{ }; - template<> struct SelectBuffProvider : AllocBufferFromCache { }; - template<> struct SelectBuffProvider<> : AllocBufferFromParent{ }; - - - template - struct Strategy ; - - using lumiera::typelist::Config; - - template - struct Strategy< Config > - : QueryCache< - AllocBufferTable< - PullInput< - AllocOutput< - ProcessData< - FeedCache< + using lumiera::typelist::Config; + + template + struct Strategy< Config > + : QueryCache< + AllocBufferTable< + PullInput< + AllocOutput< + ProcessData< + FeedCache< + ReleaseBuffers< + OperationBase > > > > > > > + { }; + + template + struct Strategy< Config > + : AllocBufferTable< + PullInput< + AllocOutput< + ProcessData< ReleaseBuffers< - OperationBase > > > > > > > - { }; - - template - struct Strategy< Config > - : 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 > : Strategy< Config<> > { }; - - template<> - struct Strategy< Config > - : AllocBufferTable< - ReadSource< - AllocOutput< - ProcessData< // wiring_.processFunction is supposed to do just buffer copying here - ReleaseBuffers< - OperationBase > > > > > - { }; - - - + OperationBase > > > + { }; + + template<> + struct Strategy< Config > : Strategy< Config<> > { }; + + template<> + struct Strategy< Config > + : AllocBufferTable< + ReadSource< + AllocOutput< + ProcessData< // wiring_.processFunction is supposed to do just buffer copying here + ReleaseBuffers< + OperationBase > > > > > + { }; + + + + + } // namespace config } // namespace engine #endif diff --git a/src/proc/engine/nodewiring.cpp b/src/proc/engine/nodewiring.cpp index a9cafa1a8..dfbe534f9 100644 --- a/src/proc/engine/nodewiring.cpp +++ b/src/proc/engine/nodewiring.cpp @@ -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::Tuple AllFlags; + + /** build the list of all possible flag combinations */ + typedef CombineFlags AllFlagCombinations; + + /** build a configuration type for each of those flag combinations */ + typedef Apply AllConfigs; + + /** filter those configurations which actually define a wiring strategy */ + typedef Filter::Test> PossibleConfigs; + + + class Alloc {}; ///////////////TODO + + + template + class WiringDescriptorFactory + { + Alloc& alloc_; + + public: + WiringDescriptorFactory(Alloc& a) + : alloc_(a) {} + + WiringDescriptor& + operator() () + { + /////////////////////////////////////////////TODO + //return offset_ + Maybe::CODE; + } + }; + + + typedef ConfigSelector 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::CODE); -// return selector(config); + size_t config = 13; /////////////////////////////////////////TODO +// return pImpl_->selector(config); } // BlockAlloc > > >::fabricate(); diff --git a/src/proc/engine/nodewiring.hpp b/src/proc/engine/nodewiring.hpp index d17b95396..2d1e587a4 100644 --- a/src/proc/engine/nodewiring.hpp +++ b/src/proc/engine/nodewiring.hpp @@ -27,6 +27,7 @@ #include "proc/engine/procnode.hpp" +#include #include @@ -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 pImpl_; + public: WiringDescriptor& operator() (uint nrOut, uint nrIn, bool cache); diff --git a/src/proc/engine/nodewiringconfig.hpp b/src/proc/engine/nodewiringconfig.hpp index fe1a24856..c6df0c0db 100644 --- a/src/proc/engine/nodewiringconfig.hpp +++ b/src/proc/engine/nodewiringconfig.hpp @@ -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 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 - struct FactoryHolder : FacFunctor - { - FAC factory_; - FactoryHolder(PAR p) : factory_(p) {} - - virtual RET invoke () { return factory_(); } - }; - - - typedef std::tr1::shared_ptr PFunc; - typedef std::map 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 - void - visit (size_t code) - { - PFunc pFactory (new FactoryHolder > (ctor_param_)); - factories_[code] = pFactory; - } - - void done() {} - }; - - public: - template - 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::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(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 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 + struct FactoryHolder : FacFunctor + { + FAC factory_; + FactoryHolder(PAR p) : factory_(p) {} + + virtual RET invoke () { return factory_(); } + }; + + + typedef std::tr1::shared_ptr PFunc; + typedef std::map 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 + void + visit (size_t code) + { + PFunc pFactory (new FactoryHolder > (ctor_param_)); + factories_[code] = pFactory; + } + + void done() {} + }; + + public: + template + 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::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(configFlags)); + } + }; + + + + } // namespace config } // namespace engine #endif diff --git a/tests/common/meta/configflagstest.cpp b/tests/common/meta/configflagstest.cpp index 63ac834d9..cf5660361 100644 --- a/tests/common/meta/configflagstest.cpp +++ b/tests/common/meta/configflagstest.cpp @@ -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 - struct Printer; - - template - struct Printer - : BASE - { - static string print () { return str( fmt % "·" % BASE::print()); } - }; - - template - struct Printer, BASE> - : BASE - { - static string print () { return str( fmt % uint(Fl) % BASE::print()); } - }; - - - - /** call the debug-print for a typelist - * utilizing the Printer template */ - template - string - printSublist () - { - typedef InstantiateChained SubList; - return SubList::print(); - } - - /** Spezialisation for debug-printing of a nested sublist */ - template - struct Printer, BASE> - : BASE - { - static string print () - { - typedef Node List; - return string("\n\t+--") + printSublist()+"+" - + BASE::print(); - } - }; - - template - struct Printer, BASE> - : BASE - { - static string print () - { - typedef typename Config::Flags FlagList; - return string("\n\t+-Conf-[") + printSublist()+"]" - + BASE::print(); - } - }; - - -#define DIAGNOSE(LIST) \ - typedef InstantiateChained 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::Test> Possible_Configs; DISPLAY (Possible_Configs); - typedef engine::ConfigSelector TestFactorySelector; + typedef engine::config::ConfigSelector TestFactorySelector; const long offset = 1000; // parameter fed to all TestFactory ctors TestFactorySelector testConfigSelector (Possible_Configs::List(), offset); diff --git a/tests/common/meta/typelistdiagnostics.hpp b/tests/common/meta/typelistdiagnostics.hpp new file mode 100644 index 000000000..bccc05ab2 --- /dev/null +++ b/tests/common/meta/typelistdiagnostics.hpp @@ -0,0 +1,140 @@ +/* + TYPELISTDIAGNOSTICS - helper for testing the typelist based utilities + + Copyright (C) Lumiera.org + 2008, 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 typelistdiagnostics.hpp + ** a Printer template usable for debugging the structure of a typelist built + ** upon some simple debugging-style types. Examples being a Num 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 + +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 + struct Printer; + + template + struct Printer + : BASE + { + static string print () { return str( fmt % "·" % BASE::print()); } + }; + + template + struct Printer, BASE> + : BASE + { + static string print () { return str( fmt % uint(Fl) % BASE::print()); } + }; + + + + /** call the debug-print for a typelist + * utilizing the Printer template */ + template + string + printSublist () + { + typedef InstantiateChained SubList; + return SubList::print(); + } + + /** Spezialisation for debug-printing of a nested sublist */ + template + struct Printer, BASE> + : BASE + { + static string print () + { + typedef Node List; + return string("\n\t+--") + printSublist()+"+" + + BASE::print(); + } + }; + + template + struct Printer, BASE> + : BASE + { + static string print () + { + typedef typename Config::Flags FlagList; + return string("\n\t+-Conf-[") + printSublist()+"]" + + BASE::print(); + } + }; + + +#define DIAGNOSE(LIST) \ + typedef InstantiateChained 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