Skyward boardcore
Loading...
Searching...
No Matches
ModuleManager.hpp
Go to the documentation of this file.
1/* Copyright (c) 2022 Skyward Experimental Rocketry
2 * Authors: Matteo Pignataro, 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#pragma once
23
24#include <Singleton.h>
25#include <assert.h>
26#include <stdint.h>
27#include <utils/Debug.h>
28
29#include <array>
30#include <atomic>
31
32namespace Boardcore
33{
34class Module
35{
36public:
37 virtual ~Module() = default;
38};
39
63class ModuleManager : public Singleton<ModuleManager>
64{
65 friend class Singleton<ModuleManager>;
66
67public:
69
71 {
72 // Delete all the modules to avoid memory leaks
73 for (size_t i = 0; i < MODULES_NUMBER; i++)
74 {
75 // It is okay to have nullptr in delete
76 delete modules[i];
77 }
78 }
79
93 template <typename T>
94 [[nodiscard]] bool insert(T *element)
95 {
96 // Verify that T is a subclass of module
97 static_assert(std::is_base_of<Module, T>(),
98 "Class must be subclass of Module");
99 static_assert((std::is_same<Module, T>() == false),
100 "Class must be subclass of Module and not Module itself");
101
102 if (!insertionAcceptance)
103 {
104 assert(false &&
105 "Cannot insert any other module after first get() call");
106 return false;
107 }
108
109 // Take the module type id
110 size_t id = getId<T>();
111
112 // This is the case in which the last slot is being occupied, so a
113 // failure is returned
114 if (id == MODULES_NUMBER)
115 {
116 return false;
117 }
118
119 // The module is added if only a module of the same subclass hasn't
120 // already been added
121 if (modules[id] == nullptr)
122 {
123 modules[id] = element;
124 return true;
125 }
126 return false;
127 }
128
136 template <class T>
137 T *get()
138 {
139 // Verify that T is a subclass of module but not actually a strict
140 // Module
141 static_assert(std::is_base_of<Module, T>(),
142 "Class must be subclass of Module");
143 static_assert((std::is_same<Module, T>() == false),
144 "Class must be subclass of Module and not Module itself");
145
146 // Inhibit further insertions
147 insertionAcceptance = false;
148
149 // Retrieve the module type id
150 size_t id = getId<T>();
151
152 // If the module is actually present, returns it by downcasting the
153 // object. It can be done because at every type, a unique id is assigned
154 if (modules[id] != nullptr)
155 {
156 return dynamic_cast<T *>(modules[id]);
157 }
158
159 // Fail if the module hasn't been added before
160 assert(false && "Get of a non previously inserted module");
161 return nullptr;
162 }
163
164private:
165 static constexpr size_t MODULES_NUMBER = 256;
166
168 std::array<Module *, MODULES_NUMBER> modules = {nullptr};
169
177 std::atomic<bool> insertionAcceptance{true};
178
185 size_t getNextId()
186 {
187 // Static variable, initialized only the first time
188 static size_t currentId = 0;
189
190 if (currentId == MODULES_NUMBER)
191 {
192 return MODULES_NUMBER;
193 }
194 currentId++;
195 return currentId;
196 }
197
212 template <typename T>
213 size_t getId()
214 {
215 // This thing works because a new static variable newId is created for
216 // every type T and the initial assignment is "called" only when the
217 // static variable is created
218 static size_t newId = getNextId();
219 return newId;
220 }
221};
222} // namespace Boardcore
virtual ~Module()=default
The module manager is a singleton object, so it can be instantiated only once. It contains all the ac...
T * get()
Get the Module object if present.
bool insert(T *element)
Inserts the module inside the array.
This file includes all the types the logdecoder script will decode.