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