NeoN
A framework for CFD software
Loading...
Searching...
No Matches
runtimeSelectionFactory.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2023 - 2025 NeoN authors
2// SPDX-FileCopyrightText: 2023 AMR Wind Authors
3//
4// SPDX-License-Identifier: MIT
5
6// ##############################################################################
7// # Original design taken from amr wind #
8// # from here #
9// # https://github.com/Exawind/amr-wind/blob/v2.1.0/amr-wind/core/Factory.H #
10// ##############################################################################
11// its quite tricky for multiple compilers that bool REGISTERED gets initialized
12// the static_assert helps to register the class
13// https://stackoverflow.com/questions/6420985/
14// how-to-force-a-static-member-to-be-initialized?noredirect=1&lq=1
15#pragma once
16
17#include <memory>
18#include <unordered_map>
19#include <iostream>
20#include <functional>
21
22#include "error.hpp"
23
24namespace NeoN
25{
26
35{
36public:
37
38 std::function<std::string(const std::string&)>
40 std::function<std::string(const std::string&)>
42 std::function<std::vector<std::string>()>
44};
45
56{
57public:
58
59 using LookupTable = std::unordered_map<std::string, BaseClassData>;
60
61 static void registerClass(std::string name, BaseClassData data)
62 {
63 // if not already registered
64 docTable()[name] = data;
65 }
66
74 static std::string doc(const std::string& baseClassName, const std::string& derivedClassName)
75 {
76 return docTable().at(baseClassName).doc(derivedClassName);
77 }
78
86 static std::string schema(const std::string& baseClassName, const std::string& derivedClassName)
87 {
88 // get the schema of the derived class
89 return docTable().at(baseClassName).schema(derivedClassName);
90 }
91
98 static std::vector<std::string> entries(const std::string& baseClassName)
99 {
100 return docTable().at(baseClassName).entries();
101 }
102
104 {
105 static LookupTable tbl;
106 return tbl;
107 }
108};
109
110
121template<class baseClass>
123{
125 {
126 // avoid unused variable warning
127 // is required to instantiate the static variable and with it the registration
128 (void)REGISTERED;
129 }
130
140 static bool init()
141 {
142 BaseClassData data = {baseClass::doc, baseClass::schema, baseClass::entries};
143 BaseClassDocumentation::registerClass(baseClass::name(), data);
144 return true;
145 }
146
147 static bool REGISTERED;
149#ifdef _MSC_VER
150 static_assert((bool)&REGISTERED);
151#endif
152};
153
154// Initialize the static variable and register the class
155template<class baseClass>
157
164{
165public:
166
167 std::function<std::string()> doc;
168 std::function<std::string()> schema;
169};
170
171// Parameters helper type
172template<typename... Args>
174{
175};
176
177// Primary template declaration
178template<typename Base, typename Params>
180
181// Partial specialization for Parameters
194template<typename Base, typename... Args>
195class RuntimeSelectionFactory<Base, Parameters<Args...>> : public RegisterDocumentation<Base>
196{
197public:
198
199 friend Base;
200
201 using CreatorFunc = std::function<std::unique_ptr<Base>(Args...)>;
202 using LookupTable = std::unordered_map<std::string, CreatorFunc>;
203 using ClassDocTable = std::unordered_map<std::string, DerivedClassDocumentation>;
204
211 static std::string doc(const std::string& derivedClassName)
212 {
213 // get the documentation of the derived class
214 return docTable().at(derivedClassName).doc();
215 }
216
223 static std::string schema(const std::string& derivedClassName)
224 {
225 // get the schema of the derived class
226 return docTable().at(derivedClassName).schema();
227 }
228
237 static std::vector<std::string> entries()
238 {
239 std::vector<std::string> entries;
240 for (const auto& it : table())
241 {
242 entries.push_back(it.first);
243 }
244 return entries;
245 }
246
247
261 static std::unique_ptr<Base> create(const std::string& key, Args... args)
262 {
263 keyExistsOrError(key);
264 auto ptr = table().at(key)(std::forward<Args>(args)...);
265 return ptr;
266 }
267
268
274 static void print(std::ostream& os)
275 {
276 const auto& tbl = table();
277 os << Base::name() << " " << tbl.size() << std::endl;
278 for (const auto& it : tbl)
279 {
280 os << " - " << it.first << std::endl;
281 }
282 }
283
294 template<class derivedClass>
295 class Register : public Base
296 {
297 public:
298
299 using Base::Base;
300
302 [[maybe_unused]] static bool REGISTERED;
303#ifdef _MSC_VER
304 static_assert((bool)&REGISTERED);
305#endif
306
317 static bool addSubType()
318 {
319 CreatorFunc func = [](Args... args) -> std::unique_ptr<Base> {
320 return static_cast<std::unique_ptr<Base>>(new derivedClass(std::forward<Args>(args
321 )...));
322 };
323 RuntimeSelectionFactory::table()[derivedClass::name()] = func;
324
326 childData.doc = []() -> std::string { return derivedClass::doc(); };
327 childData.schema = []() -> std::string { return derivedClass::schema(); };
328 RuntimeSelectionFactory::docTable()[derivedClass::name()] = childData;
329
330 return true;
331 }
332
333 ~Register() override
334 {
335 if (REGISTERED)
336 {
337 const auto& tbl = RuntimeSelectionFactory::table();
338 const auto it = tbl.find(derivedClass::name());
339 REGISTERED = (it != tbl.end());
340 }
341 }
342
343#ifdef _MSC_VER
344 private:
345
346 Register() { (void)REGISTERED; }
347#endif
348 };
349
350 virtual ~RuntimeSelectionFactory() = default;
351
352 static std::size_t size() { return table().size(); }
353
363 {
364 static LookupTable tbl;
365 return tbl;
366 }
367
377 {
378 static ClassDocTable tbl;
379 return tbl;
380 }
381
382private:
383
384
390 static void keyExistsOrError(const std::string& name)
391 {
392 const auto& tbl = table();
393 if (tbl.find(name) == tbl.end())
394 {
395 auto msg = std::string {" Could not find constructor for "} + name + "\n";
396 msg += "valid constructors are: \n";
397 for (const auto& it : tbl)
398 {
399 msg += " - " + it.first + "\n";
400 }
401 NF_ERROR_EXIT(msg);
402 }
403 }
404
405 RuntimeSelectionFactory() = default;
406};
407
408// Initialize the static variable and register the class
409template<class Base, class... Args>
410template<class derivedClass>
411bool RuntimeSelectionFactory<Base, Parameters<Args...>>::Register<derivedClass>::REGISTERED =
412 RuntimeSelectionFactory<Base, Parameters<Args...>>::template Register<derivedClass>::addSubType(
413 );
414
415}; // namespace NeoN
Represents the data for a base class.
std::function< std::string(const std::string &)> schema
std::function< std::string(const std::string &)> doc
std::function< std::vector< std::string >()> entries
Provides a mechanism for registering and retrieving documentation for base and derived classes.
static std::string schema(const std::string &baseClassName, const std::string &derivedClassName)
static std::string doc(const std::string &baseClassName, const std::string &derivedClassName)
static std::vector< std::string > entries(const std::string &baseClassName)
std::unordered_map< std::string, BaseClassData > LookupTable
static void registerClass(std::string name, BaseClassData data)
Class representing the documentation for a derived class.
std::function< std::string()> schema
static std::string schema(const std::string &derivedClassName)
static std::string doc(const std::string &derivedClassName)
static std::unique_ptr< Base > create(const std::string &key, Args... args)
Creates an instance of a derived class based on the provided key.
static LookupTable & table()
Returns the lookup table for runtime selection.
std::function< std::unique_ptr< Base >(Args...)> CreatorFunc
static std::vector< std::string > entries()
Get a vector of all entries in the runtime selection factory.
static ClassDocTable & docTable()
Returns the documentation table for runtime selection.
std::unordered_map< std::string, DerivedClassDocumentation > ClassDocTable
A factory class for runtime selection of derived classes.
A template class for registering derived classes with a base class.
#define NF_ERROR_EXIT(message)
Macro for printing an error message and aborting the program.
Definition error.hpp:110
Definition array.hpp:20
const std::string & name(const NeoN::Document &doc)
Retrieves the name of a Document.
Template struct for registering documentation of a base class.
static bool init()
Static function to initialize the registration of the class documentation.