summaryrefslogtreecommitdiffstats
path: root/04_exercise/ppmlib.h
blob: 7a7f3db4dbf469156d55c94b13e1b89f54ff0893 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
/***************************************************************************//**
 * @file ppmlib.h
 * @author Dorian Weber
 * @brief Contains a small macro library used for preprocessor programming.
 * 
 * @details
 * Preprocessor metaprogramming is very valuable in larger C projects. It's
 * efficient and can manipulate code at a very basic level. This small library
 * is intended to facilitate macro programming by collecting commonly used
 * macro functions. It supports argument lists with a size of up to 32.
 ******************************************************************************/

#ifndef PPMLIB_H_INCLUDED
#define PPMLIB_H_INCLUDED

#include <stddef.h>

/**@brief Tests if the integer type of a variable is signed.
 * @attention Due to the integer promotion rules in C, this will only work for
 * variables of type \c int and upwards, not for char and short.
 * @note Credit goes to Jens Gustedt for this typeless type cast for integer.
 */
#define IS_SIGNED(VAR) \
	((1 ? -1 : VAR) < 0)

/**@brief Number of bits in inttype_MAX, or in any (1<<k)-1 where 0 <= k < 2040.
 * @note Credit goes to Hallvard B. Furuseth for inventing this gem.
 * 
 * Use it like:
 * @code
 * 	printf("%u", PRECISION(-1u)); // prints 32 if `unsigned int` uses 32-bits
 * @endcode
 */
#define PRECISION(MAX) \
	((MAX)/((MAX)%255 + 1)/255%255*8 + 7 - 86/((MAX)%255 + 12))

/**@brief Calculates the number of elements in a static array of arbitrary type.
 */
#define ACOUNT(ARRAY) \
	(sizeof(ARRAY)/sizeof(ARRAY[0]))

/**@brief Analyses the number of arguments passed to a variadic macro.
 * 
 * This includes the possibility that the first and only argument is empty,
 * which returns 0.
 * 
 * @param ...  variadic list of arguments
 * @sa NUM_PARGS
 */
#define NUM_ARGS(...)  \
	IF_EMPTY(__VA_ARGS__)(0)(NUM_PARGS(__VA_ARGS__))

/**@brief Analyses the number of arguments passed to a variadic macro.
 * 
 * The only difference between this macro and NUM_ARGS is the result if the
 * first and only argument is empty. This macro will return 1 in this case,
 * since the empty string is a valid preprocessor argument. If you can ensure
 * or don't care if the first argument is empty, this macro is faster to
 * compute than the NUM_ARGS equivalent.
 * 
 * @param ...  variadic list of arguments
 * @sa NUM_ARGS
 */
#define NUM_PARGS(...) \
	NUM_ARGS_(__VA_ARGS__,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17, \
	          16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1,~)

/**@brief Returns if the variadic list of arguments contains a comma. 
 * 
 * A variadic list contains a comma iff it contains at least two arguments.
 * 
 * @param ...  variadic list of arguments
 * @return 1 if the list contains a comma, \n
 *         0 otherwise
 */
#define HAS_COMMA(...) \
	NUM_ARGS_(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \
	           1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,~)

/**@brief Applies a macro transformation on each of the macro arguments.
 * @note Using this macro directly is kind of complicated. If you just want to
 * apply a simple macro to each of the arguments, using TRAFO is easier.
 * 
 * @param OUTER  unary macro function that is applied to each argument, except
 *               for the last one, and after the INNER macro has been applied
 * @param INNER  unary macro function that is applied to each argument,
 *               including the last one, and before the OUTER macro is applied
 * @param LIST   the macro arguments, wrapped into parenthesis
 * @sa MAP, FOREACHP
 */
#define FOREACH(OUTER, INNER, LIST) \
	FOREACH_(OUTER, NUM_ARGS LIST, INNER, LIST)

