diff --git a/src/lib/meta/generator-combinations.hpp b/src/lib/meta/generator-combinations.hpp new file mode 100644 index 000000000..a74eaea06 --- /dev/null +++ b/src/lib/meta/generator-combinations.hpp @@ -0,0 +1,106 @@ +/* + GENERATOR-COMBINATIONS.hpp - generate combinations and variations + + Copyright (C) Lumiera.org + 2011, 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 generator-combinations.hpp + ** Metaprogramming facilities to generate combination cases. + ** Similar to the plain typelist-based generators, a custom supplied + ** template will be instantiated with combinations of the parameter types + ** and then mixed into the resulting type + ** + ** @see generator-combinations-test.cpp + ** @see generator.hpp + ** + */ + + +#ifndef LUMIERA_META_GENERATOR_COMBINATIONS_H +#define LUMIERA_META_GENERATOR_COMBINATIONS_H + +#include "lib/meta/typelist.hpp" +#include "lib/meta/typelist-util.hpp" +#include "lib/meta/generator.hpp" + + + +namespace lumiera { +namespace typelist{ + + + template + class CartesianProduct + : Distribute< typename TYPES_1::List + , typename TYPES_2::List + > + { }; + + + template + struct PickFirst; + + template + struct PickFirst > + { + typedef TY Type; + }; + + + template + struct PickSecond; + + template + struct PickSecond > + { + typedef typename PickFirst::Type Type; + }; + + + + template< template class _X_> + struct PickParametersFromSublist + { + template + struct CaseInstantiation + : _X_< PickFirst::Type + , PickSecond::Type + , BASE + > + { }; + }; + + + template + < class TYPES_1, class TYPES_2 ///< the two type collections to pick combinations from + , template class _X_ ///< template with two arg types and a base type + , class BASE = NullType + > + class InstantiateChainedCombinations + : InstantiateChained< CartesianProduct::List + , PickParametersFromSublist<_X_>::template CaseInstantiation + , BASE + > + { }; + + + +}} // namespace lumiera::typelist +#endif diff --git a/src/lib/meta/typelist-util.hpp b/src/lib/meta/typelist-util.hpp index cf66a791a..55fdd4395 100644 --- a/src/lib/meta/typelist-util.hpp +++ b/src/lib/meta/typelist-util.hpp @@ -21,6 +21,34 @@ */ +/** @file typelist-util.hpp + ** Metaprogramming: Helpers for manipulating lists-of-types. + ** Sometimes, we use metaprogramming to generate a variation of concrete + ** implementations by combining some basic building blocks. Typically, there + ** is a number of similar, but not suitably related types involved. We want to + ** process those types using a common scheme, without being forced to squeeze + ** all those types into a artificial inheritance relationship. Now, generating + ** some kind of common factory or adapter, while mixing in pieces of code tailored + ** specifically to the individual types, allows still to build a common processing + ** in such situations. + ** + ** The facilities in this header provide the basics of simple functional list + ** processing (mostly with tail recursion). Usually, there is one template parameter + ** TYPES, which accepts a \em Type-list. The result of the processing step is then + ** accessible as an embedded typedef named \c List . Here, all of the 'processing' + ** to calculate this result is performed by the compiler, as a side-effect of + ** figuring out the resulting concrete type. At run time, in the generated + ** code, typically the resulting classes are empty, maybe just + ** exposing a specifically built-up function. + ** + ** @see generator.hpp + ** @see typelist-manip-test.cpp + ** @see TimeControl_test usage example + ** @see typelist.hpp + ** + */ + + #ifndef LUMIERA_META_TYPELIST_UTIL_H #define LUMIERA_META_TYPELIST_UTIL_H @@ -34,6 +62,7 @@ namespace typelist{ /** * Metafunction counting the number of Types in the collection + * @return an embedded constant \c value holding the result */ template struct count; @@ -80,6 +109,7 @@ namespace typelist{ > List; }; + /** conditional node: skip an element based on evaluating a predicate */ template struct CondNode { typedef TAIL Next; }; @@ -202,7 +232,7 @@ namespace typelist{ typedef T Head; ///< first element typedef Node First; ///< a list containing the first element typedef TYPES Tail; ///< remainder of the list starting with the second elm. - typedef typename SplitLast::List Prefix;///< all of the list, up to but extcluding the last element + typedef typename SplitLast::List Prefix;///< all of the list, up to but excluding the last element typedef typename SplitLast::Type End; ///< the last element typedef Node Last; ///< a list containing the last element }; @@ -245,6 +275,12 @@ namespace typelist{ + /** + * build a list-of lists, where each element of the first arg list + * gets in turn prepended to all elements of the second arg list. + * Can be used to build all possible combinations from two + * sources, i.e. the Cartesian product. + */ template struct Distribute { typedef typename PrefixAll::List List; }; @@ -261,24 +297,32 @@ namespace typelist{ - /** use a permutation generator - * for creating a list of all possible combinations + /** + * build all possible combinations, based on a enumeration of the basic cases. + * For each of the types in the argument list, an "enumeration generator" template is invoked, + * yielding a list of the possible base cases. These base cases are then combined with all the + * combinations of the rest, yielding all ordered combinations of all cases. Here, "ordered" + * means that the base cases of the n-th element will appear in the n-th position of the + * resulting lists, + * + * For the typical example, the "base cases" are {flag(on), flag(off)}, so we get a + * list-of-lists, featuring all possibilities to combine these distinct toggles. */ template< class X - , template class _PERMU_> - struct Combine { typedef typename Distribute< typename _PERMU_::List + , template class _ENUM_> + struct Combine { typedef typename Distribute< typename _ENUM_::List , Node >::List List; }; - template< template class _PERMU_> - struct Combine { typedef Node List; }; + template< template class _ENUM_> + struct Combine { typedef NodeNull List; }; template< class TY, class TYPES - , template class _PERMU_> - struct Combine,_PERMU_> { typedef typename Distribute< typename _PERMU_::List - , typename Combine::List + , template class _ENUM_> + struct Combine,_ENUM_> { typedef typename Distribute< typename _ENUM_::List + , typename Combine::List >::List List; }; - /** permutation generator for the Combine metafunction, + /** enumeration generator for the Combine metafunction, * yielding an "on" and "off" case */ template diff --git a/tests/40components.tests b/tests/40components.tests index aff1800f8..3405644a7 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -806,7 +806,7 @@ return: 0 END -TEST "typelist manipulation" TypeListManipl_test <-<2>-<3>- out: List2 :-<5>-<6>-<7>- out: Added2 :-<3>-<4>-<5>- diff --git a/tests/lib/meta/typelist-diagnostics.hpp b/tests/lib/meta/typelist-diagnostics.hpp index bd924b1d8..b26eb7ae7 100644 --- a/tests/lib/meta/typelist-diagnostics.hpp +++ b/tests/lib/meta/typelist-diagnostics.hpp @@ -25,13 +25,15 @@ ** 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 returning a string visualising the structure - ** of the typelist provided as parameter to the Printer template. - ** + ** a static \c print() function. The string returned from this function + ** visualises the structure of the typelist provided as parameter + ** to the Printer template. + ** ** @see typelist-manip-test.cpp ** @see config-flags-test.cpp ** */ + #ifndef META_TYPELIST_DIAGNOSTICS_H #define META_TYPELIST_DIAGNOSTICS_H diff --git a/tests/lib/meta/typelist-manip-test.cpp b/tests/lib/meta/typelist-manip-test.cpp index ce51270a5..9bf43c429 100644 --- a/tests/lib/meta/typelist-manip-test.cpp +++ b/tests/lib/meta/typelist-manip-test.cpp @@ -90,7 +90,7 @@ namespace test { * using a "predicate template" (metafunction) * - building combinations and permutations */ - class TypeListManipl_test : public Test + class TypeListManip_test : public Test { virtual void run (Arg) @@ -352,7 +352,7 @@ namespace test { /** Register this test class... */ - LAUNCHER (TypeListManipl_test, "unit common"); + LAUNCHER (TypeListManip_test, "unit common"); diff --git a/tests/lib/time/time-control-test.cpp b/tests/lib/time/time-control-test.cpp index 2742831ce..b233ef114 100644 --- a/tests/lib/time/time-control-test.cpp +++ b/tests/lib/time/time-control-test.cpp @@ -27,6 +27,7 @@ #include "lib/time/timequant.hpp" #include "lib/time/mutation.hpp" #include "proc/asset/meta/time-grid.hpp" +#include "lib/meta/typelist.hpp" #include "lib/util.hpp" #include @@ -45,6 +46,8 @@ namespace time{ namespace test{ using asset::meta::TimeGrid; + using lumiera::typelist::Types; + using lumiera::typelist::InstantiateForEach; namespace { inline string @@ -112,7 +115,7 @@ namespace test{ FrameNr count(qChange); verifyBasics(); - runningMutations(); + verifyMatrix_of_MutationCases(); } @@ -121,10 +124,24 @@ namespace test{ { } + template + struct TestCase4Target + { + void + performTestCases() + { + + } + }; + void - runningMutations () + verifyMatrix_of_MutationCases () { + typedef Types KindsOfTarget; + typedef InstantiateForEach TestMatrix; + + TestMatrix().performTestCases(); } }; diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 1a36e067e..83ca6e30c 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -6782,7 +6782,7 @@ Thus no server and no network connection is needed. Simply open the file in your * see [[Homepage|http://tiddlywiki.com]], [[Wiki-Markup|http://tiddlywiki.org/wiki/TiddlyWiki_Markup]] -
+
Simple time points are just like values and thus easy to change. The difficulties arise when time values are to be //quantised to an existing time grid.// The first relevant point to note is that for quantised time values, the effect of a change can be disproportional to the cause. Small changes below the threshold might be accumulated, and a tiny change might trigger a jump to the next grid point. While this might be annoying, the yet more complex questions arise when we acknowledge that the amount of the change itself might be related to a time grid.
 
 The problem with modification of quantised values highlights an inner contradiction or conflicting goals within the design
@@ -6866,7 +6866,7 @@ The special focus of this problem seems to lead itself to a __visitor pattern__
 Thus the possibly mutalble time entities get an {{{accept(time::Mutation&)}}} function, which is defined to reflect back into the (virtual) visitation functions of the Mutation Interface. Additionally, we provide some static convenience shortcuts right in the Mutation interface, performing the trivial mutations.
 
 !!!life value changes and monitoring
-Based on this time::Mutation design, we provide a specialised element for dealing with //running time values:// When attached to a target time entity, a "life" connection is established. From then on, continuous changes and mutations can be fed to the target by invoking a functor interface. Besides, a change notification signal (callback) can be installed, which will be invoked on each change. This element is the foundation for implementing all kinds of running time display widgets, spin buttons, timeline selections, playheads, loop playback and similar.
+Based on this time::Mutation design, we provide a specialised element for dealing with //running time values:// When attached to a target time entity, a "life" connection is established. From then on, continuous changes and mutations can be fed to the target by invoking a functor interface. Besides, a change notification signal (callback) can be installed, which will be invoked on each change. This {{{time::Control}}} element is the foundation for implementing all kinds of running time display widgets, spin buttons, timeline selections, playheads, loop playback and similar.