diff --git a/src/Converters.cxx b/src/Converters.cxx index 5746800f..fd48f223 100644 --- a/src/Converters.cxx +++ b/src/Converters.cxx @@ -2610,6 +2610,12 @@ static void* PyFunction_AsCPointer(PyObject* pyobject, // function pointer. The former is direct, the latter involves a JIT-ed wrapper. static PyObject* sWrapperCacheEraser = PyCFunction_New(&gWrapperCacheEraserMethodDef, nullptr); + // FIXME: avoid string comparisons and parsing + std::string true_signature = signature; + true_signature.erase(std::remove(true_signature.begin(), true_signature.end(), ' '), true_signature.end()); + if (true_signature.rfind("(void)") != std::string::npos) + true_signature = true_signature.substr(0, true_signature.size() - 6) + "()"; + using namespace CPyCppyy; if (CPPOverload_Check(pyobject)) { @@ -2637,7 +2643,7 @@ static void* PyFunction_AsCPointer(PyObject* pyobject, if (pytmpl->fTemplateArgs) fullname += CPyCppyy_PyText_AsString(pytmpl->fTemplateArgs); Cppyy::TCppScope_t scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType; - Cppyy::TCppMethod_t cppmeth = Cppyy::GetMethodTemplate(scope, fullname, signature); + Cppyy::TCppMethod_t cppmeth = Cppyy::GetMethodTemplate(scope, fullname, true_signature); if (cppmeth) { void* fptr = (void*)Cppyy::GetFunctionAddress(cppmeth, false); if (fptr) return fptr; @@ -2650,7 +2656,7 @@ static void* PyFunction_AsCPointer(PyObject* pyobject, void* wpraddress = nullptr; // re-use existing wrapper if possible - auto key = rettype+signature; + auto key = rettype+true_signature; const auto& lookup = sWrapperLookup.find(key); if (lookup != sWrapperLookup.end()) { const auto& existing = lookup->second.find(pyobject); @@ -2678,7 +2684,7 @@ static void* PyFunction_AsCPointer(PyObject* pyobject, return nullptr; // extract argument types - const std::vector& argtypes = TypeManip::extract_arg_types(signature); + const std::vector& argtypes = TypeManip::extract_arg_types(true_signature); int nArgs = (int)argtypes.size(); // wrapper name diff --git a/src/Cppyy.h b/src/Cppyy.h index 4397ad47..13a6d07c 100644 --- a/src/Cppyy.h +++ b/src/Cppyy.h @@ -316,6 +316,8 @@ namespace Cppyy { CPPYY_IMPORT bool IsClassType(TCppType_t type); CPPYY_IMPORT + bool IsFunctionPointerType(TCppType_t type); + CPPYY_IMPORT TCppType_t GetType(const std::string& name, bool enable_slow_lookup = false); CPPYY_IMPORT bool AppendTypesSlow(const std::string &name, diff --git a/src/Executors.cxx b/src/Executors.cxx index 194fcde4..d04c5c0d 100644 --- a/src/Executors.cxx +++ b/src/Executors.cxx @@ -912,7 +912,13 @@ CPyCppyy::Executor* CPyCppyy::CreateExecutor(Cppyy::TCppType_t type, cdims_t dim // resolve typedefs etc. Cppyy::TCppType_t resolvedType = Cppyy::ResolveType(type); - const std::string& resolvedTypeStr = Cppyy::GetTypeAsString(resolvedType); + // FIXME: avoid string comparisons and parsing + std::string resolvedTypeStr = Cppyy::GetTypeAsString(resolvedType); + if (Cppyy::IsFunctionPointerType(resolvedType)) { + resolvedTypeStr.erase(std::remove(resolvedTypeStr.begin(), resolvedTypeStr.end(), ' '), resolvedTypeStr.end()); + if (resolvedTypeStr.rfind("(void)") != std::string::npos) + resolvedTypeStr = resolvedTypeStr.substr(0, resolvedTypeStr.size() - 6) + "()"; + } // a full, qualified matching executor is preferred if (resolvedTypeStr != fullType) { @@ -924,8 +930,8 @@ CPyCppyy::Executor* CPyCppyy::CreateExecutor(Cppyy::TCppType_t type, cdims_t dim //-- nothing? ok, collect information about the type and possible qualifiers/decorators bool isConst = strncmp(resolvedTypeStr.c_str(), "const", 5) == 0; const std::string& cpd = TypeManip::compound(resolvedTypeStr); - Cppyy::TCppType_t realType = Cppyy::GetRealType(resolvedType); - std::string realTypeStr = Cppyy::GetTypeAsString(realType); + Cppyy::TCppType_t realType = Cppyy::IsFunctionPointerType(resolvedType) ? resolvedType : Cppyy::GetRealType(resolvedType); + std::string realTypeStr = Cppyy::IsFunctionPointerType(resolvedType) ? resolvedTypeStr : Cppyy::GetTypeAsString(realType); const std::string compounded = cpd.empty() ? realTypeStr : realTypeStr + cpd; // accept unqualified type (as python does not know about qualifiers) @@ -981,6 +987,15 @@ CPyCppyy::Executor* CPyCppyy::CreateExecutor(Cppyy::TCppType_t type, cdims_t dim result = new InstancePtrRefExecutor(klass); } else result = new InstancePtrExecutor(klass); + } else if (realTypeStr.find("(*)") != std::string::npos || + (realTypeStr.find("::*)") != std::string::npos)) { + // this is a function pointer + // TODO: find better way of finding the type + auto pos1 = realTypeStr.find('('); + auto pos2 = realTypeStr.find("*)"); + auto pos3 = realTypeStr.rfind(')'); + result = new FunctionPointerExecutor( + realTypeStr.substr(0, pos1), realTypeStr.substr(pos2+2, pos3-pos2-1)); } else { // unknown: void* may work ("user knows best"), void will fail on use of return value h = (cpd == "") ? gExecFactories.find("void") : gExecFactories.find("void ptr"); diff --git a/src/Utility.cxx b/src/Utility.cxx index 40af2803..a450d3b6 100644 --- a/src/Utility.cxx +++ b/src/Utility.cxx @@ -869,7 +869,7 @@ void CPyCppyy::Utility::ConstructCallbackPreamble(const std::string& retType, int nArgs = (int)argtypes.size(); // return value and argument type converters - bool isVoid = retType == "void"; + bool isVoid = retType.find("void") == 0; // might contain trailing space if (!isVoid) code << " CPYCPPYY_STATIC std::unique_ptr> " "retconv{CPyCppyy::CreateConverter(\"" @@ -931,7 +931,7 @@ void CPyCppyy::Utility::ConstructCallbackPreamble(const std::string& retType, void CPyCppyy::Utility::ConstructCallbackReturn(const std::string& retType, int nArgs, std::ostringstream& code) { // Generate code for return value conversion and error handling. - bool isVoid = retType == "void"; + bool isVoid = retType.find("void") == 0; // might contain trailing space bool isPtr = Cppyy::ResolveName(retType).back() == '*'; if (nArgs)