rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
type_list.h
Go to the documentation of this file.
1#pragma once
2
3#include <type_traits>
4
5/*
6 * Indicates that a member of type_list should be able to be replaced in a unit test.
7 */
8template<typename base_t>
9struct Mockable;
10
11template<typename... Ts>
12struct type_list;
13
14/*
15 * Instantiates each type, allowing you to fetch by type.
16 *
17 * This is basically std::tuple, std::get, and std::apply, but with the API oriented more toward
18 * our needs.
19 *
20 * The primary use of this is to provide a list of engine modules in the giant Engine structure.
21 *
22 * The main feature is that objects are mockable. If you pass in Mockable<T> instead of T, and
23 * typedef T::interface_t, then you can call set to change what get returns.
24 *
25 * For a normal type T,
26 * T & get<T>();
27 * T & unmock<T>();
28 *
29 * For Mockable<T>,
30 * T::interface_t & get<T>();
31 * T & unmock<T>();
32 */
33template<typename base_t, typename... tail_t>
34struct type_list<base_t, tail_t...> {
36 type_list<tail_t...> others;
37
38#if EFI_UNIT_TEST
39 virtual ~type_list() = default;
40#endif
41
42 static_assert(!decltype(others)::template has<base_t>(), "Each type can only be listed once.");
43
44 template<typename count_t>
45 static consteval size_t count() {
46 return decltype(first)::template count<count_t>() +
47 decltype(others)::template count<count_t>();
48 }
49
50 static consteval size_t count() {
51 return 1 + decltype(others)::count();
52 }
53
54 /*
55 * Returns whether has_t exists in the type list
56 *
57 * has_t should not be Mockable, it should be the actual type.
58 */
59 template<typename has_t>
60 static consteval bool has() {
61 return decltype(first)::template has<has_t>() ||
62 decltype(others)::template has<has_t>();
63 }
64
65 /*
66 * Call the given function on the unmocked version of each type.
67 *
68 * It is probably best (and maybe only possible?) to call this with a generic lambda, as:
69 * tl.apply_all([](auto & m) { m.WhateverFuncIWant(); });
70 */
71 template<typename func_t>
72 void constexpr apply_all(func_t const & f) {
73 first.apply_all(f);
74 others.apply_all(f);
75 }
76
77 template<typename func_t>
78 void constexpr apply_all(func_t const & f) const {
79 first.apply_all(f);
80 others.apply_all(f);
81 }
82
83 // Applies an accumulator function over the sequence of elements.
84 // The specified seed value is used as the initial accumulator value,
85 // and the specified function is used to select the result value.
86 template<typename return_t, typename func_t>
87 decltype(auto) aggregate(func_t const& accumulator, return_t seed) {
88 return others.aggregate(accumulator, first.aggregate(accumulator, seed));
89 }
90
91 template<typename return_t, typename func_t>
92 decltype(auto) aggregate(func_t const& accumulator, return_t seed) const {
93 return others.aggregate(accumulator, first.aggregate(accumulator, seed));
94 }
95
96 /*
97 * Return the container object for type get_t.
98 *
99 * get_t should not be Mockable, it should be the actual type.
100 * The return object will have the methods unmock(), operator->, operator*, and if
101 * Mockable, set().
102 *
103 * The return type is type_list<get_t> or type_list<Mockable<get_t>>
104 */
105 template<typename get_t>
106 constexpr decltype(auto) get() {
107 static_assert(has<get_t>(), "Type not found in type_list");
108 if constexpr (decltype(first)::template has<get_t>()) {
109 return first.template get<get_t>();
110 } else {
111 return others.template get<get_t>();
112 }
113 }
114
115 template<typename get_t>
116 constexpr decltype(auto) get() const {
117 static_assert(has<get_t>(), "Type not found in type_list");
118 if constexpr (decltype(first)::template has<get_t>()) {
119 return first.template get<get_t>();
120 } else {
121 return others.template get<get_t>();
122 }
123 }
124};
125
126/*
127 * Specialization of type_list for a single base_t (that is not Mockable<>).
128 */
129template<typename base_t>
130struct type_list<base_t> {
131private:
132 base_t me;
133
134public:
135 template<typename count_t>
136 static consteval size_t count() {
137 return std::is_same_v<base_t, count_t> ? 1 : 0;
138 }
139
140 static consteval size_t count() {
141 return 1;
142 }
143
144 template<typename func_t>
145 void constexpr apply_all(func_t const & f) {
146 f(me);
147 }
148
149 template<typename func_t>
150 void constexpr apply_all(func_t const & f) const {
151 f(me);
152 }
153
154 template<typename return_t, typename func_t>
155 decltype(auto) aggregate(func_t const& accumulator, return_t seed) {
156 return accumulator(me, seed);
157 }
158
159 template<typename return_t, typename func_t>
160 decltype(auto) aggregate(func_t const& accumulator, return_t seed) const {
161 return accumulator(me, seed);
162 }
163
164 template<typename has_t>
165 static consteval bool has() {
166 return std::is_same_v<has_t, base_t>;
167 }
168
169 template<typename get_t, typename = std::enable_if_t<has<get_t>()>>
170 constexpr auto& get() {
171 return *this;
172 }
173
174 template<typename get_t, typename = std::enable_if_t<has<get_t>()>>
175 constexpr auto const& get() const {
176 return *this;
177 }
178
179 constexpr auto& unmock() {
180 return me;
181 }
182
183 constexpr auto const& unmock() const {
184 return me;
185 }
186
187 constexpr auto operator->() {
188 return &me;
189 }
190
191 constexpr auto operator->() const {
192 return &me;
193 }
194
195 constexpr auto& operator*() {
196 return me;
197 }
198
199 constexpr auto const& operator*() const {
200 return me;
201 }
202};
203
204#if EFI_PROD_CODE
205
206/*
207 * Production specialization of type_list for a single Mockable<base_t>.
208 *
209 * Performs exactly as base_t.
210 */
211template<typename base_t>
212struct type_list<Mockable<base_t>> : type_list<base_t> {
213};
214
215#else // if not EFI_PROD_CODE:
216
217#include <memory>
218
219/*
220 * Unit test/simulator specialization of type_list for a single Mockable<base_t>.
221 */
222template<typename base_t>
223struct type_list<Mockable<base_t>> {
224private:
225 // Dynamically allocate so that ASAN can detect overflows for us
226 std::unique_ptr<base_t> me = std::make_unique<base_t>();
227 using interface_t = typename base_t::interface_t;
228 interface_t* cur = me.get();
229
230public:
231 template<typename count_t>
232 static consteval size_t count() {
233 return std::is_same_v<base_t, count_t> ? 1 : 0;
234 }
235
236 static consteval size_t count() {
237 return 1;
238 }
239
240 template<typename func_t>
241 void constexpr apply_all(func_t const & f) {
242 f(*me);
243 }
244
245 template<typename func_t>
246 void constexpr apply_all(func_t const & f) const {
247 f(*me);
248 }
249
250 template<typename return_t, typename func_t>
251 decltype(auto) aggregate(func_t const& accumulator, return_t seed) {
252 return accumulator(*me, seed);
253 }
254
255 template<typename return_t, typename func_t>
256 decltype(auto) aggregate(func_t const& accumulator, return_t seed) const {
257 return accumulator(*me, seed);
258 }
259
260 template<typename has_t>
261 static consteval bool has() {
262 return std::is_same_v<has_t, base_t>;
263 }
264
265 template<typename get_t, typename = std::enable_if_t<has<get_t>()>>
266 constexpr auto& get() {
267 return *this;
268 }
269
270 template<typename get_t, typename = std::enable_if_t<has<get_t>()>>
271 constexpr auto const& get() const {
272 return *this;
273 }
274
275 auto& unmock() {
276 return *me;
277 }
278
279 auto const& unmock() const {
280 return *me;
281 }
282
283 void constexpr set(interface_t* ptr) {
284 if (ptr) {
285 cur = ptr;
286 } else {
287 cur = me.get();
288 }
289 }
290
291 constexpr interface_t* operator->() {
292 return cur;
293 }
294
295 constexpr interface_t const* operator->() const {
296 return cur;
297 }
298
299 constexpr interface_t& operator*() {
300 return *cur;
301 }
302
303 constexpr interface_t const& operator*() const {
304 return *cur;
305 }
306};
307
308#endif // EFI_UNIT_TEST
constexpr interface_t * operator->()
Definition type_list.h:291
static consteval bool has()
Definition type_list.h:261
static consteval size_t count()
Definition type_list.h:236
constexpr auto const & get() const
Definition type_list.h:271
static consteval size_t count()
Definition type_list.h:232
void constexpr apply_all(func_t const &f) const
Definition type_list.h:246
typename base_t::interface_t interface_t
Definition type_list.h:227
decltype(auto) aggregate(func_t const &accumulator, return_t seed) const
Definition type_list.h:256
auto const & unmock() const
Definition type_list.h:279
void constexpr apply_all(func_t const &f)
Definition type_list.h:241
constexpr interface_t & operator*()
Definition type_list.h:299
decltype(auto) aggregate(func_t const &accumulator, return_t seed)
Definition type_list.h:251
constexpr interface_t const * operator->() const
Definition type_list.h:295
void constexpr set(interface_t *ptr)
Definition type_list.h:283
constexpr interface_t const & operator*() const
Definition type_list.h:303
type_list< base_t > first
Definition type_list.h:35
virtual ~type_list()=default
static consteval size_t count()
Definition type_list.h:50
constexpr decltype(auto) get()
Definition type_list.h:106
static consteval size_t count()
Definition type_list.h:45
static consteval bool has()
Definition type_list.h:60
decltype(auto) aggregate(func_t const &accumulator, return_t seed) const
Definition type_list.h:92
void constexpr apply_all(func_t const &f) const
Definition type_list.h:78
decltype(auto) aggregate(func_t const &accumulator, return_t seed)
Definition type_list.h:87
void constexpr apply_all(func_t const &f)
Definition type_list.h:72
constexpr decltype(auto) get() const
Definition type_list.h:116
type_list< tail_t... > others
Definition type_list.h:36
constexpr auto const & get() const
Definition type_list.h:175
constexpr auto const & unmock() const
Definition type_list.h:183
constexpr auto & unmock()
Definition type_list.h:179
constexpr auto const & operator*() const
Definition type_list.h:199
constexpr auto operator->() const
Definition type_list.h:191
static consteval size_t count()
Definition type_list.h:136
decltype(auto) aggregate(func_t const &accumulator, return_t seed) const
Definition type_list.h:160
static consteval size_t count()
Definition type_list.h:140
decltype(auto) aggregate(func_t const &accumulator, return_t seed)
Definition type_list.h:155
static consteval bool has()
Definition type_list.h:165
void constexpr apply_all(func_t const &f) const
Definition type_list.h:150
constexpr auto operator->()
Definition type_list.h:187
constexpr auto & operator*()
Definition type_list.h:195
constexpr auto & get()
Definition type_list.h:170
void constexpr apply_all(func_t const &f)
Definition type_list.h:145
uint16_t count
Definition tunerstudio.h:1