CellModules
hooktools.hpp
Go to the documentation of this file.
1#include <array>
2#include <vector>
3#include "introspect.hpp"
4
5// A lot of stupid macros here but the result is quite pleasant to use.
6// I'd like to thank the ViM editor for basically writing this file for me...
7
8// HOOKS ENUM
9#define HOOKS_ENUM(...) enum Hooks { __VA_ARGS__, LAST };
10// METHOD CHECKS
11#define CREATE_MC1(m1) CREATE_METHOD_CHECKS(m1);
12#define CREATE_MC2(m1, m2) \
13 CREATE_METHOD_CHECKS(m1); \
14 CREATE_METHOD_CHECKS(m2);
15#define CREATE_MC3(m1, m2, m3) \
16 CREATE_METHOD_CHECKS(m1); \
17 CREATE_METHOD_CHECKS(m2); \
18 CREATE_METHOD_CHECKS(m3);
19#define CREATE_MC4(m1, m2, m3, m4) \
20 CREATE_METHOD_CHECKS(m1); \
21 CREATE_METHOD_CHECKS(m2); \
22 CREATE_METHOD_CHECKS(m3); \
23 CREATE_METHOD_CHECKS(m4);
24#define CREATE_MC5(m1, m2, m3, m4, m5) \
25 CREATE_METHOD_CHECKS(m1); \
26 CREATE_METHOD_CHECKS(m2); \
27 CREATE_METHOD_CHECKS(m3); \
28 CREATE_METHOD_CHECKS(m4); \
29 CREATE_METHOD_CHECKS(m5);
30#define CREATE_MC6(m1, m2, m3, m4, m5, m6) \
31 CREATE_METHOD_CHECKS(m1); \
32 CREATE_METHOD_CHECKS(m2); \
33 CREATE_METHOD_CHECKS(m3); \
34 CREATE_METHOD_CHECKS(m4); \
35 CREATE_METHOD_CHECKS(m5); \
36 CREATE_METHOD_CHECKS(m6);
37#define CREATE_MC7(m1, m2, m3, m4, m5, m6, m7) \
38 CREATE_METHOD_CHECKS(m1); \
39 CREATE_METHOD_CHECKS(m2); \
40 CREATE_METHOD_CHECKS(m3); \
41 CREATE_METHOD_CHECKS(m4); \
42 CREATE_METHOD_CHECKS(m5); \
43 CREATE_METHOD_CHECKS(m6); \
44 CREATE_METHOD_CHECKS(m7);
45#define CREATE_MC8(m1, m2, m3, m4, m5, m6, m7, m8) \
46 CREATE_METHOD_CHECKS(m1); \
47 CREATE_METHOD_CHECKS(m2); \
48 CREATE_METHOD_CHECKS(m3); \
49 CREATE_METHOD_CHECKS(m4); \
50 CREATE_METHOD_CHECKS(m5); \
51 CREATE_METHOD_CHECKS(m6); \
52 CREATE_METHOD_CHECKS(m7); \
53 CREATE_METHOD_CHECKS(m8);
54#define CREATE_MC9(m1, m2, m3, m4, m5, m6, m7, m8, m9) \
55 CREATE_METHOD_CHECKS(m1); \
56 CREATE_METHOD_CHECKS(m2); \
57 CREATE_METHOD_CHECKS(m3); \
58 CREATE_METHOD_CHECKS(m4); \
59 CREATE_METHOD_CHECKS(m5); \
60 CREATE_METHOD_CHECKS(m6); \
61 CREATE_METHOD_CHECKS(m7); \
62 CREATE_METHOD_CHECKS(m8); \
63 CREATE_METHOD_CHECKS(m9);
64
65#define OVERLOADED_MACRO(M, ...) _OVR(M, _COUNT_ARGS(__VA_ARGS__))(__VA_ARGS__)
66#define _OVR(macroName, number_of_args) _OVR_EXPAND(macroName, number_of_args)
67#define _OVR_EXPAND(macroName, number_of_args) macroName##number_of_args
68
69#define _COUNT_ARGS(...) _ARG_PATTERN_MATCH(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1)
70#define _ARG_PATTERN_MATCH(_1, _2, _3, _4, _5, _6, _7, _8, _9, N, ...) N
71
72#define HCHK_M(hName) \
73 template <class P> \
74 static std::enable_if_t<is_##hName##_callable<P, hook_s>::value> register_##hName( \
75 H *c, P &p) { \
76 c->registerHook(Hooks::hName, [&](H *hc) { p.hName(hc); }); \
77 } \
78 template <class P> \
79 static std::enable_if_t<!is_##hName##_callable<P, hook_s>::value> register_##hName( \
80 H *, P &) {}
81
82#define HCHK_M1(h1) HCHK_M(h1)
83#define HCHK_M2(h1, h2) \
84 HCHK_M(h1) \
85 HCHK_M(h2)
86#define HCHK_M3(h1, h2, h3) \
87 HCHK_M(h1) \
88 HCHK_M(h2) \
89 HCHK_M(h3)
90#define HCHK_M4(h1, h2, h3, h4) \
91 HCHK_M(h1) \
92 HCHK_M(h2) \
93 HCHK_M(h3) \
94 HCHK_M(h4)
95#define HCHK_M5(h1, h2, h3, h4, h5) \
96 HCHK_M(h1) \
97 HCHK_M(h2) \
98 HCHK_M(h3) \
99 HCHK_M(h4) \
100 HCHK_M(h5)
101#define HCHK_M6(h1, h2, h3, h4, h5, h6) \
102 HCHK_M(h1) \
103 HCHK_M(h2) \
104 HCHK_M(h3) \
105 HCHK_M(h4) \
106 HCHK_M(h5) \
107 HCHK_M(h6)
108#define HCHK_M7(h1, h2, h3, h4, h5, h6, h7) \
109 HCHK_M(h1) \
110 HCHK_M(h2) \
111 HCHK_M(h3) \
112 HCHK_M(h4) \
113 HCHK_M(h5) \
114 HCHK_M(h6) \
115 HCHK_M(h7)
116#define HCHK_M8(h1, h2, h3, h4, h5, h6, h7, h8) \
117 HCHK_M(h1) \
118 HCHK_M(h2) \
119 HCHK_M(h3) \
120 HCHK_M(h4) \
121 HCHK_M(h5) \
122 HCHK_M(h6) \
123 HCHK_M(h7) \
124 HCHK_M(h8)
125#define HCHK_M9(h1, h2, h3, h4, h5, h6, h7, h8, h9) \
126 HCHK_M(h1) \
127 HCHK_M(h2) \
128 HCHK_M(h3) \
129 HCHK_M(h4) \
130 HCHK_M(h5) \
131 HCHK_M(h6) \
132 HCHK_M(h7) \
133 HCHK_M(h8) \
134 HCHK_M(h9)
135
136#define H_REG(hName) hookChecker<decltype(this), hook_s>::register_##hName(this, p)
137
138#define H_REG1(h1) H_REG(h1);
139#define H_REG2(h1, h2) \
140 H_REG(h1); \
141 H_REG(h2);
142#define H_REG3(h1, h2, h3) \
143 H_REG(h1); \
144 H_REG(h2); \
145 H_REG(h3);
146#define H_REG4(h1, h2, h3, h4) \
147 H_REG(h1); \
148 H_REG(h2); \
149 H_REG(h3); \
150 H_REG(h4);
151#define H_REG5(h1, h2, h3, h4, h5) \
152 H_REG(h1); \
153 H_REG(h2); \
154 H_REG(h3); \
155 H_REG(h4); \
156 H_REG(h5);
157#define H_REG6(h1, h2, h3, h4, h5, h6) \
158 H_REG(h1); \
159 H_REG(h2); \
160 H_REG(h3); \
161 H_REG(h4); \
162 H_REG(h5); \
163 H_REG(h6);
164#define H_REG7(h1, h2, h3, h4, h5, h6, h7) \
165 H_REG(h1); \
166 H_REG(h2); \
167 H_REG(h3); \
168 H_REG(h4); \
169 H_REG(h5); \
170 H_REG(h6); \
171 H_REG(h7);
172#define H_REG8(h1, h2, h3, h4, h5, h6, h7, h8) \
173 H_REG(h1); \
174 H_REG(h2); \
175 H_REG(h3); \
176 H_REG(h4); \
177 H_REG(h5); \
178 H_REG(h6); \
179 H_REG(h7); \
180 H_REG(h8);
181#define H_REG9(h1, h2, h3, h4, h5, h6, h7, h8, h9) \
182 H_REG(h1); \
183 H_REG(h2); \
184 H_REG(h3); \
185 H_REG(h4); \
186 H_REG(h5); \
187 H_REG(h6); \
188 H_REG(h7); \
189 H_REG(h8); \
190 H_REG(h9);
191
192#define DECLARE_HOOK(...) \
193 HOOKS_ENUM(__VA_ARGS__) \
194 OVERLOADED_MACRO(CREATE_MC, __VA_ARGS__) \
195 CREATE_METHOD_CHECKS(onRegister); \
196 template <class HookableClass, class hook_s> struct hookChecker { \
197 using H = std::remove_pointer_t<std::remove_reference_t<HookableClass>>; \
198 using hook_t = std::function<hook_s>; \
199 template <class P> \
200 static std::enable_if_t<is_onRegister_callable<P, hook_s>::value, hook_t> \
201 getOnRegister(P &p) { \
202 return [&](H *hc) { p.onRegister(hc); }; \
203 } \
204 \
205 template <class P> \
206 static std::enable_if_t<!is_onRegister_callable<P, hook_s>::value, hook_t> \
207 getOnRegister(P &) { \
208 return [&](H *) {}; \
209 } \
210 OVERLOADED_MACRO(HCHK_M, __VA_ARGS__) \
211 }; \
212 using hook_t = std::function<hook_s>; \
213 std::array<std::vector<hook_t>, Hooks::LAST> hooks; \
214 template <class P> hook_t registerPlugin(P &p) { \
215 OVERLOADED_MACRO(H_REG, __VA_ARGS__) \
216 return hookChecker<decltype(this), hook_s>::getOnRegister(p); \
217 }