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, fBuffer)) { \
1861 para.fValue.fVoidp = &fBuffer; \
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
1895
1896CPyCppyy::STLWStringConverter::STLWStringConverter(bool keepControl) :
1897 InstanceConverter(Cppyy::GetScope("std::wstring"), keepControl) {}
1898
1899bool CPyCppyy::STLWStringConverter::SetArg(
1900 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1901{
1902 if (PyUnicode_Check(pyobject)) {
1904 fBuffer.resize(len);
1906 para.fValue.fVoidp = &fBuffer;
1907 para.fTypeCode = 'V';
1908 return true;
1909 }
1910#if PY_VERSION_HEX < 0x03000000
1911 else if (PyString_Check(pyobject)) {
1912#ifdef HAS_CODECVT
1913 std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cnv;
1914 fBuffer = cnv.from_bytes(PyString_AS_STRING(pyobject));
1915#else
1916 PyObject* pyu = PyUnicode_FromString(PyString_AS_STRING(pyobject));
1917 if (!pyu) return false;
1919 fBuffer.resize(len);
1921#endif
1922 para.fValue.fVoidp = &fBuffer;
1923 para.fTypeCode = 'V';
1924 return true;
1925 }
1926#endif
1927
1928 if (!(PyInt_Check(pyobject) || PyLong_Check(pyobject))) {
1929 bool result = InstancePtrConverter<false>::SetArg(pyobject, para, ctxt);
1930 para.fTypeCode = 'V';
1931 return result;
1932 }
1933
1934 return false;
1935}
1936
1937PyObject* CPyCppyy::STLWStringConverter::FromMemory(void* address)
1938{
1939 if (address)
1940 return PyUnicode_FromWideChar(((std::wstring*)address)->c_str(), ((std::wstring*)address)->size());
1941 wchar_t w = L'\0';
1942 return PyUnicode_FromWideChar(&w, 0);
1943}
1944
1945bool CPyCppyy::STLWStringConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt)
1946{
1947 if (PyUnicode_Check(value)) {
1949 wchar_t* buf = new wchar_t[len+1];
1951 *((std::wstring*)address) = std::wstring(buf, len);
1952 delete[] buf;
1953 return true;
1954 }
1955 return InstanceConverter::ToMemory(value, address, ctxt);
1956}
1957
1958
1959#if __cplusplus > 201402L
1960CPyCppyy::STLStringViewConverter::STLStringViewConverter(bool keepControl) :
1961 InstanceConverter(Cppyy::GetScope("std::string_view"), keepControl) {}
1962
1963bool CPyCppyy::STLStringViewConverter::SetArg(
1964 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1965{
1966// normal instance convertion (eg. string_view object passed)
1967 if (!PyInt_Check(pyobject) && !PyLong_Check(pyobject)) {
1969 if (InstanceConverter::SetArg(pyobject, para, ctxt)) {
1970 para.fTypeCode = 'V';
1971 return true;
1972 } else
1973 PyErr_Clear();
1974 }
1975
1976// passing of a Python string; buffering done Python-side b/c str is immutable
1978 const char* cstr = CPyCppyy_PyText_AsStringAndSize(pyobject, &len);
1979 if (cstr) {
1980 SetLifeLine(ctxt->fPyContext, pyobject, (intptr_t)this);
1981 fBuffer = std::string_view(cstr, (std::string_view::size_type)len);
1982 para.fValue.fVoidp = &fBuffer;
1983 para.fTypeCode = 'V';
1984 return true;
1985 }
1986
1987 if (!CPPInstance_Check(pyobject))
1988 return false;
1989
1990// special case of a C++ std::string object; life-time management is left to
1991// the caller to ensure any external changes propagate correctly
1992 if (CPPInstance_Check(pyobject)) {
1993 static Cppyy::TCppScope_t sStringID = Cppyy::GetScope("std::string");
1994 CPPInstance* pyobj = (CPPInstance*)pyobject;
1995 if (pyobj->ObjectIsA() == sStringID) {
1996 void* ptr = pyobj->GetObject();
1997 if (!ptr)
1998 return false; // leaves prior conversion error for report
1999
2000 PyErr_Clear();
2001
2002 fBuffer = *((std::string*)ptr);
2003 para.fValue.fVoidp = &fBuffer;
2004 para.fTypeCode = 'V';
2005 return true;
2006 }
2007 }
2008
2009 return false;
2010}
2011
2012PyObject* CPyCppyy::STLStringViewConverter::FromMemory(void* address)
2013{
2014 if (address)
2015 return InstanceConverter::FromMemory(address);
2016 auto* empty = new std::string_view();
2018}
2019
2020bool CPyCppyy::STLStringViewConverter::ToMemory(
2021 PyObject* value, void* address, PyObject* ctxt)
2022{
2023// common case of simple object assignment
2024 if (InstanceConverter::ToMemory(value, address, ctxt))
2025 return true;
2026
2027// assignment of a Python string; buffering done Python-side b/c str is immutable
2029 const char* cstr = CPyCppyy_PyText_AsStringAndSize(value, &len);
2030 if (cstr) {
2031 SetLifeLine(ctxt, value, (intptr_t)this);
2032 *reinterpret_cast<std::string_view*>(address) = \
2033 std::string_view(cstr, (std::string_view::size_type)len);
2034 return true;
2035 }
2036
2037 return false;
2038}
2039#endif
2040
2041
2042bool CPyCppyy::STLStringMoveConverter::SetArg(
2043 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2044{
2045// convert <pyobject> to C++ std::string&&, set arg for call
2046 int moveit_reason = 3; // move on temporary fBuffer
2047 if (CPPInstance_Check(pyobject)) {
2048 CPPInstance* pyobj = (CPPInstance*)pyobject;
2049 if (pyobj->fFlags & CPPInstance::kIsRValue) {
2050 pyobj->fFlags &= ~CPPInstance::kIsRValue;
2051 moveit_reason = 2;
2052 } else if (pyobject->ob_refcnt <= MOVE_REFCOUNT_CUTOFF) {
2053 moveit_reason = 1;
2054 } else
2055 moveit_reason = 0;
2056 }
2057
2058 if (moveit_reason) {
2059 bool result = this->STLStringConverter::SetArg(pyobject, para, ctxt);
2060 if (!result && moveit_reason == 2) // restore the movability flag?
2061 ((CPPInstance*)pyobject)->fFlags |= CPPInstance::kIsRValue;
2062 return result;
2063 }
2064
2065 PyErr_SetString(PyExc_ValueError, "object is not an rvalue");
2066 return false; // not a temporary or movable object
2067}
2068
2069
2070//----------------------------------------------------------------------------
2071template <bool ISCONST>
2073 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2074{
2075// convert <pyobject> to C++ instance*, set arg for call
2076 CPPInstance* pyobj = GetCppInstance(pyobject, ISCONST ? fClass : (Cppyy::TCppType_t)0);
2077 if (!pyobj) {
2078 if (GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) {
2079 para.fTypeCode = 'p'; // allow special cases such as nullptr
2080 return true;
2081 }
2082
2083 // not a cppyy object (TODO: handle SWIG etc.)
2084 return false;
2085 }
2086
2087 // smart pointers should only extract the pointer if this is NOT an implicit
2088 // conversion to another smart pointer
2089 if (pyobj->IsSmart() && IsConstructor(ctxt->fFlags) && Cppyy::IsSmartPtr(ctxt->fCurScope))
2090 return false;
2091
2092 Cppyy::TCppType_t oisa = pyobj->ObjectIsA();
2093 if (oisa && (oisa == fClass || Cppyy::IsSubtype(oisa, fClass))) {
2094 // depending on memory policy, some objects need releasing when passed into functions
2095 if (!KeepControl() && !UseStrictOwnership(ctxt))
2096 pyobj->CppOwns();
2097
2098 // calculate offset between formal and actual arguments
2099 para.fValue.fVoidp = pyobj->GetObject();
2100 if (oisa != fClass) {
2102 oisa, fClass, para.fValue.fVoidp, 1 /* up-cast */);
2103 }
2104
2105 // set pointer (may be null) and declare success
2106 para.fTypeCode = 'p';
2107 return true;
2108 }
2109
2110 return false;
2111}
2112
2113//----------------------------------------------------------------------------
2114template <bool ISCONST>
2116{
2117// construct python object from C++ instance read at <address>
2118 if (ISCONST)
2119 return BindCppObject(*(void**)address, fClass); // by pointer value
2120 return BindCppObject(address, fClass, CPPInstance::kIsReference); // modifiable
2121}
2122
2123//----------------------------------------------------------------------------
2124template <bool ISCONST>
2126{
2127// convert <value> to C++ instance, write it at <address>
2128 CPPInstance* pyobj = GetCppInstance(value, ISCONST ? fClass : (Cppyy::TCppType_t)0);
2129 if (!pyobj) {
2130 void* ptr = nullptr;
2131 if (GetAddressSpecialCase(value, ptr)) {
2132 *(void**)address = ptr; // allow special cases such as nullptr
2133 return true;
2134 }
2135
2136 // not a cppyy object (TODO: handle SWIG etc.)
2137 return false;
2138 }
2139
2140 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
2141 // depending on memory policy, some objects need releasing when passed into functions
2142 if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict)
2143 ((CPPInstance*)value)->CppOwns();
2144
2145 *(void**)address = pyobj->GetObject();
2146 return true;
2147 }
2148
2149 return false;
2150}
2151
2152// TODO: CONSOLIDATE Instance, InstanceRef, InstancePtr ...
2153
2154//----------------------------------------------------------------------------
2155bool CPyCppyy::InstanceConverter::SetArg(
2156 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2157{
2158// convert <pyobject> to C++ instance, set arg for call
2159 CPPInstance* pyobj = GetCppInstance(pyobject, fClass);
2160 if (pyobj) {
2161 auto oisa = pyobj->ObjectIsA();
2162 if (oisa && (oisa == fClass || Cppyy::IsSubtype(oisa, fClass))) {
2163 // calculate offset between formal and actual arguments
2164 para.fValue.fVoidp = pyobj->GetObject();
2165 if (!para.fValue.fVoidp)
2166 return false;
2167
2168 if (oisa != fClass) {
2170 pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */);
2171 }
2172
2173 para.fTypeCode = 'V';
2174 return true;
2175 }
2176 }
2177
2178 return (bool)ConvertImplicit(fClass, pyobject, para, ctxt);
2179}
2180
2181//----------------------------------------------------------------------------
2182PyObject* CPyCppyy::InstanceConverter::FromMemory(void* address)
2183{
2184// This should not need a cast (ie. BindCppObjectNoCast), but performing the cast
2185// here means callbacks receive down-casted object when passed by-ptr, which is
2186// needed for object identity. The latter case is assumed to be more common than
2187// conversion of (global) objects.
2188 return BindCppObject((Cppyy::TCppObject_t)address, fClass);
2189}
2190
2191//----------------------------------------------------------------------------
2192bool CPyCppyy::InstanceConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
2193{
2194// assign value to C++ instance living at <address> through assignment operator
2195 PyObject* pyobj = BindCppObjectNoCast(address, fClass);
2196 PyObject* result = PyObject_CallMethod(pyobj, (char*)"__assign__", (char*)"O", value);
2197 Py_DECREF(pyobj);
2198
2199 if (result) {
2200 Py_DECREF(result);
2201 return true;
2202 }
2203 return false;
2204}
2205
2206
2207//----------------------------------------------------------------------------
2208bool CPyCppyy::InstanceRefConverter::SetArg(
2209 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2210{
2211// convert <pyobject> to C++ instance&, set arg for call
2212 CPPInstance* pyobj = GetCppInstance(pyobject, fIsConst ? fClass : (Cppyy::TCppType_t)0);
2213 if (pyobj) {
2214
2215 // reject moves
2216 if (pyobj->fFlags & CPPInstance::kIsRValue)
2217 return false;
2218
2219 // smart pointers can end up here in case of a move, so preferentially match
2220 // the smart type directly
2221 bool argset = false;
2222 Cppyy::TCppType_t cls = 0;
2223 if (pyobj->IsSmart()) {
2224 cls = pyobj->ObjectIsA(false);
2225 if (cls && Cppyy::IsSubtype(cls, fClass)) {
2226 para.fValue.fVoidp = pyobj->GetObjectRaw();
2227 argset = true;
2228 }
2229 }
2230
2231 if (!argset) {
2232 cls = pyobj->ObjectIsA();
2233 if (cls && Cppyy::IsSubtype(cls, fClass)) {
2234 para.fValue.fVoidp = pyobj->GetObject();
2235 argset = true;
2236 }
2237 }
2238
2239 if (argset) {
2240 // do not allow null pointers through references
2241 if (!para.fValue.fVoidp) {
2242 PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer");
2243 return false;
2244 }
2245
2246 // calculate offset between formal and actual arguments
2247 if (cls != fClass) {
2249 cls, fClass, para.fValue.fVoidp, 1 /* up-cast */);
2250 }
2251
2252 para.fTypeCode = 'V';
2253 return true;
2254 }
2255 }
2256
2257 if (!fIsConst) // no implicit conversion possible
2258 return false;
2259
2260 return (bool)ConvertImplicit(fClass, pyobject, para, ctxt);
2261}
2262
2263//----------------------------------------------------------------------------
2264PyObject* CPyCppyy::InstanceRefConverter::FromMemory(void* address)
2265{
2267}
2268
2269//----------------------------------------------------------------------------
2270bool CPyCppyy::InstanceMoveConverter::SetArg(
2271 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2272{
2273// convert <pyobject> to C++ instance&&, set arg for call
2274 CPPInstance* pyobj = GetCppInstance(pyobject, fClass, true /* accept_rvalue */);
2275 if (!pyobj || (pyobj->fFlags & CPPInstance::kIsLValue)) {
2276 // implicit conversion is fine as the temporary by definition is moveable
2277 return (bool)ConvertImplicit(fClass, pyobject, para, ctxt);
2278 }
2279
2280// moving is same as by-ref, but have to check that move is allowed
2281 int moveit_reason = 0;
2282 if (pyobj->fFlags & CPPInstance::kIsRValue) {
2283 pyobj->fFlags &= ~CPPInstance::kIsRValue;
2284 moveit_reason = 2;
2285 } else if (pyobject->ob_refcnt <= MOVE_REFCOUNT_CUTOFF) {
2286 moveit_reason = 1;
2287 }
2288
2289 if (moveit_reason) {
2290 bool result = this->InstanceRefConverter::SetArg(pyobject, para, ctxt);
2291 if (!result && moveit_reason == 2) // restore the movability flag?
2292 ((CPPInstance*)pyobject)->fFlags |= CPPInstance::kIsRValue;
2293 return result;
2294 }
2295
2296 PyErr_SetString(PyExc_ValueError, "object is not an rvalue");
2297 return false; // not a temporary or movable object
2298}
2299
2300//----------------------------------------------------------------------------
2301template <bool ISREFERENCE>
2302bool CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::SetArg(
2303 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2304{
2305// convert <pyobject> to C++ instance**, set arg for call
2306 CPPInstance* pyobj = GetCppInstance(pyobject);
2307 if (!pyobj) {
2308 if (!ISREFERENCE && (pyobject == gNullPtrObject || pyobject == gDefaultObject)) {
2309 // allow nullptr as a special case
2310 para.fValue.fVoidp = nullptr;
2311 para.fTypeCode = 'p';
2312 return true;
2313 }
2314 return false; // not a cppyy object (TODO: handle SWIG etc.)
2315 }
2316
2317 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
2318 // depending on memory policy, some objects need releasing when passed into functions
2319 if (!KeepControl() && !UseStrictOwnership(ctxt))
2320 pyobj->CppOwns();
2321
2322 // set pointer (may be null) and declare success
2323 if (pyobj->fFlags & CPPInstance::kIsReference) // already a ptr to object?
2324 para.fValue.fVoidp = pyobj->GetObjectRaw();
2325 else
2326 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2327 para.fTypeCode = ISREFERENCE ? 'V' : 'p';
2328 return true;
2329 }
2330
2331 return false;
2332}
2333
2334//----------------------------------------------------------------------------
2335template <bool ISREFERENCE>
2336PyObject* CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::FromMemory(void* address)
2337{
2338// construct python object from C++ instance* read at <address>
2340}
2341
2342//----------------------------------------------------------------------------
2343template <bool ISREFERENCE>
2344bool CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::ToMemory(
2345 PyObject* value, void* address, PyObject* /* ctxt */)
2346{
2347// convert <value> to C++ instance*, write it at <address>
2349 if (!pyobj) {
2351 // allow nullptr as a special case
2352 *(void**)address = nullptr;
2353 return true;
2354 }
2355 return false; // not a cppyy object (TODO: handle SWIG etc.)
2356 }
2357
2358 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
2359 // depending on memory policy, some objects need releasing when passed into functions
2360 if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict)
2361 pyobj->CppOwns();
2362
2363 // register the value for potential recycling
2365
2366 // set pointer (may be null) and declare success
2367 *(void**)address = pyobj->GetObject();
2368 return true;
2369 }
2370
2371 return false;
2372}
2373
2374
2375namespace CPyCppyy {
2376// Instantiate the templates
2379 template class CPyCppyy::InstancePtrPtrConverter<true>;
2380 template class CPyCppyy::InstancePtrPtrConverter<false>;
2381}
2382
2383//----------------------------------------------------------------------------
2384bool CPyCppyy::InstanceArrayConverter::SetArg(
2385 PyObject* pyobject, Parameter& para, CallContext* /* txt */)
2386{
2387// convert <pyobject> to C++ instance**, set arg for call
2388 if (!TupleOfInstances_CheckExact(pyobject))
2389 return false; // no guarantee that the tuple is okay
2390
2391// treat the first instance of the tuple as the start of the array, and pass it
2392// by pointer (TODO: store and check sizes)
2393 if (PyTuple_Size(pyobject) < 1)
2394 return false;
2395
2396 PyObject* first = PyTuple_GetItem(pyobject, 0);
2397 if (!CPPInstance_Check(first))
2398 return false; // should not happen
2399
2400 if (Cppyy::IsSubtype(((CPPInstance*)first)->ObjectIsA(), fClass)) {
2401 // no memory policies supported; set pointer (may be null) and declare success
2402 para.fValue.fVoidp = ((CPPInstance*)first)->GetObject();
2403 para.fTypeCode = 'p';
2404 return true;
2405 }
2406
2407 return false;
2408}
2409
2410//----------------------------------------------------------------------------
2411PyObject* CPyCppyy::InstanceArrayConverter::FromMemory(void* address)
2412{
2413// construct python tuple of instances from C++ array read at <address>
2414 return BindCppObjectArray(*(char**)address, fClass, fShape);
2415}
2416
2417//----------------------------------------------------------------------------
2418bool CPyCppyy::InstanceArrayConverter::ToMemory(
2419 PyObject* /* value */, void* /* address */, PyObject* /* ctxt */)
2420{
2421// convert <value> to C++ array of instances, write it at <address>
2422
2423// TODO: need to have size both for the array and from the input
2424 PyErr_SetString(PyExc_NotImplementedError,
2425 "access to C-arrays of objects not yet implemented!");
2426 return false;
2427}
2428
2429//___________________________________________________________________________
2430// CLING WORKAROUND -- classes for STL iterators are completely undefined in that
2431// they come in a bazillion different guises, so just do whatever
2432bool CPyCppyy::STLIteratorConverter::SetArg(
2433 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2434{
2435 if (!CPPInstance_Check(pyobject))
2436 return false;
2437
2438// just set the pointer value, no check
2439 CPPInstance* pyobj = (CPPInstance*)pyobject;
2440 para.fValue.fVoidp = pyobj->GetObject();
2441 para.fTypeCode = 'V';
2442 return true;
2443}
2444// -- END CLING WORKAROUND
2445
2446//----------------------------------------------------------------------------
2447bool CPyCppyy::VoidPtrRefConverter::SetArg(
2448 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2449{
2450// convert <pyobject> to C++ void*&, set arg for call
2451 CPPInstance* pyobj = GetCppInstance(pyobject);
2452 if (pyobj) {
2453 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2454 para.fTypeCode = 'V';
2455 return true;
2456 }
2457
2458 return false;
2459}
2460
2461//----------------------------------------------------------------------------
2462CPyCppyy::VoidPtrPtrConverter::VoidPtrPtrConverter(cdims_t dims) :
2463 fShape(dims) {
2464 fIsFixed = dims ? fShape[0] != UNKNOWN_SIZE : false;
2465}
2466
2467//----------------------------------------------------------------------------
2468bool CPyCppyy::VoidPtrPtrConverter::SetArg(
2469 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2470{
2471// convert <pyobject> to C++ void**, set arg for call
2472 CPPInstance* pyobj = GetCppInstance(pyobject);
2473 if (pyobj) {
2474 // this is a C++ object, take and set its address
2475 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2476 para.fTypeCode = 'p';
2477 return true;
2478 } else if (IsPyCArgObject(pyobject)) {
2480 if (carg->obj) {
2481 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)carg->obj)->b_ptr;
2482 para.fTypeCode = 'p';
2483 return true;
2484 }
2485 }
2486
2487// buffer objects are allowed under "user knows best" (this includes the buffer
2488// interface to ctypes.c_void_p, which results in a void**)
2489 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', 1, para.fValue.fVoidp, false);
2490
2491// ok if buffer exists (can't perform any useful size checks)
2492 if (para.fValue.fVoidp && buflen != 0) {
2493 para.fTypeCode = 'p';
2494 return true;
2495 }
2496
2497 return false;
2498}
2499
2500//----------------------------------------------------------------------------
2501PyObject* CPyCppyy::VoidPtrPtrConverter::FromMemory(void* address)
2502{
2503// read a void** from address; since this is unknown, uintptr_t is used (user can cast)
2504 if (!address || *(ptrdiff_t*)address == 0) {
2505 Py_INCREF(gNullPtrObject);
2506 return gNullPtrObject;
2507 }
2508 if (!fIsFixed)
2509 return CreatePointerView((uintptr_t**)address, fShape);
2510 return CreatePointerView(*(uintptr_t**)address, fShape);
2511}
2512
2513//----------------------------------------------------------------------------
2514bool CPyCppyy::PyObjectConverter::SetArg(
2515 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2516{
2517// by definition: set and declare success
2518 para.fValue.fVoidp = pyobject;
2519 para.fTypeCode = 'p';
2520 return true;
2521}
2522
2523PyObject* CPyCppyy::PyObjectConverter::FromMemory(void* address)
2524{
2525// construct python object from C++ PyObject* read at <address>
2526 PyObject* pyobject = *((PyObject**)address);
2527
2528 if (!pyobject) {
2530 }
2531
2532 Py_INCREF(pyobject);
2533 return pyobject;
2534}
2535
2536bool CPyCppyy::PyObjectConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
2537{
2538// no conversion needed, write <value> at <address>
2539 Py_INCREF(value);
2540 Py_XDECREF(*((PyObject**)address));
2541 *((PyObject**)address) = value;
2542 return true;
2543}
2544
2545
2546//- function pointer converter -----------------------------------------------
2547static unsigned int sWrapperCounter = 0;
2548// cache mapping signature/return type to python callable and corresponding wrapper
2549typedef std::string RetSigKey_t;
2550static std::map<RetSigKey_t, std::vector<void*>> sWrapperFree;
2551static std::map<RetSigKey_t, std::map<PyObject*, void*>> sWrapperLookup;
2552static std::map<PyObject*, std::pair<void*, RetSigKey_t>> sWrapperWeakRefs;
2553static std::map<void*, PyObject**> sWrapperReference;
2554
2556{
2557 auto ipos = sWrapperWeakRefs.find(pyref);
2558 if (ipos != sWrapperWeakRefs.end()) {
2559 auto key = ipos->second.second;
2560
2561 // disable this callback and store on free list for possible re-use
2562 void* wpraddress = ipos->second.first;
2563 PyObject** oldref = sWrapperReference[wpraddress];
2564 const auto& lookup = sWrapperLookup.find(key);
2565 if (lookup != sWrapperLookup.end()) lookup->second.erase(*oldref);
2566 *oldref = nullptr; // to detect deletions
2567 sWrapperFree[ipos->second.second].push_back(wpraddress);
2568
2569 // clean up and remove weak reference from admin
2570 Py_DECREF(ipos->first);
2571 sWrapperWeakRefs.erase(ipos);
2572 }
2573
2575}
2576static PyMethodDef gWrapperCacheEraserMethodDef = {
2577 const_cast<char*>("internal_WrapperCacheEraser"),
2578 (PyCFunction)WrapperCacheEraser,
2579 METH_O, nullptr
2580};
2581
2582static void* PyFunction_AsCPointer(PyObject* pyobject,
2583 const std::string& rettype, const std::string& signature)
2584{
2585// Convert a bound C++ function pointer or callable python object to a C-style
2586// function pointer. The former is direct, the latter involves a JIT-ed wrapper.
2587 static PyObject* sWrapperCacheEraser = PyCFunction_New(&gWrapperCacheEraserMethodDef, nullptr);
2588
2589 using namespace CPyCppyy;
2590
2591 if (CPPOverload_Check(pyobject)) {
2592 CPPOverload* ol = (CPPOverload*)pyobject;
2593 if (!ol->fMethodInfo || ol->fMethodInfo->fMethods.empty())
2594 return nullptr;
2595
2596 // find the overload with matching signature
2597 for (auto& m : ol->fMethodInfo->fMethods) {
2598 PyObject* sig = m->GetSignature(false);
2599 bool found = signature == CPyCppyy_PyText_AsString(sig);
2600 Py_DECREF(sig);
2601 if (found) {
2602 void* fptr = (void*)m->GetFunctionAddress();
2603 if (fptr) return fptr;
2604 break; // fall-through, with calling through Python
2605 }
2606 }
2607 }
2608
2609 if (TemplateProxy_Check(pyobject)) {
2610 // get the actual underlying template matching the signature
2611 TemplateProxy* pytmpl = (TemplateProxy*)pyobject;
2612 std::string fullname = pytmpl->fTI->fCppName;
2613 if (pytmpl->fTemplateArgs)
2614 fullname += CPyCppyy_PyText_AsString(pytmpl->fTemplateArgs);
2615 Cppyy::TCppScope_t scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType;
2616 Cppyy::TCppMethod_t cppmeth = Cppyy::GetMethodTemplate(scope, fullname, signature);
2617 if (cppmeth) {
2618 void* fptr = (void*)Cppyy::GetFunctionAddress(cppmeth, false);
2619 if (fptr) return fptr;
2620 }
2621 // fall-through, with calling through Python
2622 }
2623
2624 if (PyCallable_Check(pyobject)) {
2625 // generic python callable: create a C++ wrapper function
2626 void* wpraddress = nullptr;
2627
2628 // re-use existing wrapper if possible
2629 auto key = rettype+signature;
2630 const auto& lookup = sWrapperLookup.find(key);
2631 if (lookup != sWrapperLookup.end()) {
2632 const auto& existing = lookup->second.find(pyobject);
2633 if (existing != lookup->second.end() && *sWrapperReference[existing->second] == pyobject)
2634 wpraddress = existing->second;
2635 }
2636
2637 // check for a pre-existing, unused, wrapper if not found
2638 if (!wpraddress) {
2639 const auto& freewrap = sWrapperFree.find(key);
2640 if (freewrap != sWrapperFree.end() && !freewrap->second.empty()) {
2641 wpraddress = freewrap->second.back();
2642 freewrap->second.pop_back();
2643 *(sWrapperReference[wpraddress]) = pyobject;
2644 sWrapperLookup[key][pyobject] = wpraddress;
2645 PyObject* wref = PyWeakref_NewRef(pyobject, sWrapperCacheEraser);
2646 if (wref) sWrapperWeakRefs[wref] = std::make_pair(wpraddress, key);
2647 else PyErr_Clear(); // happens for builtins which don't need this
2648 }
2649 }
2650
2651 // create wrapper if no re-use possible
2652 if (!wpraddress) {
2654 return nullptr;
2655
2656 // extract argument types
2657 const std::vector<std::string>& argtypes = TypeManip::extract_arg_types(signature);
2658 int nArgs = (int)argtypes.size();
2659
2660 // wrapper name
2661 std::ostringstream wname;
2662 wname << "fptr_wrap" << ++sWrapperCounter;
2663
2664 // build wrapper function code
2665 std::ostringstream code;
2666 code << "namespace __cppyy_internal {\n "
2667 << rettype << " " << wname.str() << "(";
2668 for (int i = 0; i < nArgs; ++i) {
2669 code << argtypes[i] << " arg" << i;
2670 if (i != nArgs-1) code << ", ";
2671 }
2672 code << ") {\n";
2673
2674 // start function body
2675 Utility::ConstructCallbackPreamble(rettype, argtypes, code);
2676
2677 // create a referenceable pointer
2678 PyObject** ref = new PyObject*{pyobject};
2679
2680 // function call itself and cleanup
2681 code << " PyObject** ref = (PyObject**)" << (intptr_t)ref << ";\n"
2682 " PyObject* pyresult = nullptr;\n"
2683 " if (*ref) pyresult = PyObject_CallFunctionObjArgs(*ref";
2684 for (int i = 0; i < nArgs; ++i)
2685 code << ", pyargs[" << i << "]";
2686 code << ", NULL);\n"
2687 " else PyErr_SetString(PyExc_TypeError, \"callable was deleted\");\n";
2688
2689 // close
2690 Utility::ConstructCallbackReturn(rettype, nArgs, code);
2691
2692 // end of namespace
2693 code << "}";
2694
2695 // finally, compile the code
2696 if (!Cppyy::Compile(code.str()))
2697 return nullptr;
2698
2699 // TODO: is there no easier way?
2700 static Cppyy::TCppScope_t scope = Cppyy::GetScope("__cppyy_internal");
2701 const auto& idx = Cppyy::GetMethodIndicesFromName(scope, wname.str());
2702 wpraddress = Cppyy::GetFunctionAddress(Cppyy::GetMethod(scope, idx[0]), false);
2703 sWrapperReference[wpraddress] = ref;
2704
2705 // cache the new wrapper
2706 sWrapperLookup[key][pyobject] = wpraddress;
2707 PyObject* wref = PyWeakref_NewRef(pyobject, sWrapperCacheEraser);
2708 if (wref) sWrapperWeakRefs[wref] = std::make_pair(wpraddress, key);
2709 else PyErr_Clear(); // happens for builtins which don't need this
2710 }
2711
2712 // now pass the pointer to the wrapper function (may be null)
2713 return wpraddress;
2714 }
2715
2716 return nullptr;
2717}
2718
2719bool CPyCppyy::FunctionPointerConverter::SetArg(
2720 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2721{
2722// special case: allow nullptr singleton:
2723 if (pyobject == gNullPtrObject || pyobject == gDefaultObject) {
2724 para.fValue.fVoidp = nullptr;
2725 para.fTypeCode = 'p';
2726 return true;
2727 }
2728
2729// normal case, get a function pointer
2730 void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature);
2731 if (fptr) {
2732 SetLifeLine(ctxt->fPyContext, pyobject, (intptr_t)this);
2733 para.fValue.fVoidp = fptr;
2734 para.fTypeCode = 'p';
2735 return true;
2736 }
2737
2738 return false;
2739}
2740
2741PyObject* CPyCppyy::FunctionPointerConverter::FromMemory(void* address)
2742{
2743// A function pointer in clang is represented by a Type, not a FunctionDecl and it's
2744// not possible to get the latter from the former: the backend will need to support
2745// both. Since that is far in the future, we'll use a std::function instead.
2746 if (address)
2747 return Utility::FuncPtr2StdFunction(fRetType, fSignature, *(void**)address);
2748 PyErr_SetString(PyExc_TypeError, "can not convert null function pointer");
2749 return nullptr;
2750}
2751
2752bool CPyCppyy::FunctionPointerConverter::ToMemory(
2753 PyObject* pyobject, void* address, PyObject* ctxt)
2754{
2755// special case: allow nullptr singleton:
2756 if (pyobject == gNullPtrObject || pyobject == gDefaultObject) {
2757 *((void**)address) = nullptr;
2758 return true;
2759 }
2760
2761// normal case, get a function pointer
2762 void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature);
2763 if (fptr) {
2764 SetLifeLine(ctxt, pyobject, (intptr_t)address);
2765 *((void**)address) = fptr;
2766 return true;
2767 }
2768
2769 return false;
2770}
2771
2772
2773//- std::function converter --------------------------------------------------
2774bool CPyCppyy::StdFunctionConverter::SetArg(
2775 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2776{
2777// prefer normal "object" conversion
2779 if (fConverter->SetArg(pyobject, para, ctxt))
2780 return true;
2781
2782 PyErr_Clear();
2783
2784// else create a wrapper function
2785 if (this->FunctionPointerConverter::SetArg(pyobject, para, ctxt)) {
2786 // retrieve the wrapper pointer and capture it in a temporary std::function,
2787 // then try normal conversion a second time
2788 PyObject* func = this->FunctionPointerConverter::FromMemory(&para.fValue.fVoidp);
2789 if (func) {
2790 SetLifeLine(ctxt->fPyContext, func, (intptr_t)this);
2791 bool result = fConverter->SetArg(func, para, ctxt);
2792 if (result) ctxt->AddTemporary(func);
2793 else Py_DECREF(func);
2794 return result;
2795 }
2796 }
2797
2798 return false;
2799}
2800
2801PyObject* CPyCppyy::StdFunctionConverter::FromMemory(void* address)
2802{
2803 return fConverter->FromMemory(address);
2804}
2805
2806bool CPyCppyy::StdFunctionConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt)
2807{
2808// if the value is not an std::function<> but a generic Python callable, the
2809// conversion is done through the assignment, which may involve a temporary
2810 if (address) SetLifeLine(ctxt, value, (intptr_t)address);
2811 return fConverter->ToMemory(value, address, ctxt);
2812}
2813
2814
2815//- smart pointer converters -------------------------------------------------
2816bool CPyCppyy::SmartPtrConverter::SetArg(
2817 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2818{
2819 char typeCode = fIsRef ? 'p' : 'V';
2820
2821 if (!CPPInstance_Check(pyobject)) {
2822 // TODO: not sure how this is correct for pass-by-ref nor does it help with
2823 // implicit conversions for pass-by-value
2824 if (fIsRef && GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) {
2825 para.fTypeCode = typeCode; // allow special cases such as nullptr
2826 return true;
2827 }
2828
2829 return false;
2830 }
2831
2832 CPPInstance* pyobj = (CPPInstance*)pyobject;
2833 Cppyy::TCppType_t oisa = pyobj->ObjectIsA();
2834
2835// for the case where we have a 'hidden' smart pointer:
2836 if (Cppyy::TCppType_t tsmart = pyobj->GetSmartIsA()) {
2837 if (Cppyy::IsSubtype(tsmart, fSmartPtrType)) {
2838 // depending on memory policy, some objects need releasing when passed into functions
2839 if (!fKeepControl && !UseStrictOwnership(ctxt))
2840 ((CPPInstance*)pyobject)->CppOwns();
2841
2842 // calculate offset between formal and actual arguments
2843 para.fValue.fVoidp = pyobj->GetSmartObject();
2844 if (tsmart != fSmartPtrType) {
2846 tsmart, fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */);
2847 }
2848
2849 // set pointer (may be null) and declare success
2850 para.fTypeCode = typeCode;
2851 return true;
2852 }
2853 }
2854
2855// for the case where we have an 'exposed' smart pointer:
2856 if (!pyobj->IsSmart() && Cppyy::IsSubtype(oisa, fSmartPtrType)) {
2857 // calculate offset between formal and actual arguments
2858 para.fValue.fVoidp = pyobj->GetObject();
2859 if (oisa != fSmartPtrType) {
2861 oisa, fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */);
2862 }
2863
2864 // set pointer (may be null) and declare success
2865 para.fTypeCode = typeCode;
2866 return true;
2867 }
2868
2869// The automatic conversion of ordinary obejcts to smart pointers is disabled
2870// for PyROOT because it can cause trouble with overload resolution. If a
2871// function has overloads for both ordinary objects and smart pointers, then
2872// the implicit conversion to smart pointers can result in the smart pointer
2873// overload being hit, even though there would be an overload for the regular
2874// object. Since PyROOT didn't have this feature before 6.32 anyway, disabling
2875// it was the safest option.
2876#if 0
2877// for the case where we have an ordinary object to convert
2878 if (!pyobj->IsSmart() && Cppyy::IsSubtype(oisa, fUnderlyingType)) {
2879 // create the relevant smart pointer and make the pyobject "smart"
2880 CPPInstance* pysmart = (CPPInstance*)ConvertImplicit(fSmartPtrType, pyobject, para, ctxt, false);
2881 if (!CPPInstance_Check(pysmart)) {
2882 Py_XDECREF(pysmart);
2883 return false;
2884 }
2885
2886 // copy internals from the fresh smart object to the original, making it smart
2887 pyobj->GetObjectRaw() = pysmart->GetSmartObject();
2888 pyobj->SetSmart(CreateScopeProxy(fSmartPtrType)); //(PyObject*)Py_TYPE(pysmart));
2889 pyobj->PythonOwns();
2890 pysmart->CppOwns();
2891 Py_DECREF(pysmart);
2892
2893 return true;
2894 }
2895#endif
2896
2897// final option, try mapping pointer types held (TODO: do not allow for non-const ref)
2898 if (pyobj->IsSmart() && Cppyy::IsSubtype(oisa, fUnderlyingType)) {
2899 para.fValue.fVoidp = ((CPPInstance*)pyobject)->GetSmartObject();
2900 para.fTypeCode = 'V';
2901 return true;
2902 }
2903
2904 return false;
2905}
2906
2907PyObject* CPyCppyy::SmartPtrConverter::FromMemory(void* address)
2908{
2909 if (!address || !fSmartPtrType)
2910 return nullptr;
2911
2912 return BindCppObjectNoCast(address, fSmartPtrType);
2913}
2914
2915
2916//----------------------------------------------------------------------------
2917namespace {
2918
2919// clang libcpp and gcc use the same structure (ptr, size)
2920#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2921struct faux_initlist
2922{
2923 typedef size_t size_type;
2924 typedef void* iterator;
2925 iterator _M_array;
2926 size_type _M_len;
2927};
2928#elif defined (_MSC_VER)
2929struct faux_initlist
2930{
2931 typedef char* iterator;
2932 iterator _M_array; // ie. _First;
2933 iterator _Last;
2934};
2935#else
2936#define NO_KNOWN_INITIALIZER_LIST 1
2937#endif
2938
2939} // unnamed namespace
2940
2941CPyCppyy::InitializerListConverter::InitializerListConverter(Cppyy::TCppType_t klass, std::string const &value_type)
2942
2943 : InstanceConverter{klass},
2944 fValueTypeName{value_type},
2945 fValueType{Cppyy::GetScope(value_type)},
2946 fValueSize{Cppyy::SizeOf(value_type)}
2947{
2948}
2949
2950CPyCppyy::InitializerListConverter::~InitializerListConverter()
2951{
2952 for (Converter *converter : fConverters) {
2953 if (converter && converter->HasState()) delete converter;
2954 }
2955 if (fBuffer) Clear();
2956}
2957
2958void CPyCppyy::InitializerListConverter::Clear() {
2959 if (fValueType) {
2960 faux_initlist* fake = (faux_initlist*)fBuffer;
2961#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2962 for (faux_initlist::size_type i = 0; i < fake->_M_len; ++i) {
2963#elif defined (_MSC_VER)
2964 for (size_t i = 0; (fake->_M_array+i*fValueSize) != fake->_Last; ++i) {
2965#endif
2966 void* memloc = (char*)fake->_M_array + i*fValueSize;
2968 }
2969 }
2970
2972 fBuffer = nullptr;
2973}
2974
2975bool CPyCppyy::InitializerListConverter::SetArg(
2976 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2977{
2978#ifdef NO_KNOWN_INITIALIZER_LIST
2979 return false;
2980#else
2981 if (fBuffer) Clear();
2982
2983// convert the given argument to an initializer list temporary; this is purely meant
2984// to be a syntactic thing, so only _python_ sequences are allowed; bound C++ proxies
2985// (likely explicitly created std::initializer_list, go through an instance converter
2986 if (!PySequence_Check(pyobject) || CPyCppyy_PyText_Check(pyobject)
2987#if PY_VERSION_HEX >= 0x03000000
2988 || PyBytes_Check(pyobject)
2989#else
2990 || PyUnicode_Check(pyobject)
2991#endif
2992 )
2993 return false;
2994
2995 if (CPPInstance_Check(pyobject))
2996 return this->InstanceConverter::SetArg(pyobject, para, ctxt);
2997
2998 void* buf = nullptr;
2999 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', (int)fValueSize, buf, true);
3000 faux_initlist* fake = nullptr;
3001 size_t entries = 0;
3002 if (buf && buflen) {
3003 // dealing with an array here, pass on whole-sale
3004 fake = (faux_initlist*)malloc(sizeof(faux_initlist));
3005 fBuffer = (void*)fake;
3006 fake->_M_array = (faux_initlist::iterator)buf;
3007#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
3008 fake->_M_len = (faux_initlist::size_type)buflen;
3009#elif defined (_MSC_VER)
3010 fake->_Last = fake->_M_array+buflen*fValueSize;
3011#endif
3012 } else if (fValueSize) {
3013 // Remove any errors set by GetBuffer(); note that if the argument was an array
3014 // that failed to extract because of a type mismatch, the following will perform
3015 // a (rather inefficient) copy. No warning is issued b/c e.g. numpy doesn't do
3016 // so either.
3017 PyErr_Clear();
3018
3019 // can only construct empty lists, so use a fake initializer list
3020 size_t len = (size_t)PySequence_Size(pyobject);
3021 fake = (faux_initlist*)malloc(sizeof(faux_initlist)+fValueSize*len);
3022 fBuffer = (void*)fake;
3023 fake->_M_array = (faux_initlist::iterator)((char*)fake+sizeof(faux_initlist));
3024#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
3025 fake->_M_len = (faux_initlist::size_type)len;
3026 for (faux_initlist::size_type i = 0; i < fake->_M_len; ++i) {
3027#elif defined (_MSC_VER)
3028 fake->_Last = fake->_M_array+len*fValueSize;
3029 for (size_t i = 0; (fake->_M_array+i*fValueSize) != fake->_Last; ++i) {
3030#endif
3031 PyObject* item = PySequence_GetItem(pyobject, i);
3032 bool convert_ok = false;
3033 if (item) {
3035 if (!converter) {
3036 if (CPPInstance_Check(item)) {
3037 // by convention, use byte copy
3038 memcpy((char*)fake->_M_array + i*fValueSize,
3039 ((CPPInstance*)item)->GetObject(), fValueSize);
3040 convert_ok = true;
3041 }
3042 } else {
3043 void* memloc = (char*)fake->_M_array + i*fValueSize;
3044 if (fValueType) {
3045 // we need to construct a default object for the constructor to assign into; this is
3046 // clunky, but the use of a copy constructor isn't much better as the Python object
3047 // need not be a C++ object
3048 memloc = (void*)Cppyy::Construct(fValueType, memloc);
3049 if (memloc) entries += 1;
3050 else {
3051 PyErr_SetString(PyExc_TypeError,
3052 "default ctor needed for initializer list of objects");
3053 }
3054 }
3055 if (memloc) {
3056 convert_ok = converter->ToMemory(item, memloc);
3057 }
3058 fConverters.emplace_back(converter);
3059 }
3060
3061
3062 Py_DECREF(item);
3063 } else
3064 PyErr_Format(PyExc_TypeError, "failed to get item %d from sequence", (int)i);
3065
3066 if (!convert_ok) {
3067#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
3068 fake->_M_len = (faux_initlist::size_type)entries;
3069#elif defined (_MSC_VER)
3070 fake->_Last = fake->_M_array+entries*fValueSize;
3071#endif
3072 Clear();
3073 return false;
3074 }
3075 }
3076 }
3077
3078 if (!fake) // no buffer and value size indeterminate
3079 return false;
3080
3081 para.fValue.fVoidp = (void*)fake;
3082 para.fTypeCode = 'V'; // means ptr that backend has to free after call
3083 return true;
3084#endif
3085}
3086
3087//----------------------------------------------------------------------------
3088bool CPyCppyy::NotImplementedConverter::SetArg(PyObject*, Parameter&, CallContext*)
3089{
3090// raise a NotImplemented exception to take a method out of overload resolution
3091 PyErr_SetString(PyExc_NotImplementedError, "this method cannot (yet) be called");
3092 return false;
3093}
3094
3095
3096//- helper to refactor some code from CreateConverter ------------------------
3098 const std::string& cpd, CPyCppyy::cdims_t dims, bool isConst, bool control)
3099{
3100 using namespace CPyCppyy;
3101 Converter* result = nullptr;
3102
3103 if (cpd == "**" || cpd == "*[]" || cpd == "&*")
3104 result = new InstancePtrPtrConverter<false>(klass, control);
3105 else if (cpd == "*&")
3106 result = new InstancePtrPtrConverter<true>(klass, control);
3107 else if (cpd == "*" && dims.ndim() == UNKNOWN_SIZE) {
3108 if (isConst) result = new InstancePtrConverter<true>(klass, control);
3109 else result = new InstancePtrConverter<false>(klass, control);
3110 }
3111 else if (cpd == "&")
3112 result = new InstanceRefConverter(klass, isConst);
3113 else if (cpd == "&&")
3114 result = new InstanceMoveConverter(klass);
3115 else if (cpd == "[]" || dims)
3116 result = new InstanceArrayConverter(klass, dims, false);
3117 else if (cpd == "") // by value
3118 result = new InstanceConverter(klass, true);
3119
3120 return result;
3121}
3122
3123//- factories ----------------------------------------------------------------
3125CPyCppyy::Converter* CPyCppyy::CreateConverter(const std::string& fullType, cdims_t dims)
3126{
3127// The matching of the fulltype to a converter factory goes through up to five levels:
3128// 1) full, exact match
3129// 2) match of decorated, unqualified type
3130// 3) accept const ref as by value
3131// 4) accept ref as pointer
3132// 5) generalized cases (covers basically all C++ classes)
3133//
3134// If all fails, void is used, which will generate a run-time warning when used.
3135
3136// an exactly matching converter is best
3137 ConvFactories_t::iterator h = gConvFactories.find(fullType);
3138 if (h != gConvFactories.end()) {
3139 return (h->second)(dims);
3140 }
3141
3142// resolve typedefs etc.
3143 const std::string& resolvedType = Cppyy::ResolveName(fullType);
3144
3145// a full, qualified matching converter is preferred
3146 if (resolvedType != fullType) {
3147 h = gConvFactories.find(resolvedType);
3148 if (h != gConvFactories.end())
3149 return (h->second)(dims);
3150 }
3151
3152//-- nothing? ok, collect information about the type and possible qualifiers/decorators
3153 bool isConst = strncmp(resolvedType.c_str(), "const", 5) == 0;
3154 const std::string& cpd = TypeManip::compound(resolvedType);
3155 std::string realType = TypeManip::clean_type(resolvedType, false, true);
3156
3157// accept unqualified type (as python does not know about qualifiers)
3158 h = gConvFactories.find((isConst ? "const " : "") + realType + cpd);
3159 if (h != gConvFactories.end())
3160 return (h->second)(dims);
3161
3162// drop const, as that is mostly meaningless to python (with the exception
3163// of c-strings, but those are specialized in the converter map)
3164 if (isConst) {
3165 h = gConvFactories.find(realType + cpd);
3166 if (h != gConvFactories.end())
3167 return (h->second)(dims);
3168 }
3169
3170//-- still nothing? try pointer instead of array (for builtins)
3171 if (cpd.compare(0, 3, "*[]") == 0) {
3172 // special case, array of pointers
3173 h = gConvFactories.find(realType + " ptr");
3174 if (h != gConvFactories.end()) {
3175 // upstream treats the pointer type as the array element type, but that pointer is
3176 // treated as a low-level view as well, unless it's a void*/char* so adjust the dims
3177 if (realType != "void" && realType != "char") {
3178 dim_t newdim = dims.ndim() == UNKNOWN_SIZE ? 2 : dims.ndim()+1;
3179 dims_t newdims = dims_t(newdim);
3180 // TODO: sometimes the array size is known and can thus be verified; however,
3181 // currently the meta layer does not provide this information
3182 newdims[0] = dims ? dims[0] : UNKNOWN_SIZE; // the array
3183 newdims[1] = UNKNOWN_SIZE; // the pointer
3184 if (2 < newdim) {
3185 for (int i = 2; i < (newdim-1); ++i)
3186 newdims[i] = dims[i-1];
3187 }
3188
3189 return (h->second)(newdims);
3190 }
3191 return (h->second)(dims);
3192 }
3193
3194 } else if (!cpd.empty() && (std::string::size_type)std::count(cpd.begin(), cpd.end(), '*') == cpd.size()) {
3195 // simple array; set or resize as necessary
3196 h = gConvFactories.find(realType + " ptr");
3197 if (h != gConvFactories.end())
3198 return (h->second)((!dims && 1 < cpd.size()) ? dims_t(cpd.size()) : dims);
3199
3200 } else if (2 <= cpd.size() && (std::string::size_type)std::count(cpd.begin(), cpd.end(), '[') == cpd.size() / 2) {
3201 // fixed array, dims will have size if available
3202 h = gConvFactories.find(realType + " ptr");
3203 if (h != gConvFactories.end())
3204 return (h->second)(dims);
3205 }
3206
3207//-- special case: initializer list
3208 if (realType.compare(0, 16, "initializer_list") == 0) {
3209 // get the type of the list and create a converter (TODO: get hold of value_type?)
3210 auto pos = realType.find('<');
3211 std::string value_type = realType.substr(pos+1, realType.size()-pos-2);
3212 return new InitializerListConverter(Cppyy::GetScope(realType), value_type);
3213 }
3214
3215//-- still nothing? use a generalized converter
3216 bool control = cpd == "&" || isConst;
3217
3218//-- special case: std::function
3219 auto pos = resolvedType.find("function<");
3220 if (pos == 0 /* no std:: */ || pos == 5 /* with std:: */ ||
3221 pos == 6 /* const no std:: */ || pos == 11 /* const with std:: */ ) {
3222
3223 // get actual converter for normal passing
3225 Cppyy::GetScope(realType), cpd, dims, isConst, control);
3226
3227 if (cnv) {
3228 // get the type of the underlying (TODO: use target_type?)
3229 auto pos1 = resolvedType.find("(", pos+9);
3230 auto pos2 = resolvedType.rfind(")");
3231 if (pos1 != std::string::npos && pos2 != std::string::npos) {
3232 auto sz1 = pos1-pos-9;
3233 if (resolvedType[pos+9+sz1-1] == ' ') sz1 -= 1;
3234
3235 return new StdFunctionConverter(cnv,
3236 resolvedType.substr(pos+9, sz1), resolvedType.substr(pos1, pos2-pos1+1));
3237 } else if (cnv->HasState())
3238 delete cnv;
3239 }
3240 }
3241
3242// converters for known C++ classes and default (void*)
3243 Converter* result = nullptr;
3244 if (Cppyy::TCppScope_t klass = Cppyy::GetScope(realType)) {
3245 Cppyy::TCppType_t raw{0};
3246 if (Cppyy::GetSmartPtrInfo(realType, &raw, nullptr)) {
3247 if (cpd == "") {
3248 result = new SmartPtrConverter(klass, raw, control);
3249 } else if (cpd == "&") {
3250 result = new SmartPtrConverter(klass, raw);
3251 } else if (cpd == "*" && dims.ndim() == UNKNOWN_SIZE) {
3252 result = new SmartPtrConverter(klass, raw, control, true);
3253 }
3254 }
3255
3256 if (!result) {
3257 // CLING WORKAROUND -- special case for STL iterators
3258 if (Utility::IsSTLIterator(realType)) {
3259 static STLIteratorConverter c;
3260 result = &c;
3261 } else
3262 // -- CLING WORKAROUND
3263 result = selectInstanceCnv(klass, cpd, dims, isConst, control);
3264 }
3265 } else {
3266 std::smatch sm;
3267 if (std::regex_search(resolvedType, sm, s_fnptr)) {
3268 // this is a function pointer
3269 auto pos1 = sm.position(0);
3270 auto pos2 = resolvedType.rfind(')');
3271 result = new FunctionPointerConverter(
3272 resolvedType.substr(0, pos1), resolvedType.substr(pos1+sm.length(), pos2-1));
3273 }
3274 }
3275
3276 if (!result && cpd == "&&") {
3277 // for builtin, can use const-ref for r-ref
3278 h = gConvFactories.find("const " + realType + "&");
3279 if (h != gConvFactories.end())
3280 return (h->second)(dims);
3281 // else, unhandled moves
3282 result = new NotImplementedConverter();
3283 }
3284
3285 if (!result && h != gConvFactories.end())
3286 // converter factory available, use it to create converter
3287 result = (h->second)(dims);
3288 else if (!result) {
3289 // default to something reasonable, assuming "user knows best"
3290 if (cpd.size() == 2 && cpd != "&&") // "**", "*[]", "*&"
3291 result = new VoidPtrPtrConverter(dims.ndim());
3292 else if (!cpd.empty())
3293 result = new VoidArrayConverter(); // "user knows best"
3294 else
3295 result = new NotImplementedConverter(); // fails on use
3296 }
3297
3298 return result;
3299}
3300
3301//----------------------------------------------------------------------------
3304{
3305 if (p && p->HasState())
3306 delete p; // state-less converters are always shared
3307}
3308
3309//----------------------------------------------------------------------------
3311bool CPyCppyy::RegisterConverter(const std::string& name, cf_t fac)
3312{
3313// register a custom converter
3314 auto f = gConvFactories.find(name);
3315 if (f != gConvFactories.end())
3316 return false;
3317
3318 gConvFactories[name] = fac;
3319 return true;
3320}
3321
3322//----------------------------------------------------------------------------
3324bool CPyCppyy::RegisterConverterAlias(const std::string& name, const std::string& target)
3325{
3326// register a custom converter that is a reference to an existing converter
3327 auto f = gConvFactories.find(name);
3328 if (f != gConvFactories.end())
3329 return false;
3330
3331 auto t = gConvFactories.find(target);
3332 if (t == gConvFactories.end())
3333 return false;
3334
3335 gConvFactories[name] = t->second;
3336 return true;
3337}
3338
3339//----------------------------------------------------------------------------
3341bool CPyCppyy::UnregisterConverter(const std::string& name)
3342{
3343// remove a custom converter
3344 auto f = gConvFactories.find(name);
3345 if (f != gConvFactories.end()) {
3346 gConvFactories.erase(f);
3347 return true;
3348 }
3349 return false;
3350}
3351
3352
3353//----------------------------------------------------------------------------
3354namespace {
3355
3356using namespace CPyCppyy;
3357
3358inline static
3359std::string::size_type dims2stringsz(cdims_t d) {
3360 return (d && d.ndim() != UNKNOWN_SIZE) ? d[0] : std::string::npos;
3361}
3362
3363#define STRINGVIEW "basic_string_view<char,char_traits<char> >"
3364#define WSTRING1 "std::basic_string<wchar_t>"
3365#define WSTRING2 "std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>"
3366
3367//-- aliasing special case: C complex (is binary compatible with C++ std::complex)
3368#ifndef _WIN32
3369#define CCOMPLEX_D "_Complex double"
3370#define CCOMPLEX_F "_Complex float"
3371#else
3372#define CCOMPLEX_D "_C_double_complex"
3373#define CCOMPLEX_F "_C_float_complex"
3374#endif
3375
3376static struct InitConvFactories_t {
3377public:
3378 InitConvFactories_t() {
3379 // load all converter factories in the global map 'gConvFactories'
3381
3382 // factories for built-ins
3383 gf["bool"] = (cf_t)+[](cdims_t) { static BoolConverter c{}; return &c; };
3384 gf["const bool&"] = (cf_t)+[](cdims_t) { static ConstBoolRefConverter c{}; return &c; };
3385 gf["bool&"] = (cf_t)+[](cdims_t) { static BoolRefConverter c{}; return &c; };
3386 gf["char"] = (cf_t)+[](cdims_t) { static CharConverter c{}; return &c; };
3387 gf["const char&"] = (cf_t)+[](cdims_t) { static ConstCharRefConverter c{}; return &c; };
3388 gf["char&"] = (cf_t)+[](cdims_t) { static CharRefConverter c{}; return &c; };
3389 gf["signed char&"] = (cf_t)+[](cdims_t) { static SCharRefConverter c{}; return &c; };
3390 gf["unsigned char"] = (cf_t)+[](cdims_t) { static UCharConverter c{}; return &c; };
3391 gf["const unsigned char&"] = (cf_t)+[](cdims_t) { static ConstUCharRefConverter c{}; return &c; };
3392 gf["unsigned char&"] = (cf_t)+[](cdims_t) { static UCharRefConverter c{}; return &c; };
3393 gf["UCharAsInt"] = (cf_t)+[](cdims_t) { static UCharAsIntConverter c{}; return &c; };
3394 gf["wchar_t"] = (cf_t)+[](cdims_t) { static WCharConverter c{}; return &c; };
3395 gf["char16_t"] = (cf_t)+[](cdims_t) { static Char16Converter c{}; return &c; };
3396 gf["char32_t"] = (cf_t)+[](cdims_t) { static Char32Converter c{}; return &c; };
3397 gf["wchar_t&"] = (cf_t)+[](cdims_t) { static WCharRefConverter c{}; return &c; };
3398 gf["char16_t&"] = (cf_t)+[](cdims_t) { static Char16RefConverter c{}; return &c; };
3399 gf["char32_t&"] = (cf_t)+[](cdims_t) { static Char32RefConverter c{}; return &c; };
3400 gf["int8_t"] = (cf_t)+[](cdims_t) { static Int8Converter c{}; return &c; };
3401 gf["const int8_t&"] = (cf_t)+[](cdims_t) { static ConstInt8RefConverter c{}; return &c; };
3402 gf["int8_t&"] = (cf_t)+[](cdims_t) { static Int8RefConverter c{}; return &c; };
3403 gf["uint8_t"] = (cf_t)+[](cdims_t) { static UInt8Converter c{}; return &c; };
3404 gf["const uint8_t&"] = (cf_t)+[](cdims_t) { static ConstUInt8RefConverter c{}; return &c; };
3405 gf["uint8_t&"] = (cf_t)+[](cdims_t) { static UInt8RefConverter c{}; return &c; };
3406 gf["short"] = (cf_t)+[](cdims_t) { static ShortConverter c{}; return &c; };
3407 gf["const short&"] = (cf_t)+[](cdims_t) { static ConstShortRefConverter c{}; return &c; };
3408 gf["short&"] = (cf_t)+[](cdims_t) { static ShortRefConverter c{}; return &c; };
3409 gf["unsigned short"] = (cf_t)+[](cdims_t) { static UShortConverter c{}; return &c; };
3410 gf["const unsigned short&"] = (cf_t)+[](cdims_t) { static ConstUShortRefConverter c{}; return &c; };
3411 gf["unsigned short&"] = (cf_t)+[](cdims_t) { static UShortRefConverter c{}; return &c; };
3412 gf["int"] = (cf_t)+[](cdims_t) { static IntConverter c{}; return &c; };
3413 gf["int&"] = (cf_t)+[](cdims_t) { static IntRefConverter c{}; return &c; };
3414 gf["const int&"] = (cf_t)+[](cdims_t) { static ConstIntRefConverter c{}; return &c; };
3415 gf["unsigned int"] = (cf_t)+[](cdims_t) { static UIntConverter c{}; return &c; };
3416 gf["const unsigned int&"] = (cf_t)+[](cdims_t) { static ConstUIntRefConverter c{}; return &c; };
3417 gf["unsigned int&"] = (cf_t)+[](cdims_t) { static UIntRefConverter c{}; return &c; };
3418 gf["long"] = (cf_t)+[](cdims_t) { static LongConverter c{}; return &c; };
3419 gf["long&"] = (cf_t)+[](cdims_t) { static LongRefConverter c{}; return &c; };
3420 gf["const long&"] = (cf_t)+[](cdims_t) { static ConstLongRefConverter c{}; return &c; };
3421 gf["unsigned long"] = (cf_t)+[](cdims_t) { static ULongConverter c{}; return &c; };
3422 gf["const unsigned long&"] = (cf_t)+[](cdims_t) { static ConstULongRefConverter c{}; return &c; };
3423 gf["unsigned long&"] = (cf_t)+[](cdims_t) { static ULongRefConverter c{}; return &c; };
3424 gf["long long"] = (cf_t)+[](cdims_t) { static LLongConverter c{}; return &c; };
3425 gf["const long long&"] = (cf_t)+[](cdims_t) { static ConstLLongRefConverter c{}; return &c; };
3426 gf["long long&"] = (cf_t)+[](cdims_t) { static LLongRefConverter c{}; return &c; };
3427 gf["unsigned long long"] = (cf_t)+[](cdims_t) { static ULLongConverter c{}; return &c; };
3428 gf["const unsigned long long&"] = (cf_t)+[](cdims_t) { static ConstULLongRefConverter c{}; return &c; };
3429 gf["unsigned long long&"] = (cf_t)+[](cdims_t) { static ULLongRefConverter c{}; return &c; };
3430
3431 gf["float"] = (cf_t)+[](cdims_t) { static FloatConverter c{}; return &c; };
3432 gf["const float&"] = (cf_t)+[](cdims_t) { static ConstFloatRefConverter c{}; return &c; };
3433 gf["float&"] = (cf_t)+[](cdims_t) { static FloatRefConverter c{}; return &c; };
3434 gf["double"] = (cf_t)+[](cdims_t) { static DoubleConverter c{}; return &c; };
3435 gf["double&"] = (cf_t)+[](cdims_t) { static DoubleRefConverter c{}; return &c; };
3436 gf["const double&"] = (cf_t)+[](cdims_t) { static ConstDoubleRefConverter c{}; return &c; };
3437 gf["long double"] = (cf_t)+[](cdims_t) { static LDoubleConverter c{}; return &c; };
3438 gf["const long double&"] = (cf_t)+[](cdims_t) { static ConstLDoubleRefConverter c{}; return &c; };
3439 gf["long double&"] = (cf_t)+[](cdims_t) { static LDoubleRefConverter c{}; return &c; };
3440 gf["std::complex<double>"] = (cf_t)+[](cdims_t) { return new ComplexDConverter{}; };
3441 gf["const std::complex<double>&"] = (cf_t)+[](cdims_t) { return new ComplexDConverter{}; };
3442 gf["void"] = (cf_t)+[](cdims_t) { static VoidConverter c{}; return &c; };
3443
3444 // pointer/array factories
3445 gf["bool ptr"] = (cf_t)+[](cdims_t d) { return new BoolArrayConverter{d}; };
3446 gf["const signed char[]"] = (cf_t)+[](cdims_t d) { return new SCharArrayConverter{d}; };
3447 gf["signed char[]"] = gf["const signed char[]"];
3448 gf["signed char**"] = (cf_t)+[](cdims_t) { return new SCharArrayConverter{{UNKNOWN_SIZE, UNKNOWN_SIZE}}; };
3449 gf["const unsigned char*"] = (cf_t)+[](cdims_t d) { return new UCharArrayConverter{d}; };
3450 gf["unsigned char ptr"] = (cf_t)+[](cdims_t d) { return new UCharArrayConverter{d}; };
3451 gf["UCharAsInt*"] = gf["unsigned char ptr"];
3452 gf["UCharAsInt[]"] = gf["unsigned char ptr"];
3453#if __cplusplus > 201402L
3454 gf["std::byte ptr"] = (cf_t)+[](cdims_t d) { return new ByteArrayConverter{d}; };
3455#endif
3456 gf["int8_t ptr"] = (cf_t)+[](cdims_t d) { return new Int8ArrayConverter{d}; };
3457 gf["uint8_t ptr"] = (cf_t)+[](cdims_t d) { return new UInt8ArrayConverter{d}; };
3458 gf["short ptr"] = (cf_t)+[](cdims_t d) { return new ShortArrayConverter{d}; };
3459 gf["unsigned short ptr"] = (cf_t)+[](cdims_t d) { return new UShortArrayConverter{d}; };
3460 gf["int ptr"] = (cf_t)+[](cdims_t d) { return new IntArrayConverter{d}; };
3461 gf["unsigned int ptr"] = (cf_t)+[](cdims_t d) { return new UIntArrayConverter{d}; };
3462 gf["long ptr"] = (cf_t)+[](cdims_t d) { return new LongArrayConverter{d}; };
3463 gf["unsigned long ptr"] = (cf_t)+[](cdims_t d) { return new ULongArrayConverter{d}; };
3464 gf["long long ptr"] = (cf_t)+[](cdims_t d) { return new LLongArrayConverter{d}; };
3465 gf["unsigned long long ptr"] = (cf_t)+[](cdims_t d) { return new ULLongArrayConverter{d}; };
3466 gf["float ptr"] = (cf_t)+[](cdims_t d) { return new FloatArrayConverter{d}; };
3467 gf["double ptr"] = (cf_t)+[](cdims_t d) { return new DoubleArrayConverter{d}; };
3468 gf["long double ptr"] = (cf_t)+[](cdims_t d) { return new LDoubleArrayConverter{d}; };
3469 gf["std::complex<float> ptr"] = (cf_t)+[](cdims_t d) { return new ComplexFArrayConverter{d}; };
3470 gf["std::complex<double> ptr"] = (cf_t)+[](cdims_t d) { return new ComplexDArrayConverter{d}; };
3471 gf["void*"] = (cf_t)+[](cdims_t d) { return new VoidArrayConverter{(bool)d}; };
3472
3473 // aliases
3474 gf["signed char"] = gf["char"];
3475 gf["const signed char&"] = gf["const char&"];
3476#if __cplusplus > 201402L
3477 gf["std::byte"] = gf["uint8_t"];
3478 gf["const std::byte&"] = gf["const uint8_t&"];
3479 gf["std::byte&"] = gf["uint8_t&"];
3480#endif
3481 gf["std::int8_t"] = gf["int8_t"];
3482 gf["const std::int8_t&"] = gf["const int8_t&"];
3483 gf["std::int8_t&"] = gf["int8_t&"];
3484 gf["std::uint8_t"] = gf["uint8_t"];
3485 gf["const std::uint8_t&"] = gf["const uint8_t&"];
3486 gf["std::uint8_t&"] = gf["uint8_t&"];
3487 gf["internal_enum_type_t"] = gf["int"];
3488 gf["internal_enum_type_t&"] = gf["int&"];
3489 gf["const internal_enum_type_t&"] = gf["const int&"];
3490 gf["internal_enum_type_t ptr"] = gf["int ptr"];
3491#ifdef _WIN32
3492 gf["__int64"] = gf["long long"];
3493 gf["const __int64&"] = gf["const long long&"];
3494 gf["__int64&"] = gf["long long&"];
3495 gf["__int64 ptr"] = gf["long long ptr"];
3496 gf["unsigned __int64"] = gf["unsigned long long"];
3497 gf["const unsigned __int64&"] = gf["const unsigned long long&"];
3498 gf["unsigned __int64&"] = gf["unsigned long long&"];
3499 gf["unsigned __int64 ptr"] = gf["unsigned long long ptr"];
3500#endif
3501 gf[CCOMPLEX_D] = gf["std::complex<double>"];
3502 gf["const " CCOMPLEX_D "&"] = gf["const std::complex<double>&"];
3503 gf[CCOMPLEX_F " ptr"] = gf["std::complex<float> ptr"];
3504 gf[CCOMPLEX_D " ptr"] = gf["std::complex<double> ptr"];
3505
3506 // factories for special cases
3507 gf["TString"] = (cf_t)+[](cdims_t) { return new TStringConverter{}; };
3508 gf["TString&"] = gf["TString"];
3509 gf["const TString&"] = gf["TString"];
3510 gf["nullptr_t"] = (cf_t)+[](cdims_t) { static NullptrConverter c{}; return &c;};
3511 gf["const char*"] = (cf_t)+[](cdims_t) { return new CStringConverter{}; };
3512 gf["const signed char*"] = gf["const char*"];
3513 gf["const char*&&"] = gf["const char*"];
3514 gf["const char[]"] = (cf_t)+[](cdims_t) { return new CStringConverter{}; };
3515 gf["char*"] = (cf_t)+[](cdims_t d) { return new NonConstCStringConverter{dims2stringsz(d)}; };
3516 gf["char[]"] = (cf_t)+[](cdims_t d) { return new NonConstCStringArrayConverter{d, true}; };
3517 gf["signed char*"] = gf["char*"];
3518 gf["wchar_t*"] = (cf_t)+[](cdims_t) { return new WCStringConverter{}; };
3519 gf["char16_t*"] = (cf_t)+[](cdims_t) { return new CString16Converter{}; };
3520 gf["char16_t[]"] = (cf_t)+[](cdims_t d) { return new CString16Converter{dims2stringsz(d)}; };
3521 gf["char32_t*"] = (cf_t)+[](cdims_t) { return new CString32Converter{}; };
3522 gf["char32_t[]"] = (cf_t)+[](cdims_t d) { return new CString32Converter{dims2stringsz(d)}; };
3523 // TODO: the following are handled incorrectly upstream (char16_t** where char16_t* intended)?!
3524 gf["char16_t**"] = gf["char16_t*"];
3525 gf["char32_t**"] = gf["char32_t*"];
3526 gf["const char**"] = (cf_t)+[](cdims_t) { return new CStringArrayConverter{{UNKNOWN_SIZE, UNKNOWN_SIZE}, false}; };
3527 gf["char**"] = gf["const char**"];
3528 gf["const char*[]"] = (cf_t)+[](cdims_t d) { return new CStringArrayConverter{d, false}; };
3529 gf["char*[]"] = (cf_t)+[](cdims_t d) { return new NonConstCStringArrayConverter{d, false}; };
3530 gf["char ptr"] = gf["char*[]"];
3531 gf["std::string"] = (cf_t)+[](cdims_t) { return new STLStringConverter{}; };
3532 gf["const std::string&"] = gf["std::string"];
3533 gf["string"] = gf["std::string"];
3534 gf["const string&"] = gf["std::string"];
3535 gf["std::string&&"] = (cf_t)+[](cdims_t) { return new STLStringMoveConverter{}; };
3536 gf["string&&"] = gf["std::string&&"];
3537#if __cplusplus > 201402L
3538 gf["std::string_view"] = (cf_t)+[](cdims_t) { return new STLStringViewConverter{}; };
3539 gf[STRINGVIEW] = gf["std::string_view"];
3540 gf["std::string_view&"] = gf["std::string_view"];
3541 gf["const std::string_view&"] = gf["std::string_view"];
3542 gf["const " STRINGVIEW "&"] = gf["std::string_view"];
3543#endif
3544 gf["std::wstring"] = (cf_t)+[](cdims_t) { return new STLWStringConverter{}; };
3545 gf[WSTRING1] = gf["std::wstring"];
3546 gf[WSTRING2] = gf["std::wstring"];
3547 gf["const std::wstring&"] = gf["std::wstring"];
3548 gf["const " WSTRING1 "&"] = gf["std::wstring"];
3549 gf["const " WSTRING2 "&"] = gf["std::wstring"];
3550 gf["void*&"] = (cf_t)+[](cdims_t) { static VoidPtrRefConverter c{}; return &c; };
3551 gf["void**"] = (cf_t)+[](cdims_t d) { return new VoidPtrPtrConverter{d}; };
3552 gf["void ptr"] = gf["void**"];
3553 gf["PyObject*"] = (cf_t)+[](cdims_t) { static PyObjectConverter c{}; return &c; };
3554 gf["_object*"] = gf["PyObject*"];
3555 gf["FILE*"] = (cf_t)+[](cdims_t) { return new VoidArrayConverter{}; };
3556 }
3557} initConvFactories_;
3558
3559} // 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
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 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:1018
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 bool RegisterConverterAlias(const std::string &name, const std::string &target)
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