Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
CPPOverload.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "CPyCppyy/Reflex.h"
4#include "structmember.h" // from Python
5#if PY_VERSION_HEX >= 0x02050000
6#if PY_VERSION_HEX < 0x030b0000
7#include "code.h" // from Python
8#endif
9#else
10#include "compile.h" // from Python
11#endif
12#ifndef CO_NOFREE
13// python2.2 does not have CO_NOFREE defined
14#define CO_NOFREE 0x0040
15#endif
16#include "CPPOverload.h"
17#include "CPPInstance.h"
18#include "CallContext.h"
19#include "PyStrings.h"
20#include "Utility.h"
21
22// Standard
23#include <algorithm>
24#include <sstream>
25#include <vector>
26
27
28namespace CPyCppyy {
29
30namespace {
31
32// from CPython's instancemethod: Free list for method objects to safe malloc/free overhead
33// The fSelf field is used to chain the elements.
34static CPPOverload* free_list;
35static int numfree = 0;
36#ifndef CPPOverload_MAXFREELIST
37#define CPPOverload_MAXFREELIST 32
38#endif
39
40
41// TODO: only used in pythonizations to add Python-side overloads to existing
42// C++ overloads, but may be better off integrated with Pythonize.cxx callbacks
43class TPythonCallback : public PyCallable {
44public:
46
47 TPythonCallback(PyObject* callable) : fCallable(nullptr)
48 {
50 PyErr_SetString(PyExc_TypeError, "parameter must be callable");
51 return;
52 }
55 }
56
57 ~TPythonCallback() override {
58 Py_DECREF(fCallable);
59 fCallable = nullptr;
60 }
61
62 PyObject* GetSignature(bool /*show_formalargs*/ = true) override {
63 return CPyCppyy_PyText_FromString("*args, **kwargs");
64 }
65 PyObject* GetSignatureNames() override {
66 return PyTuple_New(0);
67 }
68 PyObject* GetSignatureTypes() override {
69 return PyTuple_New(0);
70 }
71 PyObject* GetPrototype(bool /*show_formalargs*/ = true) override {
72 return CPyCppyy_PyText_FromString("<callback>");
73 }
74 PyObject* GetDocString() override {
75 if (PyObject_HasAttrString(fCallable, "__doc__")) {
76 return PyObject_GetAttrString(fCallable, "__doc__");
77 } else {
78 return GetPrototype();
79 }
80 }
81
82 int GetPriority() override { return 100; };
83 bool IsGreedy() override { return false; };
84
85 int GetMaxArgs() override { return 100; };
86 PyObject* GetCoVarNames() override { // TODO: pick these up from the callable
88 }
89 PyObject* GetArgDefault(int /* iarg */, bool /* silent */ =true) override {
90 Py_RETURN_NONE; // TODO: pick these up from the callable
91 }
92
93 PyObject* GetScopeProxy() override { // should this be the module ??
95 }
96
98 return (Cppyy::TCppFuncAddr_t)nullptr;
99 }
100
101 PyCallable* Clone() override { return new TPythonCallback(*this); }
102
103 PyObject* Call(CPPInstance*& self,
104 CPyCppyy_PyArgs_t args, size_t nargsf, PyObject* kwds, CallContext* /* ctxt = 0 */) override {
105
106#if PY_VERSION_HEX >= 0x03080000
107 if (self) {
108 if (nargsf & PY_VECTORCALL_ARGUMENTS_OFFSET) { // mutation allowed?
109 std::swap(((PyObject**)args-1)[0], (PyObject*&)self);
111 args = args-1;
112 } else {
116 if (!newArgs)
117 return nullptr;
118
119 newArgs[0] = (PyObject*)self;
120 if (0 < totalargs)
121 memcpy((void*)&newArgs[1], args, totalargs * sizeof(PyObject*));
122 args = newArgs;
123 }
124 nargsf += 1;
125 }
126
127 PyObject* result = CPyCppyy_PyObject_Call(fCallable, args, nargsf, kwds);
128 if (self) {
130 std::swap(((PyObject**)args-1)[0], (PyObject*&)self);
131 else PyMem_Free((void*)args);
132 }
133#else
134 PyObject* newArgs = nullptr;
135 if (self) {
140 for (Py_ssize_t iarg = 0; iarg < nargs; ++iarg) {
144 }
145 } else {
146 Py_INCREF(args);
147 newArgs = args;
148 }
149 PyObject* result = PyObject_Call(fCallable, newArgs, kwds);
151#endif
152 return result;
153 }
154};
155
156// helper to test whether a method is used in a pseudo-function modus
157static inline bool IsPseudoFunc(CPPOverload* pymeth)
158{
159 return pymeth->fMethodInfo->fFlags & CallContext::kIsPseudoFunc;
160}
161
162// helper to sort on method priority
163static int PriorityCmp(const std::pair<int, PyCallable*>& left, const std::pair<int, PyCallable*>& right)
164{
165 return left.first > right.first;
166}
167
168// return helper
169static inline void ResetCallState(CPPInstance* descr_self, CPPInstance*& im_self)
170{
171// reset self if needed, allowing simple re-use
172 if (descr_self != im_self) {
175 }
176}
177
178// helper to factor out return logic of mp_call / mp_vectorcall
179static inline PyObject* HandleReturn(
180 CPPOverload* pymeth, CPPInstance* im_self, PyObject* result)
181{
182// special case for python exceptions, propagated through C++ layer
183 if (result) {
184 CPPInstance* cppres = (CPPInstance*)(CPPInstance_Check(result) ? result : nullptr);
185
186 // if this method creates new objects, always take ownership
187 if (IsCreator(pymeth->fMethodInfo->fFlags)) {
188
189 // either be a constructor with a fresh object proxy self ...
190 if (IsConstructor(pymeth->fMethodInfo->fFlags)) {
191 if (im_self)
192 im_self->PythonOwns();
193 }
194
195 // ... or be a regular method with an object proxy return value
196 else if (cppres)
197 cppres->PythonOwns();
198 }
199
200 // if this new object falls inside self, make sure its lifetime is proper
201 if (!(pymeth->fMethodInfo->fFlags & CallContext::kNeverLifeLine)) {
202 int ll_action = 0;
203 if ((PyObject*)im_self != result) {
204 if (pymeth->fMethodInfo->fFlags & CallContext::kSetLifeLine)
205 ll_action = 1;
206 else if (cppres && CPPInstance_Check(im_self)) {
207 // if self was a by-value return and result is not, pro-actively protect result;
208 // else if the return value falls within the memory of 'this', force a lifeline
209 if (!(cppres->fFlags & CPPInstance::kIsValue)) { // no need if the result is temporary
210 if (im_self->fFlags & CPPInstance::kIsValue)
211 ll_action = 2;
212 else if (im_self->fFlags & CPPInstance::kHasLifeLine)
213 ll_action = 3;
214 else {
215 ptrdiff_t offset = (ptrdiff_t)cppres->GetObject() - (ptrdiff_t)im_self->GetObject();
216 if (0 <= offset && offset < (ptrdiff_t)Cppyy::SizeOf(im_self->ObjectIsA()))
217 ll_action = 4;
218 }
219 }
220 }
221 }
222
223 if (!ll_action)
224 pymeth->fMethodInfo->fFlags |= CallContext::kNeverLifeLine; // assume invariant semantics
225 else {
227 PyErr_Clear(); // ignored
228 if (cppres) cppres->fFlags |= CPPInstance::kHasLifeLine; // for chaining
229 pymeth->fMethodInfo->fFlags |= CallContext::kSetLifeLine; // for next time
230 }
231 }
232 }
233
234// reset self as necessary to allow re-use of the CPPOverload
236
237 return result;
238}
239
240
241//= CPyCppyy method proxy object behaviour ===================================
242static PyObject* mp_name(CPPOverload* pymeth, void*)
243{
244 return CPyCppyy_PyText_FromString(pymeth->GetName().c_str());
245}
246
247//----------------------------------------------------------------------------
248static PyObject* mp_module(CPPOverload* /* pymeth */, void*)
249{
252}
253
254//----------------------------------------------------------------------------
255static PyObject* mp_doc(CPPOverload* pymeth, void*)
256{
257 if (pymeth->fMethodInfo->fDoc) {
258 Py_INCREF(pymeth->fMethodInfo->fDoc);
259 return pymeth->fMethodInfo->fDoc;
260 }
261
262// Build python document string ('__doc__') from all C++-side overloads.
263 CPPOverload::Methods_t& methods = pymeth->fMethodInfo->fMethods;
264
265// collect doc strings
266 CPPOverload::Methods_t::size_type nMethods = methods.size();
267 if (nMethods == 0) // from template proxy with no instantiations
268 return nullptr;
269 PyObject* doc = methods[0]->GetDocString();
270
271// simple case
272 if (nMethods == 1)
273 return doc;
274
275// overloaded method
276 PyObject* separator = CPyCppyy_PyText_FromString("\n");
277 for (CPPOverload::Methods_t::size_type i = 1; i < nMethods; ++i) {
278 CPyCppyy_PyText_Append(&doc, separator);
279 CPyCppyy_PyText_AppendAndDel(&doc, methods[i]->GetDocString());
280 }
281 Py_DECREF(separator);
282
283 return doc;
284}
285
286static int mp_doc_set(CPPOverload* pymeth, PyObject *val, void *)
287{
288 Py_XDECREF(pymeth->fMethodInfo->fDoc);
289 Py_INCREF(val);
290 pymeth->fMethodInfo->fDoc = val;
291 return 0;
292}
293
294/**
295 * @brief Returns a dictionary with the input parameter names for all overloads.
296 *
297 * This dictionary may look like:
298 *
299 * {'double ::foo(int a, float b, double c)': ('a', 'b', 'c'),
300 * 'float ::foo(float b)': ('b',),
301 * 'int ::foo(int a)': ('a',),
302 * 'int ::foo(int a, float b)': ('a', 'b')}
303 */
304static PyObject *mp_func_overloads_names(CPPOverload *pymeth)
305{
306
307 const CPPOverload::Methods_t &methods = pymeth->fMethodInfo->fMethods;
308
310
311 for (PyCallable *method : methods) {
312 PyDict_SetItem(overloads_names_dict, method->GetPrototype(), method->GetSignatureNames());
313 }
314
316}
317
318/**
319 * @brief Returns a dictionary with the types of all overloads.
320 *
321 * This dictionary may look like:
322 *
323 * {'double ::foo(int a, float b, double c)': {'input_types': ('int', 'float', 'double'), 'return_type': 'double'},
324 * 'float ::foo(float b)': {'input_types': ('float',), 'return_type': 'float'},
325 * 'int ::foo(int a)': {'input_types': ('int',), 'return_type': 'int'},
326 * 'int ::foo(int a, float b)': {'input_types': ('int', 'float'), 'return_type': 'int'}}
327 */
328static PyObject *mp_func_overloads_types(CPPOverload *pymeth)
329{
330
331 const CPPOverload::Methods_t &methods = pymeth->fMethodInfo->fMethods;
332
334
335 for (PyCallable *method : methods) {
336 PyDict_SetItem(overloads_types_dict, method->GetPrototype(), method->GetSignatureTypes());
337 }
338
340}
341
342//----------------------------------------------------------------------------
343static PyObject* mp_meth_func(CPPOverload* pymeth, void*)
344{
345// Create a new method proxy to be returned.
346 CPPOverload* newPyMeth = (CPPOverload*)CPPOverload_Type.tp_alloc(&CPPOverload_Type, 0);
347
348// method info is shared, as it contains the collected overload knowledge
349 *pymeth->fMethodInfo->fRefCount += 1;
350 newPyMeth->fMethodInfo = pymeth->fMethodInfo;
351
352// new method is unbound, track whether this proxy is used in the capacity of a
353// method or a function (which normally is a CPPFunction)
354 newPyMeth->fMethodInfo->fFlags |= CallContext::kIsPseudoFunc;
355
356 return (PyObject*)newPyMeth;
357}
358
359//----------------------------------------------------------------------------
360static PyObject* mp_meth_self(CPPOverload* pymeth, void*)
361{
362// Return the bound self, if any; in case of pseudo-function role, pretend
363// that the data member im_self does not exist.
364 if (IsPseudoFunc(pymeth)) {
366 "function %s has no attribute \'im_self\'", pymeth->fMethodInfo->fName.c_str());
367 return nullptr;
368 } else if (pymeth->fSelf != 0) {
369 Py_INCREF((PyObject*)pymeth->fSelf);
370 return (PyObject*)pymeth->fSelf;
371 }
372
374}
375
376//----------------------------------------------------------------------------
377static PyObject* mp_meth_class(CPPOverload* pymeth, void*)
378{
379// Return scoping class; in case of pseudo-function role, pretend that there
380// is no encompassing class (i.e. global scope).
381 if (!IsPseudoFunc(pymeth) && pymeth->fMethodInfo->fMethods.size()) {
382 PyObject* pyclass = pymeth->fMethodInfo->fMethods[0]->GetScopeProxy();
383 if (!pyclass)
385 "function %s has no attribute \'im_class\'", pymeth->fMethodInfo->fName.c_str());
386 return pyclass;
387 }
388
390}
391
392//----------------------------------------------------------------------------
393static PyObject* mp_func_closure(CPPOverload* /* pymeth */, void*)
394{
395// Stub only, to fill out the python function interface.
397}
398
399// To declare a variable as unused only when compiling for Python 3.
400#if PY_VERSION_HEX < 0x03000000
401#define CPyCppyy_Py3_UNUSED(name) name
402#else
403#define CPyCppyy_Py3_UNUSED(name)
404#endif
405
406//----------------------------------------------------------------------------
407static PyObject* mp_func_code(CPPOverload* CPyCppyy_Py3_UNUSED(pymeth), void*)
408{
409// Code details are used in module inspect to fill out interactive help()
410#if PY_VERSION_HEX < 0x03000000
411 CPPOverload::Methods_t& methods = pymeth->fMethodInfo->fMethods;
412
413// collect arguments only if there is just 1 overload, otherwise put in a
414// fake *args (see below for co_varnames)
415 PyObject* co_varnames = methods.size() == 1 ? methods[0]->GetCoVarNames() : nullptr;
416 if (!co_varnames) {
417 // TODO: static methods need no 'self' (but is harmless otherwise)
418 co_varnames = PyTuple_New(1 /* self */ + 1 /* fake */);
421 }
422
424
425// for now, code object representing the statement 'pass'
426 PyObject* co_code = PyString_FromStringAndSize("d\x00\x00S", 4);
427
428// tuples with all the const literals used in the function
431
432// names, freevars, and cellvars go unused
434
435// filename is made-up
437
438// name is the function name, also through __name__ on the function itself
439 PyObject* co_name = PyString_FromString(pymeth->GetName().c_str());
440
441// firstlineno is the line number of first function code in the containing scope
442
443// lnotab is a packed table that maps instruction count and line number
444 PyObject* co_lnotab = PyString_FromString("\x00\x01\x0c\x01");
445
446 PyObject* code = (PyObject*)PyCode_New(
447 co_argcount, // argcount
448 co_argcount+1, // nlocals
449 2, // stacksize
451 co_code, // code
452 co_consts, // consts
453 co_names, // names
454 co_varnames, // varnames
455 co_unused, // freevars
456 co_unused, // cellvars
457 co_filename, // filename
458 co_name, // name
459 1, // firstlineno
460 co_lnotab); // lnotab
461
470
471 return code;
472#else
473// not important for functioning of most code, so not implemented for p3 for now (TODO)
475#endif
476}
477
478//----------------------------------------------------------------------------
479static PyObject* mp_func_defaults(CPPOverload* pymeth, void*)
480{
481// Create a tuple of default values, if there is only one method (otherwise
482// leave undefined: this is only used by inspect for interactive help())
483 CPPOverload::Methods_t& methods = pymeth->fMethodInfo->fMethods;
484
485 if (methods.size() != 1)
486 return PyTuple_New(0);
487
488 int maxarg = methods[0]->GetMaxArgs();
489
491
492 int itup = 0;
493 for (int iarg = 0; iarg < maxarg; ++iarg) {
494 PyObject* defvalue = methods[0]->GetArgDefault(iarg);
495 if (defvalue)
497 else
498 PyErr_Clear();
499 }
501
502 return defaults;
503}
504
505//----------------------------------------------------------------------------
506static PyObject* mp_func_globals(CPPOverload* /* pymeth */, void*)
507{
508// Return this function's global dict (hard-wired to be the cppyy module); used
509// for lookup of names from co_code indexing into co_names.
512 return pyglobal;
513}
514
515//----------------------------------------------------------------------------
516static inline int set_flag(CPPOverload* pymeth, PyObject* value, CallContext::ECallFlags flag, const char* name)
517{
518// Generic setter of a (boolean) flag.
519 if (!value) { // accept as false (delete)
520 pymeth->fMethodInfo->fFlags &= ~flag;
521 return 0;
522 }
523
524 long istrue = PyLong_AsLong(value);
525 if (istrue == -1 && PyErr_Occurred()) {
526 PyErr_Format(PyExc_ValueError, "a boolean 1 or 0 is required for %s", name);
527 return -1;
528 }
529
530 if (istrue)
531 pymeth->fMethodInfo->fFlags |= flag;
532 else
533 pymeth->fMethodInfo->fFlags &= ~flag;
534
535 return 0;
536}
537
538//----------------------------------------------------------------------------
539static PyObject* mp_getcreates(CPPOverload* pymeth, void*)
540{
541// Get '__creates__' boolean, which determines ownership of return values.
542 return PyInt_FromLong((long)IsCreator(pymeth->fMethodInfo->fFlags));
543}
544
545//----------------------------------------------------------------------------
546static int mp_setcreates(CPPOverload* pymeth, PyObject* value, void*)
547{
548// Set '__creates__' boolean, which determines ownership of return values.
549 return set_flag(pymeth, value, CallContext::kIsCreator, "__creates__");
550}
551
552//----------------------------------------------------------------------------
553static PyObject* mp_getmempolicy(CPPOverload* pymeth, void*)
554{
555// Get '_mempolicy' enum, which determines ownership of call arguments.
556 if (pymeth->fMethodInfo->fFlags & CallContext::kUseHeuristics)
558
559 if (pymeth->fMethodInfo->fFlags & CallContext::kUseStrict)
561
562 return PyInt_FromLong(-1);
563}
564
565//----------------------------------------------------------------------------
566static int mp_setmempolicy(CPPOverload* pymeth, PyObject* value, void*)
567{
568// Set '_mempolicy' enum, which determines ownership of call arguments.
571 pymeth->fMethodInfo->fFlags |= CallContext::kUseHeuristics;
572 pymeth->fMethodInfo->fFlags &= ~CallContext::kUseStrict;
573 } else if (mempolicy == CallContext::kUseStrict) {
574 pymeth->fMethodInfo->fFlags |= CallContext::kUseStrict;
575 pymeth->fMethodInfo->fFlags &= ~CallContext::kUseHeuristics;
576 } else {
578 "expected kMemoryStrict or kMemoryHeuristics as value for __mempolicy__");
579 return -1;
580 }
581
582 return 0;
583}
584
585
586//----------------------------------------------------------------------------
587#define CPPYY_BOOLEAN_PROPERTY(name, flag, label) \
588static PyObject* mp_get##name(CPPOverload* pymeth, void*) { \
589 if (pymeth->fMethodInfo->fFlags & flag) { \
590 Py_RETURN_TRUE; \
591 } \
592 Py_RETURN_FALSE; \
593} \
594 \
595static int mp_set##name(CPPOverload* pymeth, PyObject* value, void*) { \
596 return set_flag(pymeth, value, flag, label); \
597}
598
600CPPYY_BOOLEAN_PROPERTY(threaded, CallContext::kReleaseGIL, "__release_gil__")
601CPPYY_BOOLEAN_PROPERTY(useffi, CallContext::kUseFFI, "__useffi__")
602CPPYY_BOOLEAN_PROPERTY(sig2exc, CallContext::kProtected, "__sig2exc__")
603
604static PyObject* mp_getcppname(CPPOverload* pymeth, void*)
605{
606 if ((void*)pymeth == (void*)&CPPOverload_Type)
607 return CPyCppyy_PyText_FromString("CPPOverload_Type");
608
609 auto& methods = pymeth->fMethodInfo->fMethods;
610 if (methods.empty())
611 return CPyCppyy_PyText_FromString("void (*)()"); // debatable
612
613 if (methods.size() == 1)
614 return methods[0]->GetTypeName();
615
616 return CPyCppyy_PyText_FromString("void* (*)(...)"); // id.
617}
618
619
620//----------------------------------------------------------------------------
621static PyGetSetDef mp_getset[] = {
622 {(char*)"__name__", (getter)mp_name, nullptr, nullptr, nullptr},
623 {(char*)"__module__", (getter)mp_module, nullptr, nullptr, nullptr},
624 {(char*)"__doc__", (getter)mp_doc, (setter)mp_doc_set, nullptr, nullptr},
625
626// to be more python-like, where these are duplicated as well; to actually
627// derive from the python method or function type is too memory-expensive,
628// given that most of the members of those types would not be used
629 {(char*)"im_func", (getter)mp_meth_func, nullptr, nullptr, nullptr},
630 {(char*)"im_self", (getter)mp_meth_self, nullptr, nullptr, nullptr},
631 {(char*)"im_class", (getter)mp_meth_class, nullptr, nullptr, nullptr},
632
633 {(char*)"func_closure", (getter)mp_func_closure, nullptr, nullptr, nullptr},
634 {(char*)"func_code", (getter)mp_func_code, nullptr, nullptr, nullptr},
635 {(char*)"func_defaults", (getter)mp_func_defaults, nullptr, nullptr, nullptr},
636 {(char*)"func_globals", (getter)mp_func_globals, nullptr, nullptr, nullptr},
637 {(char*)"func_doc", (getter)mp_doc, (setter)mp_doc_set, nullptr, nullptr},
638 {(char*)"func_name", (getter)mp_name, nullptr, nullptr, nullptr},
639 {(char*)"func_overloads_types", (getter)mp_func_overloads_types, nullptr, nullptr, nullptr},
640 {(char*)"func_overloads_names", (getter)mp_func_overloads_names, nullptr, nullptr, nullptr},
641
642
643// flags to control behavior
644 {(char*)"__creates__", (getter)mp_getcreates, (setter)mp_setcreates,
645 (char*)"For ownership rules of result: if true, objects are python-owned", nullptr},
646 {(char*)"__mempolicy__", (getter)mp_getmempolicy, (setter)mp_setmempolicy,
647 (char*)"For argument ownership rules: like global, either heuristic or strict", nullptr},
648 {(char*)"__set_lifeline__", (getter)mp_getlifeline, (setter)mp_setlifeline,
649 (char*)"If true, set a lifeline from the return value onto self", nullptr},
650 {(char*)"__release_gil__", (getter)mp_getthreaded, (setter)mp_setthreaded,
651 (char*)"If true, releases GIL on call into C++", nullptr},
652 {(char*)"__useffi__", (getter)mp_getuseffi, (setter)mp_setuseffi,
653 (char*)"not implemented", nullptr},
654 {(char*)"__sig2exc__", (getter)mp_getsig2exc, (setter)mp_setsig2exc,
655 (char*)"If true, turn signals into Python exceptions", nullptr},
656
657// basic reflection information
658 {(char*)"__cpp_name__", (getter)mp_getcppname, nullptr, nullptr, nullptr},
659
660 {(char*)nullptr, nullptr, nullptr, nullptr, nullptr}
661};
662
663//= CPyCppyy method proxy function behavior ==================================
664#if PY_VERSION_HEX >= 0x03080000
665static PyObject* mp_vectorcall(
666 CPPOverload* pymeth, PyObject* const *args, size_t nargsf, PyObject* kwds)
667#else
668static PyObject* mp_call(CPPOverload* pymeth, PyObject* args, PyObject* kwds)
669#endif
670{
671#if PY_VERSION_HEX < 0x03080000
672 size_t nargsf = PyTuple_GET_SIZE(args);
673#endif
674
675// Call the appropriate overload of this method.
676
677// If called from a descriptor, then this could be a bound function with
678// non-zero self; otherwise pymeth->fSelf is expected to always be nullptr.
679
680 CPPInstance* im_self = pymeth->fSelf;
681
682// get local handles to proxy internals
683 auto& methods = pymeth->fMethodInfo->fMethods;
684
685 CPPOverload::Methods_t::size_type nMethods = methods.size();
686
687 CallContext ctxt{};
688 const auto mflags = pymeth->fMethodInfo->fFlags;
690 ctxt.fFlags |= mempolicy ? mempolicy : (uint64_t)CallContext::sMemoryPolicy;
692 ctxt.fFlags |= (mflags & CallContext::kProtected);
693 if (IsConstructor(pymeth->fMethodInfo->fFlags)) ctxt.fFlags |= CallContext::kIsConstructor;
695 ctxt.fPyContext = (PyObject*)im_self; // no Py_INCREF as no ownership
696
697// check implicit conversions status (may be disallowed to prevent recursion)
698 ctxt.fFlags |= (pymeth->fFlags & CallContext::kNoImplicit);
699
700// simple case
701 if (nMethods == 1) {
702 if (!NoImplicit(&ctxt)) ctxt.fFlags |= CallContext::kAllowImplicit; // no two rounds needed
703 PyObject* result = methods[0]->Call(im_self, args, nargsf, kwds, &ctxt);
704 return HandleReturn(pymeth, im_self, result);
705 }
706
707// otherwise, handle overloading
708 uint64_t sighash = HashSignature(args, nargsf);
709
710// look for known signatures ...
711 auto& dispatchMap = pymeth->fMethodInfo->fDispatchMap;
712 PyCallable* memoized_pc = nullptr;
713 for (const auto& p : dispatchMap) {
714 if (p.first == sighash) {
715 memoized_pc = p.second;
716 break;
717 }
718 }
719 if (memoized_pc) {
720 // it is necessary to enable implicit conversions as the memoized call may be from
721 // such a conversion case; if the call fails, the implicit flag is reset below
723 PyObject* result = memoized_pc->Call(im_self, args, nargsf, kwds, &ctxt);
724 if (result)
725 return HandleReturn(pymeth, im_self, result);
726
727 // fall through: python is dynamic, and so, the hashing isn't infallible
728 ctxt.fFlags &= ~CallContext::kAllowImplicit;
729 PyErr_Clear();
731 }
732
733// ... otherwise loop over all methods and find the one that does not fail
734 if (!IsSorted(mflags)) {
735 // sorting is based on priority, which is not stored on the method as it is used
736 // only once, so copy the vector of methods into one where the priority can be
737 // stored during sorting
738 std::vector<std::pair<int, PyCallable*>> pm; pm.reserve(methods.size());
739 for (auto ptr : methods)
740 pm.emplace_back(ptr->GetPriority(), ptr);
741 std::stable_sort(pm.begin(), pm.end(), PriorityCmp);
742 for (CPPOverload::Methods_t::size_type i = 0; i < methods.size(); ++i)
743 methods[i] = pm[i].second;
744 pymeth->fMethodInfo->fFlags |= CallContext::kIsSorted;
745 }
746
747 std::vector<Utility::PyError_t> errors;
748 std::vector<bool> implicit_possible(methods.size());
749 for (int stage = 0; stage < 2; ++stage) {
750 bool bHaveImplicit = false;
751 for (CPPOverload::Methods_t::size_type i = 0; i < nMethods; ++i) {
752 if (stage && !implicit_possible[i])
753 continue; // did not set implicit conversion, so don't try again
754
755 PyObject* result = methods[i]->Call(im_self, args, nargsf, kwds, &ctxt);
756 if (result) {
757 // success: update the dispatch map for subsequent calls
758 if (!memoized_pc)
759 dispatchMap.push_back(std::make_pair(sighash, methods[i]));
760 else {
761 // debatable: apparently there are two methods that map onto the same sighash
762 // and preferring the latest may result in "ping pong."
763 for (auto& p : dispatchMap) {
764 if (p.first == sighash) {
765 p.second = methods[i];
766 break;
767 }
768 }
769 }
770
771 return HandleReturn(pymeth, im_self, result);
772 }
773
774 // else failure ..
775 if (stage != 0) {
776 PyErr_Clear(); // first stage errors should be the more informative
778 continue;
779 }
780
781 // collect error message/trace (automatically clears exception, too)
782 if (!PyErr_Occurred()) {
783 // this should not happen; set an error to prevent core dump and report
784 PyObject* sig = methods[i]->GetPrototype();
785 PyErr_Format(PyExc_SystemError, "%s =>\n %s",
786 CPyCppyy_PyText_AsString(sig), (char*)"nullptr result without error in overload call");
787 Py_DECREF(sig);
788 }
789
790 // retrieve, store, and clear errors
794
795 if (HaveImplicit(&ctxt)) {
796 bHaveImplicit = true;
797 implicit_possible[i] = true;
798 ctxt.fFlags &= ~CallContext::kHaveImplicit;
799 } else
800 implicit_possible[i] = false;
802 }
803
804 // only move forward if implicit conversions are available
805 if (!bHaveImplicit)
806 break;
807
809 }
810
811// first summarize, then add details
813 "none of the %d overloaded methods succeeded. Full details:", (int)nMethods);
814 SetDetailedException(std::move(errors), topmsg /* steals */, PyExc_TypeError /* default error */);
815
816// report failure
817 return nullptr;
818}
819
820//----------------------------------------------------------------------------
821static PyObject* mp_str(CPPOverload* cppinst)
822{
823// Print a description that includes the C++ name
824 std::ostringstream s;
825 s << "<C++ overload \"" << cppinst->fMethodInfo->fName << "\" at " << (void*)cppinst << ">";
826 return CPyCppyy_PyText_FromString(s.str().c_str());
827}
828
829//----------------------------------------------------------------------------
830static CPPOverload* mp_descr_get(CPPOverload* pymeth, CPPInstance* pyobj, PyObject*)
831{
832// Descriptor; create and return a new, possibly bound, method proxy. This method
833// has evolved with versions of python as follows:
834//
835// Python version | Action
836// <- py2.7 | bound methods need to be first-class objects, so create a new
837// | method object if self is not nullptr or Py_None
838// py3.0-py3.7 | bound methods are no longer a language requirement, but
839// | still supported: for convenience, retain old behavior
840// py3.8 <= | vector calls no longer call the descriptor, so when it is
841// | called, the method is likely stored, so should be new object
842
843#if PY_VERSION_HEX < 0x03080000
844 if (!pyobj || (PyObject*)pyobj == Py_None /* from unbound TemplateProxy */) {
845 Py_XDECREF(pymeth->fSelf); pymeth->fSelf = nullptr;
848 return pymeth; // unbound, e.g. free functions
849 }
850#endif
851
852// create a new method object
853 bool gc_track = false;
854 CPPOverload* newPyMeth = free_list;
855 if (newPyMeth != NULL) {
856 free_list = (CPPOverload*)(newPyMeth->fSelf);
858 numfree--;
859 } else {
861 if (!newPyMeth)
862 return nullptr;
863 gc_track = true;
864 }
865
866// method info is shared, as it contains the collected overload knowledge
867 *pymeth->fMethodInfo->fRefCount += 1;
868 newPyMeth->fMethodInfo = pymeth->fMethodInfo;
869
870#if PY_VERSION_HEX >= 0x03080000
871 newPyMeth->fVectorCall = pymeth->fVectorCall;
872
873 if (pyobj && (PyObject*)pyobj != Py_None) {
875 newPyMeth->fSelf = pyobj;
877 } else {
878 newPyMeth->fSelf = nullptr;
880 }
881
882// vector calls don't get here, unless a method is looked up on an instance, for
883// e.g. class methods (C++ static); notify downstream to expect a 'self'
885
886#else
887// new method is to be bound to current object
889 newPyMeth->fSelf = pyobj;
890
891// reset flags of the new method, as there is a self (which may or may not have
892// come in through direct call syntax, but that's now impossible to know, so this
893// is the safer choice)
895#endif
896
897 if (gc_track)
899
900 return newPyMeth;
901}
902
903
904//= CPyCppyy method proxy construction/destruction ===========================
905static CPPOverload* mp_new(PyTypeObject*, PyObject*, PyObject*)
906{
907// Create a new method proxy object.
908 CPPOverload* pymeth = PyObject_GC_New(CPPOverload, &CPPOverload_Type);
909 pymeth->fSelf = nullptr;
910 pymeth->fFlags = CallContext::kNone;
911 pymeth->fMethodInfo = new CPPOverload::MethodInfo_t;
912
914 return pymeth;
915}
916
917//----------------------------------------------------------------------------
918static void mp_dealloc(CPPOverload* pymeth)
919{
920// Deallocate memory held by method proxy object.
922
923 Py_CLEAR(pymeth->fSelf);
924
925 if (--(*pymeth->fMethodInfo->fRefCount) <= 0) {
926 delete pymeth->fMethodInfo;
927 }
928
932 numfree++;
933 } else {
935 }
936}
937
938//----------------------------------------------------------------------------
939static Py_ssize_t mp_hash(CPPOverload* pymeth)
940{
941// Hash of method proxy object for insertion into dictionaries; with actual
942// method (fMethodInfo) shared, its address is best suited.
943#if PY_VERSION_HEX >= 0x030d0000
944 return Py_HashPointer(pymeth->fMethodInfo);
945#else
946 return _Py_HashPointer(pymeth->fMethodInfo);
947#endif
948}
949
950//----------------------------------------------------------------------------
951static int mp_traverse(CPPOverload* pymeth, visitproc visit, void* args)
952{
953// Garbage collector traverse of held python member objects.
954 if (pymeth->fSelf)
955 return visit((PyObject*)pymeth->fSelf, args);
956
957 return 0;
958}
959
960//----------------------------------------------------------------------------
961static int mp_clear(CPPOverload* pymeth)
962{
963// Garbage collector clear of held python member objects.
964 Py_CLEAR(pymeth->fSelf);
965
966 return 0;
967}
968
969//----------------------------------------------------------------------------
970static PyObject* mp_richcompare(CPPOverload* self, CPPOverload* other, int op)
971{
972// Rich set of comparison objects; only equals is defined.
973 if (op != Py_EQ)
974 return PyType_Type.tp_richcompare((PyObject*)self, (PyObject*)other, op);
975
976// defined by type + (shared) MethodInfo + bound self, with special case for
977// fSelf (i.e. pseudo-function)
978 if ((Py_TYPE(self) == Py_TYPE(other) && self->fMethodInfo == other->fMethodInfo) && \
979 ((IsPseudoFunc(self) && IsPseudoFunc(other)) || self->fSelf == other->fSelf)) {
981 }
983}
984
985
986//= CPyCppyy method proxy access to internals ================================
987static PyObject* mp_overload(CPPOverload* pymeth, PyObject* args)
988{
989// Select and call a specific C++ overload, based on its signature.
990 const char* sigarg = nullptr;
991 PyObject* sigarg_tuple = nullptr;
992 int want_const = -1;
994 if (args_size &&
995 PyArg_ParseTuple(args, const_cast<char*>("s|i:__overload__"), &sigarg, &want_const)) {
996 want_const = args_size == 1 ? -1 : want_const;
997 return pymeth->FindOverload(sigarg ? sigarg : "", want_const);
998 } else if (args_size &&
999 PyArg_ParseTuple(args, const_cast<char*>("O|i:__overload__"), &sigarg_tuple, &want_const)) {
1000 PyErr_Clear();
1001 want_const = args_size == 1 ? -1 : want_const;
1002 return pymeth->FindOverload(sigarg_tuple, want_const);
1003 } else {
1004 PyErr_Format(PyExc_TypeError, "Unexpected arguments to __overload__");
1005 return nullptr;
1006 }
1007}
1008
1009static PyObject* mp_add_overload(CPPOverload* pymeth, PyObject* new_overload)
1010{
1011 TPythonCallback* cb = new TPythonCallback(new_overload);
1012 pymeth->AdoptMethod(cb);
1014}
1015
1016static PyObject* mp_reflex(CPPOverload* pymeth, PyObject* args)
1017{
1018// Provide the requested reflection information.
1019 Cppyy::Reflex::RequestId_t request = -1;
1021 if (!PyArg_ParseTuple(args, const_cast<char*>("i|i:__cpp_reflex__"), &request, &format))
1022 return nullptr;
1023
1024 return pymeth->fMethodInfo->fMethods[0]->Reflex(request, format);
1025}
1026
1027//----------------------------------------------------------------------------
1028static PyMethodDef mp_methods[] = {
1029 {(char*)"__overload__", (PyCFunction)mp_overload, METH_VARARGS,
1030 (char*)"select overload for dispatch" },
1031 {(char*)"__add_overload__", (PyCFunction)mp_add_overload, METH_O,
1032 (char*)"add a new overload" },
1033 {(char*)"__cpp_reflex__", (PyCFunction)mp_reflex, METH_VARARGS,
1034 (char*)"C++ overload reflection information" },
1035 {(char*)nullptr, nullptr, 0, nullptr }
1036};
1037
1038} // unnamed namespace
1039
1040
1041//= CPyCppyy method proxy type ===============================================
1044 (char*)"cppyy.CPPOverload", // tp_name
1045 sizeof(CPPOverload), // tp_basicsize
1046 0, // tp_itemsize
1047 (destructor)mp_dealloc, // tp_dealloc
1048#if PY_VERSION_HEX >= 0x03080000
1050#else
1051 0, // tp_vectorcall_offset / tp_print
1052#endif
1053 0, // tp_getattr
1054 0, // tp_setattr
1055 0, // tp_as_async / tp_compare
1056 0, // tp_repr
1057 0, // tp_as_number
1058 0, // tp_as_sequence
1059 0, // tp_as_mapping
1060 (hashfunc)mp_hash, // tp_hash
1061#if PY_VERSION_HEX >= 0x03080000
1062 (ternaryfunc)PyVectorcall_Call, // tp_call
1063#else
1064 (ternaryfunc)mp_call, // tp_call
1065#endif
1066 (reprfunc)mp_str, // tp_str
1067 0, // tp_getattro
1068 0, // tp_setattro
1069 0, // tp_as_buffer
1071#if PY_VERSION_HEX >= 0x03080000
1073#endif
1074 , // tp_flags
1075 (char*)"cppyy method proxy (internal)", // tp_doc
1076 (traverseproc)mp_traverse, // tp_traverse
1077 (inquiry)mp_clear, // tp_clear
1078 (richcmpfunc)mp_richcompare, // tp_richcompare
1079 0, // tp_weaklistoffset
1080 0, // tp_iter
1081 0, // tp_iternext
1082 mp_methods, // tp_methods
1083 0, // tp_members
1084 mp_getset, // tp_getset
1085 0, // tp_base
1086 0, // tp_dict
1087 (descrgetfunc)mp_descr_get, // tp_descr_get
1088 0, // tp_descr_set
1089 0, // tp_dictoffset
1090 0, // tp_init
1091 0, // tp_alloc
1092 (newfunc)mp_new, // tp_new
1093 0, // tp_free
1094 0, // tp_is_gc
1095 0, // tp_bases
1096 0, // tp_mro
1097 0, // tp_cache
1098 0, // tp_subclasses
1099 0 // tp_weaklist
1100#if PY_VERSION_HEX >= 0x02030000
1101 , 0 // tp_del
1102#endif
1103#if PY_VERSION_HEX >= 0x02060000
1104 , 0 // tp_version_tag
1105#endif
1106#if PY_VERSION_HEX >= 0x03040000
1107 , 0 // tp_finalize
1108#endif
1109#if PY_VERSION_HEX >= 0x03080000
1110 , 0 // tp_vectorcall
1111#endif
1112#if PY_VERSION_HEX >= 0x030c0000
1113 , 0 // tp_watched
1114#endif
1115#if PY_VERSION_HEX >= 0x030d0000
1116 , 0 // tp_versions_used
1117#endif
1118};
1119
1120} // namespace CPyCppyy
1121
1122
1123//- public members -----------------------------------------------------------
1124void CPyCppyy::CPPOverload::Set(const std::string& name, std::vector<PyCallable*>& methods)
1125{
1126// Fill in the data of a freshly created method proxy.
1129 fMethodInfo->fFlags &= ~CallContext::kIsSorted;
1130
1131// special case: all constructors are considered creators by default
1132 if (name == "__init__")
1134
1135// special case, in heuristics mode also tag *Clone* methods as creators. Only
1136// check that Clone is present in the method name, not in the template argument
1137// list.
1139 std::string_view name_maybe_template = name;
1140 auto begin_template = name_maybe_template.find_first_of('<');
1141 if (begin_template <= name_maybe_template.size()) {
1143 }
1144 if (name_maybe_template.find("Clone") != std::string_view::npos) {
1146 }
1147 }
1148
1149#if PY_VERSION_HEX >= 0x03080000
1151#endif
1152}
1153
1154//----------------------------------------------------------------------------
1156{
1157// Fill in the data of a freshly created method proxy.
1158 fMethodInfo->fMethods.push_back(pc);
1159 fMethodInfo->fFlags &= ~CallContext::kIsSorted;
1160}
1161
1162//----------------------------------------------------------------------------
1164{
1165 if (!HasMethods()) // if fresh method being filled: also copy flags
1166 fMethodInfo->fFlags = meth->fMethodInfo->fFlags;
1167 fMethodInfo->fMethods.insert(fMethodInfo->fMethods.end(),
1168 meth->fMethodInfo->fMethods.begin(), meth->fMethodInfo->fMethods.end());
1169 fMethodInfo->fFlags &= ~CallContext::kIsSorted;
1170 meth->fMethodInfo->fDispatchMap.clear();
1171 meth->fMethodInfo->fMethods.clear();
1172}
1173
1174//----------------------------------------------------------------------------
1176{
1177 bool accept_any = signature == ":any:";
1178 CPPOverload* newmeth = nullptr;
1179
1180 std::string sig1{"("};
1181 if (!accept_any) {
1182 sig1.append(signature); sig1.append(")");
1183 sig1.erase(std::remove(sig1.begin(), sig1.end(), ' '), std::end(sig1));
1184 }
1185
1186 CPPOverload::Methods_t& methods = fMethodInfo->fMethods;
1187 for (auto& meth : methods) {
1188 bool found = accept_any;
1189 if (!found) {
1190 PyObject* pysig2 = meth->GetSignature(false);
1191 std::string sig2(CPyCppyy_PyText_AsString(pysig2));
1192 sig2.erase(std::remove(sig2.begin(), sig2.end(), ' '), std::end(sig2));
1194 if (sig1 == sig2) found = true;
1195
1196 if (!found) {
1197 pysig2 = meth->GetSignature(true);
1198 std::string sig3(CPyCppyy_PyText_AsString(pysig2));
1199 sig3.erase(std::remove(sig3.begin(), sig3.end(), ' '), std::end(sig3));
1201 if (sig1 == sig3) found = true;
1202 }
1203 }
1204
1205 if (found && 0 <= want_const) {
1206 bool isconst = meth->IsConst();
1207 if (!((want_const && isconst) || (!want_const && !isconst)))
1208 found = false;
1209 }
1210
1211 if (found) {
1212 if (!newmeth) {
1213 newmeth = mp_new(nullptr, nullptr, nullptr);
1214 CPPOverload::Methods_t vec; vec.push_back(meth->Clone());
1215 newmeth->Set(fMethodInfo->fName, vec);
1216
1217 if (fSelf) {
1218 Py_INCREF(fSelf);
1219 newmeth->fSelf = fSelf;
1220 }
1221 newmeth->fMethodInfo->fFlags = fMethodInfo->fFlags;
1222 } else
1223 newmeth->AdoptMethod(meth->Clone());
1224
1225 if (!accept_any)
1226 return (PyObject*)newmeth;
1227 }
1228 }
1229
1230 if (!newmeth)
1231 PyErr_Format(PyExc_LookupError, "signature \"%s\" not found", signature.c_str());
1232
1233 return (PyObject*)newmeth;
1234}
1235
1237{
1239
1240 CPPOverload::Methods_t& methods = fMethodInfo->fMethods;
1241
1242 // This value is set based on the maximum penalty in Cppyy::CompareMethodArgType
1244 bool found = false;
1245 size_t best_method = 0, method_index = 0;
1246
1247 for (auto& meth : methods) {
1248 if (0 <= want_const) {
1249 bool isconst = meth->IsConst();
1250 if (!((want_const && isconst) || (!want_const && !isconst)))
1251 continue;
1252 }
1253
1254 int score = meth->GetArgMatchScore(args_tuple);
1255
1256 if (score < min_score) {
1257 found = true;
1258 min_score = score;
1260 }
1261
1262 method_index++;
1263 }
1264
1265 if (!found) {
1266 std::string sigargs("(");
1267
1268 for (int i = 0; i < n; i++) {
1271 PyErr_Format(PyExc_LookupError, "argument types should be in string format");
1272 return (PyObject*) nullptr;
1273 }
1275 sigargs += arg_type + ", ";
1276 }
1277 sigargs += ")";
1278
1279 PyErr_Format(PyExc_LookupError, "signature with arguments \"%s\" not found", sigargs.c_str());
1280 return (PyObject*) nullptr;
1281 }
1282
1283 CPPOverload* newmeth = mp_new(nullptr, nullptr, nullptr);
1285 vec.push_back(methods[best_method]->Clone());
1286 newmeth->Set(fMethodInfo->fName, vec);
1287
1288 if (fSelf) {
1289 Py_INCREF(fSelf);
1290 newmeth->fSelf = fSelf;
1291 }
1292 newmeth->fMethodInfo->fFlags = fMethodInfo->fFlags;
1293
1294 return (PyObject*) newmeth;
1295}
1296
1297//----------------------------------------------------------------------------
1299{
1300// Destructor (this object is reference counted).
1301 for (Methods_t::iterator it = fMethods.begin(); it != fMethods.end(); ++it) {
1302 delete *it;
1303 }
1304 fMethods.clear();
1305 delete fRefCount;
1306 Py_XDECREF(fDoc);
1307}
1308
1309// TODO: something like PyMethod_Fini to clear up the free_list
#define CPyCppyy_Py3_UNUSED(name)
#define CPPOverload_MAXFREELIST
#define CO_NOFREE
#define CPPYY_BOOLEAN_PROPERTY(name, flag, label)
PyObject * fCallable
#define Py_TYPE(ob)
Definition CPyCppyy.h:196
#define Py_RETURN_TRUE
Definition CPyCppyy.h:272
#define Py_RETURN_FALSE
Definition CPyCppyy.h:276
int Py_ssize_t
Definition CPyCppyy.h:215
#define CPyCppyy_PyText_Append
Definition CPyCppyy.h:83
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:76
PyObject * CPyCppyy_PyArgs_t
Definition CPyCppyy.h:330
#define CPyCppyy_PyText_AppendAndDel
Definition CPyCppyy.h:84
PyObject * CPyCppyy_PyObject_Call(PyObject *cb, PyObject *args, size_t, PyObject *kwds)
Definition CPyCppyy.h:346
#define CPyCppyy_PyText_FromFormat
Definition CPyCppyy.h:80
#define Py_RETURN_NONE
Definition CPyCppyy.h:268
#define CPyCppyy_PyText_FromString
Definition CPyCppyy.h:81
#define CPyCppyy_PyText_Check
Definition CPyCppyy.h:74
#define PyVarObject_HEAD_INIT(type, size)
Definition CPyCppyy.h:194
_object PyObject
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t format
char name[80]
Definition TGX11.cxx:110
void MergeOverload(CPPOverload *meth)
void AdoptMethod(PyCallable *pc)
MethodInfo_t * fMethodInfo
Definition CPPOverload.h:79
PyObject * FindOverload(const std::string &signature, int want_const=-1)
std::vector< PyCallable * > Methods_t
Definition CPPOverload.h:44
void Set(const std::string &name, std::vector< PyCallable * > &methods)
const_iterator begin() const
const_iterator end() const
const Int_t n
Definition legend1.C:16
PyObject * gLifeLine
Definition PyStrings.cxx:29
PyObject * gThisModule
Definition PyStrings.cxx:67
void SetDetailedException(std::vector< PyError_t > &&errors, PyObject *topmsg, PyObject *defexc)
Definition Utility.cxx:1191
size_t FetchError(std::vector< PyError_t > &, bool is_cpp=false)
Definition Utility.cxx:1180
bool HaveImplicit(CallContext *ctxt)
PyObject * GetScopeProxy(Cppyy::TCppScope_t)
static PyMethodObject * free_list
bool NoImplicit(CallContext *ctxt)
static int numfree
bool IsCreator(uint64_t flags)
uint64_t HashSignature(CPyCppyy_PyArgs_t args, size_t nargsf)
Definition CPPOverload.h:17
bool CPPInstance_Check(T *object)
PyTypeObject CPPOverload_Type
bool IsConstructor(uint64_t flags)
bool IsSorted(uint64_t flags)
const FormatId_t OPTIMAL
Definition Reflex.h:22
RPY_EXPORTED size_t SizeOf(TCppType_t klass)
RPY_EXPORTED TCppFuncAddr_t GetFunctionAddress(TCppMethod_t method, bool check_enabled=true)
void * TCppFuncAddr_t
Definition cpp_cppyy.h:25
CPPOverload::Methods_t fMethods
Definition CPPOverload.h:53
static ECallFlags sMemoryPolicy
Definition CallContext.h:82