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