Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Converters.cxx
Go to the documentation of this file.
1// Bindings
2#include "CPyCppyy.h"
3#include "DeclareConverters.h"
4#include "CallContext.h"
5#include "CPPExcInstance.h"
6#include "CPPInstance.h"
7#include "CPPOverload.h"
8#include "CustomPyTypes.h"
9#include "LowLevelViews.h"
10#include "MemoryRegulator.h"
11#include "ProxyWrappers.h"
12#include "PyStrings.h"
13#include "TemplateProxy.h"
14#include "TupleOfInstances.h"
15#include "TypeManip.h"
16#include "Utility.h"
17
18// Standard
19#include <complex>
20#include <limits.h>
21#include <stddef.h> // for ptrdiff_t
22#include <string.h>
23#include <algorithm>
24#include <array>
25#include <locale> // for wstring_convert
26#include <regex>
27#include <utility>
28#include <sstream>
29#if __cplusplus > 201402L
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("\\(:*\\*&*\\)");
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
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
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 (pyobject->ob_refcnt <= 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 PyObject* result = PyObject_CallMethod(pyobj, (char*)"__assign__", (char*)"O", value);
2243
2244 if (result) {
2246 return true;
2247 }
2248 return false;
2249}
2250
2251
2252//----------------------------------------------------------------------------
2253bool CPyCppyy::InstanceRefConverter::SetArg(
2255{
2256// convert <pyobject> to C++ instance&, set arg for call
2258 if (pyobj) {
2259
2260 // reject moves
2261 if (pyobj->fFlags & CPPInstance::kIsRValue)
2262 return false;
2263
2264 // smart pointers can end up here in case of a move, so preferentially match
2265 // the smart type directly
2266 bool argset = false;
2268 if (pyobj->IsSmart()) {
2269 cls = pyobj->ObjectIsA(false);
2270 if (cls && Cppyy::IsSubtype(cls, fClass)) {
2271 para.fValue.fVoidp = pyobj->GetObjectRaw();
2272 argset = true;
2273 }
2274 }
2275
2276 if (!argset) {
2277 cls = pyobj->ObjectIsA();
2278 if (cls && Cppyy::IsSubtype(cls, fClass)) {
2279 para.fValue.fVoidp = pyobj->GetObject();
2280 argset = true;
2281 }
2282 }
2283
2284 if (argset) {
2285 // do not allow null pointers through references
2286 if (!para.fValue.fVoidp) {
2287 PyErr_SetString(PyExc_ReferenceError, "attempt to access a null-pointer");
2288 return false;
2289 }
2290
2291 // calculate offset between formal and actual arguments
2292 if (cls != fClass) {
2293 para.fValue.fIntPtr += Cppyy::GetBaseOffset(
2294 cls, fClass, para.fValue.fVoidp, 1 /* up-cast */);
2295 }
2296
2297 para.fTypeCode = 'V';
2298 return true;
2299 }
2300 }
2301
2302 if (!fIsConst) // no implicit conversion possible
2303 return false;
2304
2305 return (bool)ConvertImplicit(fClass, pyobject, para, ctxt);
2306}
2307
2308//----------------------------------------------------------------------------
2309PyObject* CPyCppyy::InstanceRefConverter::FromMemory(void* address)
2310{
2312}
2313
2314//----------------------------------------------------------------------------
2315bool CPyCppyy::InstanceMoveConverter::SetArg(
2317{
2318// convert <pyobject> to C++ instance&&, set arg for call
2319 CPPInstance* pyobj = GetCppInstance(pyobject, fClass, true /* accept_rvalue */);
2320 if (!pyobj || (pyobj->fFlags & CPPInstance::kIsLValue)) {
2321 // implicit conversion is fine as the temporary by definition is moveable
2322 return (bool)ConvertImplicit(fClass, pyobject, para, ctxt);
2323 }
2324
2325// moving is same as by-ref, but have to check that move is allowed
2326 int moveit_reason = 0;
2327 if (pyobj->fFlags & CPPInstance::kIsRValue) {
2328 pyobj->fFlags &= ~CPPInstance::kIsRValue;
2329 moveit_reason = 2;
2330 } else if (pyobject->ob_refcnt <= MOVE_REFCOUNT_CUTOFF) {
2331 moveit_reason = 1;
2332 }
2333
2334 if (moveit_reason) {
2335 bool result = this->InstanceRefConverter::SetArg(pyobject, para, ctxt);
2336 if (!result && moveit_reason == 2) // restore the movability flag?
2338 return result;
2339 }
2340
2341 PyErr_SetString(PyExc_ValueError, "object is not an rvalue");
2342 return false; // not a temporary or movable object
2343}
2344
2345//----------------------------------------------------------------------------
2346template <bool ISREFERENCE>
2347bool CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::SetArg(
2349{
2350// convert <pyobject> to C++ instance**, set arg for call
2352 if (!pyobj) {
2354 // allow nullptr as a special case
2355 para.fValue.fVoidp = nullptr;
2356 para.fTypeCode = 'p';
2357 return true;
2358 }
2359 return false; // not a cppyy object (TODO: handle SWIG etc.)
2360 }
2361
2362 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
2363 // depending on memory policy, some objects need releasing when passed into functions
2364 if (!KeepControl() && !UseStrictOwnership(ctxt))
2365 pyobj->CppOwns();
2366
2367 // set pointer (may be null) and declare success
2368 if (pyobj->fFlags & CPPInstance::kIsReference) // already a ptr to object?
2369 para.fValue.fVoidp = pyobj->GetObjectRaw();
2370 else
2371 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2372 para.fTypeCode = ISREFERENCE ? 'V' : 'p';
2373 return true;
2374 }
2375
2376 return false;
2377}
2378
2379//----------------------------------------------------------------------------
2380template <bool ISREFERENCE>
2381PyObject* CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::FromMemory(void* address)
2382{
2383// construct python object from C++ instance* read at <address>
2385}
2386
2387//----------------------------------------------------------------------------
2388template <bool ISREFERENCE>
2389bool CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::ToMemory(
2390 PyObject* value, void* address, PyObject* /* ctxt */)
2391{
2392// convert <value> to C++ instance*, write it at <address>
2394 if (!pyobj) {
2396 // allow nullptr as a special case
2397 *(void**)address = nullptr;
2398 return true;
2399 }
2400 return false; // not a cppyy object (TODO: handle SWIG etc.)
2401 }
2402
2403 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
2404 // depending on memory policy, some objects need releasing when passed into functions
2405 if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict)
2406 pyobj->CppOwns();
2407
2408 // register the value for potential recycling
2410
2411 // set pointer (may be null) and declare success
2412 *(void**)address = pyobj->GetObject();
2413 return true;
2414 }
2415
2416 return false;
2417}
2418
2419
2420namespace CPyCppyy {
2421// Instantiate the templates
2424 template class CPyCppyy::InstancePtrPtrConverter<true>;
2425 template class CPyCppyy::InstancePtrPtrConverter<false>;
2426}
2427
2428//----------------------------------------------------------------------------
2429bool CPyCppyy::InstanceArrayConverter::SetArg(
2431{
2432// convert <pyobject> to C++ instance**, set arg for call
2434 return false; // no guarantee that the tuple is okay
2435
2436// treat the first instance of the tuple as the start of the array, and pass it
2437// by pointer (TODO: store and check sizes)
2438 if (PyTuple_Size(pyobject) < 1)
2439 return false;
2440
2441 PyObject* first = PyTuple_GetItem(pyobject, 0);
2442 if (!CPPInstance_Check(first))
2443 return false; // should not happen
2444
2445 if (Cppyy::IsSubtype(((CPPInstance*)first)->ObjectIsA(), fClass)) {
2446 // no memory policies supported; set pointer (may be null) and declare success
2447 para.fValue.fVoidp = ((CPPInstance*)first)->GetObject();
2448 para.fTypeCode = 'p';
2449 return true;
2450 }
2451
2452 return false;
2453}
2454
2455//----------------------------------------------------------------------------
2456PyObject* CPyCppyy::InstanceArrayConverter::FromMemory(void* address)
2457{
2458// construct python tuple of instances from C++ array read at <address>
2459 return BindCppObjectArray(*(char**)address, fClass, fShape);
2460}
2461
2462//----------------------------------------------------------------------------
2463bool CPyCppyy::InstanceArrayConverter::ToMemory(
2464 PyObject* /* value */, void* /* address */, PyObject* /* ctxt */)
2465{
2466// convert <value> to C++ array of instances, write it at <address>
2467
2468// TODO: need to have size both for the array and from the input
2470 "access to C-arrays of objects not yet implemented!");
2471 return false;
2472}
2473
2474//___________________________________________________________________________
2475// CLING WORKAROUND -- classes for STL iterators are completely undefined in that
2476// they come in a bazillion different guises, so just do whatever
2477bool CPyCppyy::STLIteratorConverter::SetArg(
2478 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2479{
2481 return false;
2482
2483// just set the pointer value, no check
2485 para.fValue.fVoidp = pyobj->GetObject();
2486 para.fTypeCode = 'V';
2487 return true;
2488}
2489// -- END CLING WORKAROUND
2490
2491//----------------------------------------------------------------------------
2492bool CPyCppyy::VoidPtrRefConverter::SetArg(
2493 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2494{
2495// convert <pyobject> to C++ void*&, set arg for call
2497 if (pyobj) {
2498 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2499 para.fTypeCode = 'V';
2500 return true;
2501 }
2502
2503 return false;
2504}
2505
2506//----------------------------------------------------------------------------
2507CPyCppyy::VoidPtrPtrConverter::VoidPtrPtrConverter(cdims_t dims) :
2508 fShape(dims) {
2509 fIsFixed = dims ? fShape[0] != UNKNOWN_SIZE : false;
2510}
2511
2512//----------------------------------------------------------------------------
2513bool CPyCppyy::VoidPtrPtrConverter::SetArg(
2514 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2515{
2516// convert <pyobject> to C++ void**, set arg for call
2518 if (pyobj) {
2519 // this is a C++ object, take and set its address
2520 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2521 para.fTypeCode = 'p';
2522 return true;
2523 } else if (IsPyCArgObject(pyobject)) {
2525 if (carg->obj) {
2526 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)carg->obj)->b_ptr;
2527 para.fTypeCode = 'p';
2528 return true;
2529 }
2530 }
2531
2532// buffer objects are allowed under "user knows best" (this includes the buffer
2533// interface to ctypes.c_void_p, which results in a void**)
2534 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', 1, para.fValue.fVoidp, false);
2535
2536// ok if buffer exists (can't perform any useful size checks)
2537 if (para.fValue.fVoidp && buflen != 0) {
2538 para.fTypeCode = 'p';
2539 return true;
2540 }
2541
2542 return false;
2543}
2544
2545//----------------------------------------------------------------------------
2546PyObject* CPyCppyy::VoidPtrPtrConverter::FromMemory(void* address)
2547{
2548// read a void** from address; since this is unknown, uintptr_t is used (user can cast)
2549 if (!address || *(ptrdiff_t*)address == 0) {
2551 return gNullPtrObject;
2552 }
2553 if (!fIsFixed)
2554 return CreatePointerView((uintptr_t**)address, fShape);
2555 return CreatePointerView(*(uintptr_t**)address, fShape);
2556}
2557
2558//----------------------------------------------------------------------------
2559bool CPyCppyy::PyObjectConverter::SetArg(
2560 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2561{
2562// by definition: set and declare success
2563 para.fValue.fVoidp = pyobject;
2564 para.fTypeCode = 'p';
2565 return true;
2566}
2567
2568PyObject* CPyCppyy::PyObjectConverter::FromMemory(void* address)
2569{
2570// construct python object from C++ PyObject* read at <address>
2571 PyObject* pyobject = *((PyObject**)address);
2572
2573 if (!pyobject) {
2575 }
2576
2578 return pyobject;
2579}
2580
2581bool CPyCppyy::PyObjectConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
2582{
2583// no conversion needed, write <value> at <address>
2585 Py_XDECREF(*((PyObject**)address));
2586 *((PyObject**)address) = value;
2587 return true;
2588}
2589
2590
2591//- function pointer converter -----------------------------------------------
2592static unsigned int sWrapperCounter = 0;
2593// cache mapping signature/return type to python callable and corresponding wrapper
2594typedef std::string RetSigKey_t;
2595static std::map<RetSigKey_t, std::vector<void*>> sWrapperFree;
2596static std::map<RetSigKey_t, std::map<PyObject*, void*>> sWrapperLookup;
2597static std::map<PyObject*, std::pair<void*, RetSigKey_t>> sWrapperWeakRefs;
2598static std::map<void*, PyObject**> sWrapperReference;
2599
2601{
2602 auto ipos = sWrapperWeakRefs.find(pyref);
2603 if (ipos != sWrapperWeakRefs.end()) {
2604 auto key = ipos->second.second;
2605
2606 // disable this callback and store on free list for possible re-use
2607 void* wpraddress = ipos->second.first;
2609 const auto& lookup = sWrapperLookup.find(key);
2610 if (lookup != sWrapperLookup.end()) lookup->second.erase(*oldref);
2611 *oldref = nullptr; // to detect deletions
2612 sWrapperFree[ipos->second.second].push_back(wpraddress);
2613
2614 // clean up and remove weak reference from admin
2615 Py_DECREF(ipos->first);
2616 sWrapperWeakRefs.erase(ipos);
2617 }
2618
2620}
2622 const_cast<char*>("internal_WrapperCacheEraser"),
2624 METH_O, nullptr
2625};
2626
2628 const std::string& rettype, const std::string& signature)
2629{
2630// Convert a bound C++ function pointer or callable python object to a C-style
2631// function pointer. The former is direct, the latter involves a JIT-ed wrapper.
2633
2634 using namespace CPyCppyy;
2635
2638 if (!ol->fMethodInfo || ol->fMethodInfo->fMethods.empty())
2639 return nullptr;
2640
2641 // find the overload with matching signature
2642 for (auto& m : ol->fMethodInfo->fMethods) {
2643 PyObject* sig = m->GetSignature(false);
2644 bool found = signature == CPyCppyy_PyText_AsString(sig);
2645 Py_DECREF(sig);
2646 if (found) {
2647 void* fptr = (void*)m->GetFunctionAddress();
2648 if (fptr) return fptr;
2649 break; // fall-through, with calling through Python
2650 }
2651 }
2652 }
2653
2655 // get the actual underlying template matching the signature
2657 std::string fullname = pytmpl->fTI->fCppName;
2658 if (pytmpl->fTemplateArgs)
2659 fullname += CPyCppyy_PyText_AsString(pytmpl->fTemplateArgs);
2660 Cppyy::TCppScope_t scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType;
2662 if (cppmeth) {
2663 void* fptr = (void*)Cppyy::GetFunctionAddress(cppmeth, false);
2664 if (fptr) return fptr;
2665 }
2666 // fall-through, with calling through Python
2667 }
2668
2670 // generic python callable: create a C++ wrapper function
2671 void* wpraddress = nullptr;
2672
2673 // re-use existing wrapper if possible
2674 auto key = rettype+signature;
2675 const auto& lookup = sWrapperLookup.find(key);
2676 if (lookup != sWrapperLookup.end()) {
2677 const auto& existing = lookup->second.find(pyobject);
2678 if (existing != lookup->second.end() && *sWrapperReference[existing->second] == pyobject)
2679 wpraddress = existing->second;
2680 }
2681
2682 // check for a pre-existing, unused, wrapper if not found
2683 if (!wpraddress) {
2684 const auto& freewrap = sWrapperFree.find(key);
2685 if (freewrap != sWrapperFree.end() && !freewrap->second.empty()) {
2686 wpraddress = freewrap->second.back();
2687 freewrap->second.pop_back();
2691 if (wref) sWrapperWeakRefs[wref] = std::make_pair(wpraddress, key);
2692 else PyErr_Clear(); // happens for builtins which don't need this
2693 }
2694 }
2695
2696 // create wrapper if no re-use possible
2697 if (!wpraddress) {
2699 return nullptr;
2700
2701 // extract argument types
2702 const std::vector<std::string>& argtypes = TypeManip::extract_arg_types(signature);
2703 int nArgs = (int)argtypes.size();
2704
2705 // wrapper name
2706 std::ostringstream wname;
2707 wname << "fptr_wrap" << ++sWrapperCounter;
2708
2709 // build wrapper function code
2710 std::ostringstream code;
2711 code << "namespace __cppyy_internal {\n "
2712 << rettype << " " << wname.str() << "(";
2713 for (int i = 0; i < nArgs; ++i) {
2714 code << argtypes[i] << " arg" << i;
2715 if (i != nArgs-1) code << ", ";
2716 }
2717 code << ") {\n";
2718
2719 // start function body
2721
2722 // create a referenceable pointer
2723 PyObject** ref = new PyObject*{pyobject};
2724
2725 // function call itself and cleanup
2726 code << " PyObject** ref = (PyObject**)" << (intptr_t)ref << ";\n"
2727 " PyObject* pyresult = nullptr;\n"
2728 " if (*ref) pyresult = PyObject_CallFunctionObjArgs(*ref";
2729 for (int i = 0; i < nArgs; ++i)
2730 code << ", pyargs[" << i << "]";
2731 code << ", NULL);\n"
2732 " else PyErr_SetString(PyExc_TypeError, \"callable was deleted\");\n";
2733
2734 // close
2736
2737 // end of namespace
2738 code << "}";
2739
2740 // finally, compile the code
2741 if (!Cppyy::Compile(code.str()))
2742 return nullptr;
2743
2744 // TODO: is there no easier way?
2745 static Cppyy::TCppScope_t scope = Cppyy::GetScope("__cppyy_internal");
2746 const auto& idx = Cppyy::GetMethodIndicesFromName(scope, wname.str());
2749
2750 // cache the new wrapper
2753 if (wref) sWrapperWeakRefs[wref] = std::make_pair(wpraddress, key);
2754 else PyErr_Clear(); // happens for builtins which don't need this
2755 }
2756
2757 // now pass the pointer to the wrapper function (may be null)
2758 return wpraddress;
2759 }
2760
2761 return nullptr;
2762}
2763
2764bool CPyCppyy::FunctionPointerConverter::SetArg(
2766{
2767// special case: allow nullptr singleton:
2769 para.fValue.fVoidp = nullptr;
2770 para.fTypeCode = 'p';
2771 return true;
2772 }
2773
2774// normal case, get a function pointer
2776 if (fptr) {
2777 SetLifeLine(ctxt->fPyContext, pyobject, (intptr_t)this);
2778 para.fValue.fVoidp = fptr;
2779 para.fTypeCode = 'p';
2780 return true;
2781 }
2782
2783 return false;
2784}
2785
2786PyObject* CPyCppyy::FunctionPointerConverter::FromMemory(void* address)
2787{
2788// A function pointer in clang is represented by a Type, not a FunctionDecl and it's
2789// not possible to get the latter from the former: the backend will need to support
2790// both. Since that is far in the future, we'll use a std::function instead.
2791 if (address)
2792 return Utility::FuncPtr2StdFunction(fRetType, fSignature, *(void**)address);
2793 PyErr_SetString(PyExc_TypeError, "can not convert null function pointer");
2794 return nullptr;
2795}
2796
2797bool CPyCppyy::FunctionPointerConverter::ToMemory(
2798 PyObject* pyobject, void* address, PyObject* ctxt)
2799{
2800// special case: allow nullptr singleton:
2802 *((void**)address) = nullptr;
2803 return true;
2804 }
2805
2806// normal case, get a function pointer
2808 if (fptr) {
2809 SetLifeLine(ctxt, pyobject, (intptr_t)address);
2810 *((void**)address) = fptr;
2811 return true;
2812 }
2813
2814 return false;
2815}
2816
2817
2818//- std::function converter --------------------------------------------------
2819bool CPyCppyy::StdFunctionConverter::SetArg(
2821{
2822// prefer normal "object" conversion
2825 return true;
2826
2827 PyErr_Clear();
2828
2829// else create a wrapper function
2830 if (this->FunctionPointerConverter::SetArg(pyobject, para, ctxt)) {
2831 // retrieve the wrapper pointer and capture it in a temporary std::function,
2832 // then try normal conversion a second time
2833 PyObject* func = this->FunctionPointerConverter::FromMemory(&para.fValue.fVoidp);
2834 if (func) {
2835 SetLifeLine(ctxt->fPyContext, func, (intptr_t)this);
2836 bool result = fConverter->SetArg(func, para, ctxt);
2837 if (result) ctxt->AddTemporary(func);
2838 else Py_DECREF(func);
2839 return result;
2840 }
2841 }
2842
2843 return false;
2844}
2845
2846PyObject* CPyCppyy::StdFunctionConverter::FromMemory(void* address)
2847{
2848 return fConverter->FromMemory(address);
2849}
2850
2851bool CPyCppyy::StdFunctionConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt)
2852{
2853// if the value is not an std::function<> but a generic Python callable, the
2854// conversion is done through the assignment, which may involve a temporary
2855 if (address) SetLifeLine(ctxt, value, (intptr_t)address);
2856 return fConverter->ToMemory(value, address, ctxt);
2857}
2858
2859
2860//- smart pointer converters -------------------------------------------------
2861bool CPyCppyy::SmartPtrConverter::SetArg(
2863{
2864 char typeCode = fIsRef ? 'p' : 'V';
2865
2867 // TODO: not sure how this is correct for pass-by-ref nor does it help with
2868 // implicit conversions for pass-by-value
2869 if (fIsRef && GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) {
2870 para.fTypeCode = typeCode; // allow special cases such as nullptr
2871 return true;
2872 }
2873
2874 return false;
2875 }
2876
2878 Cppyy::TCppType_t oisa = pyobj->ObjectIsA();
2879
2880// for the case where we have a 'hidden' smart pointer:
2881 if (Cppyy::TCppType_t tsmart = pyobj->GetSmartIsA()) {
2883 // depending on memory policy, some objects need releasing when passed into functions
2885 ((CPPInstance*)pyobject)->CppOwns();
2886
2887 // calculate offset between formal and actual arguments
2888 para.fValue.fVoidp = pyobj->GetSmartObject();
2889 if (tsmart != fSmartPtrType) {
2890 para.fValue.fIntPtr += Cppyy::GetBaseOffset(
2891 tsmart, fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */);
2892 }
2893
2894 // set pointer (may be null) and declare success
2895 para.fTypeCode = typeCode;
2896 return true;
2897 }
2898 }
2899
2900// for the case where we have an 'exposed' smart pointer:
2901 if (!pyobj->IsSmart() && Cppyy::IsSubtype(oisa, fSmartPtrType)) {
2902 // calculate offset between formal and actual arguments
2903 para.fValue.fVoidp = pyobj->GetObject();
2904 if (oisa != fSmartPtrType) {
2905 para.fValue.fIntPtr += Cppyy::GetBaseOffset(
2906 oisa, fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */);
2907 }
2908
2909 // set pointer (may be null) and declare success
2910 para.fTypeCode = typeCode;
2911 return true;
2912 }
2913
2914// The automatic conversion of ordinary obejcts to smart pointers is disabled
2915// for PyROOT because it can cause trouble with overload resolution. If a
2916// function has overloads for both ordinary objects and smart pointers, then
2917// the implicit conversion to smart pointers can result in the smart pointer
2918// overload being hit, even though there would be an overload for the regular
2919// object. Since PyROOT didn't have this feature before 6.32 anyway, disabling
2920// it was the safest option.
2921#if 0
2922// for the case where we have an ordinary object to convert
2923 if (!pyobj->IsSmart() && Cppyy::IsSubtype(oisa, fUnderlyingType)) {
2924 // create the relevant smart pointer and make the pyobject "smart"
2926 if (!CPPInstance_Check(pysmart)) {
2928 return false;
2929 }
2930
2931 // copy internals from the fresh smart object to the original, making it smart
2932 pyobj->GetObjectRaw() = pysmart->GetSmartObject();
2933 pyobj->SetSmart(CreateScopeProxy(fSmartPtrType)); //(PyObject*)Py_TYPE(pysmart));
2934 pyobj->PythonOwns();
2935 pysmart->CppOwns();
2937
2938 return true;
2939 }
2940#endif
2941
2942// final option, try mapping pointer types held (TODO: do not allow for non-const ref)
2943 if (pyobj->IsSmart() && Cppyy::IsSubtype(oisa, fUnderlyingType)) {
2944 para.fValue.fVoidp = ((CPPInstance*)pyobject)->GetSmartObject();
2945 para.fTypeCode = 'V';
2946 return true;
2947 }
2948
2949 return false;
2950}
2951
2952PyObject* CPyCppyy::SmartPtrConverter::FromMemory(void* address)
2953{
2954 if (!address || !fSmartPtrType)
2955 return nullptr;
2956
2957 return BindCppObjectNoCast(address, fSmartPtrType);
2958}
2959
2960
2961//----------------------------------------------------------------------------
2962namespace {
2963
2964// clang libcpp and gcc use the same structure (ptr, size)
2965#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2966struct faux_initlist
2967{
2968 typedef size_t size_type;
2969 typedef void* iterator;
2970 iterator _M_array;
2971 size_type _M_len;
2972};
2973#elif defined (_MSC_VER)
2974struct faux_initlist
2975{
2976 typedef char* iterator;
2977 iterator _M_array; // ie. _First;
2978 iterator _Last;
2979};
2980#else
2981#define NO_KNOWN_INITIALIZER_LIST 1
2982#endif
2983
2984} // unnamed namespace
2985
2986CPyCppyy::InitializerListConverter::InitializerListConverter(Cppyy::TCppType_t klass, std::string const &value_type)
2987
2988 : InstanceConverter{klass},
2989 fValueTypeName{value_type},
2990 fValueType{Cppyy::GetScope(value_type)},
2991 fValueSize{Cppyy::SizeOf(value_type)}
2992{
2993}
2994
2995CPyCppyy::InitializerListConverter::~InitializerListConverter()
2996{
2998 if (converter && converter->HasState()) delete converter;
2999 }
3000 if (fBuffer) Clear();
3001}
3002
3003void CPyCppyy::InitializerListConverter::Clear() {
3004 if (fValueType) {
3006#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
3007 for (faux_initlist::size_type i = 0; i < fake->_M_len; ++i) {
3008#elif defined (_MSC_VER)
3009 for (size_t i = 0; (fake->_M_array+i*fValueSize) != fake->_Last; ++i) {
3010#endif
3011 void* memloc = (char*)fake->_M_array + i*fValueSize;
3013 }
3014 }
3015
3017 fBuffer = nullptr;
3018}
3019
3020bool CPyCppyy::InitializerListConverter::SetArg(
3022{
3023#ifdef NO_KNOWN_INITIALIZER_LIST
3024 return false;
3025#else
3026 if (fBuffer) Clear();
3027
3028// convert the given argument to an initializer list temporary; this is purely meant
3029// to be a syntactic thing, so only _python_ sequences are allowed; bound C++ proxies
3030// (likely explicitly created std::initializer_list, go through an instance converter
3032#if PY_VERSION_HEX >= 0x03000000
3034#else
3036#endif
3037 )
3038 return false;
3039
3041 return this->InstanceConverter::SetArg(pyobject, para, ctxt);
3042
3043 void* buf = nullptr;
3044 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', (int)fValueSize, buf, true);
3045 faux_initlist* fake = nullptr;
3046 size_t entries = 0;
3047 if (buf && buflen) {
3048 // dealing with an array here, pass on whole-sale
3050 fBuffer = (void*)fake;
3051 fake->_M_array = (faux_initlist::iterator)buf;
3052#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
3053 fake->_M_len = (faux_initlist::size_type)buflen;
3054#elif defined (_MSC_VER)
3055 fake->_Last = fake->_M_array+buflen*fValueSize;
3056#endif
3057 } else if (fValueSize) {
3058 // Remove any errors set by GetBuffer(); note that if the argument was an array
3059 // that failed to extract because of a type mismatch, the following will perform
3060 // a (rather inefficient) copy. No warning is issued b/c e.g. numpy doesn't do
3061 // so either.
3062 PyErr_Clear();
3063
3064 // can only construct empty lists, so use a fake initializer list
3065 size_t len = (size_t)PySequence_Size(pyobject);
3067 fBuffer = (void*)fake;
3068 fake->_M_array = (faux_initlist::iterator)((char*)fake+sizeof(faux_initlist));
3069#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
3070 fake->_M_len = (faux_initlist::size_type)len;
3071 for (faux_initlist::size_type i = 0; i < fake->_M_len; ++i) {
3072#elif defined (_MSC_VER)
3073 fake->_Last = fake->_M_array+len*fValueSize;
3074 for (size_t i = 0; (fake->_M_array+i*fValueSize) != fake->_Last; ++i) {
3075#endif
3077 bool convert_ok = false;
3078 if (item) {
3080 if (!converter) {
3081 if (CPPInstance_Check(item)) {
3082 // by convention, use byte copy
3083 memcpy((char*)fake->_M_array + i*fValueSize,
3084 ((CPPInstance*)item)->GetObject(), fValueSize);
3085 convert_ok = true;
3086 }
3087 } else {
3088 void* memloc = (char*)fake->_M_array + i*fValueSize;
3089 if (fValueType) {
3090 // we need to construct a default object for the constructor to assign into; this is
3091 // clunky, but the use of a copy constructor isn't much better as the Python object
3092 // need not be a C++ object
3094 if (memloc) entries += 1;
3095 else {
3097 "default ctor needed for initializer list of objects");
3098 }
3099 }
3100 if (memloc) {
3101 convert_ok = converter->ToMemory(item, memloc);
3102 }
3103 fConverters.emplace_back(converter);
3104 }
3105
3106
3107 Py_DECREF(item);
3108 } else
3109 PyErr_Format(PyExc_TypeError, "failed to get item %d from sequence", (int)i);
3110
3111 if (!convert_ok) {
3112#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
3113 fake->_M_len = (faux_initlist::size_type)entries;
3114#elif defined (_MSC_VER)
3115 fake->_Last = fake->_M_array+entries*fValueSize;
3116#endif
3117 Clear();
3118 return false;
3119 }
3120 }
3121 }
3122
3123 if (!fake) // no buffer and value size indeterminate
3124 return false;
3125
3126 para.fValue.fVoidp = (void*)fake;
3127 para.fTypeCode = 'V'; // means ptr that backend has to free after call
3128 return true;
3129#endif
3130}
3131
3132//----------------------------------------------------------------------------
3133bool CPyCppyy::NotImplementedConverter::SetArg(PyObject*, Parameter&, CallContext*)
3134{
3135// raise a NotImplemented exception to take a method out of overload resolution
3136 PyErr_SetString(PyExc_NotImplementedError, "this method cannot (yet) be called");
3137 return false;
3138}
3139
3140
3141//- helper to refactor some code from CreateConverter ------------------------
3143 const std::string& cpd, CPyCppyy::cdims_t dims, bool isConst, bool control)
3144{
3145 using namespace CPyCppyy;
3146 Converter* result = nullptr;
3147
3148 if (cpd == "**" || cpd == "*[]" || cpd == "&*")
3150 else if (cpd == "*&")
3152 else if (cpd == "*" && dims.ndim() == UNKNOWN_SIZE) {
3155 }
3156 else if (cpd == "&")
3157 result = new InstanceRefConverter(klass, isConst);
3158 else if (cpd == "&&")
3159 result = new InstanceMoveConverter(klass);
3160 else if (cpd == "[]" || dims)
3161 result = new InstanceArrayConverter(klass, dims, false);
3162 else if (cpd == "") // by value
3163 result = new InstanceConverter(klass, true);
3164
3165 return result;
3166}
3167
3168//- factories ----------------------------------------------------------------
3171{
3172// The matching of the fulltype to a converter factory goes through up to five levels:
3173// 1) full, exact match
3174// 2) match of decorated, unqualified type
3175// 3) accept const ref as by value
3176// 4) accept ref as pointer
3177// 5) generalized cases (covers basically all C++ classes)
3178//
3179// If all fails, void is used, which will generate a run-time warning when used.
3180
3181// an exactly matching converter is best
3182 ConvFactories_t::iterator h = gConvFactories.find(fullType);
3183 if (h != gConvFactories.end()) {
3184 return (h->second)(dims);
3185 }
3186
3187// resolve typedefs etc.
3188 const std::string& resolvedType = Cppyy::ResolveName(fullType);
3189
3190// a full, qualified matching converter is preferred
3191 if (resolvedType != fullType) {
3193 if (h != gConvFactories.end())
3194 return (h->second)(dims);
3195 }
3196
3197//-- nothing? ok, collect information about the type and possible qualifiers/decorators
3198 bool isConst = strncmp(resolvedType.c_str(), "const", 5) == 0;
3199 const std::string& cpd = TypeManip::compound(resolvedType);
3200 std::string realType = TypeManip::clean_type(resolvedType, false, true);
3201
3202// accept unqualified type (as python does not know about qualifiers)
3203 h = gConvFactories.find((isConst ? "const " : "") + realType + cpd);
3204 if (h != gConvFactories.end())
3205 return (h->second)(dims);
3206
3207// drop const, as that is mostly meaningless to python (with the exception
3208// of c-strings, but those are specialized in the converter map)
3209 if (isConst) {
3210 h = gConvFactories.find(realType + cpd);
3211 if (h != gConvFactories.end())
3212 return (h->second)(dims);
3213 }
3214
3215//-- still nothing? try pointer instead of array (for builtins)
3216 if (cpd.compare(0, 3, "*[]") == 0) {
3217 // special case, array of pointers
3218 h = gConvFactories.find(realType + " ptr");
3219 if (h != gConvFactories.end()) {
3220 // upstream treats the pointer type as the array element type, but that pointer is
3221 // treated as a low-level view as well, unless it's a void*/char* so adjust the dims
3222 if (realType != "void" && realType != "char") {
3223 dim_t newdim = dims.ndim() == UNKNOWN_SIZE ? 2 : dims.ndim()+1;
3225 // TODO: sometimes the array size is known and can thus be verified; however,
3226 // currently the meta layer does not provide this information
3227 newdims[0] = dims ? dims[0] : UNKNOWN_SIZE; // the array
3228 newdims[1] = UNKNOWN_SIZE; // the pointer
3229 if (2 < newdim) {
3230 for (int i = 2; i < (newdim-1); ++i)
3231 newdims[i] = dims[i-1];
3232 }
3233
3234 return (h->second)(newdims);
3235 }
3236 return (h->second)(dims);
3237 }
3238
3239 } else if (!cpd.empty() && (std::string::size_type)std::count(cpd.begin(), cpd.end(), '*') == cpd.size()) {
3240 // simple array; set or resize as necessary
3241 h = gConvFactories.find(realType + " ptr");
3242 if (h != gConvFactories.end())
3243 return (h->second)((!dims && 1 < cpd.size()) ? dims_t(cpd.size()) : dims);
3244
3245 } else if (2 <= cpd.size() && (std::string::size_type)std::count(cpd.begin(), cpd.end(), '[') == cpd.size() / 2) {
3246 // fixed array, dims will have size if available
3247 h = gConvFactories.find(realType + " ptr");
3248 if (h != gConvFactories.end())
3249 return (h->second)(dims);
3250 }
3251
3252//-- special case: initializer list
3253 if (realType.compare(0, 16, "initializer_list") == 0) {
3254 // get the type of the list and create a converter (TODO: get hold of value_type?)
3255 auto pos = realType.find('<');
3256 std::string value_type = realType.substr(pos+1, realType.size()-pos-2);
3257 return new InitializerListConverter(Cppyy::GetScope(realType), value_type);
3258 }
3259
3260//-- still nothing? use a generalized converter
3261 bool control = cpd == "&" || isConst;
3262
3263//-- special case: std::function
3264 auto pos = resolvedType.find("function<");
3265 if (pos == 0 /* no std:: */ || pos == 5 /* with std:: */ ||
3266 pos == 6 /* const no std:: */ || pos == 11 /* const with std:: */ ) {
3267
3268 // get actual converter for normal passing
3271
3272 if (cnv) {
3273 // get the type of the underlying (TODO: use target_type?)
3274 auto pos1 = resolvedType.find("(", pos+9);
3275 auto pos2 = resolvedType.rfind(")");
3276 if (pos1 != std::string::npos && pos2 != std::string::npos) {
3277 auto sz1 = pos1-pos-9;
3278 if (resolvedType[pos+9+sz1-1] == ' ') sz1 -= 1;
3279
3280 return new StdFunctionConverter(cnv,
3281 resolvedType.substr(pos+9, sz1), resolvedType.substr(pos1, pos2-pos1+1));
3282 } else if (cnv->HasState())
3283 delete cnv;
3284 }
3285 }
3286
3287// converters for known C++ classes and default (void*)
3288 Converter* result = nullptr;
3290 Cppyy::TCppType_t raw{0};
3291 if (Cppyy::GetSmartPtrInfo(realType, &raw, nullptr)) {
3292 if (cpd == "") {
3293 result = new SmartPtrConverter(klass, raw, control);
3294 } else if (cpd == "&") {
3295 result = new SmartPtrConverter(klass, raw);
3296 } else if (cpd == "*" && dims.ndim() == UNKNOWN_SIZE) {
3297 result = new SmartPtrConverter(klass, raw, control, true);
3298 }
3299 }
3300
3301 if (!result) {
3302 // CLING WORKAROUND -- special case for STL iterators
3304 static STLIteratorConverter c;
3305 result = &c;
3306 } else
3307 // -- CLING WORKAROUND
3309 }
3310 } else {
3311 std::smatch sm;
3312 if (std::regex_search(resolvedType, sm, s_fnptr)) {
3313 // this is a function pointer
3314 auto pos1 = sm.position(0);
3315 auto pos2 = resolvedType.rfind(')');
3316 result = new FunctionPointerConverter(
3317 resolvedType.substr(0, pos1), resolvedType.substr(pos1+sm.length(), pos2-1));
3318 }
3319 }
3320
3321 if (!result && cpd == "&&") {
3322 // for builtin, can use const-ref for r-ref
3323 h = gConvFactories.find("const " + realType + "&");
3324 if (h != gConvFactories.end())
3325 return (h->second)(dims);
3326 // else, unhandled moves
3327 result = new NotImplementedConverter();
3328 }
3329
3330 if (!result && h != gConvFactories.end())
3331 // converter factory available, use it to create converter
3332 result = (h->second)(dims);
3333 else if (!result) {
3334 // default to something reasonable, assuming "user knows best"
3335 if (cpd.size() == 2 && cpd != "&&") // "**", "*[]", "*&"
3336 result = new VoidPtrPtrConverter(dims.ndim());
3337 else if (!cpd.empty())
3338 result = new VoidArrayConverter(); // "user knows best"
3339 else
3340 result = new NotImplementedConverter(); // fails on use
3341 }
3342
3343 return result;
3344}
3345
3346//----------------------------------------------------------------------------
3349{
3350 if (p && p->HasState())
3351 delete p; // state-less converters are always shared
3352}
3353
3354//----------------------------------------------------------------------------
3356bool CPyCppyy::RegisterConverter(const std::string& name, cf_t fac)
3357{
3358// register a custom converter
3359 auto f = gConvFactories.find(name);
3360 if (f != gConvFactories.end())
3361 return false;
3362
3364 return true;
3365}
3366
3367//----------------------------------------------------------------------------
3369bool CPyCppyy::RegisterConverterAlias(const std::string& name, const std::string& target)
3370{
3371// register a custom converter that is a reference to an existing converter
3372 auto f = gConvFactories.find(name);
3373 if (f != gConvFactories.end())
3374 return false;
3375
3376 auto t = gConvFactories.find(target);
3377 if (t == gConvFactories.end())
3378 return false;
3379
3380 gConvFactories[name] = t->second;
3381 return true;
3382}
3383
3384//----------------------------------------------------------------------------
3386bool CPyCppyy::UnregisterConverter(const std::string& name)
3387{
3388// remove a custom converter
3389 auto f = gConvFactories.find(name);
3390 if (f != gConvFactories.end()) {
3391 gConvFactories.erase(f);
3392 return true;
3393 }
3394 return false;
3395}
3396
3397
3398//----------------------------------------------------------------------------
3399namespace {
3400
3401using namespace CPyCppyy;
3402
3403inline static
3404std::string::size_type dims2stringsz(cdims_t d) {
3405 return (d && d.ndim() != UNKNOWN_SIZE) ? d[0] : std::string::npos;
3406}
3407
3408#define STRINGVIEW "basic_string_view<char,char_traits<char> >"
3409#define WSTRING1 "std::basic_string<wchar_t>"
3410#define WSTRING2 "std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t>>"
3411
3412//-- aliasing special case: C complex (is binary compatible with C++ std::complex)
3413#ifndef _WIN32
3414#define CCOMPLEX_D "_Complex double"
3415#define CCOMPLEX_F "_Complex float"
3416#else
3417#define CCOMPLEX_D "_C_double_complex"
3418#define CCOMPLEX_F "_C_float_complex"
3419#endif
3420
3421static struct InitConvFactories_t {
3422public:
3423 InitConvFactories_t() {
3424 // load all converter factories in the global map 'gConvFactories'
3426
3427 // factories for built-ins
3428 gf["bool"] = (cf_t)+[](cdims_t) { static BoolConverter c{}; return &c; };
3429 gf["const bool&"] = (cf_t)+[](cdims_t) { static ConstBoolRefConverter c{}; return &c; };
3430 gf["bool&"] = (cf_t)+[](cdims_t) { static BoolRefConverter c{}; return &c; };
3431 gf["char"] = (cf_t)+[](cdims_t) { static CharConverter c{}; return &c; };
3432 gf["const char&"] = (cf_t)+[](cdims_t) { static ConstCharRefConverter c{}; return &c; };
3433 gf["char&"] = (cf_t)+[](cdims_t) { static CharRefConverter c{}; return &c; };
3434 gf["signed char&"] = (cf_t)+[](cdims_t) { static SCharRefConverter c{}; return &c; };
3435 gf["unsigned char"] = (cf_t)+[](cdims_t) { static UCharConverter c{}; return &c; };
3436 gf["const unsigned char&"] = (cf_t)+[](cdims_t) { static ConstUCharRefConverter c{}; return &c; };
3437 gf["unsigned char&"] = (cf_t)+[](cdims_t) { static UCharRefConverter c{}; return &c; };
3438 gf["SCharAsInt"] = (cf_t)+[](cdims_t) { static SCharAsIntConverter c{}; return &c; };
3439 gf["UCharAsInt"] = (cf_t)+[](cdims_t) { static UCharAsIntConverter c{}; return &c; };
3440 gf["wchar_t"] = (cf_t)+[](cdims_t) { static WCharConverter c{}; return &c; };
3441 gf["char16_t"] = (cf_t)+[](cdims_t) { static Char16Converter c{}; return &c; };
3442 gf["char32_t"] = (cf_t)+[](cdims_t) { static Char32Converter c{}; return &c; };
3443 gf["wchar_t&"] = (cf_t)+[](cdims_t) { static WCharRefConverter c{}; return &c; };
3444 gf["char16_t&"] = (cf_t)+[](cdims_t) { static Char16RefConverter c{}; return &c; };
3445 gf["char32_t&"] = (cf_t)+[](cdims_t) { static Char32RefConverter c{}; return &c; };
3446 gf["int8_t"] = (cf_t)+[](cdims_t) { static Int8Converter c{}; return &c; };
3447 gf["const int8_t&"] = (cf_t)+[](cdims_t) { static ConstInt8RefConverter c{}; return &c; };
3448 gf["int8_t&"] = (cf_t)+[](cdims_t) { static Int8RefConverter c{}; return &c; };
3449 gf["uint8_t"] = (cf_t)+[](cdims_t) { static UInt8Converter c{}; return &c; };
3450 gf["const uint8_t&"] = (cf_t)+[](cdims_t) { static ConstUInt8RefConverter c{}; return &c; };
3451 gf["uint8_t&"] = (cf_t)+[](cdims_t) { static UInt8RefConverter c{}; return &c; };
3452 gf["short"] = (cf_t)+[](cdims_t) { static ShortConverter c{}; return &c; };
3453 gf["const short&"] = (cf_t)+[](cdims_t) { static ConstShortRefConverter c{}; return &c; };
3454 gf["short&"] = (cf_t)+[](cdims_t) { static ShortRefConverter c{}; return &c; };
3455 gf["unsigned short"] = (cf_t)+[](cdims_t) { static UShortConverter c{}; return &c; };
3456 gf["const unsigned short&"] = (cf_t)+[](cdims_t) { static ConstUShortRefConverter c{}; return &c; };
3457 gf["unsigned short&"] = (cf_t)+[](cdims_t) { static UShortRefConverter c{}; return &c; };
3458 gf["int"] = (cf_t)+[](cdims_t) { static IntConverter c{}; return &c; };
3459 gf["int&"] = (cf_t)+[](cdims_t) { static IntRefConverter c{}; return &c; };
3460 gf["const int&"] = (cf_t)+[](cdims_t) { static ConstIntRefConverter c{}; return &c; };
3461 gf["unsigned int"] = (cf_t)+[](cdims_t) { static UIntConverter c{}; return &c; };
3462 gf["const unsigned int&"] = (cf_t)+[](cdims_t) { static ConstUIntRefConverter c{}; return &c; };
3463 gf["unsigned int&"] = (cf_t)+[](cdims_t) { static UIntRefConverter c{}; return &c; };
3464 gf["long"] = (cf_t)+[](cdims_t) { static LongConverter c{}; return &c; };
3465 gf["long&"] = (cf_t)+[](cdims_t) { static LongRefConverter c{}; return &c; };
3466 gf["const long&"] = (cf_t)+[](cdims_t) { static ConstLongRefConverter c{}; return &c; };
3467 gf["unsigned long"] = (cf_t)+[](cdims_t) { static ULongConverter c{}; return &c; };
3468 gf["const unsigned long&"] = (cf_t)+[](cdims_t) { static ConstULongRefConverter c{}; return &c; };
3469 gf["unsigned long&"] = (cf_t)+[](cdims_t) { static ULongRefConverter c{}; return &c; };
3470 gf["long long"] = (cf_t)+[](cdims_t) { static LLongConverter c{}; return &c; };
3471 gf["const long long&"] = (cf_t)+[](cdims_t) { static ConstLLongRefConverter c{}; return &c; };
3472 gf["long long&"] = (cf_t)+[](cdims_t) { static LLongRefConverter c{}; return &c; };
3473 gf["unsigned long long"] = (cf_t)+[](cdims_t) { static ULLongConverter c{}; return &c; };
3474 gf["const unsigned long long&"] = (cf_t)+[](cdims_t) { static ConstULLongRefConverter c{}; return &c; };
3475 gf["unsigned long long&"] = (cf_t)+[](cdims_t) { static ULLongRefConverter c{}; return &c; };
3476
3477 gf["float"] = (cf_t)+[](cdims_t) { static FloatConverter c{}; return &c; };
3478 gf["const float&"] = (cf_t)+[](cdims_t) { static ConstFloatRefConverter c{}; return &c; };
3479 gf["float&"] = (cf_t)+[](cdims_t) { static FloatRefConverter c{}; return &c; };
3480 gf["double"] = (cf_t)+[](cdims_t) { static DoubleConverter c{}; return &c; };
3481 gf["double&"] = (cf_t)+[](cdims_t) { static DoubleRefConverter c{}; return &c; };
3482 gf["const double&"] = (cf_t)+[](cdims_t) { static ConstDoubleRefConverter c{}; return &c; };
3483 gf["long double"] = (cf_t)+[](cdims_t) { static LDoubleConverter c{}; return &c; };
3484 gf["const long double&"] = (cf_t)+[](cdims_t) { static ConstLDoubleRefConverter c{}; return &c; };
3485 gf["long double&"] = (cf_t)+[](cdims_t) { static LDoubleRefConverter c{}; return &c; };
3486 gf["std::complex<double>"] = (cf_t)+[](cdims_t) { return new ComplexDConverter{}; };
3487 gf["const std::complex<double>&"] = (cf_t)+[](cdims_t) { return new ComplexDConverter{}; };
3488 gf["void"] = (cf_t)+[](cdims_t) { static VoidConverter c{}; return &c; };
3489
3490 // pointer/array factories
3491 gf["bool ptr"] = (cf_t)+[](cdims_t d) { return new BoolArrayConverter{d}; };
3492 gf["signed char ptr"] = (cf_t)+[](cdims_t d) { return new SCharArrayConverter{d}; };
3493 gf["signed char**"] = (cf_t)+[](cdims_t) { return new SCharArrayConverter{{UNKNOWN_SIZE, UNKNOWN_SIZE}}; };
3494 gf["const unsigned char*"] = (cf_t)+[](cdims_t d) { return new UCharArrayConverter{d}; };
3495 gf["unsigned char ptr"] = (cf_t)+[](cdims_t d) { return new UCharArrayConverter{d}; };
3496 gf["SCharAsInt*"] = gf["signed char ptr"];
3497 gf["SCharAsInt[]"] = gf["signed char ptr"];
3498 gf["UCharAsInt*"] = gf["unsigned char ptr"];
3499 gf["UCharAsInt[]"] = gf["unsigned char ptr"];
3500#if __cplusplus > 201402L
3501 gf["std::byte ptr"] = (cf_t)+[](cdims_t d) { return new ByteArrayConverter{d}; };
3502#endif
3503 gf["int8_t ptr"] = (cf_t)+[](cdims_t d) { return new Int8ArrayConverter{d}; };
3504 gf["uint8_t ptr"] = (cf_t)+[](cdims_t d) { return new UInt8ArrayConverter{d}; };
3505 gf["short ptr"] = (cf_t)+[](cdims_t d) { return new ShortArrayConverter{d}; };
3506 gf["unsigned short ptr"] = (cf_t)+[](cdims_t d) { return new UShortArrayConverter{d}; };
3507 gf["int ptr"] = (cf_t)+[](cdims_t d) { return new IntArrayConverter{d}; };
3508 gf["unsigned int ptr"] = (cf_t)+[](cdims_t d) { return new UIntArrayConverter{d}; };
3509 gf["long ptr"] = (cf_t)+[](cdims_t d) { return new LongArrayConverter{d}; };
3510 gf["unsigned long ptr"] = (cf_t)+[](cdims_t d) { return new ULongArrayConverter{d}; };
3511 gf["long long ptr"] = (cf_t)+[](cdims_t d) { return new LLongArrayConverter{d}; };
3512 gf["unsigned long long ptr"] = (cf_t)+[](cdims_t d) { return new ULLongArrayConverter{d}; };
3513 gf["float ptr"] = (cf_t)+[](cdims_t d) { return new FloatArrayConverter{d}; };
3514 gf["double ptr"] = (cf_t)+[](cdims_t d) { return new DoubleArrayConverter{d}; };
3515 gf["long double ptr"] = (cf_t)+[](cdims_t d) { return new LDoubleArrayConverter{d}; };
3516 gf["std::complex<float> ptr"] = (cf_t)+[](cdims_t d) { return new ComplexFArrayConverter{d}; };
3517 gf["std::complex<double> ptr"] = (cf_t)+[](cdims_t d) { return new ComplexDArrayConverter{d}; };
3518 gf["void*"] = (cf_t)+[](cdims_t d) { return new VoidArrayConverter{(bool)d}; };
3519
3520 // aliases
3521 gf["signed char"] = gf["char"];
3522 gf["const signed char&"] = gf["const char&"];
3523#if __cplusplus > 201402L
3524 gf["std::byte"] = gf["uint8_t"];
3525 gf["byte"] = gf["uint8_t"];
3526 gf["const std::byte&"] = gf["const uint8_t&"];
3527 gf["const byte&"] = gf["const uint8_t&"];
3528 gf["std::byte&"] = gf["uint8_t&"];
3529 gf["byte&"] = gf["uint8_t&"];
3530#endif
3531 gf["std::int8_t"] = gf["int8_t"];
3532 gf["const std::int8_t&"] = gf["const int8_t&"];
3533 gf["std::int8_t&"] = gf["int8_t&"];
3534 gf["std::uint8_t"] = gf["uint8_t"];
3535 gf["const std::uint8_t&"] = gf["const uint8_t&"];
3536 gf["std::uint8_t&"] = gf["uint8_t&"];
3537 gf["internal_enum_type_t"] = gf["int"];
3538 gf["internal_enum_type_t&"] = gf["int&"];
3539 gf["const internal_enum_type_t&"] = gf["const int&"];
3540 gf["internal_enum_type_t ptr"] = gf["int ptr"];
3541#ifdef _WIN32
3542 gf["__int64"] = gf["long long"];
3543 gf["const __int64&"] = gf["const long long&"];
3544 gf["__int64&"] = gf["long long&"];
3545 gf["__int64 ptr"] = gf["long long ptr"];
3546 gf["unsigned __int64"] = gf["unsigned long long"];
3547 gf["const unsigned __int64&"] = gf["const unsigned long long&"];
3548 gf["unsigned __int64&"] = gf["unsigned long long&"];
3549 gf["unsigned __int64 ptr"] = gf["unsigned long long ptr"];
3550#endif
3551 gf[CCOMPLEX_D] = gf["std::complex<double>"];
3552 gf["const " CCOMPLEX_D "&"] = gf["const std::complex<double>&"];
3553 gf[CCOMPLEX_F " ptr"] = gf["std::complex<float> ptr"];
3554 gf[CCOMPLEX_D " ptr"] = gf["std::complex<double> ptr"];
3555
3556 // factories for special cases
3557 gf["TString"] = (cf_t)+[](cdims_t) { return new TStringConverter{}; };
3558 gf["TString&"] = gf["TString"];
3559 gf["const TString&"] = gf["TString"];
3560 gf["nullptr_t"] = (cf_t)+[](cdims_t) { static NullptrConverter c{}; return &c;};
3561 gf["const char*"] = (cf_t)+[](cdims_t) { return new CStringConverter{}; };
3562 gf["const signed char*"] = gf["const char*"];
3563 gf["const char*&&"] = gf["const char*"];
3564 gf["const char[]"] = (cf_t)+[](cdims_t) { return new CStringConverter{}; };
3565 gf["char*"] = (cf_t)+[](cdims_t d) { return new NonConstCStringConverter{dims2stringsz(d)}; };
3566 gf["char[]"] = (cf_t)+[](cdims_t d) { return new NonConstCStringArrayConverter{d, true}; };
3567 gf["signed char*"] = gf["char*"];
3568 gf["wchar_t*"] = (cf_t)+[](cdims_t) { return new WCStringConverter{}; };
3569 gf["char16_t*"] = (cf_t)+[](cdims_t) { return new CString16Converter{}; };
3570 gf["char16_t[]"] = (cf_t)+[](cdims_t d) { return new CString16Converter{dims2stringsz(d)}; };
3571 gf["char32_t*"] = (cf_t)+[](cdims_t) { return new CString32Converter{}; };
3572 gf["char32_t[]"] = (cf_t)+[](cdims_t d) { return new CString32Converter{dims2stringsz(d)}; };
3573 // TODO: the following are handled incorrectly upstream (char16_t** where char16_t* intended)?!
3574 gf["char16_t**"] = gf["char16_t*"];
3575 gf["char32_t**"] = gf["char32_t*"];
3576 gf["const char**"] = (cf_t)+[](cdims_t) { return new CStringArrayConverter{{UNKNOWN_SIZE, UNKNOWN_SIZE}, false}; };
3577 gf["char**"] = gf["const char**"];
3578 gf["const char*[]"] = (cf_t)+[](cdims_t d) { return new CStringArrayConverter{d, false}; };
3579 gf["char*[]"] = (cf_t)+[](cdims_t d) { return new NonConstCStringArrayConverter{d, false}; };
3580 gf["char ptr"] = gf["char*[]"];
3581 gf["std::string"] = (cf_t)+[](cdims_t) { return new STLStringConverter{}; };
3582 gf["const std::string&"] = gf["std::string"];
3583 gf["string"] = gf["std::string"];
3584 gf["const string&"] = gf["std::string"];
3585 gf["std::string&&"] = (cf_t)+[](cdims_t) { return new STLStringMoveConverter{}; };
3586 gf["string&&"] = gf["std::string&&"];
3587#if __cplusplus > 201402L
3588 gf["std::string_view"] = (cf_t)+[](cdims_t) { return new STLStringViewConverter{}; };
3589 gf[STRINGVIEW] = gf["std::string_view"];
3590 gf["std::string_view&"] = gf["std::string_view"];
3591 gf["const std::string_view&"] = gf["std::string_view"];
3592 gf["const " STRINGVIEW "&"] = gf["std::string_view"];
3593#endif
3594 gf["std::wstring"] = (cf_t)+[](cdims_t) { return new STLWStringConverter{}; };
3595 gf[WSTRING1] = gf["std::wstring"];
3596 gf[WSTRING2] = gf["std::wstring"];
3597 gf["const std::wstring&"] = gf["std::wstring"];
3598 gf["const " WSTRING1 "&"] = gf["std::wstring"];
3599 gf["const " WSTRING2 "&"] = gf["std::wstring"];
3600 gf["void*&"] = (cf_t)+[](cdims_t) { static VoidPtrRefConverter c{}; return &c; };
3601 gf["void**"] = (cf_t)+[](cdims_t d) { return new VoidPtrPtrConverter{d}; };
3602 gf["void ptr"] = gf["void**"];
3603 gf["PyObject*"] = (cf_t)+[](cdims_t) { static PyObjectConverter c{}; return &c; };
3604 gf["_object*"] = gf["PyObject*"];
3605 gf["FILE*"] = (cf_t)+[](cdims_t) { return new VoidArrayConverter{}; };
3606 }
3608
3609} // 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
#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 * 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
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)
static std::regex s_fnptr("\\‍(:*\\*&*\\‍)")
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
PyObject_HEAD void * pffi_type
union CPyCppyy_tagPyCArgObject::@202 value
TMarker m
Definition textangle.C:8
TLine l
Definition textangle.C:4