libpointmatcher 1.0.2
|
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