"Jeff Flinn"
wrote in message news:000c01c29f84$ae37b0e0$ea02a8c0@adi.com... ----- Original Message ----- From: "Paul Mensonides"
"midnight2silverlake"
wrote in message news:asq7h1+r192@eGroups.com... I have what looks like a perfect application for Boost/Preprocessor. I have 192 entries in a Factory Map a portion of which are show below. I'd like to generate the permutations of the three macro inputs, but can't figure out where to start. Any help would be appreciated.
#define MAP_ENTRY_MCR( aLang, aType, aAcc ) \ \ mMap[ CKey( aLang, aType, aAcc ) ] \ = CVarX< aLang, aType, aAcc >::Make;
MAP_ENTRY_MCR( DCTlanguageC, DCT_DOUBLE , DCT_NONE ); MAP_ENTRY_MCR( DCTlanguageC, DCT_DOUBLE , DCT_INIT ); MAP_ENTRY_MCR( DCTlanguageC, DCT_DOUBLE , DCT_ANYTIME );
MAP_ENTRY_MCR( DCTlanguageC, DCT_FLOAT , DCT_NONE ); ...
Thanks, Jeff Flinn
Hi Jeff,
I want to make certain that I'm clear about what you're trying to do. You have 192 consecutive "MAP_ENTRY_MCR( ... )" with different permutions each time, right? How many different elements for each "field" do you have? (i.e. how many DCT_DOUBLE, DCT_FLOAT, etc. and how many DCT_NONE, DCT_INIT, etc.)
aLang(4) => DCTlanguageAda, DCTlanguageAdsim, DCTlanguageC , DCTlanguageFortran aType(8)=> DCT_DOUBLE, DCT_FLOAT , DCT_INT_16, DCT_INT_32, DCT_INT_8 , DCT_UINT_16, DCT_UINT_32, DCT_UINT_8 aAcc(3)=> DCT_INIT, DCT_ANYTIME, DCT_NONE
This accounts for 96 MAP_ENTRY_MCR's. There will actually be a 4th macro argument:
aDim(2)=> DCT_Vector, DCT_Scalar
Which accounts for the 192 entries.
Okay, so what we have here is a full-scale permutation of these four groups of values. It doesn't matter if they are sequential or not, because we'll deal with them by name rather than by value. (To address the topic of
thread, you _could_ use BOOST_PP_REPEAT, but only for three dimensions, and it wouldn't be a good idea for other reasons.)
Generally speaking, there are three good options. Only one of them is a good option if you plan to use an EDG front-end (such as Comeau or Intel) because the sheer size of such a cartesian product will take a while to generate.
option #1: lists --------------->
#include
#define A_LANG \ (DCTlanguageAda, (DCTlanguageAdsim, (DCTlanguageC, \ (DCTlanguageFortran, BOOST_PP_NIL)))) \ /**/
#define A_TYPE \ (DCT_DOUBLE, (DCT_FLOAT, (DCT_INT_16, (DCT_INT_32, \ (DCT_INT_8, (DCT_UINT_16, (DCT_UINT_32, \ (DCT_UINT_8, BOOST_PP_NIL)))))))) \ /**/
#define A_ACC \ (DCT_INIT, (DCT_ANYTIME, (DCT_NONE, BOOST_PP_NIL))) \ /**/
#define A_DIM (DCT_Vector, (DCT_Scalar, BOOST_PP_NIL))
#define PRODUCT(r, product) MAP_ENTRY_MCR product
#define MAP_ENTRY_MCR( aLang, aType, aAcc, aDim ) \ mMap[ CKey( aLang, aType, aAcc ) ] \ = CVarX< aLang, aType, aAcc >::Make; \ /* aDim? */
BOOST_PP_LIST_FOR_EACH_PRODUCT( PRODUCT, 4, ( A_LANG, A_TYPE, A_ACC, A_DIM ) )
#undef A_LANG #undef A_TYPE #undef A_ACC #undef A_DIM #undef PRODUCT #undef MAP_ENTRY_MCR
-------------------------
The second option requires the latest CVS sources of the PP Lib (i.e. post-1.29 release). It is a variant of the above, but with a preprocessor data type called a "sequence" that is a little simpler and more efficient that a "list."
option #2: sequences --------------->
#include
#include #define A_LANG \ (DCTlanguageAda)(DCTlanguageAdsim) \ (DCTlanguageC)(DCTlanguageFortran) \ /**/
#define A_TYPE \ (DCT_DOUBLE)(DCT_FLOAT)(DCT_INT_16)(DCT_INT_32) \ (DCT_INT_8)(DCT_UINT_16)(DCT_UINT_32)(DCT_UINT_8) \ /**/
#define A_ACC \ (DCT_INIT)(DCT_ANYTIME)(DCT_NONE) \ /**/
#define A_DIM \ (DCT_Vector)(DCT_Scalar) \ /**/
#define PRODUCT(r, seq) \ MAP_ENTRY_MCR( \ BOOST_PP_SEQ_ELEM(0, seq), BOOST_PP_SEQ_ELEM(1, seq), \ BOOST_PP_SEQ_ELEM(2, seq), BOOST_PP_SEQ_ELEM(3, seq) \ ) \ /**/
#define MAP_ENTRY_MCR( aLang, aType, aAcc, aDim ) \ mMap[ CKey( aLang, aType, aAcc ) ] \ = CVarX< aLang, aType, aAcc >::Make; \ /* aDim? */
BOOST_PP_SEQ_FOR_EACH_PRODUCT( PRODUCT, (A_LANG)(A_TYPE)(A_ACC)(A_DIM) )
#undef A_LANG #undef A_TYPE #undef A_ACC #undef A_DIM #undef PRODUCT #undef MAP_ENTRY_MCR
-------------------------
Both of the two options above use library primitives that are built for cartesian products such as this. However, they don't scale to this size well on slow preprocessors (e.g. EDG and maybe GCC). Luckily, we have a third alternative. However, this alternative is much more "invasive." It is a technique which I call "file iteration." In effect, it iterates over a file (or portion of a file) repeatedly with a different macro state each iteration. Furthermore, file iteration is supported up to five dimensions--we only have four here. I'll presume this stuff is in a
file called "map_entry_mcr.h". This psuedo-code roughly describes the implementation:
for (int i = 0; i < aLang.size(); ++i) { for (int j = 0; j < aType.size(); ++j) { for (int k = 0; k < aAcc.size(); ++k) { for (int l = 0; l < aDim.size(); ++l) { MAP_ENTRY_MCR(i, j, k, l); } } } }
option #3: file iteration --------------->
#if !BOOST_PP_IS_ITERATING
#ifndef MAP_ENTRY_MCR_H // normal include guard #define MAP_ENTRY_MCR_H
#include
#include #include // ----- normal file contents go here ----- //
#define A_LANG \ (4, (DCTlanguageAda, DCTlanguageAdsim, \ DCTlanguageC, DCTlanguageFortran))
#define A_TYPE \ (8, ( \ DCT_DOUBLE, DCT_FLOAT, DCT_INT_16, DCT_INT_32, \ DCT_INT_8, DCT_UINT_16, DCT_UINT_32, DCT_UINT_8 \ ))
#define A_ACC \ (3, (DCT_INIT, DCT_ANYTIME, DCT_NONE))
#define A_DIM \ (2, (DCT_Vector, DCT_Scalar))
#define ACCESS(array, frame) \ BOOST_PP_ARRAY_ELEM( \ BOOST_PP_FRAME_ITERATION(frame), \ array \ ) \ /**/
#define aLang ACCESS(A_LANG, 1) #define aType ACCESS(A_TYPE, 2) #define aAcc ACCESS(A_ACC, 3) #define aDim ACCESS(A_DIM, 4)
// iterate over elements in "A_LANG" #define BOOST_PP_ITERATION_PARAMS_1 \ (3, (0, BOOST_PP_ARRAY_SIZE(A_LANG) - 1, "map_entry_mcr.h")) #include BOOST_PP_ITERATE()
#undef A_LANG #undef A_TYPE #undef A_ACC #undef A_DIM #undef ACCESS
#undef aLang #undef aType #undef aAcc #undef aDim
// ----- other normal file contents go here ----- //
#endif // EOF
#elif BOOST_PP_ITERATION_DEPTH() == 1
// iterate over elements in "A_TYPE" #define BOOST_PP_ITERATION_PARAMS_2 \ (3, (0, BOOST_PP_ARRAY_SIZE(A_TYPE) - 1, "map_entry_mcr.h")) #include BOOST_PP_ITERATE()
#elif BOOST_PP_ITERATION_DEPTH() == 2
// iterate over elements in "A_ACC" #define BOOST_PP_ITERATION_PARAMS_3 \ (3, (0, BOOST_PP_ARRAY_SIZE(A_ACC) - 1, "map_entry_mcr.h")) #include BOOST_PP_ITERATE()
#elif BOOST_PP_ITERATION_DEPTH() == 3
// iterate over elements in "A_DIM" #define BOOST_PP_ITERATION_PARAMS_4 \ (3, (0, BOOST_PP_ARRAY_SIZE(A_DIM) - 1, "map_entry_mcr.h")) #include BOOST_PP_ITERATE()
#else
mMap[ CKey( aLang, aType, aAcc ) ] = CVarX< aLang, aType, aAcc >::Make;
? aDim
#endif
-------------------------
As you can see, this method is much more elaborate. The mechanism is primarily intended for repeating large swathes of code rather than cartesian products. Nevertheless, it works and is fairly fast--even on EDG. Make sure that you understand what is happening if you use this last example (maybe read the docs on file-iteration). Also, note that you can put all this iteration stuff in a separate file and merely include it where you want. The file iteration mechanism is a powerhouse, and this usage barely touches on its potential (which is partially why the implementation above is as obtuse as it is).
The strengths of option #1 and option #2 is the locality of code. Option #3 is a lot more involved. The weaknesses of option #1 and option #2 is that it is really slow on EDG preprocessors and that all the code gets expanded on a single line and is completely undebuggable. Option #3 excels in this area--though in this case, the debuggability aspect is negligible for such a small snippet of source code.
In any case, I urge you to read the documentation on each library
Paul,
Awesome! Thanks for the extensive description and all your efforts. It seems
like I run into this situation quite often. I'll be studying up on all of
these primitives.
Thanks again, Jeff
----- Original Message -----
From: "Paul Mensonides"
used and also the topic on file iteration. If you find anything unclear, then you can tell me, and I can improve the docs.
The DCT_ constants are a combination of enums and integer defines. aLang and aDim are enum entries, with sequential values starting with 1. aType and aAcc are integer defines. aType is non-sequential, aAcc is sequential starting with 1. It is possible for any of these to become non-sequential in
the future.
There are several ways to do this, so let me know if I'm clear on what you're doing, and I'll help you.
Paul Mensonides
Thanks for the help Paul
Jeff Flinn Applied Dynamics, International
Regards, Paul Mensonides
Info: http://www.boost.org Wiki: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl Unsubscribe: mailto:boost-users-unsubscribe@yahoogroups.com
Your use of Yahoo! Groups is subject to http://docs.yahoo.com/info/terms/