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