Logo ROOT  
Reference Guide
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 "ROOT/RStringView.hxx"
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++
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
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)
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 if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1812 // depending on memory policy, some objects need releasing when passed into functions
1813 if (!KeepControl() && !UseStrictOwnership(ctxt))
1814 pyobj->CppOwns();
1815
1816 // calculate offset between formal and actual arguments
1817 para.fValue.fVoidp = pyobj->GetObject();
1818 if (pyobj->ObjectIsA() != fClass) {
1820 pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */);
1821 }
1822
1823 // set pointer (may be null) and declare success
1824 para.fTypeCode = 'p';
1825 return true;
1826 }
1827
1828 return false;
1829}
1830
1831//----------------------------------------------------------------------------
1833{
1834// construct python object from C++ instance read at <address>
1836}
1837
1838//----------------------------------------------------------------------------
1840{
1841// convert <value> to C++ instance, write it at <address>
1843 if (!pyobj) {
1844 void* ptr = nullptr;
1845 if (GetAddressSpecialCase(value, ptr)) {
1846 *(void**)address = ptr; // allow special cases such as nullptr
1847 return true;
1848 }
1849
1850 // not a cppyy object (TODO: handle SWIG etc.)
1851 return false;
1852 }
1853
1854 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1855 // depending on memory policy, some objects need releasing when passed into functions
1856 if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict)
1857 ((CPPInstance*)value)->CppOwns();
1858
1859 *(void**)address = pyobj->GetObject();
1860 return true;
1861 }
1862
1863 return false;
1864}
1865
1866// TODO: CONSOLIDATE Instance, InstanceRef, InstancePtr ...
1867
1868//----------------------------------------------------------------------------
1869bool CPyCppyy::InstanceConverter::SetArg(
1870 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1871{
1872// convert <pyobject> to C++ instance, set arg for call
1873 CPPInstance* pyobj = GetCppInstance(pyobject);
1874 if (pyobj) {
1875 if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1876 // calculate offset between formal and actual arguments
1877 para.fValue.fVoidp = pyobj->GetObject();
1878 if (!para.fValue.fVoidp)
1879 return false;
1880
1881 if (pyobj->ObjectIsA() != fClass) {
1883 pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */);
1884 }
1885
1886 para.fTypeCode = 'V';
1887 return true;
1888 }
1889 }
1890
1891 return ConvertImplicit(fClass, pyobject, para, ctxt);
1892}
1893
1894//----------------------------------------------------------------------------
1895PyObject* CPyCppyy::InstanceConverter::FromMemory(void* address)
1896{
1898}
1899
1900//----------------------------------------------------------------------------
1901bool CPyCppyy::InstanceConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
1902{
1903// assign value to C++ instance living at <address> through assignment operator
1904 PyObject* pyobj = BindCppObjectNoCast(address, fClass);
1905 PyObject* result = PyObject_CallMethod(pyobj, (char*)"__assign__", (char*)"O", value);
1906 Py_DECREF(pyobj);
1907
1908 if (result) {
1909 Py_DECREF(result);
1910 return true;
1911 }
1912 return false;
1913}
1914
1915
1916//----------------------------------------------------------------------------
1917bool CPyCppyy::InstanceRefConverter::SetArg(
1918 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1919{
1920// convert <pyobject> to C++ instance&, set arg for call
1921 CPPInstance* pyobj = GetCppInstance(pyobject);
1922 if (pyobj) {
1923
1924 // reject moves
1925 if (pyobj->fFlags & CPPInstance::kIsRValue)
1926 return false;
1927
1928 if (pyobj->ObjectIsA() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1929 // calculate offset between formal and actual arguments
1930 para.fValue.fVoidp = pyobj->GetObject();
1931 if (pyobj->ObjectIsA() != fClass) {
1933 pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */);
1934 }
1935
1936 para.fTypeCode = 'V';
1937 return true;
1938 }
1939 }
1940
1941 if (!fIsConst) // no implicit conversion possible
1942 return false;
1943
1944 return ConvertImplicit(fClass, pyobject, para, ctxt);
1945}
1946
1947//----------------------------------------------------------------------------
1948PyObject* CPyCppyy::InstanceRefConverter::FromMemory(void* address)
1949{
1951}
1952
1953//----------------------------------------------------------------------------
1954bool CPyCppyy::InstanceMoveConverter::SetArg(
1955 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1956{
1957// convert <pyobject> to C++ instance&&, set arg for call
1958 CPPInstance* pyobj = GetCppInstance(pyobject);
1959 if (!pyobj) {
1960 // implicit conversion is fine as it the temporary by definition is moveable
1961 return ConvertImplicit(fClass, pyobject, para, ctxt);
1962 }
1963
1964// moving is same as by-ref, but have to check that move is allowed
1965 int moveit_reason = 0;
1966 if (pyobj->fFlags & CPPInstance::kIsRValue) {
1967 pyobj->fFlags &= ~CPPInstance::kIsRValue;
1968 moveit_reason = 2;
1969 } else if (pyobject->ob_refcnt == MOVE_REFCOUNT_CUTOFF) {
1970 moveit_reason = 1;
1971 }
1972
1973 if (moveit_reason) {
1974 bool result = this->InstanceRefConverter::SetArg(pyobject, para, ctxt);
1975 if (!result && moveit_reason == 2) // restore the movability flag?
1976 ((CPPInstance*)pyobject)->fFlags |= CPPInstance::kIsRValue;
1977 return result;
1978 }
1979
1980 PyErr_SetString(PyExc_ValueError, "object is not an rvalue");
1981 return false; // not a temporary or movable object
1982}
1983
1984//----------------------------------------------------------------------------
1985template <bool ISREFERENCE>
1986bool CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::SetArg(
1987 PyObject* pyobject, Parameter& para, CallContext* ctxt)
1988{
1989// convert <pyobject> to C++ instance**, set arg for call
1990 CPPInstance* pyobj = GetCppInstance(pyobject);
1991 if (!pyobj)
1992 return false; // not a cppyy object (TODO: handle SWIG etc.)
1993
1994 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
1995 // depending on memory policy, some objects need releasing when passed into functions
1996 if (!KeepControl() && !UseStrictOwnership(ctxt))
1997 pyobj->CppOwns();
1998
1999 // set pointer (may be null) and declare success
2000 if (pyobj->fFlags & CPPInstance::kIsReference) // already a ptr to object?
2001 para.fValue.fVoidp = pyobj->GetObjectRaw();
2002 else
2003 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2004 para.fTypeCode = ISREFERENCE ? 'V' : 'p';
2005 return true;
2006 }
2007
2008 return false;
2009}
2010
2011//----------------------------------------------------------------------------
2012template <bool ISREFERENCE>
2013PyObject* CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::FromMemory(void* address)
2014{
2015// construct python object from C++ instance* read at <address>
2017}
2018
2019//----------------------------------------------------------------------------
2020template <bool ISREFERENCE>
2021bool CPyCppyy::InstancePtrPtrConverter<ISREFERENCE>::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
2022{
2023// convert <value> to C++ instance*, write it at <address>
2025 if (!pyobj)
2026 return false; // not a cppyy object (TODO: handle SWIG etc.)
2027
2028 if (Cppyy::IsSubtype(pyobj->ObjectIsA(), fClass)) {
2029 // depending on memory policy, some objects need releasing when passed into functions
2030 if (!KeepControl() && CallContext::sMemoryPolicy != CallContext::kUseStrict)
2031 pyobj->CppOwns();
2032
2033 // register the value for potential recycling
2035
2036 // set pointer (may be null) and declare success
2037 *(void**)address = pyobj->GetObject();
2038 return true;
2039 }
2040
2041 return false;
2042}
2043
2044
2045namespace CPyCppyy {
2046// Instantiate the templates
2047 template class CPyCppyy::InstancePtrPtrConverter<true>;
2048 template class CPyCppyy::InstancePtrPtrConverter<false>;
2049}
2050
2051//----------------------------------------------------------------------------
2052bool CPyCppyy::InstanceArrayConverter::SetArg(
2053 PyObject* pyobject, Parameter& para, CallContext* /* txt */)
2054{
2055// convert <pyobject> to C++ instance**, set arg for call
2056 if (!TupleOfInstances_CheckExact(pyobject))
2057 return false; // no guarantee that the tuple is okay
2058
2059// treat the first instance of the tuple as the start of the array, and pass it
2060// by pointer (TODO: store and check sizes)
2061 if (PyTuple_Size(pyobject) < 1)
2062 return false;
2063
2064 PyObject* first = PyTuple_GetItem(pyobject, 0);
2066 return false; // should not happen
2067
2068 if (Cppyy::IsSubtype(((CPPInstance*)first)->ObjectIsA(), fClass)) {
2069 // no memory policies supported; set pointer (may be null) and declare success
2070 para.fValue.fVoidp = ((CPPInstance*)first)->GetObject();
2071 para.fTypeCode = 'p';
2072 return true;
2073 }
2074
2075 return false;
2076}
2077
2078//----------------------------------------------------------------------------
2079PyObject* CPyCppyy::InstanceArrayConverter::FromMemory(void* address)
2080{
2081// construct python tuple of instances from C++ array read at <address>
2082 return BindCppObjectArray(*(char**)address, fClass, m_dims);
2083}
2084
2085//----------------------------------------------------------------------------
2086bool CPyCppyy::InstanceArrayConverter::ToMemory(PyObject* /* value */, void* /* address */, PyObject* /* ctxt */)
2087{
2088// convert <value> to C++ array of instances, write it at <address>
2089
2090// TODO: need to have size both for the array and from the input
2091 PyErr_SetString(PyExc_NotImplementedError,
2092 "access to C-arrays of objects not yet implemented!");
2093 return false;
2094}
2095
2096//___________________________________________________________________________
2097// CLING WORKAROUND -- classes for STL iterators are completely undefined in that
2098// they come in a bazillion different guises, so just do whatever
2099bool CPyCppyy::STLIteratorConverter::SetArg(
2100 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2101{
2102 if (!CPPInstance_Check(pyobject))
2103 return false;
2104
2105// just set the pointer value, no check
2106 CPPInstance* pyobj = (CPPInstance*)pyobject;
2107 para.fValue.fVoidp = pyobj->GetObject();
2108 para.fTypeCode = 'V';
2109 return true;
2110}
2111// -- END CLING WORKAROUND
2112
2113//----------------------------------------------------------------------------
2114bool CPyCppyy::VoidPtrRefConverter::SetArg(
2115 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2116{
2117// convert <pyobject> to C++ void*&, set arg for call
2118 CPPInstance* pyobj = GetCppInstance(pyobject);
2119 if (pyobj) {
2120 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2121 para.fTypeCode = 'V';
2122 return true;
2123 }
2124
2125 return false;
2126}
2127
2128//----------------------------------------------------------------------------
2129bool CPyCppyy::VoidPtrPtrConverter::SetArg(
2130 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2131{
2132// convert <pyobject> to C++ void**, set arg for call
2133 CPPInstance* pyobj = GetCppInstance(pyobject);
2134 if (pyobj) {
2135 // this is a C++ object, take and set its address
2136 para.fValue.fVoidp = &pyobj->GetObjectRaw();
2137 para.fTypeCode = 'p';
2138 return true;
2139 } else if (IsPyCArgObject(pyobject)) {
2141 if (carg->obj) {
2142 para.fValue.fVoidp = (void*)((CPyCppyy_tagCDataObject*)carg->obj)->b_ptr;
2143 para.fTypeCode = 'p';
2144 return true;
2145 }
2146 }
2147
2148// buffer objects are allowed under "user knows best" (this includes the buffer
2149// interface to ctypes.c_void_p, which results in a void**)
2150 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', 1, para.fValue.fVoidp, false);
2151
2152// ok if buffer exists (can't perform any useful size checks)
2153 if (para.fValue.fVoidp && buflen != 0) {
2154 para.fTypeCode = 'p';
2155 return true;
2156 }
2157
2158 return false;
2159}
2160
2161//----------------------------------------------------------------------------
2162PyObject* CPyCppyy::VoidPtrPtrConverter::FromMemory(void* address)
2163{
2164// read a void** from address; since this is unknown, long is used (user can cast)
2165 if (!address || *(ptrdiff_t*)address == 0) {
2166 Py_INCREF(gNullPtrObject);
2167 return gNullPtrObject;
2168 }
2169 return CreatePointerView(*(ptrdiff_t**)address, fSize);
2170}
2171
2172//----------------------------------------------------------------------------
2173bool CPyCppyy::PyObjectConverter::SetArg(
2174 PyObject* pyobject, Parameter& para, CallContext* /* ctxt */)
2175{
2176// by definition: set and declare success
2177 para.fValue.fVoidp = pyobject;
2178 para.fTypeCode = 'p';
2179 return true;
2180}
2181
2182PyObject* CPyCppyy::PyObjectConverter::FromMemory(void* address)
2183{
2184// construct python object from C++ PyObject* read at <address>
2185 PyObject* pyobject = *((PyObject**)address);
2186
2187 if (!pyobject) {
2189 }
2190
2191 Py_INCREF(pyobject);
2192 return pyobject;
2193}
2194
2195bool CPyCppyy::PyObjectConverter::ToMemory(PyObject* value, void* address, PyObject* /* ctxt */)
2196{
2197// no conversion needed, write <value> at <address>
2198 Py_INCREF(value);
2199 Py_XDECREF(*((PyObject**)address));
2200 *((PyObject**)address) = value;
2201 return true;
2202}
2203
2204
2205//- function pointer converter -----------------------------------------------
2206static unsigned int sWrapperCounter = 0;
2207// cache mapping signature/return type to python callable and corresponding wrapper
2208typedef std::pair<std::string, std::string> RetSigKey_t;
2209static std::map<RetSigKey_t, std::vector<void*>> sWrapperFree;
2210static std::map<RetSigKey_t, std::map<PyObject*, void*>> sWrapperLookup;
2211static std::map<PyObject*, std::pair<void*, RetSigKey_t>> sWrapperWeakRefs;
2212static std::map<void*, PyObject**> sWrapperReference;
2213
2215{
2216 auto ipos = sWrapperWeakRefs.find(pyref);
2217 if (ipos != sWrapperWeakRefs.end()) {
2218 // disable this callback and store for possible re-use
2219 void* wpraddress = ipos->second.first;
2220 *sWrapperReference[wpraddress] = nullptr;
2221 sWrapperFree[ipos->second.second].push_back(wpraddress);
2222 }
2223
2225}
2226static PyMethodDef gWrapperCacheEraserMethodDef = {
2227 const_cast<char*>("interal_WrapperCacheEraser"),
2228 (PyCFunction)WrapperCacheEraser,
2229 METH_O, nullptr
2230};
2231
2232static void* PyFunction_AsCPointer(PyObject* pyobject,
2233 const std::string& rettype, const std::string& signature)
2234{
2235// Convert a bound C++ function pointer or callable python object to a C-style
2236// function pointer. The former is direct, the latter involves a JIT-ed wrapper.
2237 static PyObject* sWrapperCacheEraser = PyCFunction_New(&gWrapperCacheEraserMethodDef, nullptr);
2238
2239 using namespace CPyCppyy;
2240
2241 if (CPPOverload_Check(pyobject)) {
2242 CPPOverload* ol = (CPPOverload*)pyobject;
2243 if (!ol->fMethodInfo || ol->fMethodInfo->fMethods.empty())
2244 return nullptr;
2245
2246 // find the overload with matching signature
2247 for (auto& m : ol->fMethodInfo->fMethods) {
2248 PyObject* sig = m->GetSignature(false);
2249 bool found = signature == CPyCppyy_PyText_AsString(sig);
2250 Py_DECREF(sig);
2251 if (found) {
2252 void* fptr = (void*)m->GetFunctionAddress();
2253 if (fptr) return fptr;
2254 break; // fall-through, with calling through Python
2255 }
2256 }
2257 }
2258
2259 if (TemplateProxy_Check(pyobject)) {
2260 // get the actual underlying template matching the signature
2261 TemplateProxy* pytmpl = (TemplateProxy*)pyobject;
2262 std::string fullname = CPyCppyy_PyText_AsString(pytmpl->fTI->fCppName);
2263 if (pytmpl->fTemplateArgs)
2264 fullname += CPyCppyy_PyText_AsString(pytmpl->fTemplateArgs);
2265 Cppyy::TCppScope_t scope = ((CPPClass*)pytmpl->fTI->fPyClass)->fCppType;
2266 Cppyy::TCppMethod_t cppmeth = Cppyy::GetMethodTemplate(scope, fullname, signature);
2267 if (cppmeth) {
2268 void* fptr = (void*)Cppyy::GetFunctionAddress(cppmeth, false);
2269 if (fptr) return fptr;
2270 }
2271 // fall-through, with calling through Python
2272 }
2273
2274 if (PyCallable_Check(pyobject)) {
2275 // generic python callable: create a C++ wrapper function
2276 void* wpraddress = nullptr;
2277
2278 // re-use existing wrapper if possible
2279 auto key = std::make_pair(rettype, signature);
2280 const auto& lookup = sWrapperLookup.find(key);
2281 if (lookup != sWrapperLookup.end()) {
2282 const auto& existing = lookup->second.find(pyobject);
2283 if (existing != lookup->second.end() && *sWrapperReference[existing->second] == pyobject)
2284 wpraddress = existing->second;
2285 }
2286
2287 // check for a pre-existing, unused, wrapper if not found
2288 if (!wpraddress) {
2289 const auto& freewrap = sWrapperFree.find(key);
2290 if (freewrap != sWrapperFree.end() && !freewrap->second.empty()) {
2291 wpraddress = freewrap->second.back();
2292 freewrap->second.pop_back();
2293 *sWrapperReference[wpraddress] = pyobject;
2294 PyObject* wref = PyWeakref_NewRef(pyobject, sWrapperCacheEraser);
2295 if (wref) sWrapperWeakRefs[wref] = std::make_pair(wpraddress, key);
2296 else PyErr_Clear(); // happens for builtins which don't need this
2297 }
2298 }
2299
2300 // create wrapper if no re-use possible
2301 if (!wpraddress) {
2303 return nullptr;
2304
2305 // extract argument types
2306 const std::vector<std::string>& argtypes = TypeManip::extract_arg_types(signature);
2307 int nArgs = (int)argtypes.size();
2308
2309 // wrapper name
2310 std::ostringstream wname;
2311 wname << "fptr_wrap" << ++sWrapperCounter;
2312
2313 // build wrapper function code
2314 std::ostringstream code;
2315 code << "namespace __cppyy_internal {\n "
2316 << rettype << " " << wname.str() << "(";
2317 for (int i = 0; i < nArgs; ++i) {
2318 code << argtypes[i] << " arg" << i;
2319 if (i != nArgs-1) code << ", ";
2320 }
2321 code << ") {\n";
2322
2323 // start function body
2324 Utility::ConstructCallbackPreamble(rettype, argtypes, code);
2325
2326 // create a referencable pointer
2327 PyObject** ref = new PyObject*{pyobject};
2328
2329 // function call itself and cleanup
2330 code << " PyObject** ref = (PyObject**)" << (intptr_t)ref << ";\n"
2331 " PyObject* pyresult = nullptr;\n"
2332 " if (*ref) pyresult = PyObject_CallFunctionObjArgs(*ref";
2333 for (int i = 0; i < nArgs; ++i)
2334 code << ", pyargs[" << i << "]";
2335 code << ", NULL);\n"
2336 " else PyErr_SetString(PyExc_TypeError, \"callable was deleted\");\n";
2337
2338 // close
2339 Utility::ConstructCallbackReturn(rettype, nArgs, code);
2340
2341 // end of namespace
2342 code << "}";
2343
2344 // finally, compile the code
2345 if (!Cppyy::Compile(code.str()))
2346 return nullptr;
2347
2348 // TODO: is there no easier way?
2349 static Cppyy::TCppScope_t scope = Cppyy::GetScope("__cppyy_internal");
2350 const auto& idx = Cppyy::GetMethodIndicesFromName(scope, wname.str());
2351 wpraddress = Cppyy::GetFunctionAddress(Cppyy::GetMethod(scope, idx[0]), false);
2352 sWrapperReference[wpraddress] = ref;
2353
2354 // cache the new wrapper
2355 sWrapperLookup[key][pyobject] = wpraddress;
2356 PyObject* wref = PyWeakref_NewRef(pyobject, sWrapperCacheEraser);
2357 if (wref) sWrapperWeakRefs[wref] = std::make_pair(wpraddress, key);
2358 else PyErr_Clear(); // happens for builtins which don't need this
2359 }
2360
2361 // now pass the pointer to the wrapper function (may be null)
2362 return wpraddress;
2363 }
2364
2365 return nullptr;
2366}
2367
2368bool CPyCppyy::FunctionPointerConverter::SetArg(
2369 PyObject* pyobject, Parameter& para, CallContext* /*ctxt*/)
2370{
2371// special case: allow nullptr singleton:
2372 if (gNullPtrObject == pyobject) {
2373 para.fValue.fVoidp = nullptr;
2374 para.fTypeCode = 'p';
2375 return true;
2376 }
2377
2378// normal case, get a function pointer
2379 void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature);
2380 if (fptr) {
2381 para.fValue.fVoidp = fptr;
2382 para.fTypeCode = 'p';
2383 return true;
2384 }
2385
2386 return false;
2387}
2388
2389static std::map<void*, std::string> sFuncWrapperLookup;
2390static const char* FPCFM_ERRMSG = "conversion to std::function failed";
2391PyObject* CPyCppyy::FunctionPointerConverter::FromMemory(void* address)
2392{
2393// A function pointer in clang is represented by a Type, not a FunctionDecl and it's
2394// not possible to get the latter from the former: the backend will need to support
2395// both. Since that is far in the future, we'll use a std::function instead.
2396 static int func_count = 0;
2397
2398 if (!(address && *(void**)address)) {
2399 PyErr_SetString(PyExc_TypeError, FPCFM_ERRMSG);
2400 return nullptr;
2401 }
2402
2403 void* faddr = *(void**)address;
2404 auto cached = sFuncWrapperLookup.find(faddr);
2405 if (cached == sFuncWrapperLookup.end()) {
2406 std::ostringstream fname;
2407 fname << "ptr2func" << ++func_count;
2408
2409 std::ostringstream code;
2410 code << "namespace __cppyy_internal {\n std::function<"
2411 << fRetType << fSignature << "> " << fname.str()
2412 << " = (" << fRetType << "(*)" << fSignature << ")" << (intptr_t)faddr
2413 << ";\n}";
2414
2415 if (!Cppyy::Compile(code.str())) {
2416 PyErr_SetString(PyExc_TypeError, FPCFM_ERRMSG);
2417 return nullptr;
2418 }
2419
2420 // cache the new wrapper (TODO: does it make sense to use weakrefs on the data
2421 // member?)
2422 sFuncWrapperLookup[faddr] = fname.str();
2423 cached = sFuncWrapperLookup.find(faddr);
2424 }
2425
2426 static Cppyy::TCppScope_t scope = Cppyy::GetScope("__cppyy_internal");
2427 PyObject* pyscope = CreateScopeProxy(scope);
2428 PyObject* func = PyObject_GetAttrString(pyscope, cached->second.c_str());
2429 Py_DECREF(pyscope);
2430
2431 return func;
2432}
2433
2434bool CPyCppyy::FunctionPointerConverter::ToMemory(PyObject* pyobject, void* address, PyObject* /* ctxt */)
2435{
2436// special case: allow nullptr singleton:
2437 if (gNullPtrObject == pyobject) {
2438 *((void**)address) = nullptr;
2439 return true;
2440 }
2441
2442// normal case, get a function pointer
2443 void* fptr = PyFunction_AsCPointer(pyobject, fRetType, fSignature);
2444 if (fptr) {
2445 *((void**)address) = fptr;
2446 return true;
2447 }
2448
2449 return false;
2450}
2451
2452
2453//- std::function converter --------------------------------------------------
2454bool CPyCppyy::StdFunctionConverter::SetArg(
2455 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2456{
2457// prefer normal "object" conversion
2458 bool rf = ctxt->fFlags & CallContext::kNoImplicit;
2460 if (fConverter->SetArg(pyobject, para, ctxt)) {
2461 if (!rf) ctxt->fFlags &= ~CallContext::kNoImplicit;
2462 return true;
2463 }
2464
2465 PyErr_Clear();
2466
2467// else create a wrapper function
2468 if (this->FunctionPointerConverter::SetArg(pyobject, para, ctxt)) {
2469 // retrieve the wrapper pointer and capture it in a temporary std::function,
2470 // then try normal conversion a second time
2471 PyObject* func = this->FunctionPointerConverter::FromMemory(&para.fValue.fVoidp);
2472 if (func) {
2473 Py_XDECREF(fFuncWrap); fFuncWrap = func;
2474 bool result = fConverter->SetArg(fFuncWrap, para, ctxt);
2475 if (!rf) ctxt->fFlags &= ~CallContext::kNoImplicit;
2476 return result;
2477 }
2478 }
2479
2480 if (!rf) ctxt->fFlags &= ~CallContext::kNoImplicit;
2481 return false;
2482}
2483
2484PyObject* CPyCppyy::StdFunctionConverter::FromMemory(void* address)
2485{
2486 return fConverter->FromMemory(address);
2487}
2488
2489bool CPyCppyy::StdFunctionConverter::ToMemory(PyObject* value, void* address, PyObject* ctxt)
2490{
2491 return fConverter->ToMemory(value, address, ctxt);
2492}
2493
2494
2495//- smart pointer converters -------------------------------------------------
2496bool CPyCppyy::SmartPtrConverter::SetArg(
2497 PyObject* pyobject, Parameter& para, CallContext* ctxt)
2498{
2499 char typeCode = fIsRef ? 'p' : 'V';
2500
2501 if (!CPPInstance_Check(pyobject)) {
2502 // TODO: not sure how this is correct for pass-by-ref nor does it help with
2503 // implicit conversions for pass-by-value
2504 if (fIsRef && GetAddressSpecialCase(pyobject, para.fValue.fVoidp)) {
2505 para.fTypeCode = typeCode; // allow special cases such as nullptr
2506 return true;
2507 }
2508
2509 return false;
2510 }
2511
2512 CPPInstance* pyobj = (CPPInstance*)pyobject;
2513
2514// for the case where we have a 'hidden' smart pointer:
2515 if (Cppyy::TCppType_t tsmart = pyobj->GetSmartIsA()) {
2516 if (Cppyy::IsSubtype(tsmart, fSmartPtrType)) {
2517 // depending on memory policy, some objects need releasing when passed into functions
2518 if (fKeepControl && !UseStrictOwnership(ctxt))
2519 ((CPPInstance*)pyobject)->CppOwns();
2520
2521 // calculate offset between formal and actual arguments
2522 para.fValue.fVoidp = pyobj->GetSmartObject();
2523 if (tsmart != fSmartPtrType) {
2525 tsmart, fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */);
2526 }
2527
2528 // set pointer (may be null) and declare success
2529 para.fTypeCode = typeCode;
2530 return true;
2531 }
2532 }
2533
2534// for the case where we have an 'exposed' smart pointer:
2535 if (!pyobj->IsSmart() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fSmartPtrType)) {
2536 // calculate offset between formal and actual arguments
2537 para.fValue.fVoidp = pyobj->GetObject();
2538 if (pyobj->ObjectIsA() != fSmartPtrType) {
2540 pyobj->ObjectIsA(), fSmartPtrType, para.fValue.fVoidp, 1 /* up-cast */);
2541 }
2542
2543 // set pointer (may be null) and declare success
2544 para.fTypeCode = typeCode;
2545 return true;
2546 }
2547
2548// final option, try mapping pointer types held (TODO: do not allow for non-const ref)
2549 if (pyobj->IsSmart() && Cppyy::IsSubtype(pyobj->ObjectIsA(), fUnderlyingType)) {
2550 para.fValue.fVoidp = ((CPPInstance*)pyobject)->GetSmartObject();
2551 para.fTypeCode = 'V';
2552 return true;
2553 }
2554
2555 return false;
2556}
2557
2558PyObject* CPyCppyy::SmartPtrConverter::FromMemory(void* address)
2559{
2560 if (!address || !fSmartPtrType)
2561 return nullptr;
2562
2563 return BindCppObjectNoCast(address, fSmartPtrType);
2564}
2565
2566
2567//----------------------------------------------------------------------------
2568namespace {
2569
2570// clang libcpp and gcc use the same structure (ptr, size)
2571#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2572struct faux_initlist
2573{
2574 typedef size_t size_type;
2575 typedef void* iterator;
2576 iterator _M_array;
2577 size_type _M_len;
2578};
2579#elif defined (_MSC_VER)
2580struct faux_initlist
2581{
2582 typedef char* iterator;
2583 iterator _M_array; // ie. _First;
2584 iterator _Last;
2585};
2586#else
2587#define NO_KNOWN_INITIALIZER_LIST 1
2588#endif
2589
2590} // unnamed namespace
2591
2592CPyCppyy::InitializerListConverter::~InitializerListConverter()
2593{
2594 if (fConverter && fConverter->HasState()) delete fConverter;
2595}
2596
2597bool CPyCppyy::InitializerListConverter::SetArg(
2598 PyObject* pyobject, Parameter& para, CallContext* /*ctxt*/)
2599{
2600#ifdef NO_KNOWN_INITIALIZER_LIST
2601 return false;
2602#else
2603// convert the given argument to an initializer list temporary; this is purely meant
2604// to be a syntactic thing, so only _python_ sequences are allowed; bound C++ proxies
2605// are therefore rejected (should go through eg. a copy constructor etc.)
2606 if (CPPInstance_Check(pyobject) || !PySequence_Check(pyobject) || CPyCppyy_PyText_Check(pyobject)
2607#if PY_VERSION_HEX >= 0x03000000
2608 || PyBytes_Check(pyobject)
2609#endif
2610 )
2611 return false;
2612
2613 void* buf;
2614 Py_ssize_t buflen = Utility::GetBuffer(pyobject, '*', (int)fValueSize, buf, true);
2615 faux_initlist* fake = nullptr;
2616 if (buf && buflen) {
2617 // dealing with an array here, pass on whole-sale
2618 fake = (faux_initlist*)malloc(sizeof(faux_initlist));
2619 fake->_M_array = (faux_initlist::iterator)buf;
2620#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2621 fake->_M_len = (faux_initlist::size_type)buflen;
2622#elif defined (_MSC_VER)
2623 fake->_Last = fake->_M_array+buflen*fValueSize;
2624#endif
2625 } else {
2626 // can only construct empty lists, so use a fake initializer list
2627 size_t len = (size_t)PySequence_Size(pyobject);
2628 fake = (faux_initlist*)malloc(sizeof(faux_initlist)+fValueSize*len);
2629 fake->_M_array = (faux_initlist::iterator)((char*)fake+sizeof(faux_initlist));
2630#if defined (_LIBCPP_INITIALIZER_LIST) || defined(__GNUC__)
2631 fake->_M_len = (faux_initlist::size_type)len;
2632 for (faux_initlist::size_type i = 0; i < fake->_M_len; ++i) {
2633#elif defined (_MSC_VER)
2634 fake->_Last = fake->_M_array+len*fValueSize;
2635 for (size_t i = 0; (fake->_M_array+i*fValueSize) != fake->_Last; ++i) {
2636#endif
2637 PyObject* item = PySequence_GetItem(pyobject, i);
2638 bool convert_ok = false;
2639 if (item) {
2640 if (!fConverter) {
2641 if (CPPInstance_Check(item)) {
2642 // by convention, use byte copy
2643 memcpy((char*)fake->_M_array + i*fValueSize,
2644 ((CPPInstance*)item)->GetObject(), fValueSize);
2645 convert_ok = true;
2646 }
2647 } else
2648 convert_ok = fConverter->ToMemory(item, (char*)fake->_M_array + i*fValueSize);
2649
2650 Py_DECREF(item);
2651 } else
2652 PyErr_Format(PyExc_TypeError, "failed to get item %d from sequence", (int)i);
2653
2654 if (!convert_ok) {
2655 free((void*)fake);
2656 return false;
2657 }
2658 }
2659 }
2660
2661 para.fValue.fVoidp = (void*)fake;
2662 para.fTypeCode = 'X'; // means ptr that backend has to free after call
2663 return true;
2664#endif
2665}
2666
2667//----------------------------------------------------------------------------
2668bool CPyCppyy::NotImplementedConverter::SetArg(PyObject*, Parameter&, CallContext*)
2669{
2670// raise a NotImplemented exception to take a method out of overload resolution
2671 PyErr_SetString(PyExc_NotImplementedError, "this method cannot (yet) be called");
2672 return false;
2673}
2674
2675
2676//- helper to refactor some code from CreateConverter ------------------------
2678 Cppyy::TCppScope_t klass, const std::string& cpd, long size, dims_t dims, bool isConst, bool control)
2679{
2680 using namespace CPyCppyy;
2681 Converter* result = nullptr;
2682
2683 if (cpd == "**" || cpd == "*[]" || cpd == "&*")
2684 result = new InstancePtrPtrConverter<false>(klass, control);
2685 else if (cpd == "*&")
2686 result = new InstancePtrPtrConverter<true>(klass, control);
2687 else if (cpd == "*" && size <= 0)
2688 result = new InstancePtrConverter(klass, control);
2689 else if (cpd == "&")
2690 result = new InstanceRefConverter(klass, isConst);
2691 else if (cpd == "&&")
2692 result = new InstanceMoveConverter(klass);
2693 else if (cpd == "[]" || size > 0)
2694 result = new InstanceArrayConverter(klass, dims, false);
2695 else if (cpd == "") // by value
2696 result = new InstanceConverter(klass, true);
2697
2698 return result;
2699}
2700
2701//- factories ----------------------------------------------------------------
2703CPyCppyy::Converter* CPyCppyy::CreateConverter(const std::string& fullType, dims_t dims)
2704{
2705// The matching of the fulltype to a converter factory goes through up to five levels:
2706// 1) full, exact match
2707// 2) match of decorated, unqualified type
2708// 3) accept const ref as by value
2709// 4) accept ref as pointer
2710// 5) generalized cases (covers basically all C++ classes)
2711//
2712// If all fails, void is used, which will generate a run-time warning when used.
2713
2714 dim_t size = (dims && dims[0] != -1) ? dims[1] : -1;
2715
2716// an exactly matching converter is best
2717 ConvFactories_t::iterator h = gConvFactories.find(fullType);
2718 if (h != gConvFactories.end())
2719 return (h->second)(dims);
2720
2721// resolve typedefs etc.
2722 const std::string& resolvedType = Cppyy::ResolveName(fullType);
2723
2724// a full, qualified matching converter is preferred
2725 if (resolvedType != fullType) {
2726 h = gConvFactories.find(resolvedType);
2727 if (h != gConvFactories.end())
2728 return (h->second)(dims);
2729 }
2730
2731//-- nothing? ok, collect information about the type and possible qualifiers/decorators
2732 bool isConst = strncmp(resolvedType.c_str(), "const", 5) == 0;
2733 const std::string& cpd = Utility::Compound(resolvedType);
2734 std::string realType = TypeManip::clean_type(resolvedType, false, true);
2735
2736// accept unqualified type (as python does not know about qualifiers)
2737 h = gConvFactories.find(realType + cpd);
2738 if (h != gConvFactories.end())
2739 return (h->second)(dims);
2740
2741// drop const, as that is mostly meaningless to python (with the exception
2742// of c-strings, but those are specialized in the converter map)
2743 if (isConst) {
2744 realType = TypeManip::remove_const(realType);
2745 h = gConvFactories.find(realType + cpd);
2746 if (h != gConvFactories.end())
2747 return (h->second)(dims);
2748 }
2749
2750//-- still nothing? try pointer instead of array (for builtins)
2751 if (cpd == "[]") {
2752 // simple array
2753 h = gConvFactories.find(realType + "*");
2754 if (h != gConvFactories.end()) {
2755 if (dims && dims[1] == UNKNOWN_SIZE) dims[1] = UNKNOWN_ARRAY_SIZE;
2756 return (h->second)(dims);
2757 }
2758 } else if (cpd == "*[]") {
2759 // array of pointers
2760 h = gConvFactories.find(realType + "*");
2761 if (h != gConvFactories.end()) {
2762 // upstream treats the pointer type as the array element type, but that pointer is
2763 // treated as a low-level view as well, so adjust the dims
2764 dim_t newdim = (dims && 0 < dims[0]) ? dims[0]+1 : 2;
2765 dims_t newdims = new dim_t[newdim+1];
2766 newdims[0] = newdim;
2767 newdims[1] = (0 < size ? size : UNKNOWN_ARRAY_SIZE); // the array
2768 newdims[2] = UNKNOWN_SIZE; // the pointer
2769 if (dims && 2 < newdim) {
2770 for (int i = 2; i < (newdim-1); ++i)
2771 newdims[i+1] = dims[i];
2772 }
2773 Converter* cnv = (h->second)(newdims);
2774 delete [] newdims;
2775 return cnv;
2776 }
2777 }
2778
2779//-- special case: initializer list
2780 if (realType.compare(0, 16, "initializer_list") == 0) {
2781 // get the type of the list and create a converter (TODO: get hold of value_type?)
2782 auto pos = realType.find('<');
2783 std::string value_type = realType.substr(pos+1, realType.size()-pos-2);
2784 Converter* cnv = nullptr; bool use_byte_cnv = false;
2785 if (cpd == "" && Cppyy::GetScope(value_type)) {
2786 // initializer list of object values does not work as the target is raw
2787 // memory; simply use byte copies
2788
2789 // by convention, leave cnv as nullptr
2790 use_byte_cnv = true;
2791 } else
2792 cnv = CreateConverter(value_type);
2793 if (cnv || use_byte_cnv)
2794 return new InitializerListConverter(cnv, Cppyy::SizeOf(value_type));
2795 }
2796
2797//-- still nothing? use a generalized converter
2798 bool control = cpd == "&" || isConst;
2799
2800//-- special case: std::function
2801 auto pos = resolvedType.find("function<");
2802 if (pos == 0 /* no std:: */ || pos == 5 /* with std:: */ ||
2803 pos == 6 /* const no std:: */ || pos == 11 /* const with std:: */ ) {
2804
2805 // get actual converter for normal passing
2807 Cppyy::GetScope(realType), cpd, size, dims, isConst, control);
2808
2809 if (cnv) {
2810 // get the type of the underlying (TODO: use target_type?)
2811 auto pos1 = resolvedType.find("(", pos+9);
2812 auto pos2 = resolvedType.rfind(")");
2813 if (pos1 != std::string::npos && pos2 != std::string::npos) {
2814 auto sz1 = pos1-pos-9;
2815 if (resolvedType[pos+9+sz1-1] == ' ') sz1 -= 1;
2816
2817 return new StdFunctionConverter(cnv,
2818 resolvedType.substr(pos+9, sz1), resolvedType.substr(pos1, pos2-pos1+1));
2819 } else if (cnv->HasState())
2820 delete cnv;
2821 }
2822 }
2823
2824// converters for known C++ classes and default (void*)
2825 Converter* result = nullptr;
2826 if (Cppyy::TCppScope_t klass = Cppyy::GetScope(realType)) {
2827 Cppyy::TCppType_t raw{0};
2828 if (Cppyy::GetSmartPtrInfo(realType, &raw, nullptr)) {
2829 if (cpd == "") {
2830 result = new SmartPtrConverter(klass, raw, control);
2831 } else if (cpd == "&") {
2832 result = new SmartPtrConverter(klass, raw);
2833 } else if (cpd == "*" && size <= 0) {
2834 result = new SmartPtrConverter(klass, raw, control, true);
2835 }
2836 }
2837
2838 if (!result) {
2839 // CLING WORKAROUND -- special case for STL iterators
2840 if (realType.rfind("__gnu_cxx::__normal_iterator", 0) /* vector */ == 0
2841#ifdef __APPLE__
2842 || realType.rfind("__wrap_iter", 0) == 0
2843#endif
2844 // TODO: Windows?
2845 ) {
2846 static STLIteratorConverter c;
2847 result = &c;
2848 } else
2849 // -- CLING WORKAROUND
2850 result = selectInstanceCnv(klass, cpd, size, dims, isConst, control);
2851 }
2852 } else if (resolvedType.find("(*)") != std::string::npos ||
2853 (resolvedType.find("::*)") != std::string::npos)) {
2854 // this is a function function pointer
2855 // TODO: find better way of finding the type
2856 auto pos1 = resolvedType.find('(');
2857 auto pos2 = resolvedType.find("*)");
2858 auto pos3 = resolvedType.rfind(')');
2859 result = new FunctionPointerConverter(
2860 resolvedType.substr(0, pos1), resolvedType.substr(pos2+2, pos3-pos2-1));
2861 }
2862
2863 if (!result && cpd == "&&") {
2864 // for builtin, can use const-ref for r-ref
2865 h = gConvFactories.find("const " + realType + "&");
2866 if (h != gConvFactories.end())
2867 return (h->second)(dims);
2868 // else, unhandled moves
2869 result = new NotImplementedConverter();
2870 }
2871
2872 if (!result && h != gConvFactories.end())
2873 // converter factory available, use it to create converter
2874 result = (h->second)(dims);
2875 else if (!result) {
2876 // default to something reasonable, assuming "user knows best"
2877 if (cpd.size() == 2 && cpd != "&&") // "**", "*[]", "*&"
2878 result = new VoidPtrPtrConverter(size);
2879 else if (!cpd.empty())
2880 result = new VoidArrayConverter(); // "user knows best"
2881 else
2882 result = new NotImplementedConverter(); // fails on use
2883 }
2884
2885 return result;
2886}
2887
2888//----------------------------------------------------------------------------
2891{
2892 if (p && p->HasState())
2893 delete p; // state-less converters are always shared
2894}
2895
2896//----------------------------------------------------------------------------
2898bool CPyCppyy::RegisterConverter(const std::string& name, cf_t fac)
2899{
2900// register a custom converter
2901 auto f = gConvFactories.find(name);
2902 if (f != gConvFactories.end())
2903 return false;
2904
2905 gConvFactories[name] = fac;
2906 return true;
2907}
2908
2909//----------------------------------------------------------------------------
2911bool CPyCppyy::UnregisterConverter(const std::string& name)
2912{
2913// remove a custom converter
2914 auto f = gConvFactories.find(name);
2915 if (f != gConvFactories.end()) {
2916 gConvFactories.erase(f);
2917 return true;
2918 }
2919 return false;
2920}
2921
2922
2923//----------------------------------------------------------------------------
2924namespace {
2925
2926using namespace CPyCppyy;
2927
2928#define STRINGVIEW "basic_string_view<char,char_traits<char> >"
2929#define WSTRING "basic_string<wchar_t,char_traits<wchar_t>,allocator<wchar_t> >"
2930
2931static struct InitConvFactories_t {
2932public:
2933 InitConvFactories_t() {
2934 // load all converter factories in the global map 'gConvFactories'
2936
2937 // factories for built-ins
2938 gf["bool"] = (cf_t)+[](dims_t) { static BoolConverter c{}; return &c; };
2939 gf["const bool&"] = (cf_t)+[](dims_t) { static ConstBoolRefConverter c{}; return &c; };
2940 gf["bool&"] = (cf_t)+[](dims_t) { static BoolRefConverter c{}; return &c; };
2941 gf["char"] = (cf_t)+[](dims_t) { static CharConverter c{}; return &c; };
2942 gf["const char&"] = (cf_t)+[](dims_t) { static ConstCharRefConverter c{}; return &c; };
2943 gf["char&"] = (cf_t)+[](dims_t) { static CharRefConverter c{}; return &c; };
2944 gf["signed char&"] = (cf_t)+[](dims_t) { static SCharRefConverter c{}; return &c; };
2945 gf["unsigned char"] = (cf_t)+[](dims_t) { static UCharConverter c{}; return &c; };
2946 gf["const unsigned char&"] = (cf_t)+[](dims_t) { static ConstUCharRefConverter c{}; return &c; };
2947 gf["unsigned char&"] = (cf_t)+[](dims_t) { static UCharRefConverter c{}; return &c; };
2948 gf["UCharAsInt"] = (cf_t)+[](dims_t) { static UCharAsIntConverter c{}; return &c; };
2949 gf["wchar_t"] = (cf_t)+[](dims_t) { static WCharConverter c{}; return &c; };
2950 gf["char16_t"] = (cf_t)+[](dims_t) { static Char16Converter c{}; return &c; };
2951 gf["char32_t"] = (cf_t)+[](dims_t) { static Char32Converter c{}; return &c; };
2952 gf["wchar_t&"] = (cf_t)+[](dims_t) { static WCharRefConverter c{}; return &c; };
2953 gf["char16_t&"] = (cf_t)+[](dims_t) { static Char16RefConverter c{}; return &c; };
2954 gf["char32_t&"] = (cf_t)+[](dims_t) { static Char32RefConverter c{}; return &c; };
2955 gf["int8_t"] = (cf_t)+[](dims_t) { static Int8Converter c{}; return &c; };
2956 gf["int8_t&"] = (cf_t)+[](dims_t) { static Int8RefConverter c{}; return &c; };
2957 gf["const int8_t&"] = (cf_t)+[](dims_t) { static ConstInt8RefConverter c{}; return &c; };
2958 gf["uint8_t"] = (cf_t)+[](dims_t) { static UInt8Converter c{}; return &c; };
2959 gf["const uint8_t&"] = (cf_t)+[](dims_t) { static ConstUInt8RefConverter c{}; return &c; };
2960 gf["uint8_t&"] = (cf_t)+[](dims_t) { static UInt8RefConverter c{}; return &c; };
2961 gf["short"] = (cf_t)+[](dims_t) { static ShortConverter c{}; return &c; };
2962 gf["const short&"] = (cf_t)+[](dims_t) { static ConstShortRefConverter c{}; return &c; };
2963 gf["short&"] = (cf_t)+[](dims_t) { static ShortRefConverter c{}; return &c; };
2964 gf["unsigned short"] = (cf_t)+[](dims_t) { static UShortConverter c{}; return &c; };
2965 gf["const unsigned short&"] = (cf_t)+[](dims_t) { static ConstUShortRefConverter c{}; return &c; };
2966 gf["unsigned short&"] = (cf_t)+[](dims_t) { static UShortRefConverter c{}; return &c; };
2967 gf["int"] = (cf_t)+[](dims_t) { static IntConverter c{}; return &c; };
2968 gf["int&"] = (cf_t)+[](dims_t) { static IntRefConverter c{}; return &c; };
2969 gf["const int&"] = (cf_t)+[](dims_t) { static ConstIntRefConverter c{}; return &c; };
2970 gf["unsigned int"] = (cf_t)+[](dims_t) { static UIntConverter c{}; return &c; };
2971 gf["const unsigned int&"] = (cf_t)+[](dims_t) { static ConstUIntRefConverter c{}; return &c; };
2972 gf["unsigned int&"] = (cf_t)+[](dims_t) { static UIntRefConverter c{}; return &c; };
2973 gf["long"] = (cf_t)+[](dims_t) { static LongConverter c{}; return &c; };
2974 gf["long&"] = (cf_t)+[](dims_t) { static LongRefConverter c{}; return &c; };
2975 gf["const long&"] = (cf_t)+[](dims_t) { static ConstLongRefConverter c{}; return &c; };
2976 gf["unsigned long"] = (cf_t)+[](dims_t) { static ULongConverter c{}; return &c; };
2977 gf["const unsigned long&"] = (cf_t)+[](dims_t) { static ConstULongRefConverter c{}; return &c; };
2978 gf["unsigned long&"] = (cf_t)+[](dims_t) { static ULongRefConverter c{}; return &c; };
2979 gf["long long"] = (cf_t)+[](dims_t) { static LLongConverter c{}; return &c; };
2980 gf["const long long&"] = (cf_t)+[](dims_t) { static ConstLLongRefConverter c{}; return &c; };
2981 gf["long long&"] = (cf_t)+[](dims_t) { static LLongRefConverter c{}; return &c; };
2982 gf["unsigned long long"] = (cf_t)+[](dims_t) { static ULLongConverter c{}; return &c; };
2983 gf["const unsigned long long&"] = (cf_t)+[](dims_t) { static ConstULLongRefConverter c{}; return &c; };
2984 gf["unsigned long long&"] = (cf_t)+[](dims_t) { static ULLongRefConverter c{}; return &c; };
2985
2986 gf["float"] = (cf_t)+[](dims_t) { static FloatConverter c{}; return &c; };
2987 gf["const float&"] = (cf_t)+[](dims_t) { static ConstFloatRefConverter c{}; return &c; };
2988 gf["float&"] = (cf_t)+[](dims_t) { static FloatRefConverter c{}; return &c; };
2989 gf["double"] = (cf_t)+[](dims_t) { static DoubleConverter c{}; return &c; };
2990 gf["double&"] = (cf_t)+[](dims_t) { static DoubleRefConverter c{}; return &c; };
2991 gf["const double&"] = (cf_t)+[](dims_t) { static ConstDoubleRefConverter c{}; return &c; };
2992 gf["long double"] = (cf_t)+[](dims_t) { static LDoubleConverter c{}; return &c; };
2993 gf["const long double&"] = (cf_t)+[](dims_t) { static ConstLDoubleRefConverter c{}; return &c; };
2994 gf["long double&"] = (cf_t)+[](dims_t) { static LDoubleRefConverter c{}; return &c; };
2995 gf["std::complex<double>"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2996 gf["complex<double>"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2997 gf["const std::complex<double>&"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2998 gf["const complex<double>&"] = (cf_t)+[](dims_t) { return new ComplexDConverter{}; };
2999 gf["void"] = (cf_t)+[](dims_t) { static VoidConverter c{}; return &c; };
3000
3001 // pointer/array factories
3002 gf["bool*"] = (cf_t)+[](dims_t d) { return new BoolArrayConverter{d}; };
3003 gf["bool**"] = (cf_t)+[](dims_t d) { return new BoolArrayPtrConverter{d}; };
3004 gf["const signed char[]"] = (cf_t)+[](dims_t d) { return new SCharArrayConverter{d}; };
3005 gf["signed char[]"] = (cf_t)+[](dims_t d) { return new SCharArrayConverter{d}; };
3006 gf["signed char**"] = (cf_t)+[](dims_t d) { return new SCharArrayPtrConverter{d}; };
3007 gf["const unsigned char*"] = (cf_t)+[](dims_t d) { return new UCharArrayConverter{d}; };
3008 gf["unsigned char*"] = (cf_t)+[](dims_t d) { return new UCharArrayConverter{d}; };
3009 gf["UCharAsInt*"] = (cf_t)+[](dims_t d) { return new UCharArrayConverter{d}; };
3010 gf["unsigned char**"] = (cf_t)+[](dims_t d) { return new UCharArrayPtrConverter{d}; };
3011#if __cplusplus > 201402L
3012 gf["byte*"] = (cf_t)+[](dims_t d) { return new ByteArrayConverter{d}; };
3013 gf["byte**"] = (cf_t)+[](dims_t d) { return new ByteArrayPtrConverter{d}; };
3014#endif
3015 gf["short*"] = (cf_t)+[](dims_t d) { return new ShortArrayConverter{d}; };
3016 gf["short**"] = (cf_t)+[](dims_t d) { return new ShortArrayPtrConverter{d}; };
3017 gf["unsigned short*"] = (cf_t)+[](dims_t d) { return new UShortArrayConverter{d}; };
3018 gf["unsigned short**"] = (cf_t)+[](dims_t d) { return new UShortArrayPtrConverter{d}; };
3019 gf["int*"] = (cf_t)+[](dims_t d) { return new IntArrayConverter{d}; };
3020 gf["int**"] = (cf_t)+[](dims_t d) { return new IntArrayPtrConverter{d}; };
3021 gf["unsigned int*"] = (cf_t)+[](dims_t d) { return new UIntArrayConverter{d}; };
3022 gf["unsigned int**"] = (cf_t)+[](dims_t d) { return new UIntArrayPtrConverter{d}; };
3023 gf["long*"] = (cf_t)+[](dims_t d) { return new LongArrayConverter{d}; };
3024 gf["long**"] = (cf_t)+[](dims_t d) { return new LongArrayPtrConverter{d}; };
3025 gf["unsigned long*"] = (cf_t)+[](dims_t d) { return new ULongArrayConverter{d}; };
3026 gf["unsigned long**"] = (cf_t)+[](dims_t d) { return new ULongArrayPtrConverter{d}; };
3027 gf["long long*"] = (cf_t)+[](dims_t d) { return new LLongArrayConverter{d}; };
3028 gf["long long**"] = (cf_t)+[](dims_t d) { return new LLongArrayPtrConverter{d}; };
3029 gf["unsigned long long*"] = (cf_t)+[](dims_t d) { return new ULLongArrayConverter{d}; };
3030 gf["unsigned long long**"] = (cf_t)+[](dims_t d) { return new ULLongArrayPtrConverter{d}; };
3031 gf["float*"] = (cf_t)+[](dims_t d) { return new FloatArrayConverter{d}; };
3032 gf["float**"] = (cf_t)+[](dims_t d) { return new FloatArrayPtrConverter{d}; };
3033 gf["double*"] = (cf_t)+[](dims_t d) { return new DoubleArrayConverter{d}; };
3034 gf["double**"] = (cf_t)+[](dims_t d) { return new DoubleArrayPtrConverter{d}; };
3035 gf["long double*"] = (cf_t)+[](dims_t d) { return new LDoubleArrayConverter{d}; };
3036 gf["long double**"] = (cf_t)+[](dims_t d) { return new LDoubleArrayPtrConverter{d}; };
3037 gf["std::complex<double>*"] = (cf_t)+[](dims_t d) { return new ComplexDArrayConverter{d}; };
3038 gf["complex<double>*"] = (cf_t)+[](dims_t d) { return new ComplexDArrayConverter{d}; };
3039 gf["std::complex<double>**"] = (cf_t)+[](dims_t d) { return new ComplexDArrayPtrConverter{d}; };
3040 gf["void*"] = (cf_t)+[](dims_t d) { return new VoidArrayConverter{(bool)d}; };
3041
3042 // aliases
3043 gf["signed char"] = gf["char"];
3044 gf["const signed char&"] = gf["const char&"];
3045#if __cplusplus > 201402L
3046 gf["byte"] = gf["uint8_t"];
3047 gf["const byte&"] = gf["const uint8_t&"];
3048 gf["byte&"] = gf["uint8&"];
3049#endif
3050 gf["internal_enum_type_t"] = gf["int"];
3051 gf["internal_enum_type_t&"] = gf["int&"];
3052 gf["const internal_enum_type_t&"] = gf["const int&"];
3053 gf["Long64_t"] = gf["long long"];
3054 gf["Long64_t*"] = gf["long long*"];
3055 gf["Long64_t&"] = gf["long long&"];
3056 gf["const Long64_t&"] = gf["const long long&"];
3057 gf["ULong64_t"] = gf["unsigned long long"];
3058 gf["ULong64_t*"] = gf["unsigned long long*"];
3059 gf["ULong64_t&"] = gf["unsigned long long&"];
3060 gf["const ULong64_t&"] = gf["const unsigned long long&"];
3061 gf["Float16_t"] = gf["float"];
3062 gf["const Float16_t&"] = gf["const float&"];
3063 gf["Double32_t"] = gf["double"];
3064 gf["Double32_t&"] = gf["double&"];
3065 gf["const Double32_t&"] = gf["const double&"];
3066
3067 // factories for special cases
3068 gf["TString"] = (cf_t)+[](dims_t) { return new TStringConverter{}; };
3069 gf["TString&"] = gf["TString"];
3070 gf["const TString&"] = gf["TString"];
3071 gf["nullptr_t"] = (cf_t)+[](dims_t) { static NullptrConverter c{}; return &c;};
3072 gf["const char*"] = (cf_t)+[](dims_t) { return new CStringConverter{}; };
3073 gf["const signed char*"] = gf["const char*"];
3074 gf["const char[]"] = (cf_t)+[](dims_t) { return new CStringConverter{}; };
3075 gf["char*"] = (cf_t)+[](dims_t) { return new NonConstCStringConverter{}; };
3076 gf["signed char*"] = gf["char*"];
3077 gf["wchar_t*"] = (cf_t)+[](dims_t) { return new WCStringConverter{}; };
3078 gf["char16_t*"] = (cf_t)+[](dims_t) { return new CString16Converter{}; };
3079 gf["char32_t*"] = (cf_t)+[](dims_t) { return new CString32Converter{}; };
3080 // TODO: the following are handled incorrectly upstream (char16_t** where char16_t* intended)?!
3081 gf["char16_t**"] = gf["char16_t*"];
3082 gf["char32_t**"] = gf["char32_t*"];
3083 gf["const char**"] = (cf_t)+[](dims_t d) { return new CStringArrayConverter{d}; };
3084 gf["char**"] = gf["const char**"];
3085 gf["const char*[]"] = gf["const char**"];
3086 gf["char*[]"] = gf["const char*[]"];
3087 gf["std::string"] = (cf_t)+[](dims_t) { return new STLStringConverter{}; };
3088 gf["string"] = gf["std::string"];
3089 gf["const std::string&"] = gf["std::string"];
3090 gf["const string&"] = gf["std::string"];
3091 gf["string&&"] = (cf_t)+[](dims_t) { return new STLStringMoveConverter{}; };
3092 gf["std::string&&"] = gf["string&&"];
3093 gf["std::string_view"] = (cf_t)+[](dims_t) { return new STLStringViewConverter{}; };
3094 gf["string_view"] = gf["std::string_view"];
3095 gf[STRINGVIEW] = gf["std::string_view"];
3096 gf["experimental::" STRINGVIEW] = gf["std::string_view"];
3097 gf["std::string_view&"] = gf["std::string_view"];
3098 gf["const string_view&"] = gf["std::string_view"];
3099 gf["const " STRINGVIEW "&"] = gf["std::string_view"];
3100 gf["std::wstring"] = (cf_t)+[](dims_t) { return new STLWStringConverter{}; };
3101 gf[WSTRING] = gf["std::wstring"];
3102 gf["std::" WSTRING] = gf["std::wstring"];
3103 gf["const std::wstring&"] = gf["std::wstring"];
3104 gf["const std::" WSTRING "&"] = gf["std::wstring"];
3105 gf["const " WSTRING "&"] = gf["std::wstring"];
3106 gf["void*&"] = (cf_t)+[](dims_t) { static VoidPtrRefConverter c{}; return &c; };
3107 gf["void**"] = (cf_t)+[](dims_t d) { return new VoidPtrPtrConverter{size_t((d && d[0] != -1) ? d[1] : -1)}; };
3108 gf["void*[]"] = (cf_t)+[](dims_t d) { return new VoidPtrPtrConverter{size_t((d && d[0] != -1) ? d[1] : -1)}; };
3109 gf["PyObject*"] = (cf_t)+[](dims_t) { static PyObjectConverter c{}; return &c; };
3110 gf["_object*"] = gf["PyObject*"];
3111 gf["FILE*"] = (cf_t)+[](dims_t) { return new VoidArrayConverter{}; };
3112 }
3113} initConvFactories_;
3114
3115} // 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)
Definition: Converters.cxx:293
static const char * FPCFM_ERRMSG
#define CPPYY_IMPL_BASIC_CONVERTER(name, type, stype, ctype, F1, F2, tc)
Definition: Converters.cxx:469
#define CPPYY_IMPL_ARRAY_CONVERTER(name, ctype, type, code)
static bool ConvertImplicit(Cppyy::TCppType_t klass, PyObject *pyobject, CPyCppyy::Parameter &para, CPyCppyy::CallContext *ctxt)
Definition: Converters.cxx:386
static std::map< void *, PyObject ** > sWrapperReference
static bool CPyCppyy_PyLong_AsBool(PyObject *pyobject)
Definition: Converters.cxx:242
static bool IsPyCArgObject(PyObject *pyobject)
Definition: Converters.cxx:161
static std::array< PyTypeObject *, 22 > gCTypesTypes
Definition: Converters.cxx:108
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)
Definition: Converters.cxx:582
const size_t MOVE_REFCOUNT_CUTOFF
Definition: Converters.cxx:45
#define ct_c_long
Definition: Converters.cxx:90
static char CPyCppyy_PyText_AsChar(PyObject *pyobject)
Definition: Converters.cxx:254
#define CPPYY_IMPL_BASIC_CONST_CHAR_REFCONVERTER(name, type, ctype, low, high)
Definition: Converters.cxx:566
static bool SetLifeLine(PyObject *holder, PyObject *target, intptr_t ref)
Definition: Converters.cxx:200
static std::map< RetSigKey_t, std::map< PyObject *, void * > > sWrapperLookup
static std::array< PyTypeObject *, 22 > gCTypesPtrTypes
Definition: Converters.cxx:109
static int ExtractChar(PyObject *pyobject, const char *tname, int low, int high)
Definition: Converters.cxx:510
static std::array< const char *, 22 > gCTypesNames
Definition: Converters.cxx:103
static void init_shape(Py_ssize_t defdim, dims_t dims, Py_ssize_t *&shape)
static PyTypeObject * GetCTypesPtrType(int nidx)
Definition: Converters.cxx:134
static std::map< PyObject *, std::pair< void *, RetSigKey_t > > sWrapperWeakRefs
#define ct_c_char_p
Definition: Converters.cxx:97
#define ct_c_int
Definition: Converters.cxx:87
static int8_t CPyCppyy_PyLong_AsInt8(PyObject *pyobject)
Definition: Converters.cxx:276
std::pair< std::string, std::string > RetSigKey_t
static PyMethodDef gWrapperCacheEraserMethodDef
#define CPPYY_IMPL_BASIC_CONST_REFCONVERTER(name, type, ctype, F1)
Definition: Converters.cxx:551
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)
Definition: Converters.cxx:259
static std::map< void *, std::string > sFuncWrapperLookup
static short CPyCppyy_PyLong_AsShort(PyObject *pyobject)
Definition: Converters.cxx:311
static long CPyCppyy_PyLong_AsStrictLong(PyObject *pyobject)
Definition: Converters.cxx:348
static CPyCppyy::CPPInstance * GetCppInstance(PyObject *pyobject)
Definition: Converters.cxx:216
#define WSTRING
#define UNKNOWN_ARRAY_SIZE
Definition: Converters.cxx:31
#define CPPYY_IMPL_REFCONVERTER(name, ctype, type, code)
Definition: Converters.cxx:711
static PyTypeObject * GetCTypesType(int nidx)
Definition: Converters.cxx:115
#define ct_c_void_p
Definition: Converters.cxx:99
#define UNKNOWN_SIZE
Definition: Converters.cxx:30
static bool CArraySetArg(PyObject *pyobject, CPyCppyy::Parameter &para, char tc, int size)
Definition: Converters.cxx:362
static int CPyCppyy_PyLong_AsStrictInt(PyObject *pyobject)
Definition: Converters.cxx:328
static std::map< RetSigKey_t, std::vector< void * > > sWrapperFree
static bool IsCTypesArrayOrPointer(PyObject *pyobject)
Definition: Converters.cxx:181
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)
Definition: Converters.cxx:535
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
Definition: PyMethodBase.h:43
#define d(i)
Definition: RSha256.hxx:102
#define f(i)
Definition: RSha256.hxx:104
#define c(i)
Definition: RSha256.hxx:101
#define h(i)
Definition: RSha256.hxx:106
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
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
unsigned long ULong_t
Definition: RtypesCore.h:55
winID h TVirtualViewer3D TVirtualGLPainter p
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 b
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void 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 length
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t UChar_t len
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t g
char name[80]
Definition: TGX11.cxx:110
float * q
Definition: THbookFile.cxx:89
#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:56
void *& GetObjectRaw()
Definition: CPPInstance.h:60
Cppyy::TCppType_t ObjectIsA(bool check_smart=true) const
Definition: CPPInstance.h:106
MethodInfo_t * fMethodInfo
Definition: CPPOverload.h:68
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)
Definition: Converters.cxx:460
virtual PyObject * FromMemory(void *address)
Definition: Converters.cxx:452
virtual bool SetArg(PyObject *, Parameter &, CallContext *=nullptr)
virtual PyObject * FromMemory(void *address)
Cppyy::TCppType_t fClass
Definition: Converters.h:62
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:136
basic_string_view< char > string_view
#define I(x, y, z)
#define H(x, y, z)
PyObject * gCastCpp
Definition: PyStrings.cxx:11
PyObject * gNoImplicit
Definition: PyStrings.cxx:56
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)
Definition: TypeManip.cxx:187
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:615
const std::string Compound(const std::string &name)
Definition: Utility.cxx:784
bool IncludePython()
Definition: Utility.cxx:937
Set of helper functions that are invoked from the pythonizors, on the Python side.
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)
Definition: LowLevelViews.h:56
bool RefFloat_CheckExact(T *object)
Definition: CustomPyTypes.h:20
bool CPPExcInstance_Check(T *object)
bool NoImplicit(CallContext *ctxt)
Definition: CallContext.h:131
static ConvFactories_t gConvFactories
Definition: Converters.cxx:39
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:79
bool RefInt_CheckExact(T *object)
Definition: CustomPyTypes.h:35
bool CPPScope_Check(T *object)
Definition: CPPScope.h:76
CPYCPPYY_EXTERN bool RegisterConverter(const std::string &name, ConverterFactory_t)
bool AllowImplicit(CallContext *ctxt)
Definition: CallContext.h:127
bool UseStrictOwnership(CallContext *ctxt)
Definition: CallContext.h:139
bool CPPInstance_Check(T *object)
Definition: CPPInstance.h:118
PyObject * CreateScopeProxy(Cppyy::TCppScope_t)
Converter *(* cf_t)(dims_t d)
Definition: Converters.h:27
PyObject * gNullPtrObject
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)
Definition: TemplateProxy.h:79
std::map< std::string, cf_t > ConvFactories_t
Definition: Converters.cxx:38
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 IsConstructor(TCppMethod_t method)
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 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)
static double B[]
static double Q[]
static constexpr double pc
static constexpr double L
Definition: first.py:1
const char * Long
const char * ULong
const char * Float
const char * Double
const char * UChar
const char * Short
const char * Int
const char * UInt
const char * UShort
const char * Bool
const char * Char
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)
Definition: CallContext.cxx:16
union CPyCppyy::Parameter::Value fValue
PyObject_HEAD char * b_ptr
Definition: Converters.cxx:57
PyObject_HEAD void * pffi_type
Definition: Converters.cxx:63
union CPyCppyy_tagPyCArgObject::@217 value
TMarker m
Definition: textangle.C:8
TLine l
Definition: textangle.C:4
unsigned long long fULLong
Definition: callcontext.h:26
unsigned char byte
Definition: gifdecode.c:10