Match
Description
Open a type match over the static type of x. The scrutinee is copied by value (so rvalues / function returns work) and exposed to the arms as it. Pair with When arms and an optional trailing Otherwise. Arms are mutually exclusive; the block runs at most one of them.
Because the selector is a _Generic constant, exactly one arm is live per instantiation and the construct folds to it; the others are dead but must still compile against it’s static type (it has one concrete type here). This makes Match meaningful inside generic/macro code, and free everywhere else.
Usage example (from documentation)
Match(value) {
When(int) WriteFmtLn("int {}", it);
When(double) WriteFmtLn("double {}", it);
Otherwise WriteFmtLn("other");
}Success
Runs the body of the single arm whose type matches x (or Otherwise if none), with it bound to x. Block exits after one arm.
Failure
If no When matches and there is no Otherwise, the match is non-exhaustive and aborts via LOG_FATAL – it never silently falls through. A When body that misuses it’s static type is a compile error (every arm is type-checked).
Usage example (Cross-references)
Usage examples (Cross-references)
- In
Variant.c:20:
Number n = Number_from_int(42);
bool hit = false;
Match(n) {
When(Number, int) hit = (it == 42);
When(Number, double) hit = false;- In
Variant.c:27:
Number m = Number_from_double(2.5);
bool hd = false;
Match(m) {
When(Number, int) hd = false;
When(Number, double) hd = (it == 2.5);- In
Variant.c:39:
int ai = 0;
double bd = 0.0;
Match(a) {
When(Number, int) ai = it * 2; // it : int
When(Number, double) bd = it;- In
Variant.c:43:
When(Number, double) bd = it;
}
Match(b) {
When(Number, int) ai = it;
When(Number, double) bd = it * 2.0; // it : double
- In
Variant.c:52:
// value in, value out -- no pointers
static Number twice(Number n) {
Match(n) {
When(Number, int) return Number_from_int(it * 2);
When(Number, double) return Number_from_double(it * 2.0);- In
Variant.c:62:
Number r = twice(Number_from_int(21));
bool ok = false;
Match(r) {
When(Number, int) ok = (it == 42);
When(Number, double) ok = false;- In
Variant.c:72:
bool ok = false;
// Match directly on a function-return rvalue; float-less Number -> Otherwise unused.
Match(twice(Number_from_double(1.5))) {
When(Number, int) ok = false;
When(Number, double) ok = (it == 3.0);- In
Variant.c:83:
Cell c = Cell_from_char('Z');
bool ok = false;
Match(c) {
When(Cell, int) ok = false;
When(Cell, char) ok = (it == 'Z');- In
Variant.c:95:
bool ok = true;
for (int k = 0; k < 3; k++) {
Match(vals[k]) {
When(Tri, int) ok = ok && (it == 7), seen |= 1;
When(Tri, float) ok = ok && (it == 1.5f), seen |= 2;- In
Variant.c:107:
Number n = Number_from_int(7);
int count = 0;
Match(n) {
When(Number, int) count++;
When(Number, double) count++;- In
Variant.c:121:
bool deadend_variant_nonexhaustive(void) {
Number n = Number_from_double(9.0); // holds double, only int handled, no Otherwise
Match(n) {
When(Number, int)(void) it;
}- In
TypeMatch.c:21:
int tag = -1;
Match(i) {
When(int) tag = 0;
When(double) tag = 1;- In
TypeMatch.c:28:
bool ok = tag == 0;
Match(d) {
When(int) tag = 0;
When(double) tag = 1;- In
TypeMatch.c:36:
// Unlisted type falls to Otherwise.
Match(p) {
When(int) tag = 0;
When(double) tag = 1;- In
TypeMatch.c:50:
int ri = 0;
double rd = 0.0;
Match(i) {
When(int) ri = it * 2;
When(double) rd = it;- In
TypeMatch.c:54:
When(double) rd = it;
}
Match(d) {
When(int) ri = it;
When(double) rd = it * 2.0;- In
TypeMatch.c:65:
bool hit = false;
// Scrutinee is an rvalue; copied by value into `it`.
Match(i + 1) {
When(int) hit = (it == 5);
When(double) hit = false;- In
TypeMatch.c:75:
int i = 7;
int count = 0;
Match(i) {
When(int) count++;
When(double) count++;- In
TypeMatch.c:86:
Position2D p = {1.0f, 2.0f};
bool hit = false;
Match(p) {
When(int) hit = false;
When(double) hit = false;- In
TypeMatch.c:99:
int oi = 0;
double id = 0.0;
Match(i) {
When(int) {
Match(d) {- In
TypeMatch.c:101:
Match(i) {
When(int) {
Match(d) {
When(int) id = -1.0;
When(double) id = it; // inner `it` : double
- In
TypeMatch.c:122:
bool deadend_match_nonexhaustive(void) {
Position2D p = {1.0f, 2.0f};
Match(p) {
When(int)(void) it; // never matches Position2D, and there is no Otherwise
}- In
TypeMatch.h:75:
#define Match(x) \
for (bool MisraMatched = false, UNPL(tm_once) = true; UNPL(tm_once); UNPL(tm_once) = false, \
ASSERT_OR_FATAL(MisraMatched, "Match: no arm matched and no Otherwise (non-exhaustive)")) \
for (TYPE_OF(x) MisraSubject = (x), *UNPL(tm_loop) = &MisraSubject; UNPL(tm_loop); UNPL(tm_loop) = NULL)