Registrar.h
Go to the documentation of this file.
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 
00045 #ifdef SYSTEM_YAML_CPP
00046         namespace YAML
00047         {
00048                 class Node;
00049         }
00050 #else
00051         namespace YAML_PM
00052         {
00053                 class Node;
00054         }
00055     namespace YAML = YAML_PM;
00056 #endif // HAVE_YAML_CPP
00057 
00058 namespace PointMatcherSupport
00059 {
00061         void getNameParamsFromYAML(const YAML::Node& module, std::string& name, Parametrizable::Parameters& params);
00062 
00064         struct InvalidElement: std::runtime_error
00065         {
00066                 InvalidElement(const std::string& reason);
00067         };
00068         
00070         template<typename Interface>
00071         struct Registrar
00072         {
00073         public:
00074                 typedef Interface TargetType; 
00075                 
00077                 struct ClassDescriptor
00078                 {
00080                         virtual ~ClassDescriptor() {}
00082                         virtual Interface* createInstance(const std::string& className, const Parametrizable::Parameters& params) const = 0;
00084                         virtual const std::string description() const = 0;
00086                         virtual const Parametrizable::ParametersDoc availableParameters() const = 0;
00087                 };
00088                 
00090                 template<typename C>
00091                 struct GenericClassDescriptor: public ClassDescriptor
00092                 {
00093                         virtual Interface* createInstance(const std::string& className, const Parametrizable::Parameters& params) const
00094                         {
00095                                 C* instance(new C(params));
00096                                 
00097                                 // check that there was no unsed parameter
00098                                 for (BOOST_AUTO(it, params.begin()); it != params.end() ;++it)
00099                                 {
00100                                         if (instance->parametersUsed.find(it->first) == instance->parametersUsed.end())
00101                                                 throw Parametrizable::InvalidParameter(
00102                                                         (boost::format("Parameter %1% for module %2% was set but is not used") % it->first % className).str()
00103                                                 );
00104                                 }
00105                                 
00106                                 return instance;
00107                         }
00108                         virtual const std::string description() const
00109                         {
00110                                 return C::description();
00111                         }
00112                         virtual const Parametrizable::ParametersDoc availableParameters() const
00113                         {
00114                                 return C::availableParameters();
00115                         }
00116                 };
00117                 
00119                 template<typename C>
00120                 struct GenericClassDescriptorNoParam: public ClassDescriptor
00121                 {
00122                         virtual Interface* createInstance(const std::string& className, const Parametrizable::Parameters& params) const
00123                         {
00124                                 for (BOOST_AUTO(it, params.begin()); it != params.end() ;++it)
00125                                         throw Parametrizable::InvalidParameter(
00126                                                         (boost::format("Parameter %1% was set but module %2% dos not use any parameter") % it->first % className).str()
00127                                                 );
00128                                 return new C();
00129                         }
00130                         virtual const std::string description() const
00131                         {
00132                                 return C::description();
00133                         }
00134                         virtual const Parametrizable::ParametersDoc availableParameters() const
00135                         {
00136                                 return Parametrizable::ParametersDoc();
00137                         }
00138                 };
00139                 
00140         protected:
00141                 typedef std::map<std::string, ClassDescriptor*> DescriptorMap; 
00142                 DescriptorMap classes; 
00143                 
00144         public:
00146                 ~Registrar()
00147                 {
00148                         for (BOOST_AUTO(it, classes.begin()); it != classes.end(); ++it)
00149                                 delete it->second;
00150                 }
00152                 void reg(const std::string &name, ClassDescriptor* descriptor)
00153                 {
00154                         classes[name] = descriptor;
00155                 }
00156                 
00158                 const ClassDescriptor* getDescriptor(const std::string& name) const
00159                 {
00160                         BOOST_AUTO(it, classes.find(name));
00161                         if (it == classes.end())
00162                         {
00163                                 std::cerr << "No element named " << name << " is registered. Known ones are:\n";
00164                                 dump(std::cerr);
00165                                 throw InvalidElement(
00166                                         (boost::format("Trying to instanciate unknown element %1% from registrar") % name).str()
00167                                 );
00168                         }
00169                         return it->second;
00170                 }
00171                 
00173                 Interface* create(const std::string& name, const Parametrizable::Parameters& params = Parametrizable::Parameters()) const
00174                 {
00175                         return getDescriptor(name)->createInstance(name, params);
00176                 }
00177                                 
00179         Interface* createFromYAML(const YAML::Node& module) const
00180                 {
00181                         std::string name;
00182                         Parametrizable::Parameters params;
00183 
00184                         getNameParamsFromYAML(module, name, params);
00185                         
00186                         return create(name, params);
00187                 }
00188                                 
00190                 const std::string getDescription(const std::string& name) const
00191                 {
00192                         return getDescriptor(name)->description();
00193                 }
00194                 
00196                 void dump(std::ostream &stream) const
00197                 {
00198                         for (BOOST_AUTO(it, classes.begin()); it != classes.end(); ++it)
00199                                 stream << "- " << it->first << "\n";
00200                 }
00201                 
00203                 typename DescriptorMap::const_iterator begin() const
00204                 {       
00205                         return classes.begin();
00206                 }
00208                 typename DescriptorMap::const_iterator end() const
00209                 {
00210                         return classes.end();
00211                 }
00212         };
00213 
00214         #define REG(name) name##Registrar
00215         #define DEF_REGISTRAR(name) PointMatcherSupport::Registrar< name > name##Registrar;
00216         #define DEF_REGISTRAR_IFACE(name, ifaceName) PointMatcherSupport::Registrar< ifaceName > name##Registrar;
00217         #define ADD_TO_REGISTRAR(name, elementName, element) { \
00218                 typedef typename PointMatcherSupport::Registrar< name >::template GenericClassDescriptor< element > Desc; \
00219                 name##Registrar.reg(# elementName, new Desc() ); \
00220         }
00221         #define ADD_TO_REGISTRAR_NO_PARAM(name, elementName, element) { \
00222                 typedef typename PointMatcherSupport::Registrar< name >::template GenericClassDescriptorNoParam< element > Desc; \
00223                 name##Registrar.reg(# elementName, new Desc() ); \
00224         }
00225 } // namespace PointMatcherSupport
00226 
00227 #endif // __POINTMATCHER_REGISTRAR_H


upstream_src
Author(s):
autogenerated on Mon Oct 6 2014 10:27:42