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 <limits.h>
20#include <stddef.h> // for ptrdiff_t
21#include <string.h>
22#include <array>
23#include <utility>
24#include <sstream>
25#if __cplusplus > 201402L
26#include <cstddef>
27#endif
28#include <string_view>
29
30#define UNKNOWN_SIZE -1
31#define UNKNOWN_ARRAY_SIZE -2
32
33
34//- data _____________________________________________________________________
35namespace CPyCppyy {
36
37// factories
38 typedef std::map<std::string, cf_t> ConvFactories_t;
41
42}
43
44#if PY_VERSION_HEX < 0x03000000
45const size_t MOVE_REFCOUNT_CUTOFF = 1;
46#else
47// p3 has at least 2 ref-counts, as contrary to p2, it will create a descriptor
48// copy for the method holding self in the case of __init__; but there can also
49// be a reference held by the frame object, which is indistinguishable from a
50// local variable reference, so the cut-off has to remain 2.
51const size_t MOVE_REFCOUNT_CUTOFF = 2;
52#endif
53
54//- pretend-ctypes helpers ---------------------------------------------------
55struct CPyCppyy_tagCDataObject { // non-public (but stable)
56 PyObject_HEAD
57 char* b_ptr;
59};
60
61struct CPyCppyy_tagPyCArgObject { // not public (but stable; note that older
62 PyObject_HEAD // Pythons protect 'D' with HAVE_LONG_LONG)
63 void* pffi_type;
64 char tag;
65 union { // for convenience, kept only relevant vals
66 long long q;
67 long double D;
68 void *p;
71};
72
73// indices of ctypes types into the array caches (not that c_complex does not
74// exist as a type in ctypes)
75#define ct_c_bool 0
76#define ct_c_char 1
77#define ct_c_shar 1
78#define ct_c_wchar 2
79#define ct_c_byte 3
80#define ct_c_int8 3
81#define ct_c_ubyte 4
82#define ct_c_uchar 4
83#define ct_c_uint8 4
84#define ct_c_short 5
85#define ct_c_ushort 6
86#define ct_c_uint16 7
87#define ct_c_int 8
88#define ct_c_uint 9
89#define ct_c_uint32 10
90#define ct_c_long 11
91#define ct_c_ulong 12
92#define ct_c_longlong 13
93#define ct_c_ulonglong 14
94#define ct_c_float 15
95#define ct_c_double 16
96#define ct_c_longdouble 17
97#define ct_c_char_p 18
98#define ct_c_wchar_p 19
99#define ct_c_void_p 20
100#define ct_c_complex 21
101#define NTYPES 22
102
103static std::array<const char*, NTYPES> gCTypesNames = {
104 "c_bool", "c_char", "c_wchar", "c_byte", "c_ubyte", "c_short", "c_ushort", "c_uint16",
105 "c_int", "c_uint", "c_uint32", "c_long", "c_ulong", "c_longlong", "c_ulonglong",
106 "c_float", "c_double", "c_longdouble",
107 "c_char_p", "c_wchar_p", "c_void_p", "c_complex" };
108static std::array<PyTypeObject*, NTYPES> gCTypesTypes;
109static std::array<PyTypeObject*, NTYPES> gCTypesPtrTypes;
110
111// Both GetCTypesType and GetCTypesPtrType, rely on the ctypes module itself
112// caching the types (thus also making them unique), so no ref-count is needed.
113// Further, by keeping a ref-count on the module, it won't be off-loaded until
114// the 2nd cleanup cycle.
115static PyTypeObject* GetCTypesType(int nidx)
116{
117 static PyObject* ctmod = PyImport_ImportModule("ctypes"); // ref-count kept
118 if (!ctmod) {
119 PyErr_Clear();
120 return nullptr;
121 }
122 PyTypeObject* ct_t = gCTypesTypes[nidx];
123 if (!ct_t) {
124 ct_t = (PyTypeObject*)PyObject_GetAttrString(ctmod, gCTypesNames[nidx]);
125 if (!ct_t) PyErr_Clear();
126 else {
127 gCTypesTypes[nidx] = ct_t;
128 Py_DECREF(ct_t);
129 }
130 }
131 return ct_t;
132}
133
134static PyTypeObject* GetCTypesPtrType(int nidx)
135{
136 static PyObject* ctmod = PyImport_ImportModule("ctypes"); // ref-count kept
137 if (!ctmod) {
138 PyErr_Clear();
139 return nullptr;
140 }
141 PyTypeObject* cpt_t = gCTypesPtrTypes[nidx];
142 if (!cpt_t) {
143 if (strcmp(gCTypesNames[nidx], "c_char") == 0) {
144 cpt_t = (PyTypeObject*)PyObject_GetAttrString(ctmod, "c_char_p");
145 } else {
146 PyObject* ct_t = (PyObject*)GetCTypesType(nidx);
147 if (ct_t) {
148 PyObject* ptrcreat = PyObject_GetAttrString(ctmod, "POINTER");
149 cpt_t = (PyTypeObject*)PyObject_CallFunctionObjArgs(ptrcreat, ct_t, NULL);
150 Py_DECREF(ptrcreat);
151 }
152 }
153 if (cpt_t) {
154 gCTypesPtrTypes[nidx] = cpt_t;
155 Py_DECREF(cpt_t);
156 }
157 }
158 return cpt_t;
159}
160
161static bool IsPyCArgObject(PyObject* pyobject)
162{
163 static PyTypeObject* pycarg_type = nullptr;
164 if (!pycarg_type) {
165 PyObject* ctmod = PyImport_ImportModule("ctypes");
166 if (!ctmod) PyErr_Clear();
167 else {
168 PyTypeObject* ct_t = (PyTypeObject*)PyObject_GetAttrString(ctmod, "c_int");
169 PyObject* cobj = ct_t->tp_new(ct_t, nullptr, nullptr);
170 PyObject* byref = PyObject_GetAttrString(ctmod, "byref");
171 PyObject* pyptr = PyObject_CallFunctionObjArgs(byref, cobj, NULL);
172 Py_DECREF(byref); Py_DECREF(cobj); Py_DECREF(ct_t);
173 pycarg_type = Py_TYPE(pyptr); // static, no ref-count needed
174 Py_DECREF(pyptr);
175 Py_DECREF(ctmod);
176 }
177 }
178 return Py_TYPE(pyobject) == pycarg_type;
179}
180
181static bool IsCTypesArrayOrPointer(PyObject* pyobject)
182{
183 static PyTypeObject* cstgdict_type = nullptr;
184 if (!cstgdict_type) {
185 // get any pointer type to initialize the extended dictionary type
186 PyTypeObject* ct_int = GetCTypesType(ct_c_int);
187 if (ct_int && ct_int->tp_dict) {
188 cstgdict_type = Py_TYPE(ct_int->tp_dict);
189 }
190 }
191
192 PyTypeObject* pytype = Py_TYPE(pyobject);
193 if (pytype->tp_dict && Py_TYPE(pytype->tp_dict) == cstgdict_type)
194 return true;
195 return false;
196}
197
198
199//- helper to establish life lines -------------------------------------------
200static inline bool SetLifeLine(PyObject* holder, PyObject* target, intptr_t ref)
201{
202// set a lifeline from on the holder to the target, using the ref as label
203 if (!holder) return false;
204
205// 'ref' is expected to be the converter address or data memory location, so
206// that the combination of holder and ref is unique, but also identifiable for
207// reuse when the C++ side is being overwritten
208 std::ostringstream attr_name;
209 attr_name << "__" << ref;
210 auto attr_name_str = attr_name.str();
211 auto res = PyObject_SetAttrString(holder, attr_name_str.c_str(), target);
212 return res != -1;
213}
214
215//- helper to work with both CPPInstance and CPPExcInstance ------------------
217{
218 using namespace CPyCppyy;
219 if (CPPInstance_Check(pyobject))
220 return (CPPInstance*)pyobject;
221 if (CPPExcInstance_Check(pyobject))
222 return (CPPInstance*)((CPPExcInstance*)pyobject)->fCppInstance;
223
224#if PY_VERSION_HEX < 0x03090000
225// this is not a C++ proxy; allow custom cast to C++
226 PyObject* castobj = PyObject_CallMethodNoArgs(pyobject, PyStrings::gCastCpp);
227 if (castobj) {
228 if (CPPInstance_Check(castobj))
229 return (CPPInstance*)castobj;
230 Py_DECREF(castobj);
231 return nullptr;
232 }
233
234 PyErr_Clear();
235#endif
236
237 return nullptr;
238}
239
240
241//- custom helpers to check ranges -------------------------------------------
242static inline bool CPyCppyy_PyLong_AsBool(PyObject* pyobject)
243{
244// range-checking python integer to C++ bool conversion
245 long l = PyLong_AsLong(pyobject);
246// fail to pass float -> bool; the problem is rounding (0.1 -> 0 -> False)
247 if (!(l == 0|| l == 1) || PyFloat_Check(pyobject)) {
248 PyErr_SetString(PyExc_ValueError, "boolean value should be bool, or integer 1 or 0");
249 return (bool)-1;
250 }
251 return (bool)l;
252}
253
254static inline char CPyCppyy_PyText_AsChar(PyObject* pyobject) {
255// python string to C++ char conversion
256 return (char)CPyCppyy_PyText_AsString(pyobject)[0];
257}
258
259static inline uint8_t CPyCppyy_PyLong_AsUInt8(PyObject* pyobject)
260{
261// range-checking python integer to C++ uint8_t conversion (typically, an unsigned char)
262// prevent p2.7 silent conversions and do a range check
263 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
264 PyErr_SetString(PyExc_TypeError, "short int conversion expects an integer object");
265 return (uint8_t)-1;
266 }
267 long l = PyLong_AsLong(pyobject);
268 if (l < 0 || UCHAR_MAX < l) {
269 PyErr_Format(PyExc_ValueError, "integer %ld out of range for uint8_t", l);
270 return (uint8_t)-1;
271
272 }
273 return (uint8_t)l;
274}
275
276static inline int8_t CPyCppyy_PyLong_AsInt8(PyObject* pyobject)
277{
278// range-checking python integer to C++ int8_t conversion (typically, an signed char)
279// prevent p2.7 silent conversions and do a range check
280 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
281 PyErr_SetString(PyExc_TypeError, "short int conversion expects an integer object");
282 return (int8_t)-1;
283 }
284 long l = PyLong_AsLong(pyobject);
285 if (l < SCHAR_MIN || SCHAR_MAX < l) {
286 PyErr_Format(PyExc_ValueError, "integer %ld out of range for int8_t", l);
287 return (int8_t)-1;
288
289 }
290 return (int8_t)l;
291}
292
293static inline unsigned short CPyCppyy_PyLong_AsUShort(PyObject* pyobject)
294{
295// range-checking python integer to C++ unsigend short int conversion
296
297// prevent p2.7 silent conversions and do a range check
298 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
299 PyErr_SetString(PyExc_TypeError, "unsigned short conversion expects an integer object");
300 return (unsigned short)-1;
301 }
302 long l = PyLong_AsLong(pyobject);
303 if (l < 0 || USHRT_MAX < l) {
304 PyErr_Format(PyExc_ValueError, "integer %ld out of range for unsigned short", l);
305 return (unsigned short)-1;
306
307 }
308 return (unsigned short)l;
309}
310
311static inline short CPyCppyy_PyLong_AsShort(PyObject* pyobject)
312{
313// range-checking python integer to C++ short int conversion
314// prevent p2.7 silent conversions and do a range check
315 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
316 PyErr_SetString(PyExc_TypeError, "short int conversion expects an integer object");
317 return (short)-1;
318 }
319 long l = PyLong_AsLong(pyobject);
320 if (l < SHRT_MIN || SHRT_MAX < l) {
321 PyErr_Format(PyExc_ValueError, "integer %ld out of range for short int", l);
322 return (short)-1;
323
324 }
325 return (short)l;
326}
327
328static inline int CPyCppyy_PyLong_AsStrictInt(PyObject* pyobject)
329{
330// strict python integer to C++ integer conversion
331
332// p2.7 and later silently converts floats to long, therefore require this
333// check; earlier pythons may raise a SystemError which should be avoided as
334// it is confusing
335 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
336 PyErr_SetString(PyExc_TypeError, "int/long conversion expects an integer object");
337 return -1;
338 }
339 long l = PyLong_AsLong(pyobject);
340 if (l < INT_MIN || INT_MAX < l) {
341 PyErr_Format(PyExc_ValueError, "integer %ld out of range for int", l);
342 return (int)-1;
343
344 }
345 return (int)l;
346}
347
348static inline long CPyCppyy_PyLong_AsStrictLong(PyObject* pyobject)
349{
350// strict python integer to C++ long integer conversion
351
352// prevent float -> long (see CPyCppyy_PyLong_AsStrictInt)
353 if (!(PyLong_Check(pyobject) || PyInt_Check(pyobject))) {
354 PyErr_SetString(PyExc_TypeError, "int/long conversion expects an integer object");
355 return (long)-1;
356 }
357 return (long)PyLong_AsLong(pyobject);
358}
359
360
361//- helper for pointer/array/reference conversions ---------------------------
362static inline bool CArraySetArg(PyObject* pyobject, CPyCppyy::Parameter& para, char tc, int size)
363{
364// general case of loading a C array pointer (void* + type code) as function argument
365 if (pyobject == CPyCppyy::gNullPtrObject)
366 para.fValue.fVoidp = nullptr;
367 else {
368 Py_ssize_t buflen = CPyCppyy::Utility::GetBuffer(pyobject, tc, size, para.fValue.fVoidp);
369 if (!buflen) {
370 // stuck here as it's the least common
371 if (CPyCppyy_PyLong_AsStrictInt(pyobject) == 0)
372 para.fValue.fVoidp = nullptr;
373 else {
374 PyErr_Format(PyExc_TypeError, // ValueError?
375 "could not convert argument to buffer or nullptr");
376 return false;
377 }
378 }
379 }
380 para.fTypeCode = 'p';
381 return true;
382}
383
384
385//- helper for implicit conversions ------------------------------------------
386static inline bool ConvertImplicit(Cppyy::TCppType_t klass,
387 PyObject* pyobject, CPyCppyy::Parameter& para, CPyCppyy::CallContext* ctxt)
388{
389 using namespace CPyCppyy;
390
391// filter out copy and move constructors
392 if (IsConstructor(ctxt->fFlags) && klass == ctxt->fCurScope && ctxt->GetSize() == 1)
393 return false;
394
395// only proceed if implicit conversions are allowed (in "round 2") or if the
396// argument is exactly a tuple or list, as these are the equivalent of
397// initializer lists and thus "syntax" not a conversion
398 if (!AllowImplicit(ctxt)) {
399 PyTypeObject* pytype = (PyTypeObject*)Py_TYPE(pyobject);
400 if (!(pytype == &PyList_Type || pytype == &PyTuple_Type)) {
401 if (!NoImplicit(ctxt)) ctxt->fFlags |= CallContext::kHaveImplicit;
402 return false;
403 }
404 }
405
406// exercise implicit conversion
407 PyObject* pyscope = CreateScopeProxy(klass);
408 if (!CPPScope_Check(pyscope)) {
409 Py_XDECREF(pyscope);
410 return false;
411 }
412
413// add a pseudo-keyword argument to prevent recursion
414 PyObject* kwds = PyDict_New();
415 PyDict_SetItem(kwds, PyStrings::gNoImplicit, Py_True);
416 PyObject* args = PyTuple_New(1);
417 Py_INCREF(pyobject); PyTuple_SET_ITEM(args, 0, pyobject);
418
419// call constructor of argument type to attempt implicit conversion
420 CPPInstance* pytmp = (CPPInstance*)PyObject_Call(pyscope, args, kwds);
421 if (!pytmp && PyTuple_CheckExact(pyobject)) {
422 // special case: allow implicit conversion from given set of arguments in tuple
423 PyErr_Clear();
424 PyDict_SetItem(kwds, PyStrings::gNoImplicit, Py_True); // was deleted
425 pytmp = (CPPInstance*)PyObject_Call(pyscope, pyobject, kwds);
426 }
427
428 Py_DECREF(args);
429 Py_DECREF(kwds);
430 Py_DECREF(pyscope);
431
432 if (pytmp) {
433 // implicit conversion succeeded!
434 ctxt->AddTemporary((PyObject*)pytmp);
435 para.fValue.fVoidp = pytmp->GetObject();
436 para.fTypeCode = 'V';
437 return true;
438 }
439
440 PyErr_Clear();
441 return false;
442}
443
444
445//- base converter implementation --------------------------------------------
447{
448 /* empty */
449}
450
451//----------------------------------------------------------------------------
453{
454// could happen if no derived class override
455 PyErr_SetString(PyExc_TypeError, "C++ type cannot be converted from memory");
456 return nullptr;
457}
458
459//----------------------------------------------------------------------------
461{
462// could happen if no derived class override
463 PyErr_SetString(PyExc_TypeError, "C++ type cannot be converted to memory");
464 return false;
465}
466
467
468//- helper macro's -----------------------------------------------------------
469#define CPPYY_IMPL_BASIC_CONVERTER(name, type, stype, ctype, F1, F2, tc) \
470bool CPyCppyy::name##Converter::SetArg( \
471 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \
472{ \
473/* convert <pyobject> to C++ 'type', set arg for call */ \
474 type val = (type)F2(pyobject); \
475 if (val == (type)-1 && PyErr_Occurred()) { \
476 static PyTypeObject* ctypes_type = nullptr; \
477 if (!ctypes_type) { \
478 PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0; \
479 PyErr_Fetch(&pytype, &pyvalue, &pytrace); \
480 ctypes_type = GetCTypesType(ct_##ctype); \
481 PyErr_Restore(pytype, pyvalue, pytrace); \
482 } \
483 if (Py_TYPE(pyobject) == ctypes_type) { \
484 PyErr_Clear(); \
485 val = *((type*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr); \
486 } else \
487 return false; \
488 } \
489 para.fValue.f##name = val; \
490 para.fTypeCode = tc; \
491 return true; \
492} \
493 \
494PyObject* CPyCppyy::name##Converter::FromMemory(void* address) \
495{ \
496 return F1((stype)*((type*)address)); \
497} \
498 \
499bool CPyCppyy::name##Converter::ToMemory(PyObject* value, void* address, \
500 PyObject* /* ctxt */) \
501{ \
502 type s = (type)F2(value); \
503 if (s == (type)-1 && PyErr_Occurred()) \
504 return false; \
505 *((type*)address) = (type)s; \
506 return true; \
507}
508
509//----------------------------------------------------------------------------
510static inline int ExtractChar(PyObject* pyobject, const char* tname, int low, int high)
511{
512 int lchar = -1;
513 if (CPyCppyy_PyText_Check(pyobject)) {
514 if (CPyCppyy_PyText_GET_SIZE(pyobject) == 1)
515 lchar = (int)CPyCppyy_PyText_AsChar(pyobject);
516 else
517 PyErr_Format(PyExc_ValueError, "%s expected, got string of size " PY_SSIZE_T_FORMAT,
518 tname, CPyCppyy_PyText_GET_SIZE(pyobject));
519 } else if (!PyFloat_Check(pyobject)) { // don't allow truncating conversion
520 lchar = (int)PyLong_AsLong(pyobject);
521 if (lchar == -1 && PyErr_Occurred())
522 ; // empty, as error already set
523 else if (!(low <= lchar && lchar <= high)) {
524 PyErr_Format(PyExc_ValueError,
525 "integer to character: value %d not in range [%d,%d]", lchar, low, high);
526 lchar = -1;
527 }
528 } else
529 PyErr_SetString(PyExc_TypeError, "char or small int type expected");
530
531 return lchar;
532}
533
534//----------------------------------------------------------------------------
535#define CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(name, ctype) \
536PyObject* CPyCppyy::name##RefConverter::FromMemory(void* ptr) \
537{ \
538/* convert a reference to int to Python through ctypes pointer object */ \
539 PyTypeObject* ctypes_type = GetCTypesType(ct_##ctype); \
540 if (!ctypes_type) { \
541 PyErr_SetString(PyExc_RuntimeError, "no ctypes available"); \
542 return nullptr; \
543 } \
544 PyObject* ref = ctypes_type->tp_new(ctypes_type, nullptr, nullptr); \
545 ((CPyCppyy_tagCDataObject*)ref)->b_ptr = (char*)ptr; \
546 ((CPyCppyy_tagCDataObject*)ref)->b_needsfree = 0; \
547 return ref; \
548}
549
550//----------------------------------------------------------------------------
551#define CPPYY_IMPL_BASIC_CONST_REFCONVERTER(name, type, ctype, F1) \
552bool CPyCppyy::Const##name##RefConverter::SetArg( \
553 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \
554{ \
555 type val = (type)F1(pyobject); \
556 if (val == (type)-1 && PyErr_Occurred()) \
557 return false; \
558 para.fValue.f##name = val; \
559 para.fRef = &para.fValue.f##name; \
560 para.fTypeCode = 'r'; \
561 return true; \
562} \
563CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(Const##name, ctype)
564
565//----------------------------------------------------------------------------
566#define CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(name, type, ctype, low, high)\
567bool CPyCppyy::Const##name##RefConverter::SetArg( \
568 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \
569{ \
570/* convert <pyobject> to C++ <<type>>, set arg for call, allow int -> char */\
571 type val = (type)ExtractChar(pyobject, #type, low, high); \
572 if (val == (type)-1 && PyErr_Occurred()) \
573 return false; \
574 para.fValue.fLong = val; \
575 para.fTypeCode = 'l'; \
576 return true; \
577} \
578CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(Const##name, ctype)
579
580
581//----------------------------------------------------------------------------
582#define CPPYY_IMPL_BASIC_CHAR_CONVERTER(name, type, low, high) \
583bool CPyCppyy::name##Converter::SetArg( \
584 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \
585{ \
586/* convert <pyobject> to C++ <<type>>, set arg for call, allow int -> char */\
587 long val = ExtractChar(pyobject, #type, low, high); \
588 if (val == -1 && PyErr_Occurred()) \
589 return false; \
590 para.fValue.fLong = val; \
591 para.fTypeCode = 'l'; \
592 return true; \
593} \
594 \
595PyObject* CPyCppyy::name##Converter::FromMemory(void* address) \
596{ \
597 return CPyCppyy_PyText_FromFormat("%c", *((type*)address)); \
598} \
599 \
600bool CPyCppyy::name##Converter::ToMemory(PyObject* value, void* address, \
601 PyObject* /* ctxt */) \
602{ \
603 Py_ssize_t len; \
604 const char* cstr = CPyCppyy_PyText_AsStringAndSize(value, &len); \
605 if (cstr) { \
606 if (len != 1) { \
607 PyErr_Format(PyExc_TypeError, #type" expected, got string of size %zd", len);\
608 return false; \
609 } \
610 *((type*)address) = (type)cstr[0]; \
611 } else { \
612 PyErr_Clear(); \
613 long l = PyLong_AsLong(value); \
614 if (l == -1 && PyErr_Occurred()) \
615 return false; \
616 if (!(low <= l && l <= high)) { \
617 PyErr_Format(PyExc_ValueError, \
618 "integer to character: value %ld not in range [%d,%d]", l, low, high);\
619 return false; \
620 } \
621 *((type*)address) = (type)l; \
622 } \
623 return true; \
624}
625
626
627//- converters for built-ins -------------------------------------------------
628CPPYY_IMPL_BASIC_CONVERTER(Long, long, long, c_long, PyLong_FromLong, CPyCppyy_PyLong_AsStrictLong, 'l')
629
630//----------------------------------------------------------------------------
631bool CPyCppyy::LongRefConverter::SetArg(
632 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
633{
634// convert <pyobject> to C++ long&, set arg for call
635#if PY_VERSION_HEX < 0x03000000
636 if (RefInt_CheckExact(pyobject)) {
637 para.fValue.fVoidp = (void*)&((PyIntObject*)pyobject)->ob_ival;
638 para.fTypeCode = 'V';
639 return true;
640 }
641#endif
642
643 if (Py_TYPE(pyobject) == GetCTypesType(ct_c_long)) {
644 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;
645 para.fTypeCode = 'V';
646 return true;
647 }
648
649 if (CArraySetArg(pyobject, para, 'l', sizeof(long))) {
650 para.fTypeCode = 'V';
651 return true;
652 }
653
654 PyErr_SetString(PyExc_TypeError, "use ctypes.c_long for pass-by-ref of longs");
655 return false;
656}
657
658//----------------------------------------------------------------------------
659CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(Char, char, c_char, CHAR_MIN, CHAR_MAX)
660CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(UChar, unsigned char, c_uchar, 0, UCHAR_MAX)
661
666CPPYY_IMPL_BASIC_CONST_REFCONVERTER(UShort, unsigned short, c_ushort, CPyCppyy_PyLong_AsUShort)
670CPPYY_IMPL_BASIC_CONST_REFCONVERTER(ULong, unsigned long, c_ulong, PyLongOrInt_AsULong)
671CPPYY_IMPL_BASIC_CONST_REFCONVERTER(LLong, Long64_t, c_longlong, PyLong_AsLongLong)
673
674//----------------------------------------------------------------------------
675bool CPyCppyy::IntRefConverter::SetArg(
676 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
677{
678// convert <pyobject> to C++ (pseudo)int&, set arg for call
679#if PY_VERSION_HEX < 0x03000000
680 if (RefInt_CheckExact(pyobject)) {
681 para.fValue.fVoidp = (void*)&((PyIntObject*)pyobject)->ob_ival;
682 para.fTypeCode = 'V';
683 return true;
684 }
685#endif
686
687#if PY_VERSION_HEX >= 0x02050000
688 if (Py_TYPE(pyobject) == GetCTypesType(ct_c_int)) {
689 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;
690 para.fTypeCode = 'V';
691 return true;
692 }
693#endif
694
695// alternate, pass pointer from buffer
696 Py_ssize_t buflen = Utility::GetBuffer(pyobject, 'i', sizeof(int), para.fValue.fVoidp);
697 if (para.fValue.fVoidp && buflen) {
698 para.fTypeCode = 'V';
699 return true;
700 };
701
702#if PY_VERSION_HEX < 0x02050000
703 PyErr_SetString(PyExc_TypeError, "use cppyy.Long for pass-by-ref of ints");
704#else
705 PyErr_SetString(PyExc_TypeError, "use ctypes.c_int for pass-by-ref of ints");
706#endif
707 return false;
708}
709
710//----------------------------------------------------------------------------
711#define CPPYY_IMPL_REFCONVERTER(name, ctype, type, code) \
712bool CPyCppyy::name##RefConverter::SetArg( \
713 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */) \
714{ \
715/* convert a reference to int to Python through ctypes pointer object */ \
716 if (Py_TYPE(pyobject) == GetCTypesType(ct_##ctype)) { \
717 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;\
718 para.fTypeCode = 'V'; \
719 return true; \
720 } \
721 bool res = CArraySetArg(pyobject, para, code, sizeof(type)); \
722 if (!res) { \
723 PyErr_SetString(PyExc_TypeError, "use ctypes."#ctype" for pass-by-ref of "#type);\
724 return false; \
725 } \
726 para.fTypeCode = 'V'; \
727 return res; \
728} \
729CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(name, ctype)
730
731CPPYY_IMPL_REFCONVERTER(Bool, c_bool, bool, '?');
732CPPYY_IMPL_REFCONVERTER(Char, c_char, char, 'b');
733CPPYY_IMPL_REFCONVERTER(WChar, c_wchar, wchar_t, 'u');
734CPPYY_IMPL_REFCONVERTER(Char16, c_uint16, char16_t, 'H');
735CPPYY_IMPL_REFCONVERTER(Char32, c_uint32, char32_t, 'I');
736CPPYY_IMPL_REFCONVERTER(SChar, c_byte, signed char, 'b');
737CPPYY_IMPL_REFCONVERTER(UChar, c_ubyte, unsigned char, 'B');
738CPPYY_IMPL_REFCONVERTER(Int8, c_int8, int8_t, 'b');
739CPPYY_IMPL_REFCONVERTER(UInt8, c_uint8, uint8_t, 'B');
740CPPYY_IMPL_REFCONVERTER(Short, c_short, short, 'h');
741CPPYY_IMPL_REFCONVERTER(UShort, c_ushort, unsigned short, 'H');
743CPPYY_IMPL_REFCONVERTER(UInt, c_uint, unsigned int, 'I');
745CPPYY_IMPL_REFCONVERTER(ULong, c_ulong, unsigned long, 'L');
746CPPYY_IMPL_REFCONVERTER(LLong, c_longlong, long long, 'q');
747CPPYY_IMPL_REFCONVERTER(ULLong, c_ulonglong, unsigned long long, 'Q');
748CPPYY_IMPL_REFCONVERTER(Float, c_float, float, 'f');
750CPPYY_IMPL_REFCONVERTER(LDouble, c_longdouble, LongDouble_t, 'D');
751
752
753//----------------------------------------------------------------------------
754// convert <pyobject> to C++ bool, allow int/long -> bool, set arg for call
756 Bool, bool, long, c_bool, PyInt_FromLong, CPyCppyy_PyLong_AsBool, 'l')
757
758//----------------------------------------------------------------------------
759CPPYY_IMPL_BASIC_CHAR_CONVERTER(Char, char, CHAR_MIN, CHAR_MAX)
760CPPYY_IMPL_BASIC_CHAR_CONVERTER(UChar, unsigned char, 0, UCHAR_MAX)
761
762PyObject* CPyCppyy::UCharAsIntConverter::FromMemory(void* address)
763{
764// special case to be used with arrays: return a Python int instead of str
765// (following the same convention as module array.array)
766 return PyInt_FromLong((long)*((unsigned char*)address));
767}
768
769//----------------------------------------------------------------------------
770bool CPyCppyy::WCharConverter::SetArg(
771 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
772{
773// convert <pyobject> to C++ <wchar_t>, set arg for call
774 if (!PyUnicode_Check(pyobject) || CPyCppyy_PyUnicode_GET_SIZE(pyobject) != 1) {
775 PyErr_SetString(PyExc_ValueError, "single wchar_t character expected");
776 return false;
777 }
778 wchar_t val;
779 Py_ssize_t res = CPyCppyy_PyUnicode_AsWideChar(pyobject, &val, 1);
780 if (res == -1)
781 return false;
782 para.fValue.fLong = (long)val;
783 para.fTypeCode = 'U';
784 return true;
785}
786
787PyObject* CPyCppyy::WCharConverter::FromMemory(void* address)
788{
789 return PyUnicode_FromWideChar((const wchar_t*)address, 1);
790}
791
792bool CPyCppyy::WCharConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
793{
794 if (!PyUnicode_Check(value) || CPyCppyy_PyUnicode_GET_SIZE(value) != 1) {
795 PyErr_SetString(PyExc_ValueError, "single wchar_t character expected");
796 return false;
797 }
798 wchar_t val;
800 if (res == -1)
801 return false;
802 *((wchar_t*)address) = val;
803 return true;
804}
805
806//----------------------------------------------------------------------------
807bool CPyCppyy::Char16Converter::SetArg(
808 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
809{
810// convert <pyobject> to C++ <char16_t>, set arg for call
811 if (!PyUnicode_Check(pyobject) || CPyCppyy_PyUnicode_GET_SIZE(pyobject) != 1) {
812 PyErr_SetString(PyExc_ValueError, "single char16_t character expected");
813 return false;
814 }
815
816 PyObject* bstr = PyUnicode_AsUTF16String(pyobject);
817 if (!bstr) return false;
818
819 char16_t val = *(char16_t*)(PyBytes_AS_STRING(bstr) + sizeof(char16_t) /*BOM*/);
820 Py_DECREF(bstr);
821 para.fValue.fLong = (long)val;
822 para.fTypeCode = 'U';
823 return true;
824}
825
826PyObject* CPyCppyy::Char16Converter::FromMemory(void* address)
827{
828 return PyUnicode_DecodeUTF16((const char*)address, sizeof(char16_t), nullptr, nullptr);
829}
830
831bool CPyCppyy::Char16Converter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
832{
833 if (!PyUnicode_Check(value) || CPyCppyy_PyUnicode_GET_SIZE(value) != 1) {
834 PyErr_SetString(PyExc_ValueError, "single char16_t character expected");
835 return false;
836 }
837
838 PyObject* bstr = PyUnicode_AsUTF16String(value);
839 if (!bstr) return false;
840
841 *((char16_t*)address) = *(char16_t*)(PyBytes_AS_STRING(bstr) + sizeof(char16_t) /*BOM*/);
842 Py_DECREF(bstr);
843 return true;
844}
845
846//----------------------------------------------------------------------------
847bool CPyCppyy::Char32Converter::SetArg(
848 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
849{
850// convert <pyobject> to C++ <char32_t>, set arg for call
851 if (!PyUnicode_Check(pyobject) || 2 < CPyCppyy_PyUnicode_GET_SIZE(pyobject)) {
852 PyErr_SetString(PyExc_ValueError, "single char32_t character expected");
853 return false;
854 }
855
856 PyObject* bstr = PyUnicode_AsUTF32String(pyobject);
857 if (!bstr) return false;
858
859 char32_t val = *(char32_t*)(PyBytes_AS_STRING(bstr) + sizeof(char32_t) /*BOM*/);
860 Py_DECREF(bstr);
861 para.fValue.fLong = (long)val;
862 para.fTypeCode = 'U';
863 return true;
864}
865
866PyObject* CPyCppyy::Char32Converter::FromMemory(void* address)
867{
868 return PyUnicode_DecodeUTF32((const char*)address, sizeof(char32_t), nullptr, nullptr);
869}
870
871bool CPyCppyy::Char32Converter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
872{
873 if (!PyUnicode_Check(value) || 2 < CPyCppyy_PyUnicode_GET_SIZE(value)) {
874 PyErr_SetString(PyExc_ValueError, "single char32_t character expected");
875 return false;
876 }
877
878 PyObject* bstr = PyUnicode_AsUTF32String(value);
879 if (!bstr) return false;
880
881 *((char32_t*)address) = *(char32_t*)(PyBytes_AS_STRING(bstr) + sizeof(char32_t) /*BOM*/);
882 Py_DECREF(bstr);
883 return true;
884}
885
886//----------------------------------------------------------------------------
888 Int8, int8_t, long, c_int8, PyInt_FromLong, CPyCppyy_PyLong_AsInt8, 'l')
890 UInt8, uint8_t, long, c_uint8, PyInt_FromLong, CPyCppyy_PyLong_AsUInt8, 'l')
892 Short, short, long, c_short, PyInt_FromLong, CPyCppyy_PyLong_AsShort, 'l')
894 UShort, unsigned short, long, c_ushort, PyInt_FromLong, CPyCppyy_PyLong_AsUShort, 'l')
896 Int, int, long, c_uint, PyInt_FromLong, CPyCppyy_PyLong_AsStrictInt, 'l')
897
898//----------------------------------------------------------------------------
899bool CPyCppyy::ULongConverter::SetArg(
900 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
901{
902// convert <pyobject> to C++ unsigned long, set arg for call
903 para.fValue.fULong = PyLongOrInt_AsULong(pyobject);
904 if (para.fValue.fULong == (unsigned long)-1 && PyErr_Occurred())
905 return false;
906 para.fTypeCode = 'L';
907 return true;
908}
909
910PyObject* CPyCppyy::ULongConverter::FromMemory(void* address)
911{
912// construct python object from C++ unsigned long read at <address>
913 return PyLong_FromUnsignedLong(*((unsigned long*)address));
914}
915
916bool CPyCppyy::ULongConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
917{
918// convert <value> to C++ unsigned long, write it at <address>
919 unsigned long u = PyLongOrInt_AsULong(value);
920 if (u == (unsigned long)-1 && PyErr_Occurred())
921 return false;
922 *((unsigned long*)address) = u;
923 return true;
924}
925
926//----------------------------------------------------------------------------
927PyObject* CPyCppyy::UIntConverter::FromMemory(void* address)
928{
929// construct python object from C++ unsigned int read at <address>
930 return PyLong_FromUnsignedLong(*((UInt_t*)address));
931}
932
933bool CPyCppyy::UIntConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
934{
935// convert <value> to C++ unsigned int, write it at <address>
937 if (u == (unsigned long)-1 && PyErr_Occurred())
938 return false;
939
940 if (u > (ULong_t)UINT_MAX) {
941 PyErr_SetString(PyExc_OverflowError, "value too large for unsigned int");
942 return false;
943 }
944
945 *((UInt_t*)address) = (UInt_t)u;
946 return true;
947}
948
949//- floating point converters ------------------------------------------------
951 Float, float, double, c_float, PyFloat_FromDouble, PyFloat_AsDouble, 'f')
953 Double, double, double, c_double, PyFloat_FromDouble, PyFloat_AsDouble, 'd')
954
956 LDouble, LongDouble_t, LongDouble_t, c_longdouble, PyFloat_FromDouble, PyFloat_AsDouble, 'g')
957
958CPyCppyy::ComplexDConverter::ComplexDConverter(bool keepControl) :
959 InstanceConverter(Cppyy::GetScope("std::complex<double>"), keepControl) {}
960
961// special case for std::complex<double>, maps it to/from Python's complex
962bool CPyCppyy::ComplexDConverter::SetArg(
963 PyObject* pyobject, Parameter& para, CallContext* ctxt)
964{
965 const Py_complex& pc = PyComplex_AsCComplex(pyobject);
966 if (pc.real != -1.0 || !PyErr_Occurred()) {
967 fBuffer.real(pc.real);
968 fBuffer.imag(pc.imag);
969 para.fValue.fVoidp = &fBuffer;
970 para.fTypeCode = 'V';
971 return true;
972 }
973
974 return this->InstanceConverter::SetArg(pyobject, para, ctxt);
975} \
976 \
977PyObject* CPyCppyy::ComplexDConverter::FromMemory(void* address)
978{
979 std::complex<double>* dc = (std::complex<double>*)address;
980 return PyComplex_FromDoubles(dc->real(), dc->imag());
981}
982
983bool CPyCppyy::ComplexDConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt)
984{
985 const Py_complex& pc = PyComplex_AsCComplex(value);
986 if (pc.real != -1.0 || !PyErr_Occurred()) {
987 std::complex<double>* dc = (std::complex<double>*)address;
988 dc->real(pc.real);
989 dc->imag(pc.imag);
990 return true;
991 }
992 return this->InstanceConverter::ToMemory(value, address, ctxt);
993}
994
995//----------------------------------------------------------------------------
996bool CPyCppyy::DoubleRefConverter::SetArg(
997 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
998{
999// convert <pyobject> to C++ double&, set arg for call
1000 if (RefFloat_CheckExact(pyobject)) {
1001 para.fValue.fVoidp = (void*)&((PyFloatObject*)pyobject)->ob_fval;
1002 para.fTypeCode = 'V';
1003 return true;
1004 }
1005
1006// alternate, pass pointer from buffer
1007 Py_ssize_t buflen = Utility::GetBuffer(pyobject, 'd', sizeof(double), para.fValue.fVoidp);
1008 if (para.fValue.fVoidp && buflen) {
1009 para.fTypeCode = 'V';
1010 return true;
1011 }
1012
1013#if PY_VERSION_HEX < 0x02050000
1014 PyErr_SetString(PyExc_TypeError, "use cppyy.Double for pass-by-ref of doubles");
1015#else
1016 PyErr_SetString(PyExc_TypeError, "use ctypes.c_double for pass-by-ref of doubles");
1017#endif
1018 return false;
1019}
1020
1021//----------------------------------------------------------------------------
1022CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Float, float, c_float, PyFloat_AsDouble)
1023CPPYY_IMPL_BASIC_CONST_REFCONVERTER(Double, double, c_double, PyFloat_AsDouble)
1024CPPYY_IMPL_BASIC_CONST_REFCONVERTER(LDouble, LongDouble_t, c_longdouble, PyFloat_AsDouble)
1025
1026//----------------------------------------------------------------------------
1027bool CPyCppyy::VoidConverter::SetArg(PyObject*, Parameter&, CallContext*)
1028{
1029// can't happen (unless a type is mapped wrongly), but implemented for completeness
1030 PyErr_SetString(PyExc_SystemError, "void/unknown arguments can\'t be set");
1031 return false;
1032}
1033
1034//----------------------------------------------------------------------------
1035bool CPyCppyy::LLongConverter::SetArg(
1036 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1037{
1038// convert <pyobject> to C++ long long, set arg for call
1039 if (PyFloat_Check(pyobject)) {
1040 // special case: float implements nb_int, but allowing rounding conversions
1041 // interferes with overloading
1042 PyErr_SetString(PyExc_ValueError, "cannot convert float to long long");
1043 return false;
1044 }
1045
1046 para.fValue.fLLong = PyLong_AsLongLong(pyobject);
1047 if (PyErr_Occurred())
1048 return false;
1049 para.fTypeCode = 'q';
1050 return true;
1051}
1052
1053PyObject* CPyCppyy::LLongConverter::FromMemory(void* address)
1054{
1055// construct python object from C++ long long read at <address>
1056 return PyLong_FromLongLong(*(Long64_t*)address);
1057}
1058
1059bool CPyCppyy::LLongConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1060{
1061// convert <value> to C++ long long, write it at <address>
1062 Long64_t ll = PyLong_AsLongLong(value);
1063 if (ll == -1 && PyErr_Occurred())
1064 return false;
1065 *((Long64_t*)address) = ll;
1066 return true;
1067}
1068
1069//----------------------------------------------------------------------------
1070bool CPyCppyy::ULLongConverter::SetArg(
1071 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1072{
1073// convert <pyobject> to C++ unsigned long long, set arg for call
1074 para.fValue.fULLong = PyLongOrInt_AsULong64(pyobject);
1075 if (PyErr_Occurred())
1076 return false;
1077 para.fTypeCode = 'Q';
1078 return true;
1079}
1080
1081PyObject* CPyCppyy::ULLongConverter::FromMemory(void* address)
1082{
1083// construct python object from C++ unsigned long long read at <address>
1084 return PyLong_FromUnsignedLongLong(*(ULong64_t*)address);
1085}
1086
1087bool CPyCppyy::ULLongConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1088{
1089// convert <value> to C++ unsigned long long, write it at <address>
1091 if (PyErr_Occurred())
1092 return false;
1093 *((ULong64_t*)address) = ull;
1094 return true;
1095}
1096
1097//----------------------------------------------------------------------------
1098bool CPyCppyy::CStringConverter::SetArg(
1099 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1100{
1101// construct a new string and copy it in new memory
1103 const char* cstr = CPyCppyy_PyText_AsStringAndSize(pyobject, &len);
1104 if (!cstr) {
1105 // special case: allow ctypes c_char_p
1106 PyObject* pytype = 0, *pyvalue = 0, *pytrace = 0;
1107 PyErr_Fetch(&pytype, &pyvalue, &pytrace);
1108 if (Py_TYPE(pyobject) == GetCTypesType(ct_c_char_p)) {
1109 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;
1110 para.fTypeCode = 'V';
1111 Py_XDECREF(pytype); Py_XDECREF(pyvalue); Py_XDECREF(pytrace);
1112 return true;
1113 }
1114 PyErr_Restore(pytype, pyvalue, pytrace);
1115 return false;
1116 }
1117
1118 fBuffer = std::string(cstr, len);
1119
1120// verify (too long string will cause truncation, no crash)
1121 if (fMaxSize != -1 && fMaxSize < (long)fBuffer.size())
1122 PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for char array (truncated)");
1123 else if (fMaxSize != -1)
1124 fBuffer.resize(fMaxSize, '\0'); // padd remainder of buffer as needed
1125
1126// set the value and declare success
1127 para.fValue.fVoidp = (void*)fBuffer.c_str();
1128 para.fTypeCode = 'p';
1129 return true;
1130}
1131
1132PyObject* CPyCppyy::CStringConverter::FromMemory(void* address)
1133{
1134// construct python object from C++ const char* read at <address>
1135 if (address && *(char**)address) {
1136 if (fMaxSize != -1) { // need to prevent reading beyond boundary
1137 std::string buf(*(char**)address, fMaxSize); // cut on fMaxSize
1138 return CPyCppyy_PyText_FromString(buf.c_str()); // cut on \0
1139 }
1140
1141 return CPyCppyy_PyText_FromString(*(char**)address);
1142 }
1143
1144// empty string in case there's no address
1145 Py_INCREF(PyStrings::gEmptyString);
1147}
1148
1149bool CPyCppyy::CStringConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1150{
1151// convert <value> to C++ const char*, write it at <address>
1153 const char* cstr = CPyCppyy_PyText_AsStringAndSize(value, &len);
1154 if (!cstr) return false;
1155
1156// verify (too long string will cause truncation, no crash)
1157 if (fMaxSize != -1 && fMaxSize < (long)len)
1158 PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for char array (truncated)");
1159
1160 if (fMaxSize != -1)
1161 strncpy(*(char**)address, cstr, fMaxSize); // padds remainder
1162 else
1163 // coverity[secure_coding] - can't help it, it's intentional.
1164 strcpy(*(char**)address, cstr);
1165
1166 return true;
1167}
1168
1169//----------------------------------------------------------------------------
1170bool CPyCppyy::WCStringConverter::SetArg(
1171 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1172{
1173// construct a new string and copy it in new memory
1174 Py_ssize_t len = PyUnicode_GetSize(pyobject);
1175 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1176 return false;
1177
1178 fBuffer = (wchar_t*)realloc(fBuffer, sizeof(wchar_t)*(len+1));
1180 if (res == -1)
1181 return false; // could free the buffer here
1182
1183// set the value and declare success
1184 fBuffer[len] = L'\0';
1185 para.fValue.fVoidp = (void*)fBuffer;
1186 para.fTypeCode = 'p';
1187 return true;
1188}
1189
1190PyObject* CPyCppyy::WCStringConverter::FromMemory(void* address)
1191{
1192// construct python object from C++ wchar_t* read at <address>
1193 if (address && *(wchar_t**)address) {
1194 if (fMaxSize != -1) // need to prevent reading beyond boundary
1195 return PyUnicode_FromWideChar(*(wchar_t**)address, fMaxSize);
1196 // with unknown size
1197 return PyUnicode_FromWideChar(*(wchar_t**)address, wcslen(*(wchar_t**)address));
1198 }
1199
1200// empty string in case there's no valid address
1201 wchar_t w = L'\0';
1202 return PyUnicode_FromWideChar(&w, 0);
1203}
1204
1205bool CPyCppyy::WCStringConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1206{
1207// convert <value> to C++ wchar_t*, write it at <address>
1208 Py_ssize_t len = PyUnicode_GetSize(value);
1209 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1210 return false;
1211
1212// verify (too long string will cause truncation, no crash)
1213 if (fMaxSize != -1 && fMaxSize < len)
1214 PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for wchar_t array (truncated)");
1215
1216 Py_ssize_t res = -1;
1217 if (fMaxSize != -1)
1218 res = CPyCppyy_PyUnicode_AsWideChar(value, *(wchar_t**)address, fMaxSize);
1219 else
1220 // coverity[secure_coding] - can't help it, it's intentional.
1221 res = CPyCppyy_PyUnicode_AsWideChar(value, *(wchar_t**)address, len);
1222
1223 if (res == -1) return false;
1224 return true;
1225}
1226
1227//----------------------------------------------------------------------------
1228bool CPyCppyy::CString16Converter::SetArg(
1229 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1230{
1231// construct a new string and copy it in new memory
1232 Py_ssize_t len = PyUnicode_GetSize(pyobject);
1233 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1234 return false;
1235
1236 PyObject* bstr = PyUnicode_AsUTF16String(pyobject);
1237 if (!bstr) return false;
1238
1239 fBuffer = (char16_t*)realloc(fBuffer, sizeof(char16_t)*(len+1));
1240 memcpy(fBuffer, PyBytes_AS_STRING(bstr) + sizeof(char16_t) /*BOM*/, len*sizeof(char16_t));
1241 Py_DECREF(bstr);
1242
1243// set the value and declare success
1244 fBuffer[len] = u'\0';
1245 para.fValue.fVoidp = (void*)fBuffer;
1246 para.fTypeCode = 'p';
1247 return true;
1248}
1249
1250PyObject* CPyCppyy::CString16Converter::FromMemory(void* address)
1251{
1252// construct python object from C++ char16_t* read at <address>
1253 if (address && *(char16_t**)address) {
1254 if (fMaxSize != -1) // need to prevent reading beyond boundary
1255 return PyUnicode_DecodeUTF16(*(const char**)address, fMaxSize, nullptr, nullptr);
1256 // with unknown size
1257 return PyUnicode_DecodeUTF16(*(const char**)address,
1258 std::char_traits<char16_t>::length(*(char16_t**)address)*sizeof(char16_t), nullptr, nullptr);
1259 }
1260
1261// empty string in case there's no valid address
1262 char16_t w = u'\0';
1263 return PyUnicode_DecodeUTF16((const char*)&w, 0, nullptr, nullptr);
1264}
1265
1266bool CPyCppyy::CString16Converter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1267{
1268// convert <value> to C++ char16_t*, write it at <address>
1269 Py_ssize_t len = PyUnicode_GetSize(value);
1270 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1271 return false;
1272
1273// verify (too long string will cause truncation, no crash)
1274 if (fMaxSize != -1 && fMaxSize < len) {
1275 PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for char16_t array (truncated)");
1276 len = fMaxSize-1;
1277 }
1278
1279 PyObject* bstr = PyUnicode_AsUTF16String(value);
1280 if (!bstr) return false;
1281
1282 memcpy(*((void**)address), PyBytes_AS_STRING(bstr) + sizeof(char16_t) /*BOM*/, len*sizeof(char16_t));
1283 Py_DECREF(bstr);
1284 *((char16_t**)address)[len] = u'\0';
1285 return true;
1286}
1287
1288//----------------------------------------------------------------------------
1289bool CPyCppyy::CString32Converter::SetArg(
1290 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1291{
1292// construct a new string and copy it in new memory
1293 Py_ssize_t len = PyUnicode_GetSize(pyobject);
1294 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1295 return false;
1296
1297 PyObject* bstr = PyUnicode_AsUTF32String(pyobject);
1298 if (!bstr) return false;
1299
1300 fBuffer = (char32_t*)realloc(fBuffer, sizeof(char32_t)*(len+1));
1301 memcpy(fBuffer, PyBytes_AS_STRING(bstr) + sizeof(char32_t) /*BOM*/, len*sizeof(char32_t));
1302 Py_DECREF(bstr);
1303
1304// set the value and declare success
1305 fBuffer[len] = U'\0';
1306 para.fValue.fVoidp = (void*)fBuffer;
1307 para.fTypeCode = 'p';
1308 return true;
1309}
1310
1311PyObject* CPyCppyy::CString32Converter::FromMemory(void* address)
1312{
1313// construct python object from C++ char32_t* read at <address>
1314 if (address && *(char32_t**)address) {
1315 if (fMaxSize != -1) // need to prevent reading beyond boundary
1316 return PyUnicode_DecodeUTF32(*(const char**)address, fMaxSize, nullptr, nullptr);
1317 // with unknown size
1318 return PyUnicode_DecodeUTF32(*(const char**)address,
1319 std::char_traits<char32_t>::length(*(char32_t**)address)*sizeof(char32_t), nullptr, nullptr);
1320 }
1321
1322// empty string in case there's no valid address
1323 char32_t w = U'\0';
1324 return PyUnicode_DecodeUTF32((const char*)&w, 0, nullptr, nullptr);
1325}
1326
1327bool CPyCppyy::CString32Converter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1328{
1329// convert <value> to C++ char32_t*, write it at <address>
1330 Py_ssize_t len = PyUnicode_GetSize(value);
1331 if (len == (Py_ssize_t)-1 && PyErr_Occurred())
1332 return false;
1333
1334// verify (too long string will cause truncation, no crash)
1335 if (fMaxSize != -1 && fMaxSize < len) {
1336 PyErr_Warn(PyExc_RuntimeWarning, (char*)"string too long for char32_t array (truncated)");
1337 len = fMaxSize-1;
1338 }
1339
1340 PyObject* bstr = PyUnicode_AsUTF32String(value);
1341 if (!bstr) return false;
1342
1343 memcpy(*((void**)address), PyBytes_AS_STRING(bstr) + sizeof(char32_t) /*BOM*/, len*sizeof(char32_t));
1344 Py_DECREF(bstr);
1345 *((char32_t**)address)[len] = U'\0';
1346 return true;
1347}
1348
1349
1350//----------------------------------------------------------------------------
1351bool CPyCppyy::NonConstCStringConverter::SetArg(
1352 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1353{
1354// attempt base class first (i.e. passing a string), but if that fails, try a buffer
1355 if (this->CStringConverter::SetArg(pyobject, para, ctxt))
1356 return true;
1357
1358// apparently failed, try char buffer
1359 PyErr_Clear();
1360 return CArraySetArg(pyobject, para, 'c', sizeof(char));
1361}
1362
1363//----------------------------------------------------------------------------
1364PyObject* CPyCppyy::NonConstCStringConverter::FromMemory(void* address)
1365{
1366// assume this is a buffer access if the size is known; otherwise assume string
1367 if (fMaxSize != -1)
1368 return CPyCppyy_PyText_FromStringAndSize(*(char**)address, fMaxSize);
1369 return this->CStringConverter::FromMemory(address);
1370}
1371
1372//----------------------------------------------------------------------------
1374{
1375// (1): C++11 style "null pointer"
1376 if (pyobject == gNullPtrObject) {
1377 address = nullptr;
1378 return true;
1379 }
1380
1381// (2): allow integer zero to act as a null pointer (C NULL), no deriveds
1382 if (PyInt_CheckExact(pyobject) || PyLong_CheckExact(pyobject)) {
1383 intptr_t val = (intptr_t)PyLong_AsLongLong(pyobject);
1384 if (val == 0l) {
1385 address = (void*)val;
1386 return true;
1387 }
1388
1389 return false;
1390 }
1391
1392// (3): opaque PyCapsule (CObject in older pythons) from somewhere
1393 if (CPyCppyy_PyCapsule_CheckExact(pyobject)) {
1394 address = (void*)CPyCppyy_PyCapsule_GetPointer(pyobject, nullptr);
1395 return true;
1396 }
1397
1398 return false;
1399}
1400
1401//----------------------------------------------------------------------------
1403 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1404{
1405// just convert pointer if it is a C++ object
1406 CPPInstance* pyobj = GetCppInstance(pyobject);
1407 if (pyobj) {
1408 // depending on memory policy, some objects are no longer owned when passed to C++
1409 if (!fKeepControl && !UseStrictOwnership(ctxt))
1410 pyobj->CppOwns();
1411
1412 // set pointer (may be null) and declare success
1413 para.fValue.fVoidp = pyobj->GetObject();
1414 para.fTypeCode = 'p';
1415 return true;
1416 }
1417
1418// handle special cases
1419 if (GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) {
1420 para.fTypeCode = 'p';
1421 return true;
1422 }
1423
1424// allow ctypes voidp (which if got as a buffer will return void**, not void*); use
1425// isintance instead of an exact check, b/c c_void_p is the type mapper for typedefs
1426// of void* (typically opaque handles)
1427 if (PyObject_IsInstance(pyobject, (PyObject*)GetCTypesType(ct_c_void_p))) {
1428 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;
1429 para.fTypeCode = 'V';
1430 return true;
1431 }
1432
1433// allow any other ctypes pointer type
1434 if (IsCTypesArrayOrPointer(pyobject)) {
1435 void** payload = (void**)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;
1436 if (payload) {
1437 para.fValue.fVoidp = *payload;
1438 para.fTypeCode = 'p';
1439 return true;
1440 }
1441 }
1442
1443// final try: attempt to get buffer
1444 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', 1, para.fValue.fVoidp, false);
1445
1446// ok if buffer exists (can't perform any useful size checks)
1447 if (para.fValue.fVoidp && buflen != 0) {
1448 para.fTypeCode = 'p';
1449 return true;
1450 }
1451
1452// give up
1453 return false;
1454}
1455
1456//----------------------------------------------------------------------------
1458{
1459// nothing sensible can be done, just return <address> as pylong
1460 if (!address || *(ptrdiff_t*)address == 0) {
1461 Py_INCREF(gNullPtrObject);
1462 return gNullPtrObject;
1463 }
1464 return CreatePointerView(*(ptrdiff_t**)address);
1465}
1466
1467//----------------------------------------------------------------------------
1469{
1470// just convert pointer if it is a C++ object
1472 if (pyobj) {
1473 // depending on memory policy, some objects are no longer owned when passed to C++
1475 pyobj->CppOwns();
1476
1477 // set pointer (may be null) and declare success
1478 *(void**)address = pyobj->GetObject();
1479 return true;
1480 }
1481
1482// handle special cases
1483 void* ptr = nullptr;
1484 if (GetAddressSpecialCase(value, ptr)) {
1485 *(void**)address = ptr;
1486 return true;
1487 }
1488
1489// final try: attempt to get buffer
1490 void* buf = nullptr;
1491 Py_ssize_t buflen = Utility::GetBuffer(value, '*', 1, buf, false);
1492 if (!buf || buflen == 0)
1493 return false;
1494
1495 *(void**)address = buf;
1496 return true;
1497}
1498
1499
1500//----------------------------------------------------------------------------
1501static inline void init_shape(Py_ssize_t defdim, dims_t dims, Py_ssize_t*& shape)
1502{
1503 int nalloc = (dims && 0 < dims[0]) ? (int)dims[0]+1: defdim+1;
1504 shape = new Py_ssize_t[nalloc];
1505 if (dims) {
1506 for (int i = 0; i < nalloc; ++i)
1507 shape[i] = (Py_ssize_t)dims[i];
1508 } else {
1509 shape[0] = defdim;
1510 for (int i = 1; i < nalloc; ++i) shape[i] = UNKNOWN_SIZE;
1511 }
1512}
1513
1514//----------------------------------------------------------------------------
1515#define CPPYY_IMPL_ARRAY_CONVERTER(name, ctype, type, code) \
1516CPyCppyy::name##ArrayConverter::name##ArrayConverter(dims_t dims, bool init) {\
1517 if (init) { \
1518 init_shape(1, dims, fShape); \
1519 fIsFixed = fShape[1] != UNKNOWN_SIZE; \
1520 } else fIsFixed = false; \
1521} \
1522 \
1523bool CPyCppyy::name##ArrayConverter::SetArg( \
1524 PyObject* pyobject, Parameter& para, CallContext* ctxt) \
1525{ \
1526 /* filter ctypes first b/c their buffer conversion will be wrong */ \
1527 bool res = false; \
1528 PyTypeObject* ctypes_type = GetCTypesType(ct_##ctype); \
1529 if (Py_TYPE(pyobject) == ctypes_type) { \
1530 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;\
1531 para.fTypeCode = 'p'; \
1532 res = true; \
1533 } else if (Py_TYPE(pyobject) == GetCTypesPtrType(ct_##ctype)) { \
1534 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;\
1535 para.fTypeCode = 'V'; \
1536 res = true; \
1537 } else if (IsPyCArgObject(pyobject)) { \
1538 CPyCppyy_tagPyCArgObject* carg = (CPyCppyy_tagPyCArgObject*)pyobject;\
1539 if (carg->obj && Py_TYPE(carg->obj) == ctypes_type) { \
1540 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)carg->obj)->b_ptr;\
1541 para.fTypeCode = 'p'; \
1542 res = true; \
1543 } \
1544 } \
1545 if (!res) res = CArraySetArg(pyobject, para, code, sizeof(type)); \
1546 if (res) SetLifeLine(ctxt->fPyContext, pyobject, (intptr_t)this); \
1547 return res; \
1548} \
1549 \
1550PyObject* CPyCppyy::name##ArrayConverter::FromMemory(void* address) \
1551{ \
1552 if (!fIsFixed) \
1553 return CreateLowLevelView((type**)address, fShape); \
1554 return CreateLowLevelView(*(type**)address, fShape); \
1555} \
1556 \
1557bool CPyCppyy::name##ArrayConverter::ToMemory( \
1558 PyObject* value, void* address, PyObject* ctxt) \
1559{ \
1560 if (fShape[0] != 1) { \
1561 PyErr_SetString(PyExc_ValueError, "only 1-dim arrays supported"); \
1562 return false; \
1563 } \
1564 void* buf = nullptr; \
1565 Py_ssize_t buflen = Utility::GetBuffer(value, code, sizeof(type), buf); \
1566 if (buflen == 0) \
1567 return false; \
1568 if (fIsFixed) { \
1569 if (fShape[1] < buflen) { \
1570 PyErr_SetString(PyExc_ValueError, "buffer too large for value"); \
1571 return false; \
1572 } \
1573 memcpy(*(type**)address, buf, (0 < buflen ? buflen : 1)*sizeof(type));\
1574 } else { \
1575 *(type**)address = (type*)buf; \
1576 fShape[1] = buflen; \
1577 } \
1578 SetLifeLine(ctxt, value, (intptr_t)address); \
1579 return true; \
1580} \
1581 \
1582bool CPyCppyy::name##ArrayPtrConverter::SetArg( \
1583 PyObject* pyobject, Parameter& para, CallContext* ctxt ) \
1584{ \
1585 if (Py_TYPE(pyobject) == GetCTypesPtrType(ct_##ctype)) { \
1586 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;\
1587 para.fTypeCode = 'p'; \
1588 return true; \
1589 } else if (Py_TYPE(pyobject) == GetCTypesType(ct_c_void_p)) { \
1590 /* special case: pass address of c_void_p buffer to return the address */\
1591 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)pyobject)->b_ptr;\
1592 para.fTypeCode = 'p'; \
1593 return true; \
1594 } \
1595 bool res = name##ArrayConverter::SetArg(pyobject, para, ctxt); \
1596 if (res && para.fTypeCode == 'p') { \
1597 para.fRef = para.fValue.fVoidp; \
1598 para.fValue.fVoidp = &para.fRef; \
1599 return true; \
1600 } \
1601 return false; \
1602}
1603
1604
1605//----------------------------------------------------------------------------
1606CPPYY_IMPL_ARRAY_CONVERTER(Bool, c_bool, bool, '?')
1607CPPYY_IMPL_ARRAY_CONVERTER(SChar, c_char, signed char, 'b')
1608CPPYY_IMPL_ARRAY_CONVERTER(UChar, c_ubyte, unsigned char, 'B')
1609#if __cplusplus > 201402L
1610CPPYY_IMPL_ARRAY_CONVERTER(Byte, c_ubyte, std::byte, 'B')
1611#endif
1612CPPYY_IMPL_ARRAY_CONVERTER(Short, c_short, short, 'h')
1613CPPYY_IMPL_ARRAY_CONVERTER(UShort, c_ushort, unsigned short, 'H')
1614CPPYY_IMPL_ARRAY_CONVERTER(Int, c_int, int, 'i')
1615CPPYY_IMPL_ARRAY_CONVERTER(UInt, c_uint, unsigned int, 'I')
1616CPPYY_IMPL_ARRAY_CONVERTER(Long, c_long, long, 'l')
1617CPPYY_IMPL_ARRAY_CONVERTER(ULong, c_ulong, unsigned long, 'L')
1618CPPYY_IMPL_ARRAY_CONVERTER(LLong, c_longlong, long long, 'q')
1619CPPYY_IMPL_ARRAY_CONVERTER(ULLong, c_ulonglong, unsigned long long, 'Q')
1620CPPYY_IMPL_ARRAY_CONVERTER(Float, c_float, float, 'f')
1621CPPYY_IMPL_ARRAY_CONVERTER(Double, c_double, double, 'd')
1622CPPYY_IMPL_ARRAY_CONVERTER(LDouble, c_longdouble, long double, 'D')
1623CPPYY_IMPL_ARRAY_CONVERTER(ComplexD, c_complex, std::complex<double>, 'Z')
1624
1625
1626//----------------------------------------------------------------------------
1627PyObject* CPyCppyy::CStringArrayConverter::FromMemory(void* address)
1628{
1629 if (fShape[1] == UNKNOWN_SIZE)
1630 return CreateLowLevelView((const char**)address, fShape);
1631 return CreateLowLevelView(*(const char***)address, fShape);
1632}
1633
1634
1635//- converters for special cases ---------------------------------------------
1636bool CPyCppyy::NullptrConverter::SetArg(PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
1637{
1638// Only allow C++11 style nullptr to pass
1639 if (pyobject == gNullPtrObject) {
1640 para.fValue.fVoidp = nullptr;
1641 para.fTypeCode = 'p';
1642 return true;
1643 }
1644 return false;
1645}
1646
1647
1648//----------------------------------------------------------------------------
1649#define CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(name, type, F1, F2) \
1650CPyCppyy::name##Converter::name##Converter(bool keepControl) : \
1651 InstanceConverter(Cppyy::GetScope(#type), keepControl) {} \
1652 \
1653bool CPyCppyy::name##Converter::SetArg( \
1654 PyObject* pyobject, Parameter& para, CallContext* ctxt) \
1655{ \
1656 Py_ssize_t len; \
1657 const char* cstr = CPyCppyy_PyText_AsStringAndSize(pyobject, &len); \
1658 if (cstr) { \
1659 fBuffer = type(cstr, len); \
1660 para.fValue.fVoidp = &fBuffer; \
1661 para.fTypeCode = 'V'; \
1662 return true; \
1663 } \
1664 \
1665 PyErr_Clear(); \
1666 if (!(PyInt_Check(pyobject) || PyLong_Check(pyobject))) { \
1667 bool result = InstanceConverter::SetArg(pyobject, para, ctxt); \
1668 para.fTypeCode = 'V'; \
1669 return result; \
1670 } \
1671 return false; \
1672} \
1673 \
1674PyObject* CPyCppyy::name##Converter::FromMemory(void* address) \
1675{ \
1676 if (address) \
1677 return CPyCppyy_PyText_FromStringAndSize(((type*)address)->F1(), ((type*)address)->F2()); \
1678 Py_INCREF(PyStrings::gEmptyString); \
1679 return PyStrings::gEmptyString; \
1680} \
1681 \
1682bool CPyCppyy::name##Converter::ToMemory(PyObject* value, void* address, \
1683 PyObject* ctxt) \
1684{ \
1685 if (CPyCppyy_PyText_Check(value)) { \
1686 *((type*)address) = CPyCppyy_PyText_AsString(value); \
1687 return true; \
1688 } \
1689 \
1690 return InstanceConverter::ToMemory(value, address, ctxt); \
1691}
1692
1694CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(STLString, std::string, c_str, size)
1695CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(STLStringViewBase, std::string_view, data, size)
1696bool CPyCppyy::STLStringViewConverter::SetArg(
1697 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1698{
1699 if (this->STLStringViewBaseConverter::SetArg(pyobject, para, ctxt))
1700 return true;
1701
1702 if (!CPPInstance_Check(pyobject))
1703 return false;
1704
1705 static Cppyy::TCppScope_t sStringID = Cppyy::GetScope("std::string");
1706 CPPInstance* pyobj = (CPPInstance*)pyobject;
1707 if (pyobj->ObjectIsA() == sStringID) {
1708 void* ptr = pyobj->GetObject();
1709 if (!ptr)
1710 return false;
1711
1712 fBuffer = *((std::string*)ptr);
1713 para.fValue.fVoidp = &fBuffer;
1714 para.fTypeCode = 'V';
1715 return true;
1716 }
1717
1718 return false;
1719}
1720
1721CPyCppyy::STLWStringConverter::STLWStringConverter(bool keepControl) :
1722 InstanceConverter(Cppyy::GetScope("std::wstring"), keepControl) {}
1723
1724bool CPyCppyy::STLWStringConverter::SetArg(
1725 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1726{
1727 if (PyUnicode_Check(pyobject)) {
1729 fBuffer.resize(len);
1731 para.fValue.fVoidp = &fBuffer;
1732 para.fTypeCode = 'V';
1733 return true;
1734 }
1735
1736 if (!(PyInt_Check(pyobject) || PyLong_Check(pyobject))) {
1737 bool result = InstancePtrConverter::SetArg(pyobject, para, ctxt);
1738 para.fTypeCode = 'V';
1739 return result;
1740 }
1741
1742 return false;
1743}
1744
1745PyObject* CPyCppyy::STLWStringConverter::FromMemory(void* address)
1746{
1747 if (address)
1748 return PyUnicode_FromWideChar(((std::wstring*)address)->c_str(), ((std::wstring*)address)->size());
1749 wchar_t w = L'\0';
1750 return PyUnicode_FromWideChar(&w, 0);
1751}
1752
1753bool CPyCppyy::STLWStringConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt)
1754{
1755 if (PyUnicode_Check(value)) {
1757 wchar_t* buf = new wchar_t[len+1];
1759 *((std::wstring*)address) = std::wstring(buf, len);
1760 delete[] buf;
1761 return true;
1762 }
1763 return InstanceConverter::ToMemory(value, address, ctxt);
1764}
1765
1766
1767bool CPyCppyy::STLStringMoveConverter::SetArg(
1768 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1769{
1770// convert <pyobject> to C++ std::string&&, set arg for call
1771 int moveit_reason = 3; // move on temporary fBuffer
1772 if (CPPInstance_Check(pyobject)) {
1773 CPPInstance* pyobj = (CPPInstance*)pyobject;
1774 if (pyobj->fFlags & CPPInstance::kIsRValue) {
1775 pyobj->fFlags &= ~CPPInstance::kIsRValue;
1776 moveit_reason = 2;
1777 } else if (pyobject->ob_refcnt == MOVE_REFCOUNT_CUTOFF) {
1778 moveit_reason = 1;
1779 } else
1780 moveit_reason = 0;
1781 }
1782
1783 if (moveit_reason) {
1784 bool result = this->STLStringConverter::SetArg(pyobject, para, ctxt);
1785 if (!result && moveit_reason == 2) // restore the movability flag?
1786 ((CPPInstance*)pyobject)->fFlags |= CPPInstance::kIsRValue;
1787 return result;
1788 }
1789
1790 PyErr_SetString(PyExc_ValueError, "object is not an rvalue");
1791 return false; // not a temporary or movable object
1792}
1793
1794
1795//----------------------------------------------------------------------------
1797 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1798{
1799// convert <pyobject> to C++ instance*, set arg for call
1800 CPPInstance* pyobj = GetCppInstance(pyobject);
1801 if (!pyobj) {
1802 if (GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) {
1803 para.fTypeCode = 'p'; // allow special cases such as nullptr
1804 return true;
1805 }
1806
1807 // not a cppyy object (TODO: handle SWIG etc.)
1808 return false;
1809 }
1810
1811 // smart pointers should only extract the pointer if this is NOT an implicit
1812 // conversion to another smart pointer
1813 if (pyobj->IsSmart() && IsConstructor(ctxt->fFlags) && Cppyy::IsSmartPtr(ctxt->fCurScope))
1814 return false;
1815
1816 Cppyy::TCppType_t oisa = pyobj->ObjectIsA();
1817 if (oisa && (oisa == fClass || Cppyy::IsSubtype(oisa, fClass))) {
1818 // depending on memory policy, some objects need releasing when passed into functions
1819 if (!KeepControl() && !UseStrictOwnership(ctxt))
1820 pyobj->CppOwns();
1821
1822 // calculate offset between formal and actual arguments
1823 para.fValue.fVoidp = pyobj->GetObject();
1824 if (pyobj->ObjectIsA() != fClass) {
1826 pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */);
1827 }
1828
1829 // set pointer (may be null) and declare success
1830 para.fTypeCode = 'p';
1831 return true;
1832 }
1833
1834 return false;
1835}
1836
1837//----------------------------------------------------------------------------
1839{
1840// construct python object from C++ instance read at <address>
1842}
1843
1844//----------------------------------------------------------------------------
1846{
1847// convert <value> to C++ instance, write it at <address>
1849 if (!pyobj) {
1850 void* ptr = nullptr;
1851 if (GetAddressSpecialCase(value, ptr)) {
1852 *(void**)address = ptr; // allow special cases such as nullptr
1853 return true;
1854 }
1855
1856 // not a cppyy object (TODO: handle SWIG etc.)
1857 return false;
1858 }
1859
1860 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1861 // depending on memory policy, some objects need releasing when passed into functions
1862 if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict)
1863 ((CPPInstance*)value)->CppOwns();
1864
1865 *(void**)address = pyobj->GetObject();
1866 return true;
1867 }
1868
1869 return false;
1870}
1871
1872// TODO: CONSOLIDATE Instance, InstanceRef, InstancePtr ...
1873
1874//----------------------------------------------------------------------------
1875bool CPyCppyy::InstanceConverter::SetArg(
1876 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1877{
1878// convert <pyobject> to C++ instance, set arg for call
1879 CPPInstance* pyobj = GetCppInstance(pyobject);
1880 if (pyobj) {
1881 if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1882 // calculate offset between formal and actual arguments
1883 para.fValue.fVoidp = pyobj->GetObject();
1884 if (!para.fValue.fVoidp)
1885 return false;
1886
1887 if (pyobj->ObjectIsA() != fClass) {
1889 pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */);
1890 }
1891
1892 para.fTypeCode = 'V';
1893 return true;
1894 }
1895 }
1896
1897 return ConvertImplicit(fClass, pyobject, para, ctxt);
1898}
1899
1900//----------------------------------------------------------------------------
1901PyObject* CPyCppyy::InstanceConverter::FromMemory(void* address)
1902{
1904}
1905
1906//----------------------------------------------------------------------------
1907bool CPyCppyy::InstanceConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1908{
1909// assign value to C++ instance living at <address> through assignment operator
1910 PyObject* pyobj = BindCppObjectNoCast(address, fClass);
1911 PyObject* result = PyObject_CallMethod(pyobj, (char*)"__assign__", (char*)"O", value);
1912 Py_DECREF(pyobj);
1913
1914 if (result) {
1915 Py_DECREF(result);
1916 return true;
1917 }
1918 return false;
1919}
1920
1921
1922//----------------------------------------------------------------------------
1923bool CPyCppyy::InstanceRefConverter::SetArg(
1924 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1925{
1926// convert <pyobject> to C++ instance&, set arg for call
1927 CPPInstance* pyobj = GetCppInstance(pyobject);
1928 if (pyobj) {
1929
1930 // reject moves
1931 if (pyobj->fFlags & CPPInstance::kIsRValue)
1932 return false;
1933
1934 if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1935 // calculate offset between formal and actual arguments
1936 para.fValue.fVoidp = pyobj->GetObject();
1937 if (pyobj->ObjectIsA() != fClass) {
1939 pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */);
1940 }
1941
1942 para.fTypeCode = 'V';
1943 return true;
1944 }
1945 }
1946
1947 if (!fIsConst) // no implicit conversion possible
1948 return false;
1949
1950 return ConvertImplicit(fClass, pyobject, para, ctxt);
1951}
1952
1953//----------------------------------------------------------------------------
1954PyObject* CPyCppyy::InstanceRefConverter::FromMemory(void* address)
1955{
1957}
1958
1959//----------------------------------------------------------------------------
1960bool CPyCppyy::InstanceMoveConverter::SetArg(
1961 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1962{
1963// convert <pyobject> to C++ instance&&, set arg for call
1964 CPPInstance* pyobj = GetCppInstance(pyobject);
1965 if (!pyobj) {
1966 // implicit conversion is fine as it the temporary by definition is moveable
1967 return ConvertImplicit(fClass, pyobject, para, ctxt);
1968 }
1969
1970// moving is same as by-ref, but have to check that move is allowed
1971 int moveit_reason = 0;
1972 if (pyobj->fFlags & CPPInstance::kIsRValue) {
1973 pyobj->fFlags &= ~CPPInstance::kIsRValue;
1974 moveit_reason = 2;
1975 } else if (pyobject->ob_refcnt == MOVE_REFCOUNT_CUTOFF) {
1976 moveit_reason = 1;
1977 }
1978
1979 if (moveit_reason) {
1980 bool result = this->InstanceRefConverter::SetArg(pyobject, para, ctxt);
1981 if (!result && moveit_reason == 2) // restore the movability flag?
1982 ((CPPInstance*)pyobject)->fFlags |= CPPInstance::kIsRValue;
1983 return result;
1984 }
1985
1986 PyErr_SetString(PyExc_ValueError, "object is not an rvalue");
1987 return false; // not a temporary or movable object
1988}
1989
1990//----------------------------------------------------------------------------
1991template <bool ISREFERENCE>
1992bool CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::SetArg(
1993 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1994{
1995// convert <pyobject> to C++ instance**, set arg for call
1996 CPPInstance* pyobj = GetCppInstance(pyobject);
1997 if (!pyobj)
1998 return false; // not a cppyy object (TODO: handle SWIG etc.)
1999
2000 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
2001 // depending on memory policy, some objects need releasing when passed into functions
2002 if (!KeepControl() && !UseStrictOwnership(ctxt))
2003 pyobj->CppOwns();
2004
2005 // set pointer (may be null) and declare success
2006 if (pyobj->fFlags & CPPInstance::kIsReference) // already a ptr to object?
2007 para.fValue.fVoidp = pyobj->GetObjectRaw();
2008 else
2009 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2010 para.fTypeCode = ISREFERENCE ? 'V' : 'p';
2011 return true;
2012 }
2013
2014 return false;
2015}
2016
2017//----------------------------------------------------------------------------
2018template <bool ISREFERENCE>
2019PyObject* CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::FromMemory(void* address)
2020{
2021// construct python object from C++ instance* read at <address>
2023}
2024
2025//----------------------------------------------------------------------------
2026template <bool ISREFERENCE>
2027bool CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
2028{
2029// convert <value> to C++ instance*, write it at <address>
2031 if (!pyobj)
2032 return false; // not a cppyy object (TODO: handle SWIG etc.)
2033
2034 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
2035 // depending on memory policy, some objects need releasing when passed into functions
2036 if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict)
2037 pyobj->CppOwns();
2038
2039 // register the value for potential recycling
2041
2042 // set pointer (may be null) and declare success
2043 *(void**)address = pyobj->GetObject();
2044 return true;
2045 }
2046
2047 return false;
2048}
2049
2050
2051namespace CPyCppyy {
2052// Instantiate the templates
2053 template class CPyCppyy::InstancePtrPtrConverter<true>;
2054 template class CPyCppyy::InstancePtrPtrConverter<false>;
2055}
2056
2057//----------------------------------------------------------------------------
2058bool CPyCppyy::InstanceArrayConverter::SetArg(
2059 PyObject* pyobject, Parameter& para, CallContext* /* txt */)
2060{
2061// convert <pyobject> to C++ instance**, set arg for call
2062 if (!TupleOfInstances_CheckExact(pyobject))
2063 return false; // no guarantee that the tuple is okay
2064
2065// treat the first instance of the tuple as the start of the array, and pass it
2066// by pointer (TODO: store and check sizes)
2067 if (PyTuple_Size(pyobject) < 1)
2068 return false;
2069
2070 PyObject* first = PyTuple_GetItem(pyobject, 0);
2071 if (!CPPInstance_Check(first))
2072 return false; // should not happen
2073
2074 if (Cppyy::IsSubtype(((CPPInstance*)first)->ObjectIsA(), fClass)) {
2075 // no memory policies supported; set pointer (may be null) and declare success
2076 para.fValue.fVoidp = ((CPPInstance*)first)->GetObject();
2077 para.fTypeCode = 'p';
2078 return true;
2079 }
2080
2081 return false;
2082}
2083
2084//----------------------------------------------------------------------------
2085PyObject* CPyCppyy::InstanceArrayConverter::FromMemory(void* address)
2086{
2087// construct python tuple of instances from C++ array read at <address>
2088 return BindCppObjectArray(*(char**)address, fClass, m_dims);
2089}
2090
2091//----------------------------------------------------------------------------
2092bool CPyCppyy::InstanceArrayConverter::ToMemory(PyObject* /* value */, void* /* address */, PyObject* /* ctxt */)
2093{
2094// convert <value> to C++ array of instances, write it at <address>
2095
2096// TODO: need to have size both for the array and from the input
2097 PyErr_SetString(PyExc_NotImplementedError,
2098 "access to C-arrays of objects not yet implemented!");
2099 return false;
2100}
2101
2102//___________________________________________________________________________
2103// CLING WORKAROUND -- classes for STL iterators are completely undefined in that
2104// they come in a bazillion different guises, so just do whatever
2105bool CPyCppyy::STLIteratorConverter::SetArg(
2106 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2107{
2108 if (!CPPInstance_Check(pyobject))
2109 return false;
2110
2111// just set the pointer value, no check
2112 CPPInstance* pyobj = (CPPInstance*)pyobject;
2113 para.fValue.fVoidp = pyobj->GetObject();
2114 para.fTypeCode = 'V';
2115 return true;
2116}
2117// -- END CLING WORKAROUND
2118
2119//----------------------------------------------------------------------------
2120bool CPyCppyy::VoidPtrRefConverter::SetArg(
2121 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2122{
2123// convert <pyobject> to C++ void*&, set arg for call
2124 CPPInstance* pyobj = GetCppInstance(pyobject);
2125 if (pyobj) {
2126 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2127 para.fTypeCode = 'V';
2128 return true;
2129 }
2130
2131 return false;
2132}
2133
2134//----------------------------------------------------------------------------
2135bool CPyCppyy::VoidPtrPtrConverter::SetArg(
2136 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2137{
2138// convert <pyobject> to C++ void**, set arg for call
2139 CPPInstance* pyobj = GetCppInstance(pyobject);
2140 if (pyobj) {
2141 // this is a C++ object, take and set its address
2142 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2143 para.fTypeCode = 'p';
2144 return true;
2145 } else if (IsPyCArgObject(pyobject)) {
2147 if (carg->obj) {
2148 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)carg->obj)->b_ptr;
2149 para.fTypeCode = 'p';
2150 return true;
2151 }
2152 }
2153
2154// buffer objects are allowed under "user knows best" (this includes the buffer
2155// interface to ctypes.c_void_p, which results in a void**)
2156 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', 1, para.fValue.fVoidp, false);
2157
2158// ok if buffer exists (can't perform any useful size checks)
2159 if (para.fValue.fVoidp && buflen != 0) {
2160 para.fTypeCode = 'p';
2161 return true;
2162 }
2163
2164 return false;
2165}
2166
2167//----------------------------------------------------------------------------
2168PyObject* CPyCppyy::VoidPtrPtrConverter::FromMemory(void* address)
2169{
2170// read a void** from address; since this is unknown, long is used (user can cast)
2171 if (!address || *(ptrdiff_t*)address == 0) {
2172 Py_INCREF(gNullPtrObject);
2173 return gNullPtrObject;
2174 }
2175 return CreatePointerView(*(ptrdiff_t**)address, fSize);
2176}
2177
2178//----------------------------------------------------------------------------
2179bool CPyCppyy::PyObjectConverter::SetArg(
2180 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2181{
2182// by definition: set and declare success
2183 para.fValue.fVoidp = pyobject;
2184 para.fTypeCode = 'p';
2185 return true;
2186}
2187
2188PyObject* CPyCppyy::PyObjectConverter::FromMemory(void* address)
2189{
2190// construct python object from C++ PyObject* read at <address>
2191 PyObject* pyobject = *((PyObject**)address);
2192
2193 if (!pyobject) {
2195 }
2196
2197 Py_INCREF(pyobject);
2198 return pyobject;
2199}
2200
2201bool CPyCppyy::PyObjectConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
2202{
2203// no conversion needed, write <value> at <address>
2204 Py_INCREF(value);
2205 Py_XDECREF(*((PyObject**)address));
2206 *((PyObject**)address) = value;
2207 return true;
2208}
2209
2210
2211//- function pointer converter -----------------------------------------------
2212static unsigned int sWrapperCounter = 0;
2213// cache mapping signature/return type to python callable and corresponding wrapper
2214typedef std::pair<std::string, std::string> RetSigKey_t;
2215static std::map<RetSigKey_t, std::vector<void*>> sWrapperFree;
2216static std::map<RetSigKey_t, std::map<PyObject*, void*>> sWrapperLookup;
2217static std::map<PyObject*, std::pair<void*, RetSigKey_t>> sWrapperWeakRefs;
2218static std::map<void*, PyObject**> sWrapperReference;
2219
2221{
2222 auto ipos = sWrapperWeakRefs.find(pyref);
2223 if (ipos != sWrapperWeakRefs.end()) {
2224 // disable this callback and store for possible re-use
2225 void* wpraddress = ipos->second.first;
2226 *sWrapperReference[wpraddress] = nullptr;
2227 sWrapperFree[ipos->second.second].push_back(wpraddress);
2228 }
2229
2231}
2232static PyMethodDef gWrapperCacheEraserMethodDef = {
2233 const_cast<char*>("interal_WrapperCacheEraser"),
2234 (PyCFunction)WrapperCacheEraser,
2235 METH_O, nullptr
2236};
2237
2238static void* PyFunction_AsCPointer(PyObject* pyobject,
2239 const std::string& rettype, const std::string& signature)
2240{
2241// Convert a bound C++ function pointer or callable python object to a C-style
2242// function pointer. The former is direct, the latter involves a JIT-ed wrapper.
2243 static PyObject* sWrapperCacheEraser = PyCFunction_New(&gWrapperCacheEraserMethodDef, nullptr);
2244
2245 using namespace CPyCppyy;
2246
2247 if (CPPOverload_Check(pyobject)) {
2248 CPPOverload* ol = (CPPOverload*)pyobject;
2249 if (!ol->fMethodInfo || ol->fMethodInfo->fMethods.empty())
2250 return nullptr;
2251
2252 // find the overload with matching signature
2253 for (auto& m : ol->fMethodInfo->fMethods) {
2254 PyObject* sig = m->GetSignature(false);
2255 bool found = signature == CPyCppyy_PyText_AsString(sig);
2256 Py_DECREF(sig);
2257 if (found) {
2258 void* fptr = (void*)m->GetFunctionAddress();
2259 if (fptr) return fptr;
2260 break; // fall-through, with calling through Python
2261 }
2262 }
2263 }
2264
2265 if (TemplateProxy_Check(pyobject)) {
2266 // get the actual underlying template matching the signature
2267 TemplateProxy* pytmpl = (TemplateProxy*)pyobject;
2268 std::string fullname = CPyCppyy_PyText_AsString(pytmpl->fTI->fCppName);
2269 if (pytmpl->fTemplateArgs)
2270 fullname += CPyCppyy_PyText_AsString(pytmpl->fTemplateArgs);
2271 Cppyy::TCppScope_t scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType;
2272 Cppyy::TCppMethod_t cppmeth = Cppyy::GetMethodTemplate(scope, fullname, signature);
2273 if (cppmeth) {
2274 void* fptr = (void*)Cppyy::GetFunctionAddress(cppmeth, false);
2275 if (fptr) return fptr;
2276 }
2277 // fall-through, with calling through Python
2278 }
2279
2280 if (PyCallable_Check(pyobject)) {
2281 // generic python callable: create a C++ wrapper function
2282 void* wpraddress = nullptr;
2283
2284 // re-use existing wrapper if possible
2285 auto key = std::make_pair(rettype, signature);
2286 const auto& lookup = sWrapperLookup.find(key);
2287 if (lookup != sWrapperLookup.end()) {
2288 const auto& existing = lookup->second.find(pyobject);
2289 if (existing != lookup->second.end() && *sWrapperReference[existing->second] == pyobject)
2290 wpraddress = existing->second;
2291 }
2292
2293 // check for a pre-existing, unused, wrapper if not found
2294 if (!wpraddress) {
2295 const auto& freewrap = sWrapperFree.find(key);
2296 if (freewrap != sWrapperFree.end() && !freewrap->second.empty()) {
2297 wpraddress = freewrap->second.back();
2298 freewrap->second.pop_back();
2299 *sWrapperReference[wpraddress] = pyobject;
2300 PyObject* wref = PyWeakref_NewRef(pyobject, sWrapperCacheEraser);
2301 if (wref) sWrapperWeakRefs[wref] = std::make_pair(wpraddress, key);
2302 else PyErr_Clear(); // happens for builtins which don't need this
2303 }
2304 }
2305
2306 // create wrapper if no re-use possible
2307 if (!wpraddress) {
2309 return nullptr;
2310
2311 // extract argument types
2312 const std::vector<std::string>& argtypes = TypeManip::extract_arg_types(signature);
2313 int nArgs = (int)argtypes.size();
2314
2315 // wrapper name
2316 std::ostringstream wname;
2317 wname << "fptr_wrap" << ++sWrapperCounter;
2318
2319 // build wrapper function code
2320 std::ostringstream code;
2321 code << "namespace __cppyy_internal {\n "
2322 << rettype << " " << wname.str() << "(";
2323 for (int i = 0; i < nArgs; ++i) {
2324 code << argtypes[i] << " arg" << i;
2325 if (i != nArgs-1) code << ", ";
2326 }
2327 code << ") {\n";
2328
2329 // start function body
2330 Utility::ConstructCallbackPreamble(rettype, argtypes, code);
2331
2332 // create a referencable pointer
2333 PyObject** ref = new PyObject*{pyobject};
2334
2335 // function call itself and cleanup
2336 code << " PyObject** ref = (PyObject**)" << (intptr_t)ref << ";\n"
2337 " PyObject* pyresult = nullptr;\n"
2338 " if (*ref) pyresult = PyObject_CallFunctionObjArgs(*ref";
2339 for (int i = 0; i < nArgs; ++i)
2340 code << ", pyargs[" << i << "]";
2341 code << ", NULL);\n"
2342 " else PyErr_SetString(PyExc_TypeError, \"callable was deleted\");\n";
2343
2344 // close
2345 Utility::ConstructCallbackReturn(rettype, nArgs, code);
2346
2347 // end of namespace
2348 code << "}";
2349
2350 // finally, compile the code
2351 if (!Cppyy::Compile(code.str()))
2352 return nullptr;
2353
2354 // TODO: is there no easier way?
2355 static Cppyy::TCppScope_t scope = Cppyy::GetScope("__cppyy_internal");
2356 const auto& idx = Cppyy::GetMethodIndicesFromName(scope, wname.str());
2357 wpraddress = Cppyy::GetFunctionAddress(Cppyy::GetMethod(scope, idx[0]), false);
2358 sWrapperReference[wpraddress] = ref;
2359
2360 // cache the new wrapper
2361 sWrapperLookup[key][pyobject] = wpraddress;
2362 PyObject* wref = PyWeakref_NewRef(pyobject, sWrapperCacheEraser);
2363 if (wref) sWrapperWeakRefs[wref] = std::make_pair(wpraddress, key);
2364 else PyErr_Clear(); // happens for builtins which don't need this
2365 }
2366
2367 // now pass the pointer to the wrapper function (may be null)
2368 return wpraddress;
2369 }
2370
2371 return nullptr;
2372}
2373
2374bool CPyCppyy::FunctionPointerConverter::SetArg(
2375 PyObject* pyobject, Parameter& para, CallContext* /*ctxt*/)
2376{
2377// special case: allow nullptr singleton:
2378 if (gNullPtrObject == pyobject) {
2379 para.fValue.fVoidp = nullptr;
2380 para.fTypeCode = 'p';
2381 return true;
2382 }
2383
2384// normal case, get a function pointer
2385 void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature);
2386 if (fptr) {
2387 para.fValue.fVoidp = fptr;
2388 para.fTypeCode = 'p';
2389 return true;
2390 }
2391
2392 return false;
2393}
2394
2395PyObject* CPyCppyy::FunctionPointerConverter::FromMemory(void* address)
2396{
2397// A function pointer in clang is represented by a Type, not a FunctionDecl and it's
2398// not possible to get the latter from the former: the backend will need to support
2399// both. Since that is far in the future, we'll use a std::function instead.
2400 if (address)
2401 return Utility::FuncPtr2StdFunction(fRetType, fSignature, *(void**)address);
2402 PyErr_SetString(PyExc_TypeError, "can not convert null function pointer");
2403 return nullptr;
2404}
2405
2406bool CPyCppyy::FunctionPointerConverter::ToMemory(PyObject* pyobject, void* address, PyObject* /* ctxt */)
2407{
2408// special case: allow nullptr singleton:
2409 if (gNullPtrObject == pyobject) {
2410 *((void**)address) = nullptr;
2411 return true;
2412 }
2413
2414// normal case, get a function pointer
2415 void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature);
2416 if (fptr) {
2417 *((void**)address) = fptr;
2418 return true;
2419 }
2420
2421 return false;
2422}
2423
2424
2425//- std::function converter --------------------------------------------------
2426bool CPyCppyy::StdFunctionConverter::SetArg(
2427 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2428{
2429// prefer normal "object" conversion
2430 bool rf = ctxt->fFlags & CallContext::kNoImplicit;
2432 if (fConverter->SetArg(pyobject, para, ctxt)) {
2433 if (!rf) ctxt->fFlags &= ~CallContext::kNoImplicit;
2434 return true;
2435 }
2436
2437 PyErr_Clear();
2438
2439// else create a wrapper function
2440 if (this->FunctionPointerConverter::SetArg(pyobject, para, ctxt)) {
2441 // retrieve the wrapper pointer and capture it in a temporary std::function,
2442 // then try normal conversion a second time
2443 PyObject* func = this->FunctionPointerConverter::FromMemory(&para.fValue.fVoidp);
2444 if (func) {
2445 Py_XDECREF(fFuncWrap); fFuncWrap = func;
2446 bool result = fConverter->SetArg(fFuncWrap, para, ctxt);
2447 if (!rf) ctxt->fFlags &= ~CallContext::kNoImplicit;
2448 return result;
2449 }
2450 }
2451
2452 if (!rf) ctxt->fFlags &= ~CallContext::kNoImplicit;
2453 return false;
2454}
2455
2456PyObject* CPyCppyy::StdFunctionConverter::FromMemory(void* address)
2457{
2458 return fConverter->FromMemory(address);
2459}
2460
2461bool CPyCppyy::StdFunctionConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt)
2462{
2463 return fConverter->ToMemory(value, address, ctxt);
2464}
2465
2466
2467//- smart pointer converters -------------------------------------------------
2468bool CPyCppyy::SmartPtrConverter::SetArg(
2469 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2470{
2471 char typeCode = fIsRef ? 'p' : 'V';
2472
2473 if (!CPPInstance_Check(pyobject)) {
2474 // TODO: not sure how this is correct for pass-by-ref nor does it help with
2475 // implicit conversions for pass-by-value
2476 if (fIsRef && GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) {
2477 para.fTypeCode = typeCode; // allow special cases such as nullptr
2478 return true;
2479 }
2480
2481 return false;
2482 }
2483
2484 CPPInstance* pyobj = (CPPInstance*)pyobject;
2485
2486// for the case where we have a 'hidden' smart pointer:
2487 if (Cppyy::TCppType_t tsmart = pyobj->GetSmartIsA()) {
2488 if (Cppyy::IsSubtype(tsmart, fSmartPtrType)) {
2489 // depending on memory policy, some objects need releasing when passed into functions
2490 if (fKeepControl && !UseStrictOwnership(ctxt))
2491 ((CPPInstance*)pyobject)->CppOwns();
2492
2493 // calculate offset between formal and actual arguments
2494 para.fValue.fVoidp = pyobj->GetSmartObject();
2495 if (tsmart != fSmartPtrType) {
2497 tsmart, fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */);
2498 }
2499
2500 // set pointer (may be null) and declare success
2501 para.fTypeCode = typeCode;
2502 return true;
2503 }
2504 }
2505
2506// for the case where we have an 'exposed' smart pointer:
2507 if (!pyobj->IsSmart() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fSmartPtrType)) {
2508 // calculate offset between formal and actual arguments
2509 para.fValue.fVoidp = pyobj->GetObject();
2510 if (pyobj->ObjectIsA() != fSmartPtrType) {
2512 pyobj->ObjectIsA(), fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */);
2513 }
2514
2515 // set pointer (may be null) and declare success
2516 para.fTypeCode = typeCode;
2517 return true;
2518 }
2519
2520// final option, try mapping pointer types held (TODO: do not allow for non-const ref)
2521 if (pyobj->IsSmart() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fUnderlyingType)) {
2522 para.fValue.fVoidp = ((CPPInstance*)pyobject)->GetSmartObject();
2523 para.fTypeCode = 'V';
2524 return true;
2525 }
2526
2527 return false;
2528}
2529
2530PyObject* CPyCppyy::SmartPtrConverter::FromMemory(void* address)
2531{
2532 if (!address || !fSmartPtrType)
2533 return nullptr;
2534
2535 return BindCppObjectNoCast(address, fSmartPtrType);
2536}
2537
2538
2539//----------------------------------------------------------------------------
2540namespace {
2541
2542// clang libcpp and gcc use the same structure (ptr, size)
2543#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2544struct faux_initlist
2545{
2546 typedef size_t size_type;
2547 typedef void* iterator;
2548 iterator _M_array;
2549 size_type _M_len;
2550};
2551#elif defined (_MSC_VER)
2552struct faux_initlist
2553{
2554 typedef char* iterator;
2555 iterator _M_array; // ie. _First;
2556 iterator _Last;
2557};
2558#else
2559#define NO_KNOWN_INITIALIZER_LIST 1
2560#endif
2561
2562} // unnamed namespace
2563
2564CPyCppyy::InitializerListConverter::~InitializerListConverter()
2565{
2566 if (fConverter && fConverter->HasState()) delete fConverter;
2567}
2568
2569bool CPyCppyy::InitializerListConverter::SetArg(
2570 PyObject* pyobject, Parameter& para, CallContext* /*ctxt*/)
2571{
2572#ifdef NO_KNOWN_INITIALIZER_LIST
2573 return false;
2574#else
2575// convert the given argument to an initializer list temporary; this is purely meant
2576// to be a syntactic thing, so only _python_ sequences are allowed; bound C++ proxies
2577// are therefore rejected (should go through eg. a copy constructor etc.)
2578 if (CPPInstance_Check(pyobject) || !PySequence_Check(pyobject) || CPyCppyy_PyText_Check(pyobject)
2579#if PY_VERSION_HEX >= 0x03000000
2580 || PyBytes_Check(pyobject)
2581#endif
2582 )
2583 return false;
2584
2585 void* buf;
2586 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', (int)fValueSize, buf, true);
2587 faux_initlist* fake = nullptr;
2588 if (buf && buflen) {
2589 // dealing with an array here, pass on whole-sale
2590 fake = (faux_initlist*)malloc(sizeof(faux_initlist));
2591 fake->_M_array = (faux_initlist::iterator)buf;
2592#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2593 fake->_M_len = (faux_initlist::size_type)buflen;
2594#elif defined (_MSC_VER)
2595 fake->_Last = fake->_M_array+buflen*fValueSize;
2596#endif
2597 } else {
2598 // can only construct empty lists, so use a fake initializer list
2599 size_t len = (size_t)PySequence_Size(pyobject);
2600 fake = (faux_initlist*)malloc(sizeof(faux_initlist)+fValueSize*len);
2601 fake->_M_array = (faux_initlist::iterator)((char*)fake+sizeof(faux_initlist));
2602#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2603 fake->_M_len = (faux_initlist::size_type)len;
2604 for (faux_initlist::size_type i = 0; i < fake->_M_len; ++i) {
2605#elif defined (_MSC_VER)
2606 fake->_Last = fake->_M_array+len*fValueSize;
2607 for (size_t i = 0; (fake->_M_array+i*fValueSize) != fake->_Last; ++i) {
2608#endif
2609 PyObject* item = PySequence_GetItem(pyobject, i);
2610 bool convert_ok = false;
2611 if (item) {
2612 if (!fConverter) {
2613 if (CPPInstance_Check(item)) {
2614 // by convention, use byte copy
2615 memcpy((char*)fake->_M_array + i*fValueSize,
2616 ((CPPInstance*)item)->GetObject(), fValueSize);
2617 convert_ok = true;
2618 }
2619 } else
2620 convert_ok = fConverter->ToMemory(item, (char*)fake->_M_array + i*fValueSize);
2621
2622 Py_DECREF(item);
2623 } else
2624 PyErr_Format(PyExc_TypeError, "failed to get item %d from sequence", (int)i);
2625
2626 if (!convert_ok) {
2627 free((void*)fake);
2628 return false;
2629 }
2630 }
2631 }
2632
2633 para.fValue.fVoidp = (void*)fake;
2634 para.fTypeCode = 'X'; // means ptr that backend has to free after call
2635 return true;
2636#endif
2637}
2638
2639//----------------------------------------------------------------------------
2640bool CPyCppyy::NotImplementedConverter::SetArg(PyObject*, Parameter&, CallContext*)
2641{
2642// raise a NotImplemented exception to take a method out of overload resolution
2643 PyErr_SetString(PyExc_NotImplementedError, "this method cannot (yet) be called");
2644 return false;
2645}
2646
2647
2648//- helper to refactor some code from CreateConverter ------------------------
2650 Cppyy::TCppScope_t klass, const std::string& cpd, long size, dims_t dims, bool isConst, bool control)
2651{
2652 using namespace CPyCppyy;
2653 Converter* result = nullptr;
2654
2655 if (cpd == "**" || cpd == "*[]" || cpd == "&*")
2656 result = new InstancePtrPtrConverter<false>(klass, control);
2657 else if (cpd == "*&")
2658 result = new InstancePtrPtrConverter<true>(klass, control);
2659 else if (cpd == "*" && size <= 0)
2660 result = new InstancePtrConverter(klass, control);
2661 else if (cpd == "&")
2662 result = new InstanceRefConverter(klass, isConst);
2663 else if (cpd == "&&")
2664 result = new InstanceMoveConverter(klass);
2665 else if (cpd == "[]" || size > 0)
2666 result = new InstanceArrayConverter(klass, dims, false);
2667 else if (cpd == "") // by value
2668 result = new InstanceConverter(klass, true);
2669
2670 return result;
2671}
2672
2673//- factories ----------------------------------------------------------------
2675CPyCppyy::Converter* CPyCppyy::CreateConverter(const std::string& fullType, dims_t dims)
2676{
2677// The matching of the fulltype to a converter factory goes through up to five levels:
2678// 1) full, exact match
2679// 2) match of decorated, unqualified type
2680// 3) accept const ref as by value
2681// 4) accept ref as pointer
2682// 5) generalized cases (covers basically all C++ classes)
2683//
2684// If all fails, void is used, which will generate a run-time warning when used.
2685
2686 dim_t size = (dims && dims[0] != -1) ? dims[1] : -1;
2687
2688// an exactly matching converter is best
2689 ConvFactories_t::iterator h = gConvFactories.find(fullType);
2690 if (h != gConvFactories.end())
2691 return (h->second)(dims);
2692
2693// resolve typedefs etc.
2694 const std::string& resolvedType = Cppyy::ResolveName(fullType);
2695
2696// a full, qualified matching converter is preferred
2697 if (resolvedType != fullType) {
2698 h = gConvFactories.find(resolvedType);
2699 if (h != gConvFactories.end())
2700 return (h->second)(dims);
2701 }
2702
2703//-- nothing? ok, collect information about the type and possible qualifiers/decorators
2704 bool isConst = strncmp(resolvedType.c_str(), "const", 5) == 0;
2705 const std::string& cpd = Utility::Compound(resolvedType);
2706 std::string realType = TypeManip::clean_type(resolvedType, false, true);
2707
2708// accept unqualified type (as python does not know about qualifiers)
2709 h = gConvFactories.find(realType + cpd);
2710 if (h != gConvFactories.end())
2711 return (h->second)(dims);
2712
2713// drop const, as that is mostly meaningless to python (with the exception
2714// of c-strings, but those are specialized in the converter map)
2715 if (isConst) {
2716 realType = TypeManip::remove_const(realType);
2717 h = gConvFactories.find(realType + cpd);
2718 if (h != gConvFactories.end())
2719 return (h->second)(dims);
2720 }
2721
2722//-- still nothing? try pointer instead of array (for builtins)
2723 if (cpd == "[]") {
2724 // simple array
2725 h = gConvFactories.find(realType + "*");
2726 if (h != gConvFactories.end()) {
2727 if (dims && dims[1] == UNKNOWN_SIZE) dims[1] = UNKNOWN_ARRAY_SIZE;
2728 return (h->second)(dims);
2729 }
2730 } else if (cpd == "*[]") {
2731 // array of pointers
2732 h = gConvFactories.find(realType + "*");
2733 if (h != gConvFactories.end()) {
2734 // upstream treats the pointer type as the array element type, but that pointer is
2735 // treated as a low-level view as well, so adjust the dims
2736 dim_t newdim = (dims && 0 < dims[0]) ? dims[0]+1 : 2;
2737 dims_t newdims = new dim_t[newdim+1];
2738 newdims[0] = newdim;
2739 newdims[1] = (0 < size ? size : UNKNOWN_ARRAY_SIZE); // the array
2740 newdims[2] = UNKNOWN_SIZE; // the pointer
2741 if (dims && 2 < newdim) {
2742 for (int i = 2; i < (newdim-1); ++i)
2743 newdims[i+1] = dims[i];
2744 }
2745 Converter* cnv = (h->second)(newdims);
2746 delete [] newdims;
2747 return cnv;
2748 }
2749 }
2750
2751//-- special case: initializer list
2752 if (realType.compare(0, 16, "initializer_list") == 0) {
2753 // get the type of the list and create a converter (TODO: get hold of value_type?)
2754 auto pos = realType.find('<');
2755 std::string value_type = realType.substr(pos+1, realType.size()-pos-2);
2756 Converter* cnv = nullptr; bool use_byte_cnv = false;
2757 if (cpd == "" && Cppyy::GetScope(value_type)) {
2758 // initializer list of object values does not work as the target is raw
2759 // memory; simply use byte copies
2760
2761 // by convention, leave cnv as nullptr
2762 use_byte_cnv = true;
2763 } else
2764 cnv = CreateConverter(value_type);
2765 if (cnv || use_byte_cnv)
2766 return new InitializerListConverter(cnv, Cppyy::SizeOf(value_type));
2767 }
2768
2769//-- still nothing? use a generalized converter
2770 bool control = cpd == "&" || isConst;
2771
2772//-- special case: std::function
2773 auto pos = resolvedType.find("function<");
2774 if (pos == 0 /* no std:: */ || pos == 5 /* with std:: */ ||
2775 pos == 6 /* const no std:: */ || pos == 11 /* const with std:: */ ) {
2776
2777 // get actual converter for normal passing
2779 Cppyy::GetScope(realType), cpd, size, dims, isConst, control);
2780
2781 if (cnv) {
2782 // get the type of the underlying (TODO: use target_type?)
2783 auto pos1 = resolvedType.find("(", pos+9);
2784 auto pos2 = resolvedType.rfind(")");
2785 if (pos1 != std::string::npos && pos2 != std::string::npos) {
2786 auto sz1 = pos1-pos-9;
2787 if (resolvedType[pos+9+sz1-1] == ' ') sz1 -= 1;
2788
2789 return new StdFunctionConverter(cnv,
2790 resolvedType.substr(pos+9, sz1), resolvedType.substr(pos1, pos2-pos1+1));
2791 } else if (cnv->HasState())
2792 delete cnv;
2793 }
2794 }
2795
2796// converters for known C++ classes and default (void*)
2797 Converter* result = nullptr;
2798 if (Cppyy::TCppScope_t klass = Cppyy::GetScope(realType)) {
2799 Cppyy::TCppType_t raw{0};
2800 if (Cppyy::GetSmartPtrInfo(realType, &raw, nullptr)) {
2801 if (cpd == "") {
2802 result = new SmartPtrConverter(klass, raw, control);
2803 } else if (cpd == "&") {
2804 result = new SmartPtrConverter(klass, raw);
2805 } else if (cpd == "*" && size <= 0) {
2806 result = new SmartPtrConverter(klass, raw, control, true);
2807 }
2808 }
2809
2810 if (!result) {
2811 // CLING WORKAROUND -- special case for STL iterators
2812 if (realType.rfind("__gnu_cxx::__normal_iterator", 0) /* vector */ == 0
2813#ifdef __APPLE__
2814 || realType.rfind("__wrap_iter", 0) == 0
2815#endif
2816 // TODO: Windows?
2817 ) {
2818 static STLIteratorConverter c;
2819 result = &c;
2820 } else
2821 // -- CLING WORKAROUND
2822 result = selectInstanceCnv(klass, cpd, size, dims, isConst, control);
2823 }
2824 } else if (resolvedType.find("(*)") != std::string::npos ||
2825 (resolvedType.find("::*)") != std::string::npos)) {
2826 // this is a function function pointer
2827 // TODO: find better way of finding the type
2828 auto pos1 = resolvedType.find('(');
2829 auto pos2 = resolvedType.find("*)");
2830 auto pos3 = resolvedType.rfind(')');
2831 result = new FunctionPointerConverter(
2832 resolvedType.substr(0, pos1), resolvedType.substr(pos2+2, pos3-pos2-1));
2833 }
2834
2835 if (!result && cpd == "&&") {
2836 // for builtin, can use const-ref for r-ref
2837 h = gConvFactories.find("const " + realType + "&");
2838 if (h != gConvFactories.end())
2839 return (h->second)(dims);
2840 // else, unhandled moves
2841 result = new NotImplementedConverter();
2842 }
2843
2844 if (!result && h != gConvFactories.end())
2845 // converter factory available, use it to create converter
2846 result = (h->second)(dims);
2847 else if (!result) {
2848 // default to something reasonable, assuming "user knows best"
2849 if (cpd.size() == 2 && cpd != "&&") // "**", "*[]", "*&"
2850 result = new VoidPtrPtrConverter(size);
2851 else if (!cpd.empty())
2852 result = new VoidArrayConverter(); // "user knows best"
2853 else
2854 result = new NotImplementedConverter(); // fails on use
2855 }
2856
2857 return result;
2858}
2859
2860//----------------------------------------------------------------------------
2863{
2864 if (p && p->HasState())
2865 delete p; // state-less converters are always shared
2866}
2867
2868//----------------------------------------------------------------------------
2870bool CPyCppyy::RegisterConverter(const std::string& name, cf_t fac)
2871{
2872// register a custom converter
2873 auto f = gConvFactories.find(name);
2874 if (f != gConvFactories.end())
2875 return false;
2876
2877 gConvFactories[name] = fac;
2878 return true;
2879}
2880
2881//----------------------------------------------------------------------------
2883bool CPyCppyy::UnregisterConverter(const std::string& name)
2884{
2885// remove a custom converter
2886 auto f = gConvFactories.find(name);
2887 if (f != gConvFactories.end()) {
2888 gConvFactories.erase(f);
2889 return true;
2890 }
2891 return false;
2892}
2893
2894
2895//----------------------------------------------------------------------------
2896namespace {
2897
2898using namespace CPyCppyy;
2899
2900#define STRINGVIEW "basic_string_view<char,char_traits<char> >"
2901#define WSTRING "basic_string<wchar_t,char_traits<wchar_t>,allocator<wchar_t> >"
2902
2903static struct InitConvFactories_t {
2904public:
2905 InitConvFactories_t() {
2906 // load all converter factories in the global map 'gConvFactories'
2908
2909 // factories for built-ins
2910 gf["bool"] = (cf_t)+[](dims_t) { static BoolConverter c{}; return &c; };
2911 gf["const bool&"] = (cf_t)+[](dims_t) { static ConstBoolRefConverter c{}; return &c; };
2912 gf["bool&"] = (cf_t)+[](dims_t) { static BoolRefConverter c{}; return &c; };
2913 gf["char"] = (cf_t)+[](dims_t) { static CharConverter c{}; return &c; };
2914 gf["const char&"] = (cf_t)+[](dims_t) { static ConstCharRefConverter c{}; return &c; };
2915 gf["char&"] = (cf_t)+[](dims_t) { static CharRefConverter c{}; return &c; };
2916 gf["signed char&"] = (cf_t)+[](dims_t) { static SCharRefConverter c{}; return &c; };
2917 gf["unsigned char"] = (cf_t)+[](dims_t) { static UCharConverter c{}; return &c; };
2918 gf["const unsigned char&"] = (cf_t)+[](dims_t) { static ConstUCharRefConverter c{}; return &c; };
2919 gf["unsigned char&"] = (cf_t)+[](dims_t) { static UCharRefConverter c{}; return &c; };
2920 gf["UCharAsInt"] = (cf_t)+[](dims_t) { static UCharAsIntConverter c{}; return &c; };
2921 gf["wchar_t"] = (cf_t)+[](dims_t) { static WCharConverter c{}; return &c; };
2922 gf["char16_t"] = (cf_t)+[](dims_t) { static Char16Converter c{}; return &c; };
2923 gf["char32_t"] = (cf_t)+[](dims_t) { static Char32Converter c{}; return &c; };
2924 gf["wchar_t&"] = (cf_t)+[](dims_t) { static WCharRefConverter c{}; return &c; };
2925 gf["char16_t&"] = (cf_t)+[](dims_t) { static Char16RefConverter c{}; return &c; };
2926 gf["char32_t&"] = (cf_t)+[](dims_t) { static Char32RefConverter c{}; return &c; };
2927 gf["int8_t"] = (cf_t)+[](dims_t) { static Int8Converter c{}; return &c; };
2928 gf["int8_t&"] = (cf_t)+[](dims_t) { static Int8RefConverter c{}; return &c; };
2929 gf["const int8_t&"] = (cf_t)+[](dims_t) { static ConstInt8RefConverter c{}; return &c; };
2930 gf["uint8_t"] = (cf_t)+[](dims_t) { static UInt8Converter c{}; return &c; };
2931 gf["const uint8_t&"] = (cf_t)+[](dims_t) { static ConstUInt8RefConverter c{}; return &c; };
2932 gf["uint8_t&"] = (cf_t)+[](dims_t) { static UInt8RefConverter c{}; return &c; };
2933 gf["short"] = (cf_t)+[](dims_t) { static ShortConverter c{}; return &c; };
2934 gf["const short&"] = (cf_t)+[](dims_t) { static ConstShortRefConverter c{}; return &c; };
2935 gf["short&"] = (cf_t)+[](dims_t) { static ShortRefConverter c{}; return &c; };
2936 gf["unsigned short"] = (cf_t)+[](dims_t) { static UShortConverter c{}; return &c; };
2937 gf["const unsigned short&"] = (cf_t)+[](dims_t) { static ConstUShortRefConverter c{}; return &c; };
2938 gf["unsigned short&"] = (cf_t)+[](dims_t) { static UShortRefConverter c{}; return &c; };
2939 gf["int"] = (cf_t)+[](dims_t) { static IntConverter c{}; return &c; };
2940 gf["int&"] = (cf_t)+[](dims_t) { static IntRefConverter c{}; return &c; };
2941 gf["const int&"] = (cf_t)+[](dims_t) { static ConstIntRefConverter c{}; return &c; };
2942 gf["unsigned int"] = (cf_t)+[](dims_t) { static UIntConverter c{}; return &c; };
2943 gf["const unsigned int&"] = (cf_t)+[](dims_t) { static ConstUIntRefConverter c{}; return &c; };
2944 gf["unsigned int&"] = (cf_t)+[](dims_t) { static UIntRefConverter c{}; return &c; };
2945 gf["long"] = (cf_t)+[](dims_t) { static LongConverter c{}; return &c; };
2946 gf["long&"] = (cf_t)+[](dims_t) { static LongRefConverter c{}; return &c; };
2947 gf["const long&"] = (cf_t)+[](dims_t) { static ConstLongRefConverter c{}; return &c; };
2948 gf["unsigned long"] = (cf_t)+[](dims_t) { static ULongConverter c{}; return &c; };
2949 gf["const unsigned long&"] = (cf_t)+[](dims_t) { static ConstULongRefConverter c{}; return &c; };
2950 gf["unsigned long&"] = (cf_t)+[](dims_t) { static ULongRefConverter c{}; return &c; };
2951 gf["long long"] = (cf_t)+[](dims_t) { static LLongConverter c{}; return &c; };
2952 gf["const long long&"] = (cf_t)+[](dims_t) { static ConstLLongRefConverter c{}; return &c; };
2953 gf["long long&"] = (cf_t)+[](dims_t) { static LLongRefConverter c{}; return &c; };
2954 gf["unsigned long long"] = (cf_t)+[](dims_t) { static ULLongConverter c{}; return &c; };
2955 gf["const unsigned long long&"] = (cf_t)+[](dims_t) { static ConstULLongRefConverter c{}; return &c; };
2956 gf["unsigned long long&"] = (cf_t)+[](dims_t) { static ULLongRefConverter c{}; return &c; };
2957
2958 gf["float"] = (cf_t)+[](dims_t) { static FloatConverter c{}; return &c; };
2959 gf["const float&"] = (cf_t)+[](dims_t) { static ConstFloatRefConverter c{}; return &c; };
2960 gf["float&"] = (cf_t)+[](dims_t) { static FloatRefConverter c{}; return &c; };
2961 gf["double"] = (cf_t)+[](dims_t) { static DoubleConverter c{}; return &c; };
2962 gf["double&"] = (cf_t)+[](dims_t) { static DoubleRefConverter c{}; return &c; };
2963 gf["const double&"] = (cf_t)+[](dims_t) { static ConstDoubleRefConverter c{}; return &c; };
2964 gf["long double"] = (cf_t)+[](dims_t) { static LDoubleConverter c{}; return &c; };
2965 gf["const long double&"] = (cf_t)+[](dims_t) { static ConstLDoubleRefConverter c{}; return &c; };
2966 gf["long double&"] = (cf_t)+[](dims_t) { static LDoubleRefConverter c{}; return &c; };
2967 gf["std::complex<double>"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2968 gf["complex<double>"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2969 gf["const std::complex<double>&"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2970 gf["const complex<double>&"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2971 gf["void"] = (cf_t)+[](dims_t) { static VoidConverter c{}; return &c; };
2972
2973 // pointer/array factories
2974 gf["bool*"] = (cf_t)+[](dims_t d) { return new BoolArrayConverter{d}; };
2975 gf["bool**"] = (cf_t)+[](dims_t d) { return new BoolArrayPtrConverter{d}; };
2976 gf["const signed char[]"] = (cf_t)+[](dims_t d) { return new SCharArrayConverter{d}; };
2977 gf["signed char[]"] = (cf_t)+[](dims_t d) { return new SCharArrayConverter{d}; };
2978 gf["signed char**"] = (cf_t)+[](dims_t d) { return new SCharArrayPtrConverter{d}; };
2979 gf["const unsigned char*"] = (cf_t)+[](dims_t d) { return new UCharArrayConverter{d}; };
2980 gf["unsigned char*"] = (cf_t)+[](dims_t d) { return new UCharArrayConverter{d}; };
2981 gf["UCharAsInt*"] = (cf_t)+[](dims_t d) { return new UCharArrayConverter{d}; };
2982 gf["unsigned char**"] = (cf_t)+[](dims_t d) { return new UCharArrayPtrConverter{d}; };
2983#if __cplusplus > 201402L
2984 gf["byte*"] = (cf_t)+[](dims_t d) { return new ByteArrayConverter{d}; };
2985 gf["byte**"] = (cf_t)+[](dims_t d) { return new ByteArrayPtrConverter{d}; };
2986#endif
2987 gf["short*"] = (cf_t)+[](dims_t d) { return new ShortArrayConverter{d}; };
2988 gf["short**"] = (cf_t)+[](dims_t d) { return new ShortArrayPtrConverter{d}; };
2989 gf["unsigned short*"] = (cf_t)+[](dims_t d) { return new UShortArrayConverter{d}; };
2990 gf["unsigned short**"] = (cf_t)+[](dims_t d) { return new UShortArrayPtrConverter{d}; };
2991 gf["int*"] = (cf_t)+[](dims_t d) { return new IntArrayConverter{d}; };
2992 gf["int**"] = (cf_t)+[](dims_t d) { return new IntArrayPtrConverter{d}; };
2993 gf["unsigned int*"] = (cf_t)+[](dims_t d) { return new UIntArrayConverter{d}; };
2994 gf["unsigned int**"] = (cf_t)+[](dims_t d) { return new UIntArrayPtrConverter{d}; };
2995 gf["long*"] = (cf_t)+[](dims_t d) { return new LongArrayConverter{d}; };
2996 gf["long**"] = (cf_t)+[](dims_t d) { return new LongArrayPtrConverter{d}; };
2997 gf["unsigned long*"] = (cf_t)+[](dims_t d) { return new ULongArrayConverter{d}; };
2998 gf["unsigned long**"] = (cf_t)+[](dims_t d) { return new ULongArrayPtrConverter{d}; };
2999 gf["long long*"] = (cf_t)+[](dims_t d) { return new LLongArrayConverter{d}; };
3000 gf["long long**"] = (cf_t)+[](dims_t d) { return new LLongArrayPtrConverter{d}; };
3001 gf["unsigned long long*"] = (cf_t)+[](dims_t d) { return new ULLongArrayConverter{d}; };
3002 gf["unsigned long long**"] = (cf_t)+[](dims_t d) { return new ULLongArrayPtrConverter{d}; };
3003 gf["float*"] = (cf_t)+[](dims_t d) { return new FloatArrayConverter{d}; };
3004 gf["float**"] = (cf_t)+[](dims_t d) { return new FloatArrayPtrConverter{d}; };
3005 gf["double*"] = (cf_t)+[](dims_t d) { return new DoubleArrayConverter{d}; };
3006 gf["double**"] = (cf_t)+[](dims_t d) { return new DoubleArrayPtrConverter{d}; };
3007 gf["long double*"] = (cf_t)+[](dims_t d) { return new LDoubleArrayConverter{d}; };
3008 gf["long double**"] = (cf_t)+[](dims_t d) { return new LDoubleArrayPtrConverter{d}; };
3009 gf["std::complex<double>*"] = (cf_t)+[](dims_t d) { return new ComplexDArrayConverter{d}; };
3010 gf["complex<double>*"] = (cf_t)+[](dims_t d) { return new ComplexDArrayConverter{d}; };
3011 gf["std::complex<double>**"] = (cf_t)+[](dims_t d) { return new ComplexDArrayPtrConverter{d}; };
3012 gf["void*"] = (cf_t)+[](dims_t d) { return new VoidArrayConverter{(bool)d}; };
3013
3014 // aliases
3015 gf["signed char"] = gf["char"];
3016 gf["const signed char&"] = gf["const char&"];
3017#if __cplusplus > 201402L
3018 gf["byte"] = gf["uint8_t"];
3019 gf["const byte&"] = gf["const uint8_t&"];
3020 gf["byte&"] = gf["uint8&"];
3021#endif
3022 gf["internal_enum_type_t"] = gf["int"];
3023 gf["internal_enum_type_t&"] = gf["int&"];
3024 gf["const internal_enum_type_t&"] = gf["const int&"];
3025 gf["Long64_t"] = gf["long long"];
3026 gf["Long64_t*"] = gf["long long*"];
3027 gf["Long64_t&"] = gf["long long&"];
3028 gf["const Long64_t&"] = gf["const long long&"];
3029 gf["ULong64_t"] = gf["unsigned long long"];
3030 gf["ULong64_t*"] = gf["unsigned long long*"];
3031 gf["ULong64_t&"] = gf["unsigned long long&"];
3032 gf["const ULong64_t&"] = gf["const unsigned long long&"];
3033 gf["Float16_t"] = gf["float"];
3034 gf["const Float16_t&"] = gf["const float&"];
3035 gf["Double32_t"] = gf["double"];
3036 gf["Double32_t&"] = gf["double&"];
3037 gf["const Double32_t&"] = gf["const double&"];
3038
3039 // factories for special cases
3040 gf["TString"] = (cf_t)+[](dims_t) { return new TStringConverter{}; };
3041 gf["TString&"] = gf["TString"];
3042 gf["const TString&"] = gf["TString"];
3043 gf["nullptr_t"] = (cf_t)+[](dims_t) { static NullptrConverter c{}; return &c;};
3044 gf["const char*"] = (cf_t)+[](dims_t) { return new CStringConverter{}; };
3045 gf["const signed char*"] = gf["const char*"];
3046 gf["const char[]"] = (cf_t)+[](dims_t) { return new CStringConverter{}; };
3047 gf["char*"] = (cf_t)+[](dims_t) { return new NonConstCStringConverter{}; };
3048 gf["signed char*"] = gf["char*"];
3049 gf["wchar_t*"] = (cf_t)+[](dims_t) { return new WCStringConverter{}; };
3050 gf["char16_t*"] = (cf_t)+[](dims_t) { return new CString16Converter{}; };
3051 gf["char32_t*"] = (cf_t)+[](dims_t) { return new CString32Converter{}; };
3052 // TODO: the following are handled incorrectly upstream (char16_t** where char16_t* intended)?!
3053 gf["char16_t**"] = gf["char16_t*"];
3054 gf["char32_t**"] = gf["char32_t*"];
3055 gf["const char**"] = (cf_t)+[](dims_t d) { return new CStringArrayConverter{d}; };
3056 gf["char**"] = gf["const char**"];
3057 gf["const char*[]"] = gf["const char**"];
3058 gf["char*[]"] = gf["const char*[]"];
3059 gf["std::string"] = (cf_t)+[](dims_t) { return new STLStringConverter{}; };
3060 gf["string"] = gf["std::string"];
3061 gf["const std::string&"] = gf["std::string"];
3062 gf["const string&"] = gf["std::string"];
3063 gf["string&&"] = (cf_t)+[](dims_t) { return new STLStringMoveConverter{}; };
3064 gf["std::string&&"] = gf["string&&"];
3065 gf["std::string_view"] = (cf_t)+[](dims_t) { return new STLStringViewConverter{}; };
3066 gf["string_view"] = gf["std::string_view"];
3067 gf[STRINGVIEW] = gf["std::string_view"];
3068 gf["experimental::" STRINGVIEW] = gf["std::string_view"];
3069 gf["std::string_view&"] = gf["std::string_view"];
3070 gf["const string_view&"] = gf["std::string_view"];
3071 gf["const " STRINGVIEW "&"] = gf["std::string_view"];
3072 gf["std::wstring"] = (cf_t)+[](dims_t) { return new STLWStringConverter{}; };
3073 gf[WSTRING] = gf["std::wstring"];
3074 gf["std::" WSTRING] = gf["std::wstring"];
3075 gf["const std::wstring&"] = gf["std::wstring"];
3076 gf["const std::" WSTRING "&"] = gf["std::wstring"];
3077 gf["const " WSTRING "&"] = gf["std::wstring"];
3078 gf["void*&"] = (cf_t)+[](dims_t) { static VoidPtrRefConverter c{}; return &c; };
3079 gf["void**"] = (cf_t)+[](dims_t d) { return new VoidPtrPtrConverter{size_t((d && d[0] != -1) ? d[1] : -1)}; };
3080 gf["void*[]"] = (cf_t)+[](dims_t d) { return new VoidPtrPtrConverter{size_t((d && d[0] != -1) ? d[1] : -1)}; };
3081 gf["PyObject*"] = (cf_t)+[](dims_t) { static PyObjectConverter c{}; return &c; };
3082 gf["_object*"] = gf["PyObject*"];
3083 gf["FILE*"] = (cf_t)+[](dims_t) { return new VoidArrayConverter{}; };
3084 }
3085} initConvFactories_;
3086
3087} // unnamed namespace
#define Py_TYPE(ob)
Definition CPyCppyy.h:217
static Py_ssize_t CPyCppyy_PyUnicode_AsWideChar(PyObject *pyobj, wchar_t *w, Py_ssize_t size)
Definition CPyCppyy.h:222
#define PyBytes_AS_STRING
Definition CPyCppyy.h:85
#define CPyCppyy_PyText_FromStringAndSize
Definition CPyCppyy.h:106
#define CPyCppyy_PyUnicode_GET_SIZE
Definition CPyCppyy.h:117
#define PY_SSIZE_T_FORMAT
Definition CPyCppyy.h:239
#define PyBytes_Check
Definition CPyCppyy.h:83
static void * CPyCppyy_PyCapsule_GetPointer(PyObject *capsule, const char *)
Definition CPyCppyy.h:125
#define CPyCppyy_PyText_AsString
Definition CPyCppyy.h:97
#define CPyCppyy_PyText_GET_SIZE
Definition CPyCppyy.h:99
#define CPyCppyy_PyCapsule_CheckExact
Definition CPyCppyy.h:124
#define Py_RETURN_NONE
Definition CPyCppyy.h:289
static const char * CPyCppyy_PyText_AsStringAndSize(PyObject *pystr, Py_ssize_t *size)
Definition CPyCppyy.h:108
static PyObject * PyObject_CallMethodNoArgs(PyObject *obj, PyObject *name)
Definition CPyCppyy.h:315
#define CPyCppyy_PyText_FromString
Definition CPyCppyy.h:102
#define CPyCppyy_PyText_Check
Definition CPyCppyy.h:95
static unsigned short CPyCppyy_PyLong_AsUShort(PyObject *pyobject)
#define CPPYY_IMPL_BASIC_CONVERTER(name, type, stype, ctype, F1, F2, tc)
#define CPPYY_IMPL_ARRAY_CONVERTER(name, ctype, type, code)
static bool ConvertImplicit(Cppyy::TCppType_t klass, PyObject *pyobject, CPyCppyy::Parameter &para, CPyCppyy::CallContext *ctxt)
static std::map< void *, PyObject ** > sWrapperReference
static bool CPyCppyy_PyLong_AsBool(PyObject *pyobject)
static bool IsPyCArgObject(PyObject *pyobject)
static std::array< PyTypeObject *, 22 > gCTypesTypes
static PyObject * WrapperCacheEraser(PyObject *, PyObject *pyref)
#define CPPYY_IMPL_STRING_AS_PRIMITIVE_CONVERTER(name, type, F1, F2)
#define CPPYY_IMPL_BASIC_CHAR_CONVERTER(name, type, low, high)
const size_t MOVE_REFCOUNT_CUTOFF
#define ct_c_long
static char CPyCppyy_PyText_AsChar(PyObject *pyobject)
#define CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(name, type, ctype, low, high)
static bool SetLifeLine(PyObject *holder, PyObject *target, intptr_t ref)
static std::map< RetSigKey_t, std::map< PyObject *, void * > > sWrapperLookup
static std::array< PyTypeObject *, 22 > gCTypesPtrTypes
static int ExtractChar(PyObject *pyobject, const char *tname, int low, int high)
static std::array< const char *, 22 > gCTypesNames
static void init_shape(Py_ssize_t defdim, dims_t dims, Py_ssize_t *&shape)
static PyTypeObject * GetCTypesPtrType(int nidx)
static std::map< PyObject *, std::pair< void *, RetSigKey_t > > sWrapperWeakRefs
#define ct_c_char_p
#define ct_c_int
static int8_t CPyCppyy_PyLong_AsInt8(PyObject *pyobject)
std::pair< std::string, std::string > RetSigKey_t
static PyMethodDef gWrapperCacheEraserMethodDef
#define CPPYY_IMPL_BASIC_CONST_REFCONVERTER(name, type, ctype, F1)
static CPyCppyy::Converter * selectInstanceCnv(Cppyy::TCppScope_t klass, const std::string &cpd, long size, dims_t dims, bool isConst, bool control)
static uint8_t CPyCppyy_PyLong_AsUInt8(PyObject *pyobject)
static short CPyCppyy_PyLong_AsShort(PyObject *pyobject)
static long CPyCppyy_PyLong_AsStrictLong(PyObject *pyobject)
static CPyCppyy::CPPInstance * GetCppInstance(PyObject *pyobject)
#define WSTRING
#define UNKNOWN_ARRAY_SIZE
#define CPPYY_IMPL_REFCONVERTER(name, ctype, type, code)
static PyTypeObject * GetCTypesType(int nidx)
#define ct_c_void_p
#define UNKNOWN_SIZE
static bool CArraySetArg(PyObject *pyobject, CPyCppyy::Parameter &para, char tc, int size)
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
static void * PyFunction_AsCPointer(PyObject *pyobject, const std::string &rettype, const std::string &signature)
#define CPPYY_IMPL_REFCONVERTER_FROM_MEMORY(name, ctype)
std::string fRetType
Py_ssize_t * fShape
size_t fSize
long fMaxSize
size_t fValueSize
bool fIsConst
bool fKeepControl
std::string fBuffer
bool fIsRef
PyObject * fFuncWrap
Cppyy::TCppType_t fClass
dims_t m_dims
Cppyy::TCppType_t fSmartPtrType
std::string fSignature
Cppyy::TCppType_t fUnderlyingType
Converter * fConverter
_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
unsigned long ULong_t
Definition RtypesCore.h:55
unsigned int UInt_t
Definition RtypesCore.h:46
long double LongDouble_t
Definition RtypesCore.h:61
long long Long64_t
Definition RtypesCore.h:80
unsigned long long ULong64_t
Definition RtypesCore.h:81
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 data
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
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
Cppyy::TCppType_t ObjectIsA(bool check_smart=true) const
MethodInfo_t * fMethodInfo
Definition CPPOverload.h:72
virtual bool SetArg(PyObject *, Parameter &, CallContext *=nullptr)=0
virtual bool HasState()
Definition API.h:105
virtual bool ToMemory(PyObject *value, void *address, PyObject *ctxt=nullptr)
virtual PyObject * FromMemory(void *address)
virtual bool SetArg(PyObject *, Parameter &, CallContext *=nullptr)
virtual PyObject * FromMemory(void *address)
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 * gEmptyString
Definition PyStrings.cxx:16
std::string remove_const(const std::string &cppname)
Definition TypeManip.cxx:71
std::string clean_type(const std::string &cppname, bool template_strip=true, bool const_strip=true)
Definition TypeManip.cxx:98
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:518
void ConstructCallbackReturn(const std::string &retType, int nArgs, std::ostringstream &code)
Definition Utility.cxx:562
Py_ssize_t GetBuffer(PyObject *pyobject, char tc, int size, void *&buf, bool check=true)
Definition Utility.cxx:679
PyObject * FuncPtr2StdFunction(const std::string &retType, const std::string &signature, void *address)
Definition Utility.cxx:598
const std::string Compound(const std::string &name)
Definition Utility.cxx:848
unsigned long PyLongOrInt_AsULong(PyObject *pyobject)
Definition Utility.cxx:131
bool TupleOfInstances_CheckExact(T *object)
PyObject * CreatePointerView(void *ptr, size_t size=(size_t) -1)
bool RefFloat_CheckExact(T *object)
bool CPPExcInstance_Check(T *object)
bool NoImplicit(CallContext *ctxt)
static ConvFactories_t gConvFactories
PyObject * CreateLowLevelView(bool *, Py_ssize_t *shape=nullptr)
PyObject * BindCppObjectNoCast(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
bool CPPOverload_Check(T *object)
Definition CPPOverload.h:83
bool RefInt_CheckExact(T *object)
bool CPPScope_Check(T *object)
Definition CPPScope.h:76
CPYCPPYY_EXTERN bool RegisterConverter(const std::string &name, ConverterFactory_t)
bool AllowImplicit(CallContext *ctxt)
bool UseStrictOwnership(CallContext *ctxt)
bool CPPInstance_Check(T *object)
PyObject * CreateScopeProxy(Cppyy::TCppScope_t)
Converter *(* cf_t)(dims_t d)
Definition Converters.h:27
PyObject * gNullPtrObject
bool IsConstructor(uint64_t flags)
PyObject * BindCppObject(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
ULong64_t PyLongOrInt_AsULong64(PyObject *pyobject)
Definition Utility.cxx:151
CPYCPPYY_EXTERN void DestroyConverter(Converter *p)
bool TemplateProxy_Check(T *object)
std::map< std::string, cf_t > ConvFactories_t
PyObject * BindCppObjectArray(Cppyy::TCppObject_t address, Cppyy::TCppType_t klass, Py_ssize_t *dims)
CPYCPPYY_EXTERN bool UnregisterConverter(const std::string &name)
CPYCPPYY_EXTERN Converter * CreateConverter(const std::string &name, Py_ssize_t *dims=nullptr)
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 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 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)
RPY_EXPORTED bool Compile(const std::string &code)
RooArgList L(Args_t &&... args)
Definition RooArgList.h:156
CPPOverload::Methods_t fMethods
Definition CPPOverload.h:47
static ECallFlags sMemoryPolicy
Definition CallContext.h:71
Cppyy::TCppScope_t fCurScope
Definition CallContext.h:99
void AddTemporary(PyObject *pyobj)
union CPyCppyy::Parameter::Value fValue
PyObject_HEAD char * b_ptr
union CPyCppyy_tagPyCArgObject::@205 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