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