emit methods to pxd, change the way template methods are handled

pxd allows template methods, whereas the current scheme instantiates/expands all template methods and add them to the same methods_ container. The new scheme treats them all separately: nontemplated methods in methods_, template methods in templateMethods_, and template methods after instantiation in expandedTemplateMethods_.
release/4.3a0
Duy-Nguyen Ta 2016-09-09 07:26:11 -04:00
parent 6e96e095f3
commit 40da298f68
6 changed files with 170 additions and 18 deletions

View File

@ -23,6 +23,7 @@
#include <boost/lexical_cast.hpp>
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
#include <boost/range/join.hpp>
#include <vector>
#include <iostream>
@ -70,9 +71,13 @@ static void handleException(const out_of_range& oor,
/* ************************************************************************* */
const Method& Class::method(Str key) const {
try {
return methods_.at(key);
if (methods_.find(key) != methods_.end())
return methods_.at(key);
else
return expandedTemplateMethods_.at(key);
} catch (const out_of_range& oor) {
handleException(oor, methods_);
handleException(oor, expandedTemplateMethods_);
throw runtime_error("Internal error in wrap");
}
}
@ -156,7 +161,7 @@ void Class::matlab_proxy(Str toolboxPath, Str wrapperName,
<< " function disp(obj), obj.display; end\n %DISP Calls print on the object\n";
// Methods
for(const Methods::value_type& name_m: methods_) {
for(const Methods::value_type& name_m: boost::join(methods_, expandedTemplateMethods_)) {
const Method& m = name_m.second;
m.proxy_wrapper_fragments(proxyFile, wrapperFile, cppName, matlabQualName,
matlabUniqueName, wrapperName, typeAttributes, functionNames);
@ -339,9 +344,13 @@ void Class::addMethod(bool verbose, bool is_const, Str methodName,
const Template& tmplate) {
// Check if templated
if (tmplate.valid()) {
// Create method to expand
// For all values of the template argument, create a new method
templateMethods_[methodName].addOverload(methodName, argumentList,
returnValue, is_const,
tmplate.argName(), verbose);
// Create method to expand
// For all values of the template argument, create a new method
for(const Qualified& instName: tmplate.argValues()) {
const TemplateSubstitution ts(tmplate.argName(), instName, *this);
// substitute template in arguments
ArgumentList expandedArgs = argumentList.expandTemplate(ts);
@ -350,7 +359,7 @@ void Class::addMethod(bool verbose, bool is_const, Str methodName,
// 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(methodName, expandedArgs,
expandedTemplateMethods_[expandedMethodName].addOverload(methodName, expandedArgs,
expandedRetVal, is_const, instName, verbose);
}
} else
@ -392,10 +401,12 @@ void Class::verifyAll(vector<string>& validTypes, bool& hasSerialiable) const {
//TODO:verifyArguments<ArgumentList>(validTypes, constructor.args_list);
verifyArguments<StaticMethod>(validTypes, static_methods);
verifyArguments<Method>(validTypes, methods_);
verifyArguments<Method>(validTypes, expandedTemplateMethods_);
// verify function return types
verifyReturnTypes<StaticMethod>(validTypes, static_methods);
verifyReturnTypes<Method>(validTypes, methods_);
verifyReturnTypes<Method>(validTypes, expandedTemplateMethods_);
// verify parents
boost::optional<string> parent = qualifiedParent();
@ -416,6 +427,8 @@ void Class::appendInheritedMethods(const Class& cls,
// We found a parent class for our parent, TODO improve !
if (parent.name() == cls.parentClass->name()) {
methods_.insert(parent.methods_.begin(), parent.methods_.end());
expandedTemplateMethods_.insert(parent.expandedTemplateMethods_.begin(),
parent.expandedTemplateMethods_.end());
appendInheritedMethods(parent, classes);
}
}
@ -443,9 +456,9 @@ void Class::comment_fragment(FileWriter& proxyFile) const {
constructor.comment_fragment(proxyFile);
if (!methods_.empty())
if (!methods_.empty() || !expandedTemplateMethods_.empty())
proxyFile.oss << "%\n%-------Methods-------\n";
for(const Methods::value_type& name_m: methods_)
for(const Methods::value_type& name_m: boost::join(methods_, expandedTemplateMethods_))
name_m.second.comment_fragment(proxyFile);
if (!static_methods.empty())
@ -656,31 +669,52 @@ void Class::python_wrapper(FileWriter& wrapperFile) const {
m.python_wrapper(wrapperFile, name());
for(const Method& m: methods_ | boost::adaptors::map_values)
m.python_wrapper(wrapperFile, name());
for(const Method& m: expandedTemplateMethods_ | boost::adaptors::map_values)
m.python_wrapper(wrapperFile, name());
wrapperFile.oss << ";\n\n";
}
/* ************************************************************************* */
void Class::cython_wrapper(FileWriter& pxdFile, FileWriter& pyxFile) const {
string cythonClassName = qualifiedName("_");
pxdFile.oss << "cdef extern from \"" << includeFile << "\" namespace \""
<< qualifiedNamespaces("::") << "\":" << endl;
pxdFile.oss << "\tcdef cppclass " << qualifiedName("_") << " \"" << qualifiedName("::") << "\"";
pxdFile.oss << "\tcdef cppclass " << cythonClassName << " \"" << qualifiedName("::") << "\"";
if (templateArgs.size()>0) {
pxdFile.oss << "[";
for(size_t i = 0; i<templateArgs.size(); ++i) {
pxdFile.oss << templateArgs[i];
if (i<templateArgs.size()-1) pxdFile.oss << ",";
}
pxdFile.oss << "]";
}
if (parentClass) pxdFile.oss << "(" << parentClass->qualifiedName("_") << ")";
pxdFile.oss << ":\n";
pyxFile.oss << "cdef class " << name();
if (parentClass) pyxFile.oss << "(" << parentClass->name() << ")";
pyxFile.oss << ":\n";
pyxFile.oss << "\tcdef shared_ptr[" << qualifiedName("_") << "] "
pyxFile.oss << "\tcdef shared_ptr[" << cythonClassName << "] "
<< "gt" << name() << "_\n";
constructor.cython_wrapper(pxdFile, pyxFile, qualifiedName("_"));
pxdFile.oss << "\n";
constructor.cython_wrapper(pxdFile, pyxFile, cythonClassName);
if (constructor.nrOverloads()>0) pxdFile.oss << "\n";
for(const StaticMethod& m: static_methods | boost::adaptors::map_values)
m.emit_cython_pxd(pxdFile);
if (static_methods.size()>0) pxdFile.oss << "\n";
for(const Method& m: methods_ | boost::adaptors::map_values)
m.emit_cython_pxd(pxdFile);
for(const TemplateMethod& m: templateMethods_ | boost::adaptors::map_values)
m.emit_cython_pxd(pxdFile);
size_t numMethods = constructor.nrOverloads() + static_methods.size() +
methods_.size() + templateMethods_.size();
if (numMethods == 0)
pxdFile.oss << "\t\tpass";
pxdFile.oss << "\n\n";
pyxFile.oss << "\n";
// for(const StaticMethod& m: static_methods | boost::adaptors::map_values)
// m.cython_wrapper(pxdFile, pyxFile, name());
// for(const Method& m: methods_ | boost::adaptors::map_values)
// m.cython_wrapper(pxdFile, pyxFile, name());
}
/* ************************************************************************* */

View File

@ -25,6 +25,7 @@
#include "Deconstructor.h"
#include "Method.h"
#include "StaticMethod.h"
#include "TemplateMethod.h"
#include "TypeAttributesTable.h"
#ifdef __GNUC__
@ -54,11 +55,14 @@ public:
typedef const std::string& Str;
typedef std::map<std::string, Method> Methods;
typedef std::map<std::string, StaticMethod> StaticMethods;
typedef std::map<std::string, TemplateMethod> TemplateMethods;
private:
boost::optional<Qualified> parentClass; ///< The *single* parent
Methods methods_; ///< Class methods
TemplateMethods templateMethods_;
Methods expandedTemplateMethods_;
// Method& mutableMethod(Str key);
public:
@ -87,13 +91,15 @@ public:
boost::optional<std::string> qualifiedParent() const;
size_t nrMethods() const {
return methods_.size();
return methods_.size() + expandedTemplateMethods_.size();
}
const Method& method(Str key) const;
bool exists(Str name) const {
return methods_.find(name) != methods_.end();
return methods_.find(name) != methods_.end() ||
expandedTemplateMethods_.find(name) !=
expandedTemplateMethods_.end();
}
// And finally MATLAB code is emitted, methods below called by Module::matlab_code
@ -152,6 +158,8 @@ public:
os << m << ";\n";
for(const Method& m: cls.methods_ | boost::adaptors::map_values)
os << m << ";\n";
for(const Method& m: cls.expandedTemplateMethods_ | boost::adaptors::map_values)
os << m << ";\n";
os << "};" << std::endl;
return os;
}

View File

@ -76,3 +76,17 @@ string Method::wrapper_call(FileWriter& wrapperFile, Str cppClassName,
}
/* ************************************************************************* */
void Method::emit_cython_pxd(FileWriter& file) const {
for(size_t i = 0; i < nrOverloads(); ++i) {
file.oss << "\t\t";
returnVals_[i].emit_cython_pxd(file);
file.oss << name_ << "(";
argumentList(i).emit_cython_pxd(file);
file.oss << ")";
if (is_const_) file.oss << " const";
file.oss << "\n";
}
}
/* ************************************************************************* */

View File

@ -25,6 +25,7 @@ namespace wrap {
/// Method class
class Method: public MethodBase {
protected:
bool is_const_;
public:
@ -50,6 +51,8 @@ public:
return os;
}
void emit_cython_pxd(FileWriter& file) const;
private:
// Emit method header

50
wrap/TemplateMethod.cpp Normal file
View File

@ -0,0 +1,50 @@
/* ----------------------------------------------------------------------------
* 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 TemplateMethod.ccp
* @author Duy-Nguyen Ta
**/
#include "TemplateMethod.h"
using namespace std;
using namespace wrap;
/* ************************************************************************* */
void TemplateMethod::emit_cython_pxd(FileWriter& file) const {
for(size_t i = 0; i < nrOverloads(); ++i) {
file.oss << "\t\t";
returnVals_[i].emit_cython_pxd(file);
file.oss << name_ << "[" << argName << "]" << "(";
argumentList(i).emit_cython_pxd(file);
file.oss << ")\n";
}
}
/* ************************************************************************* */
bool TemplateMethod::addOverload(Str name, const ArgumentList& args,
const ReturnValue& retVal, bool is_const,
std::string _argName, bool verbose) {
argName = _argName;
bool first = MethodBase::addOverload(name, args, retVal, boost::none, verbose);
if (first)
is_const_ = is_const;
else if (is_const && !is_const_)
throw std::runtime_error(
"Method::addOverload now designated as const whereas before it was not");
else if (!is_const && is_const_)
throw std::runtime_error(
"Method::addOverload now designated as non-const whereas before it was");
return first;
}
/* ************************************************************************* */

43
wrap/TemplateMethod.h Normal file
View File

@ -0,0 +1,43 @@
/* ----------------------------------------------------------------------------
* 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 StaticMethod.h
* @brief describes and generates code for static methods
* @author Duy-Nguyen Ta
**/
#pragma once
#include "Method.h"
namespace wrap {
/// StaticMethod class
struct TemplateMethod: public Method {
std::string argName; // name of template argument
bool addOverload(Str name, const ArgumentList& args,
const ReturnValue& retVal, bool is_const,
std::string argName, bool verbose = false);
friend std::ostream& operator<<(std::ostream& os, const TemplateMethod& m) {
for (size_t i = 0; i < m.nrOverloads(); i++)
os << "template <" << m.argName << "> " << m.returnVals_[i] << " " << m.name_ << m.argLists_[i];
return os;
}
void emit_cython_pxd(FileWriter& file) const;
};
} // \namespace wrap