Cartesian Product with Boost.Preprocessor

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

Advertisements
Post a comment or leave a trackback: Trackback URL.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: