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