Skip to content

Commit 905f883

Browse files
committed
Sync CPPOverload
1 parent cdda6f2 commit 905f883

File tree

2 files changed

+91
-9
lines changed

2 files changed

+91
-9
lines changed

src/CPPOverload.cxx

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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

937952
static 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
//----------------------------------------------------------------------------
11481229
CPyCppyy::CPPOverload::MethodInfo_t::~MethodInfo_t()
11491230
{

src/CPPOverload.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class CPPOverload {
6767

6868
// find a method based on the provided signature
6969
PyObject* FindOverload(const std::string& signature, int want_const = -1);
70+
PyObject* FindOverload(PyObject *args_tuple, int want_const = -1);
7071

7172
public: // public, as the python C-API works with C structs
7273
PyObject_HEAD

0 commit comments

Comments
 (0)