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