diff --git a/src/lib/meta/generator-combinations.hpp b/src/lib/meta/generator-combinations.hpp index a74eaea06..dae553182 100644 --- a/src/lib/meta/generator-combinations.hpp +++ b/src/lib/meta/generator-combinations.hpp @@ -25,7 +25,7 @@ ** 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 + ** and then mixed into the resulting type ** ** @see generator-combinations-test.cpp ** @see generator.hpp @@ -54,40 +54,35 @@ namespace typelist{ { }; - 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 + struct SingleCaseInstantiation + : _X_< Pick::Type + , Pick::Type , BASE > { }; }; + /** + * Build a Case matrix. + * The given parameter template _X_ + * will be instantiated for each possible combination + * of the elements from both parameter type-lists. + * All these instantiations will be chained up + * into a linear inheritance chain rooted + * at the BASE type. + * @note the custom-supplied template _X_ needs to take a 3rd parameter, + * and inherit from this parameter, in order to form that chain. + * Typically you'll define some (static) functions within that + * template, which then forward the call to the given BASE + * (and of course, that BASE then needs to define this + * function as well). + */ 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 @@ -95,7 +90,7 @@ namespace typelist{ > class InstantiateChainedCombinations : InstantiateChained< CartesianProduct::List - , PickParametersFromSublist<_X_>::template CaseInstantiation + , PickParametersFromSublist<_X_>::template SingleCaseInstantiation , BASE > { }; diff --git a/src/lib/meta/typelist-util.hpp b/src/lib/meta/typelist-util.hpp index 55fdd4395..428c23f97 100644 --- a/src/lib/meta/typelist-util.hpp +++ b/src/lib/meta/typelist-util.hpp @@ -97,6 +97,26 @@ namespace typelist{ }; + /** pick the n-th element from a typelist */ + template + struct Pick + { + typedef NullType Type; + }; + template + struct Pick, 0> + { + typedef TY Type; + }; + template + struct Pick, i> + { + typedef typename Pick::Type Type; + }; + + + + /** apply a transformation (template) to each type in the list */ template class _TRANS_> struct Apply { typedef TY List; }; diff --git a/src/lib/meta/util.hpp b/src/lib/meta/util.hpp index e6bb82209..97e60f1e1 100644 --- a/src/lib/meta/util.hpp +++ b/src/lib/meta/util.hpp @@ -38,6 +38,24 @@ namespace lumiera { namespace typelist { + /** Compile-time Type equality: + * Simple Trait template to pick up types considered + * \em identical by the compiler. + * @warning identical, not sub-type! + */ + template + class is_sameType + { + static const bool value = false; + }; + + template + class is_sameType + { + static const bool value = true; + }; + + /** 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/tests/40components.tests b/tests/40components.tests index 3405644a7..340203dbf 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -1104,6 +1104,11 @@ return: 0 END +TEST "Typelist combinations generator" GeneratorCombinations_test < + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +* *****************************************************/ + + +#include "lib/test/run.hpp" +#include "lib/meta/generator.hpp" +#include "lib/meta/generator-combinations.hpp" +#include "meta/typelist-diagnostics.hpp" + +#include +#include + +using ::test::Test; +using std::string; +using std::cout; +using std::endl; + + +namespace lumiera { +namespace typelist{ +namespace test { + + + namespace { // test cases and data.... + + typedef Types< Num<1> + , Num<3> + , Num<5> + > Types1; + typedef Types< Num<2> + , Num<4> + , Num<6> + > Types2; + + + using boost::str; + using boost::format; + format fmt ("-<%u%u>%s"); + + /** + * A Test-Template to be instantiated + * for all possible combinations + * of the {Types1} x {Types2} + */ + template + struct TestCase + { + static string + visitAll() + { + T1 param1; + T2 param2; + return str(fmt % param1 % param2 + % BASE::visitAll()); + } + }; + + struct TestCase + { + static string + visitAll() + { + return "-|"; + } + }; + typedef TestCase IterationEnd; + + } // (End) test data + + + + + + + /************************************************************************* + * @test check utilities for generating case combinations. + * - verify the Cartesian product is built properly + * - instantiate a two-parameter test template + * for all those cases, as given by the + * Cartesian product of two Type collections + */ + class GeneratorCombinations_test : public Test + { + virtual void + run (Arg) + { + checkCartesian(); + checkCaseInstantiation(); + } + + + void + checkCartesian () + { + typedef CartesianProduct Cartesian; + DISPLAY (Cartesian); + } + + + void + checkCaseInstantiation () + { + typedef InstantiateChainedCombinations< Types1,Types2 + , TestCase + , IterationEnd > CombnationCases; + + cout << "All-Test-Combinations-" << CombnationCases::visitAll() << endl; + } + + }; + + + /** Register this test class... */ + LAUNCHER (GeneratorCombinations_test, "unit common"); + + + +}}} // namespace lumiera::typelist::test diff --git a/tests/lib/meta/typelist-diagnostics.hpp b/tests/lib/meta/typelist-diagnostics.hpp index b26eb7ae7..10e64154a 100644 --- a/tests/lib/meta/typelist-diagnostics.hpp +++ b/tests/lib/meta/typelist-diagnostics.hpp @@ -200,10 +200,10 @@ namespace typelist{ #define DISPLAY(NAME) \ - cout << STRINGIFY(NAME) << "\t:" << showType() << "\n"; + cout << STRINGIFY(NAME) << "\t:" << showType() << endl; #define DUMPVAL(NAME) \ - cout << STRINGIFY(NAME) << "\t:" << showDump (NAME) << "\n"; + cout << STRINGIFY(NAME) << "\t:" << showDump (NAME) << endl; diff --git a/tests/lib/meta/typelist-manip-test.cpp b/tests/lib/meta/typelist-manip-test.cpp index 9bf43c429..3e34eab37 100644 --- a/tests/lib/meta/typelist-manip-test.cpp +++ b/tests/lib/meta/typelist-manip-test.cpp @@ -43,12 +43,11 @@ #include "lib/meta/typelist-util.hpp" #include "meta/typelist-diagnostics.hpp" -#include #include using ::test::Test; -using std::string; using std::cout; +using std::endl; namespace lumiera { @@ -96,6 +95,7 @@ namespace test { run (Arg) { check_diagnostics (); + check_pick_elm (); check_apply (); check_filter (); check_append (); @@ -113,7 +113,7 @@ namespace test { { // Explanation: the DISPLAY macro results in the following definition.... typedef InstantiateChained Contents_List1; - cout << "List1" << "\t:" << Contents_List1::print() << "\n"; + cout << "List1" << "\t:" << Contents_List1::print() << endl; // That is: we instantiate the "Printer" template for each of the types in List1, // forming an inheritance chain. I.e. the defined Type "Contents_List1" inherits @@ -124,6 +124,27 @@ namespace test { } + void + check_pick_elm () + { + Pick::Type e0; + Pick::Type e1; + Pick::Type e2; + + Pick::Type E3; + Pick::Type Nil; + Pick::Type Irrelevant; + + CHECK (5 == e0); + CHECK (6 == e1); + CHECK (7 == e2); + + CHECK (is_sameType::value); + CHECK (is_sameType::value); + CHECK (is_sameType::value); + } + + void check_append () {