Some disgusting macro hackery!

207 views
Skip to first unread message

Bakul Shah

unread,
Jan 26, 2014, 9:05:50 PM1/26/14
to kona...@googlegroups.com
/* key idea from
http://cplusplus.co.il/2010/07/17/variadic-macro-to-count-number-of-arguments/
*/

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N

#define mkmacro(func, ...) mkmacro_(func, VA_NUM_ARGS(__VA_ARGS__))
#define mkmacro_(func, nargs) mkmacro__(func, nargs)
#define mkmacro__(func, nargs) func ## nargs

#define DO(...) mkmacro(DO, __VA_ARGS__)(__VA_ARGS__)
#define DO1(n) for(I i=0;i<(n); i++)
#define DO2(m,n) DO1(m) for(I j=0;j<(n);j++)
#define DO3(l,m,n) DO2(l,m) for(I k=0;k<(n);k++)


Now you can do

I a = 0, b = 0, c = 0;
DO(3) a+=i; // +/!3
DO(3,3) b+=i*3+j; // +//3 3#!9
DO(3,3,3) c+=i*9+j*3+k; // +//3 3 3#!27
O("%d %d %d\n", a, b, c);

This will print out "3 36 351"

Must be compiled with -std=c99 or later.

Quick explanation:

The cleverest bit is VA_NUM_ARGS_IMPL, which returns the
number of macro args (works upto 5 args but can be easily
extended). The rest is just routine macro hackery: mkmacro is
used to construct names such as <func><n>. So for example,
DO(n) maps to DO1(n) and DO(m,n) maps to DO2(m,n) and so
forth. C99 feature is used to reduce some ugliness so that
you can say

DO(n) {...}

instead of

DO(n,...)

[Obviously these are not equivalent to DO, DO2, DO3 in kona code]

Kevin Lawler

unread,
Jan 26, 2014, 10:52:03 PM1/26/14
to kona...@googlegroups.com
Nice
> --
> You received this message because you are subscribed to the Google Groups "Kona Developers" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to kona-dev+u...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Kevin Lawler

unread,
Jan 29, 2014, 6:32:52 PM1/29/14
to kona...@googlegroups.com
Alternate take. Bakul's macros except as "DO(3, a+=i)" instead of
"DO(3) a+=i;". One caveat: the macros so far in this thread iterate
closely over the indicated dimensions; they do not allow, for
instance, putting a DO2 mixed with other instructions inside of a DO1.

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N

#define mkmacro(func, ...) mkmacro_(func, VA_NUM_ARGS(__VA_ARGS__))
#define mkmacro_(func, nargs) mkmacro__(func, nargs)
#define mkmacro__(func, nargs) func ## nargs

#define DO(...) mkmacro(DO, __VA_ARGS__)(__VA_ARGS__)
#define DO1(n,x) {for(I i=0, _i=(n);i<_i;++i){x;}}
#define DO2(m,n,x) DO1(m,for(I j=0,_j=(n);j<_j;++j){x;})
#define DO3(l,m,n,x) DO2(l,m,for(I k=0,_k=(n);k<_k;k++){x;})

Kevin

Bakul Shah

unread,
Jan 29, 2014, 8:41:31 PM1/29/14
to kona...@googlegroups.com
On Wed, 29 Jan 2014 15:32:52 PST Kevin Lawler <kevin....@gmail.com> wrote:
> Alternate take. Bakul's macros except as "DO(3, a+=i)" instead of
> "DO(3) a+=i;".

Yes, that would fit in better with the existing code but macro
names will have to change to DO2,DO3,DO4.

> One caveat: the macros so far in this thread iterate
> closely over the indicated dimensions; they do not allow, for
> instance, putting a DO2 mixed with other instructions inside of a DO1.

One way to handle that is to make the index variable explicit.
Then one can choose diff index var for embedded DOs.

#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 7,6,5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,N,...) N

#define DO(...) mkmacro(DO, __VA_ARGS__)(__VA_ARGS__)
#define DO1(x) error
#define DO2(x,y) error
#define DO3(i,n,x) {for(I i=0, _i=(n);i<_i;++i){x;}}
#define DO4(x,y,z,w) error
#define DO5(i,j,m,n,x) DO1(m,for(I j=0,_j=(n);j<_j;++j){x;})
#define DO6(x,y,z,w,u,v) error
#define DO7(i,j,k,l,m,n,x) DO2(l,m,for(I k=0,_k=(n);k<_k;k++){x;})
Reply all
Reply to author
Forward
0 new messages