/**@brief Applies a macro transformation on each of the macro arguments and
 * takes an additional static argument.
 * 
 * It works exactly like the FOREACH-macro but allows passing an addition data
 * argument.
 * @sa FOLD, FOREACH
 */
#define FOREACHP(OUTER, INNER, PARAM, LIST) \
	FOREACHP_(OUTER, NUM_ARGS LIST, INNER, PARAM, LIST)

/**@brief Returns whether the variadic list of macro arguments only contains
 * the empty parameter or not.
 * 
 * @param ...  variadic argument list
 * @return 1 if there is only one argument and it is empty,\n
 *         0 otherwise
 */
#define IS_EMPTY(...) _IS_EMPTY(                                        \
	/* test if there is just one argument, possibly an empty one */     \
	HAS_COMMA(__VA_ARGS__),                                             \
	/* test if _IS_EMPTY_FN together with the argument adds a comma */  \
	HAS_COMMA(_IS_EMPTY_FN __VA_ARGS__),                                \
	/* test if the argument together with a parenthesis adds a comma */ \
	HAS_COMMA(__VA_ARGS__ (/*empty*/)),                                 \
	/* test if placing it between _IS_EMPTY_FN and the parenthesis      \
	 * adds a comma */                                                  \
	HAS_COMMA(_IS_EMPTY_FN __VA_ARGS__ (/*empty*/))                     \
)

/**@name Expansion specifier
 * Contains unary macros that perform common transformations on a macro
 * argument.
 * @{
 */

/**@brief Simply expands the macro arguments.
 * 
 * Use it to unpack argument lists like:
 * @code
 * 	#define ARGS (1, 2, 3, 4, 5)
 * 	CALL_VAR_FN(EXPAND ARGS); // expands to CALL_VAR_FN(1, 2, 3, 4, 5)
 * @endcode
 */
#define EXPAND(...) \
	__VA_ARGS__

/**@brief Prevents a function-like macro from expanding immediately.
 * 
 * Use it to prevent macros from expanding immediately:
 * @code
 * 	#define FOO() foo
 * 	DEFER(FOO)()         // DEFER(FOO)() -> FOO()
 * 	EXPAND(DEFER(FOO)()) // EXPAND(DEFER(FOO)()) -> EXPAND(FOO()) -> foo
 * @endcode
 */
#define DEFER(...) \
	__VA_ARGS__ FORGET()

/**@brief Expands the macro arguments and adds a comma to them.
 */
#define EXPAND_W_COMMA(...) \
	__VA_ARGS__,

/**@brief Expands two macro arguments as a pair.
 */
#define EXPAND_AS_PAIR(E1, E2) \
	(E1, E2)

/**@brief Replaces the macro arguments with the empty argument.
 */
#define FORGET(...)

/**@brief Stringifies the arguments.
 */
#define STR(...) \
	STR_(__VA_ARGS__)

/**@brief Generates a unique name using the current line in the code.
 * This is useful for variable names in macro-expansions.
 */
#define UID(VAR) \
	CONCAT(VAR, _, __LINE__)

/**@}*/

/**@brief Constructs a comma separated list that can be transformed using a 
 * unary macro.
 * 
 * @param M    the unary macro function that is applied for each argument
 * @param ...  variadic argument list
 */
#define VECM(M,...) \
	FOREACH(EXPAND_W_COMMA, M, (__VA_ARGS__))

/**@brief Construct a comma separated list that can be transformed using a
 * unary macro and takes an additional static argument.
 * 
 * This macro behaves exactly like VECM but allows for an additional argument.
 */
#define VECMP(M,P, ...) \
	FOREACHP(EXPAND_W_COMMA, M, P, (__VA_ARGS__))

/**@brief Applies the unary macro to each element of a variadic argument list.
 * 
 * This is the less powerful version of the FOREACH macro. It simply applies a
 * unary macro to each of its arguments.
 * 
 * @param M    the macro function to apply
 * @param ...  variadic argument list 
 * @sa FOLD, FOREACH
 */
#define MAP(M, ...) \
	FOREACH(EXPAND, M, (__VA_ARGS__))

/**@brief Applies a binary macro for each element of a variadic argument list.
 * 
 * The macro receives both a static argument as well as the current element.
 * The static argument is given as the \p P parameter during invokation.
 * @sa MAP, FOREACHP
 */
#define FOLD(M,P, ...) \
	FOREACHP(EXPAND, M, P, (__VA_ARGS__))

/**@brief Splices together two variadic sequences into a sequence of pairs.
 * 
 * The number of elements in the combined sequence is always equal to the
 * number of elements in the first sequence. If the first sequence contains
 * more elements, the final sequence's tail has empty second arguments.
 * @sa ZIP_MAP
*/
#define ZIP(SEQ_A, SEQ_B) \
	ZIP_MAP(EXPAND_AS_PAIR, SEQ_A, SEQ_B)

/**@brief Splices together two variadic sequences using a binary macro.
 * 
 * Like the ZIP-macro, the number of combined elements is always equal to the
 * number of elements in the first sequence. This operator is slightly more
 * generic since it allows arbitrary operations on every pair of elements
 * through the binary macro.
 * @sa ZIP
 */
#define ZIP_MAP(M, SEQ_A, SEQ_B) \
	CONCAT(ZIP_, NUM_ARGS SEQ_A)(M, SEQ_A, SEQ_B)

/**@brief Selects an argument from a variadic list.
 * 
 * This macro function can be used to index into a variadic argument list. It
 * is possible to select a higher index than the list is long. In this case the
 * result is the empty argument.
 * 
 * @param N    index of the argument to select
 * @param ...  variadic argument list
 */
#define ARG(N, ...) \
	CONCAT_2(ARG_,N)(__VA_ARGS__,)

/**@brief Selects and returns the first argument from a variadic list.
 */
#define ARG_FIRST(...) \
	ARG_1_(__VA_ARGS__,)

/**@brief Selects and returns the last argument from a variadic list.
 */
#define ARG_LAST(...) \
	ARG(NUM_PARGS(__VA_ARGS__),__VA_ARGS__)

/**@brief Selects the remainder of an argument list after removing the first.
 */
#define ARG_REST(...) \
	IF_COMMA(__VA_ARGS__)(ARG_REST_(__VA_ARGS__))()

/**@brief Selects every argument except for the last of a variadic list.
 */
#define ARG_CHOP(...) \
	FOREACH_(EXPAND_W_COMMA, NUM_ARGS(ARG_REST(__VA_ARGS__)), EXPAND, (__VA_ARGS__))

/**@brief Concatenates a variable number of arguments.
 * 
 * Since it is not specified by the C standard: concatenation occurs from left
 * to right with left associativity. To give an example `CONCAT(a,b,c)` would
 * be treated as `(a ## b) ## c`.
 * 
 * @param ...  variadic list of valid preprocessor tokens
 */
#define CONCAT(...) \
	CONCAT_(NUM_PARGS(__VA_ARGS__), __VA_ARGS__)

/**@name Inline conditionals
 * Macros that support the conditional generation of text.
 * @{
 */

/**@brief Tests if two numbers are equal and generates code according to the
 * result.
 * 
 * The numbers are expanded first. The syntax for this tool is like
 * @code
 * IF_EQ(a,b)(<true>)(<false>)
 * @endcode
 * The code in the first branch is generated if `a` equals `b`, the code in the
 * second branch otherwise.
 * 
 * @param A  first number
 * @param B  second number
 */
#define IF_EQ(A, B) \
	_IF_CLAUSE(CONCAT_4(_IS_,A,_EQ_,B)())

/**@brief Tests if the number of arguments is equal to a number and generates
 * code according to the result.
 * 
 * The numbers are expanded first. The syntax for this tool is like
 * @code
 * IF_LEN(a,__VA_ARGS__)(<true>)(<false>)
 * @endcode
 * The code in the first branch is generated if `a` equals the length of
 * `__VA_ARGS__`, the code in the second branch otherwise.
 * 
 * @param A    first number
 * @param ...  argument list
 */
#define IF_LEN(A, ...) \
	_IF_CLAUSE(CONCAT_4(_IS_,A,_EQ_,NUM_ARGS(__VA_ARGS__)()))

/**@brief Tests if the argument list passed is empty and generates code
 * according to the result.
 * 
 * The argument list is empty iff it only contains one argument that is the
 * empty token. Use this function like this:
 * @code
 * IF_EMPTY(<arglist>)(<empty>)(<not empty>)
 * @endcode
 * The branch labeled with `<empty>` gets generated if the passed `<arglist>`
 * is indeed empty, the other branch if it isn't.
 * 
 * @param ...  variadic argument list
 * @sa IS_EMPTY
 */
#define IF_EMPTY(...) \
	IF_EQ(1, IS_EMPTY(__VA_ARGS__))

/**@brief Tests if the argument list contains a comma and generates code
 * according to the result.
 * 
 * If the argument list contains a comma, it must contain at least two
 * arguments. Use this tool like:
 * @code
 * IF_COMMA(<arglist>)(<comma>)(<no comma>)
 * @endcode
 * The result is the branch labeled with `<comma>` if the `<arglist>`
 * contains at least two arguments, otherwise the contents of the other branch
 * are produced.
 * 
 * @param ...  variadic argument list
 * @sa HAS_COMMA
 */
#define IF_COMMA(...) \
	IF_EQ(1, HAS_COMMA(__VA_ARGS__))

/**@}*/

/**@cond Internal */
#define NUM_ARGS_(_20,_1F,_1E,_1D,_1C,_1B,_1A,_19,_18,_17,_16,_15,_14,_13,_12,_11, \
                  _10, _F, _E, _D, _C, _B, _A, _9, _8, _7, _6, _5, _4, _3, _2, _1, N,...) N

#define FOREACH_(E,N,M, LIST)     FOREACH__(E,N,M,LIST)
#define FOREACH__(E,N,M, LIST)    FOREACH_N##N(E,M,LIST)

#define FOREACHP_(E,N,M,P, LIST)  FOREACHP__(E,N,M,P,LIST)
#define FOREACHP__(E,N,M,P, LIST) FOREACH_P##N(E,M,P,LIST)

#define FOREACH_P0(E,M,P, LIST)  /* empty */
#define FOREACH_P1(E,M,P, LIST)  M(P,ARG_1 LIST)
#define FOREACH_P2(E,M,P, LIST)  E(M(P,ARG_1 LIST)) FOREACH_P1(E,M,P, (ARG_REST LIST))
#define FOREACH_P3(E,M,P, LIST)  E(M(P,ARG_1 LIST)) FOREACH_P2(E,M,P, (ARG_REST LIST))
#define FOREACH_P4(E,M,P, LIST)  E(M(P,ARG_1 LIST)) FOREACH_P3(E,M,P, (ARG_REST LIST))
#define FOREACH_P5(E,M,P, LIST)  E(M(P,ARG_1 LIST)) FOREACH_P4(E,M,P, (ARG_REST LIST))
#define FOREACH_P6(E,M,P, LIST)  E(M(P,ARG_1 LIST)) FOREACH_P5(E,M,P, (ARG_REST LIST))
#define FOREACH_P7(E,M,P, LIST)  E(M(P,ARG_1 LIST)) FOREACH_P6(E,M,P, (ARG_REST LIST))
#define FOREACH_P8(E,M,P, LIST)  E(M(P,ARG_1 LIST)) FOREACH_P7(E,M,P, (ARG_REST LIST))
#define FOREACH_P9(E,M,P, LIST)  E(M(P,ARG_1 LIST)) FOREACH_P8(E,M,P, (ARG_REST LIST))
#define FOREACH_P10(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P9(E,M,P, (ARG_REST LIST))
#define FOREACH_P11(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P10(E,M,P, (ARG_REST LIST))
#define FOREACH_P12(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P11(E,M,P, (ARG_REST LIST))
#define FOREACH_P13(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P12(E,M,P, (ARG_REST LIST))
#define FOREACH_P14(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P13(E,M,P, (ARG_REST LIST))
#define FOREACH_P15(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P14(E,M,P, (ARG_REST LIST))
#define FOREACH_P16(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P15(E,M,P, (ARG_REST LIST))
#define FOREACH_P17(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P16(E,M,P, (ARG_REST LIST))
#define FOREACH_P18(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P17(E,M,P, (ARG_REST LIST))
#define FOREACH_P19(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P18(E,M,P, (ARG_REST LIST))
#define FOREACH_P20(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P19(E,M,P, (ARG_REST LIST))
#define FOREACH_P21(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P20(E,M,P, (ARG_REST LIST))
#define FOREACH_P22(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P21(E,M,P, (ARG_REST LIST))
#define FOREACH_P23(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P22(E,M,P, (ARG_REST LIST))
#define FOREACH_P24(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P23(E,M,P, (ARG_REST LIST))
#define FOREACH_P25(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P24(E,M,P, (ARG_REST LIST))
#define FOREACH_P26(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P25(E,M,P, (ARG_REST LIST))
#define FOREACH_P27(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P26(E,M,P, (ARG_REST LIST))
#define FOREACH_P28(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P27(E,M,P, (ARG_REST LIST))
#define FOREACH_P29(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P28(E,M,P, (ARG_REST LIST))
#define FOREACH_P30(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P29(E,M,P, (ARG_REST LIST))
#define FOREACH_P31(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P30(E,M,P, (ARG_REST LIST))
#define FOREACH_P32(E,M,P, LIST) E(M(P,ARG_1 LIST)) FOREACH_P31(E,M,P, (ARG_REST LIST))

#define FOREACH_N0(E,M, LIST)  /* empty */
#define FOREACH_N1(E,M, LIST)  M(ARG_1 LIST)
#define FOREACH_N2(E,M, LIST)  E(M(ARG_1 LIST)) FOREACH_N1(E,M, (ARG_REST LIST))
#define FOREACH_N3(E,M, LIST)  E(M(ARG_1 LIST)) FOREACH_N2(E,M, (ARG_REST LIST))
#define FOREACH_N4(E,M, LIST)  E(M(ARG_1 LIST)) FOREACH_N3(E,M, (ARG_REST LIST))
#define FOREACH_N5(E,M, LIST)  E(M(ARG_1 LIST)) FOREACH_N4(E,M, (ARG_REST LIST))
#define FOREACH_N6(E,M, LIST)  E(M(ARG_1 LIST)) FOREACH_N5(E,M, (ARG_REST LIST))
#define FOREACH_N7(E,M, LIST)  E(M(ARG_1 LIST)) FOREACH_N6(E,M, (ARG_REST LIST))
#define FOREACH_N8(E,M, LIST)  E(M(ARG_1 LIST)) FOREACH_N7(E,M, (ARG_REST LIST))
#define FOREACH_N9(E,M, LIST)  E(M(ARG_1 LIST)) FOREACH_N8(E,M, (ARG_REST LIST))
#define FOREACH_N10(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N9(E,M, (ARG_REST LIST))
#define FOREACH_N11(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N10(E,M, (ARG_REST LIST))
#define FOREACH_N12(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N11(E,M, (ARG_REST LIST))
#define FOREACH_N13(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N12(E,M, (ARG_REST LIST))
#define FOREACH_N14(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N13(E,M, (ARG_REST LIST))
#define FOREACH_N15(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N14(E,M, (ARG_REST LIST))
#define FOREACH_N16(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N15(E,M, (ARG_REST LIST))
#define FOREACH_N17(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N16(E,M, (ARG_REST LIST))
#define FOREACH_N18(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N17(E,M, (ARG_REST LIST))
#define FOREACH_N19(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N18(E,M, (ARG_REST LIST))
#define FOREACH_N20(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N19(E,M, (ARG_REST LIST))
#define FOREACH_N21(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N20(E,M, (ARG_REST LIST))
#define FOREACH_N22(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N21(E,M, (ARG_REST LIST))
#define FOREACH_N23(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N22(E,M, (ARG_REST LIST))
#define FOREACH_N24(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N23(E,M, (ARG_REST LIST))
#define FOREACH_N25(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N24(E,M, (ARG_REST LIST))
#define FOREACH_N26(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N25(E,M, (ARG_REST LIST))
#define FOREACH_N27(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N26(E,M, (ARG_REST LIST))
#define FOREACH_N28(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N27(E,M, (ARG_REST LIST))
#define FOREACH_N29(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N28(E,M, (ARG_REST LIST))
#define FOREACH_N30(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N29(E,M, (ARG_REST LIST))
#define FOREACH_N31(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N30(E,M, (ARG_REST LIST))
#define FOREACH_N32(E,M, LIST) E(M(ARG_1 LIST)) FOREACH_N31(E,M, (ARG_REST LIST))

#define ZIP_0(M, SEQ_A, SEQ_B) /* empty */
#define ZIP_1(M, SEQ_A, SEQ_B)  M(ARG_1 SEQ_A, ARG_1 SEQ_B)
#define ZIP_2(M, SEQ_A, SEQ_B)  M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_1(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_3(M, SEQ_A, SEQ_B)  M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_2(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_4(M, SEQ_A, SEQ_B)  M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_3(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_5(M, SEQ_A, SEQ_B)  M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_4(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_6(M, SEQ_A, SEQ_B)  M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_5(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_7(M, SEQ_A, SEQ_B)  M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_6(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_8(M, SEQ_A, SEQ_B)  M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_7(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_9(M, SEQ_A, SEQ_B)  M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_8(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_10(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_9(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_11(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_10(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_12(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_11(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_13(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_12(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_14(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_13(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_15(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_14(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_16(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_15(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_17(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_16(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_18(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_17(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_19(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_18(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_20(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_19(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_21(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_20(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_22(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_21(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_23(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_22(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_24(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_23(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_25(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_24(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_26(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_25(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_27(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_26(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_28(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_27(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_29(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_28(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_30(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_29(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_31(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_30(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))
#define ZIP_32(M, SEQ_A, SEQ_B) M(ARG_1 SEQ_A, ARG_1 SEQ_B), ZIP_31(M, (ARG_REST SEQ_A), (ARG_REST SEQ_B))

#define CONCAT_(C, ...)   CONCAT__(C,__VA_ARGS__)
#define CONCAT__(C, ...)  CONCAT_ ## C(__VA_ARGS__)

#define CONCAT_1(_1)           _1
#define CONCAT_2(_1,_2)        _1 ## _2
#define CONCAT_3(_1,_2,...)    CONCAT_2(_1 ## _2, __VA_ARGS__)
#define CONCAT_4(_1,_2,...)    CONCAT_3(_1 ## _2, __VA_ARGS__)
#define CONCAT_5(_1,_2,...)    CONCAT_4(_1 ## _2, __VA_ARGS__)
#define CONCAT_6(_1,_2,...)    CONCAT_5(_1 ## _2, __VA_ARGS__)
#define CONCAT_7(_1,_2,...)    CONCAT_6(_1 ## _2, __VA_ARGS__)
#define CONCAT_8(_1,_2,...)    CONCAT_7(_1 ## _2, __VA_ARGS__)
#define CONCAT_9(_1,_2,...)    CONCAT_8(_1 ## _2, __VA_ARGS__)
#define CONCAT_10(_1,_2,...)   CONCAT_9(_1 ## _2, __VA_ARGS__)
#define CONCAT_11(_1,_2,...)   CONCAT_10(_1 ## _2, __VA_ARGS__)
#define CONCAT_12(_1,_2,...)   CONCAT_11(_1 ## _2, __VA_ARGS__)
#define CONCAT_13(_1,_2,...)   CONCAT_12(_1 ## _2, __VA_ARGS__)
#define CONCAT_14(_1,_2,...)   CONCAT_13(_1 ## _2, __VA_ARGS__)
#define CONCAT_15(_1,_2,...)   CONCAT_14(_1 ## _2, __VA_ARGS__)
#define CONCAT_16(_1,_2,...)   CONCAT_15(_1 ## _2, __VA_ARGS__)
#define CONCAT_17(_1,_2,...)   CONCAT_16(_1 ## _2, __VA_ARGS__)
#define CONCAT_18(_1,_2,...)   CONCAT_17(_1 ## _2, __VA_ARGS__)
#define CONCAT_19(_1,_2,...)   CONCAT_18(_1 ## _2, __VA_ARGS__)
#define CONCAT_20(_1,_2,...)   CONCAT_19(_1 ## _2, __VA_ARGS__)
#define CONCAT_21(_1,_2,...)   CONCAT_20(_1 ## _2, __VA_ARGS__)
#define CONCAT_22(_1,_2,...)   CONCAT_21(_1 ## _2, __VA_ARGS__)
#define CONCAT_23(_1,_2,...)   CONCAT_22(_1 ## _2, __VA_ARGS__)
#define CONCAT_24(_1,_2,...)   CONCAT_23(_1 ## _2, __VA_ARGS__)
#define CONCAT_25(_1,_2,...)   CONCAT_24(_1 ## _2, __VA_ARGS__)
#define CONCAT_26(_1,_2,...)   CONCAT_25(_1 ## _2, __VA_ARGS__)
#define CONCAT_27(_1,_2,...)   CONCAT_26(_1 ## _2, __VA_ARGS__)
#define CONCAT_28(_1,_2,...)   CONCAT_27(_1 ## _2, __VA_ARGS__)
#define CONCAT_29(_1,_2,...)   CONCAT_28(_1 ## _2, __VA_ARGS__)
#define CONCAT_30(_1,_2,...)   CONCAT_29(_1 ## _2, __VA_ARGS__)
#define CONCAT_31(_1,_2,...)   CONCAT_30(_1 ## _2, __VA_ARGS__)
#define CONCAT_32(_1,_2,...)   CONCAT_31(_1 ## _2, __VA_ARGS__)

#define ARG_REST_(_1, ...) \
	__VA_ARGS__

#define ARG_(...)            /* empty */
#define ARG_0(...)           /* empty */
#define ARG_1_(_1, ...)      _1
#define ARG_1(...)           ARG_1_(__VA_ARGS__,)
#define ARG_2(...)           ARG_1(ARG_REST_(__VA_ARGS__,))
#define ARG_3(...)           ARG_2(ARG_REST_(__VA_ARGS__,))
#define ARG_4(...)           ARG_3(ARG_REST_(__VA_ARGS__,))
#define ARG_5(...)           ARG_4(ARG_REST_(__VA_ARGS__,))
#define ARG_6(...)           ARG_5(ARG_REST_(__VA_ARGS__,))
#define ARG_7(...)           ARG_6(ARG_REST_(__VA_ARGS__,))
#define ARG_8(...)           ARG_7(ARG_REST_(__VA_ARGS__,))
#define ARG_9(...)           ARG_8(ARG_REST_(__VA_ARGS__,))
#define ARG_10(...)          ARG_9(ARG_REST_(__VA_ARGS__,))
#define ARG_11(...)          ARG_10(ARG_REST_(__VA_ARGS__,))
#define ARG_12(...)          ARG_11(ARG_REST_(__VA_ARGS__,))
#define ARG_13(...)          ARG_12(ARG_REST_(__VA_ARGS__,))
#define ARG_14(...)          ARG_13(ARG_REST_(__VA_ARGS__,))
#define ARG_15(...)          ARG_14(ARG_REST_(__VA_ARGS__,))
#define ARG_16(...)          ARG_15(ARG_REST_(__VA_ARGS__,))
#define ARG_17(...)          ARG_16(ARG_REST_(__VA_ARGS__,))
#define ARG_18(...)          ARG_17(ARG_REST_(__VA_ARGS__,))
#define ARG_19(...)          ARG_18(ARG_REST_(__VA_ARGS__,))
#define ARG_20(...)          ARG_19(ARG_REST_(__VA_ARGS__,))
#define ARG_21(...)          ARG_20(ARG_REST_(__VA_ARGS__,))
#define ARG_22(...)          ARG_21(ARG_REST_(__VA_ARGS__,))
#define ARG_23(...)          ARG_22(ARG_REST_(__VA_ARGS__,))
#define ARG_24(...)          ARG_23(ARG_REST_(__VA_ARGS__,))
#define ARG_25(...)          ARG_24(ARG_REST_(__VA_ARGS__,))
#define ARG_26(...)          ARG_25(ARG_REST_(__VA_ARGS__,))
#define ARG_27(...)          ARG_26(ARG_REST_(__VA_ARGS__,))
#define ARG_28(...)          ARG_27(ARG_REST_(__VA_ARGS__,))
#define ARG_29(...)          ARG_28(ARG_REST_(__VA_ARGS__,))
#define ARG_30(...)          ARG_29(ARG_REST_(__VA_ARGS__,))
#define ARG_31(...)          ARG_30(ARG_REST_(__VA_ARGS__,))
#define ARG_32(...)          ARG_31(ARG_REST_(__VA_ARGS__,))

#define _CLAUSE1(...) __VA_ARGS__ FORGET
#define _CLAUSE2(...) EXPAND

#define __IF_CLAUSE(A,B,C,...) C
#define _IF_CLAUSE(EXP) __IF_CLAUSE(EXP, _CLAUSE1, _CLAUSE2,)

#define _IS_0_EQ_0    ,
#define _IS_1_EQ_1    ,
#define _IS_2_EQ_2    ,
#define _IS_3_EQ_3    ,
#define _IS_4_EQ_4    ,
#define _IS_5_EQ_5    ,
#define _IS_6_EQ_6    ,
#define _IS_7_EQ_7    ,
#define _IS_8_EQ_8    ,
#define _IS_9_EQ_9    ,
#define _IS_10_EQ_10  ,
#define _IS_11_EQ_11  ,
#define _IS_12_EQ_12  ,
#define _IS_13_EQ_13  ,
#define _IS_14_EQ_14  ,
#define _IS_15_EQ_15  ,
#define _IS_16_EQ_16  ,
#define _IS_17_EQ_17  ,
#define _IS_18_EQ_18  ,
#define _IS_19_EQ_19  ,
#define _IS_20_EQ_20  ,
#define _IS_21_EQ_21  ,
#define _IS_22_EQ_22  ,
#define _IS_23_EQ_23  ,
#define _IS_24_EQ_24  ,
#define _IS_25_EQ_25  ,
#define _IS_26_EQ_26  ,
#define _IS_27_EQ_27  ,
#define _IS_28_EQ_28  ,
#define _IS_29_EQ_29  ,
#define _IS_30_EQ_30  ,
#define _IS_31_EQ_31  ,
#define _IS_32_EQ_32  ,

#define STR_(...)   #__VA_ARGS__

/* detect empty arguments */
#define _IS_EMPTY(_0, _1, _2, _3) \
	HAS_COMMA(CONCAT_5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define _IS_EMPTY_CASE_0001 ,
#define _IS_EMPTY_FN(...) ,

/**@endcond*/

#endif	/* PPMLIB_H_INCLUDED */