-
Notifications
You must be signed in to change notification settings - Fork 0
/
cpoly.h
59 lines (48 loc) · 2.66 KB
/
cpoly.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#define POLY_TYPE(name) _Poly_##name
#define POLY_VAR(var) _poly_##var
#define POLY_INTERFACE(name) POLY_TYPE(Func_##name)
#define POLY_FUNC_PTR(name) POLY_TYPE(FunPtr_##name)
#define POLY_PROTOTYPE(ret, name, ...) \
typedef ret (*POLY_TYPE(name))(__VA_ARGS__); \
static inline void *POLY_FUNC_PTR(name)(POLY_TYPE(name) func) \
{ \
return (void*)func; \
}
#define POLY_IMPL(name, impl) [POLY_INTERFACE(name)] = POLY_FUNC_PTR(name)(impl)
typedef void (*PolyFreeFunc)(void *);
typedef struct {
char const *const type;
void *const *interfaces;
} POLY_TYPE(table);
#define POLY_DECLARE_DERIVED(base, derived, ctor) extern base ctor(derived *ptr, PolyFreeFunc _dtor);
#define POLY_DEFINE_DERIVED(base, derived, ctor, ...) \
base ctor(derived *ptr, PolyFreeFunc dtor) \
{ \
static void *interfaces[POLY_TYPE(base)] = {0}; \
void *tmp[] = {__VA_ARGS__}; \
memcpy(interfaces, tmp, sizeof(tmp)); \
static POLY_TYPE(table) const tbl = {.type = #derived, .interfaces = &interfaces[0]}; \
return (base){.POLY_VAR(self) = ptr, .POLY_VAR(dtor) = dtor, .POLY_VAR(table) = &tbl}; \
}
#define POLY_TABLE(base, ...) \
enum { \
__VA_ARGS__, \
POLY_TYPE(base) \
}; \
PolyFreeFunc POLY_VAR(dtor); \
void *POLY_VAR(self); \
POLY_TYPE(table) const *POLY_VAR(table);
#define POLY_FUNC(base, name) ((POLY_TYPE(name))(base)->POLY_VAR(table)->interfaces[POLY_INTERFACE(name)])
#define poly_cast(base, derived) ((derived *)(base)->POLY_VAR(self))
#define poly_safe_cast(base, derived) \
(strcmp((base)->POLY_VAR(table)->type, #derived) == 0 ? (derived *)(base)->POLY_VAR(self) : 0)
#define poly_free(base) \
{ \
if ((base)->_poly_dtor) (base)->_poly_dtor((base)->_poly_self); \
(base)->_poly_self = NULL; \
}