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//----------------------------------------------------------------------------
20TemplateInfo::TemplateInfo() : fPyClass(nullptr), fNonTemplated(nullptr),
21 fTemplated(nullptr), fLowPriority(nullptr), fDoc(nullptr)
22{
23 /* empty */
24}
25
26//----------------------------------------------------------------------------
28{
30
35
36 for (const auto& p : fDispatchMap) {
37 for (const auto& c : p.second) {
38 Py_DECREF(c.second);
39 }
40 }
41}
42
43
44//----------------------------------------------------------------------------
46// Store overloads of this templated method.
47 bool isGreedy = false;
48 for (auto pc : mp->fMethodInfo->fMethods) {
49 if (pc->IsGreedy()) {
50 isGreedy = true;
51 break;
52 }
53 }
54
55 CPPOverload* cppol = isGreedy ? fTI->fLowPriority : fTI->fNonTemplated;
56 cppol->MergeOverload(mp);
57}
58
60// Store overload of this templated method.
61 CPPOverload* cppol = pc->IsGreedy() ? fTI->fLowPriority : fTI->fNonTemplated;
62 cppol->AdoptMethod(pc);
63}
64
66{
67// Store known template methods.
68 fTI->fTemplated->AdoptMethod(pc);
69}
70
71//----------------------------------------------------------------------------
74{
75// Instantiate (and cache) templated methods, return method if any
76 std::string proto = "";
77
78#if PY_VERSION_HEX >= 0x03080000
79// adjust arguments for self if this is a rebound (global) function
80 bool isNS = (((CPPScope*)fTI->fPyClass)->fFlags & CPPScope::kIsNamespace);
81 if (!isNS && CPyCppyy_PyArgs_GET_SIZE(args, nargsf) && \
82 (!fSelf ||
83 (fSelf == Py_None && !Cppyy::IsStaticTemplate(((CPPScope*)fTI->fPyClass)->fCppType, fname)))) {
84 args += 1;
85 nargsf -= 1;
86 }
87#endif
88
90 if (argc != 0) {
92 for (Py_ssize_t i = 0; i < argc; ++i) {
94
95 bool bArgSet = false;
96
97 // special case for arrays
99 if (pytc) {
101 memset(&bufinfo, 0, sizeof(Py_buffer));
102 std::string ptrdef;
104 for (int j = 0; j < bufinfo.ndim; ++j) ptrdef += "*";
106 } else {
107 ptrdef += "*";
108 PyErr_Clear();
109 }
110
112 if (pyptrname) {
114 bArgSet = true;
115 // string added, but not counted towards nStrings
116 }
117 Py_DECREF(pytc); pytc = nullptr;
118 } else
119 PyErr_Clear();
120
121 // if not arg set, try special case for ctypes
123
124 if (!bArgSet && pytc) {
126 if (!pyactname) {
127 // _type_ of a pointer to c_type is that type, which will have a type
130 pytc = newpytc;
131 if (pytc) {
132 pyactname = Utility::CT2CppName(pytc, "*", false);
133 } else
134 PyErr_Clear();
135 }
136 Py_XDECREF(pytc); pytc = nullptr;
137 if (pyactname) {
139 bArgSet = true;
140 // string added, but not counted towards nStrings
141 }
142 } else
143 PyErr_Clear();
144
145 if (!bArgSet && (Py_TYPE(itemi) == &TemplateProxy_Type)) {
147 PyObject *tmpl_name = CPyCppyy_PyText_FromFormat("decltype(%s%s)", tp->fTI->fCppName.c_str(), tp->fTemplateArgs ? CPyCppyy_PyText_AsString(tp->fTemplateArgs) : "");
149 bArgSet = true;
150 }
151 if (!bArgSet) {
152 // normal case (may well fail)
153 PyErr_Clear();
155 Py_INCREF(tp);
157 }
158 }
159
160#if PY_VERSION_HEX >= 0x03080000
162 for (Py_ssize_t i = 0; i < argc; ++i) {
166 }
167#else
168 Py_INCREF(args);
169 PyObject* pyargs = args;
170#endif
171 const std::string& name_v1 = \
172 Utility::ConstructTemplateArgs(nullptr, tpArgs, pyargs, pref, 0, pcnt);
173
176 if (name_v1.size())
177 proto = name_v1.substr(1, name_v1.size()-2);
178 }
179
180// the following causes instantiation as necessary
181 Cppyy::TCppScope_t scope = ((CPPClass*)fTI->fPyClass)->fCppType;
183 if (cppmeth) { // overload stops here
184 // A successful instantiation needs to be cached to pre-empt future instantiations. There
185 // are two names involved, the original asked (which may be partial) and the received.
186 //
187 // Caching scheme: if the match is exact, simply add the overload to the pre-existing
188 // one, or create a new overload for later lookups. If the match is not exact, do the
189 // same, but also create an alias. Only add exact matches to the set of known template
190 // instantiations, to prevent piling on from different partial instantiations.
191 //
192 // TODO: this caches the lookup method before the call, meaning that failing overloads
193 // can add already existing overloads to the set of methods.
194
196
197 // An initializer_list is preferred for the argument types, but should not leak into
198 // the argument types. If it did, replace with vector and lookup anew.
199 if (resname.find("initializer_list") != std::string::npos) {
200 auto pos = proto.find("initializer_list");
201 while (pos != std::string::npos) {
202 proto.replace(pos, 16, "vector");
203 pos = proto.find("initializer_list", pos + 6);
204 }
205
207 if (m2 && m2 != cppmeth) {
208 // replace if the new method with vector was found; otherwise just continue
209 // with the previously found method with initializer_list.
210 cppmeth = m2;
212 }
213 }
214
215 bool bExactMatch = fname == resname;
216
217 // lookup on existing name in case this was an overload, not a caching, failure
221 if (!pyol) PyErr_Clear();
223
224 if (pyol && !bIsCppOL && !TemplateProxy_Check(pyol)) {
225 // unknown object ... leave well alone
228 Py_DECREF(dct);
229 return nullptr;
230 }
231
232 // find the full name if the requested one was partial
233 PyObject* exact = nullptr;
235 if (!bExactMatch) {
237 if (!exact) PyErr_Clear();
238 }
239 Py_DECREF(dct);
240
241 bool bIsConstructor = false, bNeedsRebind = true;
242
243 PyCallable* meth = nullptr;
246 bNeedsRebind = false;
247 } else if (Cppyy::IsStaticMethod(cppmeth)) {
249 bNeedsRebind = false;
250 } else if (Cppyy::IsConstructor(cppmeth)) {
251 bIsConstructor = true;
253 } else
254 meth = new CPPMethod(scope, cppmeth);
255
256 // Case 1/2: method simply did not exist before
257 if (!pyol) {
258 // actual overload to use (now owns meth)
260 if (bIsConstructor) {
261 // TODO: this is an ugly hack :(
264 }
265
266 // add to class dictionary
267 PyType_Type.tp_setattro(fTI->fPyClass, pycachename, pyol);
268 }
269
270 // Case 3/4: pre-existing method that was either not found b/c the full
271 // templated name was constructed in this call or it failed as overload
272 else if (bIsCppOL) {
273 // TODO: see above, since the call hasn't happened yet, this overload may
274 // already exist and fail again.
275 ((CPPOverload*)pyol)->AdoptMethod(meth); // takes ownership
276 }
277
278 // Case 5: must be a template proxy, meaning that current template name is not
279 // a template overload
280 else {
281 ((TemplateProxy*)pyol)->AdoptTemplate(meth->Clone());
283 pyol = (PyObject*)CPPOverload_New(fname, meth); // takes ownership
284 }
285
286 // Special Case if name was aliased (e.g. typedef in template instantiation)
287 if (!exact && !bExactMatch) {
288 PyType_Type.tp_setattro(fTI->fPyClass, pyresname, pyol);
289 }
290
291 // cleanup
294
295 // retrieve fresh (for boundedness) and call
297 CPPOverload_Type.tp_descr_get(pyol, bNeedsRebind ? fSelf : nullptr, (PyObject*)&CPPOverload_Type);
299 return pymeth;
300 }
301
302 PyErr_Format(PyExc_TypeError, "Failed to instantiate \"%s(%s)\"", fname.c_str(), proto.c_str());
303 return nullptr;
304}
305
306
307//= CPyCppyy template proxy construction/destruction =========================
309{
310// Create a new empty template method proxy.
312 pytmpl->fSelf = nullptr;
313 pytmpl->fTemplateArgs = nullptr;
314 pytmpl->fWeakrefList = nullptr;
315 new (&pytmpl->fTI) TP_TInfo_t{};
316 pytmpl->fTI = std::make_shared<TemplateInfo>();
317
319 return pytmpl;
320}
321
322//----------------------------------------------------------------------------
324{
325 return (Py_hash_t)self;
326}
327
328//----------------------------------------------------------------------------
330{
331 if (op == Py_EQ || op == Py_NE) {
334
335 if (self->fTI == ((TemplateProxy*)other)->fTI)
337
339 }
340
342 return Py_NotImplemented;
343}
344
345//----------------------------------------------------------------------------
347{
348// Garbage collector clear of held python member objects.
349 Py_CLEAR(pytmpl->fSelf);
350 Py_CLEAR(pytmpl->fTemplateArgs);
351
352 return 0;
353}
354
355//----------------------------------------------------------------------------
357{
358// Destroy the given template method proxy.
359 if (pytmpl->fWeakrefList)
363 pytmpl->fTI.~TP_TInfo_t();
365}
366
367//----------------------------------------------------------------------------
369{
370// Garbage collector traverse of held python member objects.
371 Py_VISIT(pytmpl->fSelf);
372 Py_VISIT(pytmpl->fTemplateArgs);
373
374 return 0;
375}
376
377//----------------------------------------------------------------------------
379{
380 if (pytmpl->fTI->fDoc) {
381 Py_INCREF(pytmpl->fTI->fDoc);
382 return pytmpl->fTI->fDoc;
383 }
384
385// Forward to method proxies to doc all overloads
386 PyObject* doc = nullptr;
387 if (pytmpl->fTI->fNonTemplated->HasMethods())
388 doc = PyObject_GetAttrString((PyObject*)pytmpl->fTI->fNonTemplated, "__doc__");
389 if (pytmpl->fTI->fTemplated->HasMethods()) {
390 PyObject* doc2 = PyObject_GetAttrString((PyObject*)pytmpl->fTI->fTemplated, "__doc__");
391 if (doc && doc2) {
394 } else if (!doc && doc2) {
395 doc = doc2;
396 }
397 }
398 if (pytmpl->fTI->fLowPriority->HasMethods()) {
399 PyObject* doc2 = PyObject_GetAttrString((PyObject*)pytmpl->fTI->fLowPriority, "__doc__");
400 if (doc && doc2) {
403 } else if (!doc && doc2) {
404 doc = doc2;
405 }
406 }
407
408 if (doc)
409 return doc;
410
412}
413
414static int tpp_doc_set(TemplateProxy* pytmpl, PyObject *val, void *)
415{
416 Py_XDECREF(pytmpl->fTI->fDoc);
417 Py_INCREF(val);
418 pytmpl->fTI->fDoc = val;
419 return 0;
420}
421
422//----------------------------------------------------------------------------
423
424//= CPyCppyy template proxy callable behavior ================================
425
426#define TPPCALL_RETURN \
427{ errors.clear(); \
428 return result; }
429
430static inline std::string targs2str(TemplateProxy* pytmpl)
431{
432 if (!pytmpl || !pytmpl->fTemplateArgs) return "";
433 return CPyCppyy_PyText_AsString(pytmpl->fTemplateArgs);
434}
435
437{
438// Memoize a method in the dispatch map after successful call; replace old if need be (may be
439// with the same CPPOverload, just with more methods).
440 bool bInserted = false;
441 auto& v = pytmpl->fTI->fDispatchMap[use_targs ? targs2str(pytmpl) : ""];
442
444 for (auto& p : v) {
445 if (p.first == sighash) {
446 Py_DECREF(p.second);
447 p.second = pymeth;
448 bInserted = true;
449 }
450 }
451 if (!bInserted) v.push_back(std::make_pair(sighash, pymeth));
452}
453
455 CPyCppyy_PyArgs_t args, size_t nargsf, PyObject* kwds,
456 bool implicitOkay, bool use_targs, uint64_t sighash, std::vector<Utility::PyError_t>& errors)
457{
458// Forward a call to known overloads, if any.
459 if (pymeth->HasMethods()) {
460 PyObject* pycall = CPPOverload_Type.tp_descr_get(
462
463 if (!implicitOkay)
465
466 // now call the method with the arguments (loops internally)
469 if (result) {
472 }
474 }
475
476 return nullptr;
477}
478
480 CPyCppyy_PyArgs_t args, size_t nargsf, PyObject* kwds, bool impOK, uint64_t sighash)
481{
482// Actual call of a given overload: takes care of handlign of "self" and
483// dereferences the overloaded method after use.
484
488 bool isNS = (((CPPScope*)pytmpl->fTI->fPyClass)->fFlags & CPPScope::kIsNamespace);
489 if (isNS && pytmpl->fSelf && pytmpl->fSelf != Py_None) {
490 // this is a global method added a posteriori to the class
491 PyCallArgs cargs{(CPPInstance*&)pytmpl->fSelf, args, nargsf, kwds};
493 result = CPyCppyy_tp_call(pymeth, cargs.fArgs, cargs.fNArgsf, cargs.fKwds);
494 } else {
495 if (!pytmpl->fSelf && CPPOverload_Check(pymeth))
496 ((CPPOverload*)pymeth)->fFlags &= ~CallContext::kFromDescr;
498 }
499
500 if (result) {
501 Py_XDECREF(((CPPOverload*)pymeth)->fSelf); ((CPPOverload*)pymeth)->fSelf = nullptr; // unbind
503 }
504
505 Py_DECREF(pymeth); pymeth = nullptr;
506 return result;
507}
508
509#if PY_VERSION_HEX >= 0x03080000
511 TemplateProxy* pytmpl, PyObject* const *args, size_t nargsf, PyObject* kwds)
512#else
514#endif
515{
516// Dispatcher to the actual member method, several uses possible; in order:
517//
518// case 1: explicit template previously selected through subscript
519//
520// case 2: select known non-template overload
521//
522// obj.method(a0, a1, ...)
523// => obj->method(a0, a1, ...) // non-template
524//
525// case 3: select known template overload
526//
527// obj.method(a0, a1, ...)
528// => obj->method(a0, a1, ...) // all known templates
529//
530// case 4: auto-instantiation from types of arguments
531//
532// obj.method(a0, a1, ...)
533// => obj->method<type(a0), type(a1), ...>(a0, a1, ...)
534//
535// Note: explicit instantiation needs to use [] syntax:
536//
537// obj.method[type<a0>, type<a1>, ...](a0, a1, ...)
538//
539// case 5: low priority methods, such as ones that take void* arguments
540//
541
542// TODO: should previously instantiated templates be considered first?
543
544#if PY_VERSION_HEX < 0x03080000
545 size_t nargsf = PyTuple_GET_SIZE(args);
546#endif
547
548 PyObject *pymeth = nullptr, *result = nullptr;
549
550// short-cut through memoization map
552 uint64_t sighash = HashSignature(args, argc);
553
554 CPPOverload* ol = nullptr;
555 if (!pytmpl->fTemplateArgs) {
556 // look for known signatures ...
557 auto& v = pytmpl->fTI->fDispatchMap[""];
558 for (const auto& p : v) {
559 if (p.first == sighash) {
560 ol = p.second;
561 break;
562 }
563 }
564
565 if (ol != nullptr) {
566 if (!pytmpl->fSelf || pytmpl->fSelf == Py_None) {
568 } else {
569 pymeth = CPPOverload_Type.tp_descr_get(
572 Py_DECREF(pymeth); pymeth = nullptr;
573 }
574 if (result)
575 return result;
576 }
577 }
578
579// container for collecting errors
580 std::vector<Utility::PyError_t> errors;
582
583// case 1: explicit template previously selected through subscript
584 if (pytmpl->fTemplateArgs) {
585 // instantiate explicitly
586 PyObject* pyfullname = CPyCppyy_PyText_FromString(pytmpl->fTI->fCppName.c_str());
587 CPyCppyy_PyText_Append(&pyfullname, pytmpl->fTemplateArgs);
588
589 // first, lookup by full name, if previously stored
590 bool isNS = (((CPPScope*)pytmpl->fTI->fPyClass)->fFlags & CPPScope::kIsNamespace);
591 if (pytmpl->fSelf && pytmpl->fSelf != Py_None && !isNS)
593 else // by-passes custom scope getattr that searches into Cling
594 pymeth = PyType_Type.tp_getattro(pytmpl->fTI->fPyClass, pyfullname);
595
596 // attempt call if found (this may fail if there are specializations)
598 // since the template args are fully explicit, allow implicit conversion of arguments
600 if (result) {
603 }
605 } else if (pymeth && PyCallable_Check(pymeth)) {
606 // something different (user provided?)
609 if (result) {
612 }
614 } else if (!pymeth)
615 PyErr_Clear();
616
617 // not cached or failed call; try instantiation
618 pymeth = pytmpl->Instantiate(
620 if (pymeth) {
621 // attempt actual call; same as above, allow implicit conversion of arguments
623 if (result) {
626 }
627 }
628
629 // no drop through if failed (if implicit was desired, don't provide template args)
632 "Could not find \"%s\" (set cppyy.set_debug() for C++ errors):", CPyCppyy_PyText_AsString(pyfullname));
634 Utility::SetDetailedException(std::move(errors), topmsg /* steals */, PyExc_TypeError /* default error */);
635
636 return nullptr;
637 }
638
639// case 2: select known non-template overload
640 result = SelectAndForward(pytmpl, pytmpl->fTI->fNonTemplated, args, nargsf, kwds,
641 true /* implicitOkay */, false /* use_targs */, sighash, errors);
642 if (result)
644
645// case 3: select known template overload
646 result = SelectAndForward(pytmpl, pytmpl->fTI->fTemplated, args, nargsf, kwds,
647 false /* implicitOkay */, true /* use_targs */, sighash, errors);
648 if (result)
650
651// case 4: auto-instantiation from types of arguments
653 // TODO: no need to loop if there are no non-instance arguments; also, should any
654 // failed lookup be removed?
655 int pcnt = 0;
656 pymeth = pytmpl->Instantiate(pytmpl->fTI->fCppName, args, nargsf, pref, &pcnt);
657 if (pymeth) {
658 // attempt actual call; argument based, so do not allow implicit conversions
659 result = CallMethodImp(pytmpl, pymeth, args, nargsf, kwds, false, sighash);
661 }
663 if (!pcnt) break; // preference never used; no point trying others
664 }
665
666// case 5: low priority methods, such as ones that take void* arguments
667 result = SelectAndForward(pytmpl, pytmpl->fTI->fLowPriority, args, nargsf, kwds,
668 false /* implicitOkay */, false /* use_targs */, sighash, errors);
669 if (result)
671
672// error reporting is fraud, given the numerous steps taken, but more details seems better
673 if (!errors.empty()) {
674 PyObject* topmsg = CPyCppyy_PyText_FromString("Template method resolution failed:");
675 Utility::SetDetailedException(std::move(errors), topmsg /* steals */, PyExc_TypeError /* default error */);
676 } else {
677 PyErr_Format(PyExc_TypeError, "cannot resolve method template call for \'%s\'",
678 pytmpl->fTI->fCppName.c_str());
679 }
680
681 return nullptr;
682}
683
684//----------------------------------------------------------------------------
686{
687// create and use a new template proxy (language requirement)
689
690// new method is to be bound to current object (may be nullptr)
691 if (pyobj) {
693 newPyTmpl->fSelf = pyobj;
694 } else {
696 newPyTmpl->fSelf = Py_None;
697 }
698
699 Py_XINCREF(pytmpl->fTemplateArgs);
700 newPyTmpl->fTemplateArgs = pytmpl->fTemplateArgs;
701
702// copy name, class, etc. pointers
703 new (&newPyTmpl->fTI) std::shared_ptr<TemplateInfo>{pytmpl->fTI};
704
705#if PY_VERSION_HEX >= 0x03080000
706 newPyTmpl->fVectorCall = pytmpl->fVectorCall;
707#endif
708
709 return newPyTmpl;
710}
711
712
713//----------------------------------------------------------------------------
715{
716// Explicit template member lookup/instantiation; works by re-bounding. This method can
717// not cache overloads as instantiations need not be unique for the argument types due
718// to template specializations.
720 Py_XDECREF(typeBoundMethod->fTemplateArgs);
722 Utility::ConstructTemplateArgs(nullptr, args).c_str());
723 return (PyObject*)typeBoundMethod;
724}
725
726//-----------------------------------------------------------------------------
728{
729 return PyInt_FromLong(0); // dummy (__useffi__ unused)
730}
731
732//-----------------------------------------------------------------------------
733static int tpp_setuseffi(CPPOverload*, PyObject*, void*)
734{
735 return 0; // dummy (__useffi__ unused)
736}
737
738//-----------------------------------------------------------------------------
740 if (!self->fTemplateArgs) {
742 }
743
744 Py_INCREF(self->fTemplateArgs);
745 return self->fTemplateArgs;
746}
747
748//-----------------------------------------------------------------------------
750 PyErr_SetString(PyExc_AttributeError, "__template_args__ is read-only");
751 return -1;
752}
753
754//----------------------------------------------------------------------------
756 nullptr, (binaryfunc)tpp_subscript, nullptr
757};
758
760 {(char*)"__doc__", (getter)tpp_doc, (setter)tpp_doc_set, nullptr, nullptr},
761 {(char*)"__useffi__", (getter)tpp_getuseffi, (setter)tpp_setuseffi,
762 (char*)"unused", nullptr},
763 {(char*)"__template_args__", (getter)tpp_gettemplateargs, (setter)tpp_settemplateargs,
764 (char*)"the template arguments for this method", nullptr},
765 {(char*)nullptr, nullptr, nullptr, nullptr, nullptr},
766};
767
768
769//----------------------------------------------------------------------------
770void TemplateProxy::Set(const std::string& cppname, const std::string& pyname, PyObject* pyclass)
771{
772// Initialize the proxy for the given 'pyclass.'
773 fSelf = nullptr;
774 fTemplateArgs = nullptr;
775
776 fTI->fCppName = cppname;
778 fTI->fPyClass = pyclass;
779
780 std::vector<PyCallable*> dummy;
781 fTI->fNonTemplated = CPPOverload_New(pyname, dummy);
782 fTI->fTemplated = CPPOverload_New(pyname, dummy);
783 fTI->fLowPriority = CPPOverload_New(pyname, dummy);
784
785#if PY_VERSION_HEX >= 0x03080000
787#endif
788}
789
790
791//= CPyCppyy method proxy access to internals ================================
793{
794// Select and call a specific C++ overload, based on its signature.
795 const char* sigarg = nullptr;
796 const char* tmplarg = nullptr;
797 PyObject* sigarg_tuple = nullptr;
798 int want_const = -1;
799
802 std::string proto;
803
804 if (PyArg_ParseTuple(args, const_cast<char*>("s|i:__overload__"), &sigarg, &want_const)) {
805 want_const = PyTuple_GET_SIZE(args) == 1 ? -1 : want_const;
806
807 // check existing overloads in order
808 PyObject* ol = pytmpl->fTI->fNonTemplated->FindOverload(sigarg, want_const);
809 if (ol) return ol;
810 PyErr_Clear();
811 ol = pytmpl->fTI->fTemplated->FindOverload(sigarg, want_const);
812 if (ol) return ol;
813 PyErr_Clear();
814 ol = pytmpl->fTI->fLowPriority->FindOverload(sigarg, want_const);
815 if (ol) return ol;
816
817 proto = Utility::ConstructTemplateArgs(nullptr, args);
818
819 scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType;
821 scope, pytmpl->fTI->fCppName, proto.substr(1, proto.size()-2));
822 } else if (PyArg_ParseTuple(args, const_cast<char*>("ss:__overload__"), &sigarg, &tmplarg)) {
823 scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType;
824 std::string full_name = std::string(pytmpl->fTI->fCppName) + "<" + tmplarg + ">";
825
827 } else if (PyArg_ParseTuple(args, const_cast<char*>("O|i:__overload__"), &sigarg_tuple, &want_const)) {
828 PyErr_Clear();
829 want_const = PyTuple_GET_SIZE(args) == 1 ? -1 : want_const;
830
831 // check existing overloads in order
832 PyObject* ol = pytmpl->fTI->fNonTemplated->FindOverload(sigarg_tuple, want_const);
833 if (ol) return ol;
834 PyErr_Clear();
835 ol = pytmpl->fTI->fTemplated->FindOverload(sigarg_tuple, want_const);
836 if (ol) return ol;
837 PyErr_Clear();
838 ol = pytmpl->fTI->fLowPriority->FindOverload(sigarg_tuple, want_const);
839 if (ol) return ol;
840
841 proto.reserve(128);
842 proto.push_back('<');
844 for (int i = 0; i < n; i++) {
847 PyErr_Format(PyExc_LookupError, "argument types should be in string format");
848 return (PyObject*) nullptr;
849 }
851 if (i < n - 1)
852 proto.push_back(',');
853 }
854 proto.push_back('>');
855
856 scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType;
858 scope, pytmpl->fTI->fCppName, proto.substr(1, proto.size()-2));
859 } else {
860 PyErr_Format(PyExc_TypeError, "Unexpected arguments to __overload__");
861 return nullptr;
862 }
863
864// else attempt instantiation
865 if (!cppmeth) {
866 return nullptr;
867 }
868
869 PyErr_Clear();
870
871 // TODO: the next step should be consolidated with Instantiate()
872 PyCallable* meth = nullptr;
875 } else if (Cppyy::IsStaticMethod(cppmeth)) {
877 } else if (Cppyy::IsConstructor(cppmeth)) {
879 } else
880 meth = new CPPMethod(scope, cppmeth);
881
882 return (PyObject*)CPPOverload_New(pytmpl->fTI->fCppName+proto, meth);
883}
884
886 {(char*)"__overload__", (PyCFunction)tpp_overload, METH_VARARGS,
887 (char*)"select overload for dispatch" },
888 {(char*)nullptr, nullptr, 0, nullptr }
889};
890
891
892//= CPyCppyy template proxy type =============================================
895 (char*)"cppyy.TemplateProxy", // tp_name
896 sizeof(TemplateProxy), // tp_basicsize
897 0, // tp_itemsize
898 (destructor)tpp_dealloc, // tp_dealloc
899#if PY_VERSION_HEX >= 0x03080000
901#else
902 0, // tp_vectorcall_offset / tp_print
903#endif
904 0, // tp_getattr
905 0, // tp_setattr
906 0, // tp_as_async / tp_compare
907 0, // tp_repr
908 0, // tp_as_number
909 0, // tp_as_sequence
910 &tpp_as_mapping, // tp_as_mapping
911 (hashfunc)tpp_hash, // tp_hash
912#if PY_VERSION_HEX >= 0x03080000
913 (ternaryfunc)PyVectorcall_Call, // tp_call
914#else
915 (ternaryfunc)tpp_call, // tp_call
916#endif
917 0, // tp_str
918 0, // tp_getattro
919 0, // tp_setattro
920 0, // tp_as_buffer
922#if PY_VERSION_HEX >= 0x03080000
924#endif
925 , // tp_flags
926 (char*)"cppyy template proxy (internal)", // tp_doc
927 (traverseproc)tpp_traverse, // tp_traverse
928 (inquiry)tpp_clear, // tp_clear
929 (richcmpfunc)tpp_richcompare, // tp_richcompare
930 offsetof(TemplateProxy, fWeakrefList), // tp_weaklistoffset
931 0, // tp_iter
932 0, // tp_iternext
933 tpp_methods, // tp_methods
934 0, // tp_members
935 tpp_getset, // tp_getset
936 0, // tp_base
937 0, // tp_dict
938 (descrgetfunc)tpp_descr_get, // tp_descr_get
939 0, // tp_descr_set
940 0, // tp_dictoffset
941 0, // tp_init
942 0, // tp_alloc
943 (newfunc)tpp_new, // tp_new
944 0, // tp_free
945 0, // tp_is_gc
946 0, // tp_bases
947 0, // tp_mro
948 0, // tp_cache
949 0, // tp_subclasses
950 0 // tp_weaklist
951#if PY_VERSION_HEX >= 0x02030000
952 , 0 // tp_del
953#endif
954#if PY_VERSION_HEX >= 0x02060000
955 , 0 // tp_version_tag
956#endif
957#if PY_VERSION_HEX >= 0x03040000
958 , 0 // tp_finalize
959#endif
960#if PY_VERSION_HEX >= 0x03080000
961 , 0 // tp_vectorcall
962#endif
963#if PY_VERSION_HEX >= 0x030c0000
964 , 0 // tp_watched
965#endif
966#if PY_VERSION_HEX >= 0x030d0000
967 , 0 // tp_versions_used
968#endif
969};
970
971} // 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
void CPyCppyy_PyBuffer_Release(PyObject *, Py_buffer *view)
Definition CPyCppyy.h:282
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
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
#define TPPCALL_RETURN
const char * proto
Definition civetweb.c:18822
MethodInfo_t * fMethodInfo
Definition CPPOverload.h:79
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
PyObject * CT2CppName(PyObject *pytc, const char *cpd, bool allow_voidp)
Definition Utility.h:44
void SetDetailedException(std::vector< PyError_t > &&errors, PyObject *topmsg, PyObject *defexc)
Definition Utility.cxx:1191
std::string ConstructTemplateArgs(PyObject *pyname, PyObject *tpArgs, PyObject *args=nullptr, ArgPreference=kNone, int argoff=0, int *pcnt=nullptr)
Definition Utility.cxx:621
size_t FetchError(std::vector< PyError_t > &, bool is_cpp=false)
Definition Utility.cxx:1180
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:94
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 int tpp_settemplateargs(TemplateProxy *, PyObject *, void *)
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 *)
static PyObject * tpp_gettemplateargs(TemplateProxy *self, void *)
bool TemplateProxy_Check(T *object)
std::shared_ptr< TemplateInfo > TP_TInfo_t
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)
RPY_EXPORTED bool IsStaticTemplate(TCppScope_t scope, const std::string &name)
size_t TCppScope_t
Definition cpp_cppyy.h:18
RPY_EXPORTED std::string GetMethodFullName(TCppMethod_t)