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