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 
48 namespace 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  {
133  ARMARX_TRACE;
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  {
152  ARMARX_TRACE;
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  {
167  ARMARX_TRACE;
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  {
219  ARMARX_TRACE;
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
armarx::Factory::Registrar
Definition: SelfRegisteringFactory.h:79
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:94
armarx::Factory
Definition: SelfRegisteringFactory.h:52
armarx::Factory::make
static auto make(const Identification &s, Args &&... args)
Definition: SelfRegisteringFactory.h:60
TemplateMetaProgramming.h
trace.h
armarx::Factory2D::make
static auto make(const Identification1 &f, const Identification2 &s, Args &&... args)
Definition: SelfRegisteringFactory.h:150
armarx::Factory2D::Registrar
Definition: SelfRegisteringFactory.h:159
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:77
armarx::Factory2D::Registrar::Derived
friend Derived
Definition: SelfRegisteringFactory.h:162
data
uint8_t data[1]
Definition: EtherCATFrame.h:68
armarx::Factory2D
Definition: SelfRegisteringFactory.h:140
armarx::Factory::Registrar::registerT
static bool registerT()
Definition: SelfRegisteringFactory.h:85
armarx::meta::is_streamable
Definition: TemplateMetaProgramming.h:367
armarx::Factory::Registrar::Derived
friend Derived
Definition: SelfRegisteringFactory.h:82
armarx::Factory::Registrar::getID
const Identification getID() const override
Definition: SelfRegisteringFactory.h:97
ExpressionException.h
armarx::Factory::~Factory
virtual ~Factory()=default
armarx::Factory2D::Registrar::registerT
static bool registerT()
Definition: SelfRegisteringFactory.h:165
armarx::Factory2D::Registrar::getFirstID
const Identification1 getFirstID() const override
Definition: SelfRegisteringFactory.h:177
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:116
armarx::Factory2D::getSecondID
virtual const Identification2 getSecondID() const =0
armarx::Factory2D::~Factory2D
virtual ~Factory2D()=default
armarx::Factory::getID
virtual const Identification getID() const =0
Logging.h
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:27
armarx::Factory2D::Registrar::getSecondID
const Identification2 getSecondID() const override
Definition: SelfRegisteringFactory.h:183