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>
33#include <mia/core/traits.hh>
35
37
38
48template <typename P>
50 public TPlugin<typename P::plugin_data, typename P::plugin_type>
51{
52public:
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
80private:
81 virtual Product *do_create() const __attribute__((warn_unused_result)) = 0 ;
82 CMutex m_mutex;
83};
84
85
93template <typename I>
95{
96protected:
98
99
105public:
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
152private:
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
172template <typename I>
173TFactory<I>::TFactory(char const *const name):
174 TPlugin<typename I::plugin_data, typename I::plugin_type>(name)
175{
176}
177
178template <typename I>
179typename 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
209template <typename I>
211 m_cache(this->get_descriptor())
212{
213 set_caching(__cache_policy<I>::apply());
214}
215
216template <typename I>
218{
219 cvdebug() << this->get_descriptor() << ":Set cache policy to " << enable << "\n";
220 m_cache.enable_write(enable);
221}
222
223template <typename I>
225TFactoryPluginHandler<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
238template <typename I>
240TFactoryPluginHandler<I>::produce_unique(const std::string& plugindescr) const
241{
242 return UniqueProduct(this->produce_raw(plugindescr));
243}
244
245template <typename I>
246std::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
252template <typename I>
254{
255 return "factory";
256}
257
258template <typename I>
259bool 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
273template <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
309template <typename Handler, typename ProductChained>
310struct 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
356template <typename I>
357typename 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 class to provide filtering of series of 2D images as if they where 3D images.
Parser for complex command line options.
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.
The type specific product cache.
#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
vstream & cverr()
send errors to this stream adapter
Definition msgstream.hh:311
#define cverb
define a shortcut to the raw output stream
Definition msgstream.hh:341
vstream & cvmsg()
send messages to this stream adapter
Definition msgstream.hh:331
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
Handler::Product Product
Definition factory.hh:275
static Product * apply(const Handler &h, const CComplexOptionParser &param_list, const std::string &params)
Definition factory.hh:276