diff options
-rw-r--r-- | cppgenerator.cpp | 29 | ||||
-rw-r--r-- | doc/codeinjectionsemantics.rst | 13 | ||||
-rw-r--r-- | doc/typesystemvariables.rst | 9 | ||||
-rw-r--r-- | shibokengenerator.cpp | 24 | ||||
-rw-r--r-- | shibokengenerator.h | 9 |
5 files changed, 62 insertions, 22 deletions
diff --git a/cppgenerator.cpp b/cppgenerator.cpp index a3954f6dc..395fe1470 100644 --- a/cppgenerator.cpp +++ b/cppgenerator.cpp @@ -304,10 +304,10 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu if (func->allowThread()) s << INDENT << "// how to say to Python to allow threads?" << endl; - s << INDENT << "PyObject* method = BindingManager::instance().getOverride(this, \""; + s << INDENT << "PyObject* py_override = BindingManager::instance().getOverride(this, \""; s << func->name() << "\");" << endl; - s << INDENT << "if (!method) {" << endl; + s << INDENT << "if (!py_override) {" << endl; { Indentation indentation(INDENT); s << INDENT; @@ -376,13 +376,14 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu s << endl; } - s << INDENT << "PyGILState_STATE gil_state = PyGILState_Ensure();" << endl; - - s << INDENT; - if (!returnKeyword.isEmpty()) - s << "PyObject* " << retvalVariableName() << " = "; - s << "PyObject_Call(method, pyargs, NULL);" << endl; - s << INDENT << "PyGILState_Release(gil_state);" << endl << endl; + if (!injectedCodeCallsPythonOverride(func)) { + s << INDENT << "PyGILState_STATE gil_state = PyGILState_Ensure();" << endl; + s << INDENT; + if (!returnKeyword.isEmpty()) + s << "PyObject* " << retvalVariableName() << " = "; + s << "PyObject_Call(py_override, pyargs, NULL);" << endl; + s << INDENT << "PyGILState_Release(gil_state);" << endl << endl; + } foreach (FunctionModification func_mod, functionModifications(func)) { foreach (ArgumentModification arg_mod, func_mod.argument_mods) { @@ -393,16 +394,16 @@ void CppGenerator::writeVirtualMethodNative(QTextStream &s, const AbstractMetaFu } } - s << INDENT << "Py_XDECREF(pyargs);" << endl; - s << INDENT << "Py_XDECREF(method);" << endl; - - s << endl << INDENT << "// check and set Python error here..." << endl; - if (func->hasInjectedCode()) { s << endl; writeCodeSnips(s, snips, CodeSnip::End, TypeSystem::NativeCode, func); } + s << INDENT << "Py_XDECREF(pyargs);" << endl; + s << INDENT << "Py_XDECREF(py_override);" << endl; + + s << endl << INDENT << "// check and set Python error here..." << endl; + if (!returnKeyword.isEmpty()) { s << INDENT << returnKeyword; writeToCppConversion(s, func->type(), func->implementingClass(), retvalVariableName()); diff --git a/doc/codeinjectionsemantics.rst b/doc/codeinjectionsemantics.rst index c0d6fa2d7..aaa965fea 100644 --- a/doc/codeinjectionsemantics.rst +++ b/doc/codeinjectionsemantics.rst @@ -71,9 +71,9 @@ The following table describes the semantics of ``inject-code`` tag as used on | | | |Python override, if there is any), right after the C++ | | | | |arguments have been converted but before the Python call. | | | +---------+--------------------------------------------------------------+ - | | |end |This code injection goes to the end of a virtual method | - | | | |override on the C++ wrapper class, right before the return | - | | | |statement (if any). | + | | |end |This code injection is put in a virtual method override on the| + | | | |C++ wrapper class, after the call to Python and before | + | | | |dereferencing the Python method and tuple of arguments. | | +------+---------+--------------------------------------------------------------+ | |target|beginning|This code is injected on the Python method wrapper | | | | |(``PyCLASS_METHOD(...)``), right after the decisor have found | @@ -186,6 +186,9 @@ instead of Code Injection for Functions/Methods ==================================== + +.. _codeinjecting_method_native: + On The Native Side ------------------ @@ -197,7 +200,7 @@ class is polymorphic. int InjectCodeWrapper::virtualMethod(int arg) { PyObject* method = BindingManager::instance().getOverride(this, "virtualMethod"); - if (!method) + if (!py_override) return this->InjectCode::virtualMethod(arg); (... here C++ arguments are converted to Python ...) @@ -212,6 +215,8 @@ class is polymorphic. // Uses: post method call custom code, modify the result before delivering // it to C++ caller. + (... Python method and argument tuple are dereferenced here ...) + return Shiboken::Converter<int>::toCpp(method_result); } diff --git a/doc/typesystemvariables.rst b/doc/typesystemvariables.rst index dbfc29350..9966cfc55 100644 --- a/doc/typesystemvariables.rst +++ b/doc/typesystemvariables.rst @@ -206,6 +206,15 @@ Variables C++ parent's one. +.. _python_method_override: + +**%PYTHON_METHOD_OVERRIDE** + + This variable is used only on :ref:`native method code injections + <codeinjecting_method_native>`, i.e. on the binding overrides for C++ virtual + methods. It is replaced by a pointer to the Python method override. + + .. _pythontypeobject: **%PYTHONTYPEOBJECT** diff --git a/shibokengenerator.cpp b/shibokengenerator.cpp index 624c0c2eb..b30a85aca 100644 --- a/shibokengenerator.cpp +++ b/shibokengenerator.cpp @@ -978,12 +978,17 @@ void ShibokenGenerator::writeCodeSnips(QTextStream& s, } code.replace("%ARGUMENT_NAMES", argumentNames.join(", ")); - // replace template %PYTHON_ARGUMENTS variable for a pointer to the Python tuple - // containing the converted virtual method arguments received from C++ to be passed - // to the Python override - if (snip.language == TypeSystem::NativeCode) + if (snip.language == TypeSystem::NativeCode) { + // replace template %PYTHON_ARGUMENTS variable for a pointer to the Python tuple + // containing the converted virtual method arguments received from C++ to be passed + // to the Python override code.replace("%PYTHON_ARGUMENTS", "pyargs"); + // replace variable %PYTHON_METHOD_OVERRIDE for a pointer to the Python method + // override for the C++ virtual method in which this piece of code was inserted + code.replace("%PYTHON_METHOD_OVERRIDE", "py_override"); + } + replaceTemplateVariables(code, func); } @@ -1029,6 +1034,17 @@ bool ShibokenGenerator::injectedCodeCallsCppFunction(const AbstractMetaFunction* return false; } +bool ShibokenGenerator::injectedCodeCallsPythonOverride(const AbstractMetaFunction* func) +{ + static QRegExp overrideCallRegexCheck("PyObject_Call\\s*\\(\\s*%PYTHON_METHOD_OVERRIDE\\s*,"); + CodeSnipList snips = func->injectedCodeSnips(CodeSnip::Any, TypeSystem::NativeCode); + foreach (CodeSnip snip, snips) { + if (overrideCallRegexCheck.indexIn(snip.code()) != -1) + return true; + } + return false; +} + bool ShibokenGenerator::injectedCodeHasReturnValueAttribution(const AbstractMetaFunction* func) { static QRegExp retValAttributionRegexCheck("%0\\s*=[^=]\\s*.+"); diff --git a/shibokengenerator.h b/shibokengenerator.h index 6c6f372fe..2b53f7298 100644 --- a/shibokengenerator.h +++ b/shibokengenerator.h @@ -146,6 +146,15 @@ public: bool injectedCodeCallsCppFunction(const AbstractMetaFunction* func); /** + * Verifies if any of the function's code injections of the "native" class makes a + * call to the C++ method. This is used by the generator to avoid writing calls to + * Python overrides of C++ virtual methods when the user custom code already does this. + * \param func the function to check + * \return true if the function's code snippets call the Python override for a C++ virtual method + */ + bool injectedCodeCallsPythonOverride(const AbstractMetaFunction* func); + + /** * Verifies if any of the function's code injections attributes values to * the return variable (%0). * \param func the function to check |