SelfRegisteringFactory.h
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * ArmarX is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * ArmarX is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * @package ArmarXCore
17 * @author Christoph Pohl ( christoph dot pohl at kit dot edu )
18 * @date 24.02.22
19 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20 * GNU General Public License
21 */
22
23// http://www.nirfriedman.com/2018/04/29/unforgettable-factory/
24#pragma once
25
26#include <iostream>
27#include <memory>
28#include <string>
29#include <unordered_map>
30
31#include <boost/version.hpp>
32
34
35#if (BOOST_VERSION < 106701)
36
37#include <boost/functional/hash.hpp>
38
39#else
40#include <boost/container_hash/hash.hpp>
41#endif
42
47
48namespace armarx
49{
50
51 template <class Base, typename Identification, class... Args>
52 class Factory
53 {
54 public:
55 virtual const Identification getID() const = 0;
56
57 virtual ~Factory() = default;
58
59 static auto
60 make(const Identification& s, Args&&... args)
61 {
63 auto itr = data().find(s);
65 {
66 ARMARX_CHECK(itr != data().end())
67 << "Product for Factory " << meta::type_name<Base>() << " was not registered!";
68 }
69 else
70 {
71 ARMARX_CHECK(itr != data().end())
72 << "Product " << s << " for Factory " << meta::type_name<Base>()
73 << " was not registered!";
74 }
75 return itr->second(std::forward<Args>(args)...);
76 }
77
78 template <typename Derived>
79 struct Registrar : Base
80 {
81
82 friend Derived;
83
84 static bool
86 {
88 constexpr auto name = Derived::id;
89 Factory::data()[name] = [](Args... args) -> std::unique_ptr<Base>
90 { return std::make_unique<Derived>(std::forward<Args>(args)...); };
91 return true;
92 }
93
94 inline static const bool registered{registerT()};
95
96 const Identification
97 getID() const override
98 {
99 return Derived::id;
100 }
101
102 private:
103 class Registration
104 {
105 };
106
107 // IMPORTANT: this forces the derived constructor to not be = default; otherwise std::out_of_range: _Map_base::at error is thrown
108 // this is, because the registration does not work then
109 // see https://stackoverflow.com/questions/59919831/unforgettable-factory-when-is-constructor-instantiated?noredirect=1&lq=1
110 explicit Registrar(Registration) : Base(Key{})
111 {
112 (void)registered;
113 }
114 };
115
116 friend Base;
117
118 private:
119 class Key
120 {
121 Key(){};
122 template <typename T>
123 friend struct Registrar;
124 };
125
126 using FuncType = std::unique_ptr<Base> (*)(Args...);
127
128 Factory() = default;
129
130 static auto&
131 data()
132 {
134 static std::unordered_map<Identification, FuncType> s;
135 return s;
136 }
137 };
138
139 template <class Base, typename Identification1, typename Identification2, class... Args>
140 class Factory2D
141 {
142 public:
143 virtual const Identification1 getFirstID() const = 0;
144
145 virtual const Identification2 getSecondID() const = 0;
146
147 virtual ~Factory2D() = default;
148
149 static auto
150 make(const Identification1& f, const Identification2& s, Args&&... args)
151 {
153 auto itr = data().find(std::make_pair(f, s));
154 ARMARX_CHECK(itr != data().end()) << "Product was not registered!";
155 return itr->second(std::forward<Args>(args)...);
156 }
157
158 template <typename Derived>
159 struct Registrar : Base
160 {
161
162 friend Derived;
163
164 static bool
166 {
168 constexpr auto name = std::make_pair(Derived::idDimOne, Derived::idDimTwo);
169 Factory2D::data()[name] = [](Args... args) -> std::unique_ptr<Base>
170 { return std::make_unique<Derived>(std::forward<Args>(args)...); };
171 return true;
172 }
173
174 inline static const bool registered{registerT()};
175
176 const Identification1
177 getFirstID() const override
178 {
179 return Derived::idDimOne;
180 }
181
182 const Identification2
183 getSecondID() const override
184 {
185 return Derived::idDimTwo;
186 }
187
188 private:
189 class Registration
190 {
191 };
192
193 // IMPORTANT: this forces the derived constructor to not be = default; otherwise std::out_of_range: _Map_base::at error is thrown
194 // this is, because the registration does not work then
195 // see https://stackoverflow.com/questions/59919831/unforgettable-Factory2D-when-is-constructor-instantiated?noredirect=1&lq=1
196 explicit Registrar(Registration) : Base(Key{})
197 {
198 (void)registered;
199 }
200 };
201
202 friend Base;
203
204 private:
205 class Key
206 {
207 Key(){};
208 template <typename T>
209 friend struct Registrar;
210 };
211
212 using FuncType = std::unique_ptr<Base> (*)(Args...);
213
214 Factory2D() = default;
215
216 static auto&
217 data()
218 {
220 static std::unordered_map<std::pair<Identification1, Identification2>,
221 FuncType,
222 boost::hash<std::pair<Identification1, Identification2>>>
223 s;
224 return s;
225 }
226 };
227} // namespace armarx
uint8_t data[1]
static auto make(const Identification1 &f, const Identification2 &s, Args &&... args)
virtual const Identification2 getSecondID() const =0
virtual ~Factory2D()=default
virtual const Identification1 getFirstID() const =0
virtual ~Factory()=default
static auto make(const Identification &s, Args &&... args)
virtual const Identification getID() const =0
Stores key object pairs.
Definition Registrar.h:63
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
constexpr auto type_name() -> std::string_view
Definition ctti.h:78
This file offers overloads of toIce() and fromIce() functions for STL container types.
const Identification1 getFirstID() const override
const Identification2 getSecondID() const override
const Identification getID() const override
#define ARMARX_TRACE
Definition trace.h:77