Make internal, overloaded static methods cdefs to avoid call code/overhead

release/4.3a0
dellaert 2017-08-06 13:25:54 -07:00
parent 9505144f44
commit 2374347e69
4 changed files with 93 additions and 78 deletions

View File

@ -176,7 +176,7 @@ void Class::matlab_proxy(Str toolboxPath, Str wrapperName,
proxyFile.oss << " methods(Static = true)\n"; proxyFile.oss << " methods(Static = true)\n";
// Static methods // Static methods
for(const StaticMethods::value_type& name_m: static_methods) { for(const StaticMethods::value_type& name_m: static_methods_) {
const StaticMethod& m = name_m.second; const StaticMethod& m = name_m.second;
m.proxy_wrapper_fragments(proxyFile, wrapperFile, cppName, matlabQualName, m.proxy_wrapper_fragments(proxyFile, wrapperFile, cppName, matlabQualName,
matlabUniqueName, wrapperName, typeAttributes, functionNames); matlabUniqueName, wrapperName, typeAttributes, functionNames);
@ -295,7 +295,7 @@ void Class::pointer_constructor_fragments(FileWriter& proxyFile,
Class Class::expandTemplate(const TemplateSubstitution& ts) const { Class Class::expandTemplate(const TemplateSubstitution& ts) const {
Class inst = *this; Class inst = *this;
inst.methods_ = expandMethodTemplate(methods_, ts); inst.methods_ = expandMethodTemplate(methods_, ts);
inst.static_methods = expandMethodTemplate(static_methods, ts); inst.static_methods_ = expandMethodTemplate(static_methods_, ts);
inst.constructor = constructor.expandTemplate(ts); inst.constructor = constructor.expandTemplate(ts);
inst.deconstructor.name = inst.name(); inst.deconstructor.name = inst.name();
return inst; return inst;
@ -409,11 +409,11 @@ void Class::verifyAll(vector<string>& validTypes, bool& hasSerialiable) const {
// verify all of the function arguments // verify all of the function arguments
//TODO:verifyArguments<ArgumentList>(validTypes, constructor.args_list); //TODO:verifyArguments<ArgumentList>(validTypes, constructor.args_list);
verifyArguments<StaticMethod>(validTypes, static_methods); verifyArguments<StaticMethod>(validTypes, static_methods_);
verifyArguments<Method>(validTypes, methods_); verifyArguments<Method>(validTypes, methods_);
// verify function return types // verify function return types
verifyReturnTypes<StaticMethod>(validTypes, static_methods); verifyReturnTypes<StaticMethod>(validTypes, static_methods_);
verifyReturnTypes<Method>(validTypes, methods_); verifyReturnTypes<Method>(validTypes, methods_);
// verify parents // verify parents
@ -517,9 +517,9 @@ void Class::comment_fragment(FileWriter& proxyFile) const {
for(const Methods::value_type& name_m: methods_) for(const Methods::value_type& name_m: methods_)
name_m.second.comment_fragment(proxyFile); name_m.second.comment_fragment(proxyFile);
if (!static_methods.empty()) if (!static_methods_.empty())
proxyFile.oss << "%\n%-------Static Methods-------\n"; proxyFile.oss << "%\n%-------Static Methods-------\n";
for(const StaticMethods::value_type& name_m: static_methods) for(const StaticMethods::value_type& name_m: static_methods_)
name_m.second.comment_fragment(proxyFile); name_m.second.comment_fragment(proxyFile);
if (hasSerialization) { if (hasSerialization) {
@ -721,7 +721,7 @@ string Class::getSerializationExport() const {
void Class::python_wrapper(FileWriter& wrapperFile) const { void Class::python_wrapper(FileWriter& wrapperFile) const {
wrapperFile.oss << "class_<" << name() << ">(\"" << name() << "\")\n"; wrapperFile.oss << "class_<" << name() << ">(\"" << name() << "\")\n";
constructor.python_wrapper(wrapperFile, name()); constructor.python_wrapper(wrapperFile, name());
for(const StaticMethod& m: static_methods | boost::adaptors::map_values) for(const StaticMethod& m: static_methods_ | boost::adaptors::map_values)
m.python_wrapper(wrapperFile, name()); m.python_wrapper(wrapperFile, name());
for(const Method& m: methods_ | boost::adaptors::map_values) for(const Method& m: methods_ | boost::adaptors::map_values)
m.python_wrapper(wrapperFile, name()); m.python_wrapper(wrapperFile, name());
@ -729,61 +729,64 @@ void Class::python_wrapper(FileWriter& wrapperFile) const {
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Class::emit_cython_pxd(FileWriter& pxdFile) const { void Class::emit_cython_pxd(FileWriter& file) const {
pxdFile.oss << "cdef extern from \"" << includeFile << "\""; file.oss << "cdef extern from \"" << includeFile << "\"";
string ns = qualifiedNamespaces("::"); string ns = qualifiedNamespaces("::");
if (!ns.empty()) if (!ns.empty())
pxdFile.oss << " namespace \"" << ns << "\""; file.oss << " namespace \"" << ns << "\"";
pxdFile.oss << ":" << endl; file.oss << ":" << endl;
pxdFile.oss << " cdef cppclass " << pxdClassName() << " \"" << qualifiedName("::") << "\""; file.oss << " cdef cppclass " << pxdClassName() << " \"" << qualifiedName("::") << "\"";
if (templateArgs.size()>0) { if (templateArgs.size()>0) {
pxdFile.oss << "["; file.oss << "[";
for(size_t i = 0; i<templateArgs.size(); ++i) { for(size_t i = 0; i<templateArgs.size(); ++i) {
pxdFile.oss << templateArgs[i]; file.oss << templateArgs[i];
if (i<templateArgs.size()-1) pxdFile.oss << ","; if (i<templateArgs.size()-1) file.oss << ",";
} }
pxdFile.oss << "]"; file.oss << "]";
} }
if (parentClass) pxdFile.oss << "(" << parentClass->pxdClassName() << ")"; if (parentClass) file.oss << "(" << parentClass->pxdClassName() << ")";
pxdFile.oss << ":\n"; file.oss << ":\n";
constructor.emit_cython_pxd(pxdFile, *this); constructor.emit_cython_pxd(file, *this);
if (constructor.nrOverloads()>0) pxdFile.oss << "\n"; if (constructor.nrOverloads()>0) file.oss << "\n";
for(const StaticMethod& m: static_methods | boost::adaptors::map_values) for(const StaticMethod& m: static_methods_ | boost::adaptors::map_values)
m.emit_cython_pxd(pxdFile, *this); m.emit_cython_pxd(file, *this);
if (static_methods.size()>0) pxdFile.oss << "\n"; if (static_methods_.size()>0) file.oss << "\n";
for(const Method& m: nontemplateMethods_ | boost::adaptors::map_values) for(const Method& m: nontemplateMethods_ | boost::adaptors::map_values)
m.emit_cython_pxd(pxdFile, *this); m.emit_cython_pxd(file, *this);
for(const TemplateMethod& m: templateMethods_ | boost::adaptors::map_values) for(const TemplateMethod& m: templateMethods_ | boost::adaptors::map_values)
m.emit_cython_pxd(pxdFile, *this); m.emit_cython_pxd(file, *this);
size_t numMethods = constructor.nrOverloads() + static_methods.size() + size_t numMethods = constructor.nrOverloads() + static_methods_.size() +
methods_.size() + templateMethods_.size(); methods_.size() + templateMethods_.size();
if (numMethods == 0) if (numMethods == 0)
pxdFile.oss << " pass\n"; file.oss << " pass\n";
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Class::emit_cython_wrapper_pxd(FileWriter& pxdFile) const { void Class::emit_cython_wrapper_pxd(FileWriter& file) const {
pxdFile.oss << "cdef class " << pyxClassName(); file.oss << "\ncdef class " << pyxClassName();
if (getParent()) if (getParent())
pxdFile.oss << "(" << getParent()->pyxClassName() << ")"; file.oss << "(" << getParent()->pyxClassName() << ")";
pxdFile.oss << ":\n"; file.oss << ":\n";
pxdFile.oss << " cdef " << shared_pxd_class_in_pyx() << " " file.oss << " cdef " << shared_pxd_class_in_pyx() << " "
<< shared_pxd_obj_in_pyx() << "\n"; << shared_pxd_obj_in_pyx() << "\n";
// cyCreateFromShared // cyCreateFromShared
pxdFile.oss << " @staticmethod\n"; file.oss << " @staticmethod\n";
pxdFile.oss << " cdef " << pyxClassName() << " cyCreateFromShared(const " file.oss << " cdef " << pyxClassName() << " cyCreateFromShared(const "
<< shared_pxd_class_in_pyx() << "& other)\n"; << shared_pxd_class_in_pyx() << "& other)\n";
for(const StaticMethod& m: static_methods_ | boost::adaptors::map_values)
m.emit_cython_wrapper_pxd(file, *this);
if (static_methods_.size()>0) file.oss << "\n";
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Class::pyxInitParentObj(FileWriter& pyxFile, const std::string& pyObj, void Class::pyxInitParentObj(FileWriter& file, const std::string& pyObj,
const std::string& cySharedObj, const std::string& cySharedObj,
const std::vector<Class>& allClasses) const { const std::vector<Class>& allClasses) const {
if (parentClass) { if (parentClass) {
pyxFile.oss << pyObj << "." << parentClass->shared_pxd_obj_in_pyx() << " = " file.oss << pyObj << "." << parentClass->shared_pxd_obj_in_pyx() << " = "
<< "<" << parentClass->shared_pxd_class_in_pyx() << ">(" << "<" << parentClass->shared_pxd_class_in_pyx() << ">("
<< cySharedObj << ")\n"; << cySharedObj << ")\n";
// Find the parent class with name "parentClass" and point its cython obj // Find the parent class with name "parentClass" and point its cython obj
@ -797,27 +800,27 @@ void Class::pyxInitParentObj(FileWriter& pyxFile, const std::string& pyObj,
cerr << "Can't find parent class: " << parentClass->pxdClassName(); cerr << "Can't find parent class: " << parentClass->pxdClassName();
throw std::runtime_error("Parent class not found!"); throw std::runtime_error("Parent class not found!");
} }
parent_it->pyxInitParentObj(pyxFile, pyObj, cySharedObj, allClasses); parent_it->pyxInitParentObj(file, pyObj, cySharedObj, allClasses);
} }
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Class::pyxDynamicCast(FileWriter& pyxFile, const Class& curLevel, void Class::pyxDynamicCast(FileWriter& file, const Class& curLevel,
const std::vector<Class>& allClasses) const { const std::vector<Class>& allClasses) const {
std::string me = this->pyxClassName(), sharedMe = this->shared_pxd_class_in_pyx(); std::string me = this->pyxClassName(), sharedMe = this->shared_pxd_class_in_pyx();
if (curLevel.parentClass) { if (curLevel.parentClass) {
std::string parent = curLevel.parentClass->pyxClassName(), std::string parent = curLevel.parentClass->pyxClassName(),
parentObj = curLevel.parentClass->shared_pxd_obj_in_pyx(), parentObj = curLevel.parentClass->shared_pxd_obj_in_pyx(),
parentCythonClass = curLevel.parentClass->pxd_class_in_pyx(); parentCythonClass = curLevel.parentClass->pxd_class_in_pyx();
pyxFile.oss << "def dynamic_cast_" << me << "_" << parent << "(" << parent file.oss << "def dynamic_cast_" << me << "_" << parent << "(" << parent
<< " parent):\n"; << " parent):\n";
pyxFile.oss << " try:\n"; file.oss << " try:\n";
pyxFile.oss << " return " << me << ".cyCreateFromShared(<" << sharedMe file.oss << " return " << me << ".cyCreateFromShared(<" << sharedMe
<< ">dynamic_pointer_cast[" << pxd_class_in_pyx() << "," << ">dynamic_pointer_cast[" << pxd_class_in_pyx() << ","
<< parentCythonClass << "](parent." << parentObj << parentCythonClass << "](parent." << parentObj
<< "))\n"; << "))\n";
pyxFile.oss << " except:\n"; file.oss << " except:\n";
pyxFile.oss << " raise TypeError('dynamic cast failed!')\n"; file.oss << " raise TypeError('dynamic cast failed!')\n";
// Move up higher to one level: Find the parent class with name "parentClass" // Move up higher to one level: Find the parent class with name "parentClass"
auto parent_it = find_if(allClasses.begin(), allClasses.end(), auto parent_it = find_if(allClasses.begin(), allClasses.end(),
[&curLevel](const Class& cls) { [&curLevel](const Class& cls) {
@ -828,61 +831,61 @@ void Class::pyxDynamicCast(FileWriter& pyxFile, const Class& curLevel,
cerr << "Can't find parent class: " << parentClass->pxdClassName(); cerr << "Can't find parent class: " << parentClass->pxdClassName();
throw std::runtime_error("Parent class not found!"); throw std::runtime_error("Parent class not found!");
} }
pyxDynamicCast(pyxFile, *parent_it, allClasses); pyxDynamicCast(file, *parent_it, allClasses);
} }
} }
/* ************************************************************************* */ /* ************************************************************************* */
void Class::emit_cython_pyx(FileWriter& pyxFile, const std::vector<Class>& allClasses) const { void Class::emit_cython_pyx(FileWriter& file, const std::vector<Class>& allClasses) const {
pyxFile.oss << "cdef class " << pyxClassName(); file.oss << "cdef class " << pyxClassName();
if (parentClass) pyxFile.oss << "(" << parentClass->pyxClassName() << ")"; if (parentClass) file.oss << "(" << parentClass->pyxClassName() << ")";
pyxFile.oss << ":\n"; file.oss << ":\n";
// shared variable of the corresponding cython object // shared variable of the corresponding cython object
// pyxFile.oss << " cdef " << shared_pxd_class_in_pyx() << " " << shared_pxd_obj_in_pyx() << "\n"; // file.oss << " cdef " << shared_pxd_class_in_pyx() << " " << shared_pxd_obj_in_pyx() << "\n";
// __cinit___ // __cinit___
pyxFile.oss << " def __init__(self, *args, **kwargs):\n" file.oss << " def __init__(self, *args, **kwargs):\n"
" self." << shared_pxd_obj_in_pyx() << " = " " self." << shared_pxd_obj_in_pyx() << " = "
<< shared_pxd_class_in_pyx() << "()\n"; << shared_pxd_class_in_pyx() << "()\n";
pyxFile.oss << " if len(args)==0 and len(kwargs)==1 and kwargs.has_key('cyCreateFromShared'):\n return\n"; file.oss << " if len(args)==0 and len(kwargs)==1 and kwargs.has_key('cyCreateFromShared'):\n return\n";
for (size_t i = 0; i<constructor.nrOverloads(); ++i) { for (size_t i = 0; i<constructor.nrOverloads(); ++i) {
pyxFile.oss << " " << "elif" << " self." file.oss << " " << "elif" << " self."
<< pyxClassName() << "_" << i << pyxClassName() << "_" << i
<< "(args, kwargs):\n pass\n"; << "(args, kwargs):\n pass\n";
} }
pyxFile.oss << " else:\n raise TypeError('" << pyxClassName() file.oss << " else:\n raise TypeError('" << pyxClassName()
<< " construction failed!')\n"; << " construction failed!')\n";
pyxInitParentObj(pyxFile, " self", "self." + shared_pxd_obj_in_pyx(), allClasses); pyxInitParentObj(file, " self", "self." + shared_pxd_obj_in_pyx(), allClasses);
pyxFile.oss << "\n"; file.oss << "\n";
// Constructors // Constructors
constructor.emit_cython_pyx(pyxFile, *this); constructor.emit_cython_pyx(file, *this);
if (constructor.nrOverloads()>0) pyxFile.oss << "\n"; if (constructor.nrOverloads()>0) file.oss << "\n";
// cyCreateFromShared // cyCreateFromShared
pyxFile.oss << " @staticmethod\n"; file.oss << " @staticmethod\n";
pyxFile.oss << " cdef " << pyxClassName() << " cyCreateFromShared(const " file.oss << " cdef " << pyxClassName() << " cyCreateFromShared(const "
<< shared_pxd_class_in_pyx() << "& other):\n" << shared_pxd_class_in_pyx() << "& other):\n"
<< " if other.get() == NULL:\n" << " if other.get() == NULL:\n"
<< " raise RuntimeError('Cannot create object from a nullptr!')\n" << " raise RuntimeError('Cannot create object from a nullptr!')\n"
<< " cdef " << pyxClassName() << " return_value = " << pyxClassName() << "(cyCreateFromShared=True)\n" << " cdef " << pyxClassName() << " return_value = " << pyxClassName() << "(cyCreateFromShared=True)\n"
<< " return_value." << shared_pxd_obj_in_pyx() << " = other\n"; << " return_value." << shared_pxd_obj_in_pyx() << " = other\n";
pyxInitParentObj(pyxFile, " return_value", "other", allClasses); pyxInitParentObj(file, " return_value", "other", allClasses);
pyxFile.oss << " return return_value" << "\n\n"; file.oss << " return return_value" << "\n\n";
for(const StaticMethod& m: static_methods | boost::adaptors::map_values) for(const StaticMethod& m: static_methods_ | boost::adaptors::map_values)
m.emit_cython_pyx(pyxFile, *this); m.emit_cython_pyx(file, *this);
if (static_methods.size()>0) pyxFile.oss << "\n"; if (static_methods_.size()>0) file.oss << "\n";
for(const Method& m: methods_ | boost::adaptors::map_values) for(const Method& m: methods_ | boost::adaptors::map_values)
m.emit_cython_pyx(pyxFile, *this); m.emit_cython_pyx(file, *this);
pyxDynamicCast(pyxFile, *this, allClasses); pyxDynamicCast(file, *this, allClasses);
pyxFile.oss << "\n\n"; file.oss << "\n\n";
} }
/* ************************************************************************* */ /* ************************************************************************* */

View File

@ -67,7 +67,7 @@ private:
public: public:
StaticMethods static_methods; ///< Static methods StaticMethods static_methods_; ///< Static methods
// Then the instance variables are set directly by the Module constructor // Then the instance variables are set directly by the Module constructor
std::vector<std::string> templateArgs; ///< Template arguments std::vector<std::string> templateArgs; ///< Template arguments
@ -177,7 +177,7 @@ public:
friend std::ostream& operator<<(std::ostream& os, const Class& cls) { friend std::ostream& operator<<(std::ostream& os, const Class& cls) {
os << "class " << cls.name() << "{\n"; os << "class " << cls.name() << "{\n";
os << cls.constructor << ";\n"; os << cls.constructor << ";\n";
for(const StaticMethod& m: cls.static_methods | boost::adaptors::map_values) for(const StaticMethod& m: cls.static_methods_ | boost::adaptors::map_values)
os << m << ";\n"; os << m << ";\n";
for(const Method& m: cls.methods_ | boost::adaptors::map_values) for(const Method& m: cls.methods_ | boost::adaptors::map_values)
os << m << ";\n"; os << m << ";\n";
@ -272,7 +272,7 @@ struct ClassGrammar: public classic::grammar<ClassGrammar> {
>> staticMethodName_p[assign_a(methodName)] >> argumentList_g >> ';' >> staticMethodName_p[assign_a(methodName)] >> argumentList_g >> ';'
>> *comments_p) // >> *comments_p) //
[bl::bind(&StaticMethod::addOverload, [bl::bind(&StaticMethod::addOverload,
bl::var(self.cls_.static_methods)[bl::var(methodName)], bl::var(self.cls_.static_methods_)[bl::var(methodName)],
bl::var(methodName), bl::var(args), bl::var(retVal), boost::none, bl::var(methodName), bl::var(args), bl::var(retVal), boost::none,
verbose)] // verbose)] //
[assign_a(retVal, retVal0)][clear_a(args)]; [assign_a(retVal, retVal0)][clear_a(args)];

View File

@ -58,7 +58,6 @@ string StaticMethod::wrapper_call(FileWriter& wrapperFile, Str cppClassName,
/* ************************************************************************* */ /* ************************************************************************* */
void StaticMethod::emit_cython_pxd(FileWriter& file, const Class& cls) const { void StaticMethod::emit_cython_pxd(FileWriter& file, const Class& cls) const {
// don't support overloads for static method :-(
for(size_t i = 0; i < nrOverloads(); ++i) { for(size_t i = 0; i < nrOverloads(); ++i) {
file.oss << " @staticmethod\n"; file.oss << " @staticmethod\n";
file.oss << " "; file.oss << " ";
@ -69,6 +68,18 @@ void StaticMethod::emit_cython_pxd(FileWriter& file, const Class& cls) const {
} }
} }
/* ************************************************************************* */
void StaticMethod::emit_cython_wrapper_pxd(FileWriter& file,
const Class& cls) const {
if (nrOverloads() > 1) {
for (size_t i = 0; i < nrOverloads(); ++i) {
string funcName = name_ + "_" + to_string(i);
file.oss << " @staticmethod\n";
file.oss << " cdef tuple " + funcName + "(tuple args, dict kwargs)\n";
}
}
}
/* ************************************************************************* */ /* ************************************************************************* */
void StaticMethod::emit_cython_pyx_no_overload(FileWriter& file, void StaticMethod::emit_cython_pyx_no_overload(FileWriter& file,
const Class& cls) const { const Class& cls) const {
@ -108,22 +119,22 @@ void StaticMethod::emit_cython_pyx(FileWriter& file, const Class& cls) const {
} }
file.oss << " raise TypeError('Could not find the correct overload')\n\n"; file.oss << " raise TypeError('Could not find the correct overload')\n\n";
// Create cdef methods for all overloaded methods
for(size_t i = 0; i < N; ++i) { for(size_t i = 0; i < N; ++i) {
file.oss << " @staticmethod\n";
string funcName = name_ + "_" + to_string(i); string funcName = name_ + "_" + to_string(i);
string pxdFuncName = name_ + ((i>0)?"_" + to_string(i):""); file.oss << " @staticmethod\n";
ArgumentList args = argumentList(i); file.oss << " cdef tuple " + funcName + "(tuple args, dict kwargs):\n";
file.oss << " def " + funcName + "(args, kwargs):\n";
file.oss << " cdef list __params\n"; file.oss << " cdef list __params\n";
if (!returnVals_[i].isVoid()) { if (!returnVals_[i].isVoid()) {
file.oss << " cdef " << returnVals_[i].pyx_returnType() << " return_value\n"; file.oss << " cdef " << returnVals_[i].pyx_returnType() << " return_value\n";
} }
file.oss << " try:\n"; file.oss << " try:\n";
file.oss << pyx_resolveOverloadParams(args, false, 3); // lazy: always return None even if it's a void function ArgumentList args = argumentList(i);
file.oss << pyx_resolveOverloadParams(args, false, 3);
/// Call cython corresponding function and return /// Call cython corresponding function and return
file.oss << argumentList(i).pyx_convertEigenTypeAndStorageOrder(" "); file.oss << args.pyx_convertEigenTypeAndStorageOrder(" ");
string pxdFuncName = name_ + ((i>0)?"_" + to_string(i):"");
string call = pyx_functionCall(cls.pxd_class_in_pyx(), pxdFuncName, i); string call = pyx_functionCall(cls.pxd_class_in_pyx(), pxdFuncName, i);
if (!returnVals_[i].isVoid()) { if (!returnVals_[i].isVoid()) {
file.oss << " return_value = " << call << "\n"; file.oss << " return_value = " << call << "\n";

View File

@ -35,6 +35,7 @@ struct StaticMethod: public MethodBase {
} }
void emit_cython_pxd(FileWriter& file, const Class& cls) const; void emit_cython_pxd(FileWriter& file, const Class& cls) const;
void emit_cython_wrapper_pxd(FileWriter& file, const Class& cls) const;
void emit_cython_pyx(FileWriter& file, const Class& cls) const; void emit_cython_pyx(FileWriter& file, const Class& cls) const;
void emit_cython_pyx_no_overload(FileWriter& file, const Class& cls) const; void emit_cython_pyx_no_overload(FileWriter& file, const Class& cls) const;