factory.hh
Go to the documentation of this file.
/* -*- mia-c++ -*-
*
* This file is part of MIA - a toolbox for medical image analysis
* Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
*
* MIA is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MIA; if not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef mia_core_factory_hh
#define mia_core_factory_hh
#include <iostream>
#include <memory>
#include <string>
#include <mia/core/handler.hh>
#include <mia/core/msgstream.hh>
#include <mia/core/errormacro.hh>
#include <mia/core/product_base.hh>
#include <mia/core/optionparser.hh>
#include <mia/core/productcache.hh>
#include <mia/core/traits.hh>
#include <mia/core/import_handler.hh>
NS_MIA_BEGIN
template <typename P>
class EXPORT_HANDLER TFactory:
public TPlugin<typename P::plugin_data, typename P::plugin_type>
{
public:
typedef P Product;
typedef std::shared_ptr<P > SharedProduct;
typedef std::unique_ptr<P > UniqueProduct;
TFactory(char const *const name);
virtual Product *create(const CParsedOptions& options, char const *params) __attribute__((warn_unused_result));
private:
virtual Product *do_create() const __attribute__((warn_unused_result)) = 0 ;
CMutex m_mutex;
};
template <typename I>
class EXPORT_HANDLER TFactoryPluginHandler: public TPluginHandler< I >
{
protected:
TFactoryPluginHandler();
public:
typedef typename I::Product Product;
typedef typename I::SharedProduct ProductPtr;
typedef typename I::UniqueProduct UniqueProduct;
ProductPtr produce(const std::string& plugindescr)const;
ProductPtr produce(const char *plugindescr) const
{
return produce(std::string(plugindescr));
}
UniqueProduct produce_unique(const std::string& plugindescr)const;
UniqueProduct produce_unique(const char *plugindescr) const
{
return produce_unique(std::string(plugindescr));
}
void set_caching(bool enable) const;
private:
std::string get_handler_type_string_and_help(std::ostream& os) const;
std::string do_get_handler_type_string() const;
virtual bool do_validate_parameter_string(const std::string& s) const;
typename I::Product *produce_raw(const std::string& plugindescr) const;
mutable TProductCache<ProductPtr> m_cache;
template <typename Handler, typename Chained, bool chainable>
friend struct create_plugin;
};
/*
Implementation of the factory
*/
template <typename I>
TFactory<I>::TFactory(char const *const name):
TPlugin<typename I::plugin_data, typename I::plugin_type>(name)
{
}
template <typename I>
typename TFactory<I>::Product *TFactory<I>::create(const CParsedOptions& options, char const *params)
{
CScopedLock lock(m_mutex);
try {
this->set_parameters(options);
this->check_parameters();
auto product = this->do_create();
if (product) {
product->set_module(this->get_module());
product->set_init_string(params);
}
return product;
} catch (std::length_error& x) {
std::stringstream msg;
msg << "CParamList::set: Some string was not created properly\n";
msg << " options were:\n";
for (auto i = options.begin();
i != options.end(); ++i) {
msg << " " << i->first << "=" << i->second << "\n";
}
cverr() << msg.str();
throw std::logic_error("Probably a race condition");
}
}
template <typename I>
TFactoryPluginHandler<I>::TFactoryPluginHandler():
m_cache(this->get_descriptor())
{
set_caching(__cache_policy<I>::apply());
}
template <typename I>
void TFactoryPluginHandler<I>::set_caching(bool enable) const
{
cvdebug() << this->get_descriptor() << ":Set cache policy to " << enable << "\n";
m_cache.enable_write(enable);
}
template <typename I>
typename TFactoryPluginHandler<I>::ProductPtr
TFactoryPluginHandler<I>::produce(const std::string& plugindescr) const
{
auto result = m_cache.get(plugindescr);
if (!result) {
result.reset(this->produce_raw(plugindescr));
m_cache.add(plugindescr, result);
} else
cvdebug() << "Use cached '" << plugindescr << "'\n";
return result;
}
template <typename I>
typename TFactoryPluginHandler<I>::UniqueProduct
TFactoryPluginHandler<I>::produce_unique(const std::string& plugindescr) const
{
return UniqueProduct(this->produce_raw(plugindescr));
}
template <typename I>
std::string TFactoryPluginHandler<I>::get_handler_type_string_and_help(std::ostream& os) const
{
os << " The string value will be used to construct a plug-in.";
return do_get_handler_type_string();
}
template <typename I>
std::string TFactoryPluginHandler<I>::do_get_handler_type_string() const
{
return "factory";
}
template <typename I>
bool TFactoryPluginHandler<I>::do_validate_parameter_string(const std::string& s) const
{
cvdebug() << "Check whether factory '" << this->get_descriptor() << "' can understand '" << s << "'\n";
// find the part describing the plug-in name and check whether it
// is available
auto colon_pos = s.find(':');
auto plugin_name = s.substr(0, colon_pos);
if (this->plugin(plugin_name.c_str()))
return true;
return false;
}
template <typename Handler, typename Chained, bool chainable>
struct create_plugin {
typedef typename Handler::Product Product;
static Product *apply(const Handler& h, const CComplexOptionParser& param_list, const std::string& params)
{
if (param_list.size() > 1) {
throw create_exception<std::invalid_argument>( "Factory ", h.get_descriptor(),
": No chaining supported but ", param_list.size(),
" plugin descriptors were given. "
"If the description contains a '+' sign as part "
"of a parameter you must protect it by enclosing the "
"value in square brackets like this: [1e+6]");
}
cvdebug() << "TFactoryPluginHandler<P>::produce use '" << param_list.begin()->first << "'\n";
const std::string& factory_name = param_list.begin()->first;
if (factory_name == plugin_help) {
cvdebug() << "print help\n";
cvmsg() << "\n";
h.print_help(cverb);
return nullptr;
}
cvdebug() << "TFactoryPluginHandler<" << h.get_descriptor() << ">::produce: "
"Create plugin from '" << factory_name << "'\n";
auto factory = h.plugin(factory_name.c_str());
if (!factory)
throw create_exception<std::invalid_argument>("Factory ", h.get_descriptor(),
":Unable to find plugin for '", factory_name, "'");
return factory->create(param_list.begin()->second, params.c_str());
}
};
template <typename Handler, typename ProductChained>
struct create_plugin<Handler, ProductChained, true> {
typedef typename Handler::Product Product;
static Product *apply(const Handler& h, const CComplexOptionParser& param_list, const std::string& params)
{
if (param_list.size() == 1)
return create_plugin<Handler, ProductChained, false>::apply(h, param_list, params);
ProductChained *result = new ProductChained();
try {
for (auto ipl = param_list.begin(); ipl != param_list.end(); ++ipl) {
const std::string& factory_name = ipl->first;
cvdebug() << "TFactoryPluginHandler<P>::produce use '" << factory_name << "\n";
if (factory_name == plugin_help) {
cvdebug() << "print help\n";
cvmsg() << "\n";
h.print_help(cverb);
delete result;
return nullptr;
}
auto factory = h.plugin(factory_name.c_str());
if (!factory) {
delete result;
throw create_exception<std::invalid_argument>("Factory ", h.get_descriptor(),
"Unable to find plugin for '", factory_name, "'");
}
auto r = factory->create(ipl->second, params.c_str());
result->push_back(typename Product::Pointer(r));
}
result->set_init_string(params.c_str());
} catch (std::exception& x) {
delete result;
throw x;
}
return result;
}
};
template <typename I>
typename I::Product *TFactoryPluginHandler<I>::produce_raw(const std::string& params)const
{
if (params.empty()) {
throw create_exception<std::invalid_argument>("Factory ", this->get_descriptor(), ": Empty description string given. "
"Supported plug-ins are '", this->get_plugin_names(), "'. "
"Set description to 'help' for more information.");
}
CComplexOptionParser param_list(params);
if (param_list.size() < 1) {
throw create_exception<std::invalid_argument>( "Factory ", this->get_descriptor(), ": Description string '"
, params, "' can not be interpreted. "
"Supported plug-ins are '", this->get_plugin_names(), "'. "
"Set description to 'help' for more information.");
}
return create_plugin<TFactoryPluginHandler<I>,
typename plugin_can_chain<I>::Chained,
plugin_can_chain<I>::value>::apply(*this, param_list, params);
}
#define EXPLICIT_INSTANCE_PLUGIN(T) \
template class TPlugin<T::plugin_data, T::plugin_type>; \
template class TFactory<T>;
#define EXPLICIT_INSTANCE_PLUGIN_HANDLER(P) \
template class TPluginHandler<P>; \
template class TFactoryPluginHandler<P>; \
template class THandlerSingleton<TFactoryPluginHandler<P> >;
#define EXPLICIT_INSTANCE_HANDLER(T) \
template class TPlugin<T::plugin_data, T::plugin_type>; \
template class TFactory<T>; \
template class TPluginHandler<TFactory<T> >; \
template class TFactoryPluginHandler<TFactory<T> >; \
template class THandlerSingleton<TFactoryPluginHandler<TFactory<T> > >;
#define EXPLICIT_INSTANCE_DERIVED_FACTORY_HANDLER(T, F) \
template class TPlugin<T::plugin_data, T::plugin_type>; \
template class TFactory<T>; \
template class TPluginHandler<F>; \
template class TFactoryPluginHandler<F>; \
template class THandlerSingleton<TFactoryPluginHandler<F> >;
NS_MIA_END
#endif
CComplexOptionParser
Parser for complex command line options.
Definition optionparser.hh:56
CComplexOptionParser::begin
const_iterator begin() const
CComplexOptionParser::end
const_iterator end() const
CComplexOptionParser::size
CParts::size_type size() const
CParamTranslator::set_parameters
void set_parameters(const CParsedOptions &options)
CParamTranslator::check_parameters
void check_parameters()
CPluginBase::get_module
PPluginModule get_module() const
CPluginHandlerBase::get_descriptor
const std::string & get_descriptor() const
TFactoryPluginHandler::Product
I::Product Product
The type of the the object this plug in hander produces.
Definition factory.hh:107
TFactoryPluginHandler::produce
ProductPtr produce(const std::string &plugindescr) const
Definition factory.hh:225
TFactoryPluginHandler::set_caching
void set_caching(bool enable) const
Definition factory.hh:217
TFactoryPluginHandler::produce_unique
UniqueProduct produce_unique(const char *plugindescr) const
Definition factory.hh:139
TFactoryPluginHandler::produce_unique
UniqueProduct produce_unique(const std::string &plugindescr) const
Definition factory.hh:240
TFactoryPluginHandler::UniqueProduct
I::UniqueProduct UniqueProduct
The unique pointer type of the the object this plug in hander produces.
Definition factory.hh:113
TFactoryPluginHandler::produce
ProductPtr produce(const char *plugindescr) const
Definition factory.hh:124
TFactoryPluginHandler::create_plugin
friend struct create_plugin
Definition factory.hh:164
TFactoryPluginHandler::TFactoryPluginHandler
TFactoryPluginHandler()
Initializes the plugin handler.
Definition factory.hh:210
TFactoryPluginHandler::ProductPtr
I::SharedProduct ProductPtr
The shared pointer type of the the object this plug in hander produces.
Definition factory.hh:110
TFactory< CMeans::Initializer >::Product
CMeans::Initializer Product
Definition factory.hh:55
TFactory< CMeans::Initializer >::SharedProduct
std::shared_ptr< CMeans::Initializer > SharedProduct
Definition factory.hh:58
TFactory::create
virtual Product * create(const CParsedOptions &options, char const *params) __attribute__((warn_unused_result))
Definition factory.hh:179
TFactory::TFactory
TFactory(char const *const name)
Definition factory.hh:173
TFactory< CMeans::Initializer >::UniqueProduct
std::unique_ptr< CMeans::Initializer > UniqueProduct
Definition factory.hh:62
TPluginHandler::TPluginHandler
TPluginHandler()
Initializes the plugin handler based on the build-in search path.
TPlugin< P::plugin_data, P::plugin_type >::TPlugin
TPlugin(const char *name)
TProductCache
The type specific product cache.
Definition productcache.hh:80
EXPORT_HANDLER
#define EXPORT_HANDLER
Definition core/cost.hh:32
NS_MIA_BEGIN
#define NS_MIA_BEGIN
conveniance define to start the mia namespace
Definition defines.hh:33
NS_MIA_END
#define NS_MIA_END
conveniance define to end the mia namespace
Definition defines.hh:36
errormacro.hh
CParsedOptions
std::map< std::string, std::string > CParsedOptions
Definition optionparser.hh:38
cverr
vstream & cverr()
send errors to this stream adapter
Definition msgstream.hh:311
cverb
#define cverb
define a shortcut to the raw output stream
Definition msgstream.hh:341
cvmsg
vstream & cvmsg()
send messages to this stream adapter
Definition msgstream.hh:331
create_exception
E create_exception(T ...t)
helper template to create exceptions with complex messages
Definition errormacro.hh:80
handler.hh
import_handler.hh
msgstream.hh
cvdebug
CDebugSink & cvdebug()
Definition msgstream.hh:226
optionparser.hh
CMutex
std::mutex CMutex
Definition parallelcxx11.hh:34
CScopedLock
TScopedLock< CMutex > CScopedLock
Definition parallelcxx11.hh:80
plugin_help
EXPORT_CORE const std::string plugin_help
standard string to print out help in the factory plug-in handler
product_base.hh
productcache.hh
create_plugin< Handler, ProductChained, true >::Product
Handler::Product Product
Definition factory.hh:311
create_plugin< Handler, ProductChained, true >::apply
static Product * apply(const Handler &h, const CComplexOptionParser &param_list, const std::string &params)
Definition factory.hh:313
create_plugin
Definition factory.hh:274
create_plugin::Product
Handler::Product Product
Definition factory.hh:275
create_plugin::apply
static Product * apply(const Handler &h, const CComplexOptionParser &param_list, const std::string &params)
Definition factory.hh:276
plugin_can_chain::value
static constexpr bool value
Definition plugin_base.hh:211
plugin_can_chain::Chained
void Chained
Definition plugin_base.hh:212
traits.hh