Skip to content

Commit 02a9251

Browse files
committed
Sync Utility
1 parent 0b0c238 commit 02a9251

File tree

2 files changed

+65
-17
lines changed

2 files changed

+65
-17
lines changed

src/Utility.cxx

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,9 @@ namespace {
115115
gC2POperatorMapping["="] = "__assign__"; // id.
116116

117117
#if PY_VERSION_HEX < 0x03000000
118-
gC2POperatorMapping["bool"] = "__nonzero__";
118+
gC2POperatorMapping["bool"] = "__cpp_nonzero__";
119119
#else
120-
gC2POperatorMapping["bool"] = "__bool__";
120+
gC2POperatorMapping["bool"] = "__cpp_bool__";
121121
#endif
122122
}
123123
} initOperatorMapping_;
@@ -386,6 +386,22 @@ CPyCppyy::PyCallable* CPyCppyy::Utility::FindBinaryOperator(
386386
}
387387

388388
//----------------------------------------------------------------------------
389+
static inline std::string AnnotationAsText(PyObject* pyobj)
390+
{
391+
if (!CPyCppyy_PyText_Check(pyobj)) {
392+
PyObject* pystr = PyObject_GetAttr(pyobj, CPyCppyy::PyStrings::gName);
393+
if (!pystr) {
394+
PyErr_Clear();
395+
pystr = PyObject_Str(pyobj);
396+
}
397+
398+
std::string str = CPyCppyy_PyText_AsString(pystr);
399+
Py_DECREF(pystr);
400+
return str;
401+
}
402+
return CPyCppyy_PyText_AsString(pyobj);
403+
}
404+
389405
static bool AddTypeName(std::string& tmpl_name, PyObject* tn, PyObject* arg,
390406
CPyCppyy::Utility::ArgPreference pref, int* pcnt = nullptr)
391407
{
@@ -510,14 +526,14 @@ static bool AddTypeName(std::string& tmpl_name, PyObject* tn, PyObject* arg,
510526
if (ret) {
511527
// dict is ordered, with the last value being the return type
512528
std::ostringstream tpn;
513-
tpn << (CPPScope_Check(ret) ? ClassName(ret) : CPyCppyy_PyText_AsString(ret))
529+
tpn << (CPPScope_Check(ret) ? ClassName(ret) : AnnotationAsText(ret))
514530
<< " (*)(";
515531

516532
PyObject* values = PyDict_Values(annot);
517533
for (Py_ssize_t i = 0; i < (PyList_GET_SIZE(values)-1); ++i) {
518534
if (i) tpn << ", ";
519535
PyObject* item = PyList_GET_ITEM(values, i);
520-
tpn << (CPPScope_Check(item) ? ClassName(item) : CPyCppyy_PyText_AsString(item));
536+
tpn << (CPPScope_Check(item) ? ClassName(item) : AnnotationAsText(item));
521537
}
522538
Py_DECREF(values);
523539

@@ -587,7 +603,7 @@ std::string CPyCppyy::Utility::ConstructTemplateArgs(
587603
PyObject* tn = justOne ? tpArgs : PyTuple_GET_ITEM(tpArgs, i);
588604
if (CPyCppyy_PyText_Check(tn)) {
589605
tmpl_name.append(CPyCppyy_PyText_AsString(tn));
590-
// some commmon numeric types (separated out for performance: checking for
606+
// some common numeric types (separated out for performance: checking for
591607
// __cpp_name__ and/or __name__ is rather expensive)
592608
} else {
593609
if (!AddTypeName(tmpl_name, tn, (args ? PyTuple_GET_ITEM(args, i) : nullptr), pref, pcnt)) {
@@ -1039,14 +1055,18 @@ Py_ssize_t CPyCppyy::Utility::GetBuffer(PyObject* pyobject, char tc, int size, v
10391055

10401056
// new-style buffer interface
10411057
if (PyObject_CheckBuffer(pyobject)) {
1058+
if (PySequence_Check(pyobject) && !PySequence_Size(pyobject))
1059+
return 0; // PyObject_GetBuffer() crashes on some platforms for some zero-sized seqeunces
1060+
10421061
Py_buffer bufinfo;
10431062
memset(&bufinfo, 0, sizeof(Py_buffer));
10441063
if (PyObject_GetBuffer(pyobject, &bufinfo, PyBUF_FORMAT) == 0) {
10451064
if (tc == '*' || strchr(bufinfo.format, tc)
1046-
#ifdef _WIN32
1047-
// ctypes is inconsistent in format on Windows; either way these types are the same size
1048-
|| (tc == 'I' && strchr(bufinfo.format, 'L')) || (tc == 'i' && strchr(bufinfo.format, 'l'))
1049-
#endif
1065+
// if `long int` and `int` are the same size (on Windows and 32bit Linux,
1066+
// for example), `ctypes` isn't too picky about the type format, so make
1067+
// sure both integer types pass the type check
1068+
|| (sizeof(long int) == sizeof(int) && ((tc == 'I' && strchr(bufinfo.format, 'L')) ||
1069+
(tc == 'i' && strchr(bufinfo.format, 'l'))))
10501070
// complex float is 'Zf' in bufinfo.format, but 'z' in single char
10511071
|| (tc == 'z' && strstr(bufinfo.format, "Zf"))
10521072
// allow 'signed char' ('b') from array to pass through '?' (bool as from struct)
@@ -1227,6 +1247,29 @@ std::string CPyCppyy::Utility::ClassName(PyObject* pyobj)
12271247
return clname;
12281248
}
12291249

1250+
//----------------------------------------------------------------------------
1251+
static std::set<std::string> sIteratorTypes;
1252+
bool CPyCppyy::Utility::IsSTLIterator(const std::string& classname)
1253+
{
1254+
// attempt to recognize STL iterators (TODO: probably belongs in the backend)
1255+
if (sIteratorTypes.empty()) {
1256+
std::string tt = "<int>::";
1257+
for (auto c : {"std::vector", "std::list", "std::deque"}) {
1258+
for (auto i : {"iterator", "const_iterator"}) {
1259+
const std::string& itname = Cppyy::ResolveName(c+tt+i);
1260+
auto pos = itname.find('<');
1261+
if (pos != std::string::npos)
1262+
sIteratorTypes.insert(itname.substr(0, pos));
1263+
}
1264+
}
1265+
}
1266+
1267+
auto pos = classname.find('<');
1268+
if (pos != std::string::npos)
1269+
return sIteratorTypes.find(classname.substr(0, pos)) != sIteratorTypes.end();
1270+
return false;
1271+
}
1272+
12301273

12311274
//----------------------------------------------------------------------------
12321275
CPyCppyy::Utility::PyOperators::~PyOperators()
@@ -1284,23 +1327,17 @@ void CPyCppyy::Utility::SetDetailedException(std::vector<PyError_t>& errors, PyO
12841327
return;
12851328
}
12861329

1287-
// if a _single_ exception was from C++, assume it has priority
1288-
PyObject* exc_type = nullptr;
1330+
// if a _single_ exception was thrown from C++, assume it has priority (see below)
12891331
PyError_t* unique_from_cpp = nullptr;
12901332
for (auto& e : errors) {
12911333
if (e.fIsCpp) {
12921334
if (!unique_from_cpp)
12931335
unique_from_cpp = &e;
12941336
else {
1295-
// two C++ exceptions, resort to default
1337+
// two C++ exceptions, resort to default behavior
12961338
unique_from_cpp = nullptr;
1297-
exc_type = defexc;
12981339
break;
12991340
}
1300-
} else if (!unique_from_cpp) {
1301-
// try to consolidate Python exceptions, otherwise select default
1302-
if (!exc_type) exc_type = e.fType;
1303-
else if (exc_type != e.fType) exc_type = defexc;
13041341
}
13051342
}
13061343

@@ -1314,6 +1351,16 @@ void CPyCppyy::Utility::SetDetailedException(std::vector<PyError_t>& errors, PyO
13141351
Py_INCREF(unique_from_cpp->fType); Py_INCREF(unique_from_cpp->fValue); Py_XINCREF(unique_from_cpp->fTrace);
13151352
PyErr_Restore(unique_from_cpp->fType, unique_from_cpp->fValue, unique_from_cpp->fTrace);
13161353
} else {
1354+
// try to consolidate Python exceptions, otherwise select default
1355+
PyObject* exc_type = nullptr;
1356+
for (auto& e : errors) {
1357+
if (!exc_type) exc_type = e.fType;
1358+
else if (exc_type != e.fType) {
1359+
exc_type = defexc;
1360+
break;
1361+
}
1362+
}
1363+
13171364
// add the details to the topmsg
13181365
PyObject* separator = CPyCppyy_PyText_FromString("\n ");
13191366
for (auto& e : errors) {

src/Utility.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct PyOperators {
8080

8181
// meta information
8282
std::string ClassName(PyObject* pyobj);
83+
bool IsSTLIterator(const std::string& classname);
8384

8485
// for threading: save call to PyErr_Occurred()
8586
PyObject* PyErr_Occurred_WithGIL();

0 commit comments

Comments
 (0)