Skip to content

Instantly share code, notes, and snippets.

@pkhuong
Last active December 12, 2019 03:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pkhuong/de212fbd5322a115cd8f908548a5a352 to your computer and use it in GitHub Desktop.
Save pkhuong/de212fbd5322a115cd8f908548a5a352 to your computer and use it in GitHub Desktop.
Traits in C
#include "trait.h"
static inline int
cmp_int(int x, int y)
{
if (x == y)
return 0;
return x < y ? -1 : 1;
}
#define TRAIT_INFO TYPE(int) IMPL(cmp, &cmp_int)
#include TRAIT_INC
static inline int
cmp_double(double x, double y)
{
if (x == y)
return 0;
return x < y ? -1 : 1;
}
#define TRAIT_INFO TYPE(double) IMPL(cmp, &cmp_double)
#include TRAIT_INC
int foo(int x, int y)
{
return TRAIT_DISPATCH(x, cmp)(x, y);
}
/* gcc -E test.c | grep -v '^#' | clang-format-4.0 --style=google */
static inline int cmp_int(int x, int y) {
if (x == y) return 0;
return x < y ? -1 : 1;
}
typedef int trait_type_0;
static const struct {
typeof(&cmp_int) cmp;
} trait_struct_0 __attribute__((__unused__)) = {
.cmp = &cmp_int,
};
static inline int cmp_double(double x, double y) {
if (x == y) return 0;
return x < y ? -1 : 1;
}
typedef double trait_type_1;
static const struct {
typeof(&cmp_double) cmp;
} trait_struct_1 __attribute__((__unused__)) = {
.cmp = &cmp_double,
};
int foo(int x, int y) {
return (_Generic((x), trait_type_1
: trait_struct_1, trait_type_0
: trait_struct_0)
.cmp)(x, y);
}
.text
.file "test.c"
.globl foo # -- Begin function foo
.p2align 4, 0x90
.type foo,@function
foo: # @foo
.cfi_startproc
# %bb.0:
xorl %ecx, %ecx
xorl %eax, %eax
cmpl %esi, %edi
setge %al
leal -1(%rax,%rax), %eax
cmovel %ecx, %eax
retq
.Lfunc_end0:
.size foo, .Lfunc_end0-foo
.cfi_endproc
# -- End function
.ident "clang version 7.1.0-svn353565-1~exp1~20190407125230.69 (branches/release_70)"
.section ".note.GNU-stack","",@progbits
.addrsig
#pragma once
#define TRAIT_INC "trait_0.inc"
#define TRAIT_DISPATCH_LIST
#define TRAIT_DISPATCH(X, FIELD) (_Generic((X), TRAIT_DISPATCH_LIST).FIELD)
/* -*- mode: C; -*- */
#define TYPE(X) typedef X trait_type_0;
#define IMPL(X, Y)
TRAIT_INFO
#undef TYPE
#undef IMPL
static const struct {
#define TYPE(X)
#define IMPL(X, Y) typeof(Y) X;
TRAIT_INFO
#undef IMPL
#undef TYPE
} trait_struct_0 __attribute__((__unused__)) = {
#define TYPE(X)
#define IMPL(X, Y) .X = Y,
TRAIT_INFO
#undef IMPL
#undef TYPE
};
#define TRAIT_DISPATCH_LIST_0 trait_type_0 : trait_struct_0
#undef TRAIT_DISPATCH_LIST
#define TRAIT_DISPATCH_LIST TRAIT_DISPATCH_LIST_0
#undef TRAIT_INC
#define TRAIT_INC "trait_1.inc"
#undef TRAIT_INFO
/* -*- mode: C; -*- */
#define TYPE(X) typedef X trait_type_1;
#define IMPL(X, Y)
TRAIT_INFO
#undef TYPE
#undef IMPL
static const struct {
#define TYPE(X)
#define IMPL(X, Y) typeof(Y) X;
TRAIT_INFO
#undef IMPL
#undef TYPE
} trait_struct_1 __attribute__((__unused__)) = {
#define TYPE(X)
#define IMPL(X, Y) .X = Y,
TRAIT_INFO
#undef IMPL
#undef TYPE
};
#define TRAIT_DISPATCH_LIST_1 trait_type_1 : trait_struct_1
#undef TRAIT_DISPATCH_LIST
#define TRAIT_DISPATCH_LIST TRAIT_DISPATCH_LIST_1, TRAIT_DISPATCH_LIST_0
#undef TRAIT_INC
#define TRAIT_INC "trait_2.inc"
#undef TRAIT_INFO
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment