Last active
April 24, 2024 17:53
-
-
Save Jomy10/e0a8d34d3b5793a0d95524b1c5d5c143 to your computer and use it in GitHub Desktop.
C Tagged Union Macro
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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__) \ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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