NeoN
A framework for CFD software
Loading...
Searching...
No Matches
runtimeSelectionFactory.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2023 - 2026 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 <functional>
18#include <iostream>
19#include <memory>
20#include <ranges>
21#include <unordered_map>
22
23#include "error.hpp"
24
25namespace NeoN
26{
27
36{
37public:
38
39 std::function<std::string(const std::string&)>
41 std::function<std::string(const std::string&)>
43 std::function<std::vector<std::string>()>
45};
46
57{
58public:
59
60 using LookupTable = std::unordered_map<std::string, BaseClassData>;
61
62 static void registerClass(std::string name, BaseClassData data)
63 {
64 // if not already registered
65 docTable()[name] = data;
66 }
67
75 static std::string doc(const std::string& baseClassName, const std::string& derivedClassName)
76 {
77 return docTable().at(baseClassName).doc(derivedClassName);
78 }
79
87 static std::string schema(const std::string& baseClassName, const std::string& derivedClassName)
88 {
89 // get the schema of the derived class
90 return docTable().at(baseClassName).schema(derivedClassName);
91 }
92
99 static std::vector<std::string> entries(const std::string& baseClassName)
100 {
101 return docTable().at(baseClassName).entries();
102 }
103
105 {
106 static LookupTable tbl;
107 return tbl;
108 }
109};
110
111
122template<class baseClass>
124{
126 {
127 // avoid unused variable warning
128 // is required to instantiate the static variable and with it the registration
129 (void)REGISTERED;
130 }
131
141 static bool init()
142 {
143 BaseClassData data = {baseClass::doc, baseClass::schema, baseClass::entries};
144 BaseClassDocumentation::registerClass(baseClass::name(), data);
145 return true;
146 }
147
148 static bool REGISTERED;
150#ifdef _MSC_VER
151 static_assert((bool)&REGISTERED);
152#endif
153};
154
155// Initialize the static variable and register the class
156template<class baseClass>
158
165{
166public:
167
168 std::function<std::string()> doc;
169 std::function<std::string()> schema;
170};
171
172// Parameters helper type
173template<typename... Args>
175{
176};
177
178// Primary template declaration
179template<typename Base, typename Params>
181
182// Partial specialization for Parameters
195template<typename Base, typename... Args>
196class RuntimeSelectionFactory<Base, Parameters<Args...>> : public RegisterDocumentation<Base>
197{
198public:
199
200 friend Base;
201
202 using CreatorFunc = std::function<std::unique_ptr<Base>(Args...)>;
203 using LookupTable = std::unordered_map<std::string, CreatorFunc>;
204 using ClassDocTable = std::unordered_map<std::string, DerivedClassDocumentation>;
205
212 static std::string doc(const std::string& derivedClassName)
213 {
214 // get the documentation of the derived class
215 return docTable().at(derivedClassName).doc();
216 }
217
224 static std::string schema(const std::string& derivedClassName)
225 {
226 // get the schema of the derived class
227 return docTable().at(derivedClassName).schema();
228 }
229
238 static std::vector<std::string> entries()
239 {
240 auto k = table() | std::views::keys;
241 return {k.begin(), k.end()};
242 }
243
244
258 static std::unique_ptr<Base> create(const std::string& key, Args... args)
259 {
260 keyExistsOrError(key);
261 auto ptr = table().at(key)(std::forward<Args>(args)...);
262 return ptr;
263 }
264
265
271 static void print(std::ostream& os)
272 {
273 const auto& tbl = table();
274 os << Base::name() << " " << tbl.size() << std::endl;
275 for (const auto& it : tbl)
276 {
277 os << " - " << it.first << std::endl;
278 }
279 }
280
291 template<class derivedClass>
292 class Register : public Base
293 {
294 public:
295
296 using Base::Base;
297
299 [[maybe_unused]] static bool REGISTERED;
300#ifdef _MSC_VER
301 static_assert((bool)&REGISTERED);
302#endif
303
314 static bool addSubType()
315 {
316 CreatorFunc func = [](Args... args) -> std::unique_ptr<Base> {
317 return static_cast<std::unique_ptr<Base>>(new derivedClass(std::forward<Args>(args
318 )...));
319 };
320 RuntimeSelectionFactory::table()[derivedClass::name()] = func;
321
323 childData.doc = []() -> std::string { return derivedClass::doc(); };
324 childData.schema = []() -> std::string { return derivedClass::schema(); };
325 RuntimeSelectionFactory::docTable()[derivedClass::name()] = childData;
326
327 return true;
328 }
329
330 ~Register() override
331 {
332 if (REGISTERED)
333 {
334 const auto& tbl = RuntimeSelectionFactory::table();
335 const auto it = tbl.find(derivedClass::name());
336 REGISTERED = (it != tbl.end());
337 }
338 }
339
340#ifdef _MSC_VER
341 private:
342
343 Register() { (void)REGISTERED; }
344#endif
345 };
346
347 virtual ~RuntimeSelectionFactory() = default;
348
349 static std::size_t size() { return table().size(); }
350
360 {
361 static LookupTable tbl;
362 return tbl;
363 }
364
374 {
375 static ClassDocTable tbl;
376 return tbl;
377 }
378
379private:
380
381
387 static void keyExistsOrError(const std::string& name)
388 {
389 const auto& tbl = table();
390 if (!tbl.contains(name))
391 {
392 auto msg = std::string {" Could not find constructor for "} + name + "\n";
393 msg += "valid constructors are: \n";
394 for (const auto& it : tbl)
395 {
396 msg += " - " + it.first + "\n";
397 }
398 NF_ERROR_EXIT(msg);
399 }
400 }
401
402 RuntimeSelectionFactory() = default;
403};
404
405// Initialize the static variable and register the class
406template<class Base, class... Args>
407template<class derivedClass>
408bool RuntimeSelectionFactory<Base, Parameters<Args...>>::Register<derivedClass>::REGISTERED =
409 RuntimeSelectionFactory<Base, Parameters<Args...>>::template Register<derivedClass>::addSubType(
410 );
411
412}; // 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:90
Integer types used throughout NeoN.
Definition array.hpp:18
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.