Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
CPPFunction.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "CPPFunction.h"
4#include "CPPInstance.h"
5
6// Standard
7#include <algorithm>
8
9
10//- CFunction helpers -----------------------------------------------------------
12{
13#if PY_VERSION_HEX >= 0x03080000
14 if (cargs.fNArgsf & PY_VECTORCALL_ARGUMENTS_OFFSET) { // mutation allowed?
15 std::swap(((PyObject**)cargs.fArgs-1)[0], (PyObject*&)cargs.fSelf);
16 cargs.fFlags |= PyCallArgs::kSelfSwap;
17 cargs.fArgs -= 1;
18 cargs.fNArgsf &= ~PY_VECTORCALL_ARGUMENTS_OFFSET;
19 cargs.fNArgsf += 1;
20 } else {
21 Py_ssize_t nkwargs = cargs.fKwds ? PyTuple_GET_SIZE(cargs.fKwds) : 0;
22 Py_ssize_t totalargs = PyVectorcall_NARGS(cargs.fNArgsf)+nkwargs;
23 PyObject** newArgs = (PyObject**)PyMem_Malloc((totalargs+1) * sizeof(PyObject*));
24 if (!newArgs)
25 return false;
26
27 newArgs[0] = (PyObject*)cargs.fSelf;
28 if (0 < totalargs)
29 memcpy((void*)&newArgs[1], cargs.fArgs, totalargs * sizeof(PyObject*));
30 cargs.fArgs = newArgs;
31 cargs.fFlags |= PyCallArgs::kDoFree;
32 cargs.fNArgsf += 1;
33 }
34#else
35 Py_ssize_t sz = PyTuple_GET_SIZE(cargs.fArgs);
36 CPyCppyy_PyArgs_t newArgs = PyTuple_New(sz+1);
37 for (int i = 0; i < sz; ++i) {
38 PyObject* item = PyTuple_GET_ITEM(cargs.fArgs, i);
39 Py_INCREF(item);
40 PyTuple_SET_ITEM(newArgs, i+1, item);
41 }
42 Py_INCREF(cargs.fSelf);
43 PyTuple_SET_ITEM(newArgs, 0, (PyObject*)cargs.fSelf);
44
45 cargs.fArgs = newArgs;
46 cargs.fFlags |= PyCallArgs::kDoDecref;
47 cargs.fNArgsf += 1;
48#endif
49 return true;
50}
51
53{
54// add self as part of the function arguments (means bound member)
55 if (cargs.fKwds)
56 return this->ProcessKwds((PyObject*)cargs.fSelf, cargs);
57 return AdjustSelf(cargs);
58}
59
60//- CPPFunction public members --------------------------------------------------
62 CPyCppyy_PyArgs_t args, size_t nargsf, PyObject* kwds, CallContext* ctxt)
63{
64// setup as necessary
65 if (fArgsRequired == -1 && !this->Initialize(ctxt))
66 return nullptr;
67
68// if function was attached to a class, self will be non-zero and should be
69// the first function argument, so reorder
70 PyCallArgs cargs{self, args, nargsf, kwds};
71 if (self || kwds) {
72 if (!this->ProcessArgs(cargs))
73 return nullptr;
74 }
75
76#if PY_VERSION_HEX >= 0x03080000
77// special case, if this method was inserted as a constructor, then self is nullptr
78// and it will be the first argument and needs to be used as Python context
79 if (IsConstructor(ctxt->fFlags) && !ctxt->fPyContext && \
80 CPyCppyy_PyArgs_GET_SIZE(cargs.fArgs, cargs.fNArgsf)) {
81 ctxt->fPyContext = cargs.fArgs[0];
82 }
83#endif
84
85// translate the arguments as normal
86 if (!this->ConvertAndSetArgs(cargs.fArgs, cargs.fNArgsf, ctxt))
87 return nullptr;
88
89// execute function
90 PyObject* result = this->Execute(nullptr, 0, ctxt);
91
92#if PY_VERSION_HEX >= 0x03080000
93// special case, if this method was inserted as a constructor, then if no self was
94// provided, it will be the first argument and may have been updated
95 if (IsConstructor(ctxt->fFlags) && result && !cargs.fSelf && \
96 CPyCppyy_PyArgs_GET_SIZE(cargs.fArgs, cargs.fNArgsf) && CPPInstance_Check(cargs.fArgs[0])) {
97 self = (CPPInstance*)cargs.fArgs[0];
98 Py_INCREF(self);
99 }
100#endif
101
102 return result;
103}
104
105
106//- CPPReverseBinary private helper ---------------------------------------------
108{
109 if (cargs.fSelf || cargs.fKwds) {
110 // add self as part of the function arguments (means bound member)
111 if (!this->CPPFunction::ProcessArgs(cargs))
112 return false;
113 }
114
115// swap the arguments
116#if PY_VERSION_HEX >= 0x03080000
117 std::swap(((PyObject**)cargs.fArgs)[0], ((PyObject**)cargs.fArgs)[1]);
118#else
119 std::swap(PyTuple_GET_ITEM(cargs.fArgs, 0), PyTuple_GET_ITEM(cargs.fArgs, 1));
120#endif
122
123 return true;
124}
125
126//- CPPReverseBinary public members ---------------------------------------------
128 CPyCppyy_PyArgs_t args, size_t nargsf, PyObject* kwds, CallContext* ctxt)
129{
130// This Call() function is very similar to the one of CPPFunction: only difference is
131// that ProcessArgs() is always called.
132
133// setup as necessary
134 if (fArgsRequired == -1 && !this->Initialize(ctxt))
135 return nullptr;
136
137// if function was attached to a class, self will be non-zero and should be
138// the first function argument, further, the arguments needs swapping
139 PyCallArgs cargs{self, args, nargsf, kwds};
140 if (!this->ProcessArgs(cargs))
141 return nullptr;
142
143// translate the arguments as normal
144 if (!this->ConvertAndSetArgs(cargs.fArgs, cargs.fNArgsf, ctxt))
145 return nullptr;
146
147// execute function
148 return this->Execute(nullptr, 0, ctxt);
149}
int Py_ssize_t
Definition CPyCppyy.h:215
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
_object PyObject
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
virtual PyObject * Call(CPPInstance *&self, CPyCppyy_PyArgs_t args, size_t nargsf, PyObject *kwds, CallContext *ctxt=nullptr)
virtual bool ProcessArgs(PyCallArgs &args)
bool ProcessKwds(PyObject *self_in, PyCallArgs &args)
virtual bool ProcessArgs(PyCallArgs &args)
virtual PyObject * Call(CPPInstance *&self, CPyCppyy_PyArgs_t args, size_t nargsf, PyObject *kwds, CallContext *ctxt=nullptr)
CPyCppyy_PyArgs_t fArgs
Definition CPPMethod.h:39
CPPInstance *& fSelf
Definition CPPMethod.h:38
bool AdjustSelf(PyCallArgs &cargs)
bool CPPInstance_Check(T *object)
bool IsConstructor(uint64_t flags)