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


libpointmatcher
Author(s): Stéphane Magnenat, François Pomerleau
autogenerated on Thu Jan 2 2014 11:16:06