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-2013 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 public:
52 
54  typedef P Product;
55 
57  typedef std::shared_ptr<P > SharedProduct;
58 
59 
61  typedef std::unique_ptr<P > UniqueProduct;
62 
66  TFactory(char const * const name);
67 
77  virtual Product *create(const CParsedOptions& options, char const *params) __attribute__((warn_unused_result));
78 
79 private:
80  virtual Product *do_create() const __attribute__((warn_unused_result)) = 0 ;
81  CMutex m_mutex;
82 };
83 
84 
92 template <typename I>
94 protected:
96 
97 
103 public:
105  typedef typename I::Product Product;
106 
108  typedef typename I::SharedProduct ProductPtr;
109 
111  typedef typename I::UniqueProduct UniqueProduct;
112 
119  ProductPtr produce(const std::string& plugindescr)const;
120 
122  ProductPtr produce(const char *plugindescr) const{
123  return produce(std::string(plugindescr));
124  }
125 
133  UniqueProduct produce_unique(const std::string& plugindescr)const;
134 
136  UniqueProduct produce_unique(const char *plugindescr) const{
137  return produce_unique(std::string(plugindescr));
138  }
139 
145  void set_caching(bool enable) const;
146 
147 
148 private:
149  std::string get_handler_type_string_and_help(std::ostream& os) const;
150 
151  std::string do_get_handler_type_string() const;
152 
153  typename I::Product *produce_raw(const std::string& plugindescr) const;
154 
155  mutable TProductCache<ProductPtr> m_cache;
156 
157 };
158 
159 /*
160  Implementation of the factory
161 */
162 
163 template <typename I>
164 TFactory<I>::TFactory(char const * const name):
165  TPlugin<typename I::plugin_data, typename I::plugin_type>(name)
166 {
167 }
168 
169 template <typename I>
170 typename TFactory<I>::Product *TFactory<I>::create(const CParsedOptions& options, char const *params)
171 {
172  CScopedLock lock(m_mutex);
173  try {
174  this->set_parameters(options);
175  this->check_parameters();
176  auto product = this->do_create();
177  if (product) {
178  product->set_module(this->get_module());
179  product->set_init_string(params);
180  }
181  return product;
182  }
183  catch (std::length_error& x) {
184  std::stringstream msg;
185  msg << "CParamList::set: Some string was not created properly\n";
186  msg << " options were:\n";
187  for (auto i = options.begin();
188  i != options.end(); ++i) {
189  msg << " " << i->first << "=" << i->second << "\n";
190  }
191  cverr() << msg.str();
192  throw std::logic_error("Probably a race condition");
193 
194  }
195 }
196 
197 template <typename I>
199  m_cache(this->get_descriptor())
200 {
201  set_caching(__cache_policy<I>::apply());
202 }
203 
204 template <typename I>
206 {
207  cvdebug() << this->get_descriptor() << ":Set cache policy to " << enable << "\n";
208  m_cache.enable_write(enable);
209 }
210 
211 template <typename I>
213 TFactoryPluginHandler<I>::produce(const std::string& plugindescr) const
214 {
215  auto result = m_cache.get(plugindescr);
216  if (!result) {
217  result.reset(this->produce_raw(plugindescr));
218  m_cache.add(plugindescr, result);
219  }else
220  cvdebug() << "Use cached '" << plugindescr << "'\n";
221  return result;
222 }
223 
224 template <typename I>
226 TFactoryPluginHandler<I>::produce_unique(const std::string& plugindescr) const
227 {
228  return UniqueProduct(this->produce_raw(plugindescr));
229 }
230 
231 template <typename I>
232 std::string TFactoryPluginHandler<I>::get_handler_type_string_and_help(std::ostream& os) const
233 {
234  os << " The string value will be used to construct a plug-in.";
235  return do_get_handler_type_string();
236 }
237 
238 template <typename I>
240 {
241  return "factory";
242 }
243 
244 template <typename I>
245 typename I::Product *TFactoryPluginHandler<I>::produce_raw(const std::string& params)const
246 {
247  if (params.empty()) {
248  throw create_exception<std::invalid_argument>("Factory ", this->get_descriptor(), ": Empty description string given. "
249  "Supported plug-ins are '", this->get_plugin_names(), "'. "
250  "Set description to 'help' for more information.");
251  }
252 
253  CComplexOptionParser param_list(params);
254 
255  if (param_list.size() < 1) {
256  throw create_exception<std::invalid_argument>( "Factory " , this->get_descriptor(), ": Description string '"
257  , params , "' can not be interpreted. "
258  "Supported plug-ins are '" , this->get_plugin_names() , "'. "
259  "Set description to 'help' for more information.");
260  }
261 
262  cvdebug() << "TFactoryPluginHandler<P>::produce use '" << param_list.begin()->first << "'\n";
263  const std::string& factory_name = param_list.begin()->first;
264 
265  if (factory_name == plugin_help) {
266  cvdebug() << "print help\n";
267  cvmsg() << "\n";
268  this->print_help(cverb);
269  return NULL;
270  }
271 
272  cvdebug() << "TFactoryPluginHandler<>::produce: Create plugin from '" << factory_name << "'\n";
273 
274  auto factory = this->plugin(factory_name.c_str());
275  DEBUG_ASSERT_RELEASE_THROW(factory, "A plug-in was not found but 'this->plugin' did not throw");
276  return factory->create(param_list.begin()->second,params.c_str());
277 
278 }
279 
284 #define EXPLICIT_INSTANCE_PLUGIN(T) \
285  template class TPlugin<T::plugin_data, T::plugin_type>; \
286  template class TFactory<T>;
287 
292 #define EXPLICIT_INSTANCE_PLUGIN_HANDLER(P) \
293  template class TPluginHandler<P>; \
294  template class TFactoryPluginHandler<P>; \
295  template class THandlerSingleton<TFactoryPluginHandler<P> >;
296 
302 #define EXPLICIT_INSTANCE_HANDLER(T) \
303  template class TPlugin<T::plugin_data, T::plugin_type>; \
304  template class TFactory<T>; \
305  template class TPluginHandler<TFactory<T> >; \
306  template class TFactoryPluginHandler<TFactory<T> >; \
307  template class THandlerSingleton<TFactoryPluginHandler<TFactory<T> > >;
308 
315 #define EXPLICIT_INSTANCE_DERIVED_FACTORY_HANDLER(T, F) \
316  template class TPlugin<T::plugin_data, T::plugin_type>; \
317  template class TFactory<T>; \
318  template class TPluginHandler<F>; \
319  template class TFactoryPluginHandler<F>; \
320  template class THandlerSingleton<TFactoryPluginHandler<F> >;
321 
322 
323 
325 #endif