Added support for multi-argument templates that are then instantiated with typedefs in wrap interface header.

release/4.3a0
Richard Roberts 2012-07-12 02:11:29 +00:00
parent 8d661f6e86
commit 76e5375dea
4 changed files with 141 additions and 33 deletions

View File

@ -248,42 +248,58 @@ map<string, METHOD> expandMethodTemplate(const map<string, METHOD>& 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<string>& 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> Class::expandTemplate(const string& templateArg, const vector<vector<string> >& instantiations) const {
vector<Class> result;
BOOST_FOREACH(const vector<string>& 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<string>& instantiation) const {
return expandClassTemplate(*this, templateArg, instantiation);
}
/* ************************************************************************* */
std::string Class::getTypedef() const {
string 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::vector<std::string> 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<std::string> 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<Class> expandTemplate(const std::string& templateArg, const std::vector<std::vector<std::string> >& instantiations) const;
Class expandTemplate(const std::string& templateArg, const std::vector<std::string>& instantiation) const;
// The typedef line for this class, if this class is a typedef, otherwise returns an empty string.
std::string getTypedef() const;

View File

@ -88,6 +88,7 @@ Module::Module(const string& interfacePath,
string templateArgument;
vector<string> templateInstantiationNamespace;
vector<vector<string> > 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 <boost/foreach.hpp>\n";
wrapperFile.oss << "\n";
// Expand templates
vector<Class> expandedClasses = expandTemplates();
// Dependency check list
vector<string> 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<ArgumentList>(validTypes, cls.constructor.args_list);
verifyArguments<StaticMethod>(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<boost::shared_ptr<" << cppName << ">*> "
<< "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<std::string, std::string> 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<Class> Module::expandTemplates() const {
vector<Class> expandedClasses = classes;
BOOST_FOREACH(const TemplateSingleInstantiation& inst, singleInstantiations) {
// Find matching class
std::vector<Class>::iterator clsIt = expandedClasses.end();
for(std::vector<Class>::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;
}
/* ************************************************************************* */

View File

@ -36,8 +36,17 @@ struct Module {
ForwardDeclaration() : isVirtual(false) {}
};
struct TemplateSingleInstantiation {
std::vector<std::string> classNamespaces;
std::string className;
std::vector<std::string> namespaces;
std::string name;
std::vector<std::vector<std::string> > typeList;
};
std::string name; ///< module name
std::vector<Class> classes; ///< list of classes
std::vector<TemplateSingleInstantiation> singleInstantiations; ///< list of template instantiations
bool verbose; ///< verbose flag
// std::vector<std::string> using_namespaces; ///< all default namespaces
std::vector<ForwardDeclaration> forward_declarations;
@ -55,6 +64,9 @@ struct Module {
void finish_wrapper(FileWriter& file, const std::vector<std::string>& functionNames) const;
void generateIncludes(FileWriter& file) const;
private:
std::vector<Class> expandTemplates() const;
};
} // \namespace wrap