libpointmatcher  1.1.0
Registrar.h
00001 // kate: replace-tabs off; indent-width 4; indent-mode normal
00002 // vim: ts=4:sw=4:noexpandtab
00003 /*
00004 
00005 Copyright (c) 2010--2012,
00006 François Pomerleau and Stephane Magnenat, ASL, ETHZ, Switzerland
00007 You can contact the authors at <f dot pomerleau at gmail dot com> and
00008 <stephane at magnenat dot net>
00009 
00010 All rights reserved.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014     * Redistributions of source code must retain the above copyright
00015       notice, this list of conditions and the following disclaimer.
00016     * Redistributions in binary form must reproduce the above copyright
00017       notice, this list of conditions and the following disclaimer in the
00018       documentation and/or other materials provided with the distribution.
00019     * Neither the name of the <organization> nor the
00020       names of its contributors may be used to endorse or promote products
00021       derived from this software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00026 DISCLAIMED. IN NO EVENT SHALL ETH-ASL BE LIABLE FOR ANY
00027 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00028 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00030 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00031 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00032 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00033 
00034 */
00035 
00036 #ifndef __POINTMATCHER_REGISTRAR_H
00037 #define __POINTMATCHER_REGISTRAR_H
00038 
00039 #include "Parametrizable.h"
00040 #include "PointMatcher.h"
00041 #include <boost/format.hpp>
00042 #include <boost/typeof/typeof.hpp>
00043 
00044 #ifdef HAVE_YAML_CPP
00045     #include "yaml-cpp/yaml.h"
00046 #endif // HAVE_YAML_CPP
00047 
00048 namespace PointMatcherSupport
00049 {
00051     struct InvalidElement: std::runtime_error
00052     {
00053         InvalidElement(const std::string& reason);
00054     };
00055     
00057     template<typename Interface>
00058     struct Registrar
00059     {
00060     public:
00061         typedef Interface TargetType; 
00062         
00064         struct ClassDescriptor
00065         {
00067             virtual ~ClassDescriptor() {}
00069             virtual Interface* createInstance(const std::string& className, const Parametrizable::Parameters& params) const = 0;
00071             virtual const std::string description() const = 0;
00073             virtual const Parametrizable::ParametersDoc availableParameters() const = 0;
00074         };
00075         
00077         template<typename C>
00078         struct GenericClassDescriptor: public ClassDescriptor
00079         {
00080             virtual Interface* createInstance(const std::string& className, const Parametrizable::Parameters& params) const
00081             {
00082                 C* instance(new C(params));
00083                 
00084                 // check that there was no unsed parameter
00085                 for (BOOST_AUTO(it, params.begin()); it != params.end() ;++it)
00086                 {
00087                     if (instance->parametersUsed.find(it->first) == instance->parametersUsed.end())
00088                         throw Parametrizable::InvalidParameter(
00089                             (boost::format("Parameter %1% for module %2% was set but is not used") % it->first % className).str()
00090                         );
00091                 }
00092                 
00093                 return instance;
00094             }
00095             virtual const std::string description() const
00096             {
00097                 return C::description();
00098             }
00099             virtual const Parametrizable::ParametersDoc availableParameters() const
00100             {
00101                 return C::availableParameters();
00102             }
00103         };
00104         
00106         template<typename C>
00107         struct GenericClassDescriptorNoParam: public ClassDescriptor
00108         {
00109             virtual Interface* createInstance(const std::string& className, const Parametrizable::Parameters& params) const
00110             {
00111                 for (BOOST_AUTO(it, params.begin()); it != params.end() ;++it)
00112                     throw Parametrizable::InvalidParameter(
00113                             (boost::format("Parameter %1% was set but module %2% dos not use any parameter") % it->first % className).str()
00114                         );
00115                 return new C();
00116             }
00117             virtual const std::string description() const
00118             {
00119                 return C::description();
00120             }
00121             virtual const Parametrizable::ParametersDoc availableParameters() const
00122             {
00123                 return Parametrizable::ParametersDoc();
00124             }
00125         };
00126         
00127     protected:
00128         typedef std::map<std::string, ClassDescriptor*> DescriptorMap; 
00129         DescriptorMap classes; 
00130         
00131     public:
00133         ~Registrar()
00134         {
00135             for (BOOST_AUTO(it, classes.begin()); it != classes.end(); ++it)
00136                 delete it->second;
00137         }
00139         void reg(const std::string &name, ClassDescriptor* descriptor)
00140         {
00141             classes[name] = descriptor;
00142         }
00143         
00145         const ClassDescriptor* getDescriptor(const std::string& name) const
00146         {
00147             BOOST_AUTO(it, classes.find(name));
00148             if (it == classes.end())
00149             {
00150                 std::cerr << "No element named " << name << " is registered. Known ones are:\n";
00151                 dump(std::cerr);
00152                 throw InvalidElement(
00153                     (boost::format("Trying to instanciate unknown element %1% from registrar") % name).str()
00154                 );
00155             }
00156             return it->second;
00157         }
00158         
00160         Interface* create(const std::string& name, const Parametrizable::Parameters& params = Parametrizable::Parameters()) const
00161         {
00162             return getDescriptor(name)->createInstance(name, params);
00163         }
00164         
00165         #ifdef HAVE_YAML_CPP
00166         
00168         Interface* createFromYAML(const YAML::Node& module) const
00169         {
00170             Parametrizable::Parameters params;
00171             std::string name;
00172             
00173             if (module.size() != 1)
00174             {
00175                 // parameter-less entry
00176                 name = module.to<std::string>();
00177             }
00178             else
00179             {
00180                 // get parameters
00181                 YAML::Iterator mapIt(module.begin());
00182                 mapIt.first() >> name;
00183                 for(YAML::Iterator paramIt = mapIt.second().begin(); paramIt != mapIt.second().end(); ++paramIt)
00184                 {
00185                     std::string key, value;
00186                     paramIt.first() >> key;
00187                     paramIt.second() >> value;
00188                     params[key] = value;
00189                 }
00190             }
00191             
00192             return create(name, params);
00193         }
00194         
00195         #endif // HAVE_YAML_CPP
00196         
00198         const std::string getDescription(const std::string& name) const
00199         {
00200             return getDescriptor(name)->description();
00201         }
00202         
00204         void dump(std::ostream &stream) const
00205         {
00206             for (BOOST_AUTO(it, classes.begin()); it != classes.end(); ++it)
00207                 stream << "- " << it->first << "\n";
00208         }
00209         
00211         typename DescriptorMap::const_iterator begin() const
00212         {
00213             return classes.begin();
00214         }
00216         typename DescriptorMap::const_iterator end() const
00217         {
00218             return classes.end();
00219         }
00220     };
00221 
00222     #define REG(name) name##Registrar
00223     #define DEF_REGISTRAR(name) PointMatcherSupport::Registrar< name > name##Registrar;
00224     #define DEF_REGISTRAR_IFACE(name, ifaceName) PointMatcherSupport::Registrar< ifaceName > name##Registrar;
00225     #define ADD_TO_REGISTRAR(name, elementName, element) { \
00226         typedef typename PointMatcherSupport::Registrar< name >::template GenericClassDescriptor< element > Desc; \
00227         name##Registrar.reg(# elementName, new Desc() ); \
00228     }
00229     #define ADD_TO_REGISTRAR_NO_PARAM(name, elementName, element) { \
00230         typedef typename PointMatcherSupport::Registrar< name >::template GenericClassDescriptorNoParam< element > Desc; \
00231         name##Registrar.reg(# elementName, new Desc() ); \
00232     }
00233 } // namespace PointMatcherSupport
00234 
00235 #endif // __POINTMATCHER_REGISTRAR_H