Logo ROOT  
Reference Guide
Utility.cxx
Go to the documentation of this file.
1 // Bindings
2 #include "CPyCppyy.h"
3 #include "Utility.h"
4 #include "CPPFunction.h"
5 #include "CPPInstance.h"
6 #include "CPPOverload.h"
7 #include "ProxyWrappers.h"
8 #include "PyCallable.h"
9 #include "PyStrings.h"
10 #include "CustomPyTypes.h"
11 #include "TemplateProxy.h"
12 #include "TypeManip.h"
13 
14 // Standard
15 #include <limits.h>
16 #include <string.h>
17 #include <algorithm>
18 #include <list>
19 #include <mutex>
20 #include <set>
21 #include <sstream>
22 #include <utility>
23 
24 
25 //- data _____________________________________________________________________
28 
29 typedef std::map<std::string, std::string> TC2POperatorMapping_t;
31 static std::set<std::string> gOpSkip;
32 static std::set<std::string> gOpRemove;
33 
34 namespace {
35 
36  using namespace CPyCppyy::Utility;
37 
38  struct InitOperatorMapping_t {
39  public:
40  InitOperatorMapping_t() {
41  // Initialize the global map of operator names C++ -> python.
42 
43  gOpSkip.insert("[]"); // __s/getitem__, depends on return type
44  gOpSkip.insert("+"); // __add__, depends on # of args (see __pos__)
45  gOpSkip.insert("-"); // __sub__, id. (eq. __neg__)
46  gOpSkip.insert("*"); // __mul__ or __deref__
47  gOpSkip.insert("++"); // __postinc__ or __preinc__
48  gOpSkip.insert("--"); // __postdec__ or __predec__
49 
50  gOpRemove.insert("new"); // this and the following not handled at all
51  gOpRemove.insert("new[]");
52  gOpRemove.insert("delete");
53  gOpRemove.insert("delete[]");
54 
55  gC2POperatorMapping["[]"] = "__getitem__";
56  gC2POperatorMapping["()"] = "__call__";
58  gC2POperatorMapping["%"] = "__mod__";
59  gC2POperatorMapping["**"] = "__pow__";
60  gC2POperatorMapping["<<"] = "__lshift__";
61  gC2POperatorMapping[">>"] = "__rshift__";
62  gC2POperatorMapping["&"] = "__and__";
63  gC2POperatorMapping["&&"] = "__dand__";
64  gC2POperatorMapping["|"] = "__or__";
65  gC2POperatorMapping["||"] = "__dor__";
66  gC2POperatorMapping["^"] = "__xor__";
67  gC2POperatorMapping["~"] = "__invert__";
68  gC2POperatorMapping[","] = "__comma__";
69  gC2POperatorMapping["+="] = "__iadd__";
70  gC2POperatorMapping["-="] = "__isub__";
71  gC2POperatorMapping["*="] = "__imul__";
73  gC2POperatorMapping["%="] = "__imod__";
74  gC2POperatorMapping["**="] = "__ipow__";
75  gC2POperatorMapping["<<="] = "__ilshift__";
76  gC2POperatorMapping[">>="] = "__irshift__";
77  gC2POperatorMapping["&="] = "__iand__";
78  gC2POperatorMapping["|="] = "__ior__";
79  gC2POperatorMapping["^="] = "__ixor__";
80  gC2POperatorMapping["=="] = "__eq__";
81  gC2POperatorMapping["!="] = "__ne__";
82  gC2POperatorMapping[">"] = "__gt__";
83  gC2POperatorMapping["<"] = "__lt__";
84  gC2POperatorMapping[">="] = "__ge__";
85  gC2POperatorMapping["<="] = "__le__";
86 
87  // the following type mappings are "exact"
88  gC2POperatorMapping["const char*"] = "__str__";
89  gC2POperatorMapping["char*"] = "__str__";
90  gC2POperatorMapping["const char *"] = gC2POperatorMapping["const char*"];
91  gC2POperatorMapping["char *"] = gC2POperatorMapping["char*"];
92  gC2POperatorMapping["int"] = "__int__";
94  gC2POperatorMapping["double"] = "__float__";
95 
96  // the following type mappings are "okay"; the assumption is that they
97  // are not mixed up with the ones above or between themselves (and if
98  // they are, that it is done consistently)
99  gC2POperatorMapping["short"] = "__int__";
100  gC2POperatorMapping["unsigned short"] = "__int__";
101  gC2POperatorMapping["unsigned int"] = CPPYY__long__;
102  gC2POperatorMapping["unsigned long"] = CPPYY__long__;
103  gC2POperatorMapping["long long"] = CPPYY__long__;
104  gC2POperatorMapping["unsigned long long"] = CPPYY__long__;
105  gC2POperatorMapping["float"] = "__float__";
106 
107  gC2POperatorMapping["->"] = "__follow__"; // not an actual python operator
108  gC2POperatorMapping["="] = "__assign__"; // id.
109 
110 #if PY_VERSION_HEX < 0x03000000
111  gC2POperatorMapping["bool"] = "__nonzero__";
112 #else
113  gC2POperatorMapping["bool"] = "__bool__";
114 #endif
115  }
116  } initOperatorMapping_;
117 
118 // TODO: this should live with Helpers
119  inline void RemoveConst(std::string& cleanName) {
120  std::string::size_type spos = std::string::npos;
121  while ((spos = cleanName.find("const")) != std::string::npos) {
122  cleanName.swap(cleanName.erase(spos, 5));
123  }
124  }
125 
126 } // unnamed namespace
127 
128 
129 //- public functions ---------------------------------------------------------
130 unsigned long CPyCppyy::PyLongOrInt_AsULong(PyObject* pyobject)
131 {
132 // Convert <pybject> to C++ unsigned long, with bounds checking, allow int -> ulong.
133  unsigned long ul = PyLong_AsUnsignedLong(pyobject);
134  if (PyErr_Occurred() && PyInt_Check(pyobject)) {
135  PyErr_Clear();
136  long i = PyInt_AS_LONG(pyobject);
137  if (0 <= i) {
138  ul = (unsigned long)i;
139  } else {
140  PyErr_SetString(PyExc_ValueError,
141  "can\'t convert negative value to unsigned long");
142  return (unsigned long)-1;
143  }
144  }
145 
146  return ul;
147 }
148 
149 //----------------------------------------------------------------------------
151 {
152 // Convert <pyobject> to C++ unsigned long long, with bounds checking.
153  ULong64_t ull = PyLong_AsUnsignedLongLong(pyobject);
154  if (PyErr_Occurred() && PyInt_Check(pyobject)) {
155  PyErr_Clear();
156  long i = PyInt_AS_LONG(pyobject);
157  if (0 <= i) {
158  ull = (ULong64_t)i;
159  } else {
160  PyErr_SetString(PyExc_ValueError,
161  "can\'t convert negative value to unsigned long long");
162  }
163  }
164 
165  return ull;
166 }
167 
168 //----------------------------------------------------------------------------
170  PyObject* pyclass, const char* label, PyCFunction cfunc, int flags)
171 {
172 // Add the given function to the class under name 'label'.
173 
174 // use list for clean-up (.so's are unloaded only at interpreter shutdown)
175  static std::list<PyMethodDef> s_pymeths;
176 
177  s_pymeths.push_back(PyMethodDef());
178  PyMethodDef* pdef = &s_pymeths.back();
179  pdef->ml_name = const_cast<char*>(label);
180  pdef->ml_meth = cfunc;
181  pdef->ml_flags = flags;
182  pdef->ml_doc = nullptr;
183 
184  PyObject* func = PyCFunction_New(pdef, nullptr);
186  PyObject* method = CustomInstanceMethod_New(func, nullptr, pyclass);
187  bool isOk = PyType_Type.tp_setattro(pyclass, name, method) == 0;
188  Py_DECREF(method);
189  Py_DECREF(name);
190  Py_DECREF(func);
191 
192  if (PyErr_Occurred())
193  return false;
194 
195  if (!isOk) {
196  PyErr_Format(PyExc_TypeError, "could not add method %s", label);
197  return false;
198  }
199 
200  return true;
201 }
202 
203 //----------------------------------------------------------------------------
204 bool CPyCppyy::Utility::AddToClass(PyObject* pyclass, const char* label, const char* func)
205 {
206 // Add the given function to the class under name 'label'.
207  PyObject* pyfunc = PyObject_GetAttrString(pyclass, const_cast<char*>(func));
208  if (!pyfunc)
209  return false;
210 
211  PyObject* pylabel = CPyCppyy_PyText_InternFromString(const_cast<char*>(label));
212  bool isOk = PyType_Type.tp_setattro(pyclass, pylabel, pyfunc) == 0;
213  Py_DECREF(pylabel);
214 
215  Py_DECREF(pyfunc);
216  return isOk;
217 }
218 
219 //----------------------------------------------------------------------------
220 bool CPyCppyy::Utility::AddToClass(PyObject* pyclass, const char* label, PyCallable* pyfunc)
221 {
222 // Add the given function to the class under name 'label'.
223  CPPOverload* method =
224  (CPPOverload*)PyObject_GetAttrString(pyclass, const_cast<char*>(label));
225 
226  if (!method || !CPPOverload_Check(method)) {
227  // not adding to existing CPPOverload; add callable directly to the class
228  if (PyErr_Occurred())
229  PyErr_Clear();
230  Py_XDECREF((PyObject*)method);
231  method = CPPOverload_New(label, pyfunc);
232  PyObject* pylabel = CPyCppyy_PyText_InternFromString(const_cast<char*>(label));
233  bool isOk = PyType_Type.tp_setattro(pyclass, pylabel, (PyObject*)method) == 0;
234  Py_DECREF(pylabel);
235  Py_DECREF(method);
236  return isOk;
237  }
238 
239  method->AdoptMethod(pyfunc);
240 
241  Py_DECREF(method);
242  return true;
243 }
244 
245 
246 //----------------------------------------------------------------------------
247 static inline
248 CPyCppyy::PyCallable* BuildOperator(const std::string& lcname, const std::string& rcname,
249  const char* op, Cppyy::TCppScope_t scope, bool reverse=false)
250 {
251 // Helper to find a function with matching signature in 'funcs'.
252  std::string opname = "operator";
253  opname += op;
254 
255  Cppyy::TCppIndex_t idx = Cppyy::GetGlobalOperator(scope, lcname, rcname, opname);
256  if (idx == (Cppyy::TCppIndex_t)-1)
257  return nullptr;
258 
259  Cppyy::TCppMethod_t meth = Cppyy::GetMethod(scope, idx);
260  if (!reverse)
261  return new CPyCppyy::CPPFunction(scope, meth);
262  return new CPyCppyy::CPPReverseBinary(scope, meth);
263 }
264 
265 //----------------------------------------------------------------------------
267 {
268 // Find a callable matching named operator (op) and klass arguments in the global
269 // namespace or the klass' namespace.
270  if (!CPPScope_Check(pyclass))
271  return nullptr;
272 
273  CPPClass* klass = (CPPClass*)pyclass;
274  const std::string& lcname = Cppyy::GetScopedFinalName(klass->fCppType);
276  return FindBinaryOperator(lcname, "", op, scope, false);
277 }
278 
279 //----------------------------------------------------------------------------
281  const char* op, Cppyy::TCppScope_t scope)
282 {
283 // Find a callable matching the named operator (op) and the (left, right)
284 // arguments in the global or these objects' namespaces.
285 
286  bool reverse = false;
287  if (!CPPInstance_Check(left)) {
288  if (CPPInstance_Check(right))
289  reverse = true;
290  else
291  return nullptr;
292  }
293 
294 // retrieve the class names to match the signature of any found global functions
295  const std::string& lcname = ClassName(left);
296  const std::string& rcname = ClassName(right);
297  return FindBinaryOperator(lcname, rcname, op, scope, reverse);
298 }
299 
300 //----------------------------------------------------------------------------
302  const std::string& lcname, const std::string& rcname,
303  const char* op, Cppyy::TCppScope_t scope, bool reverse)
304 {
305 // Find a global function with a matching signature; search __gnu_cxx, std::__1,
306 // and __cppyy_internal pro-actively (as there's AFAICS no way to unearth 'using'
307 // information).
308 
309  if (rcname == "<unknown>" || lcname == "<unknown>")
310  return nullptr;
311 
312  PyCallable* pyfunc = 0;
313 
314  const std::string& lnsname = TypeManip::extract_namespace(lcname);
315  if (!scope) scope = Cppyy::GetScope(lnsname);
316  if (scope)
317  pyfunc = BuildOperator(lcname, rcname, op, scope, reverse);
318 
319  if (!pyfunc && scope != Cppyy::gGlobalScope) // search in global scope anyway
320  pyfunc = BuildOperator(lcname, rcname, op, Cppyy::gGlobalScope, reverse);
321 
322  if (!pyfunc) {
323  // For GNU on clang, search the internal __gnu_cxx namespace for binary operators (is
324  // typically the case for STL iterators operator==/!=.
325  // TODO: only look in __gnu_cxx for iterators (and more generally: do lookups in the
326  // namespace where the class is defined
327  static Cppyy::TCppScope_t gnucxx = Cppyy::GetScope("__gnu_cxx");
328  if (gnucxx)
329  pyfunc = BuildOperator(lcname, rcname, op, gnucxx, reverse);
330  }
331 
332  if (!pyfunc) {
333  // Same for clang (on Mac only?). TODO: find proper pre-processor magic to only use those
334  // specific namespaces that are actually around; although to be sure, this isn't expensive.
335  static Cppyy::TCppScope_t std__1 = Cppyy::GetScope("std::__1");
336 
337  if (std__1
338 #ifdef __APPLE__
339  && lcname.find("__wrap_iter") == std::string::npos // wrapper call does not compile
340 #endif
341  ) {
342  pyfunc = BuildOperator(lcname, rcname, op, std__1, reverse);
343  }
344  }
345 
346  if (!pyfunc) {
347  // One more, mostly for Mac, but again not sure whether this is not a general issue. Some
348  // operators are declared as friends only in classes, so then they're not found in the
349  // global namespace, so this helper let's the compiler resolve the operator.
350  static Cppyy::TCppScope_t s_intern = Cppyy::GetScope("__cppyy_internal");
351  if (s_intern) {
352  std::stringstream fname, proto;
353  if (strncmp(op, "==", 2) == 0) { fname << "is_equal<"; }
354  else if (strncmp(op, "!=", 2) == 0) { fname << "is_not_equal<"; }
355  else { fname << "not_implemented<"; }
356  fname << lcname << ", " << rcname << ">";
357  proto << "const " << lcname << "&, const " << rcname;
358  Cppyy::TCppMethod_t method = Cppyy::GetMethodTemplate(s_intern, fname.str(), proto.str());
359  if (method) pyfunc = new CPPFunction(s_intern, method);
360  }
361  }
362 
363  return pyfunc;
364 }
365 
366 //----------------------------------------------------------------------------
367 static bool AddTypeName(std::string& tmpl_name, PyObject* tn, PyObject* arg,
368  CPyCppyy::Utility::ArgPreference pref, int* pcnt = nullptr)
369 {
370 // Determine the appropriate C++ type for a given Python type; this is a helper because
371 // it can recurse if the type is list or tuple and needs matching on std::vector.
372  using namespace CPyCppyy;
373  using namespace CPyCppyy::Utility;
374 
375  if (tn == (PyObject*)&PyInt_Type) {
376  if (arg) {
377 #if PY_VERSION_HEX < 0x03000000
378  long l = PyInt_AS_LONG(arg);
379  tmpl_name.append((l < INT_MIN || INT_MAX < l) ? "long" : "int");
380 #else
381  Long64_t ll = PyLong_AsLongLong(arg);
382  if (ll == (Long64_t)-1 && PyErr_Occurred()) {
383  PyErr_Clear();
384  ULong64_t ull = PyLong_AsUnsignedLongLong(arg);
385  if (ull == (ULong64_t)-1 && PyErr_Occurred()) {
386  PyErr_Clear();
387  tmpl_name.append("int"); // still out of range, will fail later
388  } else
389  tmpl_name.append("ULong64_t"); // since already failed long long
390  } else
391  tmpl_name.append((ll < INT_MIN || INT_MAX < ll) ? \
392  ((ll < LONG_MIN || LONG_MAX < ll) ? "Long64_t" : "long") : "int");
393 #endif
394  } else
395  tmpl_name.append("int");
396 #if PY_VERSION_HEX < 0x03000000
397  } else if (tn == (PyObject*)&PyLong_Type) {
398  if (arg) {
399  Long64_t ll = PyLong_AsLongLong(arg);
400  if (ll == (Long64_t)-1 && PyErr_Occurred()) {
401  PyErr_Clear();
402  ULong64_t ull = PyLong_AsUnsignedLongLong(arg);
403  if (ull == (ULong64_t)-1 && PyErr_Occurred()) {
404  PyErr_Clear();
405  tmpl_name.append("long"); // still out of range, will fail later
406  } else
407  tmpl_name.append("ULong64_t"); // since already failed long long
408  } else
409  tmpl_name.append((ll < LONG_MIN || LONG_MAX < ll) ? "Long64_t" : "long");
410  } else
411  tmpl_name.append("long");
412 #endif
413  } else if (tn == (PyObject*)&PyFloat_Type) {
414  // special case for floats (Python-speak for double) if from argument (only)
415  tmpl_name.append(arg ? "double" : "float");
416 #if PY_VERSION_HEX < 0x03000000
417  } else if (tn == (PyObject*)&PyString_Type) {
418 #else
419  } else if (tn == (PyObject*)&PyUnicode_Type) {
420 #endif
421  tmpl_name.append("std::string");
422  } else if (tn == (PyObject*)&PyList_Type || tn == (PyObject*)&PyTuple_Type) {
423  if (arg && PySequence_Size(arg)) {
424  std::string subtype{"std::initializer_list<"};
425  PyObject* item = PySequence_GetItem(arg, 0);
426  ArgPreference subpref = pref == kValue ? kValue : kPointer;
427  if (AddTypeName(subtype, (PyObject*)Py_TYPE(item), item, subpref)) {
428  tmpl_name.append(subtype);
429  tmpl_name.append(">");
430  }
431  Py_DECREF(item);
432  }
433 
434  } else if (CPPScope_Check(tn)) {
435  tmpl_name.append(Cppyy::GetScopedFinalName(((CPPClass*)tn)->fCppType));
436  if (arg) {
437  // try to specialize the type match for the given object
438  CPPInstance* pyobj = (CPPInstance*)arg;
439  if (CPPInstance_Check(pyobj)) {
440  if (pyobj->fFlags & CPPInstance::kIsRValue)
441  tmpl_name.append("&&");
442  else {
443  if (pcnt) *pcnt += 1;
444  if ((pyobj->fFlags & CPPInstance::kIsReference) || pref == kPointer)
445  tmpl_name.push_back('*');
446  else if (pref != kValue)
447  tmpl_name.push_back('&');
448  }
449  }
450  }
451  } else if (PyObject_HasAttr(tn, PyStrings::gCppName)) {
452  PyObject* tpName = PyObject_GetAttr(tn, PyStrings::gCppName);
453  tmpl_name.append(CPyCppyy_PyText_AsString(tpName));
454  Py_DECREF(tpName);
455  } else if (PyObject_HasAttr(tn, PyStrings::gName)) {
456  PyObject* tpName = PyObject_GetAttr(tn, PyStrings::gName);
457  tmpl_name.append(CPyCppyy_PyText_AsString(tpName));
458  Py_DECREF(tpName);
459  } else if (PyInt_Check(tn) || PyLong_Check(tn) || PyFloat_Check(tn)) {
460  // last ditch attempt, works for things like int values; since this is a
461  // source of errors otherwise, it is limited to specific types and not
462  // generally used (str(obj) can print anything ...)
463  PyObject* pystr = PyObject_Str(tn);
464  tmpl_name.append(CPyCppyy_PyText_AsString(pystr));
465  Py_DECREF(pystr);
466  } else {
467  return false;
468  }
469 
470  return true;
471 }
472 
474  PyObject* pyname, PyObject* tpArgs, PyObject* args, ArgPreference pref, int argoff, int* pcnt)
475 {
476 // Helper to construct the "<type, type, ...>" part of a templated name (either
477 // for a class or method lookup
478  bool justOne = !PyTuple_CheckExact(tpArgs);
479 
480 // Note: directly appending to string is a lot faster than stringstream
481  std::string tmpl_name;
482  tmpl_name.reserve(128);
483  if (pyname)
484  tmpl_name.append(CPyCppyy_PyText_AsString(pyname));
485  tmpl_name.push_back('<');
486 
487  if (pcnt) *pcnt = 0; // count number of times 'pref' is used
488 
489  Py_ssize_t nArgs = justOne ? 1 : PyTuple_GET_SIZE(tpArgs);
490  for (int i = argoff; i < nArgs; ++i) {
491  // add type as string to name
492  PyObject* tn = justOne ? tpArgs : PyTuple_GET_ITEM(tpArgs, i);
493  if (CPyCppyy_PyText_Check(tn)) {
494  tmpl_name.append(CPyCppyy_PyText_AsString(tn));
495  // some commmon numeric types (separated out for performance: checking for
496  // __cpp_name__ and/or __name__ is rather expensive)
497  } else {
498  if (!AddTypeName(tmpl_name, tn, (args ? PyTuple_GET_ITEM(args, i) : nullptr), pref, pcnt)) {
499  PyErr_SetString(PyExc_SyntaxError,
500  "could not construct C++ name from provided template argument.");
501  return "";
502  }
503  }
504 
505  // add a comma, as needed (no space as internally, final names don't have them)
506  if (i != nArgs-1)
507  tmpl_name.push_back(',');
508  }
509 
510 // close template name
511  tmpl_name.push_back('>');
512 
513  return tmpl_name;
514 }
515 
516 //----------------------------------------------------------------------------
517 void CPyCppyy::Utility::ConstructCallbackPreamble(const std::string& retType,
518  const std::vector<std::string>& argtypes, std::ostringstream& code)
519 {
520 // Generate function setup to be used in callbacks (wrappers and overrides).
521  int nArgs = (int)argtypes.size();
522 
523 // return value and argument type converters
524  bool isVoid = retType == "void";
525  if (!isVoid)
526  code << " CPYCPPYY_STATIC std::unique_ptr<CPyCppyy::Converter, std::function<void(CPyCppyy::Converter*)>> "
527  "retconv{CPyCppyy::CreateConverter(\""
528  << retType << "\"), CPyCppyy::DestroyConverter};\n";
529  if (nArgs) {
530  code << " CPYCPPYY_STATIC std::vector<std::unique_ptr<CPyCppyy::Converter, std::function<void(CPyCppyy::Converter*)>>> argcvs;\n"
531  << " if (argcvs.empty()) {\n"
532  << " argcvs.reserve(" << nArgs << ");\n";
533  for (int i = 0; i < nArgs; ++i)
534  code << " argcvs.emplace_back(CPyCppyy::CreateConverter(\"" << argtypes[i] << "\"), CPyCppyy::DestroyConverter);\n";
535  code << " }\n";
536  }
537 
538 // declare return value (TODO: this does not work for most non-builtin values)
539  if (!isVoid)
540  code << " " << retType << " ret{};\n";
541 
542 // acquire GIL
543  code << " PyGILState_STATE state = PyGILState_Ensure();\n";
544 
545 // build argument tuple if needed
546  if (nArgs) {
547  code << " std::vector<PyObject*> pyargs;\n";
548  code << " pyargs.reserve(" << nArgs << ");\n"
549  << " try {\n";
550  for (int i = 0; i < nArgs; ++i) {
551  code << " pyargs.emplace_back(argcvs[" << i << "]->FromMemory((void*)&arg" << i << "));\n"
552  << " if (!pyargs.back()) throw " << i << ";\n";
553  }
554  code << " } catch(int) {\n"
555  << " for (auto pyarg : pyargs) Py_XDECREF(pyarg);\n"
556  << " PyGILState_Release(state); throw CPyCppyy::PyException{};\n"
557  << " }\n";
558  }
559 }
560 
561 void CPyCppyy::Utility::ConstructCallbackReturn(const std::string& retType, int nArgs, std::ostringstream& code)
562 {
563 // Generate code for return value conversion and error handling.
564  bool isVoid = retType == "void";
565  bool isPtr = Cppyy::ResolveName(retType).back() == '*';
566  if (nArgs)
567  code << " for (auto pyarg : pyargs) Py_DECREF(pyarg);\n";
568  code << " bool cOk = (bool)pyresult;\n"
569  " if (pyresult) {\n";
570  if (isPtr) {
571  // If the return type is a CPPInstance, owned by Python, and the ref-count down
572  // to 1, the return will hold a dangling pointer, so set it to nullptr instead.
573  code << " if (!CPyCppyy::Instance_IsLively(pyresult))\n"
574  " ret = nullptr;\n"
575  " else {\n";
576  }
577  code << (isVoid ? "" : " cOk = retconv->ToMemory(pyresult, &ret);\n")
578  << " Py_DECREF(pyresult);\n }\n";
579  if (isPtr) code << " }\n";
580  code << " if (!cOk) {" // assume error set when converter failed
581 // TODO: On Windows, throwing a C++ exception here makes the code hang; leave
582 // the error be which allows at least one layer of propagation
583 #ifdef _WIN32
584  " /* do nothing */ }\n"
585 #else
586  " PyGILState_Release(state); throw CPyCppyy::PyException{}; }\n"
587 #endif
588  " PyGILState_Release(state);\n"
589  " return";
590  code << (isVoid ? ";\n }\n" : " ret;\n }\n");
591 }
592 
593 //----------------------------------------------------------------------------
594 bool CPyCppyy::Utility::InitProxy(PyObject* module, PyTypeObject* pytype, const char* name)
595 {
596 // Initialize a proxy class for use by python, and add it to the module.
597 
598 // finalize proxy type
599  if (PyType_Ready(pytype) < 0)
600  return false;
601 
602 // add proxy type to the given module
603  Py_INCREF(pytype); // PyModule_AddObject steals reference
604  if (PyModule_AddObject(module, (char*)name, (PyObject*)pytype) < 0) {
605  Py_DECREF(pytype);
606  return false;
607  }
608 
609 // declare success
610  return true;
611 }
612 
613 //----------------------------------------------------------------------------
614 Py_ssize_t CPyCppyy::Utility::GetBuffer(PyObject* pyobject, char tc, int size, void*& buf, bool check)
615 {
616 // Retrieve a linear buffer pointer from the given pyobject.
617 
618 // special case: don't handle character strings here (yes, they're buffers, but not quite)
619  if (PyBytes_Check(pyobject))
620  return 0;
621 
622 // special case: bytes array
623  if ((!check || tc == '*' || tc == 'B') && PyByteArray_CheckExact(pyobject)) {
624  buf = PyByteArray_AS_STRING(pyobject);
625  return PyByteArray_GET_SIZE(pyobject);
626  }
627 
628 // new-style buffer interface
629  if (PyObject_CheckBuffer(pyobject)) {
630  Py_buffer bufinfo;
631  memset(&bufinfo, 0, sizeof(Py_buffer));
632  if (PyObject_GetBuffer(pyobject, &bufinfo, PyBUF_FORMAT) == 0) {
633  if (tc == '*' || strchr(bufinfo.format, tc)
634 #ifdef _WIN32
635  // ctypes is inconsistent in format on Windows; either way these types are the same size
636  || (tc == 'I' && strchr(bufinfo.format, 'L')) || (tc == 'i' && strchr(bufinfo.format, 'l'))
637 #endif
638  // allow 'signed char' ('b') from array to pass through '?' (bool as from struct)
639  || (tc == '?' && strchr(bufinfo.format, 'b'))
640  ) {
641  buf = bufinfo.buf;
642  if (buf && bufinfo.ndim == 0) {
643  PyBuffer_Release(&bufinfo);
644  return bufinfo.len/bufinfo.itemsize;
645  } else if (buf && bufinfo.ndim == 1) {
646  Py_ssize_t size1d = bufinfo.shape ? bufinfo.shape[0] : bufinfo.len/bufinfo.itemsize;
647  PyBuffer_Release(&bufinfo);
648  return size1d;
649  }
650  } else {
651  // have buf, but format mismatch: bail out now, otherwise the old
652  // code will return based on itemsize match
653  PyBuffer_Release(&bufinfo);
654  return 0;
655  }
656  }
657  PyErr_Clear();
658  }
659 
660 // attempt to retrieve pointer through old-style buffer interface
661  PyBufferProcs* bufprocs = Py_TYPE(pyobject)->tp_as_buffer;
662 
663  PySequenceMethods* seqmeths = Py_TYPE(pyobject)->tp_as_sequence;
664  if (seqmeths != 0 && bufprocs != 0
665 #if PY_VERSION_HEX < 0x03000000
666  && bufprocs->bf_getwritebuffer != 0
667  && (*(bufprocs->bf_getsegcount))(pyobject, 0) == 1
668 #else
669  && bufprocs->bf_getbuffer != 0
670 #endif
671  ) {
672 
673  // get the buffer
674 #if PY_VERSION_HEX < 0x03000000
675  Py_ssize_t buflen = (*(bufprocs->bf_getwritebuffer))(pyobject, 0, &buf);
676 #else
677  Py_buffer bufinfo;
678  (*(bufprocs->bf_getbuffer))(pyobject, &bufinfo, PyBUF_WRITABLE);
679  buf = (char*)bufinfo.buf;
680  Py_ssize_t buflen = bufinfo.len;
681 #if PY_VERSION_HEX < 0x03010000
682  PyBuffer_Release(pyobject, &bufinfo);
683 #else
684  PyBuffer_Release(&bufinfo);
685 #endif
686 #endif
687 
688  if (buf && check == true) {
689  // determine buffer compatibility (use "buf" as a status flag)
690  PyObject* pytc = PyObject_GetAttr(pyobject, PyStrings::gTypeCode);
691  if (pytc != 0) { // for array objects
692  char cpytc = CPyCppyy_PyText_AsString(pytc)[0];
693  if (!(cpytc == tc || (tc == '?' && cpytc == 'b')))
694  buf = 0; // no match
695  Py_DECREF(pytc);
696  } else if (seqmeths->sq_length &&
697  (int)(buflen/(*(seqmeths->sq_length))(pyobject)) == size) {
698  // this is a gamble ... may or may not be ok, but that's for the user
699  PyErr_Clear();
700  } else if (buflen == size) {
701  // also a gamble, but at least 1 item will fit into the buffer, so very likely ok ...
702  PyErr_Clear();
703  } else {
704  buf = 0; // not compatible
705 
706  // clarify error message
707  PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0;
708  PyErr_Fetch(&pytype, &pyvalue, &pytrace);
710  (char*)"%s and given element size (%ld) do not match needed (%d)",
711  CPyCppyy_PyText_AsString(pyvalue),
712  seqmeths->sq_length ? (Long_t)(buflen/(*(seqmeths->sq_length))(pyobject)) : (Long_t)buflen,
713  size);
714  Py_DECREF(pyvalue);
715  PyErr_Restore(pytype, pyvalue2, pytrace);
716  }
717  }
718 
719  if (!buf) return 0;
720  return buflen/(size ? size : 1);
721  }
722 
723  return 0;
724 }
725 
726 //----------------------------------------------------------------------------
727 std::string CPyCppyy::Utility::MapOperatorName(const std::string& name, bool bTakesParams)
728 {
729 // Map the given C++ operator name on the python equivalent.
730  if (8 < name.size() && name.substr(0, 8) == "operator") {
731  std::string op = name.substr(8, std::string::npos);
732 
733  // stripping ...
734  std::string::size_type start = 0, end = op.size();
735  while (start < end && isspace(op[start])) ++start;
736  while (start < end && isspace(op[end-1])) --end;
737  op = op.substr(start, end - start);
738 
739  // certain operators should be removed completely (e.g. operator delete & friends)
740  if (gOpRemove.find(op) != gOpRemove.end())
741  return "";
742 
743  // check first if none, to prevent spurious deserializing downstream
744  TC2POperatorMapping_t::iterator pop = gC2POperatorMapping.find(op);
745  if (pop == gC2POperatorMapping.end() && gOpSkip.find(op) == gOpSkip.end()) {
746  op = Cppyy::ResolveName(op);
747  pop = gC2POperatorMapping.find(op);
748  }
749 
750  // map C++ operator to python equivalent, or made up name if no equivalent exists
751  if (pop != gC2POperatorMapping.end()) {
752  return pop->second;
753 
754  } else if (op == "*") {
755  // dereference v.s. multiplication of two instances
756  return bTakesParams ? "__mul__" : "__deref__";
757 
758  } else if (op == "+") {
759  // unary positive v.s. addition of two instances
760  return bTakesParams ? "__add__" : "__pos__";
761 
762  } else if (op == "-") {
763  // unary negative v.s. subtraction of two instances
764  return bTakesParams ? "__sub__" : "__neg__";
765 
766  } else if (op == "++") {
767  // prefix v.s. postfix increment
768  return bTakesParams ? "__postinc__" : "__preinc__";
769 
770  } else if (op == "--") {
771  // prefix v.s. postfix decrement
772  return bTakesParams ? "__postdec__" : "__predec__";
773  }
774 
775  }
776 
777 // might get here, as not all operator methods are handled (new, delete, etc.)
778  return name;
779 }
780 
781 //----------------------------------------------------------------------------
782 const std::string CPyCppyy::Utility::Compound(const std::string& name)
783 {
784 // TODO: consolidate with other string manipulations in TypeManip.cxx
785 // Break down the compound of a fully qualified type name.
786  std::string cleanName = name;
787  RemoveConst(cleanName);
788 
789  std::string compound = "";
790  for (int ipos = (int)cleanName.size()-1; 0 <= ipos; --ipos) {
791  char c = cleanName[ipos];
792  if (isspace(c)) continue;
793  if (isalnum(c) || c == '_' || c == '>' || c == ')') break;
794 
795  compound = c + compound;
796  }
797 
798 // for arrays (TODO: deal with the actual size)
799  if (compound == "]")
800  return "[]";
801 
802  return compound;
803 }
804 
805 //----------------------------------------------------------------------------
807 {
808 // TODO: consolidate with other string manipulations in Helpers.cxx
809 // Extract size from an array type, if available.
810  std::string cleanName = name;
811  RemoveConst(cleanName);
812 
813  if (cleanName[cleanName.size()-1] == ']') {
814  std::string::size_type idx = cleanName.rfind('[');
815  if (idx != std::string::npos) {
816  const std::string asize = cleanName.substr(idx+1, cleanName.size()-2);
817  return strtoul(asize.c_str(), nullptr, 0);
818  }
819  }
820 
821  return -1;
822 }
823 
824 //----------------------------------------------------------------------------
826 {
827 // Retrieve the class name from the given Python instance.
828  std::string clname = "<unknown>";
829  PyObject* pyclass = (PyObject*)Py_TYPE(pyobj);
830  PyObject* pyname = PyObject_GetAttr(pyclass, PyStrings::gCppName);
831  if (!pyname) {
832  PyErr_Clear();
833  pyname = PyObject_GetAttr(pyclass, PyStrings::gName);
834  }
835 
836  if (pyname) {
838  Py_DECREF(pyname);
839  } else
840  PyErr_Clear();
841  return clname;
842 }
843 
844 
845 //----------------------------------------------------------------------------
847 {
848  Py_XDECREF(fEq);
849  Py_XDECREF(fNe);
850  Py_XDECREF(fLAdd); Py_XDECREF(fRAdd);
851  Py_XDECREF(fSub);
852  Py_XDECREF(fLMul); Py_XDECREF(fRMul);
853  Py_XDECREF(fDiv);
854  Py_XDECREF(fHash);
855 }
856 
857 
858 //----------------------------------------------------------------------------
860 {
861 // Re-acquire the GIL before calling PyErr_Occurred() in case it has been
862 // released; note that the p2.2 code assumes that there are no callbacks in
863 // C++ to python (or at least none returning errors).
864 #if PY_VERSION_HEX >= 0x02030000
865  PyGILState_STATE gstate = PyGILState_Ensure();
866  PyObject* e = PyErr_Occurred();
867  PyGILState_Release(gstate);
868 #else
869  if (PyThreadState_GET())
870  return PyErr_Occurred();
871  PyObject* e = 0;
872 #endif
873 
874  return e;
875 }
876 
877 
878 //----------------------------------------------------------------------------
879 size_t CPyCppyy::Utility::FetchError(std::vector<PyError_t>& errors)
880 {
881 // Fetch the current python error, if any, and store it for future use.
882  if (PyErr_Occurred()) {
883  PyError_t e;
884  PyErr_Fetch(&e.fType, &e.fValue, &e.fTrace);
885  errors.push_back(e);
886  }
887  return errors.size();
888 }
889 
890 //----------------------------------------------------------------------------
891 void CPyCppyy::Utility::SetDetailedException(std::vector<PyError_t>& errors, PyObject* topmsg, PyObject* defexc)
892 {
893 // Use the collected exceptions to build up a detailed error log.
894  if (errors.empty()) {
895  // should not happen ...
896  PyErr_SetString(defexc, CPyCppyy_PyText_AsString(topmsg));
897  Py_DECREF(topmsg);
898  return;
899  }
900 
901 // add the details to the topmsg
903 
904  PyObject* exc_type = nullptr;
905  for (auto& e : errors) {
906  if (!exc_type) exc_type = e.fType;
907  else if (exc_type != e.fType) exc_type = defexc;
909  if (CPyCppyy_PyText_Check(e.fValue)) {
910  CPyCppyy_PyText_Append(&topmsg, e.fValue);
911  } else if (e.fValue) {
912  PyObject* excstr = PyObject_Str(e.fValue);
913  if (!excstr) {
914  PyErr_Clear();
915  excstr = PyObject_Str((PyObject*)Py_TYPE(e.fValue));
916  }
917  CPyCppyy_PyText_AppendAndDel(&topmsg, excstr);
918  } else {
920  CPyCppyy_PyText_FromString("unknown exception"));
921  }
922  }
923 
924  Py_DECREF(separator);
925  std::for_each(errors.begin(), errors.end(), PyError_t::Clear);
926 
927 // set the python exception
928  PyErr_SetString(exc_type, CPyCppyy_PyText_AsString(topmsg));
929  Py_DECREF(topmsg);
930 }
931 
932 
933 //----------------------------------------------------------------------------
934 static bool includesDone = false;
936 {
937 // setup Python API for callbacks
938  if (!includesDone) {
939  bool okay = Cppyy::Compile(
940  // basic API (converters etc.)
941  "#include \"CPyCppyy/API.h\"\n"
942 
943  // utilities from the CPyCppyy public API
944  "#include \"CPyCppyy/DispatchPtr.h\"\n"
945  "#include \"CPyCppyy/PyException.h\"\n"
946  );
947  includesDone = okay;
948  }
949 
950  return includesDone;
951 }
static CPyCppyy::PyCallable * BuildOperator(const std::string &lcname, const std::string &rcname, const char *op, Cppyy::TCppScope_t scope, bool reverse=false)
Definition: Utility.cxx:248
#define CPyCppyy_PyText_InternFromString
Definition: CPyCppyy.h:103
#define pyname
Definition: TMCParticle.cxx:19
long long Long64_t
Definition: RtypesCore.h:71
Cppyy::TCppType_t fCppType
Definition: CPPScope.h:50
bool CPPInstance_Check(T *object)
Definition: CPPInstance.h:118
bool gDictLookupActive
Definition: Utility.cxx:27
ULong64_t PyLongOrInt_AsULong64(PyObject *pyobject)
Definition: Utility.cxx:150
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
std::string ClassName(PyObject *pyobj)
Definition: Utility.cxx:825
size_t TCppScope_t
Definition: cpp_cppyy.h:18
bool InitProxy(PyObject *module, PyTypeObject *pytype, const char *name)
Definition: Utility.cxx:594
PyObject * CustomInstanceMethod_New(PyObject *func, PyObject *self, PyObject *pyclass)
void SetDetailedException(std::vector< PyError_t > &errors, PyObject *topmsg, PyObject *defexc)
Definition: Utility.cxx:891
static bool AddTypeName(std::string &tmpl_name, PyObject *tn, PyObject *arg, CPyCppyy::Utility::ArgPreference pref, int *pcnt=nullptr)
Definition: Utility.cxx:367
Py_ssize_t GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, bool check=true)
Definition: Utility.cxx:614
RPY_EXPORTED bool Compile(const std::string &code)
Py_ssize_t ArraySize(const std::string &name)
Definition: Utility.cxx:806
std::string ConstructTemplateArgs(PyObject *pyname, PyObject *tpArgs, PyObject *args=nullptr, ArgPreference=kNone, int argoff=0, int *pcnt=nullptr)
Definition: Utility.cxx:473
#define Py_TYPE(ob)
Definition: CPyCppyy.h:209
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
PyObject * gCppName
Definition: PyStrings.cxx:10
RPY_EXPORTED TCppScope_t gGlobalScope
Definition: cpp_cppyy.h:51
std::string MapOperatorName(const std::string &name, bool bTakesParames)
Definition: Utility.cxx:727
static const std::string separator("@@@")
size_t TCppIndex_t
Definition: cpp_cppyy.h:24
void compound()
Definition: compound.C:25
static bool includesDone
Definition: Utility.cxx:934
static TC2POperatorMapping_t gC2POperatorMapping
Definition: Utility.cxx:30
void AdoptMethod(PyCallable *pc)
bool CPPOverload_Check(T *object)
Definition: CPPOverload.h:79
PyObject * PyErr_Occurred_WithGIL()
Definition: Utility.cxx:859
dict_lookup_func gDictLookupOrg
Definition: Utility.cxx:26
void ConstructCallbackReturn(const std::string &retType, int nArgs, std::ostringstream &code)
Definition: Utility.cxx:561
std::string extract_namespace(const std::string &name)
Definition: TypeManip.cxx:159
CPPOverload * CPPOverload_New(const std::string &name, std::vector< PyCallable *> &methods)
Definition: CPPOverload.h:91
RPY_EXPORTED std::string ResolveName(const std::string &cppitem_name)
std::map< std::string, std::string > TC2POperatorMapping_t
Definition: Utility.cxx:29
PyObject * gTypeCode
Definition: PyStrings.cxx:28
_object PyObject
Definition: PyMethodBase.h:41
bool IncludePython()
Definition: Utility.cxx:935
PyCallable * FindUnaryOperator(PyObject *pyclass, const char *op)
Definition: Utility.cxx:266
intptr_t TCppMethod_t
Definition: cpp_cppyy.h:22
#define PyBytes_Check
Definition: CPyCppyy.h:83
RPY_EXPORTED TCppIndex_t GetGlobalOperator(TCppType_t scope, const std::string &lc, const std::string &rc, const std::string &op)
#define CPyCppyy_PyText_Append
Definition: CPyCppyy.h:104
long Long_t
Definition: RtypesCore.h:52
#define CPyCppyy_PyText_FromString
Definition: CPyCppyy.h:102
#define CPyCppyy_PyText_FromFormat
Definition: CPyCppyy.h:101
#define CPyCppyy_PyText_AppendAndDel
Definition: CPyCppyy.h:105
#define CPPYY__long__
Definition: CPyCppyy.h:128
unsigned long long ULong64_t
Definition: RtypesCore.h:72
void ConstructCallbackPreamble(const std::string &retType, const std::vector< std::string > &argtypes, std::ostringstream &code)
Definition: Utility.cxx:517
static std::set< std::string > gOpRemove
Definition: Utility.cxx:32
you should not use this method at all Int_t Int_t Double_t Double_t Double_t e
Definition: TRolke.cxx:630
bool CPPScope_Check(T *object)
Definition: CPPScope.h:76
static std::set< std::string > gOpSkip
Definition: Utility.cxx:31
unsigned long PyLongOrInt_AsULong(PyObject *pyobject)
Definition: Utility.cxx:130
const std::string Compound(const std::string &name)
Definition: Utility.cxx:782
#define CPPYY__div__
Definition: CPyCppyy.h:130
#define CPPYY__idiv__
Definition: CPyCppyy.h:129
auto * l
Definition: textangle.C:4
size_t FetchError(std::vector< PyError_t > &)
Definition: Utility.cxx:879
PyDictEntry *(* dict_lookup_func)(PyDictObject *, PyObject *, long)
Definition: CPyCppyy.h:69
RooCmdArg ClassName(const char *name)
RPY_EXPORTED TCppMethod_t GetMethodTemplate(TCppScope_t scope, const std::string &name, const std::string &proto)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
bool AddToClass(PyObject *pyclass, const char *label, PyCFunction cfunc, int flags=METH_VARARGS)
Definition: Utility.cxx:169
const char * proto
Definition: civetweb.c:16604
#define c(i)
Definition: RSha256.hxx:101
PyCallable * FindBinaryOperator(PyObject *left, PyObject *right, const char *op, Cppyy::TCppScope_t scope=0)
Definition: Utility.cxx:280
PyObject * gName
Definition: PyStrings.cxx:26
long
Definition: Converters.cxx:858
char name[80]
Definition: TGX11.cxx:109
#define CPyCppyy_PyText_Check
Definition: CPyCppyy.h:95
#define CPyCppyy_PyText_AsString
Definition: CPyCppyy.h:97