Skip to content

Instantly share code, notes, and snippets.

@adragomir
Forked from vurtun/typed_union.c
Created July 10, 2017 21:57
Show Gist options
  • Save adragomir/fa49e4eeba47113babfc3630f4c7d493 to your computer and use it in GitHub Desktop.
Save adragomir/fa49e4eeba47113babfc3630f4c7d493 to your computer and use it in GitHub Desktop.
#include <assert.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#define tag(x) ((ptrdiff_t)&Tag##x)
#define is(x, T) ((x)->tag == tag(T))
#define as(x, T) ((struct T *)variant_cast((void *)(x), tag(T)))
static inline void*
variant_cast(void * variant_ptr, ptrdiff_t desired_tag) {
ptrdiff_t * variant_tag = (ptrdiff_t *)variant_ptr;
assert(*variant_tag == desired_tag);
return (void *)((char *)variant_ptr + sizeof(ptrdiff_t));
}
#include <errno.h>
struct Error {
int id;
} TagError;
struct Value {
float z;
float w;
} TagValue;
struct Result {
ptrdiff_t tag;
union {
struct Error _;
struct Value __;
};
};
struct Result
function_with_possible_error(int n)
{
struct Result res;
if (n < 0) {
res.tag = tag(Error);
struct Error *e = as(&res, Error);
e->id = ENOMEM;
return res;
}
res.tag = tag(Value);
struct Value *v = as(&res, Value);
v->w = 5.0f;
v->z = 2.0f;
return res;
}
struct Result
function_taking_some(struct Result r, float n)
{
struct Result res = r;
if (is(&res,Error))
return r;
if (n < 0) {
res.tag = tag(Error);
struct Error *e = as(&res, Error);
e->id = EINVAL;
return res;
}
struct Value *v = as(&res, Value);
v->w += n;
return res;
}
int main() {
struct Result res = {};
res = function_with_possible_error(5);
res = function_taking_some(res, 2.0f);
if (is(&res, Error)) {
struct Error *err = as(&res, Error);
printf("%d\n", err->id);
} else if (is(&res, Value)) {
struct Value *v = as(&res, Value);
printf("%.2f, %.2f\n", v->z, v->w);
} return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment