diff --git a/wrap/Class.cpp b/wrap/Class.cpp index 81ee508a0..43258da61 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -248,42 +248,58 @@ map expandMethodTemplate(const map& methods, con instRetVal.namespaces2.assign(instName.begin(), instName.end()-1); instRetVal.type2 = instName.back(); } + instMethod.returnVals.push_back(instRetVal); } result.insert(make_pair(name_method.first, instMethod)); } return result; } +/* ************************************************************************* */ +Class expandClassTemplate(const Class& cls, const string& templateArg, const vector& instName) { + Class inst; + inst.name = cls.name; + inst.templateArgs = cls.templateArgs; + inst.typedefName = cls.typedefName; + inst.isVirtual = cls.isVirtual; + inst.qualifiedParent = cls.qualifiedParent; + inst.methods = expandMethodTemplate(cls.methods, templateArg, instName); + inst.static_methods = expandMethodTemplate(cls.static_methods, templateArg, instName); + inst.namespaces = cls.namespaces; + inst.using_namespaces = cls.using_namespaces; + bool allIncludesEmpty = true; + BOOST_FOREACH(const string& inc, cls.includes) { if(!inc.empty()) { allIncludesEmpty = true; break; } } + if(allIncludesEmpty) + inst.includes.push_back(cls.name + ".h"); + else + inst.includes = cls.includes; + inst.constructor = cls.constructor; + inst.constructor.args_list = expandArgumentListsTemplate(cls.constructor.args_list, templateArg, instName); + inst.constructor.name = inst.name; + inst.deconstructor = cls.deconstructor; + inst.deconstructor.name = inst.name; + inst.verbose_ = cls.verbose_; + return inst; +} + /* ************************************************************************* */ vector Class::expandTemplate(const string& templateArg, const vector >& instantiations) const { vector result; BOOST_FOREACH(const vector& instName, instantiations) { - Class inst; + Class inst = expandClassTemplate(*this, templateArg, instName); inst.name = name + instName.back(); + inst.templateArgs.clear(); inst.typedefName = qualifiedName("::") + "<" + wrap::qualifiedName("::", instName) + ">"; - inst.isVirtual = isVirtual; - inst.qualifiedParent = qualifiedParent; - inst.methods = expandMethodTemplate(methods, templateArg, instName); - inst.static_methods = expandMethodTemplate(static_methods, templateArg, instName); - inst.namespaces = namespaces; - inst.using_namespaces = using_namespaces; - bool allIncludesEmpty = true; - BOOST_FOREACH(const string& inc, includes) { if(!inc.empty()) { allIncludesEmpty = true; break; } } - if(allIncludesEmpty) - inst.includes.push_back(name + ".h"); - else - inst.includes = includes; - inst.constructor = constructor; - inst.constructor.args_list = expandArgumentListsTemplate(constructor.args_list, templateArg, instName); - inst.constructor.name = inst.name; - inst.deconstructor = deconstructor; - inst.deconstructor.name = inst.name; - inst.verbose_ = verbose_; result.push_back(inst); } return result; } +/* ************************************************************************* */ +Class Class::expandTemplate(const string& templateArg, const vector& instantiation) const { + return expandClassTemplate(*this, templateArg, instantiation); +} + /* ************************************************************************* */ std::string Class::getTypedef() const { string result; diff --git a/wrap/Class.h b/wrap/Class.h index 9b0af4bb4..4626a901a 100644 --- a/wrap/Class.h +++ b/wrap/Class.h @@ -38,6 +38,7 @@ struct Class { // Then the instance variables are set directly by the Module constructor std::string name; ///< Class name + std::vector templateArgs; ///< Template arguments std::string typedefName; ///< The name to typedef *from*, if this class is actually a typedef, i.e. typedef [typedefName] [name] bool isVirtual; ///< Whether the class is part of a virtual inheritance chain std::vector qualifiedParent; ///< The *single* parent - the last string is the parent class name, preceededing elements are a namespace stack @@ -56,6 +57,7 @@ struct Class { std::string qualifiedName(const std::string& delim = "") const; ///< creates a namespace-qualified name, optional delimiter std::vector expandTemplate(const std::string& templateArg, const std::vector >& instantiations) const; + Class expandTemplate(const std::string& templateArg, const std::vector& instantiation) const; // The typedef line for this class, if this class is a typedef, otherwise returns an empty string. std::string getTypedef() const; diff --git a/wrap/Module.cpp b/wrap/Module.cpp index b50591176..3cc5af18e 100644 --- a/wrap/Module.cpp +++ b/wrap/Module.cpp @@ -88,6 +88,7 @@ Module::Module(const string& interfacePath, string templateArgument; vector templateInstantiationNamespace; vector > templateInstantiations; + TemplateSingleInstantiation singleInstantiation, singleInstantiation0; string include_path = ""; const string null_str = ""; @@ -145,10 +146,34 @@ Module::Module(const string& interfacePath, [clear_a(templateInstantiationNamespace)]; Rule templateInstantiations_p = - str_p("template") >> + (str_p("template") >> '<' >> name_p[assign_a(templateArgument)] >> '=' >> '{' >> !(templateInstantiation_p >> *(',' >> templateInstantiation_p)) >> - '}' >> '>'; + '}' >> '>') + [push_back_a(cls.templateArgs, templateArgument)]; + + Rule templateSingleInstantiationArg_p = + (*(namespace_name_p[push_back_a(templateInstantiationNamespace)] >> str_p("::")) >> + className_p[push_back_a(templateInstantiationNamespace)]) + [push_back_a(singleInstantiation.typeList, templateInstantiationNamespace)] + [clear_a(templateInstantiationNamespace)]; + + Rule templateSingleInstantiation_p = + (str_p("typedef") >> + *(namespace_name_p[push_back_a(singleInstantiation.classNamespaces)] >> str_p("::")) >> + className_p[assign_a(singleInstantiation.className)] >> + '<' >> templateSingleInstantiationArg_p >> *(',' >> templateSingleInstantiationArg_p) >> + '>' >> + className_p[assign_a(singleInstantiation.name)] >> + ';') + [assign_a(singleInstantiation.namespaces, namespaces)] + [push_back_a(singleInstantiations, singleInstantiation)] + [assign_a(singleInstantiation, singleInstantiation0)]; + + Rule templateList_p = + (str_p("template") >> + '<' >> name_p[push_back_a(cls.templateArgs)] >> *(',' >> name_p[push_back_a(cls.templateArgs)]) >> + '>'); Rule argument_p = ((basisType_p[assign_a(arg.type)] | argEigenType_p | eigenRef_p | classArg_p) @@ -230,7 +255,7 @@ Module::Module(const string& interfacePath, Rule class_p = (!*include_p - >> !(templateInstantiations_p) + >> !(templateInstantiations_p | templateList_p) >> !(str_p("virtual")[assign_a(cls.isVirtual, true)]) >> str_p("class")[push_back_a(cls.includes, include_path)][assign_a(include_path, null_str)] >> className_p[assign_a(cls.name)] @@ -256,7 +281,7 @@ Module::Module(const string& interfacePath, >> str_p("namespace")[push_back_a(namespace_includes, include_path)][assign_a(include_path, null_str)] >> namespace_name_p[push_back_a(namespaces)] >> ch_p('{') - >> *(class_p | namespace_def_p | comments_p) + >> *(class_p | templateSingleInstantiation_p | namespace_def_p | comments_p) >> str_p("}///\\namespace") // end namespace, avoid confusion with classes >> !namespace_name_p) [pop_a(namespaces)] @@ -274,7 +299,7 @@ Module::Module(const string& interfacePath, [push_back_a(forward_declarations, fwDec)] [assign_a(fwDec, fwDec0)]; - Rule module_content_p = comments_p | using_namespace_p | class_p | forward_declaration_p | namespace_def_p ; + Rule module_content_p = comments_p | using_namespace_p | class_p | templateSingleInstantiation_p | forward_declaration_p | namespace_def_p ; Rule module_p = *module_content_p >> !end_p; @@ -388,6 +413,9 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co wrapperFile.oss << "#include \n"; wrapperFile.oss << "\n"; + // Expand templates + vector expandedClasses = expandTemplates(); + // Dependency check list vector validTypes; BOOST_FOREACH(const ForwardDeclaration& fwDec, forward_declarations) { @@ -404,7 +432,7 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co validTypes.push_back("Vector"); validTypes.push_back("Matrix"); //Create a list of parsed classes for dependency checking - BOOST_FOREACH(const Class& cls, classes) { + BOOST_FOREACH(const Class& cls, expandedClasses) { validTypes.push_back(cls.qualifiedName("::")); } @@ -414,12 +442,12 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co if(!typeAttributes.insert(make_pair(fwDec.name, ReturnValue::TypeAttributes(fwDec.isVirtual))).second) throw DuplicateDefinition("class " + fwDec.name); } - BOOST_FOREACH(const Class& cls, classes) { + BOOST_FOREACH(const Class& cls, expandedClasses) { if(!typeAttributes.insert(make_pair(cls.qualifiedName("::"), ReturnValue::TypeAttributes(cls.isVirtual))).second) throw DuplicateDefinition("class " + cls.qualifiedName("::")); } // Check attributes - BOOST_FOREACH(const Class& cls, classes) { + BOOST_FOREACH(const Class& cls, expandedClasses) { // Check that class is virtual if it has a parent if(!cls.qualifiedParent.empty() && !cls.isVirtual) throw AttributeError(cls.qualifiedName("::"), "Has a base class so needs to be declared virtual, change to 'virtual class "+cls.name+" ...'"); @@ -430,7 +458,7 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co } // Check that all classes have been defined somewhere - BOOST_FOREACH(const Class& cls, classes) { + BOOST_FOREACH(const Class& cls, expandedClasses) { // verify all of the function arguments //TODO:verifyArguments(validTypes, cls.constructor.args_list); verifyArguments(validTypes, cls.static_methods); @@ -445,14 +473,14 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co generateIncludes(wrapperFile); // create typedef classes - BOOST_FOREACH(const Class& cls, classes) { + BOOST_FOREACH(const Class& cls, expandedClasses) { if(!cls.typedefName.empty()) wrapperFile.oss << cls.getTypedef() << "\n"; } wrapperFile.oss << "\n"; // Generate all collectors - BOOST_FOREACH(const Class& cls, classes) { + BOOST_FOREACH(const Class& cls, expandedClasses) { const string matlabName = cls.qualifiedName(), cppName = cls.qualifiedName("::"); wrapperFile.oss << "typedef std::set*> " << "Collector_" << matlabName << ";\n"; @@ -463,7 +491,7 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co // generate mexAtExit cleanup function wrapperFile.oss << "\nvoid _deleteAllObjects()\n"; wrapperFile.oss << "{\n"; - BOOST_FOREACH(const Class& cls, classes) { + BOOST_FOREACH(const Class& cls, expandedClasses) { const string matlabName = cls.qualifiedName(); const string cppName = cls.qualifiedName("::"); const string collectorType = "Collector_" + matlabName; @@ -482,7 +510,7 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co "static bool _RTTIRegister_" << name << "_done = false;\n" "void _" << name << "_RTTIRegister() {\n" " std::map types;\n"; - BOOST_FOREACH(const Class& cls, classes) { + BOOST_FOREACH(const Class& cls, expandedClasses) { if(cls.isVirtual) wrapperFile.oss << " types.insert(std::make_pair(typeid(" << cls.qualifiedName("::") << ").name(), \"" << cls.qualifiedName() << "\"));\n"; @@ -509,7 +537,7 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co } // create proxy class and wrapper code - BOOST_FOREACH(const Class& cls, classes) { + BOOST_FOREACH(const Class& cls, expandedClasses) { string classFile = toolboxPath + "/" + cls.qualifiedName() + ".m"; cls.matlab_proxy(classFile, wrapperName, typeAttributes, wrapperFile, functionNames); } @@ -545,3 +573,53 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co } /* ************************************************************************* */ +vector Module::expandTemplates() const { + + vector expandedClasses = classes; + + BOOST_FOREACH(const TemplateSingleInstantiation& inst, singleInstantiations) { + // Find matching class + std::vector::iterator clsIt = expandedClasses.end(); + for(std::vector::iterator it = expandedClasses.begin(); it != expandedClasses.end(); ++it) { + if(it->name == inst.className && it->namespaces == inst.classNamespaces && it->templateArgs.size() == inst.typeList.size()) { + clsIt = it; + break; + } + } + + if(clsIt == expandedClasses.end()) + throw DependencyMissing(wrap::qualifiedName("::", inst.classNamespaces, inst.className), + "instantiation into typedef name " + wrap::qualifiedName("::", inst.namespaces, inst.name) + + ". Ensure that the typedef provides the correct number of template arguments."); + + // Instantiate it + Class classInst = *clsIt; + for(size_t i = 0; i < inst.typeList.size(); ++i) + classInst = classInst.expandTemplate(classInst.templateArgs[i], inst.typeList[i]); + + // Fix class properties + classInst.name = inst.name; + classInst.templateArgs.clear(); + classInst.typedefName = clsIt->qualifiedName("::") + "<"; + if(inst.typeList.size() > 0) + classInst.typedefName += wrap::qualifiedName("::", inst.typeList[0]); + for(size_t i = 1; i < inst.typeList.size(); ++i) + classInst.typedefName += (", " + wrap::qualifiedName("::", inst.typeList[i])); + classInst.typedefName += ">"; + classInst.namespaces = inst.namespaces; + + // Add the new class to the list + expandedClasses.push_back(classInst); + } + + // Remove all template classes + for(int i = 0; i < expandedClasses.size(); ++i) + if(!expandedClasses[size_t(i)].templateArgs.empty()) { + expandedClasses.erase(expandedClasses.begin() + size_t(i)); + -- i; + } + + return expandedClasses; +} + +/* ************************************************************************* */ diff --git a/wrap/Module.h b/wrap/Module.h index 786379d16..42089291c 100644 --- a/wrap/Module.h +++ b/wrap/Module.h @@ -36,8 +36,17 @@ struct Module { ForwardDeclaration() : isVirtual(false) {} }; + struct TemplateSingleInstantiation { + std::vector classNamespaces; + std::string className; + std::vector namespaces; + std::string name; + std::vector > typeList; + }; + std::string name; ///< module name std::vector classes; ///< list of classes + std::vector singleInstantiations; ///< list of template instantiations bool verbose; ///< verbose flag // std::vector using_namespaces; ///< all default namespaces std::vector forward_declarations; @@ -55,6 +64,9 @@ struct Module { void finish_wrapper(FileWriter& file, const std::vector& functionNames) const; void generateIncludes(FileWriter& file) const; + +private: + std::vector expandTemplates() const; }; } // \namespace wrap