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