blob: 99dfc2addcaea2d03eb0a476cfa0108580716d03 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#ifndef AOS_UTIL_GLOBAL_FACTORY_H_
2#define AOS_UTIL_GLOBAL_FACTORY_H_
Parker Schuh36416692017-02-18 17:34:15 -08003
4#include <functional>
5#include <memory>
6#include <string>
7#include <unordered_map>
Stephan Pleinesb1177672024-05-27 17:48:32 -07008#include <utility>
Parker Schuh36416692017-02-18 17:34:15 -08009
10// // File Usage Description:
11// class ExampleBaseClass { virtual ~ExampleBaseClass(); }
12// class ExampleSubClass : public ExampleBaseClass {}
13//
14// // At namespace scope in header file:
15// SETUP_FACTORY(ExampleBaseClass);
16// // At namespace scope in cc file:
17// REGISTER_SUBCLASS("ExampleSubClass", ExampleBaseClass, ExampleSubClass);
18//
19// // When you want an object of type "ExampleSubClass".
20// std::unique_ptr<ExampleBaseClass> constructed_item =
21// ExampleBaseClassGlobalFactory::Get("ExampleSubClass")();
22
23// Helper macro to set up a Factory Family for a particular type.
24// Put this is the header file along-side the base class.
25#define SETUP_FACTORY(BaseClass, ...) \
26 using BaseClass##GlobalFactory = \
27 ::aos::GlobalFactory<BaseClass, ##__VA_ARGS__>
28
29// Helper macro to set up a Factory for a subtype. For BaseClass
30// This should happen in a .cc file not a header file to avoid multiple
31// linkage.
32#define REGISTER_SUBCLASS_BY_KEY(key, BaseClass, SubClass) \
33 BaseClass##GlobalFactory::SubClassRegisterer<SubClass> \
34 register_for_##SubClass(key)
35
36// Proxy to above but where SubClass name is the key.
37#define REGISTER_SUBCLASS(BaseClass, SubClass) \
38 REGISTER_SUBCLASS_BY_KEY(#SubClass, BaseClass, SubClass)
39
40namespace aos {
41
42// Maintains a static std::unordered_map<std::string, FactoryFunction> for
43// BaseClass. Best to use with macros above.
44template <typename BaseClass, typename... FactoryArgs>
45class GlobalFactory {
46 public:
47 using FactoryFunction =
Parker Schuh309dd722017-02-25 11:31:18 -080048 std::function<std::unique_ptr<BaseClass>(FactoryArgs &&...)>;
Parker Schuh36416692017-02-18 17:34:15 -080049
50 // Gets the factory function by named. This will return a null factory
51 // std::function if the factory is not available, so one would be wise
52 // to check this function before use.
53 // It is an error to call this during static initialization.
54 static const FactoryFunction &Get(const std::string &name) {
55 const auto &map = *GetMap();
56 auto item = map.find(name);
57 if (item == map.end()) {
58 static FactoryFunction null_create_fn;
59 return null_create_fn;
60 }
61 return item->second;
62 }
63
64 // Installs a factory function for constructing SubClass
65 // using name "name". It is an error not call this at namespace scope
66 // through the REGISTER_SUBCLASS macro above.
67 template <typename SubClass>
68 class SubClassRegisterer {
69 public:
70 explicit SubClassRegisterer(const char *name) {
Austin Schuh60e77942022-05-16 17:48:24 -070071 (*GetMap())[name] = [](FactoryArgs &&...args) {
Parker Schuh36416692017-02-18 17:34:15 -080072 return std::unique_ptr<BaseClass>(
73 new SubClass(std::forward<FactoryArgs>(args)...));
74 };
75 }
76 };
77
Parker Schuh309dd722017-02-25 11:31:18 -080078 // Fetch all factory functions.
79 static const std::unordered_map<std::string, FactoryFunction> &GetAll() {
80 return *GetMap();
81 }
82
Parker Schuh36416692017-02-18 17:34:15 -080083 private:
84 // Actual map. (Protected by static from concurrent construction
85 // if there is nothing registered at static linkage time).
86 static std::unordered_map<std::string, FactoryFunction> *GetMap() {
87 static std::unordered_map<std::string, FactoryFunction> map;
88 return &map;
89 }
90};
91
92} // namespace aos
93
John Park33858a32018-09-28 23:05:48 -070094#endif // AOS_UTIL_GLOBAL_FACTORY_H_