Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
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 _____________________________________________________________________
26#if PY_VERSION_HEX < 0x030b0000
29#endif
30
31typedef std::map<std::string, std::string> TC2POperatorMapping_t;
33static std::set<std::string> gOpSkip;
34static std::set<std::string> gOpRemove;
35
36namespace CPyCppyy {
37// special objects
40}
41
42namespace {
43
44 using namespace CPyCppyy::Utility;
45
46 struct InitOperatorMapping_t {
47 public:
48 InitOperatorMapping_t() {
49 // Initialize the global map of operator names C++ -> python.
50
51 gOpSkip.insert("[]"); // __s/getitem__, depends on return type
52 gOpSkip.insert("+"); // __add__, depends on # of args (see __pos__)
53 gOpSkip.insert("-"); // __sub__, id. (eq. __neg__)
54 gOpSkip.insert("*"); // __mul__ or __deref__
55 gOpSkip.insert("++"); // __postinc__ or __preinc__
56 gOpSkip.insert("--"); // __postdec__ or __predec__
57
58 gOpRemove.insert("new"); // this and the following not handled at all
59 gOpRemove.insert("new[]");
60 gOpRemove.insert("delete");
61 gOpRemove.insert("delete[]");
62
63 gC2POperatorMapping["[]"] = "__getitem__";
64 gC2POperatorMapping["()"] = "__call__";
65 gC2POperatorMapping["%"] = "__mod__";
66 gC2POperatorMapping["**"] = "__pow__";
67 gC2POperatorMapping["<<"] = "__lshift__";
68 gC2POperatorMapping[">>"] = "__rshift__";
69 gC2POperatorMapping["&"] = "__and__";
70 gC2POperatorMapping["&&"] = "__dand__";
71 gC2POperatorMapping["|"] = "__or__";
72 gC2POperatorMapping["||"] = "__dor__";
73 gC2POperatorMapping["^"] = "__xor__";
74 gC2POperatorMapping["~"] = "__invert__";
75 gC2POperatorMapping[","] = "__comma__";
76 gC2POperatorMapping["+="] = "__iadd__";
77 gC2POperatorMapping["-="] = "__isub__";
78 gC2POperatorMapping["*="] = "__imul__";
80 gC2POperatorMapping["%="] = "__imod__";
81 gC2POperatorMapping["**="] = "__ipow__";
82 gC2POperatorMapping["<<="] = "__ilshift__";
83 gC2POperatorMapping[">>="] = "__irshift__";
84 gC2POperatorMapping["&="] = "__iand__";
85 gC2POperatorMapping["|="] = "__ior__";
86 gC2POperatorMapping["^="] = "__ixor__";
87 gC2POperatorMapping["=="] = "__eq__";
88 gC2POperatorMapping["!="] = "__ne__";
89 gC2POperatorMapping[">"] = "__gt__";
90 gC2POperatorMapping["<"] = "__lt__";
91 gC2POperatorMapping[">="] = "__ge__";
92 gC2POperatorMapping["<="] = "__le__";
93
94 // the following type mappings are "exact"
95 gC2POperatorMapping["const char*"] = "__str__";
96 gC2POperatorMapping["char*"] = "__str__";
97 gC2POperatorMapping["const char *"] = gC2POperatorMapping["const char*"];
98 gC2POperatorMapping["char *"] = gC2POperatorMapping["char*"];
99 gC2POperatorMapping["int"] = "__int__";
101 gC2POperatorMapping["double"] = "__float__";
102
103 // the following type mappings are "okay"; the assumption is that they
104 // are not mixed up with the ones above or between themselves (and if
105 // they are, that it is done consistently)
106 gC2POperatorMapping["short"] = "__int__";
107 gC2POperatorMapping["unsigned short"] = "__int__";
108 gC2POperatorMapping["unsigned int"] = CPPYY__long__;
109 gC2POperatorMapping["unsigned long"] = CPPYY__long__;
110 gC2POperatorMapping["long long"] = CPPYY__long__;
111 gC2POperatorMapping["unsigned long long"] = CPPYY__long__;
112 gC2POperatorMapping["float"] = "__float__";
113
114 gC2POperatorMapping["->"] = "__follow__"; // not an actual python operator
115 gC2POperatorMapping["="] = "__assign__"; // id.
116
117#if PY_VERSION_HEX < 0x03000000
118 gC2POperatorMapping["bool"] = "__cpp_nonzero__";
119#else
120 gC2POperatorMapping["bool"] = "__cpp_bool__";
121#endif
122 }
123 } initOperatorMapping_;
124
125} // unnamed namespace
126
127
128//- public functions ---------------------------------------------------------
130{
131// Convert <pybject> to C++ unsigned long, with bounds checking, allow int -> ulong.
132 if (PyFloat_Check(pyobject)) {
133 PyErr_SetString(PyExc_TypeError, "can\'t convert float to unsigned long");
134 return (unsigned long)-1;
135 } else if (pyobject == CPyCppyy::gDefaultObject) {
136 return (unsigned long)0;
137 }
138
139 unsigned long ul = PyLong_AsUnsignedLong(pyobject);
140 if (PyErr_Occurred() && PyInt_Check(pyobject)) {
141 PyErr_Clear();
142 long i = PyInt_AS_LONG(pyobject);
143 if (0 <= i) {
144 ul = (unsigned long)i;
145 } else {
146 PyErr_SetString(PyExc_ValueError,
147 "can\'t convert negative value to unsigned long");
148 return (unsigned long)-1;
149 }
150 }
151
152 return ul;
153}
154
155//----------------------------------------------------------------------------
157{
158// Convert <pyobject> to C++ unsigned long long, with bounds checking.
159 if (PyFloat_Check(pyobject)) {
160 PyErr_SetString(PyExc_TypeError, "can\'t convert float to unsigned long long");
161 return -1;
162 } else if (pyobject == CPyCppyy::gDefaultObject) {
163 return (unsigned long)0;
164 }
165
166 PY_ULONG_LONG ull = PyLong_AsUnsignedLongLong(pyobject);
167 if (PyErr_Occurred() && PyInt_Check(pyobject)) {
168 PyErr_Clear();
169 long i = PyInt_AS_LONG(pyobject);
170 if (0 <= i) {
171 ull = (PY_ULONG_LONG)i;
172 } else {
173 PyErr_SetString(PyExc_ValueError,
174 "can\'t convert negative value to unsigned long long");
175 }
176 }
177
178 return ull;
179}
180
181//----------------------------------------------------------------------------
183 PyObject* pyclass, const char* label, PyCFunction cfunc, int flags)
184{
185// Add the given function to the class under name 'label'.
186
187// use list for clean-up (.so's are unloaded only at interpreter shutdown)
188 static std::list<PyMethodDef> s_pymeths;
189
190 s_pymeths.push_back(PyMethodDef());
191 PyMethodDef* pdef = &s_pymeths.back();
192 pdef->ml_name = const_cast<char*>(label);
193 pdef->ml_meth = cfunc;
194 pdef->ml_flags = flags;
195 pdef->ml_doc = nullptr;
196
197 PyObject* func = PyCFunction_New(pdef, nullptr);
199 PyObject* method = CustomInstanceMethod_New(func, nullptr, pyclass);
200 bool isOk = PyType_Type.tp_setattro(pyclass, name, method) == 0;
201 Py_DECREF(method);
202 Py_DECREF(name);
203 Py_DECREF(func);
204
205 if (PyErr_Occurred())
206 return false;
207
208 if (!isOk) {
209 PyErr_Format(PyExc_TypeError, "could not add method %s", label);
210 return false;
211 }
212
213 return true;
214}
215
216//----------------------------------------------------------------------------
217bool CPyCppyy::Utility::AddToClass(PyObject* pyclass, const char* label, const char* func)
218{
219// Add the given function to the class under name 'label'.
220 PyObject* pyfunc = PyObject_GetAttrString(pyclass, const_cast<char*>(func));
221 if (!pyfunc)
222 return false;
223
224 PyObject* pylabel = CPyCppyy_PyText_InternFromString(const_cast<char*>(label));
225 bool isOk = PyType_Type.tp_setattro(pyclass, pylabel, pyfunc) == 0;
226 Py_DECREF(pylabel);
227
228 Py_DECREF(pyfunc);
229 return isOk;
230}
231
232//----------------------------------------------------------------------------
233bool CPyCppyy::Utility::AddToClass(PyObject* pyclass, const char* label, PyCallable* pyfunc)
234{
235// Add the given function to the class under name 'label'.
236 CPPOverload* method =
237 (CPPOverload*)PyObject_GetAttrString(pyclass, const_cast<char*>(label));
238
239 if (!method || !CPPOverload_Check(method)) {
240 // not adding to existing CPPOverload; add callable directly to the class
241 if (PyErr_Occurred())
242 PyErr_Clear();
243 Py_XDECREF((PyObject*)method);
244 method = CPPOverload_New(label, pyfunc);
245 PyObject* pylabel = CPyCppyy_PyText_InternFromString(const_cast<char*>(label));
246 bool isOk = PyType_Type.tp_setattro(pyclass, pylabel, (PyObject*)method) == 0;
247 Py_DECREF(pylabel);
248 Py_DECREF(method);
249 return isOk;
250 }
251
252 method->AdoptMethod(pyfunc);
253
254 Py_DECREF(method);
255 return true;
256}
257
258
259//----------------------------------------------------------------------------
260static inline
261CPyCppyy::PyCallable* BuildOperator(const std::string& lcname, const std::string& rcname,
262 const char* op, Cppyy::TCppScope_t scope, bool reverse=false)
263{
264// Helper to find a function with matching signature in 'funcs'.
265 std::string opname = "operator";
266 opname += op;
267
268 Cppyy::TCppIndex_t idx = Cppyy::GetGlobalOperator(scope, lcname, rcname, opname);
269 if (idx == (Cppyy::TCppIndex_t)-1)
270 return nullptr;
271
272 Cppyy::TCppMethod_t meth = Cppyy::GetMethod(scope, idx);
273 if (!reverse)
274 return new CPyCppyy::CPPFunction(scope, meth);
275 return new CPyCppyy::CPPReverseBinary(scope, meth);
276}
277
278//----------------------------------------------------------------------------
280{
281// Find a callable matching named operator (op) and klass arguments in the global
282// namespace or the klass' namespace.
283
284 if (!CPPScope_Check(pyclass))
285 return nullptr;
286
287 CPPClass* klass = (CPPClass*)pyclass;
288 const std::string& lcname = Cppyy::GetScopedFinalName(klass->fCppType);
289 Cppyy::TCppScope_t scope = Cppyy::GetScope(TypeManip::extract_namespace(lcname));
290 return FindBinaryOperator(lcname, "", op, scope, false);
291}
292
293//----------------------------------------------------------------------------
295 const char* op, Cppyy::TCppScope_t scope)
296{
297// Find a callable matching the named operator (op) and the (left, right)
298// arguments in the global or these objects' namespaces.
299
300 bool reverse = false;
301 if (!CPPInstance_Check(left)) {
302 if (CPPInstance_Check(right))
303 reverse = true;
304 else
305 return nullptr;
306 }
307
308// retrieve the class names to match the signature of any found global functions
309 const std::string& lcname = ClassName(left);
310 const std::string& rcname = ClassName(right);
311 return FindBinaryOperator(lcname, rcname, op, scope, reverse);
312}
313
314//----------------------------------------------------------------------------
316 const std::string& lcname, const std::string& rcname,
317 const char* op, Cppyy::TCppScope_t scope, bool reverse)
318{
319// Find a global function with a matching signature; search __gnu_cxx, std::__1,
320// and __cppyy_internal pro-actively (as there's AFAICS no way to unearth 'using'
321// information).
322
323 if (rcname == "<unknown>" || lcname == "<unknown>")
324 return nullptr;
325
326 PyCallable* pyfunc = 0;
327
328 if (!scope) {
329 // TODO: the following should remain sync with what clingwrapper does in its
330 // type remapper; there must be a better way?
331 if (lcname == "str" || lcname == "unicode" || lcname == "complex")
332 scope = Cppyy::GetScope("std");
333 else scope = Cppyy::GetScope(TypeManip::extract_namespace(lcname));
334 }
335 if (scope)
336 pyfunc = BuildOperator(lcname, rcname, op, scope, reverse);
337
338 if (!pyfunc && scope != Cppyy::gGlobalScope) // search in global scope anyway
339 pyfunc = BuildOperator(lcname, rcname, op, Cppyy::gGlobalScope, reverse);
340
341 if (!pyfunc) {
342 // For GNU on clang, search the internal __gnu_cxx namespace for binary operators (is
343 // typically the case for STL iterators operator==/!=.
344 // TODO: only look in __gnu_cxx for iterators (and more generally: do lookups in the
345 // namespace where the class is defined
346 static Cppyy::TCppScope_t gnucxx = Cppyy::GetScope("__gnu_cxx");
347 if (gnucxx)
348 pyfunc = BuildOperator(lcname, rcname, op, gnucxx, reverse);
349 }
350
351 if (!pyfunc) {
352 // Same for clang (on Mac only?). TODO: find proper pre-processor magic to only use those
353 // specific namespaces that are actually around; although to be sure, this isn't expensive.
354 static Cppyy::TCppScope_t std__1 = Cppyy::GetScope("std::__1");
355
356 if (std__1
357#ifdef __APPLE__
358 && lcname.find("__wrap_iter") == std::string::npos // wrapper call does not compile
359#endif
360 ) {
361 pyfunc = BuildOperator(lcname, rcname, op, std__1, reverse);
362 }
363 }
364
365 if (!pyfunc) {
366 // One more, mostly for Mac, but again not sure whether this is not a general issue. Some
367 // operators are declared as friends only in classes, so then they're not found in the
368 // global namespace, so this helper let's the compiler resolve the operator.
369 static Cppyy::TCppScope_t s_intern = Cppyy::GetScope("__cppyy_internal");
370 if (s_intern) {
371 std::stringstream fname, proto;
372 if (strncmp(op, "==", 2) == 0) { fname << "is_equal<"; }
373 else if (strncmp(op, "!=", 2) == 0) { fname << "is_not_equal<"; }
374 else { fname << "not_implemented<"; }
375 fname << lcname << ", " << rcname << ">";
376 proto << "const " << lcname << "&, const " << rcname;
377 Cppyy::TCppMethod_t method = Cppyy::GetMethodTemplate(s_intern, fname.str(), proto.str());
378 if (method) pyfunc = new CPPFunction(s_intern, method);
379 }
380 }
381
382 return pyfunc;
383}
384
385//----------------------------------------------------------------------------
386static inline std::string AnnotationAsText(PyObject* pyobj)
387{
388 if (!CPyCppyy_PyText_Check(pyobj)) {
389 PyObject* pystr = PyObject_GetAttr(pyobj, CPyCppyy::PyStrings::gName);
390 if (!pystr) {
391 PyErr_Clear();
392 pystr = PyObject_Str(pyobj);
393 }
394
395 std::string str = CPyCppyy_PyText_AsString(pystr);
396 Py_DECREF(pystr);
397 return str;
398 }
399 return CPyCppyy_PyText_AsString(pyobj);
400}
401
402static bool AddTypeName(std::string& tmpl_name, PyObject* tn, PyObject* arg,
403 CPyCppyy::Utility::ArgPreference pref, int* pcnt = nullptr)
404{
405// Determine the appropriate C++ type for a given Python type; this is a helper because
406// it can recurse if the type is list or tuple and needs matching on std::vector.
407 using namespace CPyCppyy;
408 using namespace CPyCppyy::Utility;
409
410 if (tn == (PyObject*)&PyInt_Type) {
411 if (arg) {
412#if PY_VERSION_HEX < 0x03000000
413 long l = PyInt_AS_LONG(arg);
414 tmpl_name.append((l < INT_MIN || INT_MAX < l) ? "long" : "int");
415#else
416 PY_LONG_LONG ll = PyLong_AsLongLong(arg);
417 if (ll == (PY_LONG_LONG)-1 && PyErr_Occurred()) {
418 PyErr_Clear();
419 PY_ULONG_LONG ull = PyLong_AsUnsignedLongLong(arg);
420 if (ull == (PY_ULONG_LONG)-1 && PyErr_Occurred()) {
421 PyErr_Clear();
422 tmpl_name.append("int"); // still out of range, will fail later
423 } else
424 tmpl_name.append("unsigned long long"); // since already failed long long
425 } else
426 tmpl_name.append((ll < INT_MIN || INT_MAX < ll) ? \
427 ((ll < LONG_MIN || LONG_MAX < ll) ? "long long" : "long") : "int");
428#endif
429 } else
430 tmpl_name.append("int");
431
432 return true;
433 }
434
435#if PY_VERSION_HEX < 0x03000000
436 if (tn == (PyObject*)&PyLong_Type) {
437 if (arg) {
438 PY_LONG_LONG ll = PyLong_AsLongLong(arg);
439 if (ll == (PY_LONG_LONG)-1 && PyErr_Occurred()) {
440 PyErr_Clear();
441 PY_ULONG_LONG ull = PyLong_AsUnsignedLongLong(arg);
442 if (ull == (PY_ULONG_LONG)-1 && PyErr_Occurred()) {
443 PyErr_Clear();
444 tmpl_name.append("long"); // still out of range, will fail later
445 } else
446 tmpl_name.append("unsigned long long"); // since already failed long long
447 } else
448 tmpl_name.append((ll < LONG_MIN || LONG_MAX < ll) ? "long long" : "long");
449 } else
450 tmpl_name.append("long");
451
452 return true;
453 }
454#endif
455
456 if (tn == (PyObject*)&PyFloat_Type) {
457 // special case for floats (Python-speak for double) if from argument (only)
458 tmpl_name.append(arg ? "double" : "float");
459 return true;
460 }
461
462#if PY_VERSION_HEX < 0x03000000
463 if (tn == (PyObject*)&PyString_Type) {
464#else
465 if (tn == (PyObject*)&PyUnicode_Type) {
466#endif
467 tmpl_name.append("std::string");
468 return true;
469 }
470
471 if (tn == (PyObject*)&PyList_Type || tn == (PyObject*)&PyTuple_Type) {
472 if (arg && PySequence_Size(arg)) {
473 std::string subtype{"std::initializer_list<"};
474 PyObject* item = PySequence_GetItem(arg, 0);
475 ArgPreference subpref = pref == kValue ? kValue : kPointer;
476 if (AddTypeName(subtype, (PyObject*)Py_TYPE(item), item, subpref)) {
477 tmpl_name.append(subtype);
478 tmpl_name.append(">");
479 }
480 Py_DECREF(item);
481 }
482
483 return true;
484 }
485
486 if (CPPScope_Check(tn)) {
487 tmpl_name.append(Cppyy::GetScopedFinalName(((CPPClass*)tn)->fCppType));
488 if (arg) {
489 // try to specialize the type match for the given object
490 CPPInstance* pyobj = (CPPInstance*)arg;
491 if (CPPInstance_Check(pyobj)) {
492 if (pyobj->fFlags & CPPInstance::kIsRValue)
493 tmpl_name.append("&&");
494 else {
495 if (pcnt) *pcnt += 1;
496 if ((pyobj->fFlags & CPPInstance::kIsReference) || pref == kPointer)
497 tmpl_name.push_back('*');
498 else if (pref != kValue)
499 tmpl_name.push_back('&');
500 }
501 }
502 }
503
504 return true;
505 }
506
507 if (tn == (PyObject*)&CPPOverload_Type) {
508 PyObject* tpName = arg ? \
509 PyObject_GetAttr(arg, PyStrings::gCppName) : \
510 CPyCppyy_PyText_FromString("void* (*)(...)");
511 tmpl_name.append(CPyCppyy_PyText_AsString(tpName));
512 Py_DECREF(tpName);
513
514 return true;
515 }
516
517 if (arg && PyCallable_Check(arg)) {
518 PyObject* annot = PyObject_GetAttr(arg, PyStrings::gAnnotations);
519 if (annot) {
520 if (PyDict_Check(annot) && 1 < PyDict_Size(annot)) {
521 PyObject* ret = PyDict_GetItemString(annot, "return");
522 if (ret) {
523 // dict is ordered, with the last value being the return type
524 std::ostringstream tpn;
525 tpn << (CPPScope_Check(ret) ? ClassName(ret) : AnnotationAsText(ret))
526 << " (*)(";
527
528 PyObject* values = PyDict_Values(annot);
529 for (Py_ssize_t i = 0; i < (PyList_GET_SIZE(values)-1); ++i) {
530 if (i) tpn << ", ";
531 PyObject* item = PyList_GET_ITEM(values, i);
532 tpn << (CPPScope_Check(item) ? ClassName(item) : AnnotationAsText(item));
533 }
534 Py_DECREF(values);
535
536 tpn << ')';
537 tmpl_name.append(tpn.str());
538
539 return true;
540
541 } else
542 PyErr_Clear();
543 }
544 Py_DECREF(annot);
545 } else
546 PyErr_Clear();
547
548 PyObject* tpName = PyObject_GetAttr(arg, PyStrings::gCppName);
549 if (tpName) {
550 tmpl_name.append(CPyCppyy_PyText_AsString(tpName));
551 Py_DECREF(tpName);
552 return true;
553 }
554 PyErr_Clear();
555 }
556
557 for (auto nn : {PyStrings::gCppName, PyStrings::gName}) {
558 PyObject* tpName = PyObject_GetAttr(tn, nn);
559 if (tpName) {
560 tmpl_name.append(CPyCppyy_PyText_AsString(tpName));
561 Py_DECREF(tpName);
562 return true;
563 }
564 PyErr_Clear();
565 }
566
567 if (PyInt_Check(tn) || PyLong_Check(tn) || PyFloat_Check(tn)) {
568 // last ditch attempt, works for things like int values; since this is a
569 // source of errors otherwise, it is limited to specific types and not
570 // generally used (str(obj) can print anything ...)
571 PyObject* pystr = PyObject_Str(tn);
572 tmpl_name.append(CPyCppyy_PyText_AsString(pystr));
573 Py_DECREF(pystr);
574 return true;
575 }
576
577 return false;
578}
579
581 PyObject* pyname, PyObject* tpArgs, PyObject* args, ArgPreference pref, int argoff, int* pcnt)
582{
583// Helper to construct the "<type, type, ...>" part of a templated name (either
584// for a class or method lookup
585 bool justOne = !PyTuple_CheckExact(tpArgs);
586
587// Note: directly appending to string is a lot faster than stringstream
588 std::string tmpl_name;
589 tmpl_name.reserve(128);
590 if (pyname)
591 tmpl_name.append(CPyCppyy_PyText_AsString(pyname));
592 tmpl_name.push_back('<');
593
594 if (pcnt) *pcnt = 0; // count number of times 'pref' is used
595
596 Py_ssize_t nArgs = justOne ? 1 : PyTuple_GET_SIZE(tpArgs);
597 for (int i = argoff; i < nArgs; ++i) {
598 // add type as string to name
599 PyObject* tn = justOne ? tpArgs : PyTuple_GET_ITEM(tpArgs, i);
600 if (CPyCppyy_PyText_Check(tn)) {
601 tmpl_name.append(CPyCppyy_PyText_AsString(tn));
602 // some common numeric types (separated out for performance: checking for
603 // __cpp_name__ and/or __name__ is rather expensive)
604 } else {
605 if (!AddTypeName(tmpl_name, tn, (args ? PyTuple_GET_ITEM(args, i) : nullptr), pref, pcnt)) {
606 PyErr_SetString(PyExc_SyntaxError,
607 "could not construct C++ name from provided template argument.");
608 return "";
609 }
610 }
611
612 // add a comma, as needed (no space as internally, final names don't have them)
613 if (i != nArgs-1)
614 tmpl_name.push_back(',');
615 }
616
617// close template name
618 tmpl_name.push_back('>');
619
620 return tmpl_name;
621}
622
623//----------------------------------------------------------------------------
624static inline bool check_scope(const std::string& name)
625{
627}
628
629void CPyCppyy::Utility::ConstructCallbackPreamble(const std::string& retType,
630 const std::vector<std::string>& argtypes, std::ostringstream& code)
631{
632// Generate function setup to be used in callbacks (wrappers and overrides).
633 int nArgs = (int)argtypes.size();
634
635// return value and argument type converters
636 bool isVoid = retType == "void";
637 if (!isVoid)
638 code << " CPYCPPYY_STATIC std::unique_ptr<CPyCppyy::Converter, std::function<void(CPyCppyy::Converter*)>> "
639 "retconv{CPyCppyy::CreateConverter(\""
640 << retType << "\"), CPyCppyy::DestroyConverter};\n";
641 std::vector<bool> arg_is_ptr;
642 if (nArgs) {
643 arg_is_ptr.reserve(nArgs);
644 code << " CPYCPPYY_STATIC std::vector<std::unique_ptr<CPyCppyy::Converter, std::function<void(CPyCppyy::Converter*)>>> argcvs;\n"
645 << " if (argcvs.empty()) {\n"
646 << " argcvs.reserve(" << nArgs << ");\n";
647 for (int i = 0; i < nArgs; ++i) {
648 arg_is_ptr[i] = false;
649 code << " argcvs.emplace_back(CPyCppyy::CreateConverter(\"";
650 const std::string& at = argtypes[i];
651 const std::string& res_at = Cppyy::ResolveName(at);
652 const std::string& cpd = TypeManip::compound(res_at);
653 if (!cpd.empty() && check_scope(res_at)) {
654 // in case of a pointer, the original argument needs to be used to ensure
655 // the pointer-value remains comparable
656 //
657 // in case of a reference, there is no extra indirection on the C++ side as
658 // would be when converting a data member, so adjust the converter
659 arg_is_ptr[i] = cpd.back() == '*';
660 if (arg_is_ptr[i] || cpd.back() == '&') {
661 code << res_at.substr(0, res_at.size()-1);
662 } else code << at;
663 } else
664 code << at;
665 code << "\"), CPyCppyy::DestroyConverter);\n";
666 }
667 code << " }\n";
668 }
669
670// declare return value (TODO: this does not work for most non-builtin values)
671 if (!isVoid)
672 code << " " << retType << " ret{};\n";
673
674// acquire GIL
675 code << " PyGILState_STATE state = PyGILState_Ensure();\n";
676
677// build argument tuple if needed
678 if (nArgs) {
679 code << " std::vector<PyObject*> pyargs;\n";
680 code << " pyargs.reserve(" << nArgs << ");\n"
681 << " try {\n";
682 for (int i = 0; i < nArgs; ++i) {
683 code << " pyargs.emplace_back(argcvs[" << i << "]->FromMemory((void*)";
684 if (!arg_is_ptr[i]) code << '&';
685 code << "arg" << i << "));\n"
686 << " if (!pyargs.back()) throw " << i << ";\n";
687 }
688 code << " } catch(int) {\n"
689 << " for (auto pyarg : pyargs) Py_XDECREF(pyarg);\n"
690 << " CPyCppyy::PyException pyexc; PyGILState_Release(state); throw pyexc;\n"
691 << " }\n";
692 }
693}
694
695void CPyCppyy::Utility::ConstructCallbackReturn(const std::string& retType, int nArgs, std::ostringstream& code)
696{
697// Generate code for return value conversion and error handling.
698 bool isVoid = retType == "void";
699 bool isPtr = Cppyy::ResolveName(retType).back() == '*';
700
701 if (nArgs)
702 code << " for (auto pyarg : pyargs) Py_DECREF(pyarg);\n";
703 code << " bool cOk = (bool)pyresult;\n"
704 " if (pyresult) {\n";
705 if (isPtr) {
706 // If the return type is a CPPInstance, owned by Python, and the ref-count down
707 // to 1, the return will hold a dangling pointer, so set it to nullptr instead.
708 code << " if (!CPyCppyy::Instance_IsLively(pyresult))\n"
709 " ret = nullptr;\n"
710 " else {\n";
711 }
712 code << (isVoid ? "" : " cOk = retconv->ToMemory(pyresult, (void*)&ret);\n")
713 << " Py_DECREF(pyresult);\n }\n";
714 if (isPtr) code << " }\n";
715 code << " if (!cOk) {" // assume error set when converter failed
716// TODO: On Windows, throwing a C++ exception here makes the code hang; leave
717// the error be which allows at least one layer of propagation
718#ifdef _WIN32
719 " /* do nothing */ }\n"
720#else
721 " CPyCppyy::PyException pyexc; PyGILState_Release(state); throw pyexc; }\n"
722#endif
723 " PyGILState_Release(state);\n"
724 " return";
725 code << (isVoid ? ";\n }\n" : " ret;\n }\n");
726}
727
728
729//----------------------------------------------------------------------------
730static std::map<void*, PyObject*> sStdFuncLookup;
731static std::map<std::string, PyObject*> sStdFuncMakerLookup;
733 const std::string& retType, const std::string& signature, void* address)
734{
735// Convert a function pointer to an equivalent std::function<> object.
736 static int maker_count = 0;
737
738 auto pf = sStdFuncLookup.find(address);
739 if (pf != sStdFuncLookup.end()) {
740 Py_INCREF(pf->second);
741 return pf->second;
742 }
743
744 PyObject* maker = nullptr;
745
746 auto pm = sStdFuncMakerLookup.find(retType+signature);
747 if (pm == sStdFuncMakerLookup.end()) {
748 std::ostringstream fname;
749 fname << "ptr2func" << ++maker_count;
750
751 std::ostringstream code;
752 code << "namespace __cppyy_internal { std::function<"
753 << retType << signature << "> " << fname.str()
754 << "(intptr_t faddr) { return (" << retType << "(*)" << signature << ")faddr;} }";
755
756 if (!Cppyy::Compile(code.str())) {
757 PyErr_SetString(PyExc_TypeError, "conversion to std::function failed");
758 return nullptr;
759 }
760
761 PyObject* pyscope = CreateScopeProxy("__cppyy_internal");
762 maker = PyObject_GetAttrString(pyscope, fname.str().c_str());
763 Py_DECREF(pyscope);
764 if (!maker)
765 return nullptr;
766
767 // cache the new maker (TODO: does it make sense to use weakrefs?)
768 sStdFuncMakerLookup[retType+signature] = maker;
769 } else
770 maker = pm->second;
771
772 PyObject* args = PyTuple_New(1);
773 PyTuple_SET_ITEM(args, 0, PyLong_FromLongLong((intptr_t)address));
774 PyObject* func = PyObject_Call(maker, args, NULL);
775 Py_DECREF(args);
776
777 if (func) { // prevent moving this func object, since then it can not be reused
778 ((CPPInstance*)func)->fFlags |= CPPInstance::kIsLValue;
779 Py_INCREF(func); // TODO: use weak? The C++ maker doesn't go away either
780 sStdFuncLookup[address] = func;
781 }
782
783 return func;
784}
785
786
787//----------------------------------------------------------------------------
788bool CPyCppyy::Utility::InitProxy(PyObject* module, PyTypeObject* pytype, const char* name)
789{
790// Initialize a proxy class for use by python, and add it to the module.
791
792// finalize proxy type
793 if (PyType_Ready(pytype) < 0)
794 return false;
795
796// add proxy type to the given module
797 Py_INCREF(pytype); // PyModule_AddObject steals reference
798 if (PyModule_AddObject(module, (char*)name, (PyObject*)pytype) < 0) {
799 Py_DECREF(pytype);
800 return false;
801 }
802
803// declare success
804 return true;
805}
806
807//----------------------------------------------------------------------------
808Py_ssize_t CPyCppyy::Utility::GetBuffer(PyObject* pyobject, char tc, int size, void*& buf, bool check)
809{
810// Retrieve a linear buffer pointer from the given pyobject.
811
812// special case: don't handle character strings here (yes, they're buffers, but not quite)
813 if (PyBytes_Check(pyobject) || PyUnicode_Check(pyobject))
814 return 0;
815
816// special case: bytes array
817 if ((!check || tc == '*' || tc == 'B') && PyByteArray_CheckExact(pyobject)) {
818 buf = PyByteArray_AS_STRING(pyobject);
819 return PyByteArray_GET_SIZE(pyobject);
820 }
821
822// new-style buffer interface
823 if (PyObject_CheckBuffer(pyobject)) {
824 if (PySequence_Check(pyobject) && !PySequence_Size(pyobject))
825 return 0; // PyObject_GetBuffer() crashes on some platforms for some zero-sized seqeunces
826
827 Py_buffer bufinfo;
828 memset(&bufinfo, 0, sizeof(Py_buffer));
829 if (PyObject_GetBuffer(pyobject, &bufinfo, PyBUF_FORMAT) == 0) {
830 if (tc == '*' || strchr(bufinfo.format, tc)
831 // if `long int` and `int` are the same size (on Windows and 32bit Linux,
832 // for example), `ctypes` isn't too picky about the type format, so make
833 // sure both integer types pass the type check
834 || (sizeof(long int) == sizeof(int) && ((tc == 'I' && strchr(bufinfo.format, 'L')) ||
835 (tc == 'i' && strchr(bufinfo.format, 'l'))))
836 // complex float is 'Zf' in bufinfo.format, but 'z' in single char
837 || (tc == 'z' && strstr(bufinfo.format, "Zf"))
838 // allow 'signed char' ('b') from array to pass through '?' (bool as from struct)
839 || (tc == '?' && strchr(bufinfo.format, 'b'))
840 ) {
841 buf = bufinfo.buf;
842
843 if (check && bufinfo.itemsize != size) {
844 PyErr_Format(PyExc_TypeError,
845 "buffer itemsize (%ld) does not match expected size (%d)", bufinfo.itemsize, size);
846 CPyCppyy_PyBuffer_Release(pyobject, &bufinfo);
847 return 0;
848 }
849
850 Py_ssize_t buflen = 0;
851 if (buf && bufinfo.ndim == 0)
852 buflen = bufinfo.len/bufinfo.itemsize;
853 else if (buf && bufinfo.ndim == 1)
854 buflen = bufinfo.shape ? bufinfo.shape[0] : bufinfo.len/bufinfo.itemsize;
855 CPyCppyy_PyBuffer_Release(pyobject, &bufinfo);
856 if (buflen)
857 return buflen;
858 } else {
859 // have buf, but format mismatch: bail out now, otherwise the old
860 // code will return based on itemsize match
861 CPyCppyy_PyBuffer_Release(pyobject, &bufinfo);
862 return 0;
863 }
864 } else if (bufinfo.obj)
865 CPyCppyy_PyBuffer_Release(pyobject, &bufinfo);
866 PyErr_Clear();
867 }
868
869// attempt to retrieve pointer through old-style buffer interface
870 PyBufferProcs* bufprocs = Py_TYPE(pyobject)->tp_as_buffer;
871
872 PySequenceMethods* seqmeths = Py_TYPE(pyobject)->tp_as_sequence;
873 if (seqmeths != 0 && bufprocs != 0
874#if PY_VERSION_HEX < 0x03000000
875 && bufprocs->bf_getwritebuffer != 0
876 && (*(bufprocs->bf_getsegcount))(pyobject, 0) == 1
877#else
878 && bufprocs->bf_getbuffer != 0
879#endif
880 ) {
881
882 // get the buffer
883#if PY_VERSION_HEX < 0x03000000
884 Py_ssize_t buflen = (*(bufprocs->bf_getwritebuffer))(pyobject, 0, &buf);
885#else
886 Py_buffer bufinfo;
887 (*(bufprocs->bf_getbuffer))(pyobject, &bufinfo, PyBUF_WRITABLE);
888 buf = (char*)bufinfo.buf;
889 Py_ssize_t buflen = bufinfo.len;
890 CPyCppyy_PyBuffer_Release(pyobject, &bufinfo);
891#endif
892
893 if (buf && check == true) {
894 // determine buffer compatibility (use "buf" as a status flag)
895 PyObject* pytc = tc != '*' ? PyObject_GetAttr(pyobject, PyStrings::gTypeCode) : nullptr;
896 if (pytc != 0) { // for array objects
897 char cpytc = CPyCppyy_PyText_AsString(pytc)[0];
898 if (!(cpytc == tc || (tc == '?' && cpytc == 'b')))
899 buf = 0; // no match
900 Py_DECREF(pytc);
901 } else if (seqmeths->sq_length &&
902 (int)(buflen/(*(seqmeths->sq_length))(pyobject)) == size) {
903 // this is a gamble ... may or may not be ok, but that's for the user
904 PyErr_Clear();
905 } else if (buflen == size) {
906 // also a gamble, but at least 1 item will fit into the buffer, so very likely ok ...
907 PyErr_Clear();
908 } else {
909 buf = 0; // not compatible
910
911 // clarify error message
912 PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0;
913 PyErr_Fetch(&pytype, &pyvalue, &pytrace);
915 (char*)"%s and given element size (%ld) do not match needed (%d)",
917 seqmeths->sq_length ? (long)(buflen/(*(seqmeths->sq_length))(pyobject)) : (long)buflen,
918 size);
919 Py_DECREF(pyvalue);
920 PyErr_Restore(pytype, pyvalue2, pytrace);
921 }
922 }
923
924 if (!buf) return 0;
925 return buflen/(size ? size : 1);
926 }
927
928 return 0;
929}
930
931//----------------------------------------------------------------------------
932std::string CPyCppyy::Utility::MapOperatorName(const std::string& name, bool bTakesParams, bool* stubbed)
933{
934// Map the given C++ operator name on the python equivalent.
935 if (8 < name.size() && name.substr(0, 8) == "operator") {
936 std::string op = name.substr(8, std::string::npos);
937
938 // stripping ...
939 std::string::size_type start = 0, end = op.size();
940 while (start < end && isspace(op[start])) ++start;
941 while (start < end && isspace(op[end-1])) --end;
942 op = op.substr(start, end - start);
943
944 // certain operators should be removed completely (e.g. operator delete & friends)
945 if (gOpRemove.find(op) != gOpRemove.end())
946 return "";
947
948 // check first if none, to prevent spurious deserializing downstream
949 TC2POperatorMapping_t::iterator pop = gC2POperatorMapping.find(op);
950 if (pop == gC2POperatorMapping.end() && gOpSkip.find(op) == gOpSkip.end()) {
951 op = Cppyy::ResolveName(op);
952 pop = gC2POperatorMapping.find(op);
953 }
954
955 // map C++ operator to python equivalent, or made up name if no equivalent exists
956 if (pop != gC2POperatorMapping.end()) {
957 return pop->second;
958
959 } else if (op == "*") {
960 // dereference v.s. multiplication of two instances
961 if (!bTakesParams) return "__deref__";
962 if (stubbed) *stubbed = true;
963 return "__mul__";
964
965 } else if (op == "/") {
966 // no unary, but is stubbed
967 return CPPYY__div__;
968
969 } else if (op == "+") {
970 // unary positive v.s. addition of two instances
971 if (!bTakesParams) return "__pos__";
972 if (stubbed) *stubbed = true;
973 return "__add__";
974
975 } else if (op == "-") {
976 // unary negative v.s. subtraction of two instances
977 if (!bTakesParams) return "__neg__";
978 if (stubbed) *stubbed = true;
979 return "__sub__";
980
981 } else if (op == "++") {
982 // prefix v.s. postfix increment
983 return bTakesParams ? "__postinc__" : "__preinc__";
984
985 } else if (op == "--") {
986 // prefix v.s. postfix decrement
987 return bTakesParams ? "__postdec__" : "__predec__";
988 }
989
990 }
991
992// might get here, as not all operator methods are handled (new, delete, etc.)
993 return name;
994}
995
996//----------------------------------------------------------------------------
998{
999// Retrieve the class name from the given Python instance.
1000 std::string clname = "<unknown>";
1001 PyObject* pyclass = (PyObject*)Py_TYPE(pyobj);
1002 PyObject* pyname = PyObject_GetAttr(pyclass, PyStrings::gCppName);
1003 if (!pyname) {
1004 PyErr_Clear();
1005 pyname = PyObject_GetAttr(pyclass, PyStrings::gName);
1006 }
1007
1008 if (pyname) {
1009 clname = CPyCppyy_PyText_AsString(pyname);
1010 Py_DECREF(pyname);
1011 } else
1012 PyErr_Clear();
1013 return clname;
1014}
1015
1016//----------------------------------------------------------------------------
1017static std::set<std::string> sIteratorTypes;
1018bool CPyCppyy::Utility::IsSTLIterator(const std::string& classname)
1019{
1020// attempt to recognize STL iterators (TODO: probably belongs in the backend)
1021 if (sIteratorTypes.empty()) {
1022 std::string tt = "<int>::";
1023 for (auto c : {"std::vector", "std::list", "std::deque"}) {
1024 for (auto i : {"iterator", "const_iterator"}) {
1025 const std::string& itname = Cppyy::ResolveName(c+tt+i);
1026 auto pos = itname.find('<');
1027 if (pos != std::string::npos)
1028 sIteratorTypes.insert(itname.substr(0, pos));
1029 }
1030 }
1031 }
1032
1033 auto pos = classname.find('<');
1034 if (pos != std::string::npos)
1035 return sIteratorTypes.find(classname.substr(0, pos)) != sIteratorTypes.end();
1036 return false;
1037}
1038
1039
1040//----------------------------------------------------------------------------
1042{
1043 Py_XDECREF(fEq);
1044 Py_XDECREF(fNe);
1045 Py_XDECREF(fLAdd); Py_XDECREF(fRAdd);
1046 Py_XDECREF(fSub);
1047 Py_XDECREF(fLMul); Py_XDECREF(fRMul);
1048 Py_XDECREF(fDiv);
1049 Py_XDECREF(fHash);
1050}
1051
1052
1053//----------------------------------------------------------------------------
1055{
1056// Re-acquire the GIL before calling PyErr_Occurred() in case it has been
1057// released; note that the p2.2 code assumes that there are no callbacks in
1058// C++ to python (or at least none returning errors).
1059#if PY_VERSION_HEX >= 0x02030000
1060 PyGILState_STATE gstate = PyGILState_Ensure();
1061 PyObject* e = PyErr_Occurred();
1062 PyGILState_Release(gstate);
1063#else
1064 if (PyThreadState_GET())
1065 return PyErr_Occurred();
1066 PyObject* e = 0;
1067#endif
1068
1069 return e;
1070}
1071
1072
1073//----------------------------------------------------------------------------
1074size_t CPyCppyy::Utility::FetchError(std::vector<PyError_t>& errors, bool is_cpp)
1075{
1076// Fetch the current python error, if any, and store it for future use.
1077 if (PyErr_Occurred()) {
1078 PyError_t e{is_cpp};
1079 PyErr_Fetch(&e.fType, &e.fValue, &e.fTrace);
1080 errors.push_back(e);
1081 }
1082 return errors.size();
1083}
1084
1085//----------------------------------------------------------------------------
1086void CPyCppyy::Utility::SetDetailedException(std::vector<PyError_t>& errors, PyObject* topmsg, PyObject* defexc)
1087{
1088// Use the collected exceptions to build up a detailed error log.
1089 if (errors.empty()) {
1090 // should not happen ...
1091 PyErr_SetString(defexc, CPyCppyy_PyText_AsString(topmsg));
1092 Py_DECREF(topmsg);
1093 return;
1094 }
1095
1096// if a _single_ exception was thrown from C++, assume it has priority (see below)
1097 PyError_t* unique_from_cpp = nullptr;
1098 for (auto& e : errors) {
1099 if (e.fIsCpp) {
1100 if (!unique_from_cpp)
1101 unique_from_cpp = &e;
1102 else {
1103 // two C++ exceptions, resort to default behavior
1104 unique_from_cpp = nullptr;
1105 break;
1106 }
1107 }
1108 }
1109
1110 if (unique_from_cpp) {
1111 // report only this error; the idea here is that all other errors come from
1112 // the bindings (e.g. argument conversion errors), while the exception from
1113 // C++ means that it originated from an otherwise successful call
1114
1115 // bind the original C++ object, rather than constructing from topmsg, as it
1116 // is expected to have informative state
1117 Py_INCREF(unique_from_cpp->fType); Py_INCREF(unique_from_cpp->fValue); Py_XINCREF(unique_from_cpp->fTrace);
1118 PyErr_Restore(unique_from_cpp->fType, unique_from_cpp->fValue, unique_from_cpp->fTrace);
1119 } else {
1120 // try to consolidate Python exceptions, otherwise select default
1121 PyObject* exc_type = nullptr;
1122 for (auto& e : errors) {
1123 if (!exc_type) exc_type = e.fType;
1124 else if (exc_type != e.fType) {
1125 exc_type = defexc;
1126 break;
1127 }
1128 }
1129
1130 // add the details to the topmsg
1131 PyObject* separator = CPyCppyy_PyText_FromString("\n ");
1132 for (auto& e : errors) {
1133 CPyCppyy_PyText_Append(&topmsg, separator);
1134 if (CPyCppyy_PyText_Check(e.fValue)) {
1135 CPyCppyy_PyText_Append(&topmsg, e.fValue);
1136 } else if (e.fValue) {
1137 PyObject* excstr = PyObject_Str(e.fValue);
1138 if (!excstr) {
1139 PyErr_Clear();
1140 excstr = PyObject_Str((PyObject*)Py_TYPE(e.fValue));
1141 }
1142 CPyCppyy_PyText_AppendAndDel(&topmsg, excstr);
1143 } else {
1145 CPyCppyy_PyText_FromString("unknown exception"));
1146 }
1147 }
1148
1149 Py_DECREF(separator);
1150
1151 // set the python exception
1152 PyErr_SetString(exc_type, CPyCppyy_PyText_AsString(topmsg));
1153 }
1154
1155// cleanup stored errors and done with topmsg (whether used or not)
1156 std::for_each(errors.begin(), errors.end(), PyError_t::Clear);
1157 Py_DECREF(topmsg);
1158}
1159
1160
1161//----------------------------------------------------------------------------
1162static bool includesDone = false;
1164{
1165// setup Python API for callbacks
1166 if (!includesDone) {
1167 bool okay = Cppyy::Compile(
1168 // basic API (converters etc.)
1169 "#include \"CPyCppyy/API.h\"\n"
1170
1171 // utilities from the CPyCppyy public API
1172 "#include \"CPyCppyy/DispatchPtr.h\"\n"
1173 "#include \"CPyCppyy/PyException.h\"\n"
1174 );
1175 includesDone = okay;
1176 }
1177
1178 return includesDone;
1179}
#define Py_TYPE(ob)
Definition CPyCppyy.h:196
#define CPPYY__long__
Definition CPyCppyy.h:109
#define CPPYY__div__
Definition CPyCppyy.h:111
PyDictEntry *(* dict_lookup_func)(PyDictObject *, PyObject *, long)
Definition CPyCppyy.h:44
#define CPyCppyy_PyText_InternFromString
Definition CPyCppyy.h:82
int Py_ssize_t
Definition CPyCppyy.h:215
#define PyBytes_Check
Definition CPyCppyy.h:61
#define CPyCppyy_PyText_Append
Definition CPyCppyy.h:83
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:76
#define CPyCppyy_PyText_AppendAndDel
Definition CPyCppyy.h:84
void CPyCppyy_PyBuffer_Release(PyObject *, Py_buffer *view)
Definition CPyCppyy.h:282
#define CPyCppyy_PyText_FromFormat
Definition CPyCppyy.h:80
#define CPyCppyy_PyText_FromString
Definition CPyCppyy.h:81
#define CPPYY__idiv__
Definition CPyCppyy.h:110
#define CPyCppyy_PyText_Check
Definition CPyCppyy.h:74
unsigned long long PY_ULONG_LONG
Definition Cppyy.h:31
long long PY_LONG_LONG
Definition Cppyy.h:23
_object PyObject
#define c(i)
Definition RSha256.hxx:101
#define e(i)
Definition RSha256.hxx:103
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
char name[80]
Definition TGX11.cxx:110
static std::set< std::string > sIteratorTypes
Definition Utility.cxx:1017
static bool includesDone
Definition Utility.cxx:1162
static TC2POperatorMapping_t gC2POperatorMapping
Definition Utility.cxx:32
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:261
static std::set< std::string > gOpRemove
Definition Utility.cxx:34
static std::map< std::string, PyObject * > sStdFuncMakerLookup
Definition Utility.cxx:731
static std::set< std::string > gOpSkip
Definition Utility.cxx:33
static std::map< void *, PyObject * > sStdFuncLookup
Definition Utility.cxx:730
static bool AddTypeName(std::string &tmpl_name, PyObject *tn, PyObject *arg, CPyCppyy::Utility::ArgPreference pref, int *pcnt=nullptr)
Definition Utility.cxx:402
static bool check_scope(const std::string &name)
Definition Utility.cxx:624
std::map< std::string, std::string > TC2POperatorMapping_t
Definition Utility.cxx:31
static std::string AnnotationAsText(PyObject *pyobj)
Definition Utility.cxx:386
const char * proto
Definition civetweb.c:17535
void AdoptMethod(PyCallable *pc)
Cppyy::TCppType_t fCppType
Definition CPPScope.h:55
std::string clean_type(const std::string &cppname, bool template_strip=true, bool const_strip=true)
PyCallable * FindBinaryOperator(PyObject *left, PyObject *right, const char *op, Cppyy::TCppScope_t scope=0)
Definition Utility.cxx:294
void ConstructCallbackPreamble(const std::string &retType, const std::vector< std::string > &argtypes, std::ostringstream &code)
Definition Utility.cxx:629
void ConstructCallbackReturn(const std::string &retType, int nArgs, std::ostringstream &code)
Definition Utility.cxx:695
Py_ssize_t GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, bool check=true)
Definition Utility.cxx:808
std::string ConstructTemplateArgs(PyObject *pyname, PyObject *tpArgs, PyObject *args=nullptr, ArgPreference=kNone, int argoff=0, int *pcnt=nullptr)
Definition Utility.cxx:580
PyObject * FuncPtr2StdFunction(const std::string &retType, const std::string &signature, void *address)
Definition Utility.cxx:732
PyCallable * FindUnaryOperator(PyObject *pyclass, const char *op)
Definition Utility.cxx:279
size_t FetchError(std::vector< PyError_t > &, bool is_cpp=false)
Definition Utility.cxx:1074
std::string MapOperatorName(const std::string &name, bool bTakesParames, bool *stubbed=nullptr)
Definition Utility.cxx:932
void SetDetailedException(std::vector< PyError_t > &errors, PyObject *topmsg, PyObject *defexc)
Definition Utility.cxx:1086
bool InitProxy(PyObject *module, PyTypeObject *pytype, const char *name)
Definition Utility.cxx:788
bool AddToClass(PyObject *pyclass, const char *label, PyCFunction cfunc, int flags=METH_VARARGS)
Definition Utility.cxx:182
bool IsSTLIterator(const std::string &classname)
Definition Utility.cxx:1018
std::string ClassName(PyObject *pyobj)
Definition Utility.cxx:997
PyObject * PyErr_Occurred_WithGIL()
Definition Utility.cxx:1054
CPPOverload * CPPOverload_New(const std::string &name, std::vector< PyCallable * > &methods)
unsigned long PyLongOrInt_AsULong(PyObject *pyobject)
Definition Utility.cxx:129
PyObject * gDefaultObject
PyObject * CustomInstanceMethod_New(PyObject *func, PyObject *self, PyObject *pyclass)
bool gDictLookupActive
Definition Utility.cxx:28
dict_lookup_func gDictLookupOrg
Definition Utility.cxx:27
PyObject * CreateScopeProxy(Cppyy::TCppScope_t, const unsigned flags=0)
bool CPPOverload_Check(T *object)
Definition CPPOverload.h:90
bool CPPScope_Check(T *object)
Definition CPPScope.h:81
PY_ULONG_LONG PyLongOrInt_AsULong64(PyObject *pyobject)
Definition Utility.cxx:156
bool CPPInstance_Check(T *object)
PyObject * gNullPtrObject
size_t TCppIndex_t
Definition cpp_cppyy.h:24
intptr_t TCppMethod_t
Definition cpp_cppyy.h:22
RPY_EXPORTED bool Compile(const std::string &code, bool silent=false)
RPY_EXPORTED TCppScope_t gGlobalScope
Definition cpp_cppyy.h:53
RPY_EXPORTED TCppMethod_t GetMethodTemplate(TCppScope_t scope, const std::string &name, const std::string &proto)
RPY_EXPORTED std::string ResolveName(const std::string &cppitem_name)
RPY_EXPORTED std::string GetScopedFinalName(TCppType_t type)
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
size_t TCppScope_t
Definition cpp_cppyy.h:18
RPY_EXPORTED TCppIndex_t GetGlobalOperator(TCppType_t scope, const std::string &lc, const std::string &rc, const std::string &op)
static void Clear(PyError_t &e)
Definition Utility.h:90
TLine l
Definition textangle.C:4
auto * tt
Definition textangle.C:16