From 16ba6ba254c87a8710bda21fe8fe7a430601bbf3 Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 12:52:01 +0100 Subject: [PATCH 01/12] Added Function Base class --- wrap/Function.cpp | 71 ++++++++++++++++++++++++++++++ wrap/Function.h | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 wrap/Function.cpp create mode 100644 wrap/Function.h diff --git a/wrap/Function.cpp b/wrap/Function.cpp new file mode 100644 index 000000000..8fd1d0655 --- /dev/null +++ b/wrap/Function.cpp @@ -0,0 +1,71 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file Function.ccp + * @author Frank Dellaert + * @date Nov 13, 2014 + **/ + +#include "Function.h" +#include "utilities.h" + +#include +#include +#include + +#include +#include + +using namespace std; +using namespace wrap; + +/* ************************************************************************* */ +void Function::addOverload(bool verbose, const std::string& name, + const ArgumentList& args, const ReturnValue& retVal, + const Qualified& instName) { + + // Check if this overload is give to the correct method + if (name_.empty()) + name_ = name; + else if (name_ != name) + throw std::runtime_error( + "Function::addOverload: tried to add overload with name " + name + + " instead of expected " + name_); + + // Check if this overload is give to the correct method + if (templateArgValue_.empty()) + templateArgValue_ = instName; + else if (templateArgValue_ != instName) + throw std::runtime_error( + "Function::addOverload: tried to add overload with template argument " + + instName.qualifiedName(":") + " instead of expected " + + templateArgValue_.qualifiedName(":")); + + verbose_ = verbose; + argLists.push_back(args); + returnVals.push_back(retVal); +} + +/* ************************************************************************* */ +vector Function::expandArgumentListsTemplate( + const string& templateArg, const Qualified& qualifiedType, + const Qualified& expandedClass) const { + vector result; + BOOST_FOREACH(const ArgumentList& argList, argLists) { + ArgumentList instArgList = argList.expandTemplate(templateArg, + qualifiedType, expandedClass); + result.push_back(instArgList); + } + return result; +} + +/* ************************************************************************* */ diff --git a/wrap/Function.h b/wrap/Function.h new file mode 100644 index 000000000..76b513907 --- /dev/null +++ b/wrap/Function.h @@ -0,0 +1,109 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file Function.h + * @brief Base class for global functions and methods + * @author Frank Dellaert + * @date Nov 13, 2014 + **/ + +#pragma once + +#include "Argument.h" +#include "ReturnValue.h" +#include "TypeAttributesTable.h" + +#include +#include + +namespace wrap { + +/// Function class +struct Function { + + /// Constructor creates empty object + Function(bool verbose = true) : + verbose_(verbose) { + } + + Function(const std::string& name, bool verbose = true) : + verbose_(verbose), name_(name) { + } + + bool verbose_; + std::string name_; ///< name of method + Qualified templateArgValue_; ///< value of template argument if applicable + std::vector argLists; + std::vector returnVals; + + // The first time this function is called, it initializes the class members + // with those in rhs, but in subsequent calls it adds additional argument + // lists as function overloads. + void addOverload(bool verbose, const std::string& name, + const ArgumentList& args, const ReturnValue& retVal, + const Qualified& instName = Qualified()); + + std::vector expandArgumentListsTemplate( + const std::string& templateArg, const Qualified& qualifiedType, + const Qualified& expandedClass) const; +}; + +// Templated checking functions +// TODO: do this via polymorphism ? + +template +FUNCTION expandMethodTemplate(const FUNCTION& method, + const std::string& templateArg, const Qualified& qualifiedType, + const Qualified& expandedClass) { + // Create new instance + FUNCTION instMethod = method; + // substitute template in arguments + instMethod.argLists = method.expandArgumentListsTemplate(templateArg, + qualifiedType, expandedClass); + // do the same for return types + instMethod.returnVals = ReturnValue::ExpandTemplate(method.returnVals, + templateArg, qualifiedType, expandedClass); + // return new method + return instMethod; +} + +// TODO use transform +template +static std::map expandMethodTemplate( + const std::map& methods, + const std::string& templateArg, const Qualified& qualifiedType, + const Qualified& expandedClass) { + std::map result; + typedef std::pair NamedMethod; + BOOST_FOREACH(NamedMethod namedMethod, methods) { + namedMethod.second = expandMethodTemplate(namedMethod.second, templateArg, + qualifiedType, expandedClass); + result.insert(namedMethod); + } + return result; +} +template +inline void verifyReturnTypes(const std::vector& validtypes, + const std::map& vt) { + typedef typename std::map::value_type NamedMethod; + BOOST_FOREACH(const NamedMethod& namedMethod, vt) { + const T& t = namedMethod.second; + BOOST_FOREACH(const ReturnValue& retval, t.returnVals) { + retval.type1.verify(validtypes, t.name_); + if (retval.isPair) + retval.type2.verify(validtypes, t.name_); + } + } +} + +} // \namespace wrap + From a5e0adb7e6815c7f2c848bb3e9eb811883f6c1f3 Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 12:52:41 +0100 Subject: [PATCH 02/12] Made methods and global functions derive from Function --- wrap/Argument.cpp | 35 +++++++++++++++--- wrap/Argument.h | 13 +++++-- wrap/Class.cpp | 80 +++++++---------------------------------- wrap/Constructor.cpp | 13 +++++++ wrap/Constructor.h | 5 +++ wrap/GlobalFunction.cpp | 17 +++------ wrap/GlobalFunction.h | 24 +++++-------- wrap/Method.cpp | 39 +++++++++----------- wrap/Method.h | 17 ++------- wrap/Module.cpp | 4 +-- wrap/Qualified.h | 4 +++ wrap/ReturnValue.cpp | 2 +- wrap/ReturnValue.h | 29 ++++++++------- wrap/StaticMethod.cpp | 23 ++++-------- wrap/StaticMethod.h | 20 ++--------- wrap/tests/testWrap.cpp | 18 +++++----- 16 files changed, 146 insertions(+), 197 deletions(-) diff --git a/wrap/Argument.cpp b/wrap/Argument.cpp index cc235207a..dbf1e93f9 100644 --- a/wrap/Argument.cpp +++ b/wrap/Argument.cpp @@ -28,12 +28,37 @@ using namespace std; using namespace wrap; +/* ************************************************************************* */ +Argument Argument::expandTemplate(const string& templateArg, + const Qualified& qualifiedType, const Qualified& expandedClass) const { + Argument instArg = *this; + if (type.name == templateArg) { + instArg.type = qualifiedType; + } else if (type.name == "This") { + instArg.type = expandedClass; + } + return instArg; +} + +/* ************************************************************************* */ +ArgumentList ArgumentList::expandTemplate(const string& templateArg, + const Qualified& qualifiedType, const Qualified& expandedClass) const { + ArgumentList instArgList; + BOOST_FOREACH(const Argument& arg, *this) { + Argument instArg = arg.expandTemplate(templateArg, qualifiedType, + expandedClass); + instArgList.push_back(instArg); + } + return instArgList; +} + /* ************************************************************************* */ string Argument::matlabClass(const string& delim) const { string result; BOOST_FOREACH(const string& ns, type.namespaces) result += ns + delim; - if (type.name == "string" || type.name == "unsigned char" || type.name == "char") + if (type.name == "string" || type.name == "unsigned char" + || type.name == "char") return result + "char"; if (type.name == "Vector" || type.name == "Matrix") return result + "double"; @@ -46,8 +71,9 @@ string Argument::matlabClass(const string& delim) const { /* ************************************************************************* */ bool Argument::isScalar() const { - return (type.name == "bool" || type.name == "char" || type.name == "unsigned char" - || type.name == "int" || type.name == "size_t" || type.name == "double"); + return (type.name == "bool" || type.name == "char" + || type.name == "unsigned char" || type.name == "int" + || type.name == "size_t" || type.name == "double"); } /* ************************************************************************* */ @@ -128,7 +154,8 @@ string ArgumentList::names() const { /* ************************************************************************* */ bool ArgumentList::allScalar() const { BOOST_FOREACH(Argument arg, *this) - if (!arg.isScalar()) return false; + if (!arg.isScalar()) + return false; return true; } diff --git a/wrap/Argument.h b/wrap/Argument.h index 5a14d1295..5fba1daef 100644 --- a/wrap/Argument.h +++ b/wrap/Argument.h @@ -35,6 +35,9 @@ struct Argument { is_const(false), is_ref(false), is_ptr(false) { } + Argument expandTemplate(const std::string& templateArg, + const Qualified& qualifiedType, const Qualified& expandedClass) const; + /// return MATLAB class for use in isa(x,class) std::string matlabClass(const std::string& delim = "") const; @@ -60,6 +63,9 @@ struct ArgumentList: public std::vector { /// Check if all arguments scalar bool allScalar() const; + ArgumentList expandTemplate(const std::string& templateArg, + const Qualified& qualifiedType, const Qualified& expandedClass) const; + // MATLAB code generation: /** @@ -93,8 +99,9 @@ struct ArgumentList: public std::vector { * @param wrapperName of method or function * @param staticMethod flag to emit "this" in call */ - void emit_conditional_call(FileWriter& proxyFile, const ReturnValue& returnVal, - const std::string& wrapperName, int id, bool staticMethod = false) const; + void emit_conditional_call(FileWriter& proxyFile, + const ReturnValue& returnVal, const std::string& wrapperName, int id, + bool staticMethod = false) const; }; template @@ -108,7 +115,7 @@ inline void verifyArguments(const std::vector& validArgs, std::string fullType = arg.type.qualifiedName("::"); if (find(validArgs.begin(), validArgs.end(), fullType) == validArgs.end()) - throw DependencyMissing(fullType, t.name); + throw DependencyMissing(fullType, t.name_); } } } diff --git a/wrap/Class.cpp b/wrap/Class.cpp index 8533fe6f7..e7dca4ace 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -239,63 +239,6 @@ void Class::pointer_constructor_fragments(FileWriter& proxyFile, "}\n"; } -/* ************************************************************************* */ -static vector expandArgumentListsTemplate( - const vector& argLists, const string& templateArg, - const Qualified& qualifiedType, const Qualified& expandedClass) { - vector result; - BOOST_FOREACH(const ArgumentList& argList, argLists) { - ArgumentList instArgList; - BOOST_FOREACH(const Argument& arg, argList) { - Argument instArg = arg; - if (arg.type.name == templateArg) { - instArg.type = qualifiedType; - } else if (arg.type.name == "This") { - instArg.type = expandedClass; - } - instArgList.push_back(instArg); - } - result.push_back(instArgList); - } - return result; -} - -/* ************************************************************************* */ -// TODO, Method, StaticMethod, and GlobalFunction should have common base ? -template -METHOD expandMethodTemplate(const METHOD& method, const string& templateArg, - const Qualified& qualifiedType, const Qualified& expandedClass) { - // Create new instance - METHOD instMethod = method; - // substitute template in arguments - instMethod.argLists = expandArgumentListsTemplate(method.argLists, - templateArg, qualifiedType, expandedClass); - // do the same for return types - instMethod.returnVals.clear(); - BOOST_FOREACH(const ReturnValue& retVal, method.returnVals) { - ReturnValue instRetVal = retVal.substituteTemplate(templateArg, - qualifiedType, expandedClass); - instMethod.returnVals.push_back(instRetVal); - } - // return new method - return instMethod; -} - -/* ************************************************************************* */ -template -static map expandMethodTemplate( - const map& methods, const string& templateArg, - const Qualified& qualifiedType, const Qualified& expandedClass) { - map result; - typedef pair NamedMethod; - BOOST_FOREACH(NamedMethod namedMethod, methods) { - namedMethod.second = expandMethodTemplate(namedMethod.second, templateArg, - qualifiedType, expandedClass); - result.insert(namedMethod); - } - return result; -} - /* ************************************************************************* */ Class Class::expandTemplate(const string& templateArg, const Qualified& instName, const Qualified& expandedClass) const { @@ -304,8 +247,8 @@ Class Class::expandTemplate(const string& templateArg, expandedClass); inst.static_methods = expandMethodTemplate(static_methods, templateArg, instName, expandedClass); - inst.constructor.args_list = expandArgumentListsTemplate( - constructor.args_list, templateArg, instName, expandedClass); + inst.constructor.args_list = inst.constructor.expandArgumentListsTemplate( + templateArg, instName, expandedClass); inst.constructor.name = inst.name; inst.deconstructor.name = inst.name; return inst; @@ -335,14 +278,17 @@ void Class::addMethod(bool verbose, bool is_const, const string& name, // Check if templated if (!templateArgName.empty() && templateArgValues.size() > 0) { // Create method to expand - Method method; - method.addOverload(verbose, is_const, name, args, retVal); // For all values of the template argument, create a new method BOOST_FOREACH(const Qualified& instName, templateArgValues) { - Method expanded = // - expandMethodTemplate(method, templateArgName, instName, *this); - methods[name].addOverload(verbose, is_const, name, expanded.argLists[0], - expanded.returnVals[0], instName); + string expandedName = name + instName.name; + // substitute template in arguments + ArgumentList expandedArgs = args.expandTemplate(templateArgName, instName, + name); + // do the same for return types + ReturnValue expandedRetVal = retVal.expandTemplate(templateArgName, + instName, name); + methods[expandedName].addOverload(verbose, is_const, expandedName, + expandedArgs, expandedRetVal, instName); } } else // just add overload @@ -446,7 +392,7 @@ void Class::comment_fragment(FileWriter& proxyFile) const { const Method& m = name_m.second; BOOST_FOREACH(ArgumentList argList, m.argLists) { proxyFile.oss << "%"; - argList.emit_prototype(proxyFile, m.name); + argList.emit_prototype(proxyFile, m.name_); proxyFile.oss << " : returns " << m.returnVals[0].return_type(false) << endl; } @@ -458,7 +404,7 @@ void Class::comment_fragment(FileWriter& proxyFile) const { const StaticMethod& m = name_m.second; BOOST_FOREACH(ArgumentList argList, m.argLists) { proxyFile.oss << "%"; - argList.emit_prototype(proxyFile, m.name); + argList.emit_prototype(proxyFile, m.name_); proxyFile.oss << " : returns " << m.returnVals[0].return_type(false) << endl; } diff --git a/wrap/Constructor.cpp b/wrap/Constructor.cpp index fdbbf0e42..a44f0893d 100644 --- a/wrap/Constructor.cpp +++ b/wrap/Constructor.cpp @@ -36,6 +36,19 @@ string Constructor::matlab_wrapper_name(const string& className) const { return str; } +/* ************************************************************************* */ +vector Constructor::expandArgumentListsTemplate( + const string& templateArg, const Qualified& qualifiedType, + const Qualified& expandedClass) const { + vector result; + BOOST_FOREACH(const ArgumentList& argList, args_list) { + ArgumentList instArgList = argList.expandTemplate(templateArg, + qualifiedType, expandedClass); + result.push_back(instArgList); + } + return result; +} + /* ************************************************************************* */ void Constructor::proxy_fragment(FileWriter& file, const std::string& wrapperName, bool hasParent, const int id, const ArgumentList args) const { diff --git a/wrap/Constructor.h b/wrap/Constructor.h index 5438c515c..49a731a7d 100644 --- a/wrap/Constructor.h +++ b/wrap/Constructor.h @@ -38,6 +38,11 @@ struct Constructor { std::string name; bool verbose_; + // TODO eliminate copy/paste with function + std::vector expandArgumentListsTemplate( + const std::string& templateArg, const Qualified& qualifiedType, + const Qualified& expandedClass) const; + // MATLAB code generation // toolboxPath is main toolbox directory, e.g., ../matlab // classFile is class proxy file, e.g., ../matlab/@Point2/Point2.m diff --git a/wrap/GlobalFunction.cpp b/wrap/GlobalFunction.cpp index afc099070..05b954652 100644 --- a/wrap/GlobalFunction.cpp +++ b/wrap/GlobalFunction.cpp @@ -17,16 +17,9 @@ using namespace std; /* ************************************************************************* */ void GlobalFunction::addOverload(bool verbose, const Qualified& overload, - const ArgumentList& args, const ReturnValue& retVal) { - if (name.empty()) - name = overload.name; - else if (overload.name != name) - throw std::runtime_error( - "GlobalFunction::addOverload: tried to add overload with name " - + overload.name + " instead of expected " + name); - verbose_ = verbose; - argLists.push_back(args); - returnVals.push_back(retVal); + const ArgumentList& args, const ReturnValue& retVal, + const Qualified& instName) { + Function::addOverload(verbose, overload.name, args, retVal, instName); overloads.push_back(overload); } @@ -48,7 +41,7 @@ void GlobalFunction::matlab_proxy(const std::string& toolboxPath, ArgumentList args = argLists.at(i); if (!grouped_functions.count(str_ns)) - grouped_functions[str_ns] = GlobalFunction(name, verbose_); + grouped_functions[str_ns] = GlobalFunction(name_, verbose_); grouped_functions[str_ns].argLists.push_back(args); grouped_functions[str_ns].returnVals.push_back(ret); @@ -82,7 +75,7 @@ void GlobalFunction::generateSingleFunction(const std::string& toolboxPath, const string matlabUniqueName = overload1.qualifiedName(""); const string cppName = overload1.qualifiedName("::"); - mfunctionFile.oss << "function varargout = " << name << "(varargin)\n"; + mfunctionFile.oss << "function varargout = " << name_ << "(varargin)\n"; for (size_t overload = 0; overload < argLists.size(); ++overload) { const ArgumentList& args = argLists[overload]; diff --git a/wrap/GlobalFunction.h b/wrap/GlobalFunction.h index b31bd313d..17d89d6f5 100644 --- a/wrap/GlobalFunction.h +++ b/wrap/GlobalFunction.h @@ -9,34 +9,28 @@ #pragma once -#include "Argument.h" -#include "ReturnValue.h" +#include "Function.h" namespace wrap { -struct GlobalFunction { +struct GlobalFunction: public Function { - bool verbose_; - std::string name; - - // each overload, regardless of namespace - std::vector argLists; ///< arugments for each overload - std::vector returnVals; ///< returnVals for each overload - std::vector overloads; ///< Stack of qualified names + std::vector overloads; ///< Stack of qualified names // Constructor only used in Module GlobalFunction(bool verbose = true) : - verbose_(verbose) { + Function(verbose) { } // Used to reconstruct - GlobalFunction(const std::string& name_, bool verbose = true) : - verbose_(verbose), name(name_) { + GlobalFunction(const std::string& name, bool verbose = true) : + Function(name,verbose) { } - // adds an overloaded version of this function + // adds an overloaded version of this function, void addOverload(bool verbose, const Qualified& overload, - const ArgumentList& args, const ReturnValue& retVal); + const ArgumentList& args, const ReturnValue& retVal, + const Qualified& instName = Qualified()); // codegen function called from Module to build the cpp and matlab versions of the function void matlab_proxy(const std::string& toolboxPath, diff --git a/wrap/Method.cpp b/wrap/Method.cpp index c003b5885..e218b45ec 100644 --- a/wrap/Method.cpp +++ b/wrap/Method.cpp @@ -29,20 +29,12 @@ using namespace std; using namespace wrap; /* ************************************************************************* */ -void Method::addOverload(bool verbose, bool is_const, const std::string& name, +void Method::addOverload(bool verbose, bool is_const, const std::string& name_, const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName) { - if (!this->name.empty() && this->name != name) - throw std::runtime_error( - "Method::addOverload: tried to add overload with name " + name - + " instead of expected " + this->name); - else - this->name = name; - verbose_ = verbose; + + Function::addOverload(verbose, name_, args, retVal); is_const_ = is_const; - argLists.push_back(args); - returnVals.push_back(retVal); - templateArgValues.push_back(instName); } /* ************************************************************************* */ @@ -53,14 +45,14 @@ void Method::proxy_wrapper_fragments(FileWriter& proxyFile, vector& functionNames) const { // Create function header - proxyFile.oss << " function varargout = " << name << "(this, varargin)\n"; + proxyFile.oss << " function varargout = " << name_ << "(this, varargin)\n"; // Emit comments for documentation - string up_name = boost::to_upper_copy(name); + string up_name = boost::to_upper_copy(name_); proxyFile.oss << " % " << up_name << " usage: "; unsigned int argLCount = 0; BOOST_FOREACH(ArgumentList argList, argLists) { - argList.emit_prototype(proxyFile, name); + argList.emit_prototype(proxyFile, name_); if (argLCount != argLists.size() - 1) proxyFile.oss << ", "; else @@ -80,7 +72,7 @@ void Method::proxy_wrapper_fragments(FileWriter& proxyFile, proxyFile.oss << " % " << "Method Overloads" << endl; BOOST_FOREACH(ArgumentList argList, argLists) { proxyFile.oss << " % "; - argList.emit_prototype(proxyFile, name); + argList.emit_prototype(proxyFile, name_); proxyFile.oss << endl; } } @@ -94,7 +86,7 @@ void Method::proxy_wrapper_fragments(FileWriter& proxyFile, // Output C++ wrapper code const string wrapFunctionName = wrapper_fragment(wrapperFile, cppClassName, - matlabUniqueName, 0, id, typeAttributes, templateArgValues[0]); + matlabUniqueName, 0, id, typeAttributes, templateArgValue_); // Add to function list functionNames.push_back(wrapFunctionName); @@ -105,13 +97,16 @@ void Method::proxy_wrapper_fragments(FileWriter& proxyFile, // Output proxy matlab code proxyFile.oss << " " << (overload == 0 ? "" : "else"); const int id = (int) functionNames.size(); + string expanded = wrapperName; + if (!templateArgValue_.empty()) + expanded += templateArgValue_.name; argLists[overload].emit_conditional_call(proxyFile, returnVals[overload], - wrapperName, id); + expanded, id); // Output C++ wrapper code const string wrapFunctionName = wrapper_fragment(wrapperFile, cppClassName, matlabUniqueName, overload, id, typeAttributes, - templateArgValues[overload]); + templateArgValue_); // Add to function list functionNames.push_back(wrapFunctionName); @@ -119,7 +114,7 @@ void Method::proxy_wrapper_fragments(FileWriter& proxyFile, proxyFile.oss << " else\n"; proxyFile.oss << " error('Arguments do not match any overload of function " - << matlabQualName << "." << name << "');" << endl; + << matlabQualName << "." << name_ << "');" << endl; proxyFile.oss << " end\n"; } @@ -134,7 +129,7 @@ string Method::wrapper_fragment(FileWriter& wrapperFile, // generate code - const string wrapFunctionName = matlabUniqueName + "_" + name + "_" + const string wrapFunctionName = matlabUniqueName + "_" + name_ + "_" + boost::lexical_cast(id); const ArgumentList& args = argLists[overload]; @@ -154,7 +149,7 @@ string Method::wrapper_fragment(FileWriter& wrapperFile, // check arguments // extra argument obj -> nargin-1 is passed ! // example: checkArguments("equals",nargout,nargin-1,2); - wrapperFile.oss << " checkArguments(\"" << name << "\",nargout,nargin-1," + wrapperFile.oss << " checkArguments(\"" << name_ << "\",nargout,nargin-1," << args.size() << ");\n"; // get class pointer @@ -166,7 +161,7 @@ string Method::wrapper_fragment(FileWriter& wrapperFile, // call method and wrap result // example: out[0]=wrap(self->return_field(t)); - string expanded = "obj->" + name; + string expanded = "obj->" + name_; if (!instName.empty()) expanded += ("<" + instName.qualifiedName("::") + ">"); expanded += ("(" + args.names() + ")"); diff --git a/wrap/Method.h b/wrap/Method.h index 3f7973db6..36a53b3d7 100644 --- a/wrap/Method.h +++ b/wrap/Method.h @@ -18,30 +18,19 @@ #pragma once -#include "Argument.h" -#include "ReturnValue.h" -#include "TypeAttributesTable.h" - -#include -#include +#include "Function.h" namespace wrap { /// Method class -struct Method { +struct Method : public Function { /// Constructor creates empty object Method(bool verbose = true) : - verbose_(verbose), is_const_(false) { + Function(verbose), is_const_(false) { } - // Then the instance variables are set directly by the Module constructor - bool verbose_; bool is_const_; - std::string name; - std::vector argLists; - std::vector returnVals; - std::vector templateArgValues; ///< value of template argument if applicable // The first time this function is called, it initializes the class members // with those in rhs, but in subsequent calls it adds additional argument diff --git a/wrap/Module.cpp b/wrap/Module.cpp index 498048ee7..f75e1d683 100644 --- a/wrap/Module.cpp +++ b/wrap/Module.cpp @@ -274,7 +274,7 @@ void Module::parseMarkup(const std::string& data) { '(' >> argumentList_p >> ')' >> ';' >> *comments_p) [bl::bind(&StaticMethod::addOverload, bl::var(cls.static_methods)[bl::var(methodName)], - verbose, bl::var(methodName), bl::var(args), bl::var(retVal))] + verbose, bl::var(methodName), bl::var(args), bl::var(retVal), Qualified())] [assign_a(retVal,retVal0)] [clear_a(args)]; @@ -313,7 +313,7 @@ void Module::parseMarkup(const std::string& data) { [assign_a(globalFunction.namespaces,namespaces)] [bl::bind(&GlobalFunction::addOverload, bl::var(global_functions)[bl::var(globalFunction.name)], - verbose, bl::var(globalFunction), bl::var(args), bl::var(retVal))] + verbose, bl::var(globalFunction), bl::var(args), bl::var(retVal), Qualified())] [assign_a(retVal,retVal0)] [clear_a(globalFunction)] [clear_a(args)]; diff --git a/wrap/Qualified.h b/wrap/Qualified.h index f38587fbb..def2343cd 100644 --- a/wrap/Qualified.h +++ b/wrap/Qualified.h @@ -44,6 +44,10 @@ struct Qualified { name.clear(); } + bool operator!=(const Qualified& other) const { + return other.name!=name || other.namespaces != namespaces; + } + /// Return a qualified string using given delimiter std::string qualifiedName(const std::string& delimiter = "") const { std::string result; diff --git a/wrap/ReturnValue.cpp b/wrap/ReturnValue.cpp index ea2cb1489..84d662e81 100644 --- a/wrap/ReturnValue.cpp +++ b/wrap/ReturnValue.cpp @@ -59,7 +59,7 @@ void ReturnType::wrapTypeUnwrap(FileWriter& wrapperFile) const { } /* ************************************************************************* */ -ReturnValue ReturnValue::substituteTemplate(const string& templateArg, +ReturnValue ReturnValue::expandTemplate(const string& templateArg, const Qualified& qualifiedType, const Qualified& expandedClass) const { ReturnValue instRetVal = *this; if (type1.name == templateArg) { diff --git a/wrap/ReturnValue.h b/wrap/ReturnValue.h index 6e6e149de..1caaeae22 100644 --- a/wrap/ReturnValue.h +++ b/wrap/ReturnValue.h @@ -86,9 +86,22 @@ struct ReturnValue { } /// Substitute template argument - ReturnValue substituteTemplate(const std::string& templateArg, + ReturnValue expandTemplate(const std::string& templateArg, const Qualified& qualifiedType, const Qualified& expandedClass) const; + // TODO use transform ? + static std::vector ExpandTemplate( + std::vector returnVals, const std::string& templateArg, + const Qualified& qualifiedType, const Qualified& expandedClass) { + std::vector result; + BOOST_FOREACH(const ReturnValue& retVal, returnVals) { + ReturnValue instRetVal = retVal.expandTemplate(templateArg, + qualifiedType, expandedClass); + result.push_back(instRetVal); + } + return result; + } + std::string return_type(bool add_ptr) const; std::string matlab_returnType() const; @@ -102,18 +115,4 @@ struct ReturnValue { }; -template -inline void verifyReturnTypes(const std::vector& validtypes, - const std::map& vt) { - typedef typename std::map::value_type NamedMethod; - BOOST_FOREACH(const NamedMethod& namedMethod, vt) { - const T& t = namedMethod.second; - BOOST_FOREACH(const ReturnValue& retval, t.returnVals) { - retval.type1.verify(validtypes, t.name); - if (retval.isPair) - retval.type2.verify(validtypes, t.name); - } - } -} - } // \namespace wrap diff --git a/wrap/StaticMethod.cpp b/wrap/StaticMethod.cpp index 870773973..f8eba744f 100644 --- a/wrap/StaticMethod.cpp +++ b/wrap/StaticMethod.cpp @@ -29,15 +29,6 @@ using namespace std; using namespace wrap; -/* ************************************************************************* */ -void StaticMethod::addOverload(bool verbose, const std::string& name, - const ArgumentList& args, const ReturnValue& retVal) { - this->verbose = verbose; - this->name = name; - this->argLists.push_back(args); - this->returnVals.push_back(retVal); -} - /* ************************************************************************* */ void StaticMethod::proxy_wrapper_fragments(FileWriter& file, FileWriter& wrapperFile, const string& cppClassName, @@ -45,16 +36,16 @@ void StaticMethod::proxy_wrapper_fragments(FileWriter& file, const string& wrapperName, const TypeAttributesTable& typeAttributes, vector& functionNames) const { - string upperName = name; + string upperName = name_; upperName[0] = std::toupper(upperName[0], std::locale()); file.oss << " function varargout = " << upperName << "(varargin)\n"; //Comments for documentation - string up_name = boost::to_upper_copy(name); + string up_name = boost::to_upper_copy(name_); file.oss << " % " << up_name << " usage: "; unsigned int argLCount = 0; BOOST_FOREACH(ArgumentList argList, argLists) { - argList.emit_prototype(file, name); + argList.emit_prototype(file, name_); if (argLCount != argLists.size() - 1) file.oss << ", "; else @@ -105,7 +96,7 @@ string StaticMethod::wrapper_fragment(FileWriter& file, // generate code - const string wrapFunctionName = matlabUniqueName + "_" + name + "_" + const string wrapFunctionName = matlabUniqueName + "_" + name_ + "_" + boost::lexical_cast(id); const ArgumentList& args = argLists[overload]; @@ -124,7 +115,7 @@ string StaticMethod::wrapper_fragment(FileWriter& file, // check arguments // NOTE: for static functions, there is no object passed - file.oss << " checkArguments(\"" << matlabUniqueName << "." << name + file.oss << " checkArguments(\"" << matlabUniqueName << "." << name_ << "\",nargout,nargin," << args.size() << ");\n"; // unwrap arguments, see Argument.cpp @@ -132,10 +123,10 @@ string StaticMethod::wrapper_fragment(FileWriter& file, // call method with default type and wrap result if (returnVal.type1.name != "void") - returnVal.wrap_result(cppClassName + "::" + name + "(" + args.names() + ")", + returnVal.wrap_result(cppClassName + "::" + name_ + "(" + args.names() + ")", file, typeAttributes); else - file.oss << cppClassName + "::" + name + "(" + args.names() + ");\n"; + file.oss << cppClassName + "::" + name_ + "(" + args.names() + ");\n"; // finish file.oss << "}\n"; diff --git a/wrap/StaticMethod.h b/wrap/StaticMethod.h index e1855f4c2..14162b3c8 100644 --- a/wrap/StaticMethod.h +++ b/wrap/StaticMethod.h @@ -19,32 +19,18 @@ #pragma once -#include "Argument.h" -#include "ReturnValue.h" -#include "TypeAttributesTable.h" +#include "Function.h" namespace wrap { /// StaticMethod class -struct StaticMethod { +struct StaticMethod: public Function { /// Constructor creates empty object StaticMethod(bool verbosity = true) : - verbose(verbosity) { + Function(verbosity) { } - // Then the instance variables are set directly by the Module constructor - bool verbose; - std::string name; - std::vector argLists; - std::vector returnVals; - - // The first time this function is called, it initializes the class members - // with those in rhs, but in subsequent calls it adds additional argument - // lists as function overloads. - void addOverload(bool verbose, const std::string& name, - const ArgumentList& args, const ReturnValue& retVal); - // MATLAB code generation // classPath is class directory, e.g., ../matlab/@Point2 void proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, diff --git a/wrap/tests/testWrap.cpp b/wrap/tests/testWrap.cpp index 4365b085a..743370c6d 100644 --- a/wrap/tests/testWrap.cpp +++ b/wrap/tests/testWrap.cpp @@ -97,7 +97,7 @@ TEST( wrap, Small ) { // Method 1 Method m1 = cls.method("x"); - EXPECT(assert_equal("x", m1.name)); + EXPECT(assert_equal("x", m1.name_)); EXPECT(m1.is_const_); LONGS_EQUAL(1, m1.argLists.size()); LONGS_EQUAL(1, m1.returnVals.size()); @@ -110,7 +110,7 @@ TEST( wrap, Small ) { // Method 2 Method m2 = cls.method("returnMatrix"); - EXPECT(assert_equal("returnMatrix", m2.name)); + EXPECT(assert_equal("returnMatrix", m2.name_)); EXPECT(m2.is_const_); LONGS_EQUAL(1, m2.argLists.size()); LONGS_EQUAL(1, m2.returnVals.size()); @@ -123,7 +123,7 @@ TEST( wrap, Small ) { // Method 3 Method m3 = cls.method("returnPoint2"); - EXPECT(assert_equal("returnPoint2", m3.name)); + EXPECT(assert_equal("returnPoint2", m3.name_)); EXPECT(m3.is_const_); LONGS_EQUAL(1, m3.argLists.size()); LONGS_EQUAL(1, m3.returnVals.size()); @@ -137,7 +137,7 @@ TEST( wrap, Small ) { // Static Method 1 // static Vector returnVector(); StaticMethod sm1 = cls.static_methods.at("returnVector"); - EXPECT(assert_equal("returnVector", sm1.name)); + EXPECT(assert_equal("returnVector", sm1.name_)); LONGS_EQUAL(1, sm1.argLists.size()); LONGS_EQUAL(1, sm1.returnVals.size()); @@ -199,7 +199,7 @@ TEST( wrap, Geometry ) { EXPECT(assert_equal("char", m1.returnVals.front().type1.name)); EXPECT_LONGS_EQUAL(ReturnType::BASIS, m1.returnVals.front().type1.category); EXPECT(!m1.returnVals.front().isPair); - EXPECT(assert_equal("returnChar", m1.name)); + EXPECT(assert_equal("returnChar", m1.name_)); LONGS_EQUAL(1, m1.argLists.size()); EXPECT_LONGS_EQUAL(0, m1.argLists.front().size()); EXPECT(m1.is_const_); @@ -213,7 +213,7 @@ TEST( wrap, Geometry ) { EXPECT(assert_equal("VectorNotEigen", m1.returnVals.front().type1.name)); EXPECT_LONGS_EQUAL(ReturnType::CLASS, m1.returnVals.front().type1.category); EXPECT(!m1.returnVals.front().isPair); - EXPECT(assert_equal("vectorConfusion", m1.name)); + EXPECT(assert_equal("vectorConfusion", m1.name_)); LONGS_EQUAL(1, m1.argLists.size()); EXPECT_LONGS_EQUAL(0, m1.argLists.front().size()); EXPECT(!m1.is_const_); @@ -255,7 +255,7 @@ TEST( wrap, Geometry ) { LONGS_EQUAL(1, m1.returnVals.size()); EXPECT(assert_equal("double", m1.returnVals.front().type1.name)); EXPECT_LONGS_EQUAL(ReturnType::BASIS, m1.returnVals.front().type1.category); - EXPECT(assert_equal("norm", m1.name)); + EXPECT(assert_equal("norm", m1.name_)); LONGS_EQUAL(1, m1.argLists.size()); EXPECT_LONGS_EQUAL(0, m1.argLists.front().size()); EXPECT(m1.is_const_); @@ -316,7 +316,7 @@ TEST( wrap, Geometry ) { CHECK(module.global_functions.find("aGlobalFunction") != module.global_functions.end()); { GlobalFunction gfunc = module.global_functions.at("aGlobalFunction"); - EXPECT(assert_equal("aGlobalFunction", gfunc.name)); + EXPECT(assert_equal("aGlobalFunction", gfunc.name_)); LONGS_EQUAL(1, gfunc.returnVals.size()); EXPECT(assert_equal("Vector", gfunc.returnVals.front().type1.name)); EXPECT_LONGS_EQUAL(1, gfunc.argLists.size()); @@ -390,7 +390,7 @@ TEST( wrap, parse_namespaces ) { CHECK(module.global_functions.find("aGlobalFunction") != module.global_functions.end()); { GlobalFunction gfunc = module.global_functions.at("aGlobalFunction"); - EXPECT(assert_equal("aGlobalFunction", gfunc.name)); + EXPECT(assert_equal("aGlobalFunction", gfunc.name_)); LONGS_EQUAL(2, gfunc.returnVals.size()); EXPECT(assert_equal("Vector", gfunc.returnVals.front().type1.name)); EXPECT_LONGS_EQUAL(2, gfunc.argLists.size()); From b451e97f6f4481e72a3f4bab97797fe6b4d3d3cc Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 17:28:05 +0100 Subject: [PATCH 03/12] New TemplateSubstitution object simplifies a lot --- wrap/Argument.cpp | 15 +- wrap/Argument.h | 17 +- wrap/Class.cpp | 40 ++--- wrap/Class.h | 3 +- wrap/Constructor.cpp | 6 +- wrap/Constructor.h | 3 +- wrap/Function.cpp | 13 +- wrap/Function.h | 171 +++++++++++++++---- wrap/GlobalFunction.cpp | 27 ++- wrap/GlobalFunction.h | 2 +- wrap/Method.cpp | 126 ++------------ wrap/Method.h | 25 ++- wrap/ReturnValue.cpp | 15 +- wrap/ReturnValue.h | 18 +- wrap/StaticMethod.cpp | 158 ++++++++++------- wrap/StaticMethod.h | 22 ++- wrap/TemplateInstantiationTypedef.cpp | 6 +- wrap/TemplateSubstitution.h | 39 +++++ wrap/tests/expected2/+gtsam/Point2.m | 90 ++++++++++ wrap/tests/expected2/+gtsam/Point3.m | 75 ++++++++ wrap/tests/expected_namespaces/+ns2/ClassA.m | 9 +- wrap/tests/testWrap.cpp | 81 +++++---- 22 files changed, 570 insertions(+), 391 deletions(-) create mode 100644 wrap/TemplateSubstitution.h create mode 100644 wrap/tests/expected2/+gtsam/Point2.m create mode 100644 wrap/tests/expected2/+gtsam/Point3.m diff --git a/wrap/Argument.cpp b/wrap/Argument.cpp index dbf1e93f9..19e46fd85 100644 --- a/wrap/Argument.cpp +++ b/wrap/Argument.cpp @@ -29,24 +29,21 @@ using namespace std; using namespace wrap; /* ************************************************************************* */ -Argument Argument::expandTemplate(const string& templateArg, - const Qualified& qualifiedType, const Qualified& expandedClass) const { +Argument Argument::expandTemplate(const TemplateSubstitution& ts) const { Argument instArg = *this; - if (type.name == templateArg) { - instArg.type = qualifiedType; + if (type.name == ts.templateArg) { + instArg.type = ts.qualifiedType; } else if (type.name == "This") { - instArg.type = expandedClass; + instArg.type = ts.expandedClass; } return instArg; } /* ************************************************************************* */ -ArgumentList ArgumentList::expandTemplate(const string& templateArg, - const Qualified& qualifiedType, const Qualified& expandedClass) const { +ArgumentList ArgumentList::expandTemplate(const TemplateSubstitution& ts) const { ArgumentList instArgList; BOOST_FOREACH(const Argument& arg, *this) { - Argument instArg = arg.expandTemplate(templateArg, qualifiedType, - expandedClass); + Argument instArg = arg.expandTemplate(ts); instArgList.push_back(instArg); } return instArgList; diff --git a/wrap/Argument.h b/wrap/Argument.h index 5fba1daef..5a4f08a25 100644 --- a/wrap/Argument.h +++ b/wrap/Argument.h @@ -19,7 +19,7 @@ #pragma once -#include "Qualified.h" +#include "TemplateSubstitution.h" #include "FileWriter.h" #include "ReturnValue.h" @@ -35,8 +35,7 @@ struct Argument { is_const(false), is_ref(false), is_ptr(false) { } - Argument expandTemplate(const std::string& templateArg, - const Qualified& qualifiedType, const Qualified& expandedClass) const; + Argument expandTemplate(const TemplateSubstitution& ts) const; /// return MATLAB class for use in isa(x,class) std::string matlabClass(const std::string& delim = "") const; @@ -63,8 +62,7 @@ struct ArgumentList: public std::vector { /// Check if all arguments scalar bool allScalar() const; - ArgumentList expandTemplate(const std::string& templateArg, - const Qualified& qualifiedType, const Qualified& expandedClass) const; + ArgumentList expandTemplate(const TemplateSubstitution& ts) const; // MATLAB code generation: @@ -110,14 +108,7 @@ inline void verifyArguments(const std::vector& validArgs, typedef typename std::map::value_type NamedMethod; BOOST_FOREACH(const NamedMethod& namedMethod, vt) { const T& t = namedMethod.second; - BOOST_FOREACH(const ArgumentList& argList, t.argLists) { - BOOST_FOREACH(Argument arg, argList) { - std::string fullType = arg.type.qualifiedName("::"); - if (find(validArgs.begin(), validArgs.end(), fullType) - == validArgs.end()) - throw DependencyMissing(fullType, t.name_); - } - } + t.verifyArguments(validArgs,t.name_); } } diff --git a/wrap/Class.cpp b/wrap/Class.cpp index e7dca4ace..d219452a3 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -240,15 +240,11 @@ void Class::pointer_constructor_fragments(FileWriter& proxyFile, } /* ************************************************************************* */ -Class Class::expandTemplate(const string& templateArg, - const Qualified& instName, const Qualified& expandedClass) const { +Class Class::expandTemplate(const TemplateSubstitution& ts) const { Class inst = *this; - inst.methods = expandMethodTemplate(methods, templateArg, instName, - expandedClass); - inst.static_methods = expandMethodTemplate(static_methods, templateArg, - instName, expandedClass); - inst.constructor.args_list = inst.constructor.expandArgumentListsTemplate( - templateArg, instName, expandedClass); + inst.methods = expandMethodTemplate(methods, ts); + inst.static_methods = expandMethodTemplate(static_methods, ts); + inst.constructor.args_list = inst.constructor.expandArgumentListsTemplate(ts); inst.constructor.name = inst.name; inst.deconstructor.name = inst.name; return inst; @@ -261,7 +257,8 @@ vector Class::expandTemplate(const string& templateArg, BOOST_FOREACH(const Qualified& instName, instantiations) { Qualified expandedClass = (Qualified) (*this); expandedClass.name += instName.name; - Class inst = expandTemplate(templateArg, instName, expandedClass); + const TemplateSubstitution ts(templateArg, instName, expandedClass); + Class inst = expandTemplate(ts); inst.name = expandedClass.name; inst.templateArgs.clear(); inst.typedefName = qualifiedName("::") + "<" + instName.qualifiedName("::") @@ -282,13 +279,12 @@ void Class::addMethod(bool verbose, bool is_const, const string& name, BOOST_FOREACH(const Qualified& instName, templateArgValues) { string expandedName = name + instName.name; // substitute template in arguments - ArgumentList expandedArgs = args.expandTemplate(templateArgName, instName, - name); + const TemplateSubstitution ts(templateArgName, instName, name); + ArgumentList expandedArgs = args.expandTemplate(ts); // do the same for return types - ReturnValue expandedRetVal = retVal.expandTemplate(templateArgName, - instName, name); - methods[expandedName].addOverload(verbose, is_const, expandedName, - expandedArgs, expandedRetVal, instName); + ReturnValue expandedRetVal = retVal.expandTemplate(ts); + methods[expandedName].addOverload(verbose, is_const, name, expandedArgs, + expandedRetVal, instName); } } else // just add overload @@ -390,24 +386,14 @@ void Class::comment_fragment(FileWriter& proxyFile) const { proxyFile.oss << "%\n%-------Methods-------\n"; BOOST_FOREACH(const Methods::value_type& name_m, methods) { const Method& m = name_m.second; - BOOST_FOREACH(ArgumentList argList, m.argLists) { - proxyFile.oss << "%"; - argList.emit_prototype(proxyFile, m.name_); - proxyFile.oss << " : returns " << m.returnVals[0].return_type(false) - << endl; - } + m.comment_fragment(proxyFile, m.name_); } if (!static_methods.empty()) proxyFile.oss << "%\n%-------Static Methods-------\n"; BOOST_FOREACH(const StaticMethods::value_type& name_m, static_methods) { const StaticMethod& m = name_m.second; - BOOST_FOREACH(ArgumentList argList, m.argLists) { - proxyFile.oss << "%"; - argList.emit_prototype(proxyFile, m.name_); - proxyFile.oss << " : returns " << m.returnVals[0].return_type(false) - << endl; - } + m.comment_fragment(proxyFile, m.name_); } if (hasSerialization) { diff --git a/wrap/Class.h b/wrap/Class.h index 9422482b4..610c9b7b4 100644 --- a/wrap/Class.h +++ b/wrap/Class.h @@ -67,8 +67,7 @@ public: const std::string& wrapperName, const TypeAttributesTable& typeAttributes, FileWriter& wrapperFile, std::vector& functionNames) const; ///< emit proxy class - Class expandTemplate(const std::string& templateArg, - const Qualified& instantiation, const Qualified& expandedClass) const; + Class expandTemplate(const TemplateSubstitution& ts) const; std::vector expandTemplate(const std::string& templateArg, const std::vector& instantiations) const; diff --git a/wrap/Constructor.cpp b/wrap/Constructor.cpp index a44f0893d..98a689ced 100644 --- a/wrap/Constructor.cpp +++ b/wrap/Constructor.cpp @@ -38,12 +38,10 @@ string Constructor::matlab_wrapper_name(const string& className) const { /* ************************************************************************* */ vector Constructor::expandArgumentListsTemplate( - const string& templateArg, const Qualified& qualifiedType, - const Qualified& expandedClass) const { + const TemplateSubstitution& ts) const { vector result; BOOST_FOREACH(const ArgumentList& argList, args_list) { - ArgumentList instArgList = argList.expandTemplate(templateArg, - qualifiedType, expandedClass); + ArgumentList instArgList = argList.expandTemplate(ts); result.push_back(instArgList); } return result; diff --git a/wrap/Constructor.h b/wrap/Constructor.h index 49a731a7d..40bca549a 100644 --- a/wrap/Constructor.h +++ b/wrap/Constructor.h @@ -40,8 +40,7 @@ struct Constructor { // TODO eliminate copy/paste with function std::vector expandArgumentListsTemplate( - const std::string& templateArg, const Qualified& qualifiedType, - const Qualified& expandedClass) const; + const TemplateSubstitution& ts) const; // MATLAB code generation // toolboxPath is main toolbox directory, e.g., ../matlab diff --git a/wrap/Function.cpp b/wrap/Function.cpp index 8fd1d0655..ab3958c62 100644 --- a/wrap/Function.cpp +++ b/wrap/Function.cpp @@ -30,7 +30,6 @@ using namespace wrap; /* ************************************************************************* */ void Function::addOverload(bool verbose, const std::string& name, - const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName) { // Check if this overload is give to the correct method @@ -51,18 +50,14 @@ void Function::addOverload(bool verbose, const std::string& name, + templateArgValue_.qualifiedName(":")); verbose_ = verbose; - argLists.push_back(args); - returnVals.push_back(retVal); } /* ************************************************************************* */ -vector Function::expandArgumentListsTemplate( - const string& templateArg, const Qualified& qualifiedType, - const Qualified& expandedClass) const { +vector ArgumentOverloads::expandArgumentListsTemplate( + const TemplateSubstitution& ts) const { vector result; - BOOST_FOREACH(const ArgumentList& argList, argLists) { - ArgumentList instArgList = argList.expandTemplate(templateArg, - qualifiedType, expandedClass); + BOOST_FOREACH(const ArgumentList& argList, argLists_) { + ArgumentList instArgList = argList.expandTemplate(ts); result.push_back(instArgList); } return result; diff --git a/wrap/Function.h b/wrap/Function.h index 76b513907..dd6d2158c 100644 --- a/wrap/Function.h +++ b/wrap/Function.h @@ -42,66 +42,163 @@ struct Function { bool verbose_; std::string name_; ///< name of method Qualified templateArgValue_; ///< value of template argument if applicable - std::vector argLists; - std::vector returnVals; // The first time this function is called, it initializes the class members // with those in rhs, but in subsequent calls it adds additional argument // lists as function overloads. void addOverload(bool verbose, const std::string& name, - const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName = Qualified()); +}; + +/** + * ArgumentList Overloads + */ +class ArgumentOverloads { + +protected: + + std::vector argLists_; + +public: + + size_t nrOverloads() const { + return argLists_.size(); + } + + const ArgumentList& argumentList(size_t i) const { + return argLists_.at(i); + } + + void addOverload(const ArgumentList& args) { + argLists_.push_back(args); + } std::vector expandArgumentListsTemplate( - const std::string& templateArg, const Qualified& qualifiedType, - const Qualified& expandedClass) const; + const TemplateSubstitution& ts) const; + + /// Expand templates, imperative ! + virtual void ExpandTemplate(const TemplateSubstitution& ts) { + argLists_ = expandArgumentListsTemplate(ts); + } + + void verifyArguments(const std::vector& validArgs, + const std::string s) const { + BOOST_FOREACH(const ArgumentList& argList, argLists_) { + BOOST_FOREACH(Argument arg, argList) { + std::string fullType = arg.type.qualifiedName("::"); + if (find(validArgs.begin(), validArgs.end(), fullType) + == validArgs.end()) + throw DependencyMissing(fullType, s); + } + } + } + +}; + +/** + * Signature Overload (including return value) + */ +class SignatureOverloads: public ArgumentOverloads { + +protected: + + std::vector returnVals_; + +public: + + const ReturnValue& returnValue(size_t i) const { + return returnVals_.at(i); + } + + void addOverload(const ArgumentList& args, const ReturnValue& retVal) { + argLists_.push_back(args); + returnVals_.push_back(retVal); + } + + void verifyReturnTypes(const std::vector& validtypes, + const std::string& s) const { + BOOST_FOREACH(const ReturnValue& retval, returnVals_) { + retval.type1.verify(validtypes, s); + if (retval.isPair) + retval.type2.verify(validtypes, s); + } + } + + // TODO use transform ? + std::vector ExpandReturnValuesTemplate( + const TemplateSubstitution& ts) const { + std::vector result; + BOOST_FOREACH(const ReturnValue& retVal, returnVals_) { + ReturnValue instRetVal = retVal.expandTemplate(ts); + result.push_back(instRetVal); + } + return result; + } + + /// Expand templates, imperative ! + void expandTemplate(const TemplateSubstitution& ts) { + // substitute template in arguments + argLists_ = expandArgumentListsTemplate(ts); + // do the same for return types + returnVals_ = ExpandReturnValuesTemplate(ts); + } + + // emit a list of comments, one for each overload + void usage_fragment(FileWriter& proxyFile, const std::string& name) const { + unsigned int argLCount = 0; + BOOST_FOREACH(ArgumentList argList, argLists_) { + argList.emit_prototype(proxyFile, name); + if (argLCount != nrOverloads() - 1) + proxyFile.oss << ", "; + else + proxyFile.oss << " : returns " << returnValue(0).return_type(false) + << std::endl; + argLCount++; + } + } + + // emit a list of comments, one for each overload + void comment_fragment(FileWriter& proxyFile, const std::string& name) const { + size_t i = 0; + BOOST_FOREACH(ArgumentList argList, argLists_) { + proxyFile.oss << "%"; + argList.emit_prototype(proxyFile, name); + proxyFile.oss << " : returns " << returnVals_[i++].return_type(false) + << std::endl; + } + } + }; // Templated checking functions // TODO: do this via polymorphism ? -template -FUNCTION expandMethodTemplate(const FUNCTION& method, - const std::string& templateArg, const Qualified& qualifiedType, - const Qualified& expandedClass) { - // Create new instance - FUNCTION instMethod = method; - // substitute template in arguments - instMethod.argLists = method.expandArgumentListsTemplate(templateArg, - qualifiedType, expandedClass); - // do the same for return types - instMethod.returnVals = ReturnValue::ExpandTemplate(method.returnVals, - templateArg, qualifiedType, expandedClass); - // return new method +template +F expandMethodTemplate(F& method, const TemplateSubstitution& ts) { + F instMethod = method; + method.expandTemplate(ts); return instMethod; } // TODO use transform -template -static std::map expandMethodTemplate( - const std::map& methods, - const std::string& templateArg, const Qualified& qualifiedType, - const Qualified& expandedClass) { - std::map result; - typedef std::pair NamedMethod; +template +static std::map expandMethodTemplate( + const std::map& methods, const TemplateSubstitution& ts) { + std::map result; + typedef std::pair NamedMethod; BOOST_FOREACH(NamedMethod namedMethod, methods) { - namedMethod.second = expandMethodTemplate(namedMethod.second, templateArg, - qualifiedType, expandedClass); + namedMethod.second = expandMethodTemplate(namedMethod.second, ts); result.insert(namedMethod); } return result; } -template -inline void verifyReturnTypes(const std::vector& validtypes, - const std::map& vt) { - typedef typename std::map::value_type NamedMethod; +template +inline void verifyReturnTypes(const std::vector& validTypes, + const std::map& vt) { + typedef typename std::map::value_type NamedMethod; BOOST_FOREACH(const NamedMethod& namedMethod, vt) { - const T& t = namedMethod.second; - BOOST_FOREACH(const ReturnValue& retval, t.returnVals) { - retval.type1.verify(validtypes, t.name_); - if (retval.isPair) - retval.type2.verify(validtypes, t.name_); - } + const F& t = namedMethod.second; + t.verifyReturnTypes(validTypes, t.name_); } } diff --git a/wrap/GlobalFunction.cpp b/wrap/GlobalFunction.cpp index 05b954652..1f9d6518e 100644 --- a/wrap/GlobalFunction.cpp +++ b/wrap/GlobalFunction.cpp @@ -19,7 +19,8 @@ using namespace std; void GlobalFunction::addOverload(bool verbose, const Qualified& overload, const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName) { - Function::addOverload(verbose, overload.name, args, retVal, instName); + Function::addOverload(verbose, overload.name, instName); + SignatureOverloads::addOverload(args, retVal); overloads.push_back(overload); } @@ -37,15 +38,10 @@ void GlobalFunction::matlab_proxy(const std::string& toolboxPath, Qualified overload = overloads.at(i); // use concatenated namespaces as key string str_ns = qualifiedName("", overload.namespaces); - ReturnValue ret = returnVals.at(i); - ArgumentList args = argLists.at(i); - - if (!grouped_functions.count(str_ns)) - grouped_functions[str_ns] = GlobalFunction(name_, verbose_); - - grouped_functions[str_ns].argLists.push_back(args); - grouped_functions[str_ns].returnVals.push_back(ret); - grouped_functions[str_ns].overloads.push_back(overload); + const ReturnValue& ret = returnValue(i); + const ArgumentList& args = argumentList(i); + grouped_functions[str_ns].addOverload(verbose_, overload, args, ret, + templateArgValue_); } size_t lastcheck = grouped_functions.size(); @@ -77,16 +73,15 @@ void GlobalFunction::generateSingleFunction(const std::string& toolboxPath, mfunctionFile.oss << "function varargout = " << name_ << "(varargin)\n"; - for (size_t overload = 0; overload < argLists.size(); ++overload) { - const ArgumentList& args = argLists[overload]; - const ReturnValue& returnVal = returnVals[overload]; + for (size_t i = 0; i < nrOverloads(); ++i) { + const ArgumentList& args = argumentList(i); + const ReturnValue& returnVal = returnValue(i); const int id = functionNames.size(); // Output proxy matlab code - mfunctionFile.oss << " " << (overload == 0 ? "" : "else"); - argLists[overload].emit_conditional_call(mfunctionFile, - returnVals[overload], wrapperName, id, true); // true omits "this" + mfunctionFile.oss << " " << (i == 0 ? "" : "else"); + args.emit_conditional_call(mfunctionFile, returnVal, wrapperName, id, true); // true omits "this" // Output C++ wrapper code diff --git a/wrap/GlobalFunction.h b/wrap/GlobalFunction.h index 17d89d6f5..6f8686925 100644 --- a/wrap/GlobalFunction.h +++ b/wrap/GlobalFunction.h @@ -13,7 +13,7 @@ namespace wrap { -struct GlobalFunction: public Function { +struct GlobalFunction: public Function, public SignatureOverloads { std::vector overloads; ///< Stack of qualified names diff --git a/wrap/Method.cpp b/wrap/Method.cpp index e218b45ec..d342df04b 100644 --- a/wrap/Method.cpp +++ b/wrap/Method.cpp @@ -29,123 +29,24 @@ using namespace std; using namespace wrap; /* ************************************************************************* */ -void Method::addOverload(bool verbose, bool is_const, const std::string& name_, +void Method::addOverload(bool verbose, bool is_const, const std::string& name, const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName) { - Function::addOverload(verbose, name_, args, retVal); + StaticMethod::addOverload(verbose, name, args, retVal, instName); is_const_ = is_const; } /* ************************************************************************* */ -void Method::proxy_wrapper_fragments(FileWriter& proxyFile, - FileWriter& wrapperFile, const string& cppClassName, - const std::string& matlabQualName, const std::string& matlabUniqueName, - const string& wrapperName, const TypeAttributesTable& typeAttributes, - vector& functionNames) const { - - // Create function header +void Method::proxy_header(FileWriter& proxyFile) const { proxyFile.oss << " function varargout = " << name_ << "(this, varargin)\n"; - - // Emit comments for documentation - string up_name = boost::to_upper_copy(name_); - proxyFile.oss << " % " << up_name << " usage: "; - unsigned int argLCount = 0; - BOOST_FOREACH(ArgumentList argList, argLists) { - argList.emit_prototype(proxyFile, name_); - if (argLCount != argLists.size() - 1) - proxyFile.oss << ", "; - else - proxyFile.oss << " : returns " << returnVals[0].return_type(false) - << endl; - argLCount++; - } - - // Emit URL to Doxygen page - proxyFile.oss << " % " - << "Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html" - << endl; - - // Document all overloads, if any - if (argLists.size() > 1) { - proxyFile.oss << " % " << "" << endl; - proxyFile.oss << " % " << "Method Overloads" << endl; - BOOST_FOREACH(ArgumentList argList, argLists) { - proxyFile.oss << " % "; - argList.emit_prototype(proxyFile, name_); - proxyFile.oss << endl; - } - } - - // Handle special case of single overload with all numeric arguments - if (argLists.size() == 1 && argLists[0].allScalar()) { - // Output proxy matlab code - proxyFile.oss << " "; - const int id = (int) functionNames.size(); - argLists[0].emit_call(proxyFile, returnVals[0], wrapperName, id); - - // Output C++ wrapper code - const string wrapFunctionName = wrapper_fragment(wrapperFile, cppClassName, - matlabUniqueName, 0, id, typeAttributes, templateArgValue_); - - // Add to function list - functionNames.push_back(wrapFunctionName); - } else { - // Check arguments for all overloads - for (size_t overload = 0; overload < argLists.size(); ++overload) { - - // Output proxy matlab code - proxyFile.oss << " " << (overload == 0 ? "" : "else"); - const int id = (int) functionNames.size(); - string expanded = wrapperName; - if (!templateArgValue_.empty()) - expanded += templateArgValue_.name; - argLists[overload].emit_conditional_call(proxyFile, returnVals[overload], - expanded, id); - - // Output C++ wrapper code - const string wrapFunctionName = wrapper_fragment(wrapperFile, - cppClassName, matlabUniqueName, overload, id, typeAttributes, - templateArgValue_); - - // Add to function list - functionNames.push_back(wrapFunctionName); - } - proxyFile.oss << " else\n"; - proxyFile.oss - << " error('Arguments do not match any overload of function " - << matlabQualName << "." << name_ << "');" << endl; - proxyFile.oss << " end\n"; - } - - proxyFile.oss << " end\n"; } /* ************************************************************************* */ -string Method::wrapper_fragment(FileWriter& wrapperFile, - const string& cppClassName, const string& matlabUniqueName, int overload, - int id, const TypeAttributesTable& typeAttributes, +string Method::wrapper_call(FileWriter& wrapperFile, const string& cppClassName, + const string& matlabUniqueName, const ArgumentList& args, + const ReturnValue& returnVal, const TypeAttributesTable& typeAttributes, const Qualified& instName) const { - - // generate code - - const string wrapFunctionName = matlabUniqueName + "_" + name_ + "_" - + boost::lexical_cast(id); - - const ArgumentList& args = argLists[overload]; - const ReturnValue& returnVal = returnVals[overload]; - - // call - wrapperFile.oss << "void " << wrapFunctionName - << "(int nargout, mxArray *out[], int nargin, const mxArray *in[])\n"; - // start - wrapperFile.oss << "{\n"; - - returnVal.wrapTypeUnwrap(wrapperFile); - - wrapperFile.oss << " typedef boost::shared_ptr<" << cppClassName - << "> Shared;" << endl; - // check arguments // extra argument obj -> nargin-1 is passed ! // example: checkArguments("equals",nargout,nargin-1,2); @@ -156,24 +57,17 @@ string Method::wrapper_fragment(FileWriter& wrapperFile, // example: shared_ptr = unwrap_shared_ptr< Test >(in[0], "Test"); wrapperFile.oss << " Shared obj = unwrap_shared_ptr<" << cppClassName << ">(in[0], \"ptr_" << matlabUniqueName << "\");" << endl; - // unwrap arguments, see Argument.cpp + + // unwrap arguments, see Argument.cpp, we start at 1 as first is obj args.matlab_unwrap(wrapperFile, 1); // call method and wrap result - // example: out[0]=wrap(self->return_field(t)); + // example: out[0]=wrap(obj->return_field(t)); string expanded = "obj->" + name_; if (!instName.empty()) expanded += ("<" + instName.qualifiedName("::") + ">"); - expanded += ("(" + args.names() + ")"); - if (returnVal.type1.name != "void") - returnVal.wrap_result(expanded, wrapperFile, typeAttributes); - else - wrapperFile.oss << " " + expanded + ";\n"; - // finish - wrapperFile.oss << "}\n"; - - return wrapFunctionName; + return expanded; } /* ************************************************************************* */ diff --git a/wrap/Method.h b/wrap/Method.h index 36a53b3d7..8b8c7eaab 100644 --- a/wrap/Method.h +++ b/wrap/Method.h @@ -18,16 +18,16 @@ #pragma once -#include "Function.h" +#include "StaticMethod.h" namespace wrap { /// Method class -struct Method : public Function { +struct Method: public StaticMethod { /// Constructor creates empty object Method(bool verbose = true) : - Function(verbose), is_const_(false) { + StaticMethod(verbose), is_const_(false) { } bool is_const_; @@ -39,21 +39,16 @@ struct Method : public Function { const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName = Qualified()); - // MATLAB code generation - // classPath is class directory, e.g., ../matlab/@Point2 - void proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, - const std::string& cppClassName, const std::string& matlabQualName, - const std::string& matlabUniqueName, const std::string& wrapperName, - const TypeAttributesTable& typeAttributes, - std::vector& functionNames) const; - private: - /// Emit C++ code - std::string wrapper_fragment(FileWriter& wrapperFile, + // Emit method header + void proxy_header(FileWriter& proxyFile) const; + + std::string wrapper_call(FileWriter& wrapperFile, const std::string& cppClassName, const std::string& matlabUniqueName, - int overload, int id, const TypeAttributesTable& typeAttributes, - const Qualified& instName) const; ///< cpp wrapper + const ArgumentList& args, const ReturnValue& returnVal, + const TypeAttributesTable& typeAttributes, + const Qualified& instName) const; }; } // \namespace wrap diff --git a/wrap/ReturnValue.cpp b/wrap/ReturnValue.cpp index 84d662e81..a511652e8 100644 --- a/wrap/ReturnValue.cpp +++ b/wrap/ReturnValue.cpp @@ -59,18 +59,17 @@ void ReturnType::wrapTypeUnwrap(FileWriter& wrapperFile) const { } /* ************************************************************************* */ -ReturnValue ReturnValue::expandTemplate(const string& templateArg, - const Qualified& qualifiedType, const Qualified& expandedClass) const { +ReturnValue ReturnValue::expandTemplate(const TemplateSubstitution& ts) const { ReturnValue instRetVal = *this; - if (type1.name == templateArg) { - instRetVal.type1.rename(qualifiedType); + if (type1.name == ts.templateArg) { + instRetVal.type1.rename(ts.qualifiedType); } else if (type1.name == "This") { - instRetVal.type1.rename(expandedClass); + instRetVal.type1.rename(ts.expandedClass); } - if (type2.name == templateArg) { - instRetVal.type2.rename(qualifiedType); + if (type2.name == ts.templateArg) { + instRetVal.type2.rename(ts.qualifiedType); } else if (type2.name == "This") { - instRetVal.type2.rename(expandedClass); + instRetVal.type2.rename(ts.expandedClass); } return instRetVal; } diff --git a/wrap/ReturnValue.h b/wrap/ReturnValue.h index 1caaeae22..55ebf8c57 100644 --- a/wrap/ReturnValue.h +++ b/wrap/ReturnValue.h @@ -8,7 +8,7 @@ * @author Richard Roberts */ -#include "Qualified.h" +#include "TemplateSubstitution.h" #include "FileWriter.h" #include "TypeAttributesTable.h" #include "utilities.h" @@ -86,21 +86,7 @@ struct ReturnValue { } /// Substitute template argument - ReturnValue expandTemplate(const std::string& templateArg, - const Qualified& qualifiedType, const Qualified& expandedClass) const; - - // TODO use transform ? - static std::vector ExpandTemplate( - std::vector returnVals, const std::string& templateArg, - const Qualified& qualifiedType, const Qualified& expandedClass) { - std::vector result; - BOOST_FOREACH(const ReturnValue& retVal, returnVals) { - ReturnValue instRetVal = retVal.expandTemplate(templateArg, - qualifiedType, expandedClass); - result.push_back(instRetVal); - } - return result; - } + ReturnValue expandTemplate(const TemplateSubstitution& ts) const; std::string return_type(bool add_ptr) const; diff --git a/wrap/StaticMethod.cpp b/wrap/StaticMethod.cpp index f8eba744f..a4d54f4dd 100644 --- a/wrap/StaticMethod.cpp +++ b/wrap/StaticMethod.cpp @@ -16,7 +16,7 @@ * @author Richard Roberts **/ -#include "StaticMethod.h" +#include "Method.h" #include "utilities.h" #include @@ -30,108 +30,148 @@ using namespace std; using namespace wrap; /* ************************************************************************* */ -void StaticMethod::proxy_wrapper_fragments(FileWriter& file, +void StaticMethod::addOverload(bool verbose, const std::string& name, + const ArgumentList& args, const ReturnValue& retVal, + const Qualified& instName) { + + Function::addOverload(verbose, name, instName); + SignatureOverloads::addOverload(args, retVal); +} + +/* ************************************************************************* */ +void StaticMethod::proxy_header(FileWriter& proxyFile) const { + string upperName = name_; + upperName[0] = std::toupper(upperName[0], std::locale()); + proxyFile.oss << " function varargout = " << upperName << "(varargin)\n"; +} + +/* ************************************************************************* */ +void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, const string& cppClassName, const std::string& matlabQualName, const std::string& matlabUniqueName, const string& wrapperName, const TypeAttributesTable& typeAttributes, vector& functionNames) const { - string upperName = name_; - upperName[0] = std::toupper(upperName[0], std::locale()); + proxy_header(proxyFile); - file.oss << " function varargout = " << upperName << "(varargin)\n"; - //Comments for documentation + // Emit comments for documentation string up_name = boost::to_upper_copy(name_); - file.oss << " % " << up_name << " usage: "; - unsigned int argLCount = 0; - BOOST_FOREACH(ArgumentList argList, argLists) { - argList.emit_prototype(file, name_); - if (argLCount != argLists.size() - 1) - file.oss << ", "; - else - file.oss << " : returns " - << returnVals[0].return_type(false) << endl; - argLCount++; - } + proxyFile.oss << " % " << up_name << " usage: "; + usage_fragment(proxyFile, name_); - file.oss << " % " + // Emit URL to Doxygen page + proxyFile.oss << " % " << "Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html" << endl; - file.oss << " % " << "" << endl; - file.oss << " % " << "Usage" << endl; - BOOST_FOREACH(ArgumentList argList, argLists) { - file.oss << " % "; - argList.emit_prototype(file, up_name); - file.oss << endl; - } - - // Check arguments for all overloads - for (size_t overload = 0; overload < argLists.size(); ++overload) { + // Handle special case of single overload with all numeric arguments + if (nrOverloads() == 1 && argumentList(0).allScalar()) { // Output proxy matlab code - file.oss << " " << (overload == 0 ? "" : "else"); + proxyFile.oss << " "; const int id = (int) functionNames.size(); - argLists[overload].emit_conditional_call(file, returnVals[overload], - wrapperName, id, true); // last bool is to indicate static ! + argumentList(0).emit_call(proxyFile, returnValue(0), wrapperName, id); // Output C++ wrapper code const string wrapFunctionName = wrapper_fragment(wrapperFile, cppClassName, - matlabUniqueName, (int) overload, id, typeAttributes); + matlabUniqueName, 0, id, typeAttributes, templateArgValue_); // Add to function list functionNames.push_back(wrapFunctionName); - } - file.oss << " else\n"; - file.oss << " error('Arguments do not match any overload of function " - << matlabQualName << "." << upperName << "');" << endl; - file.oss << " end\n"; + } else { + // Check arguments for all overloads + for (size_t i = 0; i < nrOverloads(); ++i) { - file.oss << " end\n"; + // Output proxy matlab code + proxyFile.oss << " " << (i == 0 ? "" : "else"); + const int id = (int) functionNames.size(); + string expanded = wrapperName; + if (!templateArgValue_.empty()) + expanded += templateArgValue_.name; + argumentList(i).emit_conditional_call(proxyFile, returnValue(i), expanded, + id); + + // Output C++ wrapper code + const string wrapFunctionName = wrapper_fragment(wrapperFile, + cppClassName, matlabUniqueName, i, id, typeAttributes, + templateArgValue_); + + // Add to function list + functionNames.push_back(wrapFunctionName); + } + proxyFile.oss << " else\n"; + proxyFile.oss + << " error('Arguments do not match any overload of function " + << matlabQualName << "." << name_ << "');" << endl; + proxyFile.oss << " end\n"; + } + + proxyFile.oss << " end\n"; } /* ************************************************************************* */ -string StaticMethod::wrapper_fragment(FileWriter& file, +string StaticMethod::wrapper_fragment(FileWriter& wrapperFile, const string& cppClassName, const string& matlabUniqueName, int overload, - int id, const TypeAttributesTable& typeAttributes) const { + int id, const TypeAttributesTable& typeAttributes, + const Qualified& instName) const { // generate code const string wrapFunctionName = matlabUniqueName + "_" + name_ + "_" + boost::lexical_cast(id); - const ArgumentList& args = argLists[overload]; - const ReturnValue& returnVal = returnVals[overload]; + const ArgumentList& args = argumentList(overload); + const ReturnValue& returnVal = returnValue(overload); // call - file.oss << "void " << wrapFunctionName + wrapperFile.oss << "void " << wrapFunctionName << "(int nargout, mxArray *out[], int nargin, const mxArray *in[])\n"; // start - file.oss << "{\n"; + wrapperFile.oss << "{\n"; - returnVal.wrapTypeUnwrap(file); + returnVal.wrapTypeUnwrap(wrapperFile); - file.oss << " typedef boost::shared_ptr<" << cppClassName << "> Shared;" - << endl; + wrapperFile.oss << " typedef boost::shared_ptr<" << cppClassName + << "> Shared;" << endl; - // check arguments - // NOTE: for static functions, there is no object passed - file.oss << " checkArguments(\"" << matlabUniqueName << "." << name_ - << "\",nargout,nargin," << args.size() << ");\n"; + // get call + // for static methods: cppClassName::staticMethod + // for instance methods: obj->instanceMethod + string expanded = wrapper_call(wrapperFile, cppClassName, matlabUniqueName, + args, returnVal, typeAttributes, instName); - // unwrap arguments, see Argument.cpp - args.matlab_unwrap(file, 0); // We start at 0 because there is no self object - - // call method with default type and wrap result + expanded += ("(" + args.names() + ")"); if (returnVal.type1.name != "void") - returnVal.wrap_result(cppClassName + "::" + name_ + "(" + args.names() + ")", - file, typeAttributes); + returnVal.wrap_result(expanded, wrapperFile, typeAttributes); else - file.oss << cppClassName + "::" + name_ + "(" + args.names() + ");\n"; + wrapperFile.oss << " " + expanded + ";\n"; // finish - file.oss << "}\n"; + wrapperFile.oss << "}\n"; return wrapFunctionName; } /* ************************************************************************* */ +string StaticMethod::wrapper_call(FileWriter& wrapperFile, + const string& cppClassName, const string& matlabUniqueName, + const ArgumentList& args, const ReturnValue& returnVal, + const TypeAttributesTable& typeAttributes, + const Qualified& instName) const { + // check arguments + // NOTE: for static functions, there is no object passed + wrapperFile.oss << " checkArguments(\"" << matlabUniqueName << "." << name_ + << "\",nargout,nargin," << args.size() << ");\n"; + + // unwrap arguments, see Argument.cpp + args.matlab_unwrap(wrapperFile, 0); // We start at 0 because there is no self object + + // call method and wrap result + // example: out[0]=wrap(staticMethod(t)); + string expanded = cppClassName + "::" + name_; + if (!instName.empty()) + expanded += ("<" + instName.qualifiedName("::") + ">"); + + return expanded; +} + +/* ************************************************************************* */ diff --git a/wrap/StaticMethod.h b/wrap/StaticMethod.h index 14162b3c8..9b9740bdb 100644 --- a/wrap/StaticMethod.h +++ b/wrap/StaticMethod.h @@ -24,13 +24,17 @@ namespace wrap { /// StaticMethod class -struct StaticMethod: public Function { +struct StaticMethod: public Function, public SignatureOverloads { /// Constructor creates empty object StaticMethod(bool verbosity = true) : Function(verbosity) { } + void addOverload(bool verbose, const std::string& name, + const ArgumentList& args, const ReturnValue& retVal, + const Qualified& instName); + // MATLAB code generation // classPath is class directory, e.g., ../matlab/@Point2 void proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, @@ -39,10 +43,20 @@ struct StaticMethod: public Function { const TypeAttributesTable& typeAttributes, std::vector& functionNames) const; -private: - std::string wrapper_fragment(FileWriter& file, +protected: + + virtual void proxy_header(FileWriter& proxyFile) const; + + std::string wrapper_fragment(FileWriter& wrapperFile, const std::string& cppClassName, const std::string& matlabUniqueName, - int overload, int id, const TypeAttributesTable& typeAttributes) const; ///< cpp wrapper + int overload, int id, const TypeAttributesTable& typeAttributes, + const Qualified& instName = Qualified()) const; ///< cpp wrapper + + virtual std::string wrapper_call(FileWriter& wrapperFile, + const std::string& cppClassName, const std::string& matlabUniqueName, + const ArgumentList& args, const ReturnValue& returnVal, + const TypeAttributesTable& typeAttributes, + const Qualified& instName) const; }; } // \namespace wrap diff --git a/wrap/TemplateInstantiationTypedef.cpp b/wrap/TemplateInstantiationTypedef.cpp index b93a05a54..2007acdf1 100644 --- a/wrap/TemplateInstantiationTypedef.cpp +++ b/wrap/TemplateInstantiationTypedef.cpp @@ -46,8 +46,10 @@ Class TemplateInstantiationTypedef::findAndExpand( // Instantiate it Class classInst = *matchedClass; - for (size_t i = 0; i < typeList.size(); ++i) - classInst = classInst.expandTemplate(classInst.templateArgs[i], typeList[i], *this); + for (size_t i = 0; i < typeList.size(); ++i) { + TemplateSubstitution ts(classInst.templateArgs[i], typeList[i], *this); + classInst = classInst.expandTemplate(ts); + } // Fix class properties classInst.name = name; diff --git a/wrap/TemplateSubstitution.h b/wrap/TemplateSubstitution.h new file mode 100644 index 000000000..5ce2f3a86 --- /dev/null +++ b/wrap/TemplateSubstitution.h @@ -0,0 +1,39 @@ +/* ---------------------------------------------------------------------------- + + * GTSAM Copyright 2010, Georgia Tech Research Corporation, + * Atlanta, Georgia 30332-0415 + * All Rights Reserved + * Authors: Frank Dellaert, et al. (see THANKS for the full author list) + + * See LICENSE for the license information + + * -------------------------------------------------------------------------- */ + +/** + * @file TemplateSubstitution.h + * @brief Auxiliary class for template sunstitutions + * @author Frank Dellaert + * @date Nov 13, 2014 + **/ + +#pragma once + +#include "Qualified.h" +#include + +namespace wrap { + +/** + * e.g. TemplateSubstitution("T", gtsam::Point2, gtsam::PriorFactorPoint2) + */ +struct TemplateSubstitution { + TemplateSubstitution(const std::string& a, const Qualified& t, + const Qualified& e) : + templateArg(a), qualifiedType(t), expandedClass(e) { + } + std::string templateArg; + Qualified qualifiedType, expandedClass; +}; + +} // \namespace wrap + diff --git a/wrap/tests/expected2/+gtsam/Point2.m b/wrap/tests/expected2/+gtsam/Point2.m new file mode 100644 index 000000000..308b35d9a --- /dev/null +++ b/wrap/tests/expected2/+gtsam/Point2.m @@ -0,0 +1,90 @@ +%class Point2, see Doxygen page for details +%at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html +% +%-------Constructors------- +%Point2() +%Point2(double x, double y) +% +%-------Methods------- +%argChar(char a) : returns void +%argUChar(unsigned char a) : returns void +%dim() : returns int +%returnChar() : returns char +%vectorConfusion() : returns VectorNotEigen +%x() : returns double +%y() : returns double +% +classdef Point2 < handle + properties + ptr_gtsamPoint2 = 0 + end + methods + function obj = Point2(varargin) + if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682) + my_ptr = varargin{2}; + geometry_wrapper(0, my_ptr); + elseif nargin == 0 + my_ptr = geometry_wrapper(1); + elseif nargin == 2 && isa(varargin{1},'double') && isa(varargin{2},'double') + my_ptr = geometry_wrapper(2, varargin{1}, varargin{2}); + else + error('Arguments do not match any overload of gtsam.Point2 constructor'); + end + obj.ptr_gtsamPoint2 = my_ptr; + end + + function delete(obj) + geometry_wrapper(3, obj.ptr_gtsamPoint2); + end + + function display(obj), obj.print(''); end + %DISPLAY Calls print on the object + function disp(obj), obj.display; end + %DISP Calls print on the object + function varargout = argChar(this, varargin) + % ARGCHAR usage: argChar(char a) : returns void + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + geometry_wrapper(4, this, varargin{:}); + end + + function varargout = argUChar(this, varargin) + % ARGUCHAR usage: argUChar(unsigned char a) : returns void + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + geometry_wrapper(5, this, varargin{:}); + end + + function varargout = dim(this, varargin) + % DIM usage: dim() : returns int + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + varargout{1} = geometry_wrapper(6, this, varargin{:}); + end + + function varargout = returnChar(this, varargin) + % RETURNCHAR usage: returnChar() : returns char + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + varargout{1} = geometry_wrapper(7, this, varargin{:}); + end + + function varargout = vectorConfusion(this, varargin) + % VECTORCONFUSION usage: vectorConfusion() : returns VectorNotEigen + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + varargout{1} = geometry_wrapper(8, this, varargin{:}); + end + + function varargout = x(this, varargin) + % X usage: x() : returns double + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + varargout{1} = geometry_wrapper(9, this, varargin{:}); + end + + function varargout = y(this, varargin) + % Y usage: y() : returns double + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + varargout{1} = geometry_wrapper(10, this, varargin{:}); + end + + end + + methods(Static = true) + end +end diff --git a/wrap/tests/expected2/+gtsam/Point3.m b/wrap/tests/expected2/+gtsam/Point3.m new file mode 100644 index 000000000..d445c78ef --- /dev/null +++ b/wrap/tests/expected2/+gtsam/Point3.m @@ -0,0 +1,75 @@ +%class Point3, see Doxygen page for details +%at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html +% +%-------Constructors------- +%Point3(double x, double y, double z) +% +%-------Methods------- +%norm() : returns double +% +%-------Static Methods------- +%StaticFunctionRet(double z) : returns gtsam::Point3 +%staticFunction() : returns double +% +classdef Point3 < handle + properties + ptr_gtsamPoint3 = 0 + end + methods + function obj = Point3(varargin) + if nargin == 2 && isa(varargin{1}, 'uint64') && varargin{1} == uint64(5139824614673773682) + my_ptr = varargin{2}; + geometry_wrapper(11, my_ptr); + elseif nargin == 3 && isa(varargin{1},'double') && isa(varargin{2},'double') && isa(varargin{3},'double') + my_ptr = geometry_wrapper(12, varargin{1}, varargin{2}, varargin{3}); + else + error('Arguments do not match any overload of gtsam.Point3 constructor'); + end + obj.ptr_gtsamPoint3 = my_ptr; + end + + function delete(obj) + geometry_wrapper(13, obj.ptr_gtsamPoint3); + end + + function display(obj), obj.print(''); end + %DISPLAY Calls print on the object + function disp(obj), obj.display; end + %DISP Calls print on the object + function varargout = norm(this, varargin) + % NORM usage: norm() : returns double + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + varargout{1} = geometry_wrapper(14, this, varargin{:}); + end + + end + + methods(Static = true) + function varargout = StaticFunctionRet(varargin) + % STATICFUNCTIONRET usage: StaticFunctionRet(double z) : returns gtsam::Point3 + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + % + % Usage + % STATICFUNCTIONRET(double z) + if length(varargin) == 1 && isa(varargin{1},'double') + varargout{1} = geometry_wrapper(15, varargin{:}); + else + error('Arguments do not match any overload of function gtsam.Point3.StaticFunctionRet'); + end + end + + function varargout = StaticFunction(varargin) + % STATICFUNCTION usage: staticFunction() : returns double + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + % + % Usage + % STATICFUNCTION() + if length(varargin) == 0 + varargout{1} = geometry_wrapper(16, varargin{:}); + else + error('Arguments do not match any overload of function gtsam.Point3.StaticFunction'); + end + end + + end +end diff --git a/wrap/tests/expected_namespaces/+ns2/ClassA.m b/wrap/tests/expected_namespaces/+ns2/ClassA.m index 9c064734e..9f0055af9 100644 --- a/wrap/tests/expected_namespaces/+ns2/ClassA.m +++ b/wrap/tests/expected_namespaces/+ns2/ClassA.m @@ -65,14 +65,7 @@ classdef ClassA < handle function varargout = Afunction(varargin) % AFUNCTION usage: afunction() : returns double % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html - % - % Usage - % AFUNCTION() - if length(varargin) == 0 - varargout{1} = testNamespaces_wrapper(12, varargin{:}); - else - error('Arguments do not match any overload of function ns2.ClassA.Afunction'); - end + varargout{1} = testNamespaces_wrapper(12, this, varargin{:}); end end diff --git a/wrap/tests/testWrap.cpp b/wrap/tests/testWrap.cpp index 743370c6d..02e618668 100644 --- a/wrap/tests/testWrap.cpp +++ b/wrap/tests/testWrap.cpp @@ -99,10 +99,9 @@ TEST( wrap, Small ) { Method m1 = cls.method("x"); EXPECT(assert_equal("x", m1.name_)); EXPECT(m1.is_const_); - LONGS_EQUAL(1, m1.argLists.size()); - LONGS_EQUAL(1, m1.returnVals.size()); + LONGS_EQUAL(1, m1.nrOverloads()); - ReturnValue rv1 = m1.returnVals.front(); + ReturnValue rv1 = m1.returnValue(0); EXPECT(!rv1.isPair); EXPECT(!rv1.type1.isPtr); EXPECT(assert_equal("double", rv1.type1.name)); @@ -112,10 +111,9 @@ TEST( wrap, Small ) { Method m2 = cls.method("returnMatrix"); EXPECT(assert_equal("returnMatrix", m2.name_)); EXPECT(m2.is_const_); - LONGS_EQUAL(1, m2.argLists.size()); - LONGS_EQUAL(1, m2.returnVals.size()); + LONGS_EQUAL(1, m2.nrOverloads()); - ReturnValue rv2 = m2.returnVals.front(); + ReturnValue rv2 = m2.returnValue(0); EXPECT(!rv2.isPair); EXPECT(!rv2.type1.isPtr); EXPECT(assert_equal("Matrix", rv2.type1.name)); @@ -125,10 +123,9 @@ TEST( wrap, Small ) { Method m3 = cls.method("returnPoint2"); EXPECT(assert_equal("returnPoint2", m3.name_)); EXPECT(m3.is_const_); - LONGS_EQUAL(1, m3.argLists.size()); - LONGS_EQUAL(1, m3.returnVals.size()); + LONGS_EQUAL(1, m3.nrOverloads()); - ReturnValue rv3 = m3.returnVals.front(); + ReturnValue rv3 = m3.returnValue(0); EXPECT(!rv3.isPair); EXPECT(!rv3.type1.isPtr); EXPECT(assert_equal("Point2", rv3.type1.name)); @@ -138,10 +135,9 @@ TEST( wrap, Small ) { // static Vector returnVector(); StaticMethod sm1 = cls.static_methods.at("returnVector"); EXPECT(assert_equal("returnVector", sm1.name_)); - LONGS_EQUAL(1, sm1.argLists.size()); - LONGS_EQUAL(1, sm1.returnVals.size()); + LONGS_EQUAL(1, sm1.nrOverloads()); - ReturnValue rv4 = sm1.returnVals.front(); + ReturnValue rv4 = sm1.returnValue(0); EXPECT(!rv4.isPair); EXPECT(!rv4.type1.isPtr); EXPECT(assert_equal("Vector", rv4.type1.name)); @@ -195,13 +191,13 @@ TEST( wrap, Geometry ) { // char returnChar() const; CHECK(cls.exists("returnChar")); Method m1 = cls.method("returnChar"); - LONGS_EQUAL(1, m1.returnVals.size()); - EXPECT(assert_equal("char", m1.returnVals.front().type1.name)); - EXPECT_LONGS_EQUAL(ReturnType::BASIS, m1.returnVals.front().type1.category); - EXPECT(!m1.returnVals.front().isPair); + LONGS_EQUAL(1, m1.nrOverloads()); + EXPECT(assert_equal("char", m1.returnValue(0).type1.name)); + EXPECT_LONGS_EQUAL(ReturnType::BASIS, m1.returnValue(0).type1.category); + EXPECT(!m1.returnValue(0).isPair); EXPECT(assert_equal("returnChar", m1.name_)); - LONGS_EQUAL(1, m1.argLists.size()); - EXPECT_LONGS_EQUAL(0, m1.argLists.front().size()); + LONGS_EQUAL(1, m1.nrOverloads()); + EXPECT_LONGS_EQUAL(0, m1.argumentList(0).size()); EXPECT(m1.is_const_); } @@ -209,13 +205,13 @@ TEST( wrap, Geometry ) { // VectorNotEigen vectorConfusion(); CHECK(cls.exists("vectorConfusion")); Method m1 = cls.method("vectorConfusion"); - LONGS_EQUAL(1, m1.returnVals.size()); - EXPECT(assert_equal("VectorNotEigen", m1.returnVals.front().type1.name)); - EXPECT_LONGS_EQUAL(ReturnType::CLASS, m1.returnVals.front().type1.category); - EXPECT(!m1.returnVals.front().isPair); + LONGS_EQUAL(1, m1.nrOverloads()); + EXPECT(assert_equal("VectorNotEigen", m1.returnValue(0).type1.name)); + EXPECT_LONGS_EQUAL(ReturnType::CLASS, m1.returnValue(0).type1.category); + EXPECT(!m1.returnValue(0).isPair); EXPECT(assert_equal("vectorConfusion", m1.name_)); - LONGS_EQUAL(1, m1.argLists.size()); - EXPECT_LONGS_EQUAL(0, m1.argLists.front().size()); + LONGS_EQUAL(1, m1.nrOverloads()); + EXPECT_LONGS_EQUAL(0, m1.argumentList(0).size()); EXPECT(!m1.is_const_); } @@ -252,12 +248,12 @@ TEST( wrap, Geometry ) { // check method CHECK(cls.exists("norm")); Method m1 = cls.method("norm"); - LONGS_EQUAL(1, m1.returnVals.size()); - EXPECT(assert_equal("double", m1.returnVals.front().type1.name)); - EXPECT_LONGS_EQUAL(ReturnType::BASIS, m1.returnVals.front().type1.category); + LONGS_EQUAL(1, m1.nrOverloads()); + EXPECT(assert_equal("double", m1.returnValue(0).type1.name)); + EXPECT_LONGS_EQUAL(ReturnType::BASIS, m1.returnValue(0).type1.category); EXPECT(assert_equal("norm", m1.name_)); - LONGS_EQUAL(1, m1.argLists.size()); - EXPECT_LONGS_EQUAL(0, m1.argLists.front().size()); + LONGS_EQUAL(1, m1.nrOverloads()); + EXPECT_LONGS_EQUAL(0, m1.argumentList(0).size()); EXPECT(m1.is_const_); #ifndef WRAP_DISABLE_SERIALIZE @@ -278,19 +274,19 @@ TEST( wrap, Geometry ) { // function to parse: pair return_pair (Vector v, Matrix A) const; CHECK(testCls.exists("return_pair")); Method m2 = testCls.method("return_pair"); - LONGS_EQUAL(1, m2.returnVals.size()); - EXPECT(m2.returnVals.front().isPair); - EXPECT_LONGS_EQUAL(ReturnType::EIGEN, m2.returnVals.front().type1.category); - EXPECT(assert_equal("Vector", m2.returnVals.front().type1.name)); - EXPECT_LONGS_EQUAL(ReturnType::EIGEN, m2.returnVals.front().type2.category); - EXPECT(assert_equal("Matrix", m2.returnVals.front().type2.name)); + LONGS_EQUAL(1, m2.nrOverloads()); + EXPECT(m2.returnValue(0).isPair); + EXPECT_LONGS_EQUAL(ReturnType::EIGEN, m2.returnValue(0).type1.category); + EXPECT(assert_equal("Vector", m2.returnValue(0).type1.name)); + EXPECT_LONGS_EQUAL(ReturnType::EIGEN, m2.returnValue(0).type2.category); + EXPECT(assert_equal("Matrix", m2.returnValue(0).type2.name)); // checking pointer args and return values // pair return_ptrs (Test* p1, Test* p2) const; CHECK(testCls.exists("return_ptrs")); Method m3 = testCls.method("return_ptrs"); - LONGS_EQUAL(1, m3.argLists.size()); - ArgumentList args = m3.argLists.front(); + LONGS_EQUAL(1, m3.nrOverloads()); + ArgumentList args = m3.argumentList(0); LONGS_EQUAL(2, args.size()); Argument arg1 = args.at(0); @@ -317,9 +313,9 @@ TEST( wrap, Geometry ) { { GlobalFunction gfunc = module.global_functions.at("aGlobalFunction"); EXPECT(assert_equal("aGlobalFunction", gfunc.name_)); - LONGS_EQUAL(1, gfunc.returnVals.size()); - EXPECT(assert_equal("Vector", gfunc.returnVals.front().type1.name)); - EXPECT_LONGS_EQUAL(1, gfunc.argLists.size()); + LONGS_EQUAL(1, gfunc.nrOverloads()); + EXPECT(assert_equal("Vector", gfunc.returnValue(0).type1.name)); + EXPECT_LONGS_EQUAL(1, gfunc.nrOverloads()); LONGS_EQUAL(1, gfunc.overloads.size()); EXPECT(gfunc.overloads.front().namespaces.empty()); } @@ -391,9 +387,8 @@ TEST( wrap, parse_namespaces ) { { GlobalFunction gfunc = module.global_functions.at("aGlobalFunction"); EXPECT(assert_equal("aGlobalFunction", gfunc.name_)); - LONGS_EQUAL(2, gfunc.returnVals.size()); - EXPECT(assert_equal("Vector", gfunc.returnVals.front().type1.name)); - EXPECT_LONGS_EQUAL(2, gfunc.argLists.size()); + LONGS_EQUAL(2, gfunc.nrOverloads()); + EXPECT(assert_equal("Vector", gfunc.returnValue(0).type1.name)); // check namespaces LONGS_EQUAL(2, gfunc.overloads.size()); From fe481dc775f277cb67f04fe6eef78978dc4bbc51 Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 17:34:33 +0100 Subject: [PATCH 04/12] typedef to cope with abundance of strings --- wrap/Class.cpp | 35 +++++++++++++++++++---------------- wrap/Class.h | 36 ++++++++++++++++++++---------------- wrap/Method.cpp | 6 +++--- wrap/Method.h | 11 ++++++----- wrap/StaticMethod.cpp | 26 ++++++++++++-------------- wrap/StaticMethod.h | 27 +++++++++++++-------------- 6 files changed, 73 insertions(+), 68 deletions(-) diff --git a/wrap/Class.cpp b/wrap/Class.cpp index d219452a3..fab977802 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -33,7 +33,7 @@ using namespace std; using namespace wrap; /* ************************************************************************* */ -void Class::matlab_proxy(const string& toolboxPath, const string& wrapperName, +void Class::matlab_proxy(Str toolboxPath, Str wrapperName, const TypeAttributesTable& typeAttributes, FileWriter& wrapperFile, vector& functionNames) const { @@ -144,7 +144,7 @@ void Class::matlab_proxy(const string& toolboxPath, const string& wrapperName, /* ************************************************************************* */ void Class::pointer_constructor_fragments(FileWriter& proxyFile, - FileWriter& wrapperFile, const string& wrapperName, + FileWriter& wrapperFile, Str wrapperName, vector& functionNames) const { const string matlabUniqueName = qualifiedName(); @@ -251,7 +251,7 @@ Class Class::expandTemplate(const TemplateSubstitution& ts) const { } /* ************************************************************************* */ -vector Class::expandTemplate(const string& templateArg, +vector Class::expandTemplate(Str templateArg, const vector& instantiations) const { vector result; BOOST_FOREACH(const Qualified& instName, instantiations) { @@ -269,26 +269,29 @@ vector Class::expandTemplate(const string& templateArg, } /* ************************************************************************* */ -void Class::addMethod(bool verbose, bool is_const, const string& name, - const ArgumentList& args, const ReturnValue& retVal, - const string& templateArgName, const vector& templateArgValues) { +void Class::addMethod(bool verbose, bool is_const, Str methodName, + const ArgumentList& argumentList, const ReturnValue& returnValue, + Str templateArgName, const vector& templateArgValues) { // Check if templated if (!templateArgName.empty() && templateArgValues.size() > 0) { // Create method to expand // For all values of the template argument, create a new method BOOST_FOREACH(const Qualified& instName, templateArgValues) { - string expandedName = name + instName.name; + const TemplateSubstitution ts(templateArgName, instName, this->name); // substitute template in arguments - const TemplateSubstitution ts(templateArgName, instName, name); - ArgumentList expandedArgs = args.expandTemplate(ts); + ArgumentList expandedArgs = argumentList.expandTemplate(ts); // do the same for return types - ReturnValue expandedRetVal = retVal.expandTemplate(ts); - methods[expandedName].addOverload(verbose, is_const, name, expandedArgs, - expandedRetVal, instName); + ReturnValue expandedRetVal = returnValue.expandTemplate(ts); + // Now stick in new overload stack with expandedMethodName key + // but note we use the same, unexpanded methodName in overload + string expandedMethodName = methodName + instName.name; + methods[expandedMethodName].addOverload(verbose, is_const, methodName, + expandedArgs, expandedRetVal, instName); } } else // just add overload - methods[name].addOverload(verbose, is_const, name, args, retVal); + methods[methodName].addOverload(verbose, is_const, methodName, argumentList, + returnValue); } /* ************************************************************************* */ @@ -357,7 +360,7 @@ void Class::appendInheritedMethods(const Class& cls, /* ************************************************************************* */ string Class::getTypedef() const { string result; - BOOST_FOREACH(const string& namesp, namespaces) { + BOOST_FOREACH(Str namesp, namespaces) { result += ("namespace " + namesp + " { "); } result += ("typedef " + typedefName + " " + name + ";"); @@ -408,7 +411,7 @@ void Class::comment_fragment(FileWriter& proxyFile) const { /* ************************************************************************* */ void Class::serialization_fragments(FileWriter& proxyFile, - FileWriter& wrapperFile, const string& wrapperName, + FileWriter& wrapperFile, Str wrapperName, vector& functionNames) const { //void Point3_string_serialize_17(int nargout, mxArray *out[], int nargin, const mxArray *in[]) @@ -500,7 +503,7 @@ void Class::serialization_fragments(FileWriter& proxyFile, /* ************************************************************************* */ void Class::deserialization_fragments(FileWriter& proxyFile, - FileWriter& wrapperFile, const string& wrapperName, + FileWriter& wrapperFile, Str wrapperName, vector& functionNames) const { //void Point3_string_deserialize_18(int nargout, mxArray *out[], int nargin, const mxArray *in[]) //{ diff --git a/wrap/Class.h b/wrap/Class.h index 610c9b7b4..809f40049 100644 --- a/wrap/Class.h +++ b/wrap/Class.h @@ -38,6 +38,7 @@ class Class: public Qualified { public: + typedef const std::string& Str; typedef std::map StaticMethods; // Then the instance variables are set directly by the Module constructor @@ -58,25 +59,30 @@ public: verbose), verbose_(verbose) { } - size_t nrMethods() const { return methods.size(); } - Method& method(const std::string& name) { return methods.at(name); } - bool exists(const std::string& name) const { return methods.find(name) != methods.end(); } + size_t nrMethods() const { + return methods.size(); + } + Method& method(Str name) { + return methods.at(name); + } + bool exists(Str name) const { + return methods.find(name) != methods.end(); + } // And finally MATLAB code is emitted, methods below called by Module::matlab_code - void matlab_proxy(const std::string& toolboxPath, - const std::string& wrapperName, const TypeAttributesTable& typeAttributes, - FileWriter& wrapperFile, std::vector& functionNames) const; ///< emit proxy class + void matlab_proxy(Str toolboxPath, Str wrapperName, + const TypeAttributesTable& typeAttributes, FileWriter& wrapperFile, + std::vector& functionNames) const; ///< emit proxy class Class expandTemplate(const TemplateSubstitution& ts) const; - std::vector expandTemplate(const std::string& templateArg, + std::vector expandTemplate(Str templateArg, const std::vector& instantiations) const; /// Add potentially overloaded, potentially templated method - void addMethod(bool verbose, bool is_const, const std::string& name, - const ArgumentList& args, const ReturnValue& retVal, - const std::string& templateArgName, - const std::vector& templateArgValues); + void addMethod(bool verbose, bool is_const, Str methodName, + const ArgumentList& argumentList, const ReturnValue& returnValue, + Str templateArgName, const std::vector& templateArgValues); /// Post-process classes for serialization markers void erase_serialization(); // non-const ! @@ -96,18 +102,16 @@ public: /// Creates a member function that performs serialization void serialization_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, - const std::string& wrapperName, - std::vector& functionNames) const; + Str wrapperName, std::vector& functionNames) const; /// Creates a static member function that performs deserialization void deserialization_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, - const std::string& wrapperName, - std::vector& functionNames) const; + Str wrapperName, std::vector& functionNames) const; private: void pointer_constructor_fragments(FileWriter& proxyFile, - FileWriter& wrapperFile, const std::string& wrapperName, + FileWriter& wrapperFile, Str wrapperName, std::vector& functionNames) const; void comment_fragment(FileWriter& proxyFile) const; diff --git a/wrap/Method.cpp b/wrap/Method.cpp index d342df04b..19e302e2a 100644 --- a/wrap/Method.cpp +++ b/wrap/Method.cpp @@ -29,7 +29,7 @@ using namespace std; using namespace wrap; /* ************************************************************************* */ -void Method::addOverload(bool verbose, bool is_const, const std::string& name, +void Method::addOverload(bool verbose, bool is_const, Str name, const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName) { @@ -43,8 +43,8 @@ void Method::proxy_header(FileWriter& proxyFile) const { } /* ************************************************************************* */ -string Method::wrapper_call(FileWriter& wrapperFile, const string& cppClassName, - const string& matlabUniqueName, const ArgumentList& args, +string Method::wrapper_call(FileWriter& wrapperFile, Str cppClassName, + Str matlabUniqueName, const ArgumentList& args, const ReturnValue& returnVal, const TypeAttributesTable& typeAttributes, const Qualified& instName) const { // check arguments diff --git a/wrap/Method.h b/wrap/Method.h index 8b8c7eaab..d1e382a13 100644 --- a/wrap/Method.h +++ b/wrap/Method.h @@ -25,6 +25,8 @@ namespace wrap { /// Method class struct Method: public StaticMethod { + typedef const std::string& Str; + /// Constructor creates empty object Method(bool verbose = true) : StaticMethod(verbose), is_const_(false) { @@ -35,7 +37,7 @@ struct Method: public StaticMethod { // The first time this function is called, it initializes the class members // with those in rhs, but in subsequent calls it adds additional argument // lists as function overloads. - void addOverload(bool verbose, bool is_const, const std::string& name, + void addOverload(bool verbose, bool is_const, Str name, const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName = Qualified()); @@ -44,10 +46,9 @@ private: // Emit method header void proxy_header(FileWriter& proxyFile) const; - std::string wrapper_call(FileWriter& wrapperFile, - const std::string& cppClassName, const std::string& matlabUniqueName, - const ArgumentList& args, const ReturnValue& returnVal, - const TypeAttributesTable& typeAttributes, + virtual std::string wrapper_call(FileWriter& wrapperFile, Str cppClassName, + Str matlabUniqueName, const ArgumentList& args, + const ReturnValue& returnVal, const TypeAttributesTable& typeAttributes, const Qualified& instName) const; }; diff --git a/wrap/StaticMethod.cpp b/wrap/StaticMethod.cpp index a4d54f4dd..4d3a9acde 100644 --- a/wrap/StaticMethod.cpp +++ b/wrap/StaticMethod.cpp @@ -30,9 +30,8 @@ using namespace std; using namespace wrap; /* ************************************************************************* */ -void StaticMethod::addOverload(bool verbose, const std::string& name, - const ArgumentList& args, const ReturnValue& retVal, - const Qualified& instName) { +void StaticMethod::addOverload(bool verbose, Str name, const ArgumentList& args, + const ReturnValue& retVal, const Qualified& instName) { Function::addOverload(verbose, name, instName); SignatureOverloads::addOverload(args, retVal); @@ -41,15 +40,15 @@ void StaticMethod::addOverload(bool verbose, const std::string& name, /* ************************************************************************* */ void StaticMethod::proxy_header(FileWriter& proxyFile) const { string upperName = name_; - upperName[0] = std::toupper(upperName[0], std::locale()); + upperName[0] = toupper(upperName[0], locale()); proxyFile.oss << " function varargout = " << upperName << "(varargin)\n"; } /* ************************************************************************* */ void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, - FileWriter& wrapperFile, const string& cppClassName, - const std::string& matlabQualName, const std::string& matlabUniqueName, - const string& wrapperName, const TypeAttributesTable& typeAttributes, + FileWriter& wrapperFile, Str cppClassName, Str matlabQualName, + Str matlabUniqueName, Str wrapperName, + const TypeAttributesTable& typeAttributes, vector& functionNames) const { proxy_header(proxyFile); @@ -109,9 +108,9 @@ void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, } /* ************************************************************************* */ -string StaticMethod::wrapper_fragment(FileWriter& wrapperFile, - const string& cppClassName, const string& matlabUniqueName, int overload, - int id, const TypeAttributesTable& typeAttributes, +string StaticMethod::wrapper_fragment(FileWriter& wrapperFile, Str cppClassName, + Str matlabUniqueName, int overload, int id, + const TypeAttributesTable& typeAttributes, const Qualified& instName) const { // generate code @@ -152,10 +151,9 @@ string StaticMethod::wrapper_fragment(FileWriter& wrapperFile, } /* ************************************************************************* */ -string StaticMethod::wrapper_call(FileWriter& wrapperFile, - const string& cppClassName, const string& matlabUniqueName, - const ArgumentList& args, const ReturnValue& returnVal, - const TypeAttributesTable& typeAttributes, +string StaticMethod::wrapper_call(FileWriter& wrapperFile, Str cppClassName, + Str matlabUniqueName, const ArgumentList& args, + const ReturnValue& returnVal, const TypeAttributesTable& typeAttributes, const Qualified& instName) const { // check arguments // NOTE: for static functions, there is no object passed diff --git a/wrap/StaticMethod.h b/wrap/StaticMethod.h index 9b9740bdb..cab440ef1 100644 --- a/wrap/StaticMethod.h +++ b/wrap/StaticMethod.h @@ -26,36 +26,35 @@ namespace wrap { /// StaticMethod class struct StaticMethod: public Function, public SignatureOverloads { + typedef const std::string& Str; + /// Constructor creates empty object StaticMethod(bool verbosity = true) : Function(verbosity) { } - void addOverload(bool verbose, const std::string& name, - const ArgumentList& args, const ReturnValue& retVal, - const Qualified& instName); + void addOverload(bool verbose, Str name, const ArgumentList& args, + const ReturnValue& retVal, const Qualified& instName); // MATLAB code generation // classPath is class directory, e.g., ../matlab/@Point2 void proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, - const std::string& cppClassName, const std::string& matlabQualName, - const std::string& matlabUniqueName, const std::string& wrapperName, - const TypeAttributesTable& typeAttributes, + Str cppClassName, Str matlabQualName, Str matlabUniqueName, + Str wrapperName, const TypeAttributesTable& typeAttributes, std::vector& functionNames) const; protected: virtual void proxy_header(FileWriter& proxyFile) const; - std::string wrapper_fragment(FileWriter& wrapperFile, - const std::string& cppClassName, const std::string& matlabUniqueName, - int overload, int id, const TypeAttributesTable& typeAttributes, - const Qualified& instName = Qualified()) const; ///< cpp wrapper + std::string wrapper_fragment(FileWriter& wrapperFile, Str cppClassName, + Str matlabUniqueName, int overload, int id, + const TypeAttributesTable& typeAttributes, const Qualified& instName = + Qualified()) const; ///< cpp wrapper - virtual std::string wrapper_call(FileWriter& wrapperFile, - const std::string& cppClassName, const std::string& matlabUniqueName, - const ArgumentList& args, const ReturnValue& returnVal, - const TypeAttributesTable& typeAttributes, + virtual std::string wrapper_call(FileWriter& wrapperFile, Str cppClassName, + Str matlabUniqueName, const ArgumentList& args, + const ReturnValue& returnVal, const TypeAttributesTable& typeAttributes, const Qualified& instName) const; }; From 482dbd9226fd3638bda15329d0e85dc1432104a8 Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 19:34:15 +0100 Subject: [PATCH 05/12] Made TemplateSubstitution into an operator, and added stream operator --- wrap/Argument.cpp | 6 +--- wrap/Class.cpp | 4 ++- wrap/Function.h | 6 ++-- wrap/ReturnType.cpp | 61 +++++++++++++++++++++++++++++++++ wrap/ReturnType.h | 67 +++++++++++++++++++++++++++++++++++++ wrap/ReturnValue.cpp | 56 ++----------------------------- wrap/ReturnValue.h | 54 ++---------------------------- wrap/TemplateSubstitution.h | 45 +++++++++++++++++++++---- 8 files changed, 178 insertions(+), 121 deletions(-) create mode 100644 wrap/ReturnType.cpp create mode 100644 wrap/ReturnType.h diff --git a/wrap/Argument.cpp b/wrap/Argument.cpp index 19e46fd85..4989afb0d 100644 --- a/wrap/Argument.cpp +++ b/wrap/Argument.cpp @@ -31,11 +31,7 @@ using namespace wrap; /* ************************************************************************* */ Argument Argument::expandTemplate(const TemplateSubstitution& ts) const { Argument instArg = *this; - if (type.name == ts.templateArg) { - instArg.type = ts.qualifiedType; - } else if (type.name == "This") { - instArg.type = ts.expandedClass; - } + instArg.type = ts(type); return instArg; } diff --git a/wrap/Class.cpp b/wrap/Class.cpp index fab977802..5da9d8bd0 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -274,13 +274,15 @@ void Class::addMethod(bool verbose, bool is_const, Str methodName, Str templateArgName, const vector& templateArgValues) { // Check if templated if (!templateArgName.empty() && templateArgValues.size() > 0) { + cout << methodName << endl; // Create method to expand // For all values of the template argument, create a new method BOOST_FOREACH(const Qualified& instName, templateArgValues) { const TemplateSubstitution ts(templateArgName, instName, this->name); + cout << ts << endl; // substitute template in arguments ArgumentList expandedArgs = argumentList.expandTemplate(ts); - // do the same for return types + // do the same for return type ReturnValue expandedRetVal = returnValue.expandTemplate(ts); // Now stick in new overload stack with expandedMethodName key // but note we use the same, unexpanded methodName in overload diff --git a/wrap/Function.h b/wrap/Function.h index dd6d2158c..d175fe145 100644 --- a/wrap/Function.h +++ b/wrap/Function.h @@ -88,7 +88,7 @@ public: std::string fullType = arg.type.qualifiedName("::"); if (find(validArgs.begin(), validArgs.end(), fullType) == validArgs.end()) - throw DependencyMissing(fullType, s); + throw DependencyMissing(fullType, "checking argument of " + s); } } } @@ -125,7 +125,7 @@ public: } // TODO use transform ? - std::vector ExpandReturnValuesTemplate( + std::vector expandReturnValuesTemplate( const TemplateSubstitution& ts) const { std::vector result; BOOST_FOREACH(const ReturnValue& retVal, returnVals_) { @@ -140,7 +140,7 @@ public: // substitute template in arguments argLists_ = expandArgumentListsTemplate(ts); // do the same for return types - returnVals_ = ExpandReturnValuesTemplate(ts); + returnVals_ = expandReturnValuesTemplate(ts); } // emit a list of comments, one for each overload diff --git a/wrap/ReturnType.cpp b/wrap/ReturnType.cpp new file mode 100644 index 000000000..a317a5420 --- /dev/null +++ b/wrap/ReturnType.cpp @@ -0,0 +1,61 @@ +/** + * @file ReturnType.cpp + * @date Nov 13, 2014 + * @author Frank Dellaert + */ + +#include "ReturnType.h" +#include "utilities.h" +#include +#include + +using namespace std; +using namespace wrap; + +/* ************************************************************************* */ +string ReturnType::str(bool add_ptr) const { + return maybe_shared_ptr(add_ptr && isPtr, qualifiedName("::"), name); +} + +/* ************************************************************************* */ +void ReturnType::wrap_result(const string& out, const string& result, + FileWriter& wrapperFile, const TypeAttributesTable& typeAttributes) const { + + string cppType = qualifiedName("::"), matlabType = qualifiedName("."); + + if (category == CLASS) { + string objCopy, ptrType; + ptrType = "Shared" + name; + const bool isVirtual = typeAttributes.at(cppType).isVirtual; + if (isVirtual) { + if (isPtr) + objCopy = result; + else + objCopy = result + ".clone()"; + } else { + if (isPtr) + objCopy = result; + else + objCopy = ptrType + "(new " + cppType + "(" + result + "))"; + } + wrapperFile.oss << out << " = wrap_shared_ptr(" << objCopy << ",\"" + << matlabType << "\", " << (isVirtual ? "true" : "false") << ");\n"; + } else if (isPtr) { + wrapperFile.oss << " Shared" << name << "* ret = new Shared" << name << "(" + << result << ");" << endl; + wrapperFile.oss << out << " = wrap_shared_ptr(ret,\"" << matlabType + << "\");\n"; + } else if (matlabType != "void") + wrapperFile.oss << out << " = wrap< " << str(false) << " >(" << result + << ");\n"; +} + +/* ************************************************************************* */ +void ReturnType::wrapTypeUnwrap(FileWriter& wrapperFile) const { + if (category == CLASS) + wrapperFile.oss << " typedef boost::shared_ptr<" << qualifiedName("::") + << "> Shared" << name << ";" << endl; +} + +/* ************************************************************************* */ + diff --git a/wrap/ReturnType.h b/wrap/ReturnType.h new file mode 100644 index 000000000..1829fbc81 --- /dev/null +++ b/wrap/ReturnType.h @@ -0,0 +1,67 @@ +/** + * @file ReturnValue.h + * @brief Encapsulates a return type of a method + * @date Nov 13, 2014 + * @author Frank Dellaert + */ + +#include "Qualified.h" +#include "FileWriter.h" +#include "TypeAttributesTable.h" +#include "utilities.h" + +#pragma once + +namespace wrap { + +/** + * Encapsulates return value of a method or function + */ +struct ReturnType: Qualified { + + /// the different supported return value categories + typedef enum { + CLASS = 1, EIGEN = 2, BASIS = 3, VOID = 4 + } return_category; + + bool isPtr; + return_category category; + + ReturnType() : + isPtr(false), category(CLASS) { + } + + ReturnType(const std::string& name) : + isPtr(false), category(CLASS) { + Qualified::name = name; + } + + void rename(const Qualified& q) { + name = q.name; + namespaces = q.namespaces; + } + + /// Check if this type is in a set of valid types + template + void verify(TYPES validtypes, const std::string& s) const { + std::string key = qualifiedName("::"); + if (find(validtypes.begin(), validtypes.end(), key) == validtypes.end()) + throw DependencyMissing(key, "checking return type of " + s); + } + +private: + + friend struct ReturnValue; + + std::string str(bool add_ptr) const; + + /// Example: out[1] = wrap_shared_ptr(pairResult.second,"Test", false); + void wrap_result(const std::string& out, const std::string& result, + FileWriter& wrapperFile, const TypeAttributesTable& typeAttributes) const; + + /// Creates typedef + void wrapTypeUnwrap(FileWriter& wrapperFile) const; + +}; + +} // \namespace wrap diff --git a/wrap/ReturnValue.cpp b/wrap/ReturnValue.cpp index a511652e8..993760e81 100644 --- a/wrap/ReturnValue.cpp +++ b/wrap/ReturnValue.cpp @@ -1,6 +1,5 @@ /** * @file ReturnValue.cpp - * * @date Dec 1, 2011 * @author Alex Cunningham * @author Andrew Melim @@ -15,62 +14,11 @@ using namespace std; using namespace wrap; -/* ************************************************************************* */ -string ReturnType::str(bool add_ptr) const { - return maybe_shared_ptr(add_ptr && isPtr, qualifiedName("::"), name); -} - -/* ************************************************************************* */ -void ReturnType::wrap_result(const string& out, const string& result, - FileWriter& file, const TypeAttributesTable& typeAttributes) const { - - string cppType = qualifiedName("::"), matlabType = qualifiedName("."); - - if (category == CLASS) { - string objCopy, ptrType; - ptrType = "Shared" + name; - const bool isVirtual = typeAttributes.at(cppType).isVirtual; - if (isVirtual) { - if (isPtr) - objCopy = result; - else - objCopy = result + ".clone()"; - } else { - if (isPtr) - objCopy = result; - else - objCopy = ptrType + "(new " + cppType + "(" + result + "))"; - } - file.oss << out << " = wrap_shared_ptr(" << objCopy << ",\"" << matlabType - << "\", " << (isVirtual ? "true" : "false") << ");\n"; - } else if (isPtr) { - file.oss << " Shared" << name << "* ret = new Shared" << name << "(" - << result << ");" << endl; - file.oss << out << " = wrap_shared_ptr(ret,\"" << matlabType << "\");\n"; - } else if (matlabType != "void") - file.oss << out << " = wrap< " << str(false) << " >(" << result << ");\n"; -} - -/* ************************************************************************* */ -void ReturnType::wrapTypeUnwrap(FileWriter& wrapperFile) const { - if (category == CLASS) - wrapperFile.oss << " typedef boost::shared_ptr<" << qualifiedName("::") - << "> Shared" << name << ";" << endl; -} - /* ************************************************************************* */ ReturnValue ReturnValue::expandTemplate(const TemplateSubstitution& ts) const { ReturnValue instRetVal = *this; - if (type1.name == ts.templateArg) { - instRetVal.type1.rename(ts.qualifiedType); - } else if (type1.name == "This") { - instRetVal.type1.rename(ts.expandedClass); - } - if (type2.name == ts.templateArg) { - instRetVal.type2.rename(ts.qualifiedType); - } else if (type2.name == "This") { - instRetVal.type2.rename(ts.expandedClass); - } + instRetVal.type1 = ts(type1); + if (isPair) instRetVal.type2 = ts(type2); return instRetVal; } diff --git a/wrap/ReturnValue.h b/wrap/ReturnValue.h index 55ebf8c57..e7206b494 100644 --- a/wrap/ReturnValue.h +++ b/wrap/ReturnValue.h @@ -2,12 +2,12 @@ * @file ReturnValue.h * * @brief Encapsulates a return value from a method - * * @date Dec 1, 2011 * @author Alex Cunningham * @author Richard Roberts */ +#include "ReturnType.h" #include "TemplateSubstitution.h" #include "FileWriter.h" #include "TypeAttributesTable.h" @@ -18,57 +18,7 @@ namespace wrap { /** - * Encapsulates return value of a method or function - */ -struct ReturnType: Qualified { - - /// the different supported return value categories - typedef enum { - CLASS = 1, EIGEN = 2, BASIS = 3, VOID = 4 - } return_category; - - bool isPtr; - return_category category; - - ReturnType() : - isPtr(false), category(CLASS) { - } - - ReturnType(const std::string& name) : - isPtr(false), category(CLASS) { - Qualified::name = name; - } - - void rename(const Qualified& q) { - name = q.name; - namespaces = q.namespaces; - } - - /// Check if this type is in a set of valid types - template - void verify(TYPES validtypes, const std::string& s) const { - std::string key = qualifiedName("::"); - if (find(validtypes.begin(), validtypes.end(), key) == validtypes.end()) - throw DependencyMissing(key, s); - } - -private: - - friend struct ReturnValue; - - std::string str(bool add_ptr) const; - - /// Example: out[1] = wrap_shared_ptr(pairResult.second,"Test", false); - void wrap_result(const std::string& out, const std::string& result, - FileWriter& file, const TypeAttributesTable& typeAttributes) const; - - /// Creates typedef - void wrapTypeUnwrap(FileWriter& wrapperFile) const; - -}; - -/** - * Encapsulates return value of a method or function, possibly a pair + * Encapsulates return type of a method or function, possibly a pair */ struct ReturnValue { diff --git a/wrap/TemplateSubstitution.h b/wrap/TemplateSubstitution.h index 5ce2f3a86..fd031024e 100644 --- a/wrap/TemplateSubstitution.h +++ b/wrap/TemplateSubstitution.h @@ -11,28 +11,61 @@ /** * @file TemplateSubstitution.h - * @brief Auxiliary class for template sunstitutions + * @brief Auxiliary class for template substitutions * @author Frank Dellaert * @date Nov 13, 2014 **/ #pragma once -#include "Qualified.h" +#include "ReturnType.h" #include +#include namespace wrap { /** * e.g. TemplateSubstitution("T", gtsam::Point2, gtsam::PriorFactorPoint2) */ -struct TemplateSubstitution { +class TemplateSubstitution { + + std::string templateArg_; + Qualified qualifiedType_, expandedClass_; + +public: + TemplateSubstitution(const std::string& a, const Qualified& t, const Qualified& e) : - templateArg(a), qualifiedType(t), expandedClass(e) { + templateArg_(a), qualifiedType_(t), expandedClass_(e) { } - std::string templateArg; - Qualified qualifiedType, expandedClass; + + // Substitute if needed + Qualified operator()(const Qualified& type) const { + if (type.name == templateArg_ && type.namespaces.empty()) + return qualifiedType_; + else if (type.name == "This") + return expandedClass_; + else + return type; + } + + // Substitute if needed + ReturnType operator()(const ReturnType& type) const { + ReturnType instType; + if (type.name == templateArg_ && type.namespaces.empty()) + instType.rename(qualifiedType_); + else if (type.name == "This") + instType.rename(expandedClass_); + return instType; + } + + friend std::ostream& operator<<(std::ostream& os, + const TemplateSubstitution& ts) { + os << ts.templateArg_ << '/' << ts.qualifiedType_.qualifiedName("::") + << " (" << ts.expandedClass_.qualifiedName("::") << ")"; + return os; + } + }; } // \namespace wrap From efd544527f3ba1684e61d854084b7b1da45134c8 Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 21:11:29 +0100 Subject: [PATCH 06/12] Stream operator for many classes --- wrap/Argument.h | 22 +++++++++++++++++++++- wrap/Class.cpp | 5 +++-- wrap/Class.h | 17 ++++++++++++++--- wrap/Function.h | 14 ++++++++++++++ wrap/Method.h | 6 ++++++ wrap/Qualified.h | 7 ++++++- wrap/ReturnValue.cpp | 3 ++- wrap/ReturnValue.h | 8 ++++++++ wrap/TemplateSubstitution.h | 2 +- 9 files changed, 75 insertions(+), 9 deletions(-) diff --git a/wrap/Argument.h b/wrap/Argument.h index 5a4f08a25..729792eb8 100644 --- a/wrap/Argument.h +++ b/wrap/Argument.h @@ -45,6 +45,13 @@ struct Argument { /// MATLAB code generation, MATLAB to C++ void matlab_unwrap(FileWriter& file, const std::string& matlabName) const; + + friend std::ostream& operator<<(std::ostream& os, const Argument& arg) { + os << (arg.is_const ? "const " : "") << arg.type << (arg.is_ptr ? "*" : "") + << (arg.is_ref ? "&" : ""); + return os; + } + }; /// Argument list is just a container with Arguments @@ -100,6 +107,19 @@ struct ArgumentList: public std::vector { void emit_conditional_call(FileWriter& proxyFile, const ReturnValue& returnVal, const std::string& wrapperName, int id, bool staticMethod = false) const; + + friend std::ostream& operator<<(std::ostream& os, + const ArgumentList& argList) { + os << "("; + if (argList.size() > 0) + os << argList.front(); + if (argList.size() > 1) + for (size_t i = 1; i < argList.size(); i++) + os << ", " << argList[i]; + os << ")"; + return os; + } + }; template @@ -108,7 +128,7 @@ inline void verifyArguments(const std::vector& validArgs, typedef typename std::map::value_type NamedMethod; BOOST_FOREACH(const NamedMethod& namedMethod, vt) { const T& t = namedMethod.second; - t.verifyArguments(validArgs,t.name_); + t.verifyArguments(validArgs, t.name_); } } diff --git a/wrap/Class.cpp b/wrap/Class.cpp index 5da9d8bd0..7ab618f0f 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -247,6 +247,7 @@ Class Class::expandTemplate(const TemplateSubstitution& ts) const { inst.constructor.args_list = inst.constructor.expandArgumentListsTemplate(ts); inst.constructor.name = inst.name; inst.deconstructor.name = inst.name; + cout << inst << endl; return inst; } @@ -254,10 +255,12 @@ Class Class::expandTemplate(const TemplateSubstitution& ts) const { vector Class::expandTemplate(Str templateArg, const vector& instantiations) const { vector result; + cout << *this << endl; BOOST_FOREACH(const Qualified& instName, instantiations) { Qualified expandedClass = (Qualified) (*this); expandedClass.name += instName.name; const TemplateSubstitution ts(templateArg, instName, expandedClass); + cout << ts << endl; Class inst = expandTemplate(ts); inst.name = expandedClass.name; inst.templateArgs.clear(); @@ -274,12 +277,10 @@ void Class::addMethod(bool verbose, bool is_const, Str methodName, Str templateArgName, const vector& templateArgValues) { // Check if templated if (!templateArgName.empty() && templateArgValues.size() > 0) { - cout << methodName << endl; // Create method to expand // For all values of the template argument, create a new method BOOST_FOREACH(const Qualified& instName, templateArgValues) { const TemplateSubstitution ts(templateArgName, instName, this->name); - cout << ts << endl; // substitute template in arguments ArgumentList expandedArgs = argumentList.expandTemplate(ts); // do the same for return type diff --git a/wrap/Class.h b/wrap/Class.h index 809f40049..2c2de49fc 100644 --- a/wrap/Class.h +++ b/wrap/Class.h @@ -19,15 +19,18 @@ #pragma once -#include -#include - #include "Constructor.h" #include "Deconstructor.h" #include "Method.h" #include "StaticMethod.h" #include "TypeAttributesTable.h" +#include +#include + +#include +#include + namespace wrap { /// Class has name, constructors, methods @@ -108,6 +111,14 @@ public: void deserialization_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, Str wrapperName, std::vector& functionNames) const; + friend std::ostream& operator<<(std::ostream& os, const Class& cls) { + os << "class " << cls.name << "{\n"; + BOOST_FOREACH(const Method& m, cls.methods | boost::adaptors::map_values) + os << m << ";\n"; + os << "};" << std::endl; + return os; + } + private: void pointer_constructor_fragments(FileWriter& proxyFile, diff --git a/wrap/Function.h b/wrap/Function.h index d175fe145..a06f35145 100644 --- a/wrap/Function.h +++ b/wrap/Function.h @@ -93,6 +93,13 @@ public: } } + friend std::ostream& operator<<(std::ostream& os, + const ArgumentOverloads& overloads) { + BOOST_FOREACH(const ArgumentList& argList, overloads.argLists_) + os << argList << std::endl; + return os; + } + }; /** @@ -168,6 +175,13 @@ public: } } + friend std::ostream& operator<<(std::ostream& os, + const SignatureOverloads& overloads) { + for (size_t i = 0; i < overloads.nrOverloads(); i++) + os << overloads.returnVals_[i] << overloads.argLists_[i] << std::endl; + return os; + } + }; // Templated checking functions diff --git a/wrap/Method.h b/wrap/Method.h index d1e382a13..be3e1c97f 100644 --- a/wrap/Method.h +++ b/wrap/Method.h @@ -41,6 +41,12 @@ struct Method: public StaticMethod { const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName = Qualified()); + friend std::ostream& operator<<(std::ostream& os, const Method& m) { + for (size_t i = 0; i < m.nrOverloads(); i++) + os << m.returnVals_[i] << " " << m.name_ << m.argLists_[i]; + return os; + } + private: // Emit method header diff --git a/wrap/Qualified.h b/wrap/Qualified.h index def2343cd..b23e9020d 100644 --- a/wrap/Qualified.h +++ b/wrap/Qualified.h @@ -45,7 +45,7 @@ struct Qualified { } bool operator!=(const Qualified& other) const { - return other.name!=name || other.namespaces != namespaces; + return other.name != name || other.namespaces != namespaces; } /// Return a qualified string using given delimiter @@ -66,6 +66,11 @@ struct Qualified { return result; } + friend std::ostream& operator<<(std::ostream& os, const Qualified& q) { + os << q.qualifiedName("::"); + return os; + } + }; } // \namespace wrap diff --git a/wrap/ReturnValue.cpp b/wrap/ReturnValue.cpp index 993760e81..54e585cad 100644 --- a/wrap/ReturnValue.cpp +++ b/wrap/ReturnValue.cpp @@ -18,7 +18,8 @@ using namespace wrap; ReturnValue ReturnValue::expandTemplate(const TemplateSubstitution& ts) const { ReturnValue instRetVal = *this; instRetVal.type1 = ts(type1); - if (isPair) instRetVal.type2 = ts(type2); + if (isPair) + instRetVal.type2 = ts(type2); return instRetVal; } diff --git a/wrap/ReturnValue.h b/wrap/ReturnValue.h index e7206b494..abfcec2b0 100644 --- a/wrap/ReturnValue.h +++ b/wrap/ReturnValue.h @@ -49,6 +49,14 @@ struct ReturnValue { void emit_matlab(FileWriter& proxyFile) const; + friend std::ostream& operator<<(std::ostream& os, const ReturnValue& r) { + if (!r.isPair && r.type1.category == ReturnType::VOID) + os << "void"; + else + os << r.return_type(true); + return os; + } + }; } // \namespace wrap diff --git a/wrap/TemplateSubstitution.h b/wrap/TemplateSubstitution.h index fd031024e..4e9b43f3d 100644 --- a/wrap/TemplateSubstitution.h +++ b/wrap/TemplateSubstitution.h @@ -51,7 +51,7 @@ public: // Substitute if needed ReturnType operator()(const ReturnType& type) const { - ReturnType instType; + ReturnType instType = type; if (type.name == templateArg_ && type.namespaces.empty()) instType.rename(qualifiedType_); else if (type.name == "This") From 09e3c7df9fb162cad91ccac3abc032d4364c701a Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 21:34:59 +0100 Subject: [PATCH 07/12] struct Constructor: public ArgumentOverloads --- wrap/Class.cpp | 20 +++++++------------- wrap/Class.h | 5 ++++- wrap/Constructor.cpp | 11 ----------- wrap/Constructor.h | 30 ++++++++++++++++++++++++------ wrap/Module.cpp | 2 +- wrap/StaticMethod.h | 6 ++++++ wrap/tests/testWrap.cpp | 8 ++++---- 7 files changed, 46 insertions(+), 36 deletions(-) diff --git a/wrap/Class.cpp b/wrap/Class.cpp index 7ab618f0f..316f65da2 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -73,13 +73,15 @@ void Class::matlab_proxy(Str toolboxPath, Str wrapperName, pointer_constructor_fragments(proxyFile, wrapperFile, wrapperName, functionNames); wrapperFile.oss << "\n"; + // Regular constructors - BOOST_FOREACH(ArgumentList a, constructor.args_list) { + for (size_t i = 0; i < constructor.nrOverloads(); i++) { + ArgumentList args = constructor.argumentList(i); const int id = (int) functionNames.size(); constructor.proxy_fragment(proxyFile, wrapperName, !qualifiedParent.empty(), - id, a); + id, args); const string wrapFunctionName = constructor.wrapper_fragment(wrapperFile, - cppName, matlabUniqueName, cppBaseName, id, a); + cppName, matlabUniqueName, cppBaseName, id, args); wrapperFile.oss << "\n"; functionNames.push_back(wrapFunctionName); } @@ -244,8 +246,7 @@ Class Class::expandTemplate(const TemplateSubstitution& ts) const { Class inst = *this; inst.methods = expandMethodTemplate(methods, ts); inst.static_methods = expandMethodTemplate(static_methods, ts); - inst.constructor.args_list = inst.constructor.expandArgumentListsTemplate(ts); - inst.constructor.name = inst.name; + inst.constructor = constructor.expandTemplate(ts); inst.deconstructor.name = inst.name; cout << inst << endl; return inst; @@ -374,19 +375,12 @@ string Class::getTypedef() const { } /* ************************************************************************* */ - void Class::comment_fragment(FileWriter& proxyFile) const { proxyFile.oss << "%class " << name << ", see Doxygen page for details\n"; proxyFile.oss << "%at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html\n"; - if (!constructor.args_list.empty()) - proxyFile.oss << "%\n%-------Constructors-------\n"; - BOOST_FOREACH(ArgumentList argList, constructor.args_list) { - proxyFile.oss << "%"; - argList.emit_prototype(proxyFile, name); - proxyFile.oss << "\n"; - } + constructor.comment_fragment(proxyFile); if (!methods.empty()) proxyFile.oss << "%\n%-------Methods-------\n"; diff --git a/wrap/Class.h b/wrap/Class.h index 2c2de49fc..6b9119316 100644 --- a/wrap/Class.h +++ b/wrap/Class.h @@ -112,7 +112,10 @@ public: Str wrapperName, std::vector& functionNames) const; friend std::ostream& operator<<(std::ostream& os, const Class& cls) { - os << "class " << cls.name << "{\n"; + os << "class " << cls.name << "{\n"; + os << cls.constructor << ";\n"; + BOOST_FOREACH(const StaticMethod& m, cls.static_methods | boost::adaptors::map_values) + os << m << ";\n"; BOOST_FOREACH(const Method& m, cls.methods | boost::adaptors::map_values) os << m << ";\n"; os << "};" << std::endl; diff --git a/wrap/Constructor.cpp b/wrap/Constructor.cpp index 98a689ced..fdbbf0e42 100644 --- a/wrap/Constructor.cpp +++ b/wrap/Constructor.cpp @@ -36,17 +36,6 @@ string Constructor::matlab_wrapper_name(const string& className) const { return str; } -/* ************************************************************************* */ -vector Constructor::expandArgumentListsTemplate( - const TemplateSubstitution& ts) const { - vector result; - BOOST_FOREACH(const ArgumentList& argList, args_list) { - ArgumentList instArgList = argList.expandTemplate(ts); - result.push_back(instArgList); - } - return result; -} - /* ************************************************************************* */ void Constructor::proxy_fragment(FileWriter& file, const std::string& wrapperName, bool hasParent, const int id, const ArgumentList args) const { diff --git a/wrap/Constructor.h b/wrap/Constructor.h index 40bca549a..fd9e0d32c 100644 --- a/wrap/Constructor.h +++ b/wrap/Constructor.h @@ -18,7 +18,7 @@ #pragma once -#include "Argument.h" +#include "Function.h" #include #include @@ -26,7 +26,7 @@ namespace wrap { // Constructor class -struct Constructor { +struct Constructor: public ArgumentOverloads { /// Constructor creates an empty class Constructor(bool verbose = false) : @@ -34,13 +34,15 @@ struct Constructor { } // Then the instance variables are set directly by the Module constructor - std::vector args_list; std::string name; bool verbose_; - // TODO eliminate copy/paste with function - std::vector expandArgumentListsTemplate( - const TemplateSubstitution& ts) const; + Constructor expandTemplate(const TemplateSubstitution& ts) const { + Constructor inst = *this; + inst.argLists_ = expandArgumentListsTemplate(ts); + inst.name = inst.name; + return inst; + } // MATLAB code generation // toolboxPath is main toolbox directory, e.g., ../matlab @@ -49,6 +51,16 @@ struct Constructor { /// wrapper name std::string matlab_wrapper_name(const std::string& className) const; + void comment_fragment(FileWriter& proxyFile) const { + if (nrOverloads() > 0) + proxyFile.oss << "%\n%-------Constructors-------\n"; + for (size_t i = 0; i < nrOverloads(); i++) { + proxyFile.oss << "%"; + argumentList(i).emit_prototype(proxyFile, name); + proxyFile.oss << "\n"; + } + } + /** * Create fragment to select constructor in proxy class, e.g., * if nargin == 2, obj.self = new_Pose3_RP(varargin{1},varargin{2}); end @@ -66,6 +78,12 @@ struct Constructor { void generate_construct(FileWriter& file, const std::string& cppClassName, std::vector& args_list) const; + friend std::ostream& operator<<(std::ostream& os, const Constructor& m) { + for (size_t i = 0; i < m.nrOverloads(); i++) + os << m.name << m.argLists_[i]; + return os; + } + }; } // \namespace wrap diff --git a/wrap/Module.cpp b/wrap/Module.cpp index f75e1d683..2fc8f92bc 100644 --- a/wrap/Module.cpp +++ b/wrap/Module.cpp @@ -217,7 +217,7 @@ void Module::parseMarkup(const std::string& data) { Constructor constructor0(verbose), constructor(verbose); Rule constructor_p = (className_p >> '(' >> argumentList_p >> ')' >> ';' >> !comments_p) - [push_back_a(constructor.args_list, args)] + [bl::bind(&Constructor::addOverload, bl::var(constructor), bl::var(args))] [clear_a(args)]; vector namespaces_return; /// namespace for current return type diff --git a/wrap/StaticMethod.h b/wrap/StaticMethod.h index cab440ef1..524dbb3ae 100644 --- a/wrap/StaticMethod.h +++ b/wrap/StaticMethod.h @@ -43,6 +43,12 @@ struct StaticMethod: public Function, public SignatureOverloads { Str wrapperName, const TypeAttributesTable& typeAttributes, std::vector& functionNames) const; + friend std::ostream& operator<<(std::ostream& os, const StaticMethod& m) { + for (size_t i = 0; i < m.nrOverloads(); i++) + os << "static " << m.returnVals_[i] << " " << m.name_ << m.argLists_[i]; + return os; + } + protected: virtual void proxy_header(FileWriter& proxyFile) const; diff --git a/wrap/tests/testWrap.cpp b/wrap/tests/testWrap.cpp index 02e618668..f26244772 100644 --- a/wrap/tests/testWrap.cpp +++ b/wrap/tests/testWrap.cpp @@ -184,7 +184,7 @@ TEST( wrap, Geometry ) { Class cls = module.classes.at(0); EXPECT(assert_equal("Point2", cls.name)); - EXPECT_LONGS_EQUAL(2, cls.constructor.args_list.size()); + EXPECT_LONGS_EQUAL(2, cls.constructor.nrOverloads()); EXPECT_LONGS_EQUAL(7, cls.nrMethods()); { @@ -229,13 +229,13 @@ TEST( wrap, Geometry ) { { Class cls = module.classes.at(1); EXPECT(assert_equal("Point3", cls.name)); - EXPECT_LONGS_EQUAL(1, cls.constructor.args_list.size()); + EXPECT_LONGS_EQUAL(1, cls.constructor.nrOverloads()); EXPECT_LONGS_EQUAL(1, cls.nrMethods()); EXPECT_LONGS_EQUAL(2, cls.static_methods.size()); EXPECT_LONGS_EQUAL(1, cls.namespaces.size()); // first constructor takes 3 doubles - ArgumentList c1 = cls.constructor.args_list.front(); + ArgumentList c1 = cls.constructor.argumentList(0); EXPECT_LONGS_EQUAL(3, c1.size()); // check first double argument @@ -266,7 +266,7 @@ TEST( wrap, Geometry ) { // Test class is the third one { Class testCls = module.classes.at(2); - EXPECT_LONGS_EQUAL( 2, testCls.constructor.args_list.size()); + EXPECT_LONGS_EQUAL( 2, testCls.constructor.nrOverloads()); EXPECT_LONGS_EQUAL(19, testCls.nrMethods()); EXPECT_LONGS_EQUAL( 0, testCls.static_methods.size()); EXPECT_LONGS_EQUAL( 0, testCls.namespaces.size()); From a4fe404d82d233193f5888b6f87468f41d7adc54 Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 21:53:33 +0100 Subject: [PATCH 08/12] Fixed constructor name in proxy --- wrap/Constructor.h | 2 +- wrap/TemplateSubstitution.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/wrap/Constructor.h b/wrap/Constructor.h index fd9e0d32c..adfcb8472 100644 --- a/wrap/Constructor.h +++ b/wrap/Constructor.h @@ -40,7 +40,7 @@ struct Constructor: public ArgumentOverloads { Constructor expandTemplate(const TemplateSubstitution& ts) const { Constructor inst = *this; inst.argLists_ = expandArgumentListsTemplate(ts); - inst.name = inst.name; + inst.name = ts.expandedClassName(); return inst; } diff --git a/wrap/TemplateSubstitution.h b/wrap/TemplateSubstitution.h index 4e9b43f3d..b20a1af6f 100644 --- a/wrap/TemplateSubstitution.h +++ b/wrap/TemplateSubstitution.h @@ -39,6 +39,10 @@ public: templateArg_(a), qualifiedType_(t), expandedClass_(e) { } + std::string expandedClassName() const { + return expandedClass_.name; + } + // Substitute if needed Qualified operator()(const Qualified& type) const { if (type.name == templateArg_ && type.namespaces.empty()) From 8ef78db9d86be040249ac2fab2721792e2a9845e Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 21:53:58 +0100 Subject: [PATCH 09/12] Fixed template expansion of classes --- wrap/Class.cpp | 3 --- wrap/Function.h | 11 +++-------- wrap/tests/expected2/geometry_wrapper.cpp | 2 ++ 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/wrap/Class.cpp b/wrap/Class.cpp index 316f65da2..f7f9ba7ee 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -248,7 +248,6 @@ Class Class::expandTemplate(const TemplateSubstitution& ts) const { inst.static_methods = expandMethodTemplate(static_methods, ts); inst.constructor = constructor.expandTemplate(ts); inst.deconstructor.name = inst.name; - cout << inst << endl; return inst; } @@ -256,12 +255,10 @@ Class Class::expandTemplate(const TemplateSubstitution& ts) const { vector Class::expandTemplate(Str templateArg, const vector& instantiations) const { vector result; - cout << *this << endl; BOOST_FOREACH(const Qualified& instName, instantiations) { Qualified expandedClass = (Qualified) (*this); expandedClass.name += instName.name; const TemplateSubstitution ts(templateArg, instName, expandedClass); - cout << ts << endl; Class inst = expandTemplate(ts); inst.name = expandedClass.name; inst.templateArgs.clear(); diff --git a/wrap/Function.h b/wrap/Function.h index a06f35145..3af7b38fc 100644 --- a/wrap/Function.h +++ b/wrap/Function.h @@ -187,13 +187,6 @@ public: // Templated checking functions // TODO: do this via polymorphism ? -template -F expandMethodTemplate(F& method, const TemplateSubstitution& ts) { - F instMethod = method; - method.expandTemplate(ts); - return instMethod; -} - // TODO use transform template static std::map expandMethodTemplate( @@ -201,7 +194,9 @@ static std::map expandMethodTemplate( std::map result; typedef std::pair NamedMethod; BOOST_FOREACH(NamedMethod namedMethod, methods) { - namedMethod.second = expandMethodTemplate(namedMethod.second, ts); + F instMethod = namedMethod.second; + instMethod.expandTemplate(ts); + namedMethod.second = instMethod; result.insert(namedMethod); } return result; diff --git a/wrap/tests/expected2/geometry_wrapper.cpp b/wrap/tests/expected2/geometry_wrapper.cpp index 61b58b16b..ab6ae5aa7 100644 --- a/wrap/tests/expected2/geometry_wrapper.cpp +++ b/wrap/tests/expected2/geometry_wrapper.cpp @@ -672,6 +672,7 @@ void MyTemplatePoint2_templatedMethod_54(int nargout, mxArray *out[], int nargin gtsam::Point2& t = *unwrap_shared_ptr< gtsam::Point2 >(in[1], "ptr_gtsamPoint2"); obj->templatedMethod(t); } + void MyTemplatePoint2_templatedMethod_55(int nargout, mxArray *out[], int nargin, const mxArray *in[]) { typedef boost::shared_ptr Shared; @@ -815,6 +816,7 @@ void MyTemplatePoint3_templatedMethod_67(int nargout, mxArray *out[], int nargin gtsam::Point2& t = *unwrap_shared_ptr< gtsam::Point2 >(in[1], "ptr_gtsamPoint2"); obj->templatedMethod(t); } + void MyTemplatePoint3_templatedMethod_68(int nargout, mxArray *out[], int nargin, const mxArray *in[]) { typedef boost::shared_ptr Shared; From 8a05136ca087ca291fd08242ac71dbcfd3f224b8 Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 22:15:36 +0100 Subject: [PATCH 10/12] Fixed proxy wrapper name --- wrap/StaticMethod.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/wrap/StaticMethod.cpp b/wrap/StaticMethod.cpp index 4d3a9acde..67c52906c 100644 --- a/wrap/StaticMethod.cpp +++ b/wrap/StaticMethod.cpp @@ -83,11 +83,8 @@ void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, // Output proxy matlab code proxyFile.oss << " " << (i == 0 ? "" : "else"); const int id = (int) functionNames.size(); - string expanded = wrapperName; - if (!templateArgValue_.empty()) - expanded += templateArgValue_.name; - argumentList(i).emit_conditional_call(proxyFile, returnValue(i), expanded, - id); + argumentList(i).emit_conditional_call(proxyFile, returnValue(i), + wrapperName, id); // Output C++ wrapper code const string wrapFunctionName = wrapper_fragment(wrapperFile, From e07da1c82dea3db1a7bf7e2c7780c2a93eea9822 Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 22:43:29 +0100 Subject: [PATCH 11/12] Added matlabName, and made data members private --- wrap/Argument.h | 6 ++---- wrap/Class.cpp | 12 ++++-------- wrap/Function.h | 29 +++++++++++++++++++++-------- wrap/GlobalFunction.h | 8 ++++++++ wrap/Method.cpp | 2 +- wrap/StaticMethod.cpp | 3 ++- wrap/StaticMethod.h | 13 +++++++++++++ wrap/tests/testWrap.cpp | 18 +++++++++--------- 8 files changed, 60 insertions(+), 31 deletions(-) diff --git a/wrap/Argument.h b/wrap/Argument.h index 729792eb8..02f104418 100644 --- a/wrap/Argument.h +++ b/wrap/Argument.h @@ -126,10 +126,8 @@ template inline void verifyArguments(const std::vector& validArgs, const std::map& vt) { typedef typename std::map::value_type NamedMethod; - BOOST_FOREACH(const NamedMethod& namedMethod, vt) { - const T& t = namedMethod.second; - t.verifyArguments(validArgs, t.name_); - } + BOOST_FOREACH(const NamedMethod& namedMethod, vt) + namedMethod.second.verifyArguments(validArgs); } } // \namespace wrap diff --git a/wrap/Class.cpp b/wrap/Class.cpp index f7f9ba7ee..3a3432eb3 100644 --- a/wrap/Class.cpp +++ b/wrap/Class.cpp @@ -381,17 +381,13 @@ void Class::comment_fragment(FileWriter& proxyFile) const { if (!methods.empty()) proxyFile.oss << "%\n%-------Methods-------\n"; - BOOST_FOREACH(const Methods::value_type& name_m, methods) { - const Method& m = name_m.second; - m.comment_fragment(proxyFile, m.name_); - } + BOOST_FOREACH(const Methods::value_type& name_m, methods) + name_m.second.comment_fragment(proxyFile); if (!static_methods.empty()) proxyFile.oss << "%\n%-------Static Methods-------\n"; - BOOST_FOREACH(const StaticMethods::value_type& name_m, static_methods) { - const StaticMethod& m = name_m.second; - m.comment_fragment(proxyFile, m.name_); - } + BOOST_FOREACH(const StaticMethods::value_type& name_m, static_methods) + name_m.second.comment_fragment(proxyFile); if (hasSerialization) { proxyFile.oss << "%\n%-------Serialization Interface-------\n"; diff --git a/wrap/Function.h b/wrap/Function.h index 3af7b38fc..1d40fcbea 100644 --- a/wrap/Function.h +++ b/wrap/Function.h @@ -28,7 +28,15 @@ namespace wrap { /// Function class -struct Function { +class Function { + +protected: + + bool verbose_; + std::string name_; ///< name of method + Qualified templateArgValue_; ///< value of template argument if applicable + +public: /// Constructor creates empty object Function(bool verbose = true) : @@ -39,9 +47,16 @@ struct Function { verbose_(verbose), name_(name) { } - bool verbose_; - std::string name_; ///< name of method - Qualified templateArgValue_; ///< value of template argument if applicable + std::string name() const { + return name_; + } + + std::string matlabName() const { + if (templateArgValue_.empty()) + return name_; + else + return name_ + templateArgValue_.name; + } // The first time this function is called, it initializes the class members // with those in rhs, but in subsequent calls it adds additional argument @@ -205,10 +220,8 @@ template inline void verifyReturnTypes(const std::vector& validTypes, const std::map& vt) { typedef typename std::map::value_type NamedMethod; - BOOST_FOREACH(const NamedMethod& namedMethod, vt) { - const F& t = namedMethod.second; - t.verifyReturnTypes(validTypes, t.name_); - } + BOOST_FOREACH(const NamedMethod& namedMethod, vt) + namedMethod.second.verifyReturnTypes(validTypes); } } // \namespace wrap diff --git a/wrap/GlobalFunction.h b/wrap/GlobalFunction.h index 6f8686925..18bb91995 100644 --- a/wrap/GlobalFunction.h +++ b/wrap/GlobalFunction.h @@ -27,6 +27,14 @@ struct GlobalFunction: public Function, public SignatureOverloads { Function(name,verbose) { } + void verifyArguments(const std::vector& validArgs) const { + SignatureOverloads::verifyArguments(validArgs, name_); + } + + void verifyReturnTypes(const std::vector& validtypes) const { + SignatureOverloads::verifyReturnTypes(validtypes, name_); + } + // adds an overloaded version of this function, void addOverload(bool verbose, const Qualified& overload, const ArgumentList& args, const ReturnValue& retVal, diff --git a/wrap/Method.cpp b/wrap/Method.cpp index 19e302e2a..a7072c9e7 100644 --- a/wrap/Method.cpp +++ b/wrap/Method.cpp @@ -39,7 +39,7 @@ void Method::addOverload(bool verbose, bool is_const, Str name, /* ************************************************************************* */ void Method::proxy_header(FileWriter& proxyFile) const { - proxyFile.oss << " function varargout = " << name_ << "(this, varargin)\n"; + proxyFile.oss << " function varargout = " << matlabName() << "(this, varargin)\n"; } /* ************************************************************************* */ diff --git a/wrap/StaticMethod.cpp b/wrap/StaticMethod.cpp index 67c52906c..d6b3f94f6 100644 --- a/wrap/StaticMethod.cpp +++ b/wrap/StaticMethod.cpp @@ -39,7 +39,7 @@ void StaticMethod::addOverload(bool verbose, Str name, const ArgumentList& args, /* ************************************************************************* */ void StaticMethod::proxy_header(FileWriter& proxyFile) const { - string upperName = name_; + string upperName = matlabName(); upperName[0] = toupper(upperName[0], locale()); proxyFile.oss << " function varargout = " << upperName << "(varargin)\n"; } @@ -51,6 +51,7 @@ void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, const TypeAttributesTable& typeAttributes, vector& functionNames) const { + // emit header, e.g., function varargout = templatedMethod(this, varargin) proxy_header(proxyFile); // Emit comments for documentation diff --git a/wrap/StaticMethod.h b/wrap/StaticMethod.h index 524dbb3ae..672dd0e70 100644 --- a/wrap/StaticMethod.h +++ b/wrap/StaticMethod.h @@ -36,6 +36,19 @@ struct StaticMethod: public Function, public SignatureOverloads { void addOverload(bool verbose, Str name, const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName); + // emit a list of comments, one for each overload + void comment_fragment(FileWriter& proxyFile) const { + SignatureOverloads::comment_fragment(proxyFile, name_); + } + + void verifyArguments(const std::vector& validArgs) const { + SignatureOverloads::verifyArguments(validArgs, name_); + } + + void verifyReturnTypes(const std::vector& validtypes) const { + SignatureOverloads::verifyReturnTypes(validtypes, name_); + } + // MATLAB code generation // classPath is class directory, e.g., ../matlab/@Point2 void proxy_wrapper_fragments(FileWriter& proxyFile, FileWriter& wrapperFile, diff --git a/wrap/tests/testWrap.cpp b/wrap/tests/testWrap.cpp index f26244772..8268c9a8a 100644 --- a/wrap/tests/testWrap.cpp +++ b/wrap/tests/testWrap.cpp @@ -97,7 +97,7 @@ TEST( wrap, Small ) { // Method 1 Method m1 = cls.method("x"); - EXPECT(assert_equal("x", m1.name_)); + EXPECT(assert_equal("x", m1.name())); EXPECT(m1.is_const_); LONGS_EQUAL(1, m1.nrOverloads()); @@ -109,7 +109,7 @@ TEST( wrap, Small ) { // Method 2 Method m2 = cls.method("returnMatrix"); - EXPECT(assert_equal("returnMatrix", m2.name_)); + EXPECT(assert_equal("returnMatrix", m2.name())); EXPECT(m2.is_const_); LONGS_EQUAL(1, m2.nrOverloads()); @@ -121,7 +121,7 @@ TEST( wrap, Small ) { // Method 3 Method m3 = cls.method("returnPoint2"); - EXPECT(assert_equal("returnPoint2", m3.name_)); + EXPECT(assert_equal("returnPoint2", m3.name())); EXPECT(m3.is_const_); LONGS_EQUAL(1, m3.nrOverloads()); @@ -134,7 +134,7 @@ TEST( wrap, Small ) { // Static Method 1 // static Vector returnVector(); StaticMethod sm1 = cls.static_methods.at("returnVector"); - EXPECT(assert_equal("returnVector", sm1.name_)); + EXPECT(assert_equal("returnVector", sm1.name())); LONGS_EQUAL(1, sm1.nrOverloads()); ReturnValue rv4 = sm1.returnValue(0); @@ -195,7 +195,7 @@ TEST( wrap, Geometry ) { EXPECT(assert_equal("char", m1.returnValue(0).type1.name)); EXPECT_LONGS_EQUAL(ReturnType::BASIS, m1.returnValue(0).type1.category); EXPECT(!m1.returnValue(0).isPair); - EXPECT(assert_equal("returnChar", m1.name_)); + EXPECT(assert_equal("returnChar", m1.name())); LONGS_EQUAL(1, m1.nrOverloads()); EXPECT_LONGS_EQUAL(0, m1.argumentList(0).size()); EXPECT(m1.is_const_); @@ -209,7 +209,7 @@ TEST( wrap, Geometry ) { EXPECT(assert_equal("VectorNotEigen", m1.returnValue(0).type1.name)); EXPECT_LONGS_EQUAL(ReturnType::CLASS, m1.returnValue(0).type1.category); EXPECT(!m1.returnValue(0).isPair); - EXPECT(assert_equal("vectorConfusion", m1.name_)); + EXPECT(assert_equal("vectorConfusion", m1.name())); LONGS_EQUAL(1, m1.nrOverloads()); EXPECT_LONGS_EQUAL(0, m1.argumentList(0).size()); EXPECT(!m1.is_const_); @@ -251,7 +251,7 @@ TEST( wrap, Geometry ) { LONGS_EQUAL(1, m1.nrOverloads()); EXPECT(assert_equal("double", m1.returnValue(0).type1.name)); EXPECT_LONGS_EQUAL(ReturnType::BASIS, m1.returnValue(0).type1.category); - EXPECT(assert_equal("norm", m1.name_)); + EXPECT(assert_equal("norm", m1.name())); LONGS_EQUAL(1, m1.nrOverloads()); EXPECT_LONGS_EQUAL(0, m1.argumentList(0).size()); EXPECT(m1.is_const_); @@ -312,7 +312,7 @@ TEST( wrap, Geometry ) { CHECK(module.global_functions.find("aGlobalFunction") != module.global_functions.end()); { GlobalFunction gfunc = module.global_functions.at("aGlobalFunction"); - EXPECT(assert_equal("aGlobalFunction", gfunc.name_)); + EXPECT(assert_equal("aGlobalFunction", gfunc.name())); LONGS_EQUAL(1, gfunc.nrOverloads()); EXPECT(assert_equal("Vector", gfunc.returnValue(0).type1.name)); EXPECT_LONGS_EQUAL(1, gfunc.nrOverloads()); @@ -386,7 +386,7 @@ TEST( wrap, parse_namespaces ) { CHECK(module.global_functions.find("aGlobalFunction") != module.global_functions.end()); { GlobalFunction gfunc = module.global_functions.at("aGlobalFunction"); - EXPECT(assert_equal("aGlobalFunction", gfunc.name_)); + EXPECT(assert_equal("aGlobalFunction", gfunc.name())); LONGS_EQUAL(2, gfunc.nrOverloads()); EXPECT(assert_equal("Vector", gfunc.returnValue(0).type1.name)); From 67bc951ac2851437f5777b7d0f3f09eb39b55ad9 Mon Sep 17 00:00:00 2001 From: dellaert Date: Thu, 13 Nov 2014 23:21:05 +0100 Subject: [PATCH 12/12] Fixed proxy files and calls for static methods --- wrap/Method.h | 14 ++++++++++++-- wrap/StaticMethod.cpp | 10 ++++++---- wrap/StaticMethod.h | 4 ++++ wrap/tests/expected2/+gtsam/Point3.m | 18 ++---------------- wrap/tests/expected2/MyTemplatePoint2.m | 18 +++++++++++------- wrap/tests/expected2/MyTemplatePoint3.m | 18 +++++++++++------- wrap/tests/expected_namespaces/+ns2/ClassA.m | 2 +- wrap/tests/testWrap.cpp | 12 ++++++------ 8 files changed, 53 insertions(+), 43 deletions(-) diff --git a/wrap/Method.h b/wrap/Method.h index be3e1c97f..d097cc322 100644 --- a/wrap/Method.h +++ b/wrap/Method.h @@ -23,7 +23,11 @@ namespace wrap { /// Method class -struct Method: public StaticMethod { +class Method: public StaticMethod { + + bool is_const_; + +public: typedef const std::string& Str; @@ -32,7 +36,13 @@ struct Method: public StaticMethod { StaticMethod(verbose), is_const_(false) { } - bool is_const_; + virtual bool isStatic() const { + return false; + } + + virtual bool isConst() const { + return is_const_; + } // The first time this function is called, it initializes the class members // with those in rhs, but in subsequent calls it adds additional argument diff --git a/wrap/StaticMethod.cpp b/wrap/StaticMethod.cpp index d6b3f94f6..d3bd75628 100644 --- a/wrap/StaticMethod.cpp +++ b/wrap/StaticMethod.cpp @@ -55,9 +55,9 @@ void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, proxy_header(proxyFile); // Emit comments for documentation - string up_name = boost::to_upper_copy(name_); + string up_name = boost::to_upper_copy(matlabName()); proxyFile.oss << " % " << up_name << " usage: "; - usage_fragment(proxyFile, name_); + usage_fragment(proxyFile, matlabName()); // Emit URL to Doxygen page proxyFile.oss << " % " @@ -67,9 +67,11 @@ void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, // Handle special case of single overload with all numeric arguments if (nrOverloads() == 1 && argumentList(0).allScalar()) { // Output proxy matlab code + // TODO: document why is it OK to not check arguments in this case proxyFile.oss << " "; const int id = (int) functionNames.size(); - argumentList(0).emit_call(proxyFile, returnValue(0), wrapperName, id); + argumentList(0).emit_call(proxyFile, returnValue(0), wrapperName, id, + isStatic()); // Output C++ wrapper code const string wrapFunctionName = wrapper_fragment(wrapperFile, cppClassName, @@ -85,7 +87,7 @@ void StaticMethod::proxy_wrapper_fragments(FileWriter& proxyFile, proxyFile.oss << " " << (i == 0 ? "" : "else"); const int id = (int) functionNames.size(); argumentList(i).emit_conditional_call(proxyFile, returnValue(i), - wrapperName, id); + wrapperName, id, isStatic()); // Output C++ wrapper code const string wrapFunctionName = wrapper_fragment(wrapperFile, diff --git a/wrap/StaticMethod.h b/wrap/StaticMethod.h index 672dd0e70..af5cbce59 100644 --- a/wrap/StaticMethod.h +++ b/wrap/StaticMethod.h @@ -33,6 +33,10 @@ struct StaticMethod: public Function, public SignatureOverloads { Function(verbosity) { } + virtual bool isStatic() const { + return true; + } + void addOverload(bool verbose, Str name, const ArgumentList& args, const ReturnValue& retVal, const Qualified& instName); diff --git a/wrap/tests/expected2/+gtsam/Point3.m b/wrap/tests/expected2/+gtsam/Point3.m index d445c78ef..3ef336ff1 100644 --- a/wrap/tests/expected2/+gtsam/Point3.m +++ b/wrap/tests/expected2/+gtsam/Point3.m @@ -48,27 +48,13 @@ classdef Point3 < handle function varargout = StaticFunctionRet(varargin) % STATICFUNCTIONRET usage: StaticFunctionRet(double z) : returns gtsam::Point3 % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html - % - % Usage - % STATICFUNCTIONRET(double z) - if length(varargin) == 1 && isa(varargin{1},'double') - varargout{1} = geometry_wrapper(15, varargin{:}); - else - error('Arguments do not match any overload of function gtsam.Point3.StaticFunctionRet'); - end + varargout{1} = geometry_wrapper(15, varargin{:}); end function varargout = StaticFunction(varargin) % STATICFUNCTION usage: staticFunction() : returns double % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html - % - % Usage - % STATICFUNCTION() - if length(varargin) == 0 - varargout{1} = geometry_wrapper(16, varargin{:}); - else - error('Arguments do not match any overload of function gtsam.Point3.StaticFunction'); - end + varargout{1} = geometry_wrapper(16, varargin{:}); end end diff --git a/wrap/tests/expected2/MyTemplatePoint2.m b/wrap/tests/expected2/MyTemplatePoint2.m index d06595f9b..57a7bfd66 100644 --- a/wrap/tests/expected2/MyTemplatePoint2.m +++ b/wrap/tests/expected2/MyTemplatePoint2.m @@ -107,16 +107,20 @@ classdef MyTemplatePoint2 < MyBase end end - function varargout = templatedMethod(this, varargin) - % TEMPLATEDMETHOD usage: templatedMethod(Point2 t), templatedMethod(Point3 t) : returns void + function varargout = templatedMethodPoint2(this, varargin) + % TEMPLATEDMETHODPOINT2 usage: templatedMethodPoint2(Point2 t) : returns void % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html - % - % Method Overloads - % templatedMethod(Point2 t) - % templatedMethod(Point3 t) if length(varargin) == 1 && isa(varargin{1},'gtsam.Point2') geometry_wrapper(54, this, varargin{:}); - elseif length(varargin) == 1 && isa(varargin{1},'gtsam.Point3') + else + error('Arguments do not match any overload of function MyTemplatePoint2.templatedMethod'); + end + end + + function varargout = templatedMethodPoint3(this, varargin) + % TEMPLATEDMETHODPOINT3 usage: templatedMethodPoint3(Point3 t) : returns void + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + if length(varargin) == 1 && isa(varargin{1},'gtsam.Point3') geometry_wrapper(55, this, varargin{:}); else error('Arguments do not match any overload of function MyTemplatePoint2.templatedMethod'); diff --git a/wrap/tests/expected2/MyTemplatePoint3.m b/wrap/tests/expected2/MyTemplatePoint3.m index 500316769..a585bee6e 100644 --- a/wrap/tests/expected2/MyTemplatePoint3.m +++ b/wrap/tests/expected2/MyTemplatePoint3.m @@ -107,16 +107,20 @@ classdef MyTemplatePoint3 < MyBase end end - function varargout = templatedMethod(this, varargin) - % TEMPLATEDMETHOD usage: templatedMethod(Point2 t), templatedMethod(Point3 t) : returns void + function varargout = templatedMethodPoint2(this, varargin) + % TEMPLATEDMETHODPOINT2 usage: templatedMethodPoint2(Point2 t) : returns void % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html - % - % Method Overloads - % templatedMethod(Point2 t) - % templatedMethod(Point3 t) if length(varargin) == 1 && isa(varargin{1},'gtsam.Point2') geometry_wrapper(67, this, varargin{:}); - elseif length(varargin) == 1 && isa(varargin{1},'gtsam.Point3') + else + error('Arguments do not match any overload of function MyTemplatePoint3.templatedMethod'); + end + end + + function varargout = templatedMethodPoint3(this, varargin) + % TEMPLATEDMETHODPOINT3 usage: templatedMethodPoint3(Point3 t) : returns void + % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html + if length(varargin) == 1 && isa(varargin{1},'gtsam.Point3') geometry_wrapper(68, this, varargin{:}); else error('Arguments do not match any overload of function MyTemplatePoint3.templatedMethod'); diff --git a/wrap/tests/expected_namespaces/+ns2/ClassA.m b/wrap/tests/expected_namespaces/+ns2/ClassA.m index 9f0055af9..14095899c 100644 --- a/wrap/tests/expected_namespaces/+ns2/ClassA.m +++ b/wrap/tests/expected_namespaces/+ns2/ClassA.m @@ -65,7 +65,7 @@ classdef ClassA < handle function varargout = Afunction(varargin) % AFUNCTION usage: afunction() : returns double % Doxygen can be found at http://research.cc.gatech.edu/borg/sites/edu.borg/html/index.html - varargout{1} = testNamespaces_wrapper(12, this, varargin{:}); + varargout{1} = testNamespaces_wrapper(12, varargin{:}); end end diff --git a/wrap/tests/testWrap.cpp b/wrap/tests/testWrap.cpp index 8268c9a8a..8fe862182 100644 --- a/wrap/tests/testWrap.cpp +++ b/wrap/tests/testWrap.cpp @@ -98,7 +98,7 @@ TEST( wrap, Small ) { // Method 1 Method m1 = cls.method("x"); EXPECT(assert_equal("x", m1.name())); - EXPECT(m1.is_const_); + EXPECT(m1.isConst()); LONGS_EQUAL(1, m1.nrOverloads()); ReturnValue rv1 = m1.returnValue(0); @@ -110,7 +110,7 @@ TEST( wrap, Small ) { // Method 2 Method m2 = cls.method("returnMatrix"); EXPECT(assert_equal("returnMatrix", m2.name())); - EXPECT(m2.is_const_); + EXPECT(m2.isConst()); LONGS_EQUAL(1, m2.nrOverloads()); ReturnValue rv2 = m2.returnValue(0); @@ -122,7 +122,7 @@ TEST( wrap, Small ) { // Method 3 Method m3 = cls.method("returnPoint2"); EXPECT(assert_equal("returnPoint2", m3.name())); - EXPECT(m3.is_const_); + EXPECT(m3.isConst()); LONGS_EQUAL(1, m3.nrOverloads()); ReturnValue rv3 = m3.returnValue(0); @@ -198,7 +198,7 @@ TEST( wrap, Geometry ) { EXPECT(assert_equal("returnChar", m1.name())); LONGS_EQUAL(1, m1.nrOverloads()); EXPECT_LONGS_EQUAL(0, m1.argumentList(0).size()); - EXPECT(m1.is_const_); + EXPECT(m1.isConst()); } { @@ -212,7 +212,7 @@ TEST( wrap, Geometry ) { EXPECT(assert_equal("vectorConfusion", m1.name())); LONGS_EQUAL(1, m1.nrOverloads()); EXPECT_LONGS_EQUAL(0, m1.argumentList(0).size()); - EXPECT(!m1.is_const_); + EXPECT(!m1.isConst()); } EXPECT_LONGS_EQUAL(0, cls.static_methods.size()); @@ -254,7 +254,7 @@ TEST( wrap, Geometry ) { EXPECT(assert_equal("norm", m1.name())); LONGS_EQUAL(1, m1.nrOverloads()); EXPECT_LONGS_EQUAL(0, m1.argumentList(0).size()); - EXPECT(m1.is_const_); + EXPECT(m1.isConst()); #ifndef WRAP_DISABLE_SERIALIZE // check serialization flag