The following code:
#define NOVALUE ((unsigned)-1)
#define EXPAND(...) __VA_ARGS__
#define ADDONE(...) +1
// -----------------------------------
#define IF_EMPTY_IN(a, ...) a
#define IF_EMPTY(t, f, ...) IF_EMPTY_IN(__VA_OPT__(f,) t, )
// --------------------------
#define TREE_VAL(idx, a, b, c, up, down) \
[idx] = {a, b, c, up, down},
// -----------------------------------
#define TREE_L4_NEXT(...)
#define TREE_L4_VAL_IN(f, idx, up, a, b, c, ...) \
f(idx, a, b, c, up, IF_EMPTY(NOVALUE, idx+1 __VA_OPT__(,) __VA_ARGS__)) \
TREE_L4_NEXT(f, idx+1, idx __VA_OPT__(,) __VA_ARGS__)
#define TREE_L4_VAL(...) \
TREE_L4_VAL_IN(__VA_ARGS__)
#define TREE_L4_0(f, idx, up, a)
#define TREE_L4_1(f, idx, up, a) \
TREE_L4_VAL(f, idx, up, EXPAND a)
#define TREE_L4_2(f, idx, up, a, ...) \
TREE_L4_1(f, idx, up, a) \
TREE_L4_1(f, idx TREE_L4_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L4_3(f, idx, up, a, ...) \
TREE_L4_1(f, idx, up, a) \
TREE_L4_2(f, idx TREE_L4_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L4_N(_3,_2,_1,_0,N,...) \
TREE_L4##N
#define TREE_L4(f, idx, up, ...) \
TREE_L4_N(__VA_OPT__(,) __VA_ARGS__,_3,_2,_1,_0)(f, idx, up, __VA_ARGS__)
#define TREE_L3_NEXT(...) TREE_L4(__VA_ARGS__)
#define TREE_L3_VAL_IN(f, idx, up, a, b, c, ...) \
f(idx, a, b, c, up, IF_EMPTY(NOVALUE, idx+1 __VA_OPT__(,) __VA_ARGS__)) \
TREE_L3_NEXT(f, idx+1, idx __VA_OPT__(,) __VA_ARGS__)
#define TREE_L3_VAL(...) \
TREE_L3_VAL_IN(__VA_ARGS__)
#define TREE_L3_0(f, idx, up, a)
#define TREE_L3_1(f, idx, up, a) \
TREE_L3_VAL(f, idx, up, EXPAND a)
#define TREE_L3_2(f, idx, up, a, ...) \
TREE_L3_1(f, idx, up, a) \
TREE_L3_1(f, idx TREE_L3_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L3_3(f, idx, up, a, ...) \
TREE_L3_1(f, idx, up, a) \
TREE_L3_2(f, idx TREE_L3_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L3_N(_3,_2,_1,_0,N,...) \
TREE_L3##N
#define TREE_L3(f, idx, up, ...) \
TREE_L3_N(__VA_OPT__(,) __VA_ARGS__,_3,_2,_1,_0)(f, idx, up, __VA_ARGS__)
#define TREE_L2_NEXT(...) TREE_L3(__VA_ARGS__)
#define TREE_L2_VAL_IN(f, idx, up, a, b, c, ...) \
f(idx, a, b, c, up, IF_EMPTY(NOVALUE, idx+1 __VA_OPT__(,) __VA_ARGS__)) \
TREE_L2_NEXT(f, idx+1, idx __VA_OPT__(,) __VA_ARGS__)
#define TREE_L2_VAL(...) \
TREE_L2_VAL_IN(__VA_ARGS__)
#define TREE_L2_0(f, idx, up, a)
#define TREE_L2_1(f, idx, up, a) \
TREE_L2_VAL(f, idx, up, EXPAND a)
#define TREE_L2_2(f, idx, up, a, ...) \
TREE_L2_1(f, idx, up, a) \
TREE_L2_1(f, idx TREE_L2_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L2_3(f, idx, up, a, ...) \
TREE_L2_1(f, idx, up, a) \
TREE_L2_2(f, idx TREE_L2_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L2_N(_3,_2,_1,_0,N,...) \
TREE_L2##N
#define TREE_L2(f, idx, up, ...) \
TREE_L2_N(__VA_OPT__(,) __VA_ARGS__,_3,_2,_1,_0)(f, idx, up, __VA_ARGS__)
#define TREE_L1_NEXT(...) TREE_L2(__VA_ARGS__)
#define TREE_L1_VAL_IN(f, idx, up, a, b, c, ...) \
f(idx, a, b, c, up, IF_EMPTY(NOVALUE, idx+1 __VA_OPT__(,) __VA_ARGS__)) \
TREE_L1_NEXT(f, idx+1, idx __VA_OPT__(,) __VA_ARGS__)
#define TREE_L1_VAL(...) \
TREE_L1_VAL_IN(__VA_ARGS__)
#define TREE_L1_0(f, idx, up, a)
#define TREE_L1_1(f, idx, up, a) \
TREE_L1_VAL(f, idx, up, EXPAND a)
#define TREE_L1_2(f, idx, up, a, ...) \
TREE_L1_1(f, idx, up, a) \
TREE_L1_1(f, idx TREE_L1_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L1_3(f, idx, up, a, ...) \
TREE_L1_1(f, idx, up, a) \
TREE_L1_2(f, idx TREE_L1_NEXT(ADDONE,,,a), up, __VA_ARGS__)
#define TREE_L1_N(_3,_2,_1,_0,N,...) \
TREE_L1##N
#define TREE_L1(f, idx, up, ...) \
TREE_L1_N(__VA_OPT__(,) __VA_ARGS__,_3,_2,_1,_0)(f, idx, up, __VA_ARGS__)
// -----------------------------------
#define TREE_SIZE(...) 0 TREE_L1(ADDONE, 0, NOVALUE, __VA_ARGS__)
#define TREE(...) TREE_L1(TREE_VAL, 0, NOVALUE, __VA_ARGS__)
// -----------------------------------
#include <stdio.h>
#include <string.h>
struct array_s {
int a;
int b;
int c;
unsigned int top;
unsigned int first;
};
#define LIST \
(10, -3, 8, \
(-1, -1, 13, \
(0, -7, 15)), \
(-4, 14, 13)), \
(17, 0, 1), \
(3, 3, 3, \
(1, 1, 0)) \
/* */
static const struct array_s array[] = { TREE(LIST) };
static const char *snovalue(char *buf, unsigned v) {
if (v == NOVALUE) {
strcpy(buf, "NoValue");
} else {
sprintf(buf, "%u", v);
}
return buf;
}
#define SNOVALUE(v) snovalue((char[200]){0}, v)
int main() {
for (int i = 0; i < sizeof(array)/sizeof(*array); ++i) {
const struct array_s *const e = &array[i];
printf("[%d]={%2d,%2d,%2d,%10s,%10s},\n",
i, e->a, e->b, e->c, SNOVALUE(e->top), SNOVALUE(e->first));
}
}
Outputs the content of array[]
generated from TREE(LIST)
as:
[0]={10,-3, 8, NoValue, 1},
[1]={-1,-1,13, 0, 2},
[2]={ 0,-7,15, 1, NoValue},
[3]={-4,14,13, 0, NoValue},
[4]={17, 0, 1, NoValue, NoValue},
[5]={ 3, 3, 3, NoValue, 6},
[6]={ 1, 1, 0, 5, NoValue},
I removed EMPTY
, I see no value in it. EMPTY, is just nothing, do not pass an argument. Then the macros can detect the number of arguments, and zero arguments, with the help of __VA_OPT__
.
I have written the TREE_L*
macros so that it is easy to generate them. You can just write a simple loop to generate a lot of them, and the last just has to have TREE_L*_NEXT
empty.
On each tree level, calculating the next index has been a challenge. A separate temporary tree is traversed in idx TREE_L*_NEXT(ADDONE
in each branch to calculate the current "depth" of the tree to get the index.
The code works like this: on each level, overload on number arguments. For each argument, output an [idx] = {stuff}
, and then, if there are children, repeat the overload with incremented "up" index. Each level knows the "up" - the index of the upper level tree. On each traversing level, the TREE_L<num>
is incremented because "used up" macros are painted blue by the preprocessor. All in all, this is a recursive algorithm.