@@ -342,8 +342,15 @@ static PyObject* mp_func_closure(CPPOverload* /* pymeth */, void*)
342342 Py_RETURN_NONE;
343343}
344344
345+ // To declare a variable as unused only when compiling for Python 3.
346+ #if PY_VERSION_HEX < 0x03000000
347+ #define CPyCppyy_Py3_UNUSED (name ) name
348+ #else
349+ #define CPyCppyy_Py3_UNUSED (name )
350+ #endif
351+
345352// ----------------------------------------------------------------------------
346- static PyObject* mp_func_code (CPPOverload* pymeth, void *)
353+ static PyObject* mp_func_code (CPPOverload* CPyCppyy_Py3_UNUSED ( pymeth) , void*)
347354{
348355// Code details are used in module inspect to fill out interactive help()
349356#if PY_VERSION_HEX < 0x03000000
@@ -410,7 +417,6 @@ static PyObject* mp_func_code(CPPOverload* pymeth, void*)
410417 return code;
411418#else
412419// not important for functioning of most code, so not implemented for p3 for now (TODO)
413- pymeth = 0 ;
414420 Py_RETURN_NONE;
415421#endif
416422}
@@ -821,7 +827,7 @@ static CPPOverload* mp_descr_get(CPPOverload* pymeth, CPPInstance* pyobj, PyObje
821827 }
822828
823829// vector calls don't get here, unless a method is looked up on an instance, for
824- // e.g. class mathods (C++ static); notify downstream to expect a 'self'
830+ // e.g. class methods (C++ static); notify downstream to expect a 'self'
825831 newPyMeth->fFlags |= CallContext::kFromDescr ;
826832
827833#else
@@ -925,13 +931,22 @@ static PyObject* mp_overload(CPPOverload* pymeth, PyObject* args)
925931{
926932// Select and call a specific C++ overload, based on its signature.
927933 const char * sigarg = nullptr ;
934+ PyObject* sigarg_tuple = nullptr ;
928935 int want_const = -1 ;
929- if (PyTuple_GET_SIZE (args) && \
930- !PyArg_ParseTuple (args, const_cast <char *>(" s|i:__overload__" ), &sigarg, &want_const))
936+ Py_ssize_t args_size = PyTuple_GET_SIZE (args);
937+ if (args_size &&
938+ PyArg_ParseTuple (args, const_cast <char *>(" s|i:__overload__" ), &sigarg, &want_const)) {
939+ want_const = args_size == 1 ? -1 : want_const;
940+ return pymeth->FindOverload (sigarg ? sigarg : " " , want_const);
941+ } else if (args_size &&
942+ PyArg_ParseTuple (args, const_cast <char *>(" O|i:__overload__" ), &sigarg_tuple, &want_const)) {
943+ PyErr_Clear ();
944+ want_const = args_size == 1 ? -1 : want_const;
945+ return pymeth->FindOverload (sigarg_tuple, want_const);
946+ } else {
947+ PyErr_Format (PyExc_TypeError, " Unexpected arguments to __overload__" );
931948 return nullptr ;
932- want_const = PyTuple_GET_SIZE (args) == 1 ? -1 : want_const;
933-
934- return pymeth->FindOverload (sigarg ? sigarg : " " , want_const);
949+ }
935950}
936951
937952static PyObject* mp_add_overload (CPPOverload* pymeth, PyObject* new_overload)
@@ -1034,6 +1049,12 @@ PyTypeObject CPPOverload_Type = {
10341049#if PY_VERSION_HEX >= 0x03040000
10351050 , 0 // tp_finalize
10361051#endif
1052+ #if PY_VERSION_HEX >= 0x03080000
1053+ , 0 // tp_vectorcall
1054+ #endif
1055+ #if PY_VERSION_HEX >= 0x030c0000
1056+ , 0 // tp_watched
1057+ #endif
10371058};
10381059
10391060} // namespace CPyCppyy
@@ -1095,7 +1116,6 @@ PyObject* CPyCppyy::CPPOverload::FindOverload(const std::string& signature, int
10951116
10961117 CPPOverload::Methods_t& methods = fMethodInfo ->fMethods ;
10971118 for (auto & meth : methods) {
1098-
10991119 bool found = accept_any;
11001120 if (!found) {
11011121 PyObject* pysig2 = meth->GetSignature (false );
@@ -1144,6 +1164,67 @@ PyObject* CPyCppyy::CPPOverload::FindOverload(const std::string& signature, int
11441164 return (PyObject*)newmeth;
11451165}
11461166
1167+ PyObject* CPyCppyy::CPPOverload::FindOverload (PyObject *args_tuple, int want_const)
1168+ {
1169+ Py_ssize_t n = PyTuple_Size (args_tuple);
1170+
1171+ CPPOverload::Methods_t& methods = fMethodInfo ->fMethods ;
1172+
1173+ // This value is set based on the maximum penalty in Cppyy::CompareMethodArgType
1174+ Py_ssize_t min_score = INT_MAX;
1175+ bool found = false ;
1176+ size_t best_method = 0 , method_index = 0 ;
1177+
1178+ for (auto & meth : methods) {
1179+ if (0 <= want_const) {
1180+ bool isconst = meth->IsConst ();
1181+ if (!((want_const && isconst) || (!want_const && !isconst)))
1182+ continue ;
1183+ }
1184+
1185+ int score = meth->GetArgMatchScore (args_tuple);
1186+
1187+ if (score < min_score) {
1188+ found = true ;
1189+ min_score = score;
1190+ best_method = method_index;
1191+ }
1192+
1193+ method_index++;
1194+ }
1195+
1196+ if (!found) {
1197+ std::string sigargs (" (" );
1198+
1199+ for (int i = 0 ; i < n; i++) {
1200+ PyObject *pItem = PyTuple_GetItem (args_tuple, i);
1201+ if (!CPyCppyy_PyText_Check (pItem)) {
1202+ PyErr_Format (PyExc_LookupError, " argument types should be in string format" );
1203+ return (PyObject*) nullptr ;
1204+ }
1205+ std::string arg_type (CPyCppyy_PyText_AsString (pItem));
1206+ sigargs += arg_type + " , " ;
1207+ }
1208+ sigargs += " )" ;
1209+
1210+ PyErr_Format (PyExc_LookupError, " signature with arguments \" %s\" not found" , sigargs.c_str ());
1211+ return (PyObject*) nullptr ;
1212+ }
1213+
1214+ CPPOverload* newmeth = mp_new (nullptr , nullptr , nullptr );
1215+ CPPOverload::Methods_t vec;
1216+ vec.push_back (methods[best_method]->Clone ());
1217+ newmeth->Set (fMethodInfo ->fName , vec);
1218+
1219+ if (fSelf ) {
1220+ Py_INCREF (fSelf );
1221+ newmeth->fSelf = fSelf ;
1222+ }
1223+ newmeth->fMethodInfo ->fFlags = fMethodInfo ->fFlags ;
1224+
1225+ return (PyObject*) newmeth;
1226+ }
1227+
11471228// ----------------------------------------------------------------------------
11481229CPyCppyy::CPPOverload::MethodInfo_t::~MethodInfo_t ()
11491230{
0 commit comments