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