Today is another exciting day as I finished the Preprocessor macro version of the Cartesian Product issue, unlike the template version, whose incarnation is a template class. This version is a switch-case structure. Now that the infrastructure is ready, I’ll be able to concentrate on the concurrent studies again.
A great relief to several weeks of braining. and just in time for my holiday starting from tomorrow.
Code:
#ifndef CARTISIAN_PRODUCT_SWITCH_CASE_H
#define CARTISIAN_PRODUCT_SWITCH_CASE_H
#include <boost/preprocessor/seq/for_each_product.hpp>
#include <boost/preprocessor/seq/to_tuple.hpp>
/*
===========
Description:
===========
this macro construct a switch-case structrue by apply the Cartisian Product of
3-sequence to a clause that takes them as inputs.
i.e.
switch(NAME_OF_SWITCH_INDEX)
{
case ( COMPOSE_INDEX_FROM_SEQ): CLAUSE_FOR_EACH_CASE; break;
… …
case ( COMPOSE_INDEX_FROM_SEQ ): CLAUSE_FOR_EACH_CASE; break;
default: break;
}
for example:
Given 3 Sequences S1,S2,S3, if size(S1) =3, size(S1) =2, size(S1) =3, the following something like
the following would be yielded:
switch(idx)
{
case ( ((0 & 0xF)<<8)| ((0 & 0xF)<<4)| ((0 & 0xF)) ): details::scanT<(0, 0, 0)>(); break;
case ( ((0 & 0xF)<<8)| ((0 & 0xF)<<4)| ((1 & 0xF)) ): details::scanT<(0, 0, 1)>(); break;
case ( ((0 & 0xF)<<8)| ((0 & 0xF)<<4)| ((2 & 0xF)) ): details::scanT<(0, 0, 2)>(); break;
case ( ((0 & 0xF)<<8)| ((1 & 0xF)<<4)| ((0 & 0xF)) ): details::scanT<(0, 1, 0)>(); break;
case ( ((0 & 0xF)<<8)| ((1 & 0xF)<<4)| ((1 & 0xF)) ): details::scanT<(0, 1, 1)>(); break;
case ( ((0 & 0xF)<<8)| ((1 & 0xF)<<4)| ((2 & 0xF)) ): details::scanT<(0, 1, 2)>(); break;
default: break;
}
===========
How to Use:
===========
// 1/2 change the following defines and call GENERATE_SWITCH_STRUCTURE_FOR_CARTISIAN_PRODUCTS
#define SIZE_OF_SEQ1 2
#define SIZE_OF_SEQ2 5
#define SIZE_OF_SEQ3 5
#define NAME_OF_SWITCH_INDEX g_method
#define CLAUSE_FOR_EACH_CASE(ONE_BOOST_PP_SEQ_TYPE_INSTANCE) \
details::scanT<ONE_BOOST_PP_SEQ_TYPE_INSTANCE>()
#define CLAUSE_FOR_DEFAULT_LABLE std::wcout << L”this combination is not supported.”
// 2/2 run the macro
GENERATE_SWITCH_STRUCTURE_FOR_CARTISIAN_PRODUCTS
// ======== change this define if you prefer another algotithm ========
// define variable name for switch
#ifndef NAME_OF_SWITCH_INDEX
#define NAME_OF_SWITCH_INDEX idx
#endif
// define clause for case: label
#ifndef CLAUSE_FOR_EACH_CASE
#define CLAUSE_FOR_EACH_CASE(ONE_BOOST_PP_SEQ_TYPE_INSTANCE) ;
#endif
// define clause for default: label
#ifndef CLAUSE_FOR_DEFAULT_LABLE
#define CLAUSE_FOR_DEFAULT_LABLE
#endif
*/
// Compose a 12-bit integer from 3-nibbles, which is represented by a BOOST_PP_TUPLE
// i.e. (X, Y, Z) ==> ( ((X & 0xF)<<8)| ((Y & 0xF)<<4)| ((Z & 0xF)) )
#define EXTRACT_FOUR_BIT_NIBBLE(N) (N & 0xF)
#ifndef COMPOSE_INDEX_FROM_SEQ
#define COMPOSE_INDEX_FROM_SEQ(S) (\
(EXTRACT_FOUR_BIT_NIBBLE(BOOST_PP_SEQ_ELEM(0, S))<<8)|\
(EXTRACT_FOUR_BIT_NIBBLE(BOOST_PP_SEQ_ELEM(1, S))<<4)|\
(EXTRACT_FOUR_BIT_NIBBLE(BOOST_PP_SEQ_ELEM(2, S)))\
)
#endif
// ===== DO NOT CHANGE ANYTHING BELOW THIS LINE, UNLESS YOU KNOW WHAT YOU ARE DOING =====
// define all 3 parts of a switch-case block
#define BEGIN_SWITCH(METHOD_INDEX) switch(METHOD_INDEX) {
#define CASE(S) \
case COMPOSE_INDEX_FROM_SEQ(S): \
CLAUSE_FOR_EACH_CASE(BOOST_PP_SEQ_ENUM(S)); break;
#define END_SWITCH \
default: \
CLAUSE_FOR_DEFAULT_LABLE; }
// define 3 integer sequence represented by a BOOST_PP_SEQUENCE
// i.e. N ==> (0) (1) (2)… (N-1) (N)
#define DECL_SELF(z, n, text) (n)
#define S1 BOOST_PP_REPEAT(SIZE_OF_SEQ1, DECL_SELF, UNUSED)
#define S2 BOOST_PP_REPEAT(SIZE_OF_SEQ2, DECL_SELF, UNUSED)
#define S3 BOOST_PP_REPEAT(SIZE_OF_SEQ3, DECL_SELF, UNUSED)
// apply macro CASE to each Cartisian product of (S1)(S2)(S3)
#define APPLY_ONE(r, product) CASE(product)
// run the macros and release all tokens used here
// example oupput:
/*
switch(idx)
{
case ( ((0 & 0xF)<<8)| ((0 & 0xF)<<4)| ((0 & 0xF)) ): details::scanT<(0, 0, 0)>(); break;
case ( ((0 & 0xF)<<8)| ((0 & 0xF)<<4)| ((1 & 0xF)) ): details::scanT<(0, 0, 1)>(); break;
case ( ((0 & 0xF)<<8)| ((0 & 0xF)<<4)| ((2 & 0xF)) ): details::scanT<(0, 0, 2)>(); break;
case ( ((0 & 0xF)<<8)| ((1 & 0xF)<<4)| ((0 & 0xF)) ): details::scanT<(0, 1, 0)>(); break;
case ( ((0 & 0xF)<<8)| ((1 & 0xF)<<4)| ((1 & 0xF)) ): details::scanT<(0, 1, 1)>(); break;
case ( ((0 & 0xF)<<8)| ((1 & 0xF)<<4)| ((2 & 0xF)) ): details::scanT<(0, 1, 2)>(); break;
default: break;
}
*/
#define GENERATE_SWITCH_STRUCTURE_FOR_CARTISIAN_PRODUCTS \
BEGIN_SWITCH(NAME_OF_SWITCH_INDEX) \
BOOST_PP_SEQ_FOR_EACH_PRODUCT(APPLY_ONE, (S1)(S2)(S3)) \
END_SWITCH
/*
#undef COMPOSE_INDEX
#undef BEGIN_SWITCH
#undef CASE
#undef END_SWITCH
#undef APPLY_ONE
#undef DECL_SELF
#undef S1
#undef S2
#undef S3
#undef SIZE_OF_SEQ1
#undef SIZE_OF_SEQ2
#undef SIZE_OF_SEQ3
#undef NAME_OF_SWITCH_INDEX
#undef CLAUSE_FOR_EACH_CASE
*/
#endif