Skyward boardcore
Loading...
Searching...
No Matches
DependencyManager.h
Go to the documentation of this file.
1/* Copyright (c) 2024 Skyward Experimental Rocketry
2 * Author: Davide Mor
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
26
27#include <map>
28#include <numeric>
29#include <ostream>
30#include <string>
31#include <typeindex>
32#include <typeinfo>
33#include <vector>
34
35namespace Boardcore
36{
37
43int32_t getNextDependencyId();
44
48template <typename T>
50{
51 static int32_t ID = getNextDependencyId();
52 return ID;
53}
54
55class DependencyInjector;
56class DependencyManager;
57
62{
63public:
64 virtual ~Injectable() = default;
65
73 virtual void inject(DependencyInjector& injector) {}
74};
75
115{
116 friend class DependencyInjector;
117
118private:
119 struct ModuleInfo
120 {
121 std::string name; //< Name of the type.
122 void* raw;
124 Injectable* injectable;
127 std::vector<int32_t> deps;
128 };
129
130public:
132
141 template <typename T, typename = std::enable_if_t<
142 std::is_base_of<Injectable, T>::value>>
143 [[nodiscard]] bool insert(T* dependency)
144 {
145 return insertImpl(
146 getDependencyId<T>(), reinterpret_cast<void*>(dependency),
147 static_cast<Injectable*>(dependency), typeid(T).name());
148 }
149
156 void graphviz(std::ostream& os);
157
163 [[nodiscard]] bool inject();
164
165private:
166 [[nodiscard]] bool insertImpl(int32_t id, void* raw, Injectable* injectable,
167 const char* name);
168
169 void* getImpl(int32_t id);
170
172 Boardcore::Logging::getLogger("DependencyManager");
173
174 bool load_success = true;
175 // Maps from interface type name to ModuleInfo
176 std::map<int32_t, ModuleInfo> modules;
177};
178
183{
184 friend class DependencyManager;
185
186private:
188 DependencyManager::ModuleInfo& info)
189 : manager(manager), info(info)
190 {
191 }
192
193public:
200 template <typename T>
201 T* get()
202 {
203 return reinterpret_cast<T*>(getImpl(getDependencyId<T>()));
204 }
205
206private:
207 void* getImpl(int32_t id);
208
210 Boardcore::Logging::getLogger("DependencyManager");
211
212 DependencyManager& manager;
213 DependencyManager::ModuleInfo& info;
214};
215
216namespace DependencyManagerDetails
217{
218
219// Storage implementation
220template <typename... Types>
222{
223 // No-op, base case
224 void inject(DependencyInjector& injector) {}
225
226 // No-op, dummy get (this should never be reached)
227 template <typename T>
228 T* get()
229 {
230 return nullptr;
231 }
232};
233
234template <typename Type, typename... Types>
235struct Storage<Type, Types...> : public Storage<Types...>
236{
237 using Super = Storage<Types...>;
238
239 // Recursive implementation
240 Type* item = nullptr;
241
243 {
244 item = injector.get<Type>();
245 // Call parent function
246 Super::inject(injector);
247 }
248
249 template <typename T>
250 typename std::enable_if_t<std::is_same<T, Type>::value, T*> get()
251 {
252 return item;
253 }
254
255 template <typename T>
256 typename std::enable_if_t<!std::is_same<T, Type>::value, T*> get()
257 {
258 return Super::template get<T>();
259 }
260};
261
262// Find type in list implementation
263template <typename T, typename... Types>
264struct Contains : std::false_type
265{
266};
267
268template <typename T, typename Type, typename... Types>
269struct Contains<T, Type, Types...>
270 : std::integral_constant<bool, std::is_same<T, Type>::value ||
271 Contains<T, Types...>::value>
272{
273};
274
275} // namespace DependencyManagerDetails
276
277template <typename T>
279{
280};
281
285template <typename... Types>
287{
288protected:
293 using Super = InjectableWithDeps<Types...>;
294
295public:
296 virtual void inject(DependencyInjector& injector) override
297 {
298 storage.inject(injector);
299 }
300
307 template <typename T,
308 typename = std::enable_if_t<
309 DependencyManagerDetails::Contains<T, Types...>::value>>
311 {
312 return storage.template get<T>();
313 }
314
315private:
316 DependencyManagerDetails::Storage<Types...> storage;
317};
318
323template <typename Base, typename... Types>
324class InjectableWithDeps<InjectableBase<Base>, Types...> : public Base
325{
326protected:
331 using Super = InjectableWithDeps<InjectableBase<Base>, Types...>;
332
333public:
334 using InjectableSuper = Base;
335 using Base::Base;
336
337 static_assert(std::is_base_of<Injectable, Base>::value,
338 "Base must be Injectable");
339
340 virtual void inject(DependencyInjector& injector) override
341 {
342 Base::inject(injector);
343 storage.inject(injector);
344 }
345
352 template <typename T,
353 typename = std::enable_if_t<
354 DependencyManagerDetails::Contains<T, Types...>::value>>
356 {
357 return storage.template get<T>();
358 }
359
360private:
361 DependencyManagerDetails::Storage<Types...> storage;
362};
363
364} // namespace Boardcore
Proxy class used to obtain dependencies.
T * get()
Retrieve a specific dependencies, recording it and tracking unsatisfied dependencies.
Main DependencyManager class.
bool inject()
Inject all dependencies into all inserted .
bool insert(T *dependency)
Insert a new dependency.
void graphviz(std::ostream &os)
Generate a gaphviz compatible output showing dependencies. Needs to be called after inject.
Interface for an injectable dependency.
virtual void inject(DependencyInjector &injector)
Invoked by the DependencyManager to inject dependencies. Override this method to retrieve dependencie...
virtual ~Injectable()=default
Base class for an Injectable with dependencies and an Injectable superclass.
virtual void inject(DependencyInjector &injector) override
< Inherit constructors from Base
Base class for an Injectable with dependencies.
T * getModule()
Get one of the modules in Types.
InjectableWithDeps< Types... > Super
virtual void inject(DependencyInjector &injector) override
Invoked by the DependencyManager to inject dependencies. Override this method to retrieve dependencie...
static PrintLogger getLogger(const string &name)
This file includes all the types the logdecoder script will decode.
int32_t getDependencyId()
Get the ID associated with the given T type.
int32_t getNextDependencyId()
Returns the next available id.
std::enable_if_t< std::is_same< T, Type >::value, T * > get()
std::enable_if_t<!std::is_same< T, Type >::value, T * > get()
void inject(DependencyInjector &injector)