Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Converters.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "DeclareConverters.h"
4#include "CallContext.h"
5#include "CPPExcInstance.h"
6#include "CPPInstance.h"
7#include "CPPOverload.h"
8#include "CustomPyTypes.h"
9#include "LowLevelViews.h"
10#include "MemoryRegulator.h"
11#include "ProxyWrappers.h"
12#include "PyStrings.h"
13#include "TemplateProxy.h"
14#include "TupleOfInstances.h"
15#include "TypeManip.h"
16#include "Utility.h"
17
18// Standard
19#include <limits.h>
20#include <stddef.h> // for ptrdiff_t
21#include <string.h>
22#include <array>
23#include <utility>
24#include <sstream>
25#if __cplusplus > 201402L
26#include <cstddef>
27#endif
28#include "ROOT/RStringView.hxx"
29
30#define UNKNOWN_SIZE -1
31#define UNKNOWN_ARRAY_SIZE -2
32
33
34//- data _____________________________________________________________________
35namespace CPyCppyy {
36
37// factories
38 typedef std::map<std::string, cf_t> ConvFactories_t;
41
42}
43
44#if PY_VERSION_HEX < 0x03000000
45const size_t MOVE_REFCOUNT_CUTOFF = 1;
46#else
47// p3 has at least 2 ref-counts, as contrary to p2, it will create a descriptor
48// copy for the method holding self in the case of __init__; but there can also
49// be a reference held by the frame object, which is indistinguishable from a
50// local variable reference, so the cut-off has to remain 2.
51const size_t MOVE_REFCOUNT_CUTOFF = 2;
52#endif
53
54//- pretend-ctypes helpers ---------------------------------------------------
55struct CPyCppyy_tagCDataObject { // non-public (but stable)
56 PyObject_HEAD
57 char* b_ptr;
59};
60
61struct CPyCppyy_tagPyCArgObject { // not public (but stable; note that older
62 PyObject_HEAD // Pythons protect 'D' with HAVE_LONG_LONG)
63 void* pffi_type;
64 char tag;
65 union { // for convenience, kept only relevant vals
66 long long q;
67 long double D;
68 void *p;
71};
72
73// indices of ctypes types into the array caches (not that c_complex does not
74// exist as a type in ctypes)
75#define ct_c_bool 0
76#define ct_c_char 1
77#define ct_c_shar 1
78#define ct_c_wchar 2
79#define ct_c_byte 3
80#define ct_c_int8 3
81#define ct_c_ubyte 4
82#define ct_c_uchar 4
83#define ct_c_uint8 4
84#define ct_c_short 5
85#define ct_c_ushort 6
86#define ct_c_uint16 7
87#define ct_c_int 8
88#define ct_c_uint 9
89#define ct_c_uint32 10
90#define ct_c_long 11
91#define ct_c_ulong 12
92#define ct_c_longlong 13
93#define ct_c_ulonglong 14
94#define ct_c_float 15
95#define ct_c_double 16
96#define ct_c_longdouble 17
97#define ct_c_char_p 18
98#define ct_c_wchar_p 19
99#define ct_c_void_p 20
100#define ct_c_complex 21
101#define NTYPES 22
102
103static std::array<const char*, NTYPES> gCTypesNames = {
104 "c_bool", "c_char", "c_wchar", "c_byte", "c_ubyte", "c_short", "c_ushort", "c_uint16",
105 "c_int", "c_uint", "c_uint32", "c_long", "c_ulong", "c_longlong", "c_ulonglong",
106 "c_float", "c_double", "c_longdouble",
107 "c_char_p", "c_wchar_p", "c_void_p", "c_complex" };
108static std::array<PyTypeObject*, NTYPES> gCTypesTypes;
109static std::array<PyTypeObject*, NTYPES> gCTypesPtrTypes;
110
111// Both GetCTypesType and GetCTypesPtrType, rely on the ctypes module itself
112// caching the types (thus also making them unique), so no ref-count is needed.
113// Further, by keeping a ref-count on the module, it won't be off-loaded until
114// the 2nd cleanup cycle.
115static PyTypeObject* GetCTypesType(int nidx)
116{
117 static PyObject* ctmod = PyImport_ImportModule("ctypes"); // ref-count kept
118 if (!ctmod) {
119 PyErr_Clear();
120 return nullptr;
121 }
122 PyTypeObject* ct_t = gCTypesTypes[nidx];
123 if (!ct_t) {
124 ct_t = (PyTypeObject*)PyObject_GetAttrString(ctmod, gCTypesNames[nidx]);
125 if (!ct_t) PyErr_Clear();
126 else {
127 gCTypesTypes[nidx] = ct_t;
128 Py_DECREF(ct_t);
129 }
130 }
131 return ct_t;
132}
133
134static PyTypeObject* GetCTypesPtrType(int nidx)
135{
136 static PyObject* ctmod = PyImport_ImportModule("ctypes"); // ref-count kept
137 if (!ctmod) {
138 PyErr_Clear();
139 return nullptr;
140 }
141 PyTypeObject* cpt_t = gCTypesPtrTypes[nidx];
142 if (!cpt_t) {
143 if (strcmp(gCTypesNames[nidx], "c_char") == 0) {
144 cpt_t = (PyTypeObject*)PyObject_GetAttrString(ctmod, "c_char_p");
145 } else {
146 PyObject* ct_t = (PyObject*)GetCTypesType(nidx);
147 if (ct_t) {
148 PyObject* ptrcreat = PyObject_GetAttrString(ctmod, "POINTER");
149 cpt_t = (PyTypeObject*)PyObject_CallFunctionObjArgs(ptrcreat, ct_t, NULL);
150 Py_DECREF(ptrcreat);
151 }
152 }
153 if (cpt_t) {
154 gCTypesPtrTypes[nidx] = cpt_t;
155 Py_DECREF(cpt_t);
156 }
157 }
158 return cpt_t;
159}
160
161static bool IsPyCArgObject(PyObject* pyobject)
162{
163 static PyTypeObject* pycarg_type = nullptr;
164 if (!pycarg_type) {
165 PyObject* ctmod = PyImport_ImportModule("ctypes");
166 if (!ctmod) PyErr_Clear();
167 else {
168 PyTypeObject* ct_t = (PyTypeObject*)PyObject_GetAttrString(ctmod, "c_int");
169 PyObject* cobj = ct_t->tp_new(ct_t, nullptr, nullptr);
170 PyObject* byref = PyObject_GetAttrString(ctmod, "byref");
171 PyObject* pyptr = PyObject_CallFunctionObjArgs(byref, cobj, NULL);
172 Py_DECREF(byref); Py_DECREF(cobj); Py_DECREF(ct_t);
173 pycarg_type = Py_TYPE(pyptr); // static, no ref-count needed
174 Py_DECREF(pyptr);
175 Py_DECREF(ctmod);
176 }
177 }
178 return Py_TYPE(pyobject) == pycarg_type;
179}
180
181static bool IsCTypesArrayOrPointer(PyObject* pyobject)
182{
183 static PyTypeObject* cstgdict_type = nullptr;
184 if (!cstgdict_type) {
185 // get any pointer type to initialize the extended dictionary type
186 PyTypeObject* ct_int = GetCTypesType(ct_c_int);
187 if (ct_int && ct_int->tp_dict) {
188 cstgdict_type = Py_TYPE(ct_int->tp_dict);
189 }
190 }
191
192 PyTypeObject* pytype = Py_TYPE(pyobject);
193 if (pytype->tp_dict && Py_TYPE(pytype->tp_dict) == cstgdict_type)
194 return true;
195 return false;
196}
197
198
199//- helper to establish life lines -------------------------------------------
200static inline bool SetLifeLine(PyObject* holder, PyObject* target, intptr_t ref)
201{
202// set a lifeline from on the holder to the target, using the ref as label
203 if (!holder) return false;
204
205// 'ref' is expected to be the converter address or data memory location, so
206// that the combination of holder and ref is unique, but also identifiable for
207// reuse when the C++ side is being overwritten
208 std::ostringstream attr_name;
209 attr_name << "__" << ref;
210 auto attr_name_str = attr_name.str();
211 auto res = PyObject_SetAttrString(holder, attr_name_str.c_str(), target);
212 return res != -1;
213}
214
215//- helper to work with both CPPInstance and CPPExcInstance ------------------
217{
218 using namespace CPyCppyy;
219 if (CPPInstance_Check(pyobject))
220 return (CPPInstance*)pyobject;
221 if (CPPExcInstance_Check(pyobject))
222 return (CPPInstance*)((CPPExcInstance*)pyobject)->fCppInstance;
223 return nullptr;
224}
225
226
227//- custom helpers to check ranges -------------------------------------------
228static inline bool CPyCppyy_PyLong_AsBool(PyObject* pyobject)
229{
230// range-checking python integer to C++ bool conversion
231 long l = PyLong_AsLong(pyobject);
232// fail to pass float -> bool; the problem is rounding (0.1 -> 0 -> False)
233 if (!(l == 0|| l == 1) || PyFloat_Check(pyobject)) {
234 PyErr_SetString(PyExc_ValueError, "boolean value should be bool, or integer 1 or 0");
235 return (bool)-1;
236 }
237 return (bool)l;
238}
239
240static inline char CPyCppyy_PyText_AsChar(PyObject* pyobject) {
241// python string to C++ char conversion
242 return (char)CPyCppyy_PyText_AsString(pyobject)[0];
243}
244
246{
247// range-checking python integer to C++ uint8_t conversion (typically, an unsigned char)
248// prevent p2.7 silent conversions and do a range check
249 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
250 PyErr_SetString(PyExc_TypeError, "short int conversion expects an integer object");
251 return (uint8_t)-1;
252 }
253 long l = PyLong_AsLong(pyobject);
254 if (l < 0 || UCHAR_MAX < l) {
255 PyErr_Format(PyExc_ValueError, "integer %ld out of range for uint8_t", l);
256 return (uint8_t)-1;
257
258 }
259 return (uint8_t)l;
260}
261
262static inline int8_t CPyCppyy_PyLong_AsInt8(PyObject* pyobject)
263{
264// range-checking python integer to C++ int8_t conversion (typically, an signed char)
265// prevent p2.7 silent conversions and do a range check
266 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
267 PyErr_SetString(PyExc_TypeError, "short int conversion expects an integer object");
268 return (int8_t)-1;
269 }
270 long l = PyLong_AsLong(pyobject);
271 if (l < SCHAR_MIN || SCHAR_MAX < l) {
272 PyErr_Format(PyExc_ValueError, "integer %ld out of range for int8_t", l);
273 return (int8_t)-1;
274
275 }
276 return (int8_t)l;
277}
278
279static inline unsigned short CPyCppyy_PyLong_AsUShort(PyObject* pyobject)
280{
281// range-checking python integer to C++ unsigend short int conversion
282
283// prevent p2.7 silent conversions and do a range check
284 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
285 PyErr_SetString(PyExc_TypeError, "unsigned short conversion expects an integer object");
286 return (unsigned short)-1;
287 }
288 long l = PyLong_AsLong(pyobject);
289 if (l < 0 || USHRT_MAX < l) {
290 PyErr_Format(PyExc_ValueError, "integer %ld out of range for unsigned short", l);
291 return (unsigned short)-1;
292
293 }
294 return (unsigned short)l;
295}
296
297static inline short CPyCppyy_PyLong_AsShort(PyObject* pyobject)
298{
299// range-checking python integer to C++ short int conversion
300// prevent p2.7 silent conversions and do a range check
301 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
302 PyErr_SetString(PyExc_TypeError, "short int conversion expects an integer object");
303 return (short)-1;
304 }
305 long l = PyLong_AsLong(pyobject);
306 if (l < SHRT_MIN || SHRT_MAX < l) {
307 PyErr_Format(PyExc_ValueError, "integer %ld out of range for short int", l);
308 return (short)-1;
309
310 }
311 return (short)l;
312}
313
314static inline int CPyCppyy_PyLong_AsStrictInt(PyObject* pyobject)
315{
316// strict python integer to C++ integer conversion
317
318// p2.7 and later silently converts floats to long, therefore require this
319// check; earlier pythons may raise a SystemError which should be avoided as
320// it is confusing
321 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
322 PyErr_SetString(PyExc_TypeError, "int/long conversion expects an integer object");
323 return -1;
324 }
325 long l = PyLong_AsLong(pyobject);
326 if (l < INT_MIN || INT_MAX < l) {
327 PyErr_Format(PyExc_ValueError, "integer %ld out of range for int", l);
328 return (int)-1;
329
330 }
331 return (int)l;
332}
333
334static inline long CPyCppyy_PyLong_AsStrictLong(PyObject* pyobject)
335{
336// strict python integer to C++ long integer conversion
337
338// prevent float -> long (see CPyCppyy_PyLong_AsStrictInt)
339 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
340 PyErr_SetString(PyExc_TypeError, "int/long conversion expects an integer object");
341 return (long)-1;
342 }
343 return (long)PyLong_AsLong(pyobject);
344}
345
346
347//- helper for pointer/array/reference conversions ---------------------------
348static inline bool CArraySetArg(PyObject* pyobject, CPyCppyy::Parameter& para, char tc, int size)
349{
350// general case of loading a C array pointer (void* + type code) as function argument
351 if (pyobject == CPyCppyy::gNullPtrObject)
352 para.fValue.fVoidp = nullptr;
353 else {
354 Py_ssize_t buflen = CPyCppyy::Utility::GetBuffer(pyobject, tc, size, para.fValue.fVoidp);
355 if (!buflen) {
356 // stuck here as it's the least common
357 if (CPyCppyy_PyLong_AsStrictInt(pyobject) == 0)
358 para.fValue.fVoidp = nullptr;
359 else {
360 PyErr_Format(PyExc_TypeError, // ValueError?
361 "could not convert argument to buffer or nullptr");
362 return false;
363 }
364 }
365 }
366 para.fTypeCode = 'p';
367 return true;
368}
369
370
371//- helper for implicit conversions ------------------------------------------
372static inline bool ConvertImplicit(Cppyy::TCppType_t klass,
373 PyObject* pyobject, CPyCppyy::Parameter& para, CPyCppyy::CallContext* ctxt)
374{
375 using namespace CPyCppyy;
376
377// filter out copy and move constructors
378 if (IsConstructor(ctxt->fFlags) && klass == ctxt->fCurScope && ctxt->GetSize() == 1)
379 return false;
380
381// only proceed if implicit conversions are allowed (in "round 2") or if the
382// argument is exactly a tuple or list, as these are the equivalent of
383// initializer lists and thus "syntax" not a conversion
384 if (!AllowImplicit(ctxt)) {
385 PyTypeObject* pytype = (PyTypeObject*)Py_TYPE(pyobject);
386 if (!(pytype == &PyList_Type || pytype == &PyTuple_Type)) {
387 if (!NoImplicit(ctxt)) ctxt->fFlags |= CallContext::kHaveImplicit;
388 return false;
389 }
390 }
391
392// exercise implicit conversion
393 PyObject* pyscope = CreateScopeProxy(klass);
394 if (!CPPScope_Check(pyscope)) {
395 Py_XDECREF(pyscope);
396 return false;
397 }
398
399// add a pseudo-keyword argument to prevent recursion
400 PyObject* kwds = PyDict_New();
401 PyDict_SetItem(kwds, PyStrings::gNoImplicit, Py_True);
402 PyObject* args = PyTuple_New(1);
403 Py_INCREF(pyobject); PyTuple_SET_ITEM(args, 0, pyobject);
404
405// call constructor of argument type to attempt implicit conversion
406 CPPInstance* pytmp = (CPPInstance*)PyObject_Call(pyscope, args, kwds);
407 if (!pytmp && PyTuple_CheckExact(pyobject)) {
408 // special case: allow implicit conversion from given set of arguments in tuple
409 PyErr_Clear();
410 PyDict_SetItem(kwds, PyStrings::gNoImplicit, Py_True); // was deleted
411 pytmp = (CPPInstance*)PyObject_Call(pyscope, pyobject, kwds);
412 }
413
414 Py_DECREF(args);
415 Py_DECREF(kwds);
416 Py_DECREF(pyscope);
417
418 if (pytmp) {
419 // implicit conversion succeeded!
420 ctxt->AddTemporary((PyObject*)pytmp);
421 para.fValue.fVoidp = pytmp->GetObject();
422 para.fTypeCode = 'V';
423 return true;
424 }
425
426 PyErr_Clear();
427 return false;
428}
429
430
431//- base converter implementation --------------------------------------------
433{
434 /* empty */
435}
436
437//----------------------------------------------------------------------------
439{
440// could happen if no derived class override
441 PyErr_SetString(PyExc_TypeError, "C++ type cannot be converted from memory");
442 return nullptr;
443}
444
445//----------------------------------------------------------------------------
447{
448// could happen if no derived class override
449 PyErr_SetString(PyExc_TypeError, "C++ type cannot be converted to memory");
450 return false;
451}
452
453
454//- helper macro's -----------------------------------------------------------
455#define CPPYY_IMPL_BASIC_CONVERTER(name, type, stype, ctype, F1, F2, tc) \
456bool CPyCppyy::name##Converter::SetArg( \
457 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \
458{ \
459/* convert <pyobject> to C++ 'type', set arg for call */ \
460 type val = (type)F2(pyobject); \
461 if (val == (type)-1 && PyErr_Occurred()) { \
462 static PyTypeObject* ctypes_type = nullptr; \
463 if (!ctypes_type) { \
464 PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0; \
465 PyErr_Fetch(&pytype, &pyvalue, &pytrace); \
466 ctypes_type = GetCTypesType(ct_##ctype); \
467 PyErr_Restore(pytype, pyvalue, pytrace); \
468 } \
469 if (Py_TYPE(pyobject) == ctypes_type) { \
470 PyErr_Clear(); \
471 val = *((type*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr); \
472 } else \
473 return false; \
474 } \
475 para.fValue.f##name = val; \
476 para.fTypeCode = tc; \
477 return true; \
478} \
479 \
480PyObject* CPyCppyy::name##Converter::FromMemory(void* address) \
481{ \
482 return F1((stype)*((type*)address)); \
483} \
484 \
485bool CPyCppyy::name##Converter::ToMemory(PyObject* value, void* address, \
486 PyObject* /* ctxt */) \
487{ \
488 type s = (type)F2(value); \
489 if (s == (type)-1 && PyErr_Occurred()) \
490 return false; \
491 *((type*)address) = (type)s; \
492 return true; \
493}
494
495//----------------------------------------------------------------------------
496static inline int ExtractChar(PyObject* pyobject, const char* tname, int low, int high)
497{
498 int lchar = -1;
499 if (CPyCppyy_PyText_Check(pyobject)) {
500 if (CPyCppyy_PyText_GET_SIZE(pyobject) == 1)
501 lchar = (int)CPyCppyy_PyText_AsChar(pyobject);
502 else
503 PyErr_Format(PyExc_ValueError, "%s expected, got string of size " PY_SSIZE_T_FORMAT,
504 tname, CPyCppyy_PyText_GET_SIZE(pyobject));
505 } else if (!PyFloat_Check(pyobject)) { // don't allow truncating conversion
506 lchar = (int)PyLong_AsLong(pyobject);
507 if (lchar == -1 && PyErr_Occurred())
508 ; // empty, as error already set
509 else if (!(low <= lchar && lchar <= high)) {
510 PyErr_Format(PyExc_ValueError,
511 "integer to character: value %d not in range [%d,%d]", lchar, low, high);
512 lchar = -1;
513 }
514 } else
515 PyErr_SetString(PyExc_TypeError, "char or small int type expected");
516
517 return lchar;
518}
519
520//----------------------------------------------------------------------------
521#define CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(name, ctype) \
522PyObject* CPyCppyy::name##RefConverter::FromMemory(void* ptr) \
523{ \
524/* convert a reference to int to Python through ctypes pointer object */ \
525 PyTypeObject* ctypes_type = GetCTypesType(ct_##ctype); \
526 if (!ctypes_type) { \
527 PyErr_SetString(PyExc_RuntimeError, "no ctypes available"); \
528 return nullptr; \
529 } \
530 PyObject* ref = ctypes_type->tp_new(ctypes_type, nullptr, nullptr); \
531 ((CPyCppyy_tagCDataObject*)ref)->b_ptr = (char*)ptr; \
532 ((CPyCppyy_tagCDataObject*)ref)->b_needsfree = 0; \
533 return ref; \
534}
535
536//----------------------------------------------------------------------------
537#define CPPYY_IMPL_BASIC_CONST_REFCONVERTER(name, type, ctype, F1) \
538bool CPyCppyy::Const##name##RefConverter::SetArg( \
539 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \
540{ \
541 type val = (type)F1(pyobject); \
542 if (val == (type)-1 && PyErr_Occurred()) \
543 return false; \
544 para.fValue.f##name = val; \
545 para.fRef = &para.fValue.f##name; \
546 para.fTypeCode = 'r'; \
547 return true; \
548} \
549CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(Const##name, ctype)
550
551//----------------------------------------------------------------------------
552#define CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(name, type, ctype, low, high)\
553bool CPyCppyy::Const##name##RefConverter::SetArg( \
554 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \
555{ \
556/* convert <pyobject> to C++ <<type>>, set arg for call, allow int -> char */\
557 type val = (type)ExtractChar(pyobject, #type, low, high); \
558 if (val == (type)-1 && PyErr_Occurred()) \
559 return false; \
560 para.fValue.fLong = val; \
561 para.fTypeCode = 'l'; \
562 return true; \
563} \
564CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(Const##name, ctype)
565
566
567//----------------------------------------------------------------------------
568#define CPPYY_IMPL_BASIC_CHAR_CONVERTER(name, type, low, high) \
569bool CPyCppyy::name##Converter::SetArg( \
570 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \
571{ \
572/* convert <pyobject> to C++ <<type>>, set arg for call, allow int -> char */\
573 long val = ExtractChar(pyobject, #type, low, high); \
574 if (val == -1 && PyErr_Occurred()) \
575 return false; \
576 para.fValue.fLong = val; \
577 para.fTypeCode = 'l'; \
578 return true; \
579} \
580 \
581PyObject* CPyCppyy::name##Converter::FromMemory(void* address) \
582{ \
583 return CPyCppyy_PyText_FromFormat("%c", *((type*)address)); \
584} \
585 \
586bool CPyCppyy::name##Converter::ToMemory(PyObject* value, void* address, \
587 PyObject* /* ctxt */) \
588{ \
589 Py_ssize_t len; \
590 const char* cstr = CPyCppyy_PyText_AsStringAndSize(value, &len); \
591 if (cstr) { \
592 if (len != 1) { \
593 PyErr_Format(PyExc_TypeError, #type" expected, got string of size %zd", len);\
594 return false; \
595 } \
596 *((type*)address) = (type)cstr[0]; \
597 } else { \
598 PyErr_Clear(); \
599 long l = PyLong_AsLong(value); \
600 if (l == -1 && PyErr_Occurred()) \
601 return false; \
602 if (!(low <= l && l <= high)) { \
603 PyErr_Format(PyExc_ValueError, \
604 "integer to character: value %ld not in range [%d,%d]", l, low, high);\
605 return false; \
606 } \
607 *((type*)address) = (type)l; \
608 } \
609 return true; \
610}
611
612
613//- converters for built-ins -------------------------------------------------
614CPPYY_IMPL_BASIC_CONVERTER(Long, long, long, c_long, PyLong_FromLong, CPyCppyy_PyLong_AsStrictLong, 'l')
615
616//----------------------------------------------------------------------------
617bool CPyCppyy::LongRefConverter::SetArg(
618 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
619{
620// convert <pyobject> to C++ long&, set arg for call
621#if PY_VERSION_HEX < 0x03000000
622 if (RefInt_CheckExact(pyobject)) {
623 para.fValue.fVoidp = (void*)&((PyIntObject*)pyobject)->ob_ival;
624 para.fTypeCode = 'V';
625 return true;
626 }
627#endif
628
629 if (Py_TYPE(pyobject) == GetCTypesType(ct_c_long)) {
630 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;
631 para.fTypeCode = 'V';
632 return true;
633 }
634
635 if (CArraySetArg(pyobject, para, 'l', sizeof(long))) {
636 para.fTypeCode = 'V';
637 return true;
638 }
639
640 PyErr_SetString(PyExc_TypeError, "use ctypes.c_long for pass-by-ref of longs");
641 return false;
642}
643
644//----------------------------------------------------------------------------
645CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(Char, char, c_char, CHAR_MIN, CHAR_MAX)
646CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(UChar, unsigned char, c_uchar, 0, UCHAR_MAX)
647
656CPPYY_IMPL_BASIC_CONST_REFCONVERTER(ULong, unsigned long, c_ulong, PyLongOrInt_AsULong)
657CPPYY_IMPL_BASIC_CONST_REFCONVERTER(LLong, Long64_t, c_longlong, PyLong_AsLongLong)
659
660//----------------------------------------------------------------------------
661bool CPyCppyy::IntRefConverter::SetArg(
662 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
663{
664// convert <pyobject> to C++ (pseudo)int&, set arg for call
665#if PY_VERSION_HEX < 0x03000000
666 if (RefInt_CheckExact(pyobject)) {
667 para.fValue.fVoidp = (void*)&((PyIntObject*)pyobject)->ob_ival;
668 para.fTypeCode = 'V';
669 return true;
670 }
671#endif
672
673#if PY_VERSION_HEX >= 0x02050000
674 if (Py_TYPE(pyobject) == GetCTypesType(ct_c_int)) {
675 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;
676 para.fTypeCode = 'V';
677 return true;
678 }
679#endif
680
681// alternate, pass pointer from buffer
682 Py_ssize_t buflen = Utility::GetBuffer(pyobject, 'i', sizeof(int), para.fValue.fVoidp);
683 if (para.fValue.fVoidp && buflen) {
684 para.fTypeCode = 'V';
685 return true;
686 };
687
688#if PY_VERSION_HEX < 0x02050000
689 PyErr_SetString(PyExc_TypeError, "use cppyy.Long for pass-by-ref of ints");
690#else
691 PyErr_SetString(PyExc_TypeError, "use ctypes.c_int for pass-by-ref of ints");
692#endif
693 return false;
694}
695
696//----------------------------------------------------------------------------
697#define CPPYY_IMPL_REFCONVERTER(name, ctype, type, code) \
698bool CPyCppyy::name##RefConverter::SetArg( \
699 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \
700{ \
701/* convert a reference to int to Python through ctypes pointer object */ \
702 if (Py_TYPE(pyobject) == GetCTypesType(ct_##ctype)) { \
703 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;\
704 para.fTypeCode = 'V'; \
705 return true; \
706 } \
707 bool res = CArraySetArg(pyobject, para, code, sizeof(type)); \
708 if (!res) { \
709 PyErr_SetString(PyExc_TypeError, "use ctypes."#ctype" for pass-by-ref of "#type);\
710 return false; \
711 } \
712 para.fTypeCode = 'V'; \
713 return res; \
714} \
715CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(name, ctype)
716
717CPPYY_IMPL_REFCONVERTER(Bool, c_bool, bool, '?');
718CPPYY_IMPL_REFCONVERTER(Char, c_char, char, 'b');
719CPPYY_IMPL_REFCONVERTER(WChar, c_wchar, wchar_t, 'u');
720CPPYY_IMPL_REFCONVERTER(Char16, c_uint16, char16_t, 'H');
721CPPYY_IMPL_REFCONVERTER(Char32, c_uint32, char32_t, 'I');
722CPPYY_IMPL_REFCONVERTER(SChar, c_byte, signed char, 'b');
723CPPYY_IMPL_REFCONVERTER(UChar, c_ubyte, unsigned char, 'B');
724CPPYY_IMPL_REFCONVERTER(Int8, c_int8, int8_t, 'b');
725CPPYY_IMPL_REFCONVERTER(UInt8, c_uint8, uint8_t, 'B');
726CPPYY_IMPL_REFCONVERTER(Short, c_short, short, 'h');
727CPPYY_IMPL_REFCONVERTER(UShort, c_ushort, unsigned short, 'H');
729CPPYY_IMPL_REFCONVERTER(UInt, c_uint, unsigned int, 'I');
731CPPYY_IMPL_REFCONVERTER(ULong, c_ulong, unsigned long, 'L');
732CPPYY_IMPL_REFCONVERTER(LLong, c_longlong, long long, 'q');
733CPPYY_IMPL_REFCONVERTER(ULLong, c_ulonglong, unsigned long long, 'Q');
734CPPYY_IMPL_REFCONVERTER(Float, c_float, float, 'f');
736CPPYY_IMPL_REFCONVERTER(LDouble, c_longdouble, LongDouble_t, 'D');
737
738
739//----------------------------------------------------------------------------
740// convert <pyobject> to C++ bool, allow int/long -> bool, set arg for call
742 Bool, bool, long, c_bool, PyInt_FromLong, CPyCppyy_PyLong_AsBool, 'l')
743
744//----------------------------------------------------------------------------
745CPPYY_IMPL_BASIC_CHAR_CONVERTER(Char, char, CHAR_MIN, CHAR_MAX)
746CPPYY_IMPL_BASIC_CHAR_CONVERTER(UChar, unsigned char, 0, UCHAR_MAX)
747
748PyObject* CPyCppyy::UCharAsIntConverter::FromMemory(void* address)
749{
750// special case to be used with arrays: return a Python int instead of str
751// (following the same convention as module array.array)
752 return PyInt_FromLong((long)*((unsigned char*)address));
753}
754
755//----------------------------------------------------------------------------
756bool CPyCppyy::WCharConverter::SetArg(
757 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
758{
759// convert <pyobject> to C++ <wchar_t>, set arg for call
760 if (!PyUnicode_Check(pyobject) || CPyCppyy_PyUnicode_GET_SIZE(pyobject) != 1) {
761 PyErr_SetString(PyExc_ValueError, "single wchar_t character expected");
762 return false;
763 }
764 wchar_t val;
765 Py_ssize_t res = CPyCppyy_PyUnicode_AsWideChar(pyobject, &val, 1);
766 if (res == -1)
767 return false;
768 para.fValue.fLong = (long)val;
769 para.fTypeCode = 'U';
770 return true;
771}
772
773PyObject* CPyCppyy::WCharConverter::FromMemory(void* address)
774{
775 return PyUnicode_FromWideChar((const wchar_t*)address, 1);
776}
777
778bool CPyCppyy::WCharConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
779{
780 if (!PyUnicode_Check(value) || CPyCppyy_PyUnicode_GET_SIZE(value) != 1) {
781 PyErr_SetString(PyExc_ValueError, "single wchar_t character expected");
782 return false;
783 }
784 wchar_t val;
785 Py_ssize_t res = CPyCppyy_PyUnicode_AsWideChar(value, &val, 1);
786 if (res == -1)
787 return false;
788 *((wchar_t*)address) = val;
789 return true;
790}
791
792//----------------------------------------------------------------------------
793bool CPyCppyy::Char16Converter::SetArg(
794 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
795{
796// convert <pyobject> to C++ <char16_t>, set arg for call
797 if (!PyUnicode_Check(pyobject) || CPyCppyy_PyUnicode_GET_SIZE(pyobject) != 1) {
798 PyErr_SetString(PyExc_ValueError, "single char16_t character expected");
799 return false;
800 }
801
802 PyObject* bstr = PyUnicode_AsUTF16String(pyobject);
803 if (!bstr) return false;
804
805 char16_t val = *(char16_t*)(PyBytes_AS_STRING(bstr) + sizeof(char16_t) /*BOM*/);
806 Py_DECREF(bstr);
807 para.fValue.fLong = (long)val;
808 para.fTypeCode = 'U';
809 return true;
810}
811
812PyObject* CPyCppyy::Char16Converter::FromMemory(void* address)
813{
814 return PyUnicode_DecodeUTF16((const char*)address, sizeof(char16_t), nullptr, nullptr);
815}
816
817bool CPyCppyy::Char16Converter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
818{
819 if (!PyUnicode_Check(value) || CPyCppyy_PyUnicode_GET_SIZE(value) != 1) {
820 PyErr_SetString(PyExc_ValueError, "single char16_t character expected");
821 return false;
822 }
823
824 PyObject* bstr = PyUnicode_AsUTF16String(value);
825 if (!bstr) return false;
826
827 *((char16_t*)address) = *(char16_t*)(PyBytes_AS_STRING(bstr) + sizeof(char16_t) /*BOM*/);
828 Py_DECREF(bstr);
829 return true;
830}
831
832//----------------------------------------------------------------------------
833bool CPyCppyy::Char32Converter::SetArg(
834 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
835{
836// convert <pyobject> to C++ <char32_t>, set arg for call
837 if (!PyUnicode_Check(pyobject) || 2 < CPyCppyy_PyUnicode_GET_SIZE(pyobject)) {
838 PyErr_SetString(PyExc_ValueError, "single char32_t character expected");
839 return false;
840 }
841
842 PyObject* bstr = PyUnicode_AsUTF32String(pyobject);
843 if (!bstr) return false;
844
845 char32_t val = *(char32_t*)(PyBytes_AS_STRING(bstr) + sizeof(char32_t) /*BOM*/);
846 Py_DECREF(bstr);
847 para.fValue.fLong = (long)val;
848 para.fTypeCode = 'U';
849 return true;
850}
851
852PyObject* CPyCppyy::Char32Converter::FromMemory(void* address)
853{
854 return PyUnicode_DecodeUTF32((const char*)address, sizeof(char32_t), nullptr, nullptr);
855}
856
857bool CPyCppyy::Char32Converter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
858{
859 if (!PyUnicode_Check(value) || 2 < CPyCppyy_PyUnicode_GET_SIZE(value)) {
860 PyErr_SetString(PyExc_ValueError, "single char32_t character expected");
861 return false;
862 }
863
864 PyObject* bstr = PyUnicode_AsUTF32String(value);
865 if (!bstr) return false;
866
867 *((char32_t*)address) = *(char32_t*)(PyBytes_AS_STRING(bstr) + sizeof(char32_t) /*BOM*/);
868 Py_DECREF(bstr);
869 return true;
870}
871
872//----------------------------------------------------------------------------
874 Int8, int8_t, long, c_int8, PyInt_FromLong, CPyCppyy_PyLong_AsInt8, 'l')
878 Short, short, long, c_short, PyInt_FromLong, CPyCppyy_PyLong_AsShort, 'l')
880 UShort, unsigned short, long, c_ushort, PyInt_FromLong, CPyCppyy_PyLong_AsUShort, 'l')
882 Int, int, long, c_uint, PyInt_FromLong, CPyCppyy_PyLong_AsStrictInt, 'l')
883
884//----------------------------------------------------------------------------
885bool CPyCppyy::ULongConverter::SetArg(
886 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
887{
888// convert <pyobject> to C++ unsigned long, set arg for call
889 para.fValue.fULong = PyLongOrInt_AsULong(pyobject);
890 if (para.fValue.fULong == (unsigned long)-1 && PyErr_Occurred())
891 return false;
892 para.fTypeCode = 'L';
893 return true;
894}
895
896PyObject* CPyCppyy::ULongConverter::FromMemory(void* address)
897{
898// construct python object from C++ unsigned long read at <address>
899 return PyLong_FromUnsignedLong(*((unsigned long*)address));
900}
901
902bool CPyCppyy::ULongConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
903{
904// convert <value> to C++ unsigned long, write it at <address>
905 unsigned long u = PyLongOrInt_AsULong(value);
906 if (u == (unsigned long)-1 && PyErr_Occurred())
907 return false;
908 *((unsigned long*)address) = u;
909 return true;
910}
911
912//----------------------------------------------------------------------------
913PyObject* CPyCppyy::UIntConverter::FromMemory(void* address)
914{
915// construct python object from C++ unsigned int read at <address>
916 return PyLong_FromUnsignedLong(*((UInt_t*)address));
917}
918
919bool CPyCppyy::UIntConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
920{
921// convert <value> to C++ unsigned int, write it at <address>
922 ULong_t u = PyLongOrInt_AsULong(value);
923 if (u == (unsigned long)-1 && PyErr_Occurred())
924 return false;
925
926 if (u > (ULong_t)UINT_MAX) {
927 PyErr_SetString(PyExc_OverflowError, "value too large for unsigned int");
928 return false;
929 }
930
931 *((UInt_t*)address) = (UInt_t)u;
932 return true;
933}
934
935//- floating point converters ------------------------------------------------
937 Float, float, double, c_float, PyFloat_FromDouble, PyFloat_AsDouble, 'f')
939 Double, double, double, c_double, PyFloat_FromDouble, PyFloat_AsDouble, 'd')
940
943
944CPyCppyy::ComplexDConverter::ComplexDConverter(bool keepControl) :
945 InstanceConverter(Cppyy::GetScope("std::complex<double>"), keepControl) {}
946
947// special case for std::complex<double>, maps it to/from Python's complex
948bool CPyCppyy::ComplexDConverter::SetArg(
949 PyObject* pyobject, Parameter& para, CallContext* ctxt)
950{
951 const Py_complex& pc = PyComplex_AsCComplex(pyobject);
952 if (pc.real != -1.0 || !PyErr_Occurred()) {
953 fBuffer.real(pc.real);
954 fBuffer.imag(pc.imag);
955 para.fValue.fVoidp = &fBuffer;
956 para.fTypeCode = 'V';
957 return true;
958 }
959
960 return this->InstanceConverter::SetArg(pyobject, para, ctxt);
961} \
962 \
963PyObject* CPyCppyy::ComplexDConverter::FromMemory(void* address)
964{
965 std::complex<double>* dc = (std::complex<double>*)address;
966 return PyComplex_FromDoubles(dc->real(), dc->imag());
967}
968
969bool CPyCppyy::ComplexDConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt)
970{
971 const Py_complex& pc = PyComplex_AsCComplex(value);
972 if (pc.real != -1.0 || !PyErr_Occurred()) {
973 std::complex<double>* dc = (std::complex<double>*)address;
974 dc->real(pc.real);
975 dc->imag(pc.imag);
976 return true;
977 }
978 return this->InstanceConverter::ToMemory(value, address, ctxt);
979}
980
981//----------------------------------------------------------------------------
982bool CPyCppyy::DoubleRefConverter::SetArg(
983 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
984{
985// convert <pyobject> to C++ double&, set arg for call
986 if (RefFloat_CheckExact(pyobject)) {
987 para.fValue.fVoidp = (void*)&((PyFloatObject*)pyobject)->ob_fval;
988 para.fTypeCode = 'V';
989 return true;
990 }
991
992// alternate, pass pointer from buffer
993 Py_ssize_t buflen = Utility::GetBuffer(pyobject, 'd', sizeof(double), para.fValue.fVoidp);
994 if (para.fValue.fVoidp && buflen) {
995 para.fTypeCode = 'V';
996 return true;
997 }
998
999#if PY_VERSION_HEX < 0x02050000
1000 PyErr_SetString(PyExc_TypeError, "use cppyy.Double for pass-by-ref of doubles");
1001#else
1002 PyErr_SetString(PyExc_TypeError, "use ctypes.c_double for pass-by-ref of doubles");
1003#endif
1004 return false;
1005}
1006
1007//----------------------------------------------------------------------------
1011
1012//----------------------------------------------------------------------------
1013bool CPyCppyy::VoidConverter::SetArg(PyObject*, Parameter&, CallContext*)
1014{
1015// can't happen (unless a type is mapped wrongly), but implemented for completeness
1016 PyErr_SetString(PyExc_SystemError, "void/unknown arguments can\'t be set");
1017 return false;
1018}
1019
1020//----------------------------------------------------------------------------
1021bool CPyCppyy::LLongConverter::SetArg(
1022 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1023{
1024// convert <pyobject> to C++ long long, set arg for call
1025 if (PyFloat_Check(pyobject)) {
1026 // special case: float implements nb_int, but allowing rounding conversions
1027 // interferes with overloading
1028 PyErr_SetString(PyExc_ValueError, "cannot convert float to long long");
1029 return false;
1030 }
1031
1032 para.fValue.fLLong = PyLong_AsLongLong(pyobject);
1033 if (PyErr_Occurred())
1034 return false;
1035 para.fTypeCode = 'q';
1036 return true;
1037}
1038
1039PyObject* CPyCppyy::LLongConverter::FromMemory(void* address)
1040{
1041// construct python object from C++ long long read at <address>
1042 return PyLong_FromLongLong(*(Long64_t*)address);
1043}
1044
1045bool CPyCppyy::LLongConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1046{
1047// convert <value> to C++ long long, write it at <address>
1048 Long64_t ll = PyLong_AsLongLong(value);
1049 if (ll == -1 && PyErr_Occurred())
1050 return false;
1051 *((Long64_t*)address) = ll;
1052 return true;
1053}
1054
1055//----------------------------------------------------------------------------
1056bool CPyCppyy::ULLongConverter::SetArg(
1057 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1058{
1059// convert <pyobject> to C++ unsigned long long, set arg for call
1060 para.fValue.fULLong = PyLongOrInt_AsULong64(pyobject);
1061 if (PyErr_Occurred())
1062 return false;
1063 para.fTypeCode = 'Q';
1064 return true;
1065}
1066
1067PyObject* CPyCppyy::ULLongConverter::FromMemory(void* address)
1068{
1069// construct python object from C++ unsigned long long read at <address>
1070 return PyLong_FromUnsignedLongLong(*(ULong64_t*)address);
1071}
1072
1073bool CPyCppyy::ULLongConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1074{
1075// convert <value> to C++ unsigned long long, write it at <address>
1076 Long64_t ull = PyLongOrInt_AsULong64(value);
1077 if (PyErr_Occurred())
1078 return false;
1079 *((ULong64_t*)address) = ull;
1080 return true;
1081}
1082
1083//----------------------------------------------------------------------------
1084bool CPyCppyy::CStringConverter::SetArg(
1085 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1086{
1087// construct a new string and copy it in new memory
1088 Py_ssize_t len;
1089 const char* cstr = CPyCppyy_PyText_AsStringAndSize(pyobject, &len);
1090 if (!cstr) {
1091 // special case: allow ctypes c_char_p
1092 PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0;
1093 PyErr_Fetch(&pytype, &pyvalue, &pytrace);
1094 if (Py_TYPE(pyobject) == GetCTypesType(ct_c_char_p)) {
1095 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;
1096 para.fTypeCode = 'V';
1097 Py_XDECREF(pytype); Py_XDECREF(pyvalue); Py_XDECREF(pytrace);
1098 return true;
1099 }
1100 PyErr_Restore(pytype, pyvalue, pytrace);
1101 return false;
1102 }
1103
1104 fBuffer = std::string(cstr, len);
1105
1106// verify (too long string will cause truncation, no crash)
1107 if (fMaxSize != -1 && fMaxSize < (long)fBuffer.size())
1108 PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for char array (truncated)");
1109 else if (fMaxSize != -1)
1110 fBuffer.resize(fMaxSize, '\0'); // padd remainder of buffer as needed
1111
1112// set the value and declare success
1113 para.fValue.fVoidp = (void*)fBuffer.c_str();
1114 para.fTypeCode = 'p';
1115 return true;
1116}
1117
1118PyObject* CPyCppyy::CStringConverter::FromMemory(void* address)
1119{
1120// construct python object from C++ const char* read at <address>
1121 if (address && *(char**)address) {
1122 if (fMaxSize != -1) { // need to prevent reading beyond boundary
1123 std::string buf(*(char**)address, fMaxSize); // cut on fMaxSize
1124 return CPyCppyy_PyText_FromString(buf.c_str()); // cut on \0
1125 }
1126
1127 return CPyCppyy_PyText_FromString(*(char**)address);
1128 }
1129
1130// empty string in case there's no address
1131 Py_INCREF(PyStrings::gEmptyString);
1133}
1134
1135bool CPyCppyy::CStringConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1136{
1137// convert <value> to C++ const char*, write it at <address>
1138 Py_ssize_t len;
1139 const char* cstr = CPyCppyy_PyText_AsStringAndSize(value, &len);
1140 if (!cstr) return false;
1141
1142// verify (too long string will cause truncation, no crash)
1143 if (fMaxSize != -1 && fMaxSize < (long)len)
1144 PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for char array (truncated)");
1145
1146 if (fMaxSize != -1)
1147 strncpy(*(char**)address, cstr, fMaxSize); // padds remainder
1148 else
1149 // coverity[secure_coding] - can't help it, it's intentional.
1150 strcpy(*(char**)address, cstr);
1151
1152 return true;
1153}
1154
1155//----------------------------------------------------------------------------
1156bool CPyCppyy::WCStringConverter::SetArg(
1157 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1158{
1159// construct a new string and copy it in new memory
1160 Py_ssize_t len = PyUnicode_GetSize(pyobject);
1161 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1162 return false;
1163
1164 fBuffer = (wchar_t*)realloc(fBuffer, sizeof(wchar_t)*(len+1));
1165 Py_ssize_t res = CPyCppyy_PyUnicode_AsWideChar(pyobject, fBuffer, len);
1166 if (res == -1)
1167 return false; // could free the buffer here
1168
1169// set the value and declare success
1170 fBuffer[len] = L'\0';
1171 para.fValue.fVoidp = (void*)fBuffer;
1172 para.fTypeCode = 'p';
1173 return true;
1174}
1175
1176PyObject* CPyCppyy::WCStringConverter::FromMemory(void* address)
1177{
1178// construct python object from C++ wchar_t* read at <address>
1179 if (address && *(wchar_t**)address) {
1180 if (fMaxSize != -1) // need to prevent reading beyond boundary
1181 return PyUnicode_FromWideChar(*(wchar_t**)address, fMaxSize);
1182 // with unknown size
1183 return PyUnicode_FromWideChar(*(wchar_t**)address, wcslen(*(wchar_t**)address));
1184 }
1185
1186// empty string in case there's no valid address
1187 wchar_t w = L'\0';
1188 return PyUnicode_FromWideChar(&w, 0);
1189}
1190
1191bool CPyCppyy::WCStringConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1192{
1193// convert <value> to C++ wchar_t*, write it at <address>
1194 Py_ssize_t len = PyUnicode_GetSize(value);
1195 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1196 return false;
1197
1198// verify (too long string will cause truncation, no crash)
1199 if (fMaxSize != -1 && fMaxSize < len)
1200 PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for wchar_t array (truncated)");
1201
1202 Py_ssize_t res = -1;
1203 if (fMaxSize != -1)
1204 res = CPyCppyy_PyUnicode_AsWideChar(value, *(wchar_t**)address, fMaxSize);
1205 else
1206 // coverity[secure_coding] - can't help it, it's intentional.
1207 res = CPyCppyy_PyUnicode_AsWideChar(value, *(wchar_t**)address, len);
1208
1209 if (res == -1) return false;
1210 return true;
1211}
1212
1213//----------------------------------------------------------------------------
1214bool CPyCppyy::CString16Converter::SetArg(
1215 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1216{
1217// construct a new string and copy it in new memory
1218 Py_ssize_t len = PyUnicode_GetSize(pyobject);
1219 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1220 return false;
1221
1222 PyObject* bstr = PyUnicode_AsUTF16String(pyobject);
1223 if (!bstr) return false;
1224
1225 fBuffer = (char16_t*)realloc(fBuffer, sizeof(char16_t)*(len+1));
1226 memcpy(fBuffer, PyBytes_AS_STRING(bstr) + sizeof(char16_t) /*BOM*/, len*sizeof(char16_t));
1227 Py_DECREF(bstr);
1228
1229// set the value and declare success
1230 fBuffer[len] = u'\0';
1231 para.fValue.fVoidp = (void*)fBuffer;
1232 para.fTypeCode = 'p';
1233 return true;
1234}
1235
1236PyObject* CPyCppyy::CString16Converter::FromMemory(void* address)
1237{
1238// construct python object from C++ char16_t* read at <address>
1239 if (address && *(char16_t**)address) {
1240 if (fMaxSize != -1) // need to prevent reading beyond boundary
1241 return PyUnicode_DecodeUTF16(*(const char**)address, fMaxSize, nullptr, nullptr);
1242 // with unknown size
1243 return PyUnicode_DecodeUTF16(*(const char**)address,
1244 std::char_traits<char16_t>::length(*(char16_t**)address)*sizeof(char16_t), nullptr, nullptr);
1245 }
1246
1247// empty string in case there's no valid address
1248 char16_t w = u'\0';
1249 return PyUnicode_DecodeUTF16((const char*)&w, 0, nullptr, nullptr);
1250}
1251
1252bool CPyCppyy::CString16Converter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1253{
1254// convert <value> to C++ char16_t*, write it at <address>
1255 Py_ssize_t len = PyUnicode_GetSize(value);
1256 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1257 return false;
1258
1259// verify (too long string will cause truncation, no crash)
1260 if (fMaxSize != -1 && fMaxSize < len) {
1261 PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for char16_t array (truncated)");
1262 len = fMaxSize-1;
1263 }
1264
1265 PyObject* bstr = PyUnicode_AsUTF16String(value);
1266 if (!bstr) return false;
1267
1268 memcpy(*((void**)address), PyBytes_AS_STRING(bstr) + sizeof(char16_t) /*BOM*/, len*sizeof(char16_t));
1269 Py_DECREF(bstr);
1270 *((char16_t**)address)[len] = u'\0';
1271 return true;
1272}
1273
1274//----------------------------------------------------------------------------
1275bool CPyCppyy::CString32Converter::SetArg(
1276 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1277{
1278// construct a new string and copy it in new memory
1279 Py_ssize_t len = PyUnicode_GetSize(pyobject);
1280 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1281 return false;
1282
1283 PyObject* bstr = PyUnicode_AsUTF32String(pyobject);
1284 if (!bstr) return false;
1285
1286 fBuffer = (char32_t*)realloc(fBuffer, sizeof(char32_t)*(len+1));
1287 memcpy(fBuffer, PyBytes_AS_STRING(bstr) + sizeof(char32_t) /*BOM*/, len*sizeof(char32_t));
1288 Py_DECREF(bstr);
1289
1290// set the value and declare success
1291 fBuffer[len] = U'\0';
1292 para.fValue.fVoidp = (void*)fBuffer;
1293 para.fTypeCode = 'p';
1294 return true;
1295}
1296
1297PyObject* CPyCppyy::CString32Converter::FromMemory(void* address)
1298{
1299// construct python object from C++ char32_t* read at <address>
1300 if (address && *(char32_t**)address) {
1301 if (fMaxSize != -1) // need to prevent reading beyond boundary
1302 return PyUnicode_DecodeUTF32(*(const char**)address, fMaxSize, nullptr, nullptr);
1303 // with unknown size
1304 return PyUnicode_DecodeUTF32(*(const char**)address,
1305 std::char_traits<char32_t>::length(*(char32_t**)address)*sizeof(char32_t), nullptr, nullptr);
1306 }
1307
1308// empty string in case there's no valid address
1309 char32_t w = U'\0';
1310 return PyUnicode_DecodeUTF32((const char*)&w, 0, nullptr, nullptr);
1311}
1312
1313bool CPyCppyy::CString32Converter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1314{
1315// convert <value> to C++ char32_t*, write it at <address>
1316 Py_ssize_t len = PyUnicode_GetSize(value);
1317 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1318 return false;
1319
1320// verify (too long string will cause truncation, no crash)
1321 if (fMaxSize != -1 && fMaxSize < len) {
1322 PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for char32_t array (truncated)");
1323 len = fMaxSize-1;
1324 }
1325
1326 PyObject* bstr = PyUnicode_AsUTF32String(value);
1327 if (!bstr) return false;
1328
1329 memcpy(*((void**)address), PyBytes_AS_STRING(bstr) + sizeof(char32_t) /*BOM*/, len*sizeof(char32_t));
1330 Py_DECREF(bstr);
1331 *((char32_t**)address)[len] = U'\0';
1332 return true;
1333}
1334
1335
1336//----------------------------------------------------------------------------
1337bool CPyCppyy::NonConstCStringConverter::SetArg(
1338 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1339{
1340// attempt base class first (i.e. passing a string), but if that fails, try a buffer
1341 if (this->CStringConverter::SetArg(pyobject, para, ctxt))
1342 return true;
1343
1344// apparently failed, try char buffer
1345 PyErr_Clear();
1346 return CArraySetArg(pyobject, para, 'c', sizeof(char));
1347}
1348
1349//----------------------------------------------------------------------------
1350PyObject* CPyCppyy::NonConstCStringConverter::FromMemory(void* address)
1351{
1352// assume this is a buffer access if the size is known; otherwise assume string
1353 if (fMaxSize != -1)
1354 return CPyCppyy_PyText_FromStringAndSize(*(char**)address, fMaxSize);
1355 return this->CStringConverter::FromMemory(address);
1356}
1357
1358//----------------------------------------------------------------------------
1360{
1361// (1): C++11 style "null pointer"
1362 if (pyobject == gNullPtrObject) {
1363 address = nullptr;
1364 return true;
1365 }
1366
1367// (2): allow integer zero to act as a null pointer (C NULL), no deriveds
1368 if (PyInt_CheckExact(pyobject) || PyLong_CheckExact(pyobject)) {
1369 intptr_t val = (intptr_t)PyLong_AsLongLong(pyobject);
1370 if (val == 0l) {
1371 address = (void*)val;
1372 return true;
1373 }
1374
1375 return false;
1376 }
1377
1378// (3): opaque PyCapsule (CObject in older pythons) from somewhere
1379 if (CPyCppyy_PyCapsule_CheckExact(pyobject)) {
1380 address = (void*)CPyCppyy_PyCapsule_GetPointer(pyobject, nullptr);
1381 return true;
1382 }
1383
1384 return false;
1385}
1386
1387//----------------------------------------------------------------------------
1389 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1390{
1391// just convert pointer if it is a C++ object
1392 CPPInstance* pyobj = GetCppInstance(pyobject);
1393 if (pyobj) {
1394 // depending on memory policy, some objects are no longer owned when passed to C++
1395 if (!fKeepControl && !UseStrictOwnership(ctxt))
1396 pyobj->CppOwns();
1397
1398 // set pointer (may be null) and declare success
1399 para.fValue.fVoidp = pyobj->GetObject();
1400 para.fTypeCode = 'p';
1401 return true;
1402 }
1403
1404// handle special cases
1405 if (GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) {
1406 para.fTypeCode = 'p';
1407 return true;
1408 }
1409
1410// allow ctypes voidp (which if got as a buffer will return void**, not void*); use
1411// isintance instead of an exact check, b/c c_void_p is the type mapper for typedefs
1412// of void* (typically opaque handles)
1413 if (PyObject_IsInstance(pyobject, (PyObject*)GetCTypesType(ct_c_void_p))) {
1414 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;
1415 para.fTypeCode = 'V';
1416 return true;
1417 }
1418
1419// allow any other ctypes pointer type
1420 if (IsCTypesArrayOrPointer(pyobject)) {
1421 void** payload = (void**)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;
1422 if (payload) {
1423 para.fValue.fVoidp = *payload;
1424 para.fTypeCode = 'p';
1425 return true;
1426 }
1427 }
1428
1429// final try: attempt to get buffer
1430 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', 1, para.fValue.fVoidp, false);
1431
1432// ok if buffer exists (can't perform any useful size checks)
1433 if (para.fValue.fVoidp && buflen != 0) {
1434 para.fTypeCode = 'p';
1435 return true;
1436 }
1437
1438// give up
1439 return false;
1440}
1441
1442//----------------------------------------------------------------------------
1444{
1445// nothing sensible can be done, just return <address> as pylong
1446 if (!address || *(ptrdiff_t*)address == 0) {
1447 Py_INCREF(gNullPtrObject);
1448 return gNullPtrObject;
1449 }
1450 return CreatePointerView(*(ptrdiff_t**)address);
1451}
1452
1453//----------------------------------------------------------------------------
1454bool CPyCppyy::VoidArrayConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1455{
1456// just convert pointer if it is a C++ object
1457 CPPInstance* pyobj = GetCppInstance(value);
1458 if (pyobj) {
1459 // depending on memory policy, some objects are no longer owned when passed to C++
1461 pyobj->CppOwns();
1462
1463 // set pointer (may be null) and declare success
1464 *(void**)address = pyobj->GetObject();
1465 return true;
1466 }
1467
1468// handle special cases
1469 void* ptr = nullptr;
1470 if (GetAddressSpecialCase(value, ptr)) {
1471 *(void**)address = ptr;
1472 return true;
1473 }
1474
1475// final try: attempt to get buffer
1476 void* buf = nullptr;
1477 Py_ssize_t buflen = Utility::GetBuffer(value, '*', 1, buf, false);
1478 if (!buf || buflen == 0)
1479 return false;
1480
1481 *(void**)address = buf;
1482 return true;
1483}
1484
1485
1486//----------------------------------------------------------------------------
1487static inline void init_shape(Py_ssize_t defdim, dims_t dims, Py_ssize_t*& shape)
1488{
1489 int nalloc = (dims && 0 < dims[0]) ? (int)dims[0]+1: defdim+1;
1490 shape = new Py_ssize_t[nalloc];
1491 if (dims) {
1492 for (int i = 0; i < nalloc; ++i)
1493 shape[i] = (Py_ssize_t)dims[i];
1494 } else {
1495 shape[0] = defdim;
1496 for (int i = 1; i < nalloc; ++i) shape[i] = UNKNOWN_SIZE;
1497 }
1498}
1499
1500//----------------------------------------------------------------------------
1501#define CPPYY_IMPL_ARRAY_CONVERTER(name, ctype, type, code) \
1502CPyCppyy::name##ArrayConverter::name##ArrayConverter(dims_t dims, bool init) {\
1503 if (init) { \
1504 init_shape(1, dims, fShape); \
1505 fIsFixed = fShape[1] != UNKNOWN_SIZE; \
1506 } else fIsFixed = false; \
1507} \
1508 \
1509bool CPyCppyy::name##ArrayConverter::SetArg( \
1510 PyObject* pyobject, Parameter& para, CallContext* ctxt) \
1511{ \
1512 /* filter ctypes first b/c their buffer conversion will be wrong */ \
1513 bool res = false; \
1514 PyTypeObject* ctypes_type = GetCTypesType(ct_##ctype); \
1515 if (Py_TYPE(pyobject) == ctypes_type) { \
1516 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;\
1517 para.fTypeCode = 'p'; \
1518 res = true; \
1519 } else if (Py_TYPE(pyobject) == GetCTypesPtrType(ct_##ctype)) { \
1520 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;\
1521 para.fTypeCode = 'V'; \
1522 res = true; \
1523 } else if (IsPyCArgObject(pyobject)) { \
1524 CPyCppyy_tagPyCArgObject* carg = (CPyCppyy_tagPyCArgObject*)pyobject;\
1525 if (carg->obj && Py_TYPE(carg->obj) == ctypes_type) { \
1526 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)carg->obj)->b_ptr;\
1527 para.fTypeCode = 'p'; \
1528 res = true; \
1529 } \
1530 } \
1531 if (!res) res = CArraySetArg(pyobject, para, code, sizeof(type)); \
1532 if (res) SetLifeLine(ctxt->fPyContext, pyobject, (intptr_t)this); \
1533 return res; \
1534} \
1535 \
1536PyObject* CPyCppyy::name##ArrayConverter::FromMemory(void* address) \
1537{ \
1538 if (!fIsFixed) \
1539 return CreateLowLevelView((type**)address, fShape); \
1540 return CreateLowLevelView(*(type**)address, fShape); \
1541} \
1542 \
1543bool CPyCppyy::name##ArrayConverter::ToMemory( \
1544 PyObject* value, void* address, PyObject* ctxt) \
1545{ \
1546 if (fShape[0] != 1) { \
1547 PyErr_SetString(PyExc_ValueError, "only 1-dim arrays supported"); \
1548 return false; \
1549 } \
1550 void* buf = nullptr; \
1551 Py_ssize_t buflen = Utility::GetBuffer(value, code, sizeof(type), buf); \
1552 if (buflen == 0) \
1553 return false; \
1554 if (fIsFixed) { \
1555 if (fShape[1] < buflen) { \
1556 PyErr_SetString(PyExc_ValueError, "buffer too large for value"); \
1557 return false; \
1558 } \
1559 memcpy(*(type**)address, buf, (0 < buflen ? buflen : 1)*sizeof(type));\
1560 } else { \
1561 *(type**)address = (type*)buf; \
1562 fShape[1] = buflen; \
1563 } \
1564 SetLifeLine(ctxt, value, (intptr_t)address); \
1565 return true; \
1566} \
1567 \
1568bool CPyCppyy::name##ArrayPtrConverter::SetArg( \
1569 PyObject* pyobject, Parameter& para, CallContext* ctxt ) \
1570{ \
1571 if (Py_TYPE(pyobject) == GetCTypesPtrType(ct_##ctype)) { \
1572 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;\
1573 para.fTypeCode = 'p'; \
1574 return true; \
1575 } else if (Py_TYPE(pyobject) == GetCTypesType(ct_c_void_p)) { \
1576 /* special case: pass address of c_void_p buffer to return the address */\
1577 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;\
1578 para.fTypeCode = 'p'; \
1579 return true; \
1580 } \
1581 bool res = name##ArrayConverter::SetArg(pyobject, para, ctxt); \
1582 if (res && para.fTypeCode == 'p') { \
1583 para.fRef = para.fValue.fVoidp; \
1584 para.fValue.fVoidp = &para.fRef; \
1585 return true; \
1586 } \
1587 return false; \
1588}
1589
1590
1591//----------------------------------------------------------------------------
1592CPPYY_IMPL_ARRAY_CONVERTER(Bool, c_bool, bool, '?')
1593CPPYY_IMPL_ARRAY_CONVERTER(SChar, c_char, signed char, 'b')
1594CPPYY_IMPL_ARRAY_CONVERTER(UChar, c_ubyte, unsigned char, 'B')
1595#if __cplusplus > 201402L
1596CPPYY_IMPL_ARRAY_CONVERTER(Byte, c_ubyte, std::byte, 'B')
1597#endif
1598CPPYY_IMPL_ARRAY_CONVERTER(Short, c_short, short, 'h')
1599CPPYY_IMPL_ARRAY_CONVERTER(UShort, c_ushort, unsigned short, 'H')
1600CPPYY_IMPL_ARRAY_CONVERTER(Int, c_int, int, 'i')
1601CPPYY_IMPL_ARRAY_CONVERTER(UInt, c_uint, unsigned int, 'I')
1602CPPYY_IMPL_ARRAY_CONVERTER(Long, c_long, long, 'l')
1603CPPYY_IMPL_ARRAY_CONVERTER(ULong, c_ulong, unsigned long, 'L')
1604CPPYY_IMPL_ARRAY_CONVERTER(LLong, c_longlong, long long, 'q')
1605CPPYY_IMPL_ARRAY_CONVERTER(ULLong, c_ulonglong, unsigned long long, 'Q')
1606CPPYY_IMPL_ARRAY_CONVERTER(Float, c_float, float, 'f')
1607CPPYY_IMPL_ARRAY_CONVERTER(Double, c_double, double, 'd')
1608CPPYY_IMPL_ARRAY_CONVERTER(LDouble, c_longdouble, long double, 'D')
1609CPPYY_IMPL_ARRAY_CONVERTER(ComplexD, c_complex, std::complex<double>, 'Z')
1610
1611
1612//----------------------------------------------------------------------------
1613PyObject* CPyCppyy::CStringArrayConverter::FromMemory(void* address)
1614{
1615 if (fShape[1] == UNKNOWN_SIZE)
1616 return CreateLowLevelView((const char**)address, fShape);
1617 return CreateLowLevelView(*(const char***)address, fShape);
1618}
1619
1620
1621//- converters for special cases ---------------------------------------------
1622bool CPyCppyy::NullptrConverter::SetArg(PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1623{
1624// Only allow C++11 style nullptr to pass
1625 if (pyobject == gNullPtrObject) {
1626 para.fValue.fVoidp = nullptr;
1627 para.fTypeCode = 'p';
1628 return true;
1629 }
1630 return false;
1631}
1632
1633
1634//----------------------------------------------------------------------------
1635#define CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(name, type, F1, F2) \
1636CPyCppyy::name##Converter::name##Converter(bool keepControl) : \
1637 InstanceConverter(Cppyy::GetScope(#type), keepControl) {} \
1638 \
1639bool CPyCppyy::name##Converter::SetArg( \
1640 PyObject* pyobject, Parameter& para, CallContext* ctxt) \
1641{ \
1642 Py_ssize_t len; \
1643 const char* cstr = CPyCppyy_PyText_AsStringAndSize(pyobject, &len); \
1644 if (cstr) { \
1645 fBuffer = type(cstr, len); \
1646 para.fValue.fVoidp = &fBuffer; \
1647 para.fTypeCode = 'V'; \
1648 return true; \
1649 } \
1650 \
1651 PyErr_Clear(); \
1652 if (!(PyInt_Check(pyobject) || PyLong_Check(pyobject))) { \
1653 bool result = InstanceConverter::SetArg(pyobject, para, ctxt); \
1654 para.fTypeCode = 'V'; \
1655 return result; \
1656 } \
1657 return false; \
1658} \
1659 \
1660PyObject* CPyCppyy::name##Converter::FromMemory(void* address) \
1661{ \
1662 if (address) \
1663 return CPyCppyy_PyText_FromStringAndSize(((type*)address)->F1(), ((type*)address)->F2()); \
1664 Py_INCREF(PyStrings::gEmptyString); \
1665 return PyStrings::gEmptyString; \
1666} \
1667 \
1668bool CPyCppyy::name##Converter::ToMemory(PyObject* value, void* address, \
1669 PyObject* ctxt) \
1670{ \
1671 if (CPyCppyy_PyText_Check(value)) { \
1672 *((type*)address) = CPyCppyy_PyText_AsString(value); \
1673 return true; \
1674 } \
1675 \
1676 return InstanceConverter::ToMemory(value, address, ctxt); \
1677}
1678
1680CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(STLString, std::string, c_str, size)
1681CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(STLStringViewBase, std::string_view, data, size)
1682bool CPyCppyy::STLStringViewConverter::SetArg(
1683 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1684{
1685 if (this->STLStringViewBaseConverter::SetArg(pyobject, para, ctxt))
1686 return true;
1687
1688 if (!CPPInstance_Check(pyobject))
1689 return false;
1690
1691 static Cppyy::TCppScope_t sStringID = Cppyy::GetScope("std::string");
1692 CPPInstance* pyobj = (CPPInstance*)pyobject;
1693 if (pyobj->ObjectIsA() == sStringID) {
1694 void* ptr = pyobj->GetObject();
1695 if (!ptr)
1696 return false;
1697
1698 fBuffer = *((std::string*)ptr);
1699 para.fValue.fVoidp = &fBuffer;
1700 para.fTypeCode = 'V';
1701 return true;
1702 }
1703
1704 return false;
1705}
1706
1707CPyCppyy::STLWStringConverter::STLWStringConverter(bool keepControl) :
1708 InstanceConverter(Cppyy::GetScope("std::wstring"), keepControl) {}
1709
1710bool CPyCppyy::STLWStringConverter::SetArg(
1711 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1712{
1713 if (PyUnicode_Check(pyobject)) {
1715 fBuffer.resize(len);
1716 CPyCppyy_PyUnicode_AsWideChar(pyobject, &fBuffer[0], len);
1717 para.fValue.fVoidp = &fBuffer;
1718 para.fTypeCode = 'V';
1719 return true;
1720 }
1721
1722 if (!(PyInt_Check(pyobject) || PyLong_Check(pyobject))) {
1723 bool result = InstancePtrConverter::SetArg(pyobject, para, ctxt);
1724 para.fTypeCode = 'V';
1725 return result;
1726 }
1727
1728 return false;
1729}
1730
1731PyObject* CPyCppyy::STLWStringConverter::FromMemory(void* address)
1732{
1733 if (address)
1734 return PyUnicode_FromWideChar(((std::wstring*)address)->c_str(), ((std::wstring*)address)->size());
1735 wchar_t w = L'\0';
1736 return PyUnicode_FromWideChar(&w, 0);
1737}
1738
1739bool CPyCppyy::STLWStringConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt)
1740{
1741 if (PyUnicode_Check(value)) {
1743 wchar_t* buf = new wchar_t[len+1];
1744 CPyCppyy_PyUnicode_AsWideChar(value, buf, len);
1745 *((std::wstring*)address) = std::wstring(buf, len);
1746 delete[] buf;
1747 return true;
1748 }
1749 return InstanceConverter::ToMemory(value, address, ctxt);
1750}
1751
1752
1753bool CPyCppyy::STLStringMoveConverter::SetArg(
1754 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1755{
1756// convert <pyobject> to C++ std::string&&, set arg for call
1757 int moveit_reason = 3; // move on temporary fBuffer
1758 if (CPPInstance_Check(pyobject)) {
1759 CPPInstance* pyobj = (CPPInstance*)pyobject;
1760 if (pyobj->fFlags & CPPInstance::kIsRValue) {
1761 pyobj->fFlags &= ~CPPInstance::kIsRValue;
1762 moveit_reason = 2;
1763 } else if (pyobject->ob_refcnt == MOVE_REFCOUNT_CUTOFF) {
1764 moveit_reason = 1;
1765 } else
1766 moveit_reason = 0;
1767 }
1768
1769 if (moveit_reason) {
1770 bool result = this->STLStringConverter::SetArg(pyobject, para, ctxt);
1771 if (!result && moveit_reason == 2) // restore the movability flag?
1772 ((CPPInstance*)pyobject)->fFlags |= CPPInstance::kIsRValue;
1773 return result;
1774 }
1775
1776 PyErr_SetString(PyExc_ValueError, "object is not an rvalue");
1777 return false; // not a temporary or movable object
1778}
1779
1780
1781//----------------------------------------------------------------------------
1783 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1784{
1785// convert <pyobject> to C++ instance*, set arg for call
1786 CPPInstance* pyobj = GetCppInstance(pyobject);
1787 if (!pyobj) {
1788 if (GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) {
1789 para.fTypeCode = 'p'; // allow special cases such as nullptr
1790 return true;
1791 }
1792
1793 // not a cppyy object (TODO: handle SWIG etc.)
1794 return false;
1795 }
1796
1797 if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1798 // depending on memory policy, some objects need releasing when passed into functions
1799 if (!KeepControl() && !UseStrictOwnership(ctxt))
1800 pyobj->CppOwns();
1801
1802 // calculate offset between formal and actual arguments
1803 para.fValue.fVoidp = pyobj->GetObject();
1804 if (pyobj->ObjectIsA() != fClass) {
1806 pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */);
1807 }
1808
1809 // set pointer (may be null) and declare success
1810 para.fTypeCode = 'p';
1811 return true;
1812 }
1813
1814 return false;
1815}
1816
1817//----------------------------------------------------------------------------
1819{
1820// construct python object from C++ instance read at <address>
1822}
1823
1824//----------------------------------------------------------------------------
1825bool CPyCppyy::InstancePtrConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1826{
1827// convert <value> to C++ instance, write it at <address>
1828 CPPInstance* pyobj = GetCppInstance(value);
1829 if (!pyobj) {
1830 void* ptr = nullptr;
1831 if (GetAddressSpecialCase(value, ptr)) {
1832 *(void**)address = ptr; // allow special cases such as nullptr
1833 return true;
1834 }
1835
1836 // not a cppyy object (TODO: handle SWIG etc.)
1837 return false;
1838 }
1839
1840 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1841 // depending on memory policy, some objects need releasing when passed into functions
1842 if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict)
1843 ((CPPInstance*)value)->CppOwns();
1844
1845 *(void**)address = pyobj->GetObject();
1846 return true;
1847 }
1848
1849 return false;
1850}
1851
1852// TODO: CONSOLIDATE Instance, InstanceRef, InstancePtr ...
1853
1854//----------------------------------------------------------------------------
1855bool CPyCppyy::InstanceConverter::SetArg(
1856 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1857{
1858// convert <pyobject> to C++ instance, set arg for call
1859 CPPInstance* pyobj = GetCppInstance(pyobject);
1860 if (pyobj) {
1861 if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1862 // calculate offset between formal and actual arguments
1863 para.fValue.fVoidp = pyobj->GetObject();
1864 if (!para.fValue.fVoidp)
1865 return false;
1866
1867 if (pyobj->ObjectIsA() != fClass) {
1869 pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */);
1870 }
1871
1872 para.fTypeCode = 'V';
1873 return true;
1874 }
1875 }
1876
1877 return ConvertImplicit(fClass, pyobject, para, ctxt);
1878}
1879
1880//----------------------------------------------------------------------------
1881PyObject* CPyCppyy::InstanceConverter::FromMemory(void* address)
1882{
1884}
1885
1886//----------------------------------------------------------------------------
1887bool CPyCppyy::InstanceConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1888{
1889// assign value to C++ instance living at <address> through assignment operator
1890 PyObject* pyobj = BindCppObjectNoCast(address, fClass);
1891 PyObject* result = PyObject_CallMethod(pyobj, (char*)"__assign__", (char*)"O", value);
1892 Py_DECREF(pyobj);
1893
1894 if (result) {
1895 Py_DECREF(result);
1896 return true;
1897 }
1898 return false;
1899}
1900
1901
1902//----------------------------------------------------------------------------
1903bool CPyCppyy::InstanceRefConverter::SetArg(
1904 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1905{
1906// convert <pyobject> to C++ instance&, set arg for call
1907 CPPInstance* pyobj = GetCppInstance(pyobject);
1908 if (pyobj) {
1909
1910 // reject moves
1911 if (pyobj->fFlags & CPPInstance::kIsRValue)
1912 return false;
1913
1914 if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1915 // calculate offset between formal and actual arguments
1916 para.fValue.fVoidp = pyobj->GetObject();
1917 if (pyobj->ObjectIsA() != fClass) {
1919 pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */);
1920 }
1921
1922 para.fTypeCode = 'V';
1923 return true;
1924 }
1925 }
1926
1927 if (!fIsConst) // no implicit conversion possible
1928 return false;
1929
1930 return ConvertImplicit(fClass, pyobject, para, ctxt);
1931}
1932
1933//----------------------------------------------------------------------------
1934PyObject* CPyCppyy::InstanceRefConverter::FromMemory(void* address)
1935{
1937}
1938
1939//----------------------------------------------------------------------------
1940bool CPyCppyy::InstanceMoveConverter::SetArg(
1941 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1942{
1943// convert <pyobject> to C++ instance&&, set arg for call
1944 CPPInstance* pyobj = GetCppInstance(pyobject);
1945 if (!pyobj) {
1946 // implicit conversion is fine as it the temporary by definition is moveable
1947 return ConvertImplicit(fClass, pyobject, para, ctxt);
1948 }
1949
1950// moving is same as by-ref, but have to check that move is allowed
1951 int moveit_reason = 0;
1952 if (pyobj->fFlags & CPPInstance::kIsRValue) {
1953 pyobj->fFlags &= ~CPPInstance::kIsRValue;
1954 moveit_reason = 2;
1955 } else if (pyobject->ob_refcnt == MOVE_REFCOUNT_CUTOFF) {
1956 moveit_reason = 1;
1957 }
1958
1959 if (moveit_reason) {
1960 bool result = this->InstanceRefConverter::SetArg(pyobject, para, ctxt);
1961 if (!result && moveit_reason == 2) // restore the movability flag?
1962 ((CPPInstance*)pyobject)->fFlags |= CPPInstance::kIsRValue;
1963 return result;
1964 }
1965
1966 PyErr_SetString(PyExc_ValueError, "object is not an rvalue");
1967 return false; // not a temporary or movable object
1968}
1969
1970//----------------------------------------------------------------------------
1971template <bool ISREFERENCE>
1972bool CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::SetArg(
1973 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1974{
1975// convert <pyobject> to C++ instance**, set arg for call
1976 CPPInstance* pyobj = GetCppInstance(pyobject);
1977 if (!pyobj)
1978 return false; // not a cppyy object (TODO: handle SWIG etc.)
1979
1980 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1981 // depending on memory policy, some objects need releasing when passed into functions
1982 if (!KeepControl() && !UseStrictOwnership(ctxt))
1983 pyobj->CppOwns();
1984
1985 // set pointer (may be null) and declare success
1986 if (pyobj->fFlags & CPPInstance::kIsReference) // already a ptr to object?
1987 para.fValue.fVoidp = pyobj->GetObjectRaw();
1988 else
1989 para.fValue.fVoidp = &pyobj->GetObjectRaw();
1990 para.fTypeCode = ISREFERENCE ? 'V' : 'p';
1991 return true;
1992 }
1993
1994 return false;
1995}
1996
1997//----------------------------------------------------------------------------
1998template <bool ISREFERENCE>
1999PyObject* CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::FromMemory(void* address)
2000{
2001// construct python object from C++ instance* read at <address>
2003}
2004
2005//----------------------------------------------------------------------------
2006template <bool ISREFERENCE>
2007bool CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
2008{
2009// convert <value> to C++ instance*, write it at <address>
2010 CPPInstance* pyobj = GetCppInstance(value);
2011 if (!pyobj)
2012 return false; // not a cppyy object (TODO: handle SWIG etc.)
2013
2014 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
2015 // depending on memory policy, some objects need releasing when passed into functions
2016 if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict)
2017 pyobj->CppOwns();
2018
2019 // register the value for potential recycling
2021
2022 // set pointer (may be null) and declare success
2023 *(void**)address = pyobj->GetObject();
2024 return true;
2025 }
2026
2027 return false;
2028}
2029
2030
2031namespace CPyCppyy {
2032// Instantiate the templates
2033 template class CPyCppyy::InstancePtrPtrConverter<true>;
2034 template class CPyCppyy::InstancePtrPtrConverter<false>;
2035}
2036
2037//----------------------------------------------------------------------------
2038bool CPyCppyy::InstanceArrayConverter::SetArg(
2039 PyObject* pyobject, Parameter& para, CallContext* /* txt */)
2040{
2041// convert <pyobject> to C++ instance**, set arg for call
2042 if (!TupleOfInstances_CheckExact(pyobject))
2043 return false; // no guarantee that the tuple is okay
2044
2045// treat the first instance of the tuple as the start of the array, and pass it
2046// by pointer (TODO: store and check sizes)
2047 if (PyTuple_Size(pyobject) < 1)
2048 return false;
2049
2050 PyObject* first = PyTuple_GetItem(pyobject, 0);
2052 return false; // should not happen
2053
2054 if (Cppyy::IsSubtype(((CPPInstance*)first)->ObjectIsA(), fClass)) {
2055 // no memory policies supported; set pointer (may be null) and declare success
2056 para.fValue.fVoidp = ((CPPInstance*)first)->GetObject();
2057 para.fTypeCode = 'p';
2058 return true;
2059 }
2060
2061 return false;
2062}
2063
2064//----------------------------------------------------------------------------
2065PyObject* CPyCppyy::InstanceArrayConverter::FromMemory(void* address)
2066{
2067// construct python tuple of instances from C++ array read at <address>
2068 return BindCppObjectArray(*(char**)address, fClass, m_dims);
2069}
2070
2071//----------------------------------------------------------------------------
2072bool CPyCppyy::InstanceArrayConverter::ToMemory(PyObject* /* value */, void* /* address */, PyObject* /* ctxt */)
2073{
2074// convert <value> to C++ array of instances, write it at <address>
2075
2076// TODO: need to have size both for the array and from the input
2077 PyErr_SetString(PyExc_NotImplementedError,
2078 "access to C-arrays of objects not yet implemented!");
2079 return false;
2080}
2081
2082//___________________________________________________________________________
2083// CLING WORKAROUND -- classes for STL iterators are completely undefined in that
2084// they come in a bazillion different guises, so just do whatever
2085bool CPyCppyy::STLIteratorConverter::SetArg(
2086 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2087{
2088 if (!CPPInstance_Check(pyobject))
2089 return false;
2090
2091// just set the pointer value, no check
2092 CPPInstance* pyobj = (CPPInstance*)pyobject;
2093 para.fValue.fVoidp = pyobj->GetObject();
2094 para.fTypeCode = 'V';
2095 return true;
2096}
2097// -- END CLING WORKAROUND
2098
2099//----------------------------------------------------------------------------
2100bool CPyCppyy::VoidPtrRefConverter::SetArg(
2101 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2102{
2103// convert <pyobject> to C++ void*&, set arg for call
2104 CPPInstance* pyobj = GetCppInstance(pyobject);
2105 if (pyobj) {
2106 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2107 para.fTypeCode = 'V';
2108 return true;
2109 }
2110
2111 return false;
2112}
2113
2114//----------------------------------------------------------------------------
2115bool CPyCppyy::VoidPtrPtrConverter::SetArg(
2116 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2117{
2118// convert <pyobject> to C++ void**, set arg for call
2119 CPPInstance* pyobj = GetCppInstance(pyobject);
2120 if (pyobj) {
2121 // this is a C++ object, take and set its address
2122 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2123 para.fTypeCode = 'p';
2124 return true;
2125 } else if (IsPyCArgObject(pyobject)) {
2127 if (carg->obj) {
2128 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)carg->obj)->b_ptr;
2129 para.fTypeCode = 'p';
2130 return true;
2131 }
2132 }
2133
2134// buffer objects are allowed under "user knows best" (this includes the buffer
2135// interface to ctypes.c_void_p, which results in a void**)
2136 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', 1, para.fValue.fVoidp, false);
2137
2138// ok if buffer exists (can't perform any useful size checks)
2139 if (para.fValue.fVoidp && buflen != 0) {
2140 para.fTypeCode = 'p';
2141 return true;
2142 }
2143
2144 return false;
2145}
2146
2147//----------------------------------------------------------------------------
2148PyObject* CPyCppyy::VoidPtrPtrConverter::FromMemory(void* address)
2149{
2150// read a void** from address; since this is unknown, long is used (user can cast)
2151 if (!address || *(ptrdiff_t*)address == 0) {
2152 Py_INCREF(gNullPtrObject);
2153 return gNullPtrObject;
2154 }
2155 return CreatePointerView(*(ptrdiff_t**)address, fSize);
2156}
2157
2158//----------------------------------------------------------------------------
2159bool CPyCppyy::PyObjectConverter::SetArg(
2160 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2161{
2162// by definition: set and declare success
2163 para.fValue.fVoidp = pyobject;
2164 para.fTypeCode = 'p';
2165 return true;
2166}
2167
2168PyObject* CPyCppyy::PyObjectConverter::FromMemory(void* address)
2169{
2170// construct python object from C++ PyObject* read at <address>
2171 PyObject* pyobject = *((PyObject**)address);
2172
2173 if (!pyobject) {
2175 }
2176
2177 Py_INCREF(pyobject);
2178 return pyobject;
2179}
2180
2181bool CPyCppyy::PyObjectConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
2182{
2183// no conversion needed, write <value> at <address>
2184 Py_INCREF(value);
2185 Py_XDECREF(*((PyObject**)address));
2186 *((PyObject**)address) = value;
2187 return true;
2188}
2189
2190
2191//- function pointer converter -----------------------------------------------
2192static unsigned int sWrapperCounter = 0;
2193// cache mapping signature/return type to python callable and corresponding wrapper
2194typedef std::pair<std::string, std::string> RetSigKey_t;
2195static std::map<RetSigKey_t, std::vector<void*>> sWrapperFree;
2196static std::map<RetSigKey_t, std::map<PyObject*, void*>> sWrapperLookup;
2197static std::map<PyObject*, std::pair<void*, RetSigKey_t>> sWrapperWeakRefs;
2198static std::map<void*, PyObject**> sWrapperReference;
2199
2201{
2202 auto ipos = sWrapperWeakRefs.find(pyref);
2203 if (ipos != sWrapperWeakRefs.end()) {
2204 // disable this callback and store for possible re-use
2205 void* wpraddress = ipos->second.first;
2206 *sWrapperReference[wpraddress] = nullptr;
2207 sWrapperFree[ipos->second.second].push_back(wpraddress);
2208 }
2209
2211}
2212static PyMethodDef gWrapperCacheEraserMethodDef = {
2213 const_cast<char*>("interal_WrapperCacheEraser"),
2214 (PyCFunction)WrapperCacheEraser,
2215 METH_O, nullptr
2216};
2217
2218static void* PyFunction_AsCPointer(PyObject* pyobject,
2219 const std::string& rettype, const std::string& signature)
2220{
2221// Convert a bound C++ function pointer or callable python object to a C-style
2222// function pointer. The former is direct, the latter involves a JIT-ed wrapper.
2223 static PyObject* sWrapperCacheEraser = PyCFunction_New(&gWrapperCacheEraserMethodDef, nullptr);
2224
2225 using namespace CPyCppyy;
2226
2227 if (CPPOverload_Check(pyobject)) {
2228 CPPOverload* ol = (CPPOverload*)pyobject;
2229 if (!ol->fMethodInfo || ol->fMethodInfo->fMethods.empty())
2230 return nullptr;
2231
2232 // find the overload with matching signature
2233 for (auto& m : ol->fMethodInfo->fMethods) {
2234 PyObject* sig = m->GetSignature(false);
2235 bool found = signature == CPyCppyy_PyText_AsString(sig);
2236 Py_DECREF(sig);
2237 if (found) {
2238 void* fptr = (void*)m->GetFunctionAddress();
2239 if (fptr) return fptr;
2240 break; // fall-through, with calling through Python
2241 }
2242 }
2243 }
2244
2245 if (TemplateProxy_Check(pyobject)) {
2246 // get the actual underlying template matching the signature
2247 TemplateProxy* pytmpl = (TemplateProxy*)pyobject;
2248 std::string fullname = CPyCppyy_PyText_AsString(pytmpl->fTI->fCppName);
2249 if (pytmpl->fTemplateArgs)
2250 fullname += CPyCppyy_PyText_AsString(pytmpl->fTemplateArgs);
2251 Cppyy::TCppScope_t scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType;
2252 Cppyy::TCppMethod_t cppmeth = Cppyy::GetMethodTemplate(scope, fullname, signature);
2253 if (cppmeth) {
2254 void* fptr = (void*)Cppyy::GetFunctionAddress(cppmeth, false);
2255 if (fptr) return fptr;
2256 }
2257 // fall-through, with calling through Python
2258 }
2259
2260 if (PyCallable_Check(pyobject)) {
2261 // generic python callable: create a C++ wrapper function
2262 void* wpraddress = nullptr;
2263
2264 // re-use existing wrapper if possible
2265 auto key = std::make_pair(rettype, signature);
2266 const auto& lookup = sWrapperLookup.find(key);
2267 if (lookup != sWrapperLookup.end()) {
2268 const auto& existing = lookup->second.find(pyobject);
2269 if (existing != lookup->second.end() && *sWrapperReference[existing->second] == pyobject)
2270 wpraddress = existing->second;
2271 }
2272
2273 // check for a pre-existing, unused, wrapper if not found
2274 if (!wpraddress) {
2275 const auto& freewrap = sWrapperFree.find(key);
2276 if (freewrap != sWrapperFree.end() && !freewrap->second.empty()) {
2277 wpraddress = freewrap->second.back();
2278 freewrap->second.pop_back();
2279 *sWrapperReference[wpraddress] = pyobject;
2280 PyObject* wref = PyWeakref_NewRef(pyobject, sWrapperCacheEraser);
2281 if (wref) sWrapperWeakRefs[wref] = std::make_pair(wpraddress, key);
2282 else PyErr_Clear(); // happens for builtins which don't need this
2283 }
2284 }
2285
2286 // create wrapper if no re-use possible
2287 if (!wpraddress) {
2289 return nullptr;
2290
2291 // extract argument types
2292 const std::vector<std::string>& argtypes = TypeManip::extract_arg_types(signature);
2293 int nArgs = (int)argtypes.size();
2294
2295 // wrapper name
2296 std::ostringstream wname;
2297 wname << "fptr_wrap" << ++sWrapperCounter;
2298
2299 // build wrapper function code
2300 std::ostringstream code;
2301 code << "namespace __cppyy_internal {\n "
2302 << rettype << " " << wname.str() << "(";
2303 for (int i = 0; i < nArgs; ++i) {
2304 code << argtypes[i] << " arg" << i;
2305 if (i != nArgs-1) code << ", ";
2306 }
2307 code << ") {\n";
2308
2309 // start function body
2310 Utility::ConstructCallbackPreamble(rettype, argtypes, code);
2311
2312 // create a referencable pointer
2313 PyObject** ref = new PyObject*{pyobject};
2314
2315 // function call itself and cleanup
2316 code << " PyObject** ref = (PyObject**)" << (intptr_t)ref << ";\n"
2317 " PyObject* pyresult = nullptr;\n"
2318 " if (*ref) pyresult = PyObject_CallFunctionObjArgs(*ref";
2319 for (int i = 0; i < nArgs; ++i)
2320 code << ", pyargs[" << i << "]";
2321 code << ", NULL);\n"
2322 " else PyErr_SetString(PyExc_TypeError, \"callable was deleted\");\n";
2323
2324 // close
2325 Utility::ConstructCallbackReturn(rettype, nArgs, code);
2326
2327 // end of namespace
2328 code << "}";
2329
2330 // finally, compile the code
2331 if (!Cppyy::Compile(code.str()))
2332 return nullptr;
2333
2334 // TODO: is there no easier way?
2335 static Cppyy::TCppScope_t scope = Cppyy::GetScope("__cppyy_internal");
2336 const auto& idx = Cppyy::GetMethodIndicesFromName(scope, wname.str());
2337 wpraddress = Cppyy::GetFunctionAddress(Cppyy::GetMethod(scope, idx[0]), false);
2338 sWrapperReference[wpraddress] = ref;
2339
2340 // cache the new wrapper
2341 sWrapperLookup[key][pyobject] = wpraddress;
2342 PyObject* wref = PyWeakref_NewRef(pyobject, sWrapperCacheEraser);
2343 if (wref) sWrapperWeakRefs[wref] = std::make_pair(wpraddress, key);
2344 else PyErr_Clear(); // happens for builtins which don't need this
2345 }
2346
2347 // now pass the pointer to the wrapper function (may be null)
2348 return wpraddress;
2349 }
2350
2351 return nullptr;
2352}
2353
2354bool CPyCppyy::FunctionPointerConverter::SetArg(
2355 PyObject* pyobject, Parameter& para, CallContext* /*ctxt*/)
2356{
2357// special case: allow nullptr singleton:
2358 if (gNullPtrObject == pyobject) {
2359 para.fValue.fVoidp = nullptr;
2360 para.fTypeCode = 'p';
2361 return true;
2362 }
2363
2364// normal case, get a function pointer
2365 void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature);
2366 if (fptr) {
2367 para.fValue.fVoidp = fptr;
2368 para.fTypeCode = 'p';
2369 return true;
2370 }
2371
2372 return false;
2373}
2374
2375static std::map<void*, std::string> sFuncWrapperLookup;
2376static const char* FPCFM_ERRMSG = "conversion to std::function failed";
2377PyObject* CPyCppyy::FunctionPointerConverter::FromMemory(void* address)
2378{
2379// A function pointer in clang is represented by a Type, not a FunctionDecl and it's
2380// not possible to get the latter from the former: the backend will need to support
2381// both. Since that is far in the future, we'll use a std::function instead.
2382 static int func_count = 0;
2383
2384 if (!(address && *(void**)address)) {
2385 PyErr_SetString(PyExc_TypeError, FPCFM_ERRMSG);
2386 return nullptr;
2387 }
2388
2389 void* faddr = *(void**)address;
2390 auto cached = sFuncWrapperLookup.find(faddr);
2391 if (cached == sFuncWrapperLookup.end()) {
2392 std::ostringstream fname;
2393 fname << "ptr2func" << ++func_count;
2394
2395 std::ostringstream code;
2396 code << "namespace __cppyy_internal {\n std::function<"
2397 << fRetType << fSignature << "> " << fname.str()
2398 << " = (" << fRetType << "(*)" << fSignature << ")" << (intptr_t)faddr
2399 << ";\n}";
2400
2401 if (!Cppyy::Compile(code.str())) {
2402 PyErr_SetString(PyExc_TypeError, FPCFM_ERRMSG);
2403 return nullptr;
2404 }
2405
2406 // cache the new wrapper (TODO: does it make sense to use weakrefs on the data
2407 // member?)
2408 sFuncWrapperLookup[faddr] = fname.str();
2409 cached = sFuncWrapperLookup.find(faddr);
2410 }
2411
2412 static Cppyy::TCppScope_t scope = Cppyy::GetScope("__cppyy_internal");
2413 PyObject* pyscope = CreateScopeProxy(scope);
2414 PyObject* func = PyObject_GetAttrString(pyscope, cached->second.c_str());
2415 Py_DECREF(pyscope);
2416
2417 return func;
2418}
2419
2420bool CPyCppyy::FunctionPointerConverter::ToMemory(PyObject* pyobject, void* address, PyObject* /* ctxt */)
2421{
2422// special case: allow nullptr singleton:
2423 if (gNullPtrObject == pyobject) {
2424 *((void**)address) = nullptr;
2425 return true;
2426 }
2427
2428// normal case, get a function pointer
2429 void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature);
2430 if (fptr) {
2431 *((void**)address) = fptr;
2432 return true;
2433 }
2434
2435 return false;
2436}
2437
2438
2439//- std::function converter --------------------------------------------------
2440bool CPyCppyy::StdFunctionConverter::SetArg(
2441 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2442{
2443// prefer normal "object" conversion
2444 bool rf = ctxt->fFlags & CallContext::kNoImplicit;
2446 if (fConverter->SetArg(pyobject, para, ctxt)) {
2447 if (!rf) ctxt->fFlags &= ~CallContext::kNoImplicit;
2448 return true;
2449 }
2450
2451 PyErr_Clear();
2452
2453// else create a wrapper function
2454 if (this->FunctionPointerConverter::SetArg(pyobject, para, ctxt)) {
2455 // retrieve the wrapper pointer and capture it in a temporary std::function,
2456 // then try normal conversion a second time
2457 PyObject* func = this->FunctionPointerConverter::FromMemory(&para.fValue.fVoidp);
2458 if (func) {
2459 Py_XDECREF(fFuncWrap); fFuncWrap = func;
2460 bool result = fConverter->SetArg(fFuncWrap, para, ctxt);
2461 if (!rf) ctxt->fFlags &= ~CallContext::kNoImplicit;
2462 return result;
2463 }
2464 }
2465
2466 if (!rf) ctxt->fFlags &= ~CallContext::kNoImplicit;
2467 return false;
2468}
2469
2470PyObject* CPyCppyy::StdFunctionConverter::FromMemory(void* address)
2471{
2472 return fConverter->FromMemory(address);
2473}
2474
2475bool CPyCppyy::StdFunctionConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt)
2476{
2477 return fConverter->ToMemory(value, address, ctxt);
2478}
2479
2480
2481//- smart pointer converters -------------------------------------------------
2482bool CPyCppyy::SmartPtrConverter::SetArg(
2483 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2484{
2485 char typeCode = fIsRef ? 'p' : 'V';
2486
2487 if (!CPPInstance_Check(pyobject)) {
2488 // TODO: not sure how this is correct for pass-by-ref nor does it help with
2489 // implicit conversions for pass-by-value
2490 if (fIsRef && GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) {
2491 para.fTypeCode = typeCode; // allow special cases such as nullptr
2492 return true;
2493 }
2494
2495 return false;
2496 }
2497
2498 CPPInstance* pyobj = (CPPInstance*)pyobject;
2499
2500// for the case where we have a 'hidden' smart pointer:
2501 if (Cppyy::TCppType_t tsmart = pyobj->GetSmartIsA()) {
2502 if (Cppyy::IsSubtype(tsmart, fSmartPtrType)) {
2503 // depending on memory policy, some objects need releasing when passed into functions
2504 if (fKeepControl && !UseStrictOwnership(ctxt))
2505 ((CPPInstance*)pyobject)->CppOwns();
2506
2507 // calculate offset between formal and actual arguments
2508 para.fValue.fVoidp = pyobj->GetSmartObject();
2509 if (tsmart != fSmartPtrType) {
2511 tsmart, fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */);
2512 }
2513
2514 // set pointer (may be null) and declare success
2515 para.fTypeCode = typeCode;
2516 return true;
2517 }
2518 }
2519
2520// for the case where we have an 'exposed' smart pointer:
2521 if (!pyobj->IsSmart() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fSmartPtrType)) {
2522 // calculate offset between formal and actual arguments
2523 para.fValue.fVoidp = pyobj->GetObject();
2524 if (pyobj->ObjectIsA() != fSmartPtrType) {
2526 pyobj->ObjectIsA(), fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */);
2527 }
2528
2529 // set pointer (may be null) and declare success
2530 para.fTypeCode = typeCode;
2531 return true;
2532 }
2533
2534// final option, try mapping pointer types held (TODO: do not allow for non-const ref)
2535 if (pyobj->IsSmart() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fUnderlyingType)) {
2536 para.fValue.fVoidp = ((CPPInstance*)pyobject)->GetSmartObject();
2537 para.fTypeCode = 'V';
2538 return true;
2539 }
2540
2541 return false;
2542}
2543
2544PyObject* CPyCppyy::SmartPtrConverter::FromMemory(void* address)
2545{
2546 if (!address || !fSmartPtrType)
2547 return nullptr;
2548
2549 return BindCppObjectNoCast(address, fSmartPtrType);
2550}
2551
2552
2553//----------------------------------------------------------------------------
2554namespace {
2555
2556// clang libcpp and gcc use the same structure (ptr, size)
2557#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2558struct faux_initlist
2559{
2560 typedef size_t size_type;
2561 typedef void* iterator;
2562 iterator _M_array;
2563 size_type _M_len;
2564};
2565#elif defined (_MSC_VER)
2566struct faux_initlist
2567{
2568 typedef char* iterator;
2569 iterator _M_array; // ie. _First;
2570 iterator _Last;
2571};
2572#else
2573#define NO_KNOWN_INITIALIZER_LIST 1
2574#endif
2575
2576} // unnamed namespace
2577
2578CPyCppyy::InitializerListConverter::~InitializerListConverter()
2579{
2580 if (fConverter && fConverter->HasState()) delete fConverter;
2581}
2582
2583bool CPyCppyy::InitializerListConverter::SetArg(
2584 PyObject* pyobject, Parameter& para, CallContext* /*ctxt*/)
2585{
2586#ifdef NO_KNOWN_INITIALIZER_LIST
2587 return false;
2588#else
2589// convert the given argument to an initializer list temporary; this is purely meant
2590// to be a syntactic thing, so only _python_ sequences are allowed; bound C++ proxies
2591// are therefore rejected (should go through eg. a copy constructor etc.)
2592 if (CPPInstance_Check(pyobject) || !PySequence_Check(pyobject) || CPyCppyy_PyText_Check(pyobject)
2593#if PY_VERSION_HEX >= 0x03000000
2594 || PyBytes_Check(pyobject)
2595#endif
2596 )
2597 return false;
2598
2599 void* buf;
2600 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', (int)fValueSize, buf, true);
2601 faux_initlist* fake = nullptr;
2602 if (buf && buflen) {
2603 // dealing with an array here, pass on whole-sale
2604 fake = (faux_initlist*)malloc(sizeof(faux_initlist));
2605 fake->_M_array = (faux_initlist::iterator)buf;
2606#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2607 fake->_M_len = (faux_initlist::size_type)buflen;
2608#elif defined (_MSC_VER)
2609 fake->_Last = fake->_M_array+buflen*fValueSize;
2610#endif
2611 } else {
2612 // can only construct empty lists, so use a fake initializer list
2613 size_t len = (size_t)PySequence_Size(pyobject);
2614 fake = (faux_initlist*)malloc(sizeof(faux_initlist)+fValueSize*len);
2615 fake->_M_array = (faux_initlist::iterator)((char*)fake+sizeof(faux_initlist));
2616#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2617 fake->_M_len = (faux_initlist::size_type)len;
2618 for (faux_initlist::size_type i = 0; i < fake->_M_len; ++i) {
2619#elif defined (_MSC_VER)
2620 fake->_Last = fake->_M_array+len*fValueSize;
2621 for (size_t i = 0; (fake->_M_array+i*fValueSize) != fake->_Last; ++i) {
2622#endif
2623 PyObject* item = PySequence_GetItem(pyobject, i);
2624 bool convert_ok = false;
2625 if (item) {
2626 if (!fConverter) {
2627 if (CPPInstance_Check(item)) {
2628 // by convention, use byte copy
2629 memcpy((char*)fake->_M_array + i*fValueSize,
2630 ((CPPInstance*)item)->GetObject(), fValueSize);
2631 convert_ok = true;
2632 }
2633 } else
2634 convert_ok = fConverter->ToMemory(item, (char*)fake->_M_array + i*fValueSize);
2635
2636 Py_DECREF(item);
2637 } else
2638 PyErr_Format(PyExc_TypeError, "failed to get item %d from sequence", (int)i);
2639
2640 if (!convert_ok) {
2641 free((void*)fake);
2642 return false;
2643 }
2644 }
2645 }
2646
2647 para.fValue.fVoidp = (void*)fake;
2648 para.fTypeCode = 'X'; // means ptr that backend has to free after call
2649 return true;
2650#endif
2651}
2652
2653//----------------------------------------------------------------------------
2654bool CPyCppyy::NotImplementedConverter::SetArg(PyObject*, Parameter&, CallContext*)
2655{
2656// raise a NotImplemented exception to take a method out of overload resolution
2657 PyErr_SetString(PyExc_NotImplementedError, "this method cannot (yet) be called");
2658 return false;
2659}
2660
2661
2662//- helper to refactor some code from CreateConverter ------------------------
2664 Cppyy::TCppScope_t klass, const std::string& cpd, long size, dims_t dims, bool isConst, bool control)
2665{
2666 using namespace CPyCppyy;
2667 Converter* result = nullptr;
2668
2669 if (cpd == "**" || cpd == "*[]" || cpd == "&*")
2670 result = new InstancePtrPtrConverter<false>(klass, control);
2671 else if (cpd == "*&")
2672 result = new InstancePtrPtrConverter<true>(klass, control);
2673 else if (cpd == "*" && size <= 0)
2674 result = new InstancePtrConverter(klass, control);
2675 else if (cpd == "&")
2676 result = new InstanceRefConverter(klass, isConst);
2677 else if (cpd == "&&")
2678 result = new InstanceMoveConverter(klass);
2679 else if (cpd == "[]" || size > 0)
2680 result = new InstanceArrayConverter(klass, dims, false);
2681 else if (cpd == "") // by value
2682 result = new InstanceConverter(klass, true);
2683
2684 return result;
2685}
2686
2687//- factories ----------------------------------------------------------------
2689CPyCppyy::Converter* CPyCppyy::CreateConverter(const std::string& fullType, dims_t dims)
2690{
2691// The matching of the fulltype to a converter factory goes through up to five levels:
2692// 1) full, exact match
2693// 2) match of decorated, unqualified type
2694// 3) accept const ref as by value
2695// 4) accept ref as pointer
2696// 5) generalized cases (covers basically all C++ classes)
2697//
2698// If all fails, void is used, which will generate a run-time warning when used.
2699
2700 dim_t size = (dims && dims[0] != -1) ? dims[1] : -1;
2701
2702// an exactly matching converter is best
2703 ConvFactories_t::iterator h = gConvFactories.find(fullType);
2704 if (h != gConvFactories.end())
2705 return (h->second)(dims);
2706
2707// resolve typedefs etc.
2708 const std::string& resolvedType = Cppyy::ResolveName(fullType);
2709
2710// a full, qualified matching converter is preferred
2711 if (resolvedType != fullType) {
2712 h = gConvFactories.find(resolvedType);
2713 if (h != gConvFactories.end())
2714 return (h->second)(dims);
2715 }
2716
2717//-- nothing? ok, collect information about the type and possible qualifiers/decorators
2718 bool isConst = strncmp(resolvedType.c_str(), "const", 5) == 0;
2719 const std::string& cpd = Utility::Compound(resolvedType);
2720 std::string realType = TypeManip::clean_type(resolvedType, false, true);
2721
2722// accept unqualified type (as python does not know about qualifiers)
2723 h = gConvFactories.find(realType + cpd);
2724 if (h != gConvFactories.end())
2725 return (h->second)(dims);
2726
2727// drop const, as that is mostly meaningless to python (with the exception
2728// of c-strings, but those are specialized in the converter map)
2729 if (isConst) {
2730 realType = TypeManip::remove_const(realType);
2731 h = gConvFactories.find(realType + cpd);
2732 if (h != gConvFactories.end())
2733 return (h->second)(dims);
2734 }
2735
2736//-- still nothing? try pointer instead of array (for builtins)
2737 if (cpd == "[]") {
2738 // simple array
2739 h = gConvFactories.find(realType + "*");
2740 if (h != gConvFactories.end()) {
2741 if (dims && dims[1] == UNKNOWN_SIZE) dims[1] = UNKNOWN_ARRAY_SIZE;
2742 return (h->second)(dims);
2743 }
2744 } else if (cpd == "*[]") {
2745 // array of pointers
2746 h = gConvFactories.find(realType + "*");
2747 if (h != gConvFactories.end()) {
2748 // upstream treats the pointer type as the array element type, but that pointer is
2749 // treated as a low-level view as well, so adjust the dims
2750 dim_t newdim = (dims && 0 < dims[0]) ? dims[0]+1 : 2;
2751 dims_t newdims = new dim_t[newdim+1];
2752 newdims[0] = newdim;
2753 newdims[1] = (0 < size ? size : UNKNOWN_ARRAY_SIZE); // the array
2754 newdims[2] = UNKNOWN_SIZE; // the pointer
2755 if (dims && 2 < newdim) {
2756 for (int i = 2; i < (newdim-1); ++i)
2757 newdims[i+1] = dims[i];
2758 }
2759 Converter* cnv = (h->second)(newdims);
2760 delete [] newdims;
2761 return cnv;
2762 }
2763 }
2764
2765//-- special case: initializer list
2766 if (realType.compare(0, 16, "initializer_list") == 0) {
2767 // get the type of the list and create a converter (TODO: get hold of value_type?)
2768 auto pos = realType.find('<');
2769 std::string value_type = realType.substr(pos+1, realType.size()-pos-2);
2770 Converter* cnv = nullptr; bool use_byte_cnv = false;
2771 if (cpd == "" && Cppyy::GetScope(value_type)) {
2772 // initializer list of object values does not work as the target is raw
2773 // memory; simply use byte copies
2774
2775 // by convention, leave cnv as nullptr
2776 use_byte_cnv = true;
2777 } else
2778 cnv = CreateConverter(value_type);
2779 if (cnv || use_byte_cnv)
2780 return new InitializerListConverter(cnv, Cppyy::SizeOf(value_type));
2781 }
2782
2783//-- still nothing? use a generalized converter
2784 bool control = cpd == "&" || isConst;
2785
2786//-- special case: std::function
2787 auto pos = resolvedType.find("function<");
2788 if (pos == 0 /* no std:: */ || pos == 5 /* with std:: */ ||
2789 pos == 6 /* const no std:: */ || pos == 11 /* const with std:: */ ) {
2790
2791 // get actual converter for normal passing
2793 Cppyy::GetScope(realType), cpd, size, dims, isConst, control);
2794
2795 if (cnv) {
2796 // get the type of the underlying (TODO: use target_type?)
2797 auto pos1 = resolvedType.find("(", pos+9);
2798 auto pos2 = resolvedType.rfind(")");
2799 if (pos1 != std::string::npos && pos2 != std::string::npos) {
2800 auto sz1 = pos1-pos-9;
2801 if (resolvedType[pos+9+sz1-1] == ' ') sz1 -= 1;
2802
2803 return new StdFunctionConverter(cnv,
2804 resolvedType.substr(pos+9, sz1), resolvedType.substr(pos1, pos2-pos1+1));
2805 } else if (cnv->HasState())
2806 delete cnv;
2807 }
2808 }
2809
2810// converters for known C++ classes and default (void*)
2811 Converter* result = nullptr;
2812 if (Cppyy::TCppScope_t klass = Cppyy::GetScope(realType)) {
2813 Cppyy::TCppType_t raw{0};
2814 if (Cppyy::GetSmartPtrInfo(realType, &raw, nullptr)) {
2815 if (cpd == "") {
2816 result = new SmartPtrConverter(klass, raw, control);
2817 } else if (cpd == "&") {
2818 result = new SmartPtrConverter(klass, raw);
2819 } else if (cpd == "*" && size <= 0) {
2820 result = new SmartPtrConverter(klass, raw, control, true);
2821 }
2822 }
2823
2824 if (!result) {
2825 // CLING WORKAROUND -- special case for STL iterators
2826 if (realType.rfind("__gnu_cxx::__normal_iterator", 0) /* vector */ == 0
2827#ifdef __APPLE__
2828 || realType.rfind("__wrap_iter", 0) == 0
2829#endif
2830 // TODO: Windows?
2831 ) {
2832 static STLIteratorConverter c;
2833 result = &c;
2834 } else
2835 // -- CLING WORKAROUND
2836 result = selectInstanceCnv(klass, cpd, size, dims, isConst, control);
2837 }
2838 } else if (resolvedType.find("(*)") != std::string::npos ||
2839 (resolvedType.find("::*)") != std::string::npos)) {
2840 // this is a function function pointer
2841 // TODO: find better way of finding the type
2842 auto pos1 = resolvedType.find('(');
2843 auto pos2 = resolvedType.find("*)");
2844 auto pos3 = resolvedType.rfind(')');
2845 result = new FunctionPointerConverter(
2846 resolvedType.substr(0, pos1), resolvedType.substr(pos2+2, pos3-pos2-1));
2847 }
2848
2849 if (!result && cpd == "&&") {
2850 // for builtin, can use const-ref for r-ref
2851 h = gConvFactories.find("const " + realType + "&");
2852 if (h != gConvFactories.end())
2853 return (h->second)(dims);
2854 // else, unhandled moves
2855 result = new NotImplementedConverter();
2856 }
2857
2858 if (!result && h != gConvFactories.end())
2859 // converter factory available, use it to create converter
2860 result = (h->second)(dims);
2861 else if (!result) {
2862 // default to something reasonable, assuming "user knows best"
2863 if (cpd.size() == 2 && cpd != "&&") // "**", "*[]", "*&"
2864 result = new VoidPtrPtrConverter(size);
2865 else if (!cpd.empty())
2866 result = new VoidArrayConverter(); // "user knows best"
2867 else
2868 result = new NotImplementedConverter(); // fails on use
2869 }
2870
2871 return result;
2872}
2873
2874//----------------------------------------------------------------------------
2877{
2878 if (p && p->HasState())
2879 delete p; // state-less converters are always shared
2880}
2881
2882//----------------------------------------------------------------------------
2884bool CPyCppyy::RegisterConverter(const std::string& name, cf_t fac)
2885{
2886// register a custom converter
2887 auto f = gConvFactories.find(name);
2888 if (f != gConvFactories.end())
2889 return false;
2890
2891 gConvFactories[name] = fac;
2892 return true;
2893}
2894
2895//----------------------------------------------------------------------------
2897bool CPyCppyy::UnregisterConverter(const std::string& name)
2898{
2899// remove a custom converter
2900 auto f = gConvFactories.find(name);
2901 if (f != gConvFactories.end()) {
2902 gConvFactories.erase(f);
2903 return true;
2904 }
2905 return false;
2906}
2907
2908
2909//----------------------------------------------------------------------------
2910namespace {
2911
2912using namespace CPyCppyy;
2913
2914#define STRINGVIEW "basic_string_view<char,char_traits<char> >"
2915#define WSTRING "basic_string<wchar_t,char_traits<wchar_t>,allocator<wchar_t> >"
2916
2917static struct InitConvFactories_t {
2918public:
2919 InitConvFactories_t() {
2920 // load all converter factories in the global map 'gConvFactories'
2922
2923 // factories for built-ins
2924 gf["bool"] = (cf_t)+[](dims_t) { static BoolConverter c{}; return &c; };
2925 gf["const bool&"] = (cf_t)+[](dims_t) { static ConstBoolRefConverter c{}; return &c; };
2926 gf["bool&"] = (cf_t)+[](dims_t) { static BoolRefConverter c{}; return &c; };
2927 gf["char"] = (cf_t)+[](dims_t) { static CharConverter c{}; return &c; };
2928 gf["const char&"] = (cf_t)+[](dims_t) { static ConstCharRefConverter c{}; return &c; };
2929 gf["char&"] = (cf_t)+[](dims_t) { static CharRefConverter c{}; return &c; };
2930 gf["signed char&"] = (cf_t)+[](dims_t) { static SCharRefConverter c{}; return &c; };
2931 gf["unsigned char"] = (cf_t)+[](dims_t) { static UCharConverter c{}; return &c; };
2932 gf["const unsigned char&"] = (cf_t)+[](dims_t) { static ConstUCharRefConverter c{}; return &c; };
2933 gf["unsigned char&"] = (cf_t)+[](dims_t) { static UCharRefConverter c{}; return &c; };
2934 gf["UCharAsInt"] = (cf_t)+[](dims_t) { static UCharAsIntConverter c{}; return &c; };
2935 gf["wchar_t"] = (cf_t)+[](dims_t) { static WCharConverter c{}; return &c; };
2936 gf["char16_t"] = (cf_t)+[](dims_t) { static Char16Converter c{}; return &c; };
2937 gf["char32_t"] = (cf_t)+[](dims_t) { static Char32Converter c{}; return &c; };
2938 gf["wchar_t&"] = (cf_t)+[](dims_t) { static WCharRefConverter c{}; return &c; };
2939 gf["char16_t&"] = (cf_t)+[](dims_t) { static Char16RefConverter c{}; return &c; };
2940 gf["char32_t&"] = (cf_t)+[](dims_t) { static Char32RefConverter c{}; return &c; };
2941 gf["int8_t"] = (cf_t)+[](dims_t) { static Int8Converter c{}; return &c; };
2942 gf["int8_t&"] = (cf_t)+[](dims_t) { static Int8RefConverter c{}; return &c; };
2943 gf["const int8_t&"] = (cf_t)+[](dims_t) { static ConstInt8RefConverter c{}; return &c; };
2944 gf["uint8_t"] = (cf_t)+[](dims_t) { static UInt8Converter c{}; return &c; };
2945 gf["const uint8_t&"] = (cf_t)+[](dims_t) { static ConstUInt8RefConverter c{}; return &c; };
2946 gf["uint8_t&"] = (cf_t)+[](dims_t) { static UInt8RefConverter c{}; return &c; };
2947 gf["short"] = (cf_t)+[](dims_t) { static ShortConverter c{}; return &c; };
2948 gf["const short&"] = (cf_t)+[](dims_t) { static ConstShortRefConverter c{}; return &c; };
2949 gf["short&"] = (cf_t)+[](dims_t) { static ShortRefConverter c{}; return &c; };
2950 gf["unsigned short"] = (cf_t)+[](dims_t) { static UShortConverter c{}; return &c; };
2951 gf["const unsigned short&"] = (cf_t)+[](dims_t) { static ConstUShortRefConverter c{}; return &c; };
2952 gf["unsigned short&"] = (cf_t)+[](dims_t) { static UShortRefConverter c{}; return &c; };
2953 gf["int"] = (cf_t)+[](dims_t) { static IntConverter c{}; return &c; };
2954 gf["int&"] = (cf_t)+[](dims_t) { static IntRefConverter c{}; return &c; };
2955 gf["const int&"] = (cf_t)+[](dims_t) { static ConstIntRefConverter c{}; return &c; };
2956 gf["unsigned int"] = (cf_t)+[](dims_t) { static UIntConverter c{}; return &c; };
2957 gf["const unsigned int&"] = (cf_t)+[](dims_t) { static ConstUIntRefConverter c{}; return &c; };
2958 gf["unsigned int&"] = (cf_t)+[](dims_t) { static UIntRefConverter c{}; return &c; };
2959 gf["long"] = (cf_t)+[](dims_t) { static LongConverter c{}; return &c; };
2960 gf["long&"] = (cf_t)+[](dims_t) { static LongRefConverter c{}; return &c; };
2961 gf["const long&"] = (cf_t)+[](dims_t) { static ConstLongRefConverter c{}; return &c; };
2962 gf["unsigned long"] = (cf_t)+[](dims_t) { static ULongConverter c{}; return &c; };
2963 gf["const unsigned long&"] = (cf_t)+[](dims_t) { static ConstULongRefConverter c{}; return &c; };
2964 gf["unsigned long&"] = (cf_t)+[](dims_t) { static ULongRefConverter c{}; return &c; };
2965 gf["long long"] = (cf_t)+[](dims_t) { static LLongConverter c{}; return &c; };
2966 gf["const long long&"] = (cf_t)+[](dims_t) { static ConstLLongRefConverter c{}; return &c; };
2967 gf["long long&"] = (cf_t)+[](dims_t) { static LLongRefConverter c{}; return &c; };
2968 gf["unsigned long long"] = (cf_t)+[](dims_t) { static ULLongConverter c{}; return &c; };
2969 gf["const unsigned long long&"] = (cf_t)+[](dims_t) { static ConstULLongRefConverter c{}; return &c; };
2970 gf["unsigned long long&"] = (cf_t)+[](dims_t) { static ULLongRefConverter c{}; return &c; };
2971
2972 gf["float"] = (cf_t)+[](dims_t) { static FloatConverter c{}; return &c; };
2973 gf["const float&"] = (cf_t)+[](dims_t) { static ConstFloatRefConverter c{}; return &c; };
2974 gf["float&"] = (cf_t)+[](dims_t) { static FloatRefConverter c{}; return &c; };
2975 gf["double"] = (cf_t)+[](dims_t) { static DoubleConverter c{}; return &c; };
2976 gf["double&"] = (cf_t)+[](dims_t) { static DoubleRefConverter c{}; return &c; };
2977 gf["const double&"] = (cf_t)+[](dims_t) { static ConstDoubleRefConverter c{}; return &c; };
2978 gf["long double"] = (cf_t)+[](dims_t) { static LDoubleConverter c{}; return &c; };
2979 gf["const long double&"] = (cf_t)+[](dims_t) { static ConstLDoubleRefConverter c{}; return &c; };
2980 gf["long double&"] = (cf_t)+[](dims_t) { static LDoubleRefConverter c{}; return &c; };
2981 gf["std::complex<double>"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2982 gf["complex<double>"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2983 gf["const std::complex<double>&"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2984 gf["const complex<double>&"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2985 gf["void"] = (cf_t)+[](dims_t) { static VoidConverter c{}; return &c; };
2986
2987 // pointer/array factories
2988 gf["bool*"] = (cf_t)+[](dims_t d) { return new BoolArrayConverter{d}; };
2989 gf["bool**"] = (cf_t)+[](dims_t d) { return new BoolArrayPtrConverter{d}; };
2990 gf["const signed char[]"] = (cf_t)+[](dims_t d) { return new SCharArrayConverter{d}; };
2991 gf["signed char[]"] = (cf_t)+[](dims_t d) { return new SCharArrayConverter{d}; };
2992 gf["signed char**"] = (cf_t)+[](dims_t d) { return new SCharArrayPtrConverter{d}; };
2993 gf["const unsigned char*"] = (cf_t)+[](dims_t d) { return new UCharArrayConverter{d}; };
2994 gf["unsigned char*"] = (cf_t)+[](dims_t d) { return new UCharArrayConverter{d}; };
2995 gf["UCharAsInt*"] = (cf_t)+[](dims_t d) { return new UCharArrayConverter{d}; };
2996 gf["unsigned char**"] = (cf_t)+[](dims_t d) { return new UCharArrayPtrConverter{d}; };
2997#if __cplusplus > 201402L
2998 gf["byte*"] = (cf_t)+[](dims_t d) { return new ByteArrayConverter{d}; };
2999 gf["byte**"] = (cf_t)+[](dims_t d) { return new ByteArrayPtrConverter{d}; };
3000#endif
3001 gf["short*"] = (cf_t)+[](dims_t d) { return new ShortArrayConverter{d}; };
3002 gf["short**"] = (cf_t)+[](dims_t d) { return new ShortArrayPtrConverter{d}; };
3003 gf["unsigned short*"] = (cf_t)+[](dims_t d) { return new UShortArrayConverter{d}; };
3004 gf["unsigned short**"] = (cf_t)+[](dims_t d) { return new UShortArrayPtrConverter{d}; };
3005 gf["int*"] = (cf_t)+[](dims_t d) { return new IntArrayConverter{d}; };
3006 gf["int**"] = (cf_t)+[](dims_t d) { return new IntArrayPtrConverter{d}; };
3007 gf["unsigned int*"] = (cf_t)+[](dims_t d) { return new UIntArrayConverter{d}; };
3008 gf["unsigned int**"] = (cf_t)+[](dims_t d) { return new UIntArrayPtrConverter{d}; };
3009 gf["long*"] = (cf_t)+[](dims_t d) { return new LongArrayConverter{d}; };
3010 gf["long**"] = (cf_t)+[](dims_t d) { return new LongArrayPtrConverter{d}; };
3011 gf["unsigned long*"] = (cf_t)+[](dims_t d) { return new ULongArrayConverter{d}; };
3012 gf["unsigned long**"] = (cf_t)+[](dims_t d) { return new ULongArrayPtrConverter{d}; };
3013 gf["long long*"] = (cf_t)+[](dims_t d) { return new LLongArrayConverter{d}; };
3014 gf["long long**"] = (cf_t)+[](dims_t d) { return new LLongArrayPtrConverter{d}; };
3015 gf["unsigned long long*"] = (cf_t)+[](dims_t d) { return new ULLongArrayConverter{d}; };
3016 gf["unsigned long long**"] = (cf_t)+[](dims_t d) { return new ULLongArrayPtrConverter{d}; };
3017 gf["float*"] = (cf_t)+[](dims_t d) { return new FloatArrayConverter{d}; };
3018 gf["float**"] = (cf_t)+[](dims_t d) { return new FloatArrayPtrConverter{d}; };
3019 gf["double*"] = (cf_t)+[](dims_t d) { return new DoubleArrayConverter{d}; };
3020 gf["double**"] = (cf_t)+[](dims_t d) { return new DoubleArrayPtrConverter{d}; };
3021 gf["long double*"] = (cf_t)+[](dims_t d) { return new LDoubleArrayConverter{d}; };
3022 gf["long double**"] = (cf_t)+[](dims_t d) { return new LDoubleArrayPtrConverter{d}; };
3023 gf["std::complex<double>*"] = (cf_t)+[](dims_t d) { return new ComplexDArrayConverter{d}; };
3024 gf["complex<double>*"] = (cf_t)+[](dims_t d) { return new ComplexDArrayConverter{d}; };
3025 gf["std::complex<double>**"] = (cf_t)+[](dims_t d) { return new ComplexDArrayPtrConverter{d}; };
3026 gf["void*"] = (cf_t)+[](dims_t d) { return new VoidArrayConverter{(bool)d}; };
3027
3028 // aliases
3029 gf["signed char"] = gf["char"];
3030 gf["const signed char&"] = gf["const char&"];
3031#if __cplusplus > 201402L
3032 gf["byte"] = gf["uint8_t"];
3033 gf["const byte&"] = gf["const uint8_t&"];
3034 gf["byte&"] = gf["uint8&"];
3035#endif
3036 gf["internal_enum_type_t"] = gf["int"];
3037 gf["internal_enum_type_t&"] = gf["int&"];
3038 gf["const internal_enum_type_t&"] = gf["const int&"];
3039 gf["Long64_t"] = gf["long long"];
3040 gf["Long64_t*"] = gf["long long*"];
3041 gf["Long64_t&"] = gf["long long&"];
3042 gf["const Long64_t&"] = gf["const long long&"];
3043 gf["ULong64_t"] = gf["unsigned long long"];
3044 gf["ULong64_t*"] = gf["unsigned long long*"];
3045 gf["ULong64_t&"] = gf["unsigned long long&"];
3046 gf["const ULong64_t&"] = gf["const unsigned long long&"];
3047 gf["Float16_t"] = gf["float"];
3048 gf["const Float16_t&"] = gf["const float&"];
3049 gf["Double32_t"] = gf["double"];
3050 gf["Double32_t&"] = gf["double&"];
3051 gf["const Double32_t&"] = gf["const double&"];
3052
3053 // factories for special cases
3054 gf["TString"] = (cf_t)+[](dims_t) { return new TStringConverter{}; };
3055 gf["TString&"] = gf["TString"];
3056 gf["const TString&"] = gf["TString"];
3057 gf["nullptr_t"] = (cf_t)+[](dims_t) { static NullptrConverter c{}; return &c;};
3058 gf["const char*"] = (cf_t)+[](dims_t) { return new CStringConverter{}; };
3059 gf["const signed char*"] = gf["const char*"];
3060 gf["const char[]"] = (cf_t)+[](dims_t) { return new CStringConverter{}; };
3061 gf["char*"] = (cf_t)+[](dims_t) { return new NonConstCStringConverter{}; };
3062 gf["signed char*"] = gf["char*"];
3063 gf["wchar_t*"] = (cf_t)+[](dims_t) { return new WCStringConverter{}; };
3064 gf["char16_t*"] = (cf_t)+[](dims_t) { return new CString16Converter{}; };
3065 gf["char32_t*"] = (cf_t)+[](dims_t) { return new CString32Converter{}; };
3066 // TODO: the following are handled incorrectly upstream (char16_t** where char16_t* intended)?!
3067 gf["char16_t**"] = gf["char16_t*"];
3068 gf["char32_t**"] = gf["char32_t*"];
3069 gf["const char**"] = (cf_t)+[](dims_t d) { return new CStringArrayConverter{d}; };
3070 gf["char**"] = gf["const char**"];
3071 gf["const char*[]"] = gf["const char**"];
3072 gf["char*[]"] = gf["const char*[]"];
3073 gf["std::string"] = (cf_t)+[](dims_t) { return new STLStringConverter{}; };
3074 gf["string"] = gf["std::string"];
3075 gf["const std::string&"] = gf["std::string"];
3076 gf["const string&"] = gf["std::string"];
3077 gf["string&&"] = (cf_t)+[](dims_t) { return new STLStringMoveConverter{}; };
3078 gf["std::string&&"] = gf["string&&"];
3079 gf["std::string_view"] = (cf_t)+[](dims_t) { return new STLStringViewConverter{}; };
3080 gf["string_view"] = gf["std::string_view"];
3081 gf[STRINGVIEW] = gf["std::string_view"];
3082 gf["experimental::" STRINGVIEW] = gf["std::string_view"];
3083 gf["std::string_view&"] = gf["std::string_view"];
3084 gf["const string_view&"] = gf["std::string_view"];
3085 gf["const " STRINGVIEW "&"] = gf["std::string_view"];
3086 gf["std::wstring"] = (cf_t)+[](dims_t) { return new STLWStringConverter{}; };
3087 gf[WSTRING] = gf["std::wstring"];
3088 gf["std::" WSTRING] = gf["std::wstring"];
3089 gf["const std::wstring&"] = gf["std::wstring"];
3090 gf["const std::" WSTRING "&"] = gf["std::wstring"];
3091 gf["const " WSTRING "&"] = gf["std::wstring"];
3092 gf["void*&"] = (cf_t)+[](dims_t) { static VoidPtrRefConverter c{}; return &c; };
3093 gf["void**"] = (cf_t)+[](dims_t d) { return new VoidPtrPtrConverter{size_t((d && d[0] != -1) ? d[1] : -1)}; };
3094 gf["void*[]"] = (cf_t)+[](dims_t d) { return new VoidPtrPtrConverter{size_t((d && d[0] != -1) ? d[1] : -1)}; };
3095 gf["PyObject*"] = (cf_t)+[](dims_t) { static PyObjectConverter c{}; return &c; };
3096 gf["_object*"] = gf["PyObject*"];
3097 gf["FILE*"] = (cf_t)+[](dims_t) { return new VoidArrayConverter{}; };
3098 }
3099} initConvFactories_;
3100
3101} // unnamed namespace
#define Py_TYPE(ob)
Definition CPyCppyy.h:217
static Py_ssize_t CPyCppyy_PyUnicode_AsWideChar(PyObject *pyobj, wchar_t *w, Py_ssize_t size)
Definition CPyCppyy.h:222
#define PyBytes_AS_STRING
Definition CPyCppyy.h:85
#define CPyCppyy_PyText_FromStringAndSize
Definition CPyCppyy.h:106
#define CPyCppyy_PyUnicode_GET_SIZE
Definition CPyCppyy.h:117
#define PY_SSIZE_T_FORMAT
Definition CPyCppyy.h:239
#define PyBytes_Check
Definition CPyCppyy.h:83
static void * CPyCppyy_PyCapsule_GetPointer(PyObject *capsule, const char *)
Definition CPyCppyy.h:125
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:97
#define CPyCppyy_PyText_GET_SIZE
Definition CPyCppyy.h:99
#define CPyCppyy_PyCapsule_CheckExact
Definition CPyCppyy.h:124
#define Py_RETURN_NONE
Definition CPyCppyy.h:289
static const char * CPyCppyy_PyText_AsStringAndSize(PyObject *pystr, Py_ssize_t *size)
Definition CPyCppyy.h:108
#define CPyCppyy_PyText_FromString
Definition CPyCppyy.h:102
#define CPyCppyy_PyText_Check
Definition CPyCppyy.h:95
static std::array< PyTypeObject *, NTYPES > gCTypesPtrTypes
c_uint8
static const char * FPCFM_ERRMSG
#define CPPYY_IMPL_BASIC_CONVERTER(name, type, stype, ctype, F1, F2, tc)
#define CPPYY_IMPL_ARRAY_CONVERTER(name, ctype, type, code)
static bool ConvertImplicit(Cppyy::TCppType_t klass, PyObject *pyobject, CPyCppyy::Parameter &para, CPyCppyy::CallContext *ctxt)
static std::map< void *, PyObject ** > sWrapperReference
static bool CPyCppyy_PyLong_AsBool(PyObject *pyobject)
static bool IsPyCArgObject(PyObject *pyobject)
static PyObject * WrapperCacheEraser(PyObject *, PyObject *pyref)
#define CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(name, type, F1, F2)
#define CPPYY_IMPL_BASIC_CHAR_CONVERTER(name, type, low, high)
const size_t MOVE_REFCOUNT_CUTOFF
static std::array< PyTypeObject *, NTYPES > gCTypesTypes
#define ct_c_long
CPyCppyy_PyLong_AsUInt8
static char CPyCppyy_PyText_AsChar(PyObject *pyobject)
#define CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(name, type, ctype, low, high)
static bool SetLifeLine(PyObject *holder, PyObject *target, intptr_t ref)
static std::map< RetSigKey_t, std::map< PyObject *, void * > > sWrapperLookup
PyFloat_FromDouble
static int ExtractChar(PyObject *pyobject, const char *tname, int low, int high)
static void init_shape(Py_ssize_t defdim, dims_t dims, Py_ssize_t *&shape)
static PyTypeObject * GetCTypesPtrType(int nidx)
static std::map< PyObject *, std::pair< void *, RetSigKey_t > > sWrapperWeakRefs
#define ct_c_char_p
#define ct_c_int
static int8_t CPyCppyy_PyLong_AsInt8(PyObject *pyobject)
PyFloat_AsDouble
std::pair< std::string, std::string > RetSigKey_t
static PyMethodDef gWrapperCacheEraserMethodDef
#define CPPYY_IMPL_BASIC_CONST_REFCONVERTER(name, type, ctype, F1)
l unsigned CPyCppyy_PyLong_AsUShort
static CPyCppyy::Converter * selectInstanceCnv(Cppyy::TCppScope_t klass, const std::string &cpd, long size, dims_t dims, bool isConst, bool control)
static std::map< void *, std::string > sFuncWrapperLookup
static short CPyCppyy_PyLong_AsShort(PyObject *pyobject)
static long CPyCppyy_PyLong_AsStrictLong(PyObject *pyobject)
static CPyCppyy::CPPInstance * GetCppInstance(PyObject *pyobject)
PyInt_FromLong
#define WSTRING
#define UNKNOWN_ARRAY_SIZE
l unsigned c_ushort
#define CPPYY_IMPL_REFCONVERTER(name, ctype, type, code)
long
static PyTypeObject * GetCTypesType(int nidx)
uint8_t
#define ct_c_void_p
#define UNKNOWN_SIZE
static std::array< const char *, NTYPES > gCTypesNames
static bool CArraySetArg(PyObject *pyobject, CPyCppyy::Parameter &para, char tc, int size)
static int CPyCppyy_PyLong_AsStrictInt(PyObject *pyobject)
c_double
static std::map< RetSigKey_t, std::vector< void * > > sWrapperFree
static bool IsCTypesArrayOrPointer(PyObject *pyobject)
static unsigned int sWrapperCounter
#define STRINGVIEW
static void * PyFunction_AsCPointer(PyObject *pyobject, const std::string &rettype, const std::string &signature)
#define CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(name, ctype)
std::string fRetType
size_t fSize
long fMaxSize
size_t fValueSize
bool fIsConst
std::string fBuffer
bool fKeepControl
bool fIsRef
PyObject * fFuncWrap
Cppyy::TCppType_t fClass
dims_t m_dims
Cppyy::TCppType_t fSmartPtrType
std::string fSignature
Cppyy::TCppType_t fUnderlyingType
Converter * fConverter
_object PyObject
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define g(i)
Definition RSha256.hxx:105
#define h(i)
Definition RSha256.hxx:106
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
unsigned int UInt_t
Definition RtypesCore.h:46
unsigned long ULong_t
Definition RtypesCore.h:55
long double LongDouble_t
Definition RtypesCore.h:61
long long Long64_t
Definition RtypesCore.h:80
unsigned long long ULong64_t
Definition RtypesCore.h:81
char name[80]
Definition TGX11.cxx:110
float * q
#define CPYCPPYY_EXPORT
Definition CommonDefs.h:25
#define realloc
Definition civetweb.c:1538
#define free
Definition civetweb.c:1539
#define malloc
Definition civetweb.c:1536
Cppyy::TCppType_t GetSmartIsA() const
bool IsSmart() const
Definition CPPInstance.h:56
Cppyy::TCppType_t ObjectIsA(bool check_smart=true) const
MethodInfo_t * fMethodInfo
Definition CPPOverload.h:68
virtual bool SetArg(PyObject *, Parameter &, CallContext *=nullptr)=0
virtual bool HasState()
Definition API.h:105
virtual bool ToMemory(PyObject *value, void *address, PyObject *ctxt=nullptr)
virtual PyObject * FromMemory(void *address)
virtual bool SetArg(PyObject *, Parameter &, CallContext *=nullptr)
virtual PyObject * FromMemory(void *address)
virtual bool ToMemory(PyObject *value, void *address, PyObject *ctxt=nullptr)
static bool RegisterPyObject(CPPInstance *pyobj, void *cppobj)
virtual bool GetAddressSpecialCase(PyObject *pyobject, void *&address)
virtual bool ToMemory(PyObject *value, void *address, PyObject *ctxt=nullptr)
virtual PyObject * FromMemory(void *address)
virtual bool SetArg(PyObject *, Parameter &, CallContext *=nullptr)
Basic string class.
Definition TString.h:136
#define I(x, y, z)
#define H(x, y, z)
PyObject * gNoImplicit
Definition PyStrings.cxx:55
PyObject * gEmptyString
Definition PyStrings.cxx:15
std::string remove_const(const std::string &cppname)
Definition TypeManip.cxx:71
std::string clean_type(const std::string &cppname, bool template_strip=true, bool const_strip=true)
Definition TypeManip.cxx:98
std::vector< std::string > extract_arg_types(const std::string &sig)
void ConstructCallbackPreamble(const std::string &retType, const std::vector< std::string > &argtypes, std::ostringstream &code)
Definition Utility.cxx:517
void ConstructCallbackReturn(const std::string &retType, int nArgs, std::ostringstream &code)
Definition Utility.cxx:561
Py_ssize_t GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, bool check=true)
Definition Utility.cxx:614
const std::string Compound(const std::string &name)
Definition Utility.cxx:782
Set of helper functions that are invoked from the pythonizors, on the Python side.
unsigned long PyLongOrInt_AsULong(PyObject *pyobject)
Definition Utility.cxx:130
bool TupleOfInstances_CheckExact(T *object)
PyObject * CreatePointerView(void *ptr, size_t size=(size_t) -1)
bool RefFloat_CheckExact(T *object)
bool CPPExcInstance_Check(T *object)
bool NoImplicit(CallContext *ctxt)
PyObject * CreateLowLevelView(const char **, Py_ssize_t *shape=nullptr)
static ConvFactories_t gConvFactories
PyObject * BindCppObjectNoCast(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
bool CPPOverload_Check(T *object)
Definition CPPOverload.h:79
bool RefInt_CheckExact(T *object)
bool CPPScope_Check(T *object)
Definition CPPScope.h:76
CPYCPPYY_EXTERN bool RegisterConverter(const std::string &name, ConverterFactory_t)
bool AllowImplicit(CallContext *ctxt)
bool UseStrictOwnership(CallContext *ctxt)
bool CPPInstance_Check(T *object)
PyObject * CreateScopeProxy(Cppyy::TCppScope_t)
Converter *(* cf_t)(dims_t d)
Definition Converters.h:27
PyObject * gNullPtrObject
bool IsConstructor(uint64_t flags)
PyObject * BindCppObject(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
ULong64_t PyLongOrInt_AsULong64(PyObject *pyobject)
Definition Utility.cxx:150
CPYCPPYY_EXTERN void DestroyConverter(Converter *p)
bool TemplateProxy_Check(T *object)
std::map< std::string, cf_t > ConvFactories_t
PyObject * BindCppObjectArray(Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Py_ssize_t *dims)
CPYCPPYY_EXTERN bool UnregisterConverter(const std::string &name)
CPYCPPYY_EXTERN Converter * CreateConverter(const std::string &name, Py_ssize_t *dims=nullptr)
RPY_EXPORTED std::vector< TCppIndex_t > GetMethodIndicesFromName(TCppScope_t scope, const std::string &name)
RPY_EXPORTED bool Compile(const std::string &code)
RPY_EXPORTED ptrdiff_t GetBaseOffset(TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror=false)
intptr_t TCppMethod_t
Definition cpp_cppyy.h:22
RPY_EXPORTED bool GetSmartPtrInfo(const std::string &, TCppType_t *raw, TCppMethod_t *deref)
void * TCppObject_t
Definition cpp_cppyy.h:21
TCppScope_t TCppType_t
Definition cpp_cppyy.h:19
RPY_EXPORTED TCppMethod_t GetMethodTemplate(TCppScope_t scope, const std::string &name, const std::string &proto)
RPY_EXPORTED TCppMethod_t GetMethod(TCppScope_t scope, TCppIndex_t imeth)
RPY_EXPORTED bool IsSubtype(TCppType_t derived, TCppType_t base)
size_t TCppScope_t
Definition cpp_cppyy.h:18
RPY_EXPORTED std::string ResolveName(const std::string &cppitem_name)
RPY_EXPORTED TCppFuncAddr_t GetFunctionAddress(TCppMethod_t method, bool check_enabled=true)
RPY_EXPORTED size_t SizeOf(TCppType_t klass)
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
RooArgList L(Args_t &&... args)
Definition RooArgList.h:156
Definition first.py:1
CPPOverload::Methods_t fMethods
Definition CPPOverload.h:47
static ECallFlags sMemoryPolicy
Definition CallContext.h:71
Cppyy::TCppScope_t fCurScope
Definition CallContext.h:99
void AddTemporary(PyObject *pyobj)
union CPyCppyy::Parameter::Value fValue
PyObject_HEAD char * b_ptr
PyObject_HEAD void * pffi_type
union CPyCppyy_tagPyCArgObject::@217 value
auto * m
Definition textangle.C:8
auto * l
Definition textangle.C:4
unsigned long long fULLong
Definition callcontext.h:26