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