Can define template classes in wrap interface file with a fixed list of template argument expansions, to quickly generate many classes, e.g. template<T = {gtsam::Point2,gtsam::Point3}> class BetweenFactor ... generates gtsamBetweenFactorPoint2, gtsamBetweenFactorPoint3, etc.
parent
42dec286ee
commit
c4f19a2b96
|
@ -211,3 +211,90 @@ void Class::pointer_constructor_fragments(FileWriter& proxyFile, FileWriter& wra
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
vector<ArgumentList> expandArgumentListsTemplate(const vector<ArgumentList>& argLists, const string& templateArg, const vector<string>& instName) {
|
||||||
|
vector<ArgumentList> 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<class METHOD>
|
||||||
|
map<string, METHOD> expandMethodTemplate(const map<string, METHOD>& methods, const string& templateArg, const vector<string>& instName) {
|
||||||
|
map<string, METHOD> result;
|
||||||
|
typedef pair<const string, METHOD> 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> Class::expandTemplate(const string& templateArg, const vector<vector<string> >& instantiations) const {
|
||||||
|
vector<Class> result;
|
||||||
|
BOOST_FOREACH(const vector<string>& 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
|
|
@ -38,6 +38,7 @@ struct Class {
|
||||||
|
|
||||||
// Then the instance variables are set directly by the Module constructor
|
// Then the instance variables are set directly by the Module constructor
|
||||||
std::string name; ///< Class name
|
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
|
bool isVirtual; ///< Whether the class is part of a virtual inheritance chain
|
||||||
std::vector<std::string> qualifiedParent; ///< The *single* parent - the last string is the parent class name, preceededing elements are a namespace stack
|
std::vector<std::string> qualifiedParent; ///< The *single* parent - the last string is the parent class name, preceededing elements are a namespace stack
|
||||||
Methods methods; ///< Class methods
|
Methods methods; ///< Class methods
|
||||||
|
@ -54,6 +55,11 @@ struct Class {
|
||||||
FileWriter& wrapperFile, std::vector<std::string>& functionNames) const; ///< emit proxy class
|
FileWriter& wrapperFile, std::vector<std::string>& functionNames) const; ///< emit proxy class
|
||||||
std::string qualifiedName(const std::string& delim = "") const; ///< creates a namespace-qualified name, optional delimiter
|
std::string qualifiedName(const std::string& delim = "") const; ///< creates a namespace-qualified name, optional delimiter
|
||||||
|
|
||||||
|
std::vector<Class> expandTemplate(const std::string& templateArg, const std::vector<std::vector<std::string> >& instantiations) const;
|
||||||
|
|
||||||
|
// The typedef line for this class, if this class is a typedef, otherwise returns an empty string.
|
||||||
|
std::string getTypedef() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void pointer_constructor_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, const std::string& wrapperName, std::vector<std::string>& functionNames) const;
|
void pointer_constructor_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, const std::string& wrapperName, std::vector<std::string>& functionNames) const;
|
||||||
};
|
};
|
||||||
|
|
|
@ -51,6 +51,19 @@ typedef rule<BOOST_SPIRIT_CLASSIC_NS::phrase_scanner_t> Rule;
|
||||||
// and with start rule [class_p], doubles as the specs for our interface files.
|
// and with start rule [class_p], doubles as the specs for our interface files.
|
||||||
/* ************************************************************************* */
|
/* ************************************************************************* */
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
|
void handle_possible_template(vector<Class>& classes, const Class& cls, const string& templateArgument, const vector<vector<string> >& instantiations) {
|
||||||
|
if(instantiations.empty()) {
|
||||||
|
classes.push_back(cls);
|
||||||
|
} else {
|
||||||
|
vector<Class>& classInstantiations = cls.expandTemplate(templateArgument, instantiations);
|
||||||
|
BOOST_FOREACH(const Class& c, classInstantiations) {
|
||||||
|
classes.push_back(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ************************************************************************* */
|
||||||
Module::Module(const string& interfacePath,
|
Module::Module(const string& interfacePath,
|
||||||
const string& moduleName, bool enable_verbose) : name(moduleName), verbose(enable_verbose)
|
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
|
namespace_includes, /// current set of includes
|
||||||
namespaces_return, /// namespace for current return type
|
namespaces_return, /// namespace for current return type
|
||||||
using_namespace_current; /// All namespaces from "using" declarations
|
using_namespace_current; /// All namespaces from "using" declarations
|
||||||
|
string templateArgument;
|
||||||
|
vector<string> templateInstantiationNamespace;
|
||||||
|
vector<vector<string> > templateInstantiations;
|
||||||
string include_path = "";
|
string include_path = "";
|
||||||
const string null_str = "";
|
const string null_str = "";
|
||||||
|
|
||||||
|
@ -116,11 +132,23 @@ Module::Module(const string& interfacePath,
|
||||||
className_p[assign_a(arg.type)] >>
|
className_p[assign_a(arg.type)] >>
|
||||||
(ch_p('*')[assign_a(arg.is_ptr,true)] | ch_p('&')[assign_a(arg.is_ref,true)]);
|
(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 =
|
Rule classParent_p =
|
||||||
*(namespace_name_p[push_back_a(cls.qualifiedParent)] >> str_p("::")) >>
|
*(namespace_name_p[push_back_a(cls.qualifiedParent)] >> str_p("::")) >>
|
||||||
className_p[push_back_a(cls.qualifiedParent)];
|
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 =
|
Rule argument_p =
|
||||||
((basisType_p[assign_a(arg.type)] | argEigenType_p | eigenRef_p | classArg_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 =
|
Rule class_p =
|
||||||
(!*include_p
|
(!*include_p
|
||||||
|
>> !(templateInstantiations_p)
|
||||||
>> !(str_p("virtual")[assign_a(cls.isVirtual, true)])
|
>> !(str_p("virtual")[assign_a(cls.isVirtual, true)])
|
||||||
>> str_p("class")[push_back_a(cls.includes, include_path)][assign_a(include_path, null_str)]
|
>> str_p("class")[push_back_a(cls.includes, include_path)][assign_a(include_path, null_str)]
|
||||||
>> className_p[assign_a(cls.name)]
|
>> 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)
|
>> *(functions_p | comments_p)
|
||||||
>> str_p("};"))
|
>> str_p("};"))
|
||||||
[assign_a(constructor.name, cls.name)]
|
[assign_a(constructor.name, cls.name)]
|
||||||
|
@ -215,10 +244,12 @@ Module::Module(const string& interfacePath,
|
||||||
[append_a(cls.includes, namespace_includes)]
|
[append_a(cls.includes, namespace_includes)]
|
||||||
[assign_a(deconstructor.name,cls.name)]
|
[assign_a(deconstructor.name,cls.name)]
|
||||||
[assign_a(cls.deconstructor, deconstructor)]
|
[assign_a(cls.deconstructor, deconstructor)]
|
||||||
[push_back_a(classes, cls)]
|
[bl::bind(&handle_possible_template, bl::var(classes), bl::var(cls), bl::var(templateArgument), bl::var(templateInstantiations))]
|
||||||
[assign_a(deconstructor,deconstructor0)]
|
[assign_a(deconstructor,deconstructor0)]
|
||||||
[assign_a(constructor, constructor0)]
|
[assign_a(constructor, constructor0)]
|
||||||
[assign_a(cls,cls0)];
|
[assign_a(cls,cls0)]
|
||||||
|
[clear_a(templateArgument)]
|
||||||
|
[clear_a(templateInstantiations)];
|
||||||
|
|
||||||
Rule namespace_def_p =
|
Rule namespace_def_p =
|
||||||
(!*include_p
|
(!*include_p
|
||||||
|
@ -413,6 +444,13 @@ void Module::matlab_code(const string& toolboxPath, const string& headerPath) co
|
||||||
// Generate includes while avoiding redundant includes
|
// Generate includes while avoiding redundant includes
|
||||||
generateIncludes(wrapperFile);
|
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
|
// Generate all collectors
|
||||||
BOOST_FOREACH(const Class& cls, classes) {
|
BOOST_FOREACH(const Class& cls, classes) {
|
||||||
const string matlabName = cls.qualifiedName(), cppName = cls.qualifiedName("::");
|
const string matlabName = cls.qualifiedName(), cppName = cls.qualifiedName("::");
|
||||||
|
|
Loading…
Reference in New Issue