| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  | /* ---------------------------------------------------------------------------- 
 | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |  * GTSAM Copyright 2010, Georgia Tech Research Corporation,   | 
					
						
							|  |  |  |  * Atlanta, Georgia 30332-0415  | 
					
						
							|  |  |  |  * All Rights Reserved  | 
					
						
							|  |  |  |  * Authors: Frank Dellaert, et al. (see THANKS for the full author list)  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |  * See LICENSE for the license information  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |  * -------------------------------------------------------------------------- */  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | /** 
 | 
					
						
							|  |  |  |  * @file Module.ccp  | 
					
						
							|  |  |  |  * @author Frank Dellaert  | 
					
						
							|  |  |  |  * @author Alex Cunningham  | 
					
						
							|  |  |  |  * @author Andrew Melim  | 
					
						
							| 
									
										
										
										
											2012-07-18 23:47:06 +08:00
										 |  |  |  * @author Richard Roberts | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  |  **/  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | #include "Module.h" 
 | 
					
						
							|  |  |  | #include "FileWriter.h" 
 | 
					
						
							|  |  |  | #include "TypeAttributesTable.h" 
 | 
					
						
							| 
									
										
										
										
											2013-10-27 06:22:31 +08:00
										 |  |  | #include "utilities.h"
 | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:22 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  | #include <boost/foreach.hpp> 
 | 
					
						
							|  |  |  | #include <boost/filesystem.hpp> 
 | 
					
						
							|  |  |  | #include <boost/lexical_cast.hpp> 
 | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | #include <iostream> 
 | 
					
						
							|  |  |  | #include <algorithm> 
 | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | using namespace std;  | 
					
						
							|  |  |  | using namespace wrap;  | 
					
						
							|  |  |  | using namespace BOOST_SPIRIT_CLASSIC_NS;  | 
					
						
							|  |  |  | namespace bl = boost::lambda;  | 
					
						
							|  |  |  | namespace fs = boost::filesystem;  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | /* ************************************************************************* */  | 
					
						
							|  |  |  | // We parse an interface file into a Module object. 
 | 
					
						
							|  |  |  | // The grammar is defined using the boost/spirit combinatorial parser. 
 | 
					
						
							|  |  |  | // For example, str_p("const") parses the string "const", and the >> 
 | 
					
						
							|  |  |  | // operator creates a sequence parser. The grammar below, composed of rules 
 | 
					
						
							|  |  |  | // and with start rule [class_p], doubles as the specs for our interface files. 
 | 
					
						
							|  |  |  | /* ************************************************************************* */  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | /* ************************************************************************* */  | 
					
						
							| 
									
										
										
										
											2014-11-12 05:38:50 +08:00
										 |  |  | // If a number of template arguments were given, generate a number of expanded
 | 
					
						
							|  |  |  | // class names, e.g., PriorFactor -> PriorFactorPose2, and add those classes
 | 
					
						
							|  |  |  | static void handle_possible_template(vector<Class>& classes, const Class& cls, | 
					
						
							| 
									
										
										
										
											2014-11-13 02:09:30 +08:00
										 |  |  |     const vector<Qualified>& instantiations) { | 
					
						
							|  |  |  |   if (cls.templateArgs.empty() || instantiations.empty()) { | 
					
						
							| 
									
										
										
										
											2014-11-12 05:38:50 +08:00
										 |  |  |     classes.push_back(cls); | 
					
						
							|  |  |  |   } else { | 
					
						
							| 
									
										
										
										
											2014-11-13 02:09:30 +08:00
										 |  |  |     if (cls.templateArgs.size() != 1) | 
					
						
							|  |  |  |       throw std::runtime_error( | 
					
						
							|  |  |  |           "In-line template instantiations only handle a single template argument"); | 
					
						
							| 
									
										
										
										
											2014-11-12 05:38:50 +08:00
										 |  |  |     vector<Class> classInstantiations = //
 | 
					
						
							| 
									
										
										
										
											2014-11-13 02:09:30 +08:00
										 |  |  |         cls.expandTemplate(cls.templateArgs.front(), instantiations); | 
					
						
							| 
									
										
										
										
											2014-11-12 05:38:50 +08:00
										 |  |  |     BOOST_FOREACH(const Class& c, classInstantiations) | 
					
						
							|  |  |  |       classes.push_back(c); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:19 +08:00
										 |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | Module::Module(const std::string& moduleName, bool enable_verbose) | 
					
						
							|  |  |  | : name(moduleName), verbose(enable_verbose) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  | /* ************************************************************************* */  | 
					
						
							|  |  |  | Module::Module(const string& interfacePath,  | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:19 +08:00
										 |  |  |          const string& moduleName, bool enable_verbose) | 
					
						
							|  |  |  | : name(moduleName), verbose(enable_verbose) | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  | {  | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:19 +08:00
										 |  |  |   // read interface file
 | 
					
						
							|  |  |  |   string interfaceFile = interfacePath + "/" + moduleName + ".h"; | 
					
						
							|  |  |  |   string contents = file_contents(interfaceFile); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // execute parsing
 | 
					
						
							|  |  |  |   parseMarkup(contents); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							|  |  |  | void Module::parseMarkup(const std::string& data) { | 
					
						
							| 
									
										
										
										
											2014-11-13 01:04:38 +08:00
										 |  |  |   // The parse imperatively :-( updates variables gradually during parse
 | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  |   // The one with postfix 0 are used to reset the variables after parse. 
 | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |   //---------------------------------------------------------------------------- 
 | 
					
						
							|  |  |  |   // Grammar with actions that build the Class object. Actions are 
 | 
					
						
							|  |  |  |   // defined within the square brackets [] and are executed whenever a 
 | 
					
						
							|  |  |  |   // rule is successfully parsed. Define BOOST_SPIRIT_DEBUG to debug. 
 | 
					
						
							|  |  |  |   // The grammar is allows a very restricted C++ header 
 | 
					
						
							|  |  |  |   // lexeme_d turns off white space skipping 
 | 
					
						
							|  |  |  |   // http://www.boost.org/doc/libs/1_37_0/libs/spirit/classic/doc/directives.html 
 | 
					
						
							|  |  |  |   // ---------------------------------------------------------------------------- 
 | 
					
						
							|  |  |  |   | 
					
						
							| 
									
										
										
										
											2014-12-01 03:12:03 +08:00
										 |  |  |   // Define Rule and instantiate basic rules
 | 
					
						
							|  |  |  |   typedef rule<phrase_scanner_t> Rule; | 
					
						
							| 
									
										
										
										
											2014-12-02 03:03:26 +08:00
										 |  |  |   BasicRules<phrase_scanner_t> basic; | 
					
						
							| 
									
										
										
										
											2014-11-13 01:04:38 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-02 20:12:21 +08:00
										 |  |  |   vector<string> namespaces; // current namespace tag
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // parse a full class
 | 
					
						
							| 
									
										
										
										
											2014-11-13 01:04:38 +08:00
										 |  |  |   Class cls0(verbose),cls(verbose); | 
					
						
							| 
									
										
										
										
											2014-12-02 20:12:21 +08:00
										 |  |  |   Template classTemplate; | 
					
						
							|  |  |  |   ClassGrammar class_g(cls,classTemplate); | 
					
						
							|  |  |  |   Rule class_p = class_g //
 | 
					
						
							|  |  |  |       [assign_a(cls.namespaces_, namespaces)] | 
					
						
							|  |  |  |       [bl::bind(&handle_possible_template, bl::var(classes), bl::var(cls), | 
					
						
							|  |  |  |           bl::var(classTemplate.argValues()))] | 
					
						
							|  |  |  |           [clear_a(classTemplate)] //
 | 
					
						
							|  |  |  |       [assign_a(cls,cls0)]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-11 00:56:22 +08:00
										 |  |  |   // parse "gtsam::Pose2" and add to singleInstantiation.typeList
 | 
					
						
							| 
									
										
										
										
											2014-12-01 03:12:03 +08:00
										 |  |  |   TemplateInstantiationTypedef singleInstantiation, singleInstantiation0; | 
					
						
							| 
									
										
										
										
											2014-12-01 19:14:08 +08:00
										 |  |  |   TypeListGrammar<'<','>'> typelist_g(singleInstantiation.typeList); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   | 
					
						
							| 
									
										
										
										
											2014-11-11 00:56:22 +08:00
										 |  |  |   // typedef gtsam::RangeFactor<gtsam::Pose2, gtsam::Point2> RangeFactorPosePoint2;
 | 
					
						
							| 
									
										
										
										
											2014-12-01 07:33:54 +08:00
										 |  |  |   TypeGrammar instantiationClass_g(singleInstantiation.class_); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   Rule templateSingleInstantiation_p =  | 
					
						
							| 
									
										
										
										
											2014-12-01 07:33:54 +08:00
										 |  |  |     (str_p("typedef") >> instantiationClass_g >> | 
					
						
							| 
									
										
										
										
											2014-12-01 19:14:08 +08:00
										 |  |  |     typelist_g >> | 
					
						
							| 
									
										
										
										
											2014-12-01 07:33:54 +08:00
										 |  |  |     basic.className_p[assign_a(singleInstantiation.name_)] >> | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |     ';')  | 
					
						
							| 
									
										
										
										
											2014-12-01 07:33:54 +08:00
										 |  |  |     [assign_a(singleInstantiation.namespaces_, namespaces)] | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |     [push_back_a(templateInstantiationTypedefs, singleInstantiation)]  | 
					
						
							|  |  |  |     [assign_a(singleInstantiation, singleInstantiation0)];  | 
					
						
							|  |  |  |   | 
					
						
							| 
									
										
										
										
											2014-12-02 20:49:25 +08:00
										 |  |  |   // Create grammar for global functions
 | 
					
						
							|  |  |  |   GlobalFunctionGrammar global_function_g(global_functions,namespaces); | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  |   | 
					
						
							| 
									
										
										
										
											2014-02-24 07:53:48 +08:00
										 |  |  |   Rule include_p = str_p("#include") >> ch_p('<') >> (*(anychar_p - '>'))[push_back_a(includes)] >> ch_p('>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef __clang__
 | 
					
						
							|  |  |  | #pragma clang diagnostic push
 | 
					
						
							|  |  |  | #pragma clang diagnostic ignored "-Wuninitialized"
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2014-11-13 01:04:38 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   Rule namespace_def_p = | 
					
						
							|  |  |  |       (str_p("namespace") | 
					
						
							| 
									
										
										
										
											2014-12-01 07:33:54 +08:00
										 |  |  |       >> basic.namespace_p[push_back_a(namespaces)] | 
					
						
							| 
									
										
										
										
											2014-11-13 01:04:38 +08:00
										 |  |  |       >> ch_p('{') | 
					
						
							| 
									
										
										
										
											2014-12-02 20:49:25 +08:00
										 |  |  |       >> *(include_p | class_p | templateSingleInstantiation_p | global_function_g | namespace_def_p | basic.comments_p) | 
					
						
							| 
									
										
										
										
											2014-11-13 01:04:38 +08:00
										 |  |  |       >> ch_p('}')) | 
					
						
							|  |  |  |       [pop_a(namespaces)]; | 
					
						
							| 
									
										
										
										
											2014-02-24 07:53:48 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef __clang__
 | 
					
						
							|  |  |  | #pragma clang diagnostic pop
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-13 01:04:38 +08:00
										 |  |  |   // parse forward declaration
 | 
					
						
							|  |  |  |   ForwardDeclaration fwDec0, fwDec; | 
					
						
							| 
									
										
										
										
											2014-02-24 07:53:48 +08:00
										 |  |  |   Rule forward_declaration_p = | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |       !(str_p("virtual")[assign_a(fwDec.isVirtual, true)])  | 
					
						
							|  |  |  |       >> str_p("class")  | 
					
						
							| 
									
										
										
										
											2014-12-01 07:33:54 +08:00
										 |  |  |       >> (*(basic.namespace_p >> str_p("::")) >> basic.className_p)[assign_a(fwDec.name)] | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |       >> ch_p(';')  | 
					
						
							|  |  |  |       [push_back_a(forward_declarations, fwDec)]  | 
					
						
							|  |  |  |       [assign_a(fwDec, fwDec0)];  | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  |   | 
					
						
							| 
									
										
										
										
											2014-12-01 03:12:03 +08:00
										 |  |  |   Rule module_content_p = basic.comments_p | include_p | class_p | 
					
						
							|  |  |  |       | templateSingleInstantiation_p | forward_declaration_p | 
					
						
							| 
									
										
										
										
											2014-12-02 20:49:25 +08:00
										 |  |  |       | global_function_g | namespace_def_p; | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  |   | 
					
						
							|  |  |  |   Rule module_p = *module_content_p >> !end_p;  | 
					
						
							|  |  |  |   | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:19 +08:00
										 |  |  |   // and parse contents
 | 
					
						
							|  |  |  |   parse_info<const char*> info = parse(data.c_str(), module_p, space_p); | 
					
						
							|  |  |  |   if(!info.full) { | 
					
						
							|  |  |  |     printf("parsing stopped at \n%.20s\n",info.stop); | 
					
						
							| 
									
										
										
										
											2014-12-02 20:12:21 +08:00
										 |  |  |     cout << "Stopped in:\n" | 
					
						
							|  |  |  |       "class '" << cls.name_ << "'" << endl; | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:19 +08:00
										 |  |  |     throw ParseFailed((int)info.length); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2012-09-09 03:51:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-20 01:49:55 +08:00
										 |  |  |   // Post-process classes for serialization markers
 | 
					
						
							| 
									
										
										
										
											2014-11-13 06:22:59 +08:00
										 |  |  |   BOOST_FOREACH(Class& cls, classes) | 
					
						
							|  |  |  |     cls.erase_serialization(); | 
					
						
							| 
									
										
										
										
											2013-06-20 01:49:55 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Explicitly add methods to the classes from parents so it shows in documentation
 | 
					
						
							| 
									
										
										
										
											2012-09-09 03:51:23 +08:00
										 |  |  |   BOOST_FOREACH(Class& cls, classes) | 
					
						
							| 
									
										
										
										
											2014-11-13 06:22:59 +08:00
										 |  |  |     cls.appendInheritedMethods(cls, classes); | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Expand templates - This is done first so that template instantiations are
 | 
					
						
							|  |  |  |   // counted in the list of valid types, have their attributes and dependencies
 | 
					
						
							|  |  |  |   // checked, etc.
 | 
					
						
							| 
									
										
										
										
											2014-11-15 00:04:45 +08:00
										 |  |  |   expandedClasses = ExpandTypedefInstantiations(classes, | 
					
						
							|  |  |  |       templateInstantiationTypedefs); | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Dependency check list
 | 
					
						
							| 
									
										
										
										
											2014-11-15 00:04:45 +08:00
										 |  |  |   vector<string> validTypes = GenerateValidTypes(expandedClasses, | 
					
						
							|  |  |  |       forward_declarations); | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Check that all classes have been defined somewhere
 | 
					
						
							|  |  |  |   verifyArguments<GlobalFunction>(validTypes, global_functions); | 
					
						
							|  |  |  |   verifyReturnTypes<GlobalFunction>(validTypes, global_functions); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-15 00:04:45 +08:00
										 |  |  |   hasSerialiable = false; | 
					
						
							| 
									
										
										
										
											2014-11-13 06:22:59 +08:00
										 |  |  |   BOOST_FOREACH(const Class& cls, expandedClasses) | 
					
						
							|  |  |  |     cls.verifyAll(validTypes,hasSerialiable); | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Create type attributes table and check validity
 | 
					
						
							|  |  |  |   typeAttributes.addClasses(expandedClasses); | 
					
						
							|  |  |  |   typeAttributes.addForwardDeclarations(forward_declarations); | 
					
						
							| 
									
										
										
										
											2014-11-30 03:01:48 +08:00
										 |  |  |   // add Eigen types as template arguments are also checked ?
 | 
					
						
							|  |  |  |   vector<ForwardDeclaration> eigen; | 
					
						
							|  |  |  |   eigen.push_back(ForwardDeclaration("Vector")); | 
					
						
							|  |  |  |   eigen.push_back(ForwardDeclaration("Matrix")); | 
					
						
							|  |  |  |   typeAttributes.addForwardDeclarations(eigen); | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  |   typeAttributes.checkValidity(expandedClasses); | 
					
						
							| 
									
										
										
										
											2014-11-15 00:04:45 +08:00
										 |  |  | }  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | /* ************************************************************************* */  | 
					
						
							|  |  |  | void Module::matlab_code(const string& toolboxPath) const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fs::create_directories(toolboxPath); | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-20 01:49:57 +08:00
										 |  |  |   // create the unified .cpp switch file
 | 
					
						
							|  |  |  |   const string wrapperName = name + "_wrapper"; | 
					
						
							|  |  |  |   string wrapperFileName = toolboxPath + "/" + wrapperName + ".cpp"; | 
					
						
							|  |  |  |   FileWriter wrapperFile(wrapperFileName, verbose, "//"); | 
					
						
							|  |  |  |   wrapperFile.oss << "#include <wrap/matlab.h>\n"; | 
					
						
							|  |  |  |   wrapperFile.oss << "#include <map>\n"; | 
					
						
							|  |  |  |   wrapperFile.oss << "#include <boost/foreach.hpp>\n"; | 
					
						
							|  |  |  |   wrapperFile.oss << "\n"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-20 01:50:03 +08:00
										 |  |  |   // Include boost.serialization archive headers before other class headers
 | 
					
						
							| 
									
										
										
										
											2013-06-20 01:49:57 +08:00
										 |  |  |   if (hasSerialiable) { | 
					
						
							| 
									
										
										
										
											2013-06-20 01:50:03 +08:00
										 |  |  |     wrapperFile.oss << "#include <boost/serialization/export.hpp>\n"; | 
					
						
							| 
									
										
										
										
											2013-06-20 01:49:57 +08:00
										 |  |  |     wrapperFile.oss << "#include <boost/archive/text_iarchive.hpp>\n"; | 
					
						
							|  |  |  |     wrapperFile.oss << "#include <boost/archive/text_oarchive.hpp>\n\n"; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2013-06-20 01:50:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Generate includes while avoiding redundant includes
 | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  |   generateIncludes(wrapperFile); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-15 00:04:45 +08:00
										 |  |  |   // create typedef classes - we put this at the top of the wrap file so that
 | 
					
						
							|  |  |  |   // collectors and method arguments can use these typedefs
 | 
					
						
							|  |  |  |   BOOST_FOREACH(const Class& cls, expandedClasses) | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  |     if(!cls.typedefName.empty()) | 
					
						
							|  |  |  |       wrapperFile.oss << cls.getTypedef() << "\n"; | 
					
						
							|  |  |  |   wrapperFile.oss << "\n"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-20 01:50:03 +08:00
										 |  |  |   // Generate boost.serialization export flags (needs typedefs from above)
 | 
					
						
							|  |  |  |   if (hasSerialiable) { | 
					
						
							| 
									
										
										
										
											2014-11-15 00:04:45 +08:00
										 |  |  |     BOOST_FOREACH(const Class& cls, expandedClasses) | 
					
						
							| 
									
										
										
										
											2013-06-20 01:50:03 +08:00
										 |  |  |       if(cls.isSerializable) | 
					
						
							|  |  |  |         wrapperFile.oss << cls.getSerializationExport() << "\n"; | 
					
						
							|  |  |  |     wrapperFile.oss << "\n"; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  |   // Generate collectors and cleanup function to be called from mexAtExit
 | 
					
						
							|  |  |  |   WriteCollectorsAndCleanupFcn(wrapperFile, name, expandedClasses); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // generate RTTI registry (for returning derived-most types)
 | 
					
						
							|  |  |  |   WriteRTTIRegistry(wrapperFile, name, expandedClasses); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-20 01:49:57 +08:00
										 |  |  |   vector<string> functionNames; // Function names stored by index for switch
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  |   // create proxy class and wrapper code
 | 
					
						
							| 
									
										
										
										
											2014-11-15 00:04:45 +08:00
										 |  |  |   BOOST_FOREACH(const Class& cls, expandedClasses) | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  |     cls.matlab_proxy(toolboxPath, wrapperName, typeAttributes, wrapperFile, functionNames); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // create matlab files and wrapper code for global functions
 | 
					
						
							| 
									
										
										
										
											2014-11-15 00:04:45 +08:00
										 |  |  |   BOOST_FOREACH(const GlobalFunctions::value_type& p, global_functions) | 
					
						
							| 
									
										
										
										
											2012-11-28 03:03:23 +08:00
										 |  |  |     p.second.matlab_proxy(toolboxPath, wrapperName, typeAttributes, wrapperFile, functionNames); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // finish wrapper file
 | 
					
						
							|  |  |  |   wrapperFile.oss << "\n"; | 
					
						
							|  |  |  |   finish_wrapper(wrapperFile, functionNames); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   wrapperFile.emit(true); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-09-09 03:51:23 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  | /* ************************************************************************* */  | 
					
						
							| 
									
										
										
										
											2014-11-15 00:04:45 +08:00
										 |  |  | void Module::generateIncludes(FileWriter& file) const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // collect includes
 | 
					
						
							|  |  |  |   vector<string> all_includes(includes); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // sort and remove duplicates
 | 
					
						
							|  |  |  |   sort(all_includes.begin(), all_includes.end()); | 
					
						
							|  |  |  |   vector<string>::const_iterator last_include = unique(all_includes.begin(), all_includes.end()); | 
					
						
							|  |  |  |   vector<string>::const_iterator it = all_includes.begin(); | 
					
						
							|  |  |  |   // add includes to file
 | 
					
						
							|  |  |  |   for (; it != last_include; ++it) | 
					
						
							|  |  |  |     file.oss << "#include <" << *it << ">" << endl; | 
					
						
							|  |  |  |   file.oss << "\n"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   void Module::finish_wrapper(FileWriter& file, const std::vector<std::string>& functionNames) const {  | 
					
						
							|  |  |  |     file.oss << "void mexFunction(int nargout, mxArray *out[], int nargin, const mxArray *in[])\n";  | 
					
						
							|  |  |  |     file.oss << "{\n";  | 
					
						
							|  |  |  |     file.oss << "  mstream mout;\n"; // Send stdout to MATLAB console 
 | 
					
						
							|  |  |  |     file.oss << "  std::streambuf *outbuf = std::cout.rdbuf(&mout);\n\n";  | 
					
						
							|  |  |  |     file.oss << "  _" << name << "_RTTIRegister();\n\n";  | 
					
						
							|  |  |  |     file.oss << "  int id = unwrap<int>(in[0]);\n\n";  | 
					
						
							|  |  |  |     file.oss << "  try {\n";  | 
					
						
							|  |  |  |     file.oss << "    switch(id) {\n";  | 
					
						
							|  |  |  |     for(size_t id = 0; id < functionNames.size(); ++id) {  | 
					
						
							|  |  |  |       file.oss << "    case " << id << ":\n";  | 
					
						
							|  |  |  |       file.oss << "      " << functionNames[id] << "(nargout, out, nargin-1, in+1);\n";  | 
					
						
							|  |  |  |       file.oss << "      break;\n";  | 
					
						
							|  |  |  |     }  | 
					
						
							|  |  |  |     file.oss << "    }\n";  | 
					
						
							|  |  |  |     file.oss << "  } catch(const std::exception& e) {\n";  | 
					
						
							|  |  |  |     file.oss << "    mexErrMsgTxt((\"Exception from gtsam:\\n\" + std::string(e.what()) + \"\\n\").c_str());\n";  | 
					
						
							|  |  |  |     file.oss << "  }\n";  | 
					
						
							|  |  |  |     file.oss << "\n";  | 
					
						
							|  |  |  |     file.oss << "  std::cout.rdbuf(outbuf);\n"; // Restore cout 
 | 
					
						
							|  |  |  |     file.oss << "}\n";  | 
					
						
							|  |  |  |   }  | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  |   | 
					
						
							|  |  |  | /* ************************************************************************* */  | 
					
						
							|  |  |  | vector<Class> Module::ExpandTypedefInstantiations(const vector<Class>& classes, const vector<TemplateInstantiationTypedef> instantiations) {  | 
					
						
							|  |  |  |   | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   vector<Class> expandedClasses = classes;  | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  |   | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   BOOST_FOREACH(const TemplateInstantiationTypedef& inst, instantiations) {  | 
					
						
							|  |  |  |     // Add the new class to the list 
 | 
					
						
							|  |  |  |     expandedClasses.push_back(inst.findAndExpand(classes));  | 
					
						
							|  |  |  |   }  | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  |   | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // Remove all template classes 
 | 
					
						
							|  |  |  |   for(size_t i = 0; i < expandedClasses.size(); ++i)  | 
					
						
							|  |  |  |     if(!expandedClasses[size_t(i)].templateArgs.empty()) {  | 
					
						
							|  |  |  |       expandedClasses.erase(expandedClasses.begin() + size_t(i));  | 
					
						
							|  |  |  |       -- i;  | 
					
						
							|  |  |  |     }  | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  |   | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   return expandedClasses;  | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  | }  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | /* ************************************************************************* */  | 
					
						
							|  |  |  | vector<string> Module::GenerateValidTypes(const vector<Class>& classes, const vector<ForwardDeclaration> forwardDeclarations) {  | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   vector<string> validTypes;  | 
					
						
							|  |  |  |   BOOST_FOREACH(const ForwardDeclaration& fwDec, forwardDeclarations) {  | 
					
						
							| 
									
										
										
										
											2014-12-01 07:33:54 +08:00
										 |  |  |     validTypes.push_back(fwDec.name); | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   }  | 
					
						
							|  |  |  |   validTypes.push_back("void");  | 
					
						
							|  |  |  |   validTypes.push_back("string");  | 
					
						
							|  |  |  |   validTypes.push_back("int");  | 
					
						
							|  |  |  |   validTypes.push_back("bool");  | 
					
						
							|  |  |  |   validTypes.push_back("char");  | 
					
						
							|  |  |  |   validTypes.push_back("unsigned char");  | 
					
						
							|  |  |  |   validTypes.push_back("size_t");  | 
					
						
							|  |  |  |   validTypes.push_back("double");  | 
					
						
							|  |  |  |   validTypes.push_back("Vector");  | 
					
						
							|  |  |  |   validTypes.push_back("Matrix");  | 
					
						
							|  |  |  |   //Create a list of parsed classes for dependency checking 
 | 
					
						
							|  |  |  |   BOOST_FOREACH(const Class& cls, classes) {  | 
					
						
							|  |  |  |     validTypes.push_back(cls.qualifiedName("::"));  | 
					
						
							|  |  |  |   }  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |   return validTypes;  | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  | }  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | /* ************************************************************************* */  | 
					
						
							|  |  |  | void Module::WriteCollectorsAndCleanupFcn(FileWriter& wrapperFile, const std::string& moduleName, const std::vector<Class>& classes) {  | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   // Generate all collectors 
 | 
					
						
							|  |  |  |   BOOST_FOREACH(const Class& cls, classes) {  | 
					
						
							|  |  |  |     const string matlabUniqueName = cls.qualifiedName(),  | 
					
						
							|  |  |  |       cppName = cls.qualifiedName("::");  | 
					
						
							|  |  |  |     wrapperFile.oss << "typedef std::set<boost::shared_ptr<" << cppName << ">*> "  | 
					
						
							|  |  |  |       << "Collector_" << matlabUniqueName << ";\n";  | 
					
						
							|  |  |  |     wrapperFile.oss << "static Collector_" << matlabUniqueName <<  | 
					
						
							|  |  |  |       " collector_" << matlabUniqueName << ";\n";  | 
					
						
							|  |  |  |   }  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |   // generate mexAtExit cleanup function 
 | 
					
						
							|  |  |  |   wrapperFile.oss <<  | 
					
						
							|  |  |  |     "\nvoid _deleteAllObjects()\n"  | 
					
						
							|  |  |  |     "{\n"  | 
					
						
							|  |  |  |     "  mstream mout;\n" // Send stdout to MATLAB console 
 | 
					
						
							|  |  |  |     "  std::streambuf *outbuf = std::cout.rdbuf(&mout);\n\n"  | 
					
						
							|  |  |  |     "  bool anyDeleted = false;\n";  | 
					
						
							|  |  |  |   BOOST_FOREACH(const Class& cls, classes) {  | 
					
						
							|  |  |  |     const string matlabUniqueName = cls.qualifiedName();  | 
					
						
							|  |  |  |     const string cppName = cls.qualifiedName("::");  | 
					
						
							|  |  |  |     const string collectorType = "Collector_" + matlabUniqueName;  | 
					
						
							|  |  |  |     const string collectorName = "collector_" + matlabUniqueName;  | 
					
						
							|  |  |  |     // The extra curly-braces around the for loops work around a limitation in MSVC (existing 
 | 
					
						
							|  |  |  |     // since 2005!) preventing more than 248 blocks. 
 | 
					
						
							|  |  |  |     wrapperFile.oss <<  | 
					
						
							|  |  |  |       "  { for(" << collectorType << "::iterator iter = " << collectorName << ".begin();\n"  | 
					
						
							|  |  |  |       "      iter != " << collectorName << ".end(); ) {\n"  | 
					
						
							|  |  |  |       "    delete *iter;\n"  | 
					
						
							|  |  |  |       "    " << collectorName << ".erase(iter++);\n"  | 
					
						
							|  |  |  |       "    anyDeleted = true;\n"  | 
					
						
							|  |  |  |       "  } }\n";  | 
					
						
							|  |  |  |   }  | 
					
						
							|  |  |  |   wrapperFile.oss <<  | 
					
						
							|  |  |  |     "  if(anyDeleted)\n"  | 
					
						
							|  |  |  |     "    cout <<\n"  | 
					
						
							|  |  |  |     "      \"WARNING:  Wrap modules with variables in the workspace have been reloaded due to\\n\"\n"  | 
					
						
							|  |  |  |     "      \"calling destructors, call 'clear all' again if you plan to now recompile a wrap\\n\"\n"  | 
					
						
							|  |  |  |     "      \"module, so that your recompiled module is used instead of the old one.\" << endl;\n"  | 
					
						
							|  |  |  |     "  std::cout.rdbuf(outbuf);\n" // Restore cout 
 | 
					
						
							|  |  |  |     "}\n\n";  | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  | }  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | /* ************************************************************************* */  | 
					
						
							|  |  |  | void Module::WriteRTTIRegistry(FileWriter& wrapperFile, const std::string& moduleName, const std::vector<Class>& classes) {  | 
					
						
							| 
									
										
										
										
											2012-10-02 22:40:07 +08:00
										 |  |  |   wrapperFile.oss <<  | 
					
						
							|  |  |  |     "void _" << moduleName << "_RTTIRegister() {\n"  | 
					
						
							|  |  |  |     "  const mxArray *alreadyCreated = mexGetVariablePtr(\"global\", \"gtsam_" + moduleName + "_rttiRegistry_created\");\n"  | 
					
						
							|  |  |  |     "  if(!alreadyCreated) {\n"  | 
					
						
							|  |  |  |     "    std::map<std::string, std::string> types;\n";  | 
					
						
							|  |  |  |   BOOST_FOREACH(const Class& cls, classes) {  | 
					
						
							|  |  |  |     if(cls.isVirtual)  | 
					
						
							|  |  |  |       wrapperFile.oss <<  | 
					
						
							|  |  |  |       "    types.insert(std::make_pair(typeid(" << cls.qualifiedName("::") << ").name(), \"" << cls.qualifiedName(".") << "\"));\n";  | 
					
						
							|  |  |  |   }  | 
					
						
							|  |  |  |   wrapperFile.oss << "\n";  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  |   wrapperFile.oss <<  | 
					
						
							|  |  |  |     "    mxArray *registry = mexGetVariable(\"global\", \"gtsamwrap_rttiRegistry\");\n"  | 
					
						
							|  |  |  |     "    if(!registry)\n"  | 
					
						
							|  |  |  |     "      registry = mxCreateStructMatrix(1, 1, 0, NULL);\n"  | 
					
						
							|  |  |  |     "    typedef std::pair<std::string, std::string> StringPair;\n"  | 
					
						
							|  |  |  |     "    BOOST_FOREACH(const StringPair& rtti_matlab, types) {\n"  | 
					
						
							|  |  |  |     "      int fieldId = mxAddField(registry, rtti_matlab.first.c_str());\n"  | 
					
						
							|  |  |  |     "      if(fieldId < 0)\n"  | 
					
						
							|  |  |  |     "        mexErrMsgTxt(\"gtsam wrap:  Error indexing RTTI types, inheritance will not work correctly\");\n"  | 
					
						
							|  |  |  |     "      mxArray *matlabName = mxCreateString(rtti_matlab.second.c_str());\n"  | 
					
						
							|  |  |  |     "      mxSetFieldByNumber(registry, 0, fieldId, matlabName);\n"  | 
					
						
							|  |  |  |     "    }\n"  | 
					
						
							|  |  |  |     "    if(mexPutVariable(\"global\", \"gtsamwrap_rttiRegistry\", registry) != 0)\n"  | 
					
						
							|  |  |  |     "      mexErrMsgTxt(\"gtsam wrap:  Error indexing RTTI types, inheritance will not work correctly\");\n"  | 
					
						
							|  |  |  |     "    mxDestroyArray(registry);\n"  | 
					
						
							|  |  |  |     "    \n"  | 
					
						
							|  |  |  |     "    mxArray *newAlreadyCreated = mxCreateNumericMatrix(0, 0, mxINT8_CLASS, mxREAL);\n"  | 
					
						
							|  |  |  |     "    if(mexPutVariable(\"global\", \"gtsam_" + moduleName + "_rttiRegistry_created\", newAlreadyCreated) != 0)\n"  | 
					
						
							|  |  |  |     "      mexErrMsgTxt(\"gtsam wrap:  Error indexing RTTI types, inheritance will not work correctly\");\n"  | 
					
						
							|  |  |  |     "    mxDestroyArray(newAlreadyCreated);\n"  | 
					
						
							|  |  |  |     "  }\n"  | 
					
						
							|  |  |  |     "}\n"  | 
					
						
							|  |  |  |     "\n";  | 
					
						
							| 
									
										
										
										
											2012-08-27 23:19:55 +08:00
										 |  |  | }  | 
					
						
							|  |  |  |   | 
					
						
							|  |  |  | /* ************************************************************************* */  | 
					
						
							| 
									
										
										
										
											2014-11-15 00:47:25 +08:00
										 |  |  | void Module::python_wrapper(const string& toolboxPath) const { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   fs::create_directories(toolboxPath); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // create the unified .cpp switch file
 | 
					
						
							|  |  |  |   const string wrapperName = name + "_python"; | 
					
						
							|  |  |  |   string wrapperFileName = toolboxPath + "/" + wrapperName + ".cpp"; | 
					
						
							|  |  |  |   FileWriter wrapperFile(wrapperFileName, verbose, "//"); | 
					
						
							|  |  |  |   wrapperFile.oss << "#include <boost/python.hpp>\n\n"; | 
					
						
							|  |  |  |   wrapperFile.oss << "using namespace boost::python;\n"; | 
					
						
							|  |  |  |   wrapperFile.oss << "BOOST_PYTHON_MODULE(" + name + ")\n"; | 
					
						
							|  |  |  |   wrapperFile.oss << "{\n"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // write out classes
 | 
					
						
							|  |  |  |   BOOST_FOREACH(const Class& cls, expandedClasses) | 
					
						
							|  |  |  |     cls.python_wrapper(wrapperFile); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // write out global functions
 | 
					
						
							|  |  |  |   BOOST_FOREACH(const GlobalFunctions::value_type& p, global_functions) | 
					
						
							|  |  |  |     p.second.python_wrapper(wrapperFile); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // finish wrapper file
 | 
					
						
							|  |  |  |   wrapperFile.oss << "}\n"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   wrapperFile.emit(true); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* ************************************************************************* */ |