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