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