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