My Project
factory.hh
Go to the documentation of this file.
1 /* -*- mia-c++ -*-
2  *
3  * This file is part of MIA - a toolbox for medical image analysis
4  * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
5  *
6  * MIA is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with MIA; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #ifndef mia_core_factory_hh
22 #define mia_core_factory_hh
23 
24 #include <iostream>
25 #include <memory>
26 #include <string>
27 #include <mia/core/handler.hh>
28 #include <mia/core/msgstream.hh>
29 #include <mia/core/errormacro.hh>
30 #include <mia/core/product_base.hh>
31 #include <mia/core/optionparser.hh>
32 #include <mia/core/productcache.hh>
33 #include <mia/core/traits.hh>
35 
37 
38 
48 template <typename P>
50  public TPlugin<typename P::plugin_data, typename P::plugin_type>
51 {
52 public:
53 
55  typedef P Product;
56 
58  typedef std::shared_ptr<P > SharedProduct;
59 
60 
62  typedef std::unique_ptr<P > UniqueProduct;
63 
67  TFactory(char const *const name);
68 
78  virtual Product *create(const CParsedOptions& options, char const *params) __attribute__((warn_unused_result));
79 
80 private:
81  virtual Product *do_create() const __attribute__((warn_unused_result)) = 0 ;
82  CMutex m_mutex;
83 };
84 
85 
93 template <typename I>
95 {
96 protected:
98 
99 
105 public:
107  typedef typename I::Product Product;
108 
110  typedef typename I::SharedProduct ProductPtr;
111 
113  typedef typename I::UniqueProduct UniqueProduct;
114 
121  ProductPtr produce(const std::string& plugindescr)const;
122 
124  ProductPtr produce(const char *plugindescr) const
125  {
126  return produce(std::string(plugindescr));
127  }
128 
136  UniqueProduct produce_unique(const std::string& plugindescr)const;
137 
139  UniqueProduct produce_unique(const char *plugindescr) const
140  {
141  return produce_unique(std::string(plugindescr));
142  }
143 
149  void set_caching(bool enable) const;
150 
151 
152 private:
153  std::string get_handler_type_string_and_help(std::ostream& os) const;
154 
155  std::string do_get_handler_type_string() const;
156 
157  virtual bool do_validate_parameter_string(const std::string& s) const;
158 
159  typename I::Product *produce_raw(const std::string& plugindescr) const;
160 
161  mutable TProductCache<ProductPtr> m_cache;
162 
163  template <typename Handler, typename Chained, bool chainable>
164  friend struct create_plugin;
165 
166 };
167 
168 /*
169  Implementation of the factory
170 */
171 
172 template <typename I>
173 TFactory<I>::TFactory(char const *const name):
174  TPlugin<typename I::plugin_data, typename I::plugin_type>(name)
175 {
176 }
177 
178 template <typename I>
179 typename TFactory<I>::Product *TFactory<I>::create(const CParsedOptions& options, char const *params)
180 {
181  CScopedLock lock(m_mutex);
182 
183  try {
184  this->set_parameters(options);
185  this->check_parameters();
186  auto product = this->do_create();
187 
188  if (product) {
189  product->set_module(this->get_module());
190  product->set_init_string(params);
191  }
192 
193  return product;
194  } catch (std::length_error& x) {
195  std::stringstream msg;
196  msg << "CParamList::set: Some string was not created properly\n";
197  msg << " options were:\n";
198 
199  for (auto i = options.begin();
200  i != options.end(); ++i) {
201  msg << " " << i->first << "=" << i->second << "\n";
202  }
203 
204  cverr() << msg.str();
205  throw std::logic_error("Probably a race condition");
206  }
207 }
208 
209 template <typename I>
211  m_cache(this->get_descriptor())
212 {
213  set_caching(__cache_policy<I>::apply());
214 }
215 
216 template <typename I>
218 {
219  cvdebug() << this->get_descriptor() << ":Set cache policy to " << enable << "\n";
220  m_cache.enable_write(enable);
221 }
222 
223 template <typename I>
225 TFactoryPluginHandler<I>::produce(const std::string& plugindescr) const
226 {
227  auto result = m_cache.get(plugindescr);
228 
229  if (!result) {
230  result.reset(this->produce_raw(plugindescr));
231  m_cache.add(plugindescr, result);
232  } else
233  cvdebug() << "Use cached '" << plugindescr << "'\n";
234 
235  return result;
236 }
237 
238 template <typename I>
240 TFactoryPluginHandler<I>::produce_unique(const std::string& plugindescr) const
241 {
242  return UniqueProduct(this->produce_raw(plugindescr));
243 }
244 
245 template <typename I>
246 std::string TFactoryPluginHandler<I>::get_handler_type_string_and_help(std::ostream& os) const
247 {
248  os << " The string value will be used to construct a plug-in.";
249  return do_get_handler_type_string();
250 }
251 
252 template <typename I>
254 {
255  return "factory";
256 }
257 
258 template <typename I>
259 bool TFactoryPluginHandler<I>::do_validate_parameter_string(const std::string& s) const
260 {
261  cvdebug() << "Check whether factory '" << this->get_descriptor() << "' can understand '" << s << "'\n";
262  // find the part describing the plug-in name and check whether it
263  // is available
264  auto colon_pos = s.find(':');
265  auto plugin_name = s.substr(0, colon_pos);
266 
267  if (this->plugin(plugin_name.c_str()))
268  return true;
269 
270  return false;
271 }
272 
273 template <typename Handler, typename Chained, bool chainable>
275  typedef typename Handler::Product Product;
276  static Product *apply(const Handler& h, const CComplexOptionParser& param_list, const std::string& params)
277  {
278  if (param_list.size() > 1) {
279  throw create_exception<std::invalid_argument>( "Factory ", h.get_descriptor(),
280  ": No chaining supported but ", param_list.size(),
281  " plugin descriptors were given. "
282  "If the description contains a '+' sign as part "
283  "of a parameter you must protect it by enclosing the "
284  "value in square brackets like this: [1e+6]");
285  }
286 
287  cvdebug() << "TFactoryPluginHandler<P>::produce use '" << param_list.begin()->first << "'\n";
288  const std::string& factory_name = param_list.begin()->first;
289 
290  if (factory_name == plugin_help) {
291  cvdebug() << "print help\n";
292  cvmsg() << "\n";
293  h.print_help(cverb);
294  return nullptr;
295  }
296 
297  cvdebug() << "TFactoryPluginHandler<" << h.get_descriptor() << ">::produce: "
298  "Create plugin from '" << factory_name << "'\n";
299  auto factory = h.plugin(factory_name.c_str());
300 
301  if (!factory)
302  throw create_exception<std::invalid_argument>("Factory ", h.get_descriptor(),
303  ":Unable to find plugin for '", factory_name, "'");
304 
305  return factory->create(param_list.begin()->second, params.c_str());
306  }
307 };
308 
309 template <typename Handler, typename ProductChained>
310 struct create_plugin<Handler, ProductChained, true> {
311  typedef typename Handler::Product Product;
312 
313  static Product *apply(const Handler& h, const CComplexOptionParser& param_list, const std::string& params)
314  {
315  if (param_list.size() == 1)
316  return create_plugin<Handler, ProductChained, false>::apply(h, param_list, params);
317 
318  ProductChained *result = new ProductChained();
319 
320  try {
321  for (auto ipl = param_list.begin(); ipl != param_list.end(); ++ipl) {
322  const std::string& factory_name = ipl->first;
323  cvdebug() << "TFactoryPluginHandler<P>::produce use '" << factory_name << "\n";
324 
325  if (factory_name == plugin_help) {
326  cvdebug() << "print help\n";
327  cvmsg() << "\n";
328  h.print_help(cverb);
329  delete result;
330  return nullptr;
331  }
332 
333  auto factory = h.plugin(factory_name.c_str());
334 
335  if (!factory) {
336  delete result;
337  throw create_exception<std::invalid_argument>("Factory ", h.get_descriptor(),
338  "Unable to find plugin for '", factory_name, "'");
339  }
340 
341  auto r = factory->create(ipl->second, params.c_str());
342  result->push_back(typename Product::Pointer(r));
343  }
344 
345  result->set_init_string(params.c_str());
346  } catch (std::exception& x) {
347  delete result;
348  throw x;
349  }
350 
351  return result;
352  }
353 };
354 
355 
356 template <typename I>
357 typename I::Product *TFactoryPluginHandler<I>::produce_raw(const std::string& params)const
358 {
359  if (params.empty()) {
360  throw create_exception<std::invalid_argument>("Factory ", this->get_descriptor(), ": Empty description string given. "
361  "Supported plug-ins are '", this->get_plugin_names(), "'. "
362  "Set description to 'help' for more information.");
363  }
364 
365  CComplexOptionParser param_list(params);
366 
367  if (param_list.size() < 1) {
368  throw create_exception<std::invalid_argument>( "Factory ", this->get_descriptor(), ": Description string '"
369  , params, "' can not be interpreted. "
370  "Supported plug-ins are '", this->get_plugin_names(), "'. "
371  "Set description to 'help' for more information.");
372  }
373 
376  plugin_can_chain<I>::value>::apply(*this, param_list, params);
377 }
378 
383 #define EXPLICIT_INSTANCE_PLUGIN(T) \
384  template class TPlugin<T::plugin_data, T::plugin_type>; \
385  template class TFactory<T>;
386 
391 #define EXPLICIT_INSTANCE_PLUGIN_HANDLER(P) \
392  template class TPluginHandler<P>; \
393  template class TFactoryPluginHandler<P>; \
394  template class THandlerSingleton<TFactoryPluginHandler<P> >;
395 
401 #define EXPLICIT_INSTANCE_HANDLER(T) \
402  template class TPlugin<T::plugin_data, T::plugin_type>; \
403  template class TFactory<T>; \
404  template class TPluginHandler<TFactory<T> >; \
405  template class TFactoryPluginHandler<TFactory<T> >; \
406  template class THandlerSingleton<TFactoryPluginHandler<TFactory<T> > >;
407 
414 #define EXPLICIT_INSTANCE_DERIVED_FACTORY_HANDLER(T, F) \
415  template class TPlugin<T::plugin_data, T::plugin_type>; \
416  template class TFactory<T>; \
417  template class TPluginHandler<F>; \
418  template class TFactoryPluginHandler<F>; \
419  template class THandlerSingleton<TFactoryPluginHandler<F> >;
420 
421 
422 
424 #endif
The time step class for time-marching registration algorithms.
Definition: 2d/timestep.hh:43
Parser for complex command line options.
Definition: optionparser.hh:56
const_iterator begin() const
const_iterator end() const
CParts::size_type size() const
the Base class for all plugn handlers that deal with factory plugins.
Definition: factory.hh:95
I::Product Product
The type of the the object this plug in hander produces.
Definition: factory.hh:107
ProductPtr produce(const std::string &plugindescr) const
Definition: factory.hh:225
void set_caching(bool enable) const
Definition: factory.hh:217
UniqueProduct produce_unique(const char *plugindescr) const
Definition: factory.hh:139
UniqueProduct produce_unique(const std::string &plugindescr) const
Definition: factory.hh:240
I::UniqueProduct UniqueProduct
The unique pointer type of the the object this plug in hander produces.
Definition: factory.hh:113
ProductPtr produce(const char *plugindescr) const
Definition: factory.hh:124
TFactoryPluginHandler()
Initializes the plugin handler.
Definition: factory.hh:210
I::SharedProduct ProductPtr
The shared pointer type of the the object this plug in hander produces.
Definition: factory.hh:110
This is tha base of all plugins that create "things", like filters, cost functions time step operator...
Definition: factory.hh:51
P Product
typedef to describe the product of the factory
Definition: factory.hh:55
std::shared_ptr< P > SharedProduct
typedef for the shared version of the product
Definition: factory.hh:58
virtual Product * create(const CParsedOptions &options, char const *params) __attribute__((warn_unused_result))
Definition: factory.hh:179
TFactory(char const *const name)
Definition: factory.hh:173
std::unique_ptr< P > UniqueProduct
typedef for the unique version of the product
Definition: factory.hh:62
The basic template of all plugin handlers.
Definition: handler.hh:57
The generic base for all plug-ins.
Definition: plugin_base.hh:172
The type specific product cache.
Definition: productcache.hh:80
#define EXPORT_HANDLER
Definition: core/cost.hh:32
#define NS_MIA_BEGIN
conveniance define to start the mia namespace
Definition: defines.hh:33
#define NS_MIA_END
conveniance define to end the mia namespace
Definition: defines.hh:36
std::map< std::string, std::string > CParsedOptions
Definition: optionparser.hh:38
vstream & cvmsg()
send messages to this stream adapter
Definition: msgstream.hh:331
#define cverb
define a shortcut to the raw output stream
Definition: msgstream.hh:341
vstream & cverr()
send errors to this stream adapter
Definition: msgstream.hh:311
CDebugSink & cvdebug()
Definition: msgstream.hh:226
std::mutex CMutex
EXPORT_CORE const std::string plugin_help
standard string to print out help in the factory plug-in handler
static Product * apply(const Handler &h, const CComplexOptionParser &param_list, const std::string &params)
Definition: factory.hh:313
static Product * apply(const Handler &h, const CComplexOptionParser &param_list, const std::string &params)
Definition: factory.hh:276
Handler::Product Product
Definition: factory.hh:275