29 : fPyClass(nullptr), fNonTemplated(nullptr), fTemplated(nullptr),
30 fLowPriority(nullptr), fDoc(nullptr) {
44 for (
const auto&
c :
p.second) {
53 bool isGreedy =
false;
73 fTI->fTemplated->AdoptMethod(pc);
81 std::string proto =
"";
82 std::string protoPair =
"";
96 PyObject* tpArgs = PyTuple_New(argc);
97 for (Py_ssize_t i = 0; i < argc; ++i) {
100 bool bArgSet =
false;
105 PyObject*
f = PyUnicode_FromFormat(
"%s%s", tn->
fTI->fCppName.c_str(),
107 PyTuple_SET_ITEM(tpArgs, i,
f);
113 memset(&bufinfo, 0,
sizeof(Py_buffer));
115 if (PyObject_GetBuffer(itemi, &bufinfo, PyBUF_FORMAT) == 0) {
116 for (
int j = 0; j < bufinfo.ndim; ++j)
118 PyBuffer_Release(&bufinfo);
126 PyTuple_SET_ITEM(tpArgs, i, pyptrname);
139 if (!bArgSet && pytc) {
154 PyTuple_SET_ITEM(tpArgs, i, pyactname);
166 PyTuple_SET_ITEM(tpArgs, i, tp);
170 PyObject* pyargs = PyTuple_New(argc);
171 for (Py_ssize_t i = 0; i < argc; ++i) {
174 PyTuple_SET_ITEM(pyargs, i, item);
176 const std::string& name_v1 =
183 if (!PyErr_Occurred()) {
184 bool has2Tuple =
false;
185 for (Py_ssize_t i = 0; i < argc; ++i) {
187 if (PyTuple_CheckExact(itemi) && PyTuple_GET_SIZE(itemi) == 2) {
194 PyObject* tpArgsPair = PyTuple_New(argc);
195 for (Py_ssize_t i = 0; i < argc; ++i) {
198 if (PyTuple_CheckExact(itemi) && PyTuple_GET_SIZE(itemi) == 2) {
199 PyObject* subtypes = PyTuple_New(2);
200 for (Py_ssize_t j = 0; j < 2; ++j) {
203 PyTuple_SET_ITEM(subtypes, j, tp);
206 nullptr, subtypes, itemi, pref, 0,
nullptr);
208 if (!PyErr_Occurred() && 2 < sub.size())
209 entry = PyUnicode_FromString((
"std::pair" + sub).c_str());
214 entry = PyTuple_GET_ITEM(tpArgs, i);
217 PyTuple_SET_ITEM(tpArgsPair, i, entry);
221 nullptr, tpArgsPair, pyargs, pref, 0,
nullptr);
222 Py_DECREF(tpArgsPair);
223 if (!PyErr_Occurred() && name_v2.size())
224 protoPair = name_v2.substr(1, name_v2.size() - 2);
235 if (PyErr_Occurred()) {
240 proto = name_v1.substr(1, name_v1.size() - 2);
247 if (!cppmeth && !protoPair.empty() && protoPair != proto) {
267 std::string resname =
273 if (resname.find(
"initializer_list") != std::string::npos) {
274 auto pos = proto.find(
"initializer_list");
275 while (pos != std::string::npos) {
276 proto.replace(pos, 16,
"vector");
277 pos = proto.find(
"initializer_list", pos + 6);
282 if (m2 && m2 != cppmeth) {
290 bool bExactMatch = fname == resname;
295 PyObject* pycachename = PyUnicode_InternFromString(fname.c_str());
296 PyObject* pyol = PyObject_GetItem(dct, pycachename);
304 PyObject* pyresname = PyUnicode_FromString(resname.c_str());
306 exact = PyObject_GetItem(dct, pyresname);
312 bool bIsConstructor =
false, bNeedsRebind =
true;
317 bNeedsRebind =
false;
320 bNeedsRebind =
false;
322 bIsConstructor =
true;
331 if (bIsConstructor) {
338 PyType_Type.tp_setattro(
fTI->fPyClass, pycachename, pyol);
351 auto* existing =
dynamic_cast<CPPMethod*
>(pc);
352 if (existing && existing->GetMethod() == cppmeth) {
379 if (!exact && !bExactMatch) {
380 PyType_Type.tp_setattro(
fTI->fPyClass, pyresname, pyol);
385 Py_DECREF(pyresname);
386 Py_DECREF(pycachename);
395 PyErr_Format(PyExc_TypeError,
"Failed to instantiate \"%s(%s)\"",
396 fname.c_str(), proto.c_str());
404 pytmpl->
fSelf =
nullptr;
408 pytmpl->
fTI = std::make_shared<TemplateInfo>();
410 PyObject_GC_Track(pytmpl);
419 if (op == Py_EQ || op == Py_NE) {
429 Py_INCREF(Py_NotImplemented);
430 return Py_NotImplemented;
436 Py_CLEAR(pytmpl->
fSelf);
446 PyObject_ClearWeakRefs((
PyObject*)pytmpl);
447 PyObject_GC_UnTrack(pytmpl);
449 pytmpl->
fTI.~TP_TInfo_t();
450 PyObject_GC_Del(pytmpl);
456 Py_VISIT(pytmpl->
fSelf);
464 if (pytmpl->
fTI->fDoc) {
465 Py_INCREF(pytmpl->
fTI->fDoc);
466 return pytmpl->
fTI->fDoc;
471 if (pytmpl->
fTI->fNonTemplated->HasMethods())
472 doc = PyObject_GetAttrString((
PyObject*)pytmpl->
fTI->fNonTemplated,
474 if (pytmpl->
fTI->fTemplated->HasMethods()) {
476 PyObject_GetAttrString((
PyObject*)pytmpl->
fTI->fTemplated,
"__doc__");
478 PyUnicode_AppendAndDel(&doc, PyUnicode_FromString(
"\n"));
479 PyUnicode_AppendAndDel(&doc, doc2);
480 }
else if (!doc && doc2) {
484 if (pytmpl->
fTI->fLowPriority->HasMethods()) {
486 PyObject_GetAttrString((
PyObject*)pytmpl->
fTI->fLowPriority,
"__doc__");
488 PyUnicode_AppendAndDel(&doc, PyUnicode_FromString(
"\n"));
489 PyUnicode_AppendAndDel(&doc, doc2);
490 }
else if (!doc && doc2) {
502 Py_XDECREF(pytmpl->
fTI->fDoc);
504 pytmpl->
fTI->fDoc = val;
512#define TPPCALL_RETURN \
522 bool bInserted =
false;
523 auto&
v = pytmpl->
fTI->fDispatchMap[use_targs ?
targs2str(pytmpl) :
""];
527 if (
p.first == sighash) {
534 v.push_back(std::make_pair(sighash, pymeth));
540 bool implicitOkay,
bool use_targs, uint64_t sighash,
541 std::vector<Utility::PyError_t>& errors) {
575 if (isNS && pytmpl->
fSelf && pytmpl->
fSelf != Py_None) {
636 auto&
v = pytmpl->
fTI->fDispatchMap[
""];
637 for (
const auto&
p :
v) {
638 if (
p.first == sighash) {
645 if (!pytmpl->
fSelf || pytmpl->
fSelf == Py_None) {
660 std::vector<Utility::PyError_t> errors;
667 PyObject* pyfullname = PyUnicode_FromString(pytmpl->
fTI->fCppName.c_str());
673 if (pytmpl->
fSelf && pytmpl->
fSelf != Py_None && !isNS)
674 pymeth = PyObject_GetAttr(pytmpl->
fSelf, pyfullname);
676 pymeth = PyType_Type.tp_getattro(pytmpl->
fTI->fPyClass, pyfullname);
685 Py_DECREF(pyfullname);
689 }
else if (pymeth && PyCallable_Check(pymeth)) {
694 Py_DECREF(pyfullname);
702 pymeth = pytmpl->
Instantiate(PyUnicode_AsUTF8(pyfullname), args, nargsf,
710 Py_DECREF(pyfullname);
718 PyObject* topmsg = PyUnicode_FromFormat(
719 "Could not find \"%s\" (set cppjit.set_debug() for C++ errors):",
720 PyUnicode_AsUTF8(pyfullname));
721 Py_DECREF(pyfullname);
731 false , sighash, errors);
748 pytmpl->
Instantiate(pytmpl->
fTI->fCppName, args, nargsf, pref, &pcnt);
765 false , sighash, errors);
771 if (!errors.empty()) {
773 PyUnicode_FromString(
"Template method resolution failed:");
777 PyErr_Format(PyExc_TypeError,
778 "cannot resolve method template call for \'%s\'",
779 pytmpl->
fTI->fCppName.c_str());
795 newPyTmpl->
fSelf = pyobj;
798 newPyTmpl->
fSelf = Py_None;
805 new (&newPyTmpl->
fTI) std::shared_ptr<TemplateInfo>{pytmpl->
fTI};
824 if (PyErr_Occurred()) {
832 return PyLong_FromLong(0);
852 PyErr_SetString(PyExc_AttributeError,
"__template_args__ is read-only");
863 (
char*)
"unused",
nullptr},
866 (
char*)
"the template arguments for this method",
nullptr},
867 {(
char*)
nullptr,
nullptr,
nullptr,
nullptr,
nullptr},
877 fTI->fCppName = cppname;
879 fTI->fPyClass = pyclass;
881 std::vector<PyCallable*> dummy;
892 const char* sigarg =
nullptr;
893 const char* tmplarg =
nullptr;
901 if (PyArg_ParseTuple(args,
const_cast<char*
>(
"s|i:__overload__"), &sigarg,
903 want_const = PyTuple_GET_SIZE(args) == 1 ? -1 : want_const;
906 PyObject* ol = pytmpl->
fTI->fNonTemplated->FindOverload(sigarg, want_const);
910 ol = pytmpl->
fTI->fTemplated->FindOverload(sigarg, want_const);
914 ol = pytmpl->
fTI->fLowPriority->FindOverload(sigarg, want_const);
921 if (PyErr_Occurred()) {
925 scope = ((
CPPClass*)pytmpl->
fTI->fPyClass)->fCppType;
927 proto.substr(1, proto.size() - 2));
928 }
else if (PyArg_ParseTuple(args,
const_cast<char*
>(
"ss:__overload__"),
929 &sigarg, &tmplarg)) {
930 scope = ((
CPPClass*)pytmpl->
fTI->fPyClass)->fCppType;
931 std::string full_name =
932 std::string(pytmpl->
fTI->fCppName) +
"<" + tmplarg +
">";
935 }
else if (PyArg_ParseTuple(args,
const_cast<char*
>(
"O|i:__overload__"),
936 &sigarg_tuple, &want_const)) {
938 want_const = PyTuple_GET_SIZE(args) == 1 ? -1 : want_const;
942 pytmpl->
fTI->fNonTemplated->FindOverload(sigarg_tuple, want_const);
946 ol = pytmpl->
fTI->fTemplated->FindOverload(sigarg_tuple, want_const);
950 ol = pytmpl->
fTI->fLowPriority->FindOverload(sigarg_tuple, want_const);
955 proto.push_back(
'<');
956 Py_ssize_t
n = PyTuple_Size(sigarg_tuple);
957 for (
int i = 0; i <
n; i++) {
958 PyObject* pItem = PyTuple_GetItem(sigarg_tuple, i);
959 if (!PyUnicode_Check(pItem)) {
960 PyErr_Format(PyExc_LookupError,
961 "argument types should be in string format");
964 proto.append(PyUnicode_AsUTF8(pItem));
966 proto.push_back(
',');
968 proto.push_back(
'>');
970 scope = ((
CPPClass*)pytmpl->
fTI->fPyClass)->fCppType;
972 proto.substr(1, proto.size() - 2));
974 PyErr_Format(PyExc_TypeError,
"Unexpected arguments to __overload__");
1001 (
char*)
"select overload for dispatch"},
1002 {(
char*)
nullptr,
nullptr, 0,
nullptr}};
1006 PyVarObject_HEAD_INIT(&PyType_Type,
1007 0)(
char*)
"cppjit.TemplateProxy",
1020 (ternaryfunc)PyVectorcall_Call,
1026 Py_TPFLAGS_METHOD_DESCRIPTOR,
1027 (
char*)
"cppjit template proxy (internal)",
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
void AdoptMethod(PyCallable *pc)
void MergeOverload(CPPOverload *meth)
MethodInfo_t * fMethodInfo
virtual bool IsGreedy()=0
virtual PyCallable * Clone()=0
CPPOverload * fLowPriority
CPPOverload * fNonTemplated
TP_DispatchMap_t fDispatchMap
void AdoptTemplate(PyCallable *pc)
void Set(const std::string &cppname, const std::string &pyname, PyObject *pyclass)
PyObject * Instantiate(const std::string &fname, cpyrt_PyArgs_t tmplArgs, size_t nargsf, Utility::ArgPreference, int *pcnt=nullptr)
void AdoptMethod(PyCallable *pc)
PyObject_HEAD PyObject * fSelf
void MergeOverload(CPPOverload *mp)
vectorcallfunc fVectorCall
PyObject *const * cpyrt_PyArgs_t
static Py_ssize_t cpyrt_PyArgs_GET_SIZE(cpyrt_PyArgs_t, size_t nargsf)
PyObject * cpyrt_tp_call(PyObject *cb, cpyrt_PyArgs_t args, size_t nargsf, PyObject *kwds)
#define Py_TPFLAGS_HAVE_VECTORCALL
#define CPYRT_PYTYPE_TAIL
#define cpyrt_PyObject_Call
static PyObject * cpyrt_PyArgs_GET_ITEM(cpyrt_PyArgs_t args, Py_ssize_t i)
std::string ConstructTemplateArgs(PyObject *pyname, PyObject *tpArgs, PyObject *args=nullptr, ArgPreference=kNone, int argoff=0, int *pcnt=nullptr)
size_t FetchError(std::vector< PyError_t > &, bool is_cpp=false)
void SetDetailedException(std::vector< PyError_t > &&errors, PyObject *topmsg, PyObject *defexc)
PyObject * CT2CppName(PyObject *pytc, const char *cpd, bool allow_voidp)
bool CPPOverload_Check(T *object)
bool TemplateProxy_Check(T *object)
static void tpp_dealloc(TemplateProxy *pytmpl)
static int tpp_settemplateargs(TemplateProxy *, PyObject *, void *)
static PyMethodDef tpp_methods[]
static PyGetSetDef tpp_getset[]
static TemplateProxy * tpp_new(PyTypeObject *, PyObject *, PyObject *)
static void UpdateDispatchMap(TemplateProxy *pytmpl, bool use_targs, uint64_t sighash, CPPOverload *pymeth)
bool AdjustSelf(PyCallArgs &cargs)
static PyObject * tpp_vectorcall(TemplateProxy *pytmpl, PyObject *const *args, size_t nargsf, PyObject *kwds)
uint64_t HashSignature(cpyrt_PyArgs_t args, size_t nargsf)
static int tpp_setuseffi(CPPOverload *, PyObject *, void *)
PyTypeObject CPPOverload_Type
static PyObject * tpp_gettemplateargs(TemplateProxy *self, void *)
static int tpp_clear(TemplateProxy *pytmpl)
static PyObject * tpp_getuseffi(CPPOverload *, void *)
static std::string targs2str(TemplateProxy *pytmpl)
static PyObject * SelectAndForward(TemplateProxy *pytmpl, CPPOverload *pymeth, cpyrt_PyArgs_t args, size_t nargsf, PyObject *kwds, bool implicitOkay, bool use_targs, uint64_t sighash, std::vector< Utility::PyError_t > &errors)
PyTypeObject TemplateProxy_Type
static int tpp_doc_set(TemplateProxy *pytmpl, PyObject *val, void *)
static PyObject * tpp_subscript(TemplateProxy *pytmpl, PyObject *args)
static TemplateProxy * tpp_descr_get(TemplateProxy *pytmpl, PyObject *pyobj, PyObject *)
static Py_hash_t tpp_hash(TemplateProxy *self)
bool TemplateProxy_CheckExact(T *object)
static PyMappingMethods tpp_as_mapping
std::shared_ptr< TemplateInfo > TP_TInfo_t
static int tpp_traverse(TemplateProxy *pytmpl, visitproc visit, void *arg)
static PyObject * tpp_richcompare(TemplateProxy *self, PyObject *other, int op)
CPPOverload * CPPOverload_New(const std::string &name, std::vector< PyCallable * > &methods)
static PyObject * CallMethodImp(TemplateProxy *pytmpl, PyObject *&pymeth, cpyrt_PyArgs_t args, size_t nargsf, PyObject *kwds, bool impOK, uint64_t sighash)
static PyObject * tpp_doc(TemplateProxy *pytmpl, void *)
static PyObject * tpp_overload(TemplateProxy *pytmpl, PyObject *args)
TCppMethod_t GetMethodTemplate(TCppScope_t scope, const std::string &name, const std::string &proto)
bool IsStaticTemplate(TCppScope_t scope, const std::string &name)
bool IsConstructor(TCppMethod_t method)
Cpp::FuncRef TCppMethod_t
std::string GetFullName(TCppScope_t)
bool IsNamespace(TCppScope_t scope)
bool IsStaticMethod(TCppMethod_t method)
CPPOverload::Methods_t fMethods