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