Skip to content

Instantly share code, notes, and snippets.

@Jomy10
Last active April 24, 2024 17:53
Show Gist options
  • Save Jomy10/e0a8d34d3b5793a0d95524b1c5d5c143 to your computer and use it in GitHub Desktop.
Save Jomy10/e0a8d34d3b5793a0d95524b1c5d5c143 to your computer and use it in GitHub Desktop.
C Tagged Union Macro
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Author: Jonas Everaert
//
// You can change these however you like
#define _TU_TYPE_PREFIX(Type) T_##Type
#define _MATCH_VALUE_NAME _value
// Tagged Union
#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)
#define M_FOR_EACH_0(ACTN, E) E
#define M_FOR_EACH_1(ACTN, E) ACTN(E)
#define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
#define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
#define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
#define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
#define __ENUM_VAL(name) _TU_TYPE_PREFIX(name) ,
#define __UNION_FIELD(name) name as##name;
#define TaggedUnion(name, ...) \
struct name { \
enum { \
M_FOR_EACH(__ENUM_VAL, __VA_ARGS__) \
} type; \
union { \
M_FOR_EACH(__UNION_FIELD, __VA_ARGS__) \
} value; \
}
// MATCH Statement
#define M_CONC_N3(A, B, C) M_CONC_N3_(A, B, C)
#define M_CONC_N3_(A, B, C) A##B##C
#define M_FOR_EACH_N2_E(ACTN, EV, ...) M_CONC_N3(M_FOR_EACH_, M_NARGS(__VA_ARGS__), _N2_E) (ACTN, EV, __VA_ARGS__)
#define M_FOR_EACH_0_N2_E(ACTN, ExtraVar, E, B) ExtraVar, E, B
#define M_FOR_EACH_2_N2_E(ACTN, EV, E, B) ACTN(EV, E, B)
#define M_FOR_EACH_4_N2_E(ACTN, EV, E, B, ...) ACTN(EV, E, B) M_FOR_EACH_2_N2_E(ACTN, EV, __VA_ARGS__)
#define M_FOR_EACH_6_N2_E(ACTN, EV, E, B, ...) ACTN(EV, E, B) M_FOR_EACH_4_N2_E(ACTN, EV, __VA_ARGS__)
#define M_FOR_EACH_8_N2_E(ACTN, EV, E, B, ...) ACTN(EV, E, B) M_FOR_EACH_6_N2_E(ACTN, EV, __VA_ARGS__)
#define M_FOR_EACH_10_N2_E(ACTN, EV, E, B, ...) ACTN(EV, E, B) M_FOR_EACH_8_N2_E(ACTN, EV, __VA_ARGS__)
#define __MATCH_CASE(munion, TypeName, block) case _TU_TYPE_PREFIX(TypeName): { TypeName* _MATCH_VALUE_NAME = &munion.value.as##TypeName; block; };
#define match(munion, ...) \
switch (munion.type) { \
M_FOR_EACH_N2_E(__MATCH_CASE, munion, __VA_ARGS__) \
}
// Tagged Union macro in C, including pattern matching.
#include <tagged_union.h>
typedef struct {
int a;
} A;
typedef struct {
int a;
int b;
} B;
typedef TaggedUnion(_MyUnion, A, B) MyUnion;
int main(void) {
MyUnion una = { .type = T_A, .value = { .asA = 109 } };
printf("%i\n", una.value.asA.a);
MyUion unb = { .type = T_B, .value = { .asB = { .a = 10, .b = 20 } } };
printf("%i %i\n", unb.value.asB.a, unb.value.asB.b);
match (una,
A, ({
printf("It's an A: %i\n", _value->a);
break;
}),
B, ({
printf("It's a B: %i %i\n", _value->a, _value->b);
break;
})
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment