svMultiPhysics
Loading...
Searching...
No Matches
factory.h
1// SPDX-FileCopyrightText: Copyright (c) Stanford University, The Regents of the
2// University of California, and others. SPDX-License-Identifier: BSD-3-Clause
3
4#ifndef FACTORY_H
5#define FACTORY_H
6
8
9#include <map>
10#include <string>
11
12/**
13 * @brief Abstract self-registering factory.
14 *
15 * This class gives a way to create a dynamic register of classes derived from a
16 * certain base class, and then instantiate them by name. To be compatible with
17 * this factory, the derived classes must be default constructibleß.
18 *
19 * It combines the
20 * [factory](https://en.wikipedia.org/wiki/Abstract_factory_pattern) and
21 * [singleton](https://en.wikipedia.org/wiki/Singleton_pattern) patterns. There
22 * should always exist only one instance of this class, which cannot be accessed
23 * directly but only manipulated through the static methods of this class.
24 *
25 * To register a class into the factory, you can call the register_child
26 * static method, passing a class derived from BaseType as template argument and
27 * a label for it as argument. A shortcut for this is to use the macro
28 * REGISTER_IN_FACTORY.
29 */
30template <class BaseType> class Factory {
31public:
32 /**
33 * @brief Register a derived class in the factory.
34 *
35 * @param[in] name Label for the class to be registered. An instance of that
36 * class can then be created by passing this same label to the create
37 * method.
38 */
39 template <class DerivedType>
40 static bool register_child(const std::string &name) {
41 auto &factory_instance = get_instance();
42
43 if (factory_instance.children.find(name) !=
44 factory_instance.children.end()) {
45 svmp::raise<svmp::FE::InvalidArgumentException>(
46 "A model with name '" + name +
47 "' was already registered in the ionic model factory.");
48 }
49
50 factory_instance.children[name] = []() -> std::unique_ptr<BaseType> {
51 return std::make_unique<DerivedType>();
52 };
53
54 return true;
55 }
56
57 /**
58 * @brief Instantiate a derived classs by name.
59 */
60 static std::unique_ptr<BaseType> create(const std::string &name) {
61 const auto &factory_instance = get_instance();
62
63 auto iter = factory_instance.children.find(name);
64 if (iter == factory_instance.children.end()) {
65 svmp::raise<svmp::FE::InvalidArgumentException>(
66 "No class with name '" + name + "' was registered in the factory.");
67 }
68
69 return iter->second();
70 }
71
72 /**
73 * @brief Iterate through the registered classes.
74 *
75 * For every registered class derived from BaseType, creates a dummy instance
76 * of it, and then calls the provided function on that instance. All the dummy
77 * instances are destroyed after the function call.
78 */
79 static void
80 visit(const std::function<void(const std::string &, const BaseType &)> &f) {
81 const auto &factory_instance = get_instance();
82
83 for (auto &[name, builder] : factory_instance.children) {
84 std::unique_ptr<BaseType> dummy = builder();
85 f(name, *dummy);
86 }
87 }
88
89protected:
90 /**
91 * @brief Default constructor.
92 */
93 Factory() = default;
94
95 /**
96 * @brief Access the singleton instance.
97 */
99 static Factory instance;
100 return instance;
101 }
102
103 /**
104 * @brief Registered derived classes.
105 *
106 * Each derived class is represented by a function that takes no argument and
107 * returns a unique_ptr<BaseType> constructing an instance of that class.
108 * This requires classes derived from BaseType to be default constructible.
109 */
110 std::map<std::string, std::function<std::unique_ptr<BaseType>()>> children;
111};
112
113/**
114 * @brief Macro to register a class in the factory.
115 */
116#define REGISTER_IN_FACTORY(BaseType, DerivedType, name) \
117 namespace FactoryInternals { \
118 static inline volatile const bool registered_##BaseType##_##DerivedType = \
119 Factory<BaseType>::register_child<DerivedType>(name); \
120 }
121
122#endif
Exception hierarchy for error handling in the FE library.
Abstract self-registering factory.
Definition factory.h:30
static Factory & get_instance()
Access the singleton instance.
Definition factory.h:98
std::map< std::string, std::function< std::unique_ptr< BaseType >()> > children
Registered derived classes.
Definition factory.h:110
Factory()=default
Default constructor.
static bool register_child(const std::string &name)
Register a derived class in the factory.
Definition factory.h:40
static std::unique_ptr< BaseType > create(const std::string &name)
Instantiate a derived classs by name.
Definition factory.h:60
static void visit(const std::function< void(const std::string &, const BaseType &)> &f)
Iterate through the registered classes.
Definition factory.h:80