Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TemplateProxy.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "TemplateProxy.h"
4#include "CPPClassMethod.h"
5#include "CPPConstructor.h"
6#include "CPPFunction.h"
7#include "CPPMethod.h"
8#include "CPPOverload.h"
9#include "PyCallable.h"
10#include "PyStrings.h"
11#include "Utility.h"
12
13// Standard
14#include <algorithm>
15
16
17namespace CPyCppyy {
18
19//- helper for ctypes conversions --------------------------------------------
20static PyObject* TC2CppName(PyObject* pytc, const char* cpd, bool allow_voidp)
21{
22 const char* name = nullptr;
24 char tc = ((char*)CPyCppyy_PyText_AsString(pytc))[0];
25 switch (tc) {
26 case '?': name = "bool"; break;
27 case 'c': name = "char"; break;
28 case 'b': name = "char"; break;
29 case 'B': name = "unsigned char"; break;
30 case 'h': name = "short"; break;
31 case 'H': name = "unsigned short"; break;
32 case 'i': name = "int"; break;
33 case 'I': name = "unsigned int"; break;
34 case 'l': name = "long"; break;
35 case 'L': name = "unsigned long"; break;
36 case 'q': name = "long long"; break;
37 case 'Q': name = "unsigned long long"; break;
38 case 'f': name = "float"; break;
39 case 'd': name = "double"; break;
40 case 'g': name = "long double"; break;
41 case 'z': // special case for C strings, ignore cpd
42 return CPyCppyy_PyText_FromString(std::string{"const char*"}.c_str());
43 default: name = (allow_voidp ? "void*" : nullptr); break;
44 }
45 }
46
47 if (name)
48 return CPyCppyy_PyText_FromString((std::string{name}+cpd).c_str());
49 return nullptr;
50}
51
52//----------------------------------------------------------------------------
53TemplateInfo::TemplateInfo() : fPyClass(nullptr), fNonTemplated(nullptr),
54 fTemplated(nullptr), fLowPriority(nullptr), fDoc(nullptr)
55{
56 /* empty */
57}
58
59//----------------------------------------------------------------------------
61{
63
68
69 for (const auto& p : fDispatchMap) {
70 for (const auto& c : p.second) {
71 Py_DECREF(c.second);
72 }
73 }
74}
75
76
77//----------------------------------------------------------------------------
79// Store overloads of this templated method.
80 bool isGreedy = false;
81 for (auto pc : mp->fMethodInfo->fMethods) {
82 if (pc->IsGreedy()) {
83 isGreedy = true;
84 break;
85 }
86 }
87
88 CPPOverload* cppol = isGreedy ? fTI->fLowPriority : fTI->fNonTemplated;
89 cppol->MergeOverload(mp);
90}
91
93// Store overload of this templated method.
94 CPPOverload* cppol = pc->IsGreedy() ? fTI->fLowPriority : fTI->fNonTemplated;
95 cppol->AdoptMethod(pc);
96}
97
99{
100// Store known template methods.
101 fTI->fTemplated->AdoptMethod(pc);
102}
103
104//----------------------------------------------------------------------------
107{
108// Instantiate (and cache) templated methods, return method if any
109 std::string proto = "";
110
111#if PY_VERSION_HEX >= 0x03080000
112 bool isNS = (((CPPScope*)fTI->fPyClass)->fFlags & CPPScope::kIsNamespace);
113 if (!isNS && (!fSelf || fSelf == Py_None) && CPyCppyy_PyArgs_GET_SIZE(args, nargsf)) {
114 args += 1;
115 nargsf -= 1;
116 }
117#endif
118
120 if (argc != 0) {
122 for (Py_ssize_t i = 0; i < argc; ++i) {
124
125 bool bArgSet = false;
126
127 // special case for arrays
129 if (pytc) {
130 PyObject* pyptrname = TC2CppName(pytc, "*", true);
131 if (pyptrname) {
133 bArgSet = true;
134 // string added, but not counted towards nStrings
135 }
136 Py_DECREF(pytc); pytc = nullptr;
137 } else
138 PyErr_Clear();
139
140 // if not arg set, try special case for ctypes
142
143 if (!bArgSet && pytc) {
144 PyObject* pyactname = TC2CppName(pytc, "&", false);
145 if (!pyactname) {
146 // _type_ of a pointer to c_type is that type, which will have a type
149 pytc = newpytc;
150 if (pytc) {
151 pyactname = TC2CppName(pytc, "*", false);
152 } else
153 PyErr_Clear();
154 }
155 Py_XDECREF(pytc); pytc = nullptr;
156 if (pyactname) {
158 bArgSet = true;
159 // string added, but not counted towards nStrings
160 }
161 } else
162 PyErr_Clear();
163
164 if (!bArgSet) {
165 // normal case (may well fail)
166 PyErr_Clear();
168 Py_INCREF(tp);
170 }
171 }
172
173#if PY_VERSION_HEX >= 0x03080000
175 for (Py_ssize_t i = 0; i < argc; ++i) {
179 }
180#else
181 Py_INCREF(args);
182 PyObject* pyargs = args;
183#endif
184 const std::string& name_v1 = \
185 Utility::ConstructTemplateArgs(nullptr, tpArgs, pyargs, pref, 0, pcnt);
186
189 if (name_v1.size())
190 proto = name_v1.substr(1, name_v1.size()-2);
191 }
192
193// the following causes instantiation as necessary
194 Cppyy::TCppScope_t scope = ((CPPClass*)fTI->fPyClass)->fCppType;
196 if (cppmeth) { // overload stops here
197 // A successful instantiation needs to be cached to pre-empt future instantiations. There
198 // are two names involved, the original asked (which may be partial) and the received.
199 //
200 // Caching scheme: if the match is exact, simply add the overload to the pre-existing
201 // one, or create a new overload for later lookups. If the match is not exact, do the
202 // same, but also create an alias. Only add exact matches to the set of known template
203 // instantiations, to prevent piling on from different partial instantiations.
204 //
205 // TODO: this caches the lookup method before the call, meaning that failing overloads
206 // can add already existing overloads to the set of methods.
207
209
210 // An initializer_list is preferred for the argument types, but should not leak into
211 // the argument types. If it did, replace with vector and lookup anew.
212 if (resname.find("initializer_list") != std::string::npos) {
213 auto pos = proto.find("initializer_list");
214 while (pos != std::string::npos) {
215 proto.replace(pos, 16, "vector");
216 pos = proto.find("initializer_list", pos + 6);
217 }
218
220 if (m2 && m2 != cppmeth) {
221 // replace if the new method with vector was found; otherwise just continue
222 // with the previously found method with initializer_list.
223 cppmeth = m2;
225 }
226 }
227
228 bool bExactMatch = fname == resname;
229
230 // lookup on existing name in case this was an overload, not a caching, failure
234 if (!pyol) PyErr_Clear();
236
237 if (pyol && !bIsCppOL && !TemplateProxy_Check(pyol)) {
238 // unknown object ... leave well alone
241 Py_DECREF(dct);
242 return nullptr;
243 }
244
245 // find the full name if the requested one was partial
246 PyObject* exact = nullptr;
248 if (!bExactMatch) {
250 if (!exact) PyErr_Clear();
251 }
252 Py_DECREF(dct);
253
254 bool bIsConstructor = false, bNeedsRebind = true;
255
256 PyCallable* meth = nullptr;
259 bNeedsRebind = false;
260 } else if (Cppyy::IsStaticMethod(cppmeth)) {
262 bNeedsRebind = false;
263 } else if (Cppyy::IsConstructor(cppmeth)) {
264 bIsConstructor = true;
266 } else
267 meth = new CPPMethod(scope, cppmeth);
268
269 // Case 1/2: method simply did not exist before
270 if (!pyol) {
271 // actual overload to use (now owns meth)
273 if (bIsConstructor) {
274 // TODO: this is an ugly hack :(
277 }
278
279 // add to class dictionary
280 PyType_Type.tp_setattro(fTI->fPyClass, pycachename, pyol);
281 }
282
283 // Case 3/4: pre-existing method that was either not found b/c the full
284 // templated name was constructed in this call or it failed as overload
285 else if (bIsCppOL) {
286 // TODO: see above, since the call hasn't happened yet, this overload may
287 // already exist and fail again.
288 ((CPPOverload*)pyol)->AdoptMethod(meth); // takes ownership
289 }
290
291 // Case 5: must be a template proxy, meaning that current template name is not
292 // a template overload
293 else {
294 ((TemplateProxy*)pyol)->AdoptTemplate(meth->Clone());
296 pyol = (PyObject*)CPPOverload_New(fname, meth); // takes ownership
297 }
298
299 // Special Case if name was aliased (e.g. typedef in template instantiation)
300 if (!exact && !bExactMatch) {
301 PyType_Type.tp_setattro(fTI->fPyClass, pyresname, pyol);
302 }
303
304 // cleanup
307
308 // retrieve fresh (for boundedness) and call
310 CPPOverload_Type.tp_descr_get(pyol, bNeedsRebind ? fSelf : nullptr, (PyObject*)&CPPOverload_Type);
312 return pymeth;
313 }
314
315 PyErr_Format(PyExc_TypeError, "Failed to instantiate \"%s(%s)\"", fname.c_str(), proto.c_str());
316 return nullptr;
317}
318
319
320//= CPyCppyy template proxy construction/destruction =========================
322{
323// Create a new empty template method proxy.
325 pytmpl->fSelf = nullptr;
326 pytmpl->fTemplateArgs = nullptr;
327 pytmpl->fWeakrefList = nullptr;
328 new (&pytmpl->fTI) TP_TInfo_t{};
329 pytmpl->fTI = std::make_shared<TemplateInfo>();
330
332 return pytmpl;
333}
334
335//----------------------------------------------------------------------------
337{
338 return (Py_hash_t)self;
339}
340
341//----------------------------------------------------------------------------
343{
344 if (op == Py_EQ || op == Py_NE) {
347
348 if (self->fTI == ((TemplateProxy*)other)->fTI)
350
352 }
353
355 return Py_NotImplemented;
356}
357
358//----------------------------------------------------------------------------
360{
361// Garbage collector clear of held python member objects.
362 Py_CLEAR(pytmpl->fSelf);
363 Py_CLEAR(pytmpl->fTemplateArgs);
364
365 return 0;
366}
367
368//----------------------------------------------------------------------------
370{
371// Destroy the given template method proxy.
372 if (pytmpl->fWeakrefList)
376 pytmpl->fTI.~TP_TInfo_t();
378}
379
380//----------------------------------------------------------------------------
382{
383// Garbage collector traverse of held python member objects.
384 Py_VISIT(pytmpl->fSelf);
385 Py_VISIT(pytmpl->fTemplateArgs);
386
387 return 0;
388}
389
390//----------------------------------------------------------------------------
392{
393 if (pytmpl->fTI->fDoc) {
394 Py_INCREF(pytmpl->fTI->fDoc);
395 return pytmpl->fTI->fDoc;
396 }
397
398// Forward to method proxies to doc all overloads
399 PyObject* doc = nullptr;
400 if (pytmpl->fTI->fNonTemplated->HasMethods())
401 doc = PyObject_GetAttrString((PyObject*)pytmpl->fTI->fNonTemplated, "__doc__");
402 if (pytmpl->fTI->fTemplated->HasMethods()) {
403 PyObject* doc2 = PyObject_GetAttrString((PyObject*)pytmpl->fTI->fTemplated, "__doc__");
404 if (doc && doc2) {
407 } else if (!doc && doc2) {
408 doc = doc2;
409 }
410 }
411 if (pytmpl->fTI->fLowPriority->HasMethods()) {
412 PyObject* doc2 = PyObject_GetAttrString((PyObject*)pytmpl->fTI->fLowPriority, "__doc__");
413 if (doc && doc2) {
416 } else if (!doc && doc2) {
417 doc = doc2;
418 }
419 }
420
421 if (doc)
422 return doc;
423
425}
426
427static int tpp_doc_set(TemplateProxy* pytmpl, PyObject *val, void *)
428{
429 Py_XDECREF(pytmpl->fTI->fDoc);
430 Py_INCREF(val);
431 pytmpl->fTI->fDoc = val;
432 return 0;
433}
434
435//----------------------------------------------------------------------------
436
437//= CPyCppyy template proxy callable behavior ================================
438
439#define TPPCALL_RETURN \
440{ errors.clear(); \
441 return result; }
442
443static inline std::string targs2str(TemplateProxy* pytmpl)
444{
445 if (!pytmpl || !pytmpl->fTemplateArgs) return "";
446 return CPyCppyy_PyText_AsString(pytmpl->fTemplateArgs);
447}
448
450{
451// Memoize a method in the dispatch map after successful call; replace old if need be (may be
452// with the same CPPOverload, just with more methods).
453 bool bInserted = false;
454 auto& v = pytmpl->fTI->fDispatchMap[use_targs ? targs2str(pytmpl) : ""];
455
457 for (auto& p : v) {
458 if (p.first == sighash) {
459 Py_DECREF(p.second);
460 p.second = pymeth;
461 bInserted = true;
462 }
463 }
464 if (!bInserted) v.push_back(std::make_pair(sighash, pymeth));
465}
466
468 CPyCppyy_PyArgs_t args, size_t nargsf, PyObject* kwds,
469 bool implicitOkay, bool use_targs, uint64_t sighash, std::vector<Utility::PyError_t>& errors)
470{
471// Forward a call to known overloads, if any.
472 if (pymeth->HasMethods()) {
473 PyObject* pycall = CPPOverload_Type.tp_descr_get(
475
476 if (!implicitOkay)
478
479 // now call the method with the arguments (loops internally)
482 if (result) {
485 }
487 }
488
489 return nullptr;
490}
491
493 CPyCppyy_PyArgs_t args, size_t nargsf, PyObject* kwds, bool impOK, uint64_t sighash)
494{
495// Actual call of a given overload: takes care of handlign of "self" and
496// dereferences the overloaded method after use.
497
501 bool isNS = (((CPPScope*)pytmpl->fTI->fPyClass)->fFlags & CPPScope::kIsNamespace);
502 if (isNS && pytmpl->fSelf && pytmpl->fSelf != Py_None) {
503 // this is a global method added a posteriori to the class
504 PyCallArgs cargs{(CPPInstance*&)pytmpl->fSelf, args, nargsf, kwds};
506 result = CPyCppyy_tp_call(pymeth, cargs.fArgs, cargs.fNArgsf, cargs.fKwds);
507 } else {
508 if (!pytmpl->fSelf && CPPOverload_Check(pymeth))
509 ((CPPOverload*)pymeth)->fFlags &= ~CallContext::kFromDescr;
511 }
512
513 if (result) {
514 Py_XDECREF(((CPPOverload*)pymeth)->fSelf); ((CPPOverload*)pymeth)->fSelf = nullptr; // unbind
516 }
517
518 Py_DECREF(pymeth); pymeth = nullptr;
519 return result;
520}
521
522#if PY_VERSION_HEX >= 0x03080000
524 TemplateProxy* pytmpl, PyObject* const *args, size_t nargsf, PyObject* kwds)
525#else
527#endif
528{
529// Dispatcher to the actual member method, several uses possible; in order:
530//
531// case 1: explicit template previously selected through subscript
532//
533// case 2: select known non-template overload
534//
535// obj.method(a0, a1, ...)
536// => obj->method(a0, a1, ...) // non-template
537//
538// case 3: select known template overload
539//
540// obj.method(a0, a1, ...)
541// => obj->method(a0, a1, ...) // all known templates
542//
543// case 4: auto-instantiation from types of arguments
544//
545// obj.method(a0, a1, ...)
546// => obj->method<type(a0), type(a1), ...>(a0, a1, ...)
547//
548// Note: explicit instantiation needs to use [] syntax:
549//
550// obj.method[type<a0>, type<a1>, ...](a0, a1, ...)
551//
552// case 5: low priority methods, such as ones that take void* arguments
553//
554
555// TODO: should previously instantiated templates be considered first?
556
557#if PY_VERSION_HEX < 0x03080000
558 size_t nargsf = PyTuple_GET_SIZE(args);
559#endif
560
561 PyObject *pymeth = nullptr, *result = nullptr;
562
563// short-cut through memoization map
565 uint64_t sighash = HashSignature(args, argc);
566
567 CPPOverload* ol = nullptr;
568 if (!pytmpl->fTemplateArgs) {
569 // look for known signatures ...
570 auto& v = pytmpl->fTI->fDispatchMap[""];
571 for (const auto& p : v) {
572 if (p.first == sighash) {
573 ol = p.second;
574 break;
575 }
576 }
577
578 if (ol != nullptr) {
579 if (!pytmpl->fSelf || pytmpl->fSelf == Py_None) {
581 } else {
582 pymeth = CPPOverload_Type.tp_descr_get(
585 Py_DECREF(pymeth); pymeth = nullptr;
586 }
587 if (result)
588 return result;
589 }
590 }
591
592// container for collecting errors
593 std::vector<Utility::PyError_t> errors;
595
596// case 1: explicit template previously selected through subscript
597 if (pytmpl->fTemplateArgs) {
598 // instantiate explicitly
599 PyObject* pyfullname = CPyCppyy_PyText_FromString(pytmpl->fTI->fCppName.c_str());
600 CPyCppyy_PyText_Append(&pyfullname, pytmpl->fTemplateArgs);
601
602 // first, lookup by full name, if previously stored
603 bool isNS = (((CPPScope*)pytmpl->fTI->fPyClass)->fFlags & CPPScope::kIsNamespace);
604 if (pytmpl->fSelf && pytmpl->fSelf != Py_None && !isNS)
606 else // by-passes custom scope getattr that searches into Cling
607 pymeth = PyType_Type.tp_getattro(pytmpl->fTI->fPyClass, pyfullname);
608
609 // attempt call if found (this may fail if there are specializations)
611 // since the template args are fully explicit, allow implicit conversion of arguments
613 if (result) {
616 }
618 } else if (pymeth && PyCallable_Check(pymeth)) {
619 // something different (user provided?)
622 if (result) {
625 }
627 } else if (!pymeth)
628 PyErr_Clear();
629
630 // not cached or failed call; try instantiation
631 pymeth = pytmpl->Instantiate(
633 if (pymeth) {
634 // attempt actual call; same as above, allow implicit conversion of arguments
636 if (result) {
639 }
640 }
641
642 // no drop through if failed (if implicit was desired, don't provide template args)
645 "Could not find \"%s\" (set cppyy.set_debug() for C++ errors):", CPyCppyy_PyText_AsString(pyfullname));
647 Utility::SetDetailedException(std::move(errors), topmsg /* steals */, PyExc_TypeError /* default error */);
648
649 return nullptr;
650 }
651
652// case 2: select known non-template overload
653 result = SelectAndForward(pytmpl, pytmpl->fTI->fNonTemplated, args, nargsf, kwds,
654 true /* implicitOkay */, false /* use_targs */, sighash, errors);
655 if (result)
657
658// case 3: select known template overload
659 result = SelectAndForward(pytmpl, pytmpl->fTI->fTemplated, args, nargsf, kwds,
660 false /* implicitOkay */, true /* use_targs */, sighash, errors);
661 if (result)
663
664// case 4: auto-instantiation from types of arguments
666 // TODO: no need to loop if there are no non-instance arguments; also, should any
667 // failed lookup be removed?
668 int pcnt = 0;
669 pymeth = pytmpl->Instantiate(pytmpl->fTI->fCppName, args, nargsf, pref, &pcnt);
670 if (pymeth) {
671 // attempt actual call; argument based, so do not allow implicit conversions
672 result = CallMethodImp(pytmpl, pymeth, args, nargsf, kwds, false, sighash);
674 }
676 if (!pcnt) break; // preference never used; no point trying others
677 }
678
679// case 5: low priority methods, such as ones that take void* arguments
680 result = SelectAndForward(pytmpl, pytmpl->fTI->fLowPriority, args, nargsf, kwds,
681 false /* implicitOkay */, false /* use_targs */, sighash, errors);
682 if (result)
684
685// error reporting is fraud, given the numerous steps taken, but more details seems better
686 if (!errors.empty()) {
687 PyObject* topmsg = CPyCppyy_PyText_FromString("Template method resolution failed:");
688 Utility::SetDetailedException(std::move(errors), topmsg /* steals */, PyExc_TypeError /* default error */);
689 } else {
690 PyErr_Format(PyExc_TypeError, "cannot resolve method template call for \'%s\'",
691 pytmpl->fTI->fCppName.c_str());
692 }
693
694 return nullptr;
695}
696
697//----------------------------------------------------------------------------
699{
700// create and use a new template proxy (language requirement)
702
703// new method is to be bound to current object (may be nullptr)
704 if (pyobj) {
706 newPyTmpl->fSelf = pyobj;
707 } else {
709 newPyTmpl->fSelf = Py_None;
710 }
711
712 Py_XINCREF(pytmpl->fTemplateArgs);
713 newPyTmpl->fTemplateArgs = pytmpl->fTemplateArgs;
714
715// copy name, class, etc. pointers
716 new (&newPyTmpl->fTI) std::shared_ptr<TemplateInfo>{pytmpl->fTI};
717
718#if PY_VERSION_HEX >= 0x03080000
719 newPyTmpl->fVectorCall = pytmpl->fVectorCall;
720#endif
721
722 return newPyTmpl;
723}
724
725
726//----------------------------------------------------------------------------
728{
729// Explicit template member lookup/instantiation; works by re-bounding. This method can
730// not cache overloads as instantiations need not be unique for the argument types due
731// to template specializations.
733 Py_XDECREF(typeBoundMethod->fTemplateArgs);
735 Utility::ConstructTemplateArgs(nullptr, args).c_str());
736 return (PyObject*)typeBoundMethod;
737}
738
739//-----------------------------------------------------------------------------
741{
742 return PyInt_FromLong(0); // dummy (__useffi__ unused)
743}
744
745//-----------------------------------------------------------------------------
746static int tpp_setuseffi(CPPOverload*, PyObject*, void*)
747{
748 return 0; // dummy (__useffi__ unused)
749}
750
751
752//----------------------------------------------------------------------------
754 nullptr, (binaryfunc)tpp_subscript, nullptr
755};
756
758 {(char*)"__doc__", (getter)tpp_doc, (setter)tpp_doc_set, nullptr, nullptr},
759 {(char*)"__useffi__", (getter)tpp_getuseffi, (setter)tpp_setuseffi,
760 (char*)"unused", nullptr},
761 {(char*)nullptr, nullptr, nullptr, nullptr, nullptr}
762};
763
764
765//----------------------------------------------------------------------------
766void TemplateProxy::Set(const std::string& cppname, const std::string& pyname, PyObject* pyclass)
767{
768// Initialize the proxy for the given 'pyclass.'
769 fSelf = nullptr;
770 fTemplateArgs = nullptr;
771
772 fTI->fCppName = cppname;
774 fTI->fPyClass = pyclass;
775
776 std::vector<PyCallable*> dummy;
777 fTI->fNonTemplated = CPPOverload_New(pyname, dummy);
778 fTI->fTemplated = CPPOverload_New(pyname, dummy);
779 fTI->fLowPriority = CPPOverload_New(pyname, dummy);
780
781#if PY_VERSION_HEX >= 0x03080000
783#endif
784}
785
786
787//= CPyCppyy method proxy access to internals ================================
789{
790// Select and call a specific C++ overload, based on its signature.
791 const char* sigarg = nullptr;
792 PyObject* sigarg_tuple = nullptr;
793 int want_const = -1;
794
797 std::string proto;
798
799 if (PyArg_ParseTuple(args, const_cast<char*>("s|i:__overload__"), &sigarg, &want_const)) {
800 want_const = PyTuple_GET_SIZE(args) == 1 ? -1 : want_const;
801
802 // check existing overloads in order
803 PyObject* ol = pytmpl->fTI->fNonTemplated->FindOverload(sigarg, want_const);
804 if (ol) return ol;
805 PyErr_Clear();
806 ol = pytmpl->fTI->fTemplated->FindOverload(sigarg, want_const);
807 if (ol) return ol;
808 PyErr_Clear();
809 ol = pytmpl->fTI->fLowPriority->FindOverload(sigarg, want_const);
810 if (ol) return ol;
811
812 proto = Utility::ConstructTemplateArgs(nullptr, args);
813
814 scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType;
816 scope, pytmpl->fTI->fCppName, proto.substr(1, proto.size()-2));
817 } else if (PyArg_ParseTuple(args, const_cast<char*>("O|i:__overload__"), &sigarg_tuple, &want_const)) {
818 PyErr_Clear();
819 want_const = PyTuple_GET_SIZE(args) == 1 ? -1 : want_const;
820
821 // check existing overloads in order
822 PyObject* ol = pytmpl->fTI->fNonTemplated->FindOverload(sigarg_tuple, want_const);
823 if (ol) return ol;
824 PyErr_Clear();
825 ol = pytmpl->fTI->fTemplated->FindOverload(sigarg_tuple, want_const);
826 if (ol) return ol;
827 PyErr_Clear();
828 ol = pytmpl->fTI->fLowPriority->FindOverload(sigarg_tuple, want_const);
829 if (ol) return ol;
830
831 proto.reserve(128);
832 proto.push_back('<');
834 for (int i = 0; i < n; i++) {
837 PyErr_Format(PyExc_LookupError, "argument types should be in string format");
838 return (PyObject*) nullptr;
839 }
841 if (i < n - 1)
842 proto.push_back(',');
843 }
844 proto.push_back('>');
845
846 scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType;
848 scope, pytmpl->fTI->fCppName, proto.substr(1, proto.size()-2));
849 } else {
850 PyErr_Format(PyExc_TypeError, "Unexpected arguments to __overload__");
851 return nullptr;
852 }
853
854// else attempt instantiation
855 if (!cppmeth) {
856 return nullptr;
857 }
858
859 PyErr_Clear();
860
861 // TODO: the next step should be consolidated with Instantiate()
862 PyCallable* meth = nullptr;
865 } else if (Cppyy::IsStaticMethod(cppmeth)) {
867 } else if (Cppyy::IsConstructor(cppmeth)) {
869 } else
870 meth = new CPPMethod(scope, cppmeth);
871
872 return (PyObject*)CPPOverload_New(pytmpl->fTI->fCppName+proto, meth);
873}
874
876 {(char*)"__overload__", (PyCFunction)tpp_overload, METH_VARARGS,
877 (char*)"select overload for dispatch" },
878 {(char*)nullptr, nullptr, 0, nullptr }
879};
880
881
882//= CPyCppyy template proxy type =============================================
885 (char*)"cppyy.TemplateProxy", // tp_name
886 sizeof(TemplateProxy), // tp_basicsize
887 0, // tp_itemsize
888 (destructor)tpp_dealloc, // tp_dealloc
889#if PY_VERSION_HEX >= 0x03080000
891#else
892 0, // tp_vectorcall_offset / tp_print
893#endif
894 0, // tp_getattr
895 0, // tp_setattr
896 0, // tp_as_async / tp_compare
897 0, // tp_repr
898 0, // tp_as_number
899 0, // tp_as_sequence
900 &tpp_as_mapping, // tp_as_mapping
901 (hashfunc)tpp_hash, // tp_hash
902#if PY_VERSION_HEX >= 0x03080000
903 (ternaryfunc)PyVectorcall_Call, // tp_call
904#else
905 (ternaryfunc)tpp_call, // tp_call
906#endif
907 0, // tp_str
908 0, // tp_getattro
909 0, // tp_setattro
910 0, // tp_as_buffer
912#if PY_VERSION_HEX >= 0x03080000
914#endif
915 , // tp_flags
916 (char*)"cppyy template proxy (internal)", // tp_doc
917 (traverseproc)tpp_traverse, // tp_traverse
918 (inquiry)tpp_clear, // tp_clear
919 (richcmpfunc)tpp_richcompare, // tp_richcompare
920 offsetof(TemplateProxy, fWeakrefList), // tp_weaklistoffset
921 0, // tp_iter
922 0, // tp_iternext
923 tpp_methods, // tp_methods
924 0, // tp_members
925 tpp_getset, // tp_getset
926 0, // tp_base
927 0, // tp_dict
928 (descrgetfunc)tpp_descr_get, // tp_descr_get
929 0, // tp_descr_set
930 0, // tp_dictoffset
931 0, // tp_init
932 0, // tp_alloc
933 (newfunc)tpp_new, // tp_new
934 0, // tp_free
935 0, // tp_is_gc
936 0, // tp_bases
937 0, // tp_mro
938 0, // tp_cache
939 0, // tp_subclasses
940 0 // tp_weaklist
941#if PY_VERSION_HEX >= 0x02030000
942 , 0 // tp_del
943#endif
944#if PY_VERSION_HEX >= 0x02060000
945 , 0 // tp_version_tag
946#endif
947#if PY_VERSION_HEX >= 0x03040000
948 , 0 // tp_finalize
949#endif
950#if PY_VERSION_HEX >= 0x03080000
951 , 0 // tp_vectorcall
952#endif
953#if PY_VERSION_HEX >= 0x030c0000
954 , 0 // tp_watched
955#endif
956#if PY_VERSION_HEX >= 0x030d0000
957 , 0 // tp_versions_used
958#endif
959};
960
961} // namespace CPyCppyy
#define Py_TYPE(ob)
Definition CPyCppyy.h:196
#define Py_RETURN_TRUE
Definition CPyCppyy.h:272
#define CPyCppyy_PyText_InternFromString
Definition CPyCppyy.h:82
#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
long Py_hash_t
Definition CPyCppyy.h:114
PyObject * CPyCppyy_PyObject_Call(PyObject *cb, PyObject *args, size_t, PyObject *kwds)
Definition CPyCppyy.h:346
#define CPyCppyy_PyText_FromFormat
Definition CPyCppyy.h:80
PyObject * CPyCppyy_tp_call(PyObject *cb, PyObject *args, size_t, PyObject *kwds)
Definition CPyCppyy.h:349
#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
_object PyObject
#define c(i)
Definition RSha256.hxx:101
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 result
char name[80]
Definition TGX11.cxx:110
#define TPPCALL_RETURN
const char * proto
Definition civetweb.c:17535
MethodInfo_t * fMethodInfo
Definition CPPOverload.h:75
virtual bool IsGreedy()=0
CPPOverload * fTemplated
CPPOverload * fLowPriority
TP_DispatchMap_t fDispatchMap
CPPOverload * fNonTemplated
PyObject * Instantiate(const std::string &fname, CPyCppyy_PyArgs_t tmplArgs, size_t nargsf, Utility::ArgPreference, int *pcnt=nullptr)
void Set(const std::string &cppname, const std::string &pyname, PyObject *pyclass)
PyObject_HEAD PyObject * fSelf
void AdoptTemplate(PyCallable *pc)
void AdoptMethod(PyCallable *pc)
void MergeOverload(CPPOverload *mp)
const Int_t n
Definition legend1.C:16
PyObject * gCTypesType
Definition PyStrings.cxx:39
PyObject * gTypeCode
Definition PyStrings.cxx:38
void SetDetailedException(std::vector< PyError_t > &&errors, PyObject *topmsg, PyObject *defexc)
Definition Utility.cxx:1124
std::string ConstructTemplateArgs(PyObject *pyname, PyObject *tpArgs, PyObject *args=nullptr, ArgPreference=kNone, int argoff=0, int *pcnt=nullptr)
Definition Utility.cxx:585
size_t FetchError(std::vector< PyError_t > &, bool is_cpp=false)
Definition Utility.cxx:1113
CPPOverload * CPPOverload_New(const std::string &name, std::vector< PyCallable * > &methods)
static PyObject * tpp_richcompare(TemplateProxy *self, PyObject *other, int op)
bool AdjustSelf(PyCallArgs &cargs)
static PyObject * tpp_doc(TemplateProxy *pytmpl, void *)
static PyMappingMethods tpp_as_mapping
bool CPPOverload_Check(T *object)
Definition CPPOverload.h:90
static int tpp_clear(TemplateProxy *pytmpl)
static PyObject * tpp_call(TemplateProxy *pytmpl, PyObject *args, PyObject *kwds)
static PyObject * tpp_getuseffi(CPPOverload *, void *)
bool TemplateProxy_CheckExact(T *object)
static void tpp_dealloc(TemplateProxy *pytmpl)
uint64_t HashSignature(CPyCppyy_PyArgs_t args, size_t nargsf)
Definition CPPOverload.h:17
static int tpp_traverse(TemplateProxy *pytmpl, visitproc visit, void *arg)
static PyObject * tpp_overload(TemplateProxy *pytmpl, PyObject *args)
static int tpp_setuseffi(CPPOverload *, PyObject *, void *)
static PyGetSetDef tpp_getset[]
PyTypeObject CPPOverload_Type
PyTypeObject TemplateProxy_Type
static PyObject * tpp_subscript(TemplateProxy *pytmpl, PyObject *args)
static PyObject * CallMethodImp(TemplateProxy *pytmpl, PyObject *&pymeth, CPyCppyy_PyArgs_t args, size_t nargsf, PyObject *kwds, bool impOK, uint64_t sighash)
static void UpdateDispatchMap(TemplateProxy *pytmpl, bool use_targs, uint64_t sighash, CPPOverload *pymeth)
static TemplateProxy * tpp_new(PyTypeObject *, PyObject *, PyObject *)
static PyMethodDef tpp_methods[]
static int tpp_doc_set(TemplateProxy *pytmpl, PyObject *val, void *)
static Py_hash_t tpp_hash(TemplateProxy *self)
static PyObject * SelectAndForward(TemplateProxy *pytmpl, CPPOverload *pymeth, CPyCppyy_PyArgs_t args, size_t nargsf, PyObject *kwds, bool implicitOkay, bool use_targs, uint64_t sighash, std::vector< Utility::PyError_t > &errors)
static std::string targs2str(TemplateProxy *pytmpl)
static TemplateProxy * tpp_descr_get(TemplateProxy *pytmpl, PyObject *pyobj, PyObject *)
bool TemplateProxy_Check(T *object)
std::shared_ptr< TemplateInfo > TP_TInfo_t
static PyObject * TC2CppName(PyObject *pytc, const char *cpd, bool allow_voidp)
intptr_t TCppMethod_t
Definition cpp_cppyy.h:22
RPY_EXPORTED TCppMethod_t GetMethodTemplate(TCppScope_t scope, const std::string &name, const std::string &proto)
RPY_EXPORTED bool IsConstructor(TCppMethod_t method)
RPY_EXPORTED bool IsNamespace(TCppScope_t scope)
RPY_EXPORTED bool IsStaticMethod(TCppMethod_t method)
size_t TCppScope_t
Definition cpp_cppyy.h:18
RPY_EXPORTED std::string GetMethodFullName(TCppMethod_t)