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.

release/4.3a0
Richard Roberts 2012-07-11 21:43:16 +00:00
parent 42dec286ee
commit c4f19a2b96
3 changed files with 137 additions and 6 deletions

View File

@ -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;
}
/* ************************************************************************* */

View File

@ -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<std::string> 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<std::string>& functionNames) const; ///< emit proxy class
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:
void pointer_constructor_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, const std::string& wrapperName, std::vector<std::string>& functionNames) const;
};

View File

@ -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.
/* ************************************************************************* */
/* ************************************************************************* */
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,
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<string> templateInstantiationNamespace;
vector<vector<string> > 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)]
[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)];
[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("::");