From c4f19a2b96c65c588d3b9baa1f0fe013ca1f9af7 Mon Sep 17 00:00:00 2001 From: Richard Roberts Date: Wed, 11 Jul 2012 21:43:16 +0000 Subject: [PATCH] Can define template classes in wrap interface file with a fixed list of template argument expansions, to quickly generate many classes, e.g. template class BetweenFactor ... generates gtsamBetweenFactorPoint2, gtsamBetweenFactorPoint3, etc. --- wrap/Class.cpp | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ wrap/Class.h | 6 ++++ wrap/Module.cpp | 50 ++++++++++++++++++++++++---- 3 files changed, 137 insertions(+), 6 deletions(-) diff --git a/wrap/Class.cpp b/wrap/Class.cpp index bc28ad6c0..81ee508a0 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -211,3 +211,90 @@ void Class::pointer_constructor_fragments(FileWriter& proxyFile, FileWriter& wra } /* ************************************************************************* */ +vector expandArgumentListsTemplate(const vector& argLists, const string& templateArg, const vector& instName) { + vector result; + BOOST_FOREACH(const ArgumentList& argList, argLists) { + ArgumentList instArgList; + BOOST_FOREACH(const Argument& arg, argList) { + Argument instArg = arg; + if(arg.type == templateArg) { + instArg.namespaces.assign(instName.begin(), instName.end()-1); + instArg.type = instName.back(); + } + instArgList.push_back(instArg); + } + result.push_back(instArgList); + } + return result; +} + +/* ************************************************************************* */ +template +map expandMethodTemplate(const map& methods, const string& templateArg, const vector& instName) { + map result; + typedef pair Name_Method; + BOOST_FOREACH(const Name_Method& name_method, methods) { + const METHOD& method = name_method.second; + METHOD instMethod = method; + instMethod.argLists = expandArgumentListsTemplate(method.argLists, templateArg, instName); + instMethod.returnVals.clear(); + BOOST_FOREACH(const ReturnValue& retVal, method.returnVals) { + ReturnValue instRetVal = retVal; + if(retVal.type1 == templateArg) { + instRetVal.namespaces1.assign(instName.begin(), instName.end()-1); + instRetVal.type1 = instName.back(); + } + if(retVal.type2 == templateArg) { + instRetVal.namespaces2.assign(instName.begin(), instName.end()-1); + instRetVal.type2 = instName.back(); + } + } + result.insert(make_pair(name_method.first, instMethod)); + } + return result; +} + +/* ************************************************************************* */ +vector Class::expandTemplate(const string& templateArg, const vector >& instantiations) const { + vector result; + BOOST_FOREACH(const vector& instName, instantiations) { + Class inst; + inst.name = name + instName.back(); + 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; +} + +/* ************************************************************************* */ +std::string Class::getTypedef() const { + string result; + BOOST_FOREACH(const string& namesp, namespaces) { + result += ("namespace " + namesp + " { "); + } + result += ("typedef " + typedefName + " " + name + ";"); + BOOST_FOREACH(const string& namesp, namespaces) { + result += " }"; + } + return result; +} + +/* ************************************************************************* */ diff --git a/wrap/Class.h b/wrap/Class.h index f4087f00f..9b0af4bb4 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::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 Methods methods; ///< Class methods @@ -54,6 +55,11 @@ struct Class { FileWriter& wrapperFile, std::vector& functionNames) const; ///< emit proxy 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; + + // The typedef line for this class, if this class is a typedef, otherwise returns an empty string. + std::string getTypedef() const; + private: void pointer_constructor_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, const std::string& wrapperName, std::vector& functionNames) const; }; diff --git a/wrap/Module.cpp b/wrap/Module.cpp index 997e14266..b50591176 100644 --- a/wrap/Module.cpp +++ b/wrap/Module.cpp @@ -51,6 +51,19 @@ typedef rule Rule; // and with start rule [class_p], doubles as the specs for our interface files. /* ************************************************************************* */ +/* ************************************************************************* */ +void handle_possible_template(vector& classes, const Class& cls, const string& templateArgument, const vector >& instantiations) { + if(instantiations.empty()) { + classes.push_back(cls); + } else { + vector& classInstantiations = cls.expandTemplate(templateArgument, instantiations); + BOOST_FOREACH(const Class& c, classInstantiations) { + classes.push_back(c); + } + } +} + +/* ************************************************************************* */ Module::Module(const string& interfacePath, const string& moduleName, bool enable_verbose) : name(moduleName), verbose(enable_verbose) { @@ -72,6 +85,9 @@ Module::Module(const string& interfacePath, namespace_includes, /// current set of includes namespaces_return, /// namespace for current return type using_namespace_current; /// All namespaces from "using" declarations + string templateArgument; + vector templateInstantiationNamespace; + vector > templateInstantiations; string include_path = ""; const string null_str = ""; @@ -116,11 +132,23 @@ Module::Module(const string& interfacePath, className_p[assign_a(arg.type)] >> (ch_p('*')[assign_a(arg.is_ptr,true)] | ch_p('&')[assign_a(arg.is_ref,true)]); + Rule name_p = lexeme_d[alpha_p >> *(alnum_p | '_')]; + Rule classParent_p = *(namespace_name_p[push_back_a(cls.qualifiedParent)] >> str_p("::")) >> className_p[push_back_a(cls.qualifiedParent)]; - Rule name_p = lexeme_d[alpha_p >> *(alnum_p | '_')]; + Rule templateInstantiation_p = + (*(namespace_name_p[push_back_a(templateInstantiationNamespace)] >> str_p("::")) >> + className_p[push_back_a(templateInstantiationNamespace)]) + [push_back_a(templateInstantiations, templateInstantiationNamespace)] + [clear_a(templateInstantiationNamespace)]; + + Rule templateInstantiations_p = + str_p("template") >> + '<' >> name_p[assign_a(templateArgument)] >> '=' >> '{' >> + !(templateInstantiation_p >> *(',' >> templateInstantiation_p)) >> + '}' >> '>'; Rule argument_p = ((basisType_p[assign_a(arg.type)] | argEigenType_p | eigenRef_p | classArg_p) @@ -202,10 +230,11 @@ Module::Module(const string& interfacePath, Rule class_p = (!*include_p + >> !(templateInstantiations_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)] - >> ((':' >> classParent_p >> '{') | '{') // By having (parent >> '{' | '{') here instead of (!parent >> '{'), we trigger a parse error on a badly-formed parent spec + >> ((':' >> classParent_p >> '{') | '{') >> *(functions_p | comments_p) >> str_p("};")) [assign_a(constructor.name, cls.name)] @@ -215,10 +244,12 @@ Module::Module(const string& interfacePath, [append_a(cls.includes, namespace_includes)] [assign_a(deconstructor.name,cls.name)] [assign_a(cls.deconstructor, deconstructor)] - [push_back_a(classes, cls)] - [assign_a(deconstructor,deconstructor0)] - [assign_a(constructor, constructor0)] - [assign_a(cls,cls0)]; + [bl::bind(&handle_possible_template, bl::var(classes), bl::var(cls), bl::var(templateArgument), bl::var(templateInstantiations))] + [assign_a(deconstructor,deconstructor0)] + [assign_a(constructor, constructor0)] + [assign_a(cls,cls0)] + [clear_a(templateArgument)] + [clear_a(templateInstantiations)]; Rule namespace_def_p = (!*include_p @@ -413,6 +444,13 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co // Generate includes while avoiding redundant includes generateIncludes(wrapperFile); + // create typedef classes + BOOST_FOREACH(const Class& cls, classes) { + if(!cls.typedefName.empty()) + wrapperFile.oss << cls.getTypedef() << "\n"; + } + wrapperFile.oss << "\n"; + // Generate all collectors BOOST_FOREACH(const Class& cls, classes) { const string matlabName = cls.qualifiedName(), cppName = cls.qualifiedName("::");