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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
#ifndef _HOOK_H
#define _HOOK_H
#include <stdint.h>
#include "vec.h"
/** Callback when removing hooks to clean up userdata */
typedef void (*remove_hook_cb)(void *userdata);
#define HOOK_IMPL(name, callback_type) \
struct name##_hook { \
uint32_t id; \
callback_type callback; \
void *userdata; \
}; \
\
typedef VEC(struct name##_hook) name##_hook_vec; \
\
static inline uint32_t insert_##name##_hook( \
name##_hook_vec *hooks, uint32_t *id, callback_type callback, \
void *userdata) { \
uint32_t iid = ++(*id); \
struct name##_hook hook = (struct name##_hook){ \
.id = iid, \
.callback = callback, \
.userdata = userdata, \
}; \
VEC_PUSH(hooks, hook); \
\
return iid; \
} \
\
static inline void remove_##name##_hook(name##_hook_vec *hooks, uint32_t id, \
remove_hook_cb callback) { \
uint64_t found_at = (uint64_t) - 1; \
VEC_FOR_EACH_INDEXED(hooks, struct name##_hook *h, idx) { \
if (h->id == id) { \
if (callback != NULL) { \
callback(h->userdata); \
} \
found_at = idx; \
break; \
} \
} \
if (found_at != (uint64_t) - 1) { \
if (found_at < VEC_SIZE(hooks) - 1) { \
VEC_SWAP(hooks, found_at, VEC_SIZE(hooks) - 1); \
} \
VEC_POP(hooks, struct name##_hook removed); \
(void)removed; \
} \
}
#define HOOK_IMPL_NO_REMOVE(name, callback_type) \
struct name##_hook { \
uint32_t id; \
callback_type callback; \
void *userdata; \
}; \
\
typedef VEC(struct name##_hook) name##_hook_vec; \
\
static inline uint32_t insert_##name##_hook( \
name##_hook_vec *hooks, uint32_t *id, callback_type callback, \
void *userdata) { \
uint32_t iid = ++(*id); \
struct name##_hook hook = (struct name##_hook){ \
.id = iid, \
.callback = callback, \
.userdata = userdata, \
}; \
VEC_PUSH(hooks, hook); \
\
return iid; \
}
#define dispatch_hook(hooks, hook_type, ...) \
VEC_FOR_EACH(hooks, hook_type *h) { h->callback(__VA_ARGS__, h->userdata); }
#define dispatch_hook_no_args(hooks, hook_type) \
VEC_FOR_EACH(hooks, hook_type *h) { h->callback(h->userdata); }
#endif
|