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 #include <boost/version.hpp>
31 
32 #if (BOOST_VERSION < 106701)
33 
34 #include <boost/functional/hash.hpp>
35 
36 #else
37 #include <boost/container_hash/hash.hpp>
38 #endif
39 
44 
45 
46 namespace armarx
47 {
48 
49  template <class Base, typename Identification, class... Args>
50  class Factory
51  {
52  public:
53 
54  virtual const Identification getID() const = 0;
55 
56  virtual ~Factory() = default;
57 
58  static auto make(const Identification& s, Args&& ... args)
59  {
61  auto itr = data().find(s);
63  {
64  ARMARX_CHECK(itr != data().end()) << "Product for Factory " << meta::type_name<Base>()
65  << " was not registered!";
66  } else
67  {
68  ARMARX_CHECK(itr != data().end()) << "Product " << s << " for Factory " << meta::type_name<Base>()
69  << " was not registered!";
70  }
71  return itr->second(std::forward<Args>(args)...);
72  }
73 
74  template <typename Derived>
75  struct Registrar : Base
76  {
77 
78  friend Derived;
79 
80  static bool registerT()
81  {
83  constexpr auto name = Derived::id;
84  Factory::data()[name] = [](Args... args) -> std::unique_ptr<Base>
85  {
86  return std::make_unique<Derived>(std::forward<Args>(args)...);
87  };
88  return true;
89  }
90 
91  inline static const bool registered{registerT()};
92 
93  const Identification getID() const override
94  {
95  return Derived::id;
96  }
97 
98  private:
99  class Registration
100  {
101  };
102 
103  // IMPORTANT: this forces the derived constructor to not be = default; otherwise std::out_of_range: _Map_base::at error is thrown
104  // this is, because the registration does not work then
105  // see https://stackoverflow.com/questions/59919831/unforgettable-factory-when-is-constructor-instantiated?noredirect=1&lq=1
106  explicit Registrar(Registration) : Base(Key{})
107  {
108  (void) registered;
109  }
110 
111 
112  };
113 
114  friend Base;
115 
116  private:
117  class Key
118  {
119  Key()
120  {
121  };
122  template <typename T> friend
123  struct Registrar;
124  };
125 
126  using FuncType = std::unique_ptr<Base> (*)(Args...);
127 
128  Factory() = default;
129 
130  static auto& data()
131  {
132  ARMARX_TRACE;
133  static std::unordered_map<Identification, FuncType> s;
134  return s;
135  }
136  };
137 
138  template <class Base, typename Identification1, typename Identification2, class... Args>
139  class Factory2D
140  {
141  public:
142 
143  virtual const Identification1 getFirstID() const = 0;
144 
145  virtual const Identification2 getSecondID() const = 0;
146 
147  virtual ~Factory2D() = default;
148 
149  static auto make(const Identification1& f, const Identification2& s, Args&& ... args)
150  {
151  ARMARX_TRACE;
152  auto itr = data().find(std::make_pair(f, s));
153  ARMARX_CHECK(itr != data().end()) << "Product was not registered!";
154  return itr->second(std::forward<Args>(args)...);
155  }
156 
157  template <typename Derived>
158  struct Registrar : Base
159  {
160 
161  friend Derived;
162 
163  static bool registerT()
164  {
165  ARMARX_TRACE;
166  constexpr auto name = std::make_pair(Derived::idDimOne, Derived::idDimTwo);
167  Factory2D::data()[name] = [](Args... args) -> std::unique_ptr<Base>
168  {
169  return std::make_unique<Derived>(std::forward<Args>(args)...);
170  };
171  return true;
172  }
173 
174  inline static const bool registered{registerT()};
175 
176  const Identification1 getFirstID() const override
177  {
178  return Derived::idDimOne;
179  }
180 
181  const Identification2 getSecondID() const override
182  {
183  return Derived::idDimTwo;
184  }
185 
186  private:
187  class Registration
188  {
189  };
190 
191  // IMPORTANT: this forces the derived constructor to not be = default; otherwise std::out_of_range: _Map_base::at error is thrown
192  // this is, because the registration does not work then
193  // see https://stackoverflow.com/questions/59919831/unforgettable-Factory2D-when-is-constructor-instantiated?noredirect=1&lq=1
194  explicit Registrar(Registration) : Base(Key{})
195  {
196  (void) registered;
197  }
198 
199 
200  };
201 
202  friend Base;
203 
204  private:
205  class Key
206  {
207  Key()
208  {
209  };
210  template <typename T> friend
211  struct Registrar;
212  };
213 
214  using FuncType = std::unique_ptr<Base> (*)(Args...);
215 
216  Factory2D() = default;
217 
218  static auto& data()
219  {
220  ARMARX_TRACE;
221  static std::unordered_map<std::pair<Identification1, Identification2>, FuncType,
222  boost::hash<std::pair<Identification1, Identification2>>> s;
223  return s;
224  }
225  };
226 }
227 
armarx::Factory::Registrar
Definition: SelfRegisteringFactory.h:75
armarx::control::njoint_controller::platform::platform_follower_controller::Registration
const armarx::NJointControllerRegistration< Controller > Registration(NAME)
armarx::Factory2D::Registrar::registered
static const bool registered
Definition: SelfRegisteringFactory.h:174
ctti.h
armarx::Factory::Registrar::registered
static const bool registered
Definition: SelfRegisteringFactory.h:91
armarx::Factory
Definition: SelfRegisteringFactory.h:50
armarx::Factory::make
static auto make(const Identification &s, Args &&... args)
Definition: SelfRegisteringFactory.h:58
TemplateMetaProgramming.h
trace.h
armarx::Factory2D::make
static auto make(const Identification1 &f, const Identification2 &s, Args &&... args)
Definition: SelfRegisteringFactory.h:149
armarx::Factory2D::Registrar
Definition: SelfRegisteringFactory.h:158
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
armarx::Factory2D::Base
friend Base
Definition: SelfRegisteringFactory.h:202
ARMARX_TRACE
#define ARMARX_TRACE
Definition: trace.h:69
armarx::Factory2D::Registrar::Derived
friend Derived
Definition: SelfRegisteringFactory.h:161
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
armarx::Factory2D
Definition: SelfRegisteringFactory.h:139
armarx::Factory::Registrar::registerT
static bool registerT()
Definition: SelfRegisteringFactory.h:80
armarx::meta::is_streamable
Definition: TemplateMetaProgramming.h:304
armarx::Factory::Registrar::Derived
friend Derived
Definition: SelfRegisteringFactory.h:78
armarx::Factory::Registrar::getID
const Identification getID() const override
Definition: SelfRegisteringFactory.h:93
ExpressionException.h
armarx::Factory::~Factory
virtual ~Factory()=default
armarx::Factory2D::Registrar::registerT
static bool registerT()
Definition: SelfRegisteringFactory.h:163
armarx::Factory2D::Registrar::getFirstID
const Identification1 getFirstID() const override
Definition: SelfRegisteringFactory.h:176
armarx::Registrar
Stores key object pairs.
Definition: Registrar.h:62
armarx::Factory2D::getFirstID
virtual const Identification1 getFirstID() const =0
armarx::Factory::Base
friend Base
Definition: SelfRegisteringFactory.h:114
armarx::Factory2D::getSecondID
virtual const Identification2 getSecondID() const =0
armarx::Factory2D::~Factory2D
virtual ~Factory2D()=default
armarx::Factory::getID
virtual const Identification getID() const =0
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
armarx::Factory2D::Registrar::getSecondID
const Identification2 getSecondID() const override
Definition: SelfRegisteringFactory.h:181