Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
Converters.cxx
Go to the documentation of this file.
1 // @(#)root/pyroot:$Id$
2 // Author: Wim Lavrijsen, Jan 2005
3 
4 // Bindings
5 #include "PyROOT.h"
6 #include "PyStrings.h"
7 #include "Converters.h"
8 #include "TCallContext.h"
9 #include "ObjectProxy.h"
10 #include "TPyBufferFactory.h"
11 #include "TCustomPyTypes.h"
12 #include "TTupleOfInstances.h"
13 #include "Utility.h"
14 #include "RootWrapper.h"
15 
16 // ROOT
17 #include "TClass.h" // for checking class info existence
18 #include "TClassEdit.h" // for CleanType and ShortType
19 
20 // Standard
21 #include <limits.h>
22 #include <stddef.h> // for ptrdiff_t
23 #include <string.h>
24 #include <utility>
25 #include <sstream>
26 #include <tuple>
27 
28 // FIXME: Should refer to PyROOT::TParameter in the code.
29 #ifdef R__CXXMODULES
30  #define TParameter PyROOT::TParameter
31 #endif
32 
33 //- data ______________________________________________________________________
34 namespace PyROOT {
35 
36 // factories
37  typedef TConverter* (*ConverterFactory_t) ( Long_t size );
38  typedef std::map< std::string, ConverterFactory_t > ConvFactories_t;
39  ConvFactories_t gConvFactories;
40  R__EXTERN PyObject* gNullPtrObject;
41 
42 }
43 
44 //- pretend-ctypes helpers ----------------------------------------------------
45 #if PY_VERSION_HEX >= 0x02050000
46 
47 struct PyROOT_tagCDataObject { // non-public (but so far very stable)
48  PyObject_HEAD
49  char* b_ptr;
50 };
51 
52 static inline PyTypeObject* GetCTypesType( const char* name ) {
53  PyObject* ct = PyImport_ImportModule( "ctypes" );
54  if ( ! ct ) return nullptr;
55  PyTypeObject* ct_t = (PyTypeObject*)PyObject_GetAttrString( ct, name );
56  Py_DECREF( ct );
57  return ct_t;
58 }
59 
60 #endif
61 
62 //- custom helpers to check ranges --------------------------------------------
63 
64 ////////////////////////////////////////////////////////////////////////////////
65 /// range-checking python integer to C++ bool conversion
66 static inline Bool_t PyROOT_PyLong_AsBool( PyObject* pyobject )
67 {
68  Long_t l = PyLong_AsLong( pyobject );
69 // fail to pass float -> bool; the problem is rounding (0.1 -> 0 -> False)
70  if ( ! ( l == 0 || l == 1 ) || PyFloat_Check( pyobject ) ) {
71  PyErr_SetString( PyExc_ValueError, "boolean value should be bool, or integer 1 or 0" );
72  return (Bool_t)-1;
73  }
74  return (Bool_t)l;
75 }
76 
77 ////////////////////////////////////////////////////////////////////////////////
78 /// python string to C++ char conversion
79 static inline Char_t PyROOT_PyUnicode_AsChar( PyObject* pyobject ) {
80  return (Char_t)PyROOT_PyUnicode_AsString( pyobject )[0];
81 }
82 
83 ////////////////////////////////////////////////////////////////////////////////
84 /// range-checking python integer to C++ unsigned short int conversion
85 static inline UShort_t PyROOT_PyLong_AsUShort( PyObject* pyobject )
86 {
87 // prevent p2.7 silent conversions and do a range check
88  if ( ! (PyLong_Check( pyobject ) || PyInt_Check( pyobject )) ) {
89  PyErr_SetString( PyExc_TypeError, "unsigned short conversion expects an integer object" );
90  return (UShort_t)-1;
91  }
92  Long_t l = PyLong_AsLong( pyobject );
93  if ( l < 0 || USHRT_MAX < l ) {
94  PyErr_Format( PyExc_ValueError, "integer %ld out of range for unsigned short", l );
95  return (UShort_t)-1;
96 
97  }
98  return (UShort_t)l;
99 }
100 
101 ////////////////////////////////////////////////////////////////////////////////
102 /// range-checking python integer to C++ short int conversion
103 static inline Short_t PyROOT_PyLong_AsShort( PyObject* pyobject )
104 {
105 // prevent p2.7 silent conversions and do a range check
106  if ( ! (PyLong_Check( pyobject ) || PyInt_Check( pyobject )) ) {
107  PyErr_SetString( PyExc_TypeError, "short int conversion expects an integer object" );
108  return (Short_t)-1;
109  }
110  Long_t l = PyLong_AsLong( pyobject );
111  if ( l < SHRT_MIN || SHRT_MAX < l ) {
112  PyErr_Format( PyExc_ValueError, "integer %ld out of range for short int", l );
113  return (Short_t)-1;
114 
115  }
116  return (Short_t)l;
117 }
118 
119 
120 ////////////////////////////////////////////////////////////////////////////////
121 /// strict python integer to C++ integer conversion
122 static inline Long_t PyROOT_PyLong_AsStrictLong( PyObject* pyobject )
123 {
124 // p2.7 and later silently converts floats to long, therefore require this
125 // check; earlier pythons may raise a SystemError which should be avoided as
126 // it is confusing
127  if ( ! (PyLong_Check( pyobject ) || PyInt_Check( pyobject )) ) {
128  PyErr_SetString( PyExc_TypeError, "int/long conversion expects an integer object" );
129  return (Long_t)-1;
130  }
131  return (Long_t)PyLong_AsLong( pyobject );
132 }
133 
134 
135 //- base converter implementation ---------------------------------------------
136 PyObject* PyROOT::TConverter::FromMemory( void* )
137 {
138 // could happen if no derived class override
139  PyErr_SetString( PyExc_TypeError, "C++ type can not be converted from memory" );
140  return 0;
141 }
142 
143 ////////////////////////////////////////////////////////////////////////////////
144 /// could happen if no derived class override
145 
146 Bool_t PyROOT::TConverter::ToMemory( PyObject*, void* )
147 {
148  PyErr_SetString( PyExc_TypeError, "C++ type can not be converted to memory" );
149  return kFALSE;
150 }
151 
152 
153 //- helper macro's ------------------------------------------------------------
154 #define PYROOT_IMPLEMENT_BASIC_CONVERTER( name, type, stype, F1, F2, tc ) \
155 Bool_t PyROOT::T##name##Converter::SetArg( \
156  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ ) \
157 { \
158 /* convert `pyobject` to C++ 'type', set arg for call */ \
159  type val = (type)F2( pyobject ); \
160  if ( val == (type)-1 && PyErr_Occurred() ) \
161  return kFALSE; \
162  para.fValue.f##name = val; \
163  para.fTypeCode = tc; \
164  return kTRUE; \
165 } \
166  \
167 PyObject* PyROOT::T##name##Converter::FromMemory( void* address ) \
168 { \
169  return F1( (stype)*((type*)address) ); \
170 } \
171  \
172 Bool_t PyROOT::T##name##Converter::ToMemory( PyObject* value, void* address ) \
173 { \
174  type s = (type)F2( value ); \
175  if ( s == (type)-1 && PyErr_Occurred() ) \
176  return kFALSE; \
177  *((type*)address) = (type)s; \
178  return kTRUE; \
179 }
180 
181 
182 static inline Int_t ExtractChar( PyObject* pyobject, const char* tname, Int_t low, Int_t high )
183 {
184  Int_t lchar = -1;
185  if ( PyROOT_PyUnicode_Check( pyobject ) ) {
186  if ( PyROOT_PyUnicode_GET_SIZE( pyobject ) == 1 )
187  lchar = (Int_t)PyROOT_PyUnicode_AsChar( pyobject );
188  else
189  PyErr_Format( PyExc_TypeError, "%s expected, got string of size " PY_SSIZE_T_FORMAT,
190  tname, PyROOT_PyUnicode_GET_SIZE( pyobject ) );
191  } else if ( ! PyFloat_Check( pyobject ) ) { // don't allow truncating conversion
192  lchar = PyLong_AsLong( pyobject );
193  if ( lchar == -1 && PyErr_Occurred() )
194  ; // empty, as error already set
195  else if ( ! ( low <= lchar && lchar <= high ) ) {
196  PyErr_Format( PyExc_ValueError,
197  "integer to character: value %d not in range [%d,%d]", lchar, low, high );
198  lchar = -1;
199  }
200  } else
201  PyErr_SetString( PyExc_TypeError, "char or small int type expected" );
202 
203  return lchar;
204 }
205 
206 
207 #define PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( name, type, F1 )\
208 Bool_t PyROOT::TConst##name##RefConverter::SetArg( \
209  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ ) \
210 { \
211  type val = (type)F1( pyobject ); \
212  if ( val == (type)-1 && PyErr_Occurred() ) \
213  return kFALSE; \
214  para.fValue.f##name = val; \
215  para.fRef = &para.fValue.f##name; \
216  para.fTypeCode = 'r'; \
217  return kTRUE; \
218 }
219 
220 #define PYROOT_IMPLEMENT_BASIC_CONST_CHAR_REF_CONVERTER( name, type, low, high )\
221 Bool_t PyROOT::TConst##name##RefConverter::SetArg( \
222  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ ) \
223 { \
224 /* convert `pyobject` to C++ <<type>>, set arg for call, allow int -> char */ \
225  type val = (type)ExtractChar( pyobject, #type, low, high ); \
226  if ( val == (type)-1 && PyErr_Occurred() ) \
227  return kFALSE; \
228  para.fValue.fLong = val; \
229  para.fTypeCode = 'l'; \
230  return kTRUE; \
231 }
232 
233 
234 ////////////////////////////////////////////////////////////////////////////////
235 
236 #define PYROOT_IMPLEMENT_BASIC_CHAR_CONVERTER( name, type, low, high ) \
237 Bool_t PyROOT::T##name##Converter::SetArg( \
238  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ ) \
239 { \
240 /* convert `pyobject` to C++ <<type>>, set arg for call, allow int -> char */ \
241  Long_t val = ExtractChar( pyobject, #type, low, high ); \
242  if ( val == -1 && PyErr_Occurred() ) \
243  return kFALSE; \
244  para.fValue.fLong = val; \
245  para.fTypeCode = 'l'; \
246  return kTRUE; \
247 } \
248  \
249 PyObject* PyROOT::T##name##Converter::FromMemory( void* address ) \
250 { \
251  return PyROOT_PyUnicode_FromFormat( "%c", *((type*)address) ); \
252 } \
253  \
254 Bool_t PyROOT::T##name##Converter::ToMemory( PyObject* value, void* address ) \
255 { \
256  if ( PyROOT_PyUnicode_Check( value ) ) { \
257  const char* buf = PyROOT_PyUnicode_AsString( value ); \
258  if ( PyErr_Occurred() ) \
259  return kFALSE; \
260  int len = PyROOT_PyUnicode_GET_SIZE( value ); \
261  if ( len != 1 ) { \
262  PyErr_Format( PyExc_TypeError, #type" expected, got string of size %d", len );\
263  return kFALSE; \
264  } \
265  *((type*)address) = (type)buf[0]; \
266  } else { \
267  Long_t l = PyLong_AsLong( value ); \
268  if ( l == -1 && PyErr_Occurred() ) \
269  return kFALSE; \
270  if ( ! ( low <= l && l <= high ) ) { \
271  PyErr_Format( PyExc_ValueError, \
272  "integer to character: value %ld not in range [%d,%d]", l, low, high );\
273  return kFALSE; \
274  } \
275  *((type*)address) = (type)l; \
276  } \
277  return kTRUE; \
278 }
279 
280 
281 //- converters for built-ins --------------------------------------------------
282 PYROOT_IMPLEMENT_BASIC_CONVERTER( Long, Long_t, Long_t, PyLong_FromLong, PyROOT_PyLong_AsStrictLong, 'l' )
283 
284 ////////////////////////////////////////////////////////////////////////////////
285 /// convert `pyobject` to C++ long&, set arg for call
286 
287 Bool_t PyROOT::TLongRefConverter::SetArg(
288  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
289 {
290 #if PY_VERSION_HEX < 0x03000000
291  if ( TCustomInt_CheckExact( pyobject ) ) {
292  para.fValue.fVoidp = (void*)&((PyIntObject*)pyobject)->ob_ival;
293  para.fTypeCode = 'V';
294  if (PyErr_WarnEx(PyExc_FutureWarning,
295  "ROOT.Long is deprecated and will disappear in a future version of ROOT. "
296  "Instead, use ctypes.c_long for pass-by-ref of longs", 1) < 0) {
297  return kFALSE;
298  }
299  return kTRUE;
300  }
301 #endif
302 
303 #if PY_VERSION_HEX < 0x02050000
304  PyErr_SetString( PyExc_TypeError, "use ROOT.Long for pass-by-ref of longs" );
305  return kFALSE;
306 #endif
307 
308 // TODO: this keeps a refcount to the type .. it should be okay to drop that
309  static PyTypeObject* c_long_type = GetCTypesType( "c_long" );
310  if ( Py_TYPE( pyobject ) == c_long_type ) {
311  para.fValue.fVoidp = (void*)((PyROOT_tagCDataObject*)pyobject)->b_ptr;
312  para.fTypeCode = 'V';
313  return kTRUE;
314  }
315 
316  PyErr_SetString( PyExc_TypeError, "use ctypes.c_long for pass-by-ref of longs" );
317  return kFALSE;
318 }
319 
320 ////////////////////////////////////////////////////////////////////////////////
321 
322 PYROOT_IMPLEMENT_BASIC_CONST_CHAR_REF_CONVERTER( Char, Char_t, CHAR_MIN, CHAR_MAX )
323 PYROOT_IMPLEMENT_BASIC_CONST_CHAR_REF_CONVERTER( UChar, UChar_t, 0, UCHAR_MAX )
324 
325 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( Bool, Bool_t, PyROOT_PyLong_AsBool )
326 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( Short, Short_t, PyROOT_PyLong_AsShort )
327 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( UShort, UShort_t, PyROOT_PyLong_AsUShort )
328 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( Int, Int_t, PyROOT_PyLong_AsStrictLong )
329 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( UInt, UInt_t, PyLongOrInt_AsULong )
330 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( Long, Long_t, PyROOT_PyLong_AsStrictLong )
331 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( ULong, ULong_t, PyLongOrInt_AsULong )
332 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( LongLong, Long64_t, PyLong_AsLongLong )
333 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( ULongLong, ULong64_t, PyLongOrInt_AsULong64 )
334 
335 ////////////////////////////////////////////////////////////////////////////////
336 /// convert `pyobject` to C++ (pseudo)int&, set arg for call
337 
338 Bool_t PyROOT::TIntRefConverter::SetArg(
339  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
340 {
341 #if PY_VERSION_HEX < 0x03000000
342  if ( TCustomInt_CheckExact( pyobject ) ) {
343  para.fValue.fVoidp = (void*)&((PyIntObject*)pyobject)->ob_ival;
344  para.fTypeCode = 'V';
345  if (PyErr_WarnEx(PyExc_FutureWarning,
346  "ROOT.Long is deprecated and will disappear in a future version of ROOT. "
347  "Instead, use ctypes.c_int for pass-by-ref of ints", 1) < 0) {
348  return kFALSE;
349  }
350  return kTRUE;
351  }
352 #endif
353 
354 #if PY_VERSION_HEX >= 0x02050000
355 // TODO: this keeps a refcount to the type .. it should be okay to drop that
356  static PyTypeObject* c_int_type = GetCTypesType( "c_int" );
357  if ( Py_TYPE( pyobject ) == c_int_type ) {
358  para.fValue.fVoidp = (void*)((PyROOT_tagCDataObject*)pyobject)->b_ptr;
359  para.fTypeCode = 'V';
360  return kTRUE;
361  }
362 #endif
363 
364 // alternate, pass pointer from buffer
365  int buflen = Utility::GetBuffer( pyobject, 'i', sizeof(int), para.fValue.fVoidp );
366  if ( para.fValue.fVoidp && buflen ) {
367  para.fTypeCode = 'V';
368  return kTRUE;
369  };
370 
371 #if PY_VERSION_HEX < 0x02050000
372  PyErr_SetString( PyExc_TypeError, "use ROOT.Long for pass-by-ref of ints" );
373 #else
374  PyErr_SetString( PyExc_TypeError, "use ctypes.c_int for pass-by-ref of ints" );
375 #endif
376  return kFALSE;
377 }
378 
379 ////////////////////////////////////////////////////////////////////////////////
380 /// convert `pyobject` to C++ bool, allow int/long -> bool, set arg for call
381 
382 PYROOT_IMPLEMENT_BASIC_CONVERTER( Bool, Bool_t, Long_t, PyInt_FromLong, PyROOT_PyLong_AsBool, 'l' )
383 
384 ////////////////////////////////////////////////////////////////////////////////
385 
386 PYROOT_IMPLEMENT_BASIC_CHAR_CONVERTER( Char, Char_t, CHAR_MIN, CHAR_MAX )
387 PYROOT_IMPLEMENT_BASIC_CHAR_CONVERTER( UChar, UChar_t, 0, UCHAR_MAX )
388 
389 ////////////////////////////////////////////////////////////////////////////////
390 
391 PYROOT_IMPLEMENT_BASIC_CONVERTER( Short, Short_t, Long_t, PyInt_FromLong, PyROOT_PyLong_AsShort, 'l' )
392 PYROOT_IMPLEMENT_BASIC_CONVERTER( UShort, UShort_t, Long_t, PyInt_FromLong, PyROOT_PyLong_AsUShort, 'l' )
393 PYROOT_IMPLEMENT_BASIC_CONVERTER( Int, Int_t, Long_t, PyInt_FromLong, PyROOT_PyLong_AsStrictLong, 'l' )
394 
395 ////////////////////////////////////////////////////////////////////////////////
396 /// convert `pyobject` to C++ unsigned long, set arg for call
397 
398 Bool_t PyROOT::TULongConverter::SetArg(
399  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
400 {
401  para.fValue.fULong = PyLongOrInt_AsULong( pyobject );
402  if ( PyErr_Occurred() )
403  return kFALSE;
404  para.fTypeCode = 'U';
405  return kTRUE;
406 }
407 
408 PyObject* PyROOT::TULongConverter::FromMemory( void* address )
409 {
410 // construct python object from C++ unsigned long read at <address>
411  return PyLong_FromUnsignedLong( *((ULong_t*)address) );
412 }
413 
414 Bool_t PyROOT::TULongConverter::ToMemory( PyObject* value, void* address )
415 {
416 // convert <value> to C++ unsigned long, write it at <address>
417  ULong_t u = PyLongOrInt_AsULong( value );
418  if ( PyErr_Occurred() )
419  return kFALSE;
420  *((ULong_t*)address) = u;
421  return kTRUE;
422 }
423 
424 ////////////////////////////////////////////////////////////////////////////////
425 /// construct python object from C++ unsigned int read at <address>
426 
427 PyObject* PyROOT::TUIntConverter::FromMemory( void* address )
428 {
429  return PyLong_FromUnsignedLong( *((UInt_t*)address) );
430 }
431 
432 Bool_t PyROOT::TUIntConverter::ToMemory( PyObject* value, void* address )
433 {
434 // convert <value> to C++ unsigned int, write it at <address>
435  ULong_t u = PyLongOrInt_AsULong( value );
436  if ( PyErr_Occurred() )
437  return kFALSE;
438 
439  if ( u > (ULong_t)UINT_MAX ) {
440  PyErr_SetString( PyExc_OverflowError, "value too large for unsigned int" );
441  return kFALSE;
442  }
443 
444  *((UInt_t*)address) = (UInt_t)u;
445  return kTRUE;
446 }
447 
448 ////////////////////////////////////////////////////////////////////////////////
449 /// floating point converters
450 
451 PYROOT_IMPLEMENT_BASIC_CONVERTER( Float, Float_t, Double_t, PyFloat_FromDouble, PyFloat_AsDouble, 'f' )
452 PYROOT_IMPLEMENT_BASIC_CONVERTER( Double, Double_t, Double_t, PyFloat_FromDouble, PyFloat_AsDouble, 'd' )
453 
454 PYROOT_IMPLEMENT_BASIC_CONVERTER( LongDouble, LongDouble_t, LongDouble_t, PyFloat_FromDouble, PyFloat_AsDouble, 'D' )
455 
456 ////////////////////////////////////////////////////////////////////////////////
457 /// convert `pyobject` to C++ double&, set arg for call
458 
459 Bool_t PyROOT::TDoubleRefConverter::SetArg(
460  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
461 {
462  if ( TCustomFloat_CheckExact( pyobject ) ) {
463  para.fValue.fVoidp = (void*)&((PyFloatObject*)pyobject)->ob_fval;
464  para.fTypeCode = 'V';
465  if (PyErr_WarnEx(PyExc_FutureWarning,
466  "ROOT.Double is deprecated and will disappear in a future version of ROOT. "
467  "Instead, use ctypes.c_double for pass-by-ref of doubles", 1) < 0) {
468  return kFALSE;
469  }
470  return kTRUE;
471  }
472 
473 // alternate, pass pointer from buffer
474  int buflen = Utility::GetBuffer( pyobject, 'd', sizeof(double), para.fValue.fVoidp );
475  if ( para.fValue.fVoidp && buflen ) {
476  para.fTypeCode = 'V';
477  return kTRUE;
478  }
479 
480  PyErr_SetString( PyExc_TypeError, "use ctypes.c_double for pass-by-ref of doubles" );
481  return kFALSE;
482 }
483 
484 ////////////////////////////////////////////////////////////////////////////////
485 
486 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( Float, Float_t, PyFloat_AsDouble )
487 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( Double, Double_t, PyFloat_AsDouble )
488 PYROOT_IMPLEMENT_BASIC_CONST_REF_CONVERTER( LongDouble, LongDouble_t, PyFloat_AsDouble )
489 
490 ////////////////////////////////////////////////////////////////////////////////
491 /// can't happen (unless a type is mapped wrongly), but implemented for completeness
492 
493 Bool_t PyROOT::TVoidConverter::SetArg( PyObject*, TParameter&, TCallContext* )
494 {
495  PyErr_SetString( PyExc_SystemError, "void/unknown arguments can\'t be set" );
496  return kFALSE;
497 }
498 
499 ////////////////////////////////////////////////////////////////////////////////
500 /// convert `pyobject` to C++ long long, set arg for call
501 
502 Bool_t PyROOT::TLongLongConverter::SetArg(
503  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
504 {
505  if ( PyFloat_Check( pyobject ) ) {
506  // special case: float implements nb_int, but allowing rounding conversions
507  // interferes with overloading
508  PyErr_SetString( PyExc_ValueError, "can not convert float to long long" );
509  return kFALSE;
510  }
511 
512  para.fValue.fLongLong = PyLong_AsLongLong( pyobject );
513  if ( PyErr_Occurred() )
514  return kFALSE;
515  para.fTypeCode = 'k';
516  return kTRUE;
517 }
518 
519 PyObject* PyROOT::TLongLongConverter::FromMemory( void* address )
520 {
521 // construct python object from C++ long long read at <address>
522  return PyLong_FromLongLong( *(Long64_t*)address );
523 }
524 
525 Bool_t PyROOT::TLongLongConverter::ToMemory( PyObject* value, void* address )
526 {
527 // convert <value> to C++ long long, write it at <address>
528  Long64_t ll = PyLong_AsLongLong( value );
529  if ( ll == -1 && PyErr_Occurred() )
530  return kFALSE;
531  *((Long64_t*)address) = ll;
532  return kTRUE;
533 }
534 
535 ////////////////////////////////////////////////////////////////////////////////
536 /// convert `pyobject` to C++ unsigned long long, set arg for call
537 
538 Bool_t PyROOT::TULongLongConverter::SetArg(
539  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
540 {
541  para.fValue.fULongLong = PyLongOrInt_AsULong64( pyobject );
542  if ( PyErr_Occurred() )
543  return kFALSE;
544  para.fTypeCode = 'K';
545  return kTRUE;
546 }
547 
548 PyObject* PyROOT::TULongLongConverter::FromMemory( void* address )
549 {
550 // construct python object from C++ unsigned long long read at <address>
551  return PyLong_FromUnsignedLongLong( *(ULong64_t*)address );
552 }
553 
554 Bool_t PyROOT::TULongLongConverter::ToMemory( PyObject* value, void* address )
555 {
556 // convert <value> to C++ unsigned long long, write it at <address>
557  Long64_t ull = PyLongOrInt_AsULong64( value );
558  if ( PyErr_Occurred() )
559  return kFALSE;
560  *((ULong64_t*)address) = ull;
561  return kTRUE;
562 }
563 
564 ////////////////////////////////////////////////////////////////////////////////
565 /// construct a new string and copy it in new memory
566 
567 static std::tuple<const char*,Py_ssize_t> getStringAndSizeCString(PyObject* pyobject) {
568 #if PY_VERSION_HEX >= 0x03030000
569  // Support non-ASCII strings (get the right length in bytes)
570  Py_ssize_t size = 0;
571  auto charArr = PyROOT_PyUnicode_AsStringAndSize(pyobject, &size);
572 #else
573  auto size = PyROOT_PyUnicode_GET_SIZE(pyobject);
574  auto charArr = PyROOT_PyUnicode_AsStringChecked(pyobject);
575 #endif
576  return std::tuple<const char*,Py_ssize_t>(charArr, size);
577 }
578 
579 Bool_t PyROOT::TCStringConverter::SetArg(
580  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
581 {
582  if (PyROOT_PyUnicode_Check(pyobject)
583 #if PY_VERSION_HEX < 0x03000000
584  || PyUnicode_Check(pyobject)
585 #endif
586  ) {
587  auto strAndSize = getStringAndSizeCString(pyobject);
588  fBuffer = std::string(std::get<0>(strAndSize), std::get<1>(strAndSize));
589  } else if (PyBytes_Check(pyobject)) {
590  auto s = PyBytes_AsString(pyobject); \
591  auto size = PyBytes_GET_SIZE(pyobject);
592  fBuffer = std::string(s, size);
593  } else {
594  return kFALSE;
595  }
596 
597 // verify (too long string will cause truncation, no crash)
598  if ( fMaxSize < (UInt_t)fBuffer.size() )
599  PyErr_Warn( PyExc_RuntimeWarning, (char*)"string too long for char array (truncated)" );
600  else if ( fMaxSize != UINT_MAX )
601  fBuffer.resize( fMaxSize, '\0' ); // padd remainder of buffer as needed
602 
603 // set the value and declare success
604  para.fValue.fVoidp = (void*)fBuffer.c_str();
605  para.fTypeCode = 'p';
606  return kTRUE;
607 }
608 
609 PyObject* PyROOT::TCStringConverter::FromMemory( void* address )
610 {
611 // construct python object from C++ const char* read at <address>
612  if ( address && *(char**)address ) {
613  if ( fMaxSize != UINT_MAX ) { // need to prevent reading beyond boundary
614  std::string buf( *(char**)address, fMaxSize ); // cut on fMaxSize
615  return PyROOT_PyUnicode_FromString( buf.c_str() ); // cut on \0
616  }
617 
618  return PyROOT_PyUnicode_FromString( *(char**)address );
619  }
620 
621 // empty string in case there's no address
622  Py_INCREF( PyStrings::gEmptyString );
623  return PyStrings::gEmptyString;
624 }
625 
626 Bool_t PyROOT::TCStringConverter::ToMemory( PyObject* value, void* address )
627 {
628 // convert <value> to C++ const char*, write it at <address>
629  const char* s = PyROOT_PyUnicode_AsStringChecked( value );
630  if ( PyErr_Occurred() )
631  return kFALSE;
632 
633 // verify (too long string will cause truncation, no crash)
634  if ( fMaxSize < (UInt_t)PyROOT_PyUnicode_GET_SIZE( value ) )
635  PyErr_Warn( PyExc_RuntimeWarning, (char*)"string too long for char array (truncated)" );
636 
637  if ( fMaxSize != UINT_MAX )
638  strncpy( *(char**)address, s, fMaxSize ); // padds remainder
639  else
640  // coverity[secure_coding] - can't help it, it's intentional.
641  strcpy( *(char**)address, s );
642 
643  return kTRUE;
644 }
645 
646 
647 //- pointer/array conversions -------------------------------------------------
648 namespace {
649 
650  using namespace PyROOT;
651 
652  inline Bool_t CArraySetArg(
653  PyObject* pyobject, TParameter& para, char tc, int size )
654  {
655  // general case of loading a C array pointer (void* + type code) as function argument
656  if ( pyobject == gNullPtrObject ) {
657  para.fValue.fVoidp = NULL;
658  } else {
659  int buflen = Utility::GetBuffer( pyobject, tc, size, para.fValue.fVoidp );
660  if ( ! para.fValue.fVoidp || buflen == 0 )
661  return kFALSE;
662  }
663  para.fTypeCode = 'p';
664  return kTRUE;
665  }
666 
667 } // unnamed namespace
668 
669 
670 ////////////////////////////////////////////////////////////////////////////////
671 /// attempt base class first (i.e. passing a string), but if that fails, try a buffer
672 
673 Bool_t PyROOT::TNonConstCStringConverter::SetArg(
674  PyObject* pyobject, TParameter& para, TCallContext* ctxt )
675 {
676  if ( this->TCStringConverter::SetArg( pyobject, para, ctxt ) )
677  return kTRUE;
678 
679 // apparently failed, try char buffer
680  PyErr_Clear();
681  return CArraySetArg( pyobject, para, 'c', sizeof(char) );
682 }
683 
684 ////////////////////////////////////////////////////////////////////////////////
685 /// assume this is a buffer access if the size is known; otherwise assume string
686 
687 PyObject* PyROOT::TNonConstCStringConverter::FromMemory( void* address )
688 {
689  if ( fMaxSize != UINT_MAX )
690  return PyROOT_PyUnicode_FromStringAndSize( *(char**)address, fMaxSize );
691  return this->TCStringConverter::FromMemory( address );
692 }
693 
694 ////////////////////////////////////////////////////////////////////////////////
695 /// attempt base class first (i.e. passing a string), but if that fails, try a buffer
696 
697 Bool_t PyROOT::TNonConstUCStringConverter::SetArg(
698  PyObject* pyobject, TParameter& para, TCallContext* ctxt )
699 {
700  if ( this->TCStringConverter::SetArg( pyobject, para, ctxt ) )
701  return kTRUE;
702 
703 // apparently failed, try char buffer
704  PyErr_Clear();
705  return CArraySetArg( pyobject, para, 'B', sizeof(unsigned char) );
706 }
707 
708 ////////////////////////////////////////////////////////////////////////////////
709 /// (1): "null pointer" or C++11 style nullptr
710 
711 Bool_t PyROOT::TVoidArrayConverter::GetAddressSpecialCase( PyObject* pyobject, void*& address )
712 {
713  if ( pyobject == Py_None || pyobject == gNullPtrObject ) {
714 
715  if (pyobject == Py_None) {
716  if (PyErr_WarnEx(PyExc_FutureWarning,
717  "The conversion from None to null pointer is deprecated "
718  "and will not be allowed anymore in a future version of ROOT. "
719  "Instead, use ROOT.nullptr or 0", 1) < 0) {
720  return kFALSE;
721  }
722  }
723 
724  address = (void*)0;
725  return kTRUE;
726  }
727 
728 // (2): allow integer zero to act as a null pointer, no deriveds
729  if ( PyInt_CheckExact( pyobject ) || PyLong_CheckExact( pyobject ) ) {
730  Long_t val = (Long_t)PyLong_AsLong( pyobject );
731  if ( val == 0l ) {
732  address = (void*)val;
733  return kTRUE;
734  }
735 
736  return kFALSE;
737  }
738 
739 // (3): opaque PyCapsule (CObject in older pythons) from somewhere
740  if ( PyROOT_PyCapsule_CheckExact( pyobject ) ) {
741  address = (void*)PyROOT_PyCapsule_GetPointer( pyobject, NULL );
742  return kTRUE;
743  }
744 
745  return kFALSE;
746 }
747 
748 ////////////////////////////////////////////////////////////////////////////////
749 /// just convert pointer if it is a ROOT object
750 
751 Bool_t PyROOT::TVoidArrayConverter::SetArg(
752  PyObject* pyobject, TParameter& para, TCallContext* ctxt )
753 {
754  if ( ObjectProxy_Check( pyobject ) ) {
755  // depending on memory policy, some objects are no longer owned when passed to C++
756  if ( ! fKeepControl && ! UseStrictOwnership( ctxt ) )
757  ((ObjectProxy*)pyobject)->Release();
758 
759  // set pointer (may be null) and declare success
760  para.fValue.fVoidp = ((ObjectProxy*)pyobject)->GetObject();
761  para.fTypeCode = 'p';
762  return kTRUE;
763  }
764 
765 // handle special cases
766  if ( GetAddressSpecialCase( pyobject, para.fValue.fVoidp ) ) {
767  para.fTypeCode = 'p';
768  return kTRUE;
769  }
770 
771 // final try: attempt to get buffer
772  int buflen = Utility::GetBuffer( pyobject, '*', 1, para.fValue.fVoidp, kFALSE );
773 
774 // ok if buffer exists (can't perform any useful size checks)
775  if ( para.fValue.fVoidp && buflen != 0 ) {
776  para.fTypeCode = 'p';
777  return kTRUE;
778  }
779 
780 // give up
781  return kFALSE;
782 }
783 
784 ////////////////////////////////////////////////////////////////////////////////
785 /// nothing sensible can be done, just return <address> as pylong
786 
787 PyObject* PyROOT::TVoidArrayConverter::FromMemory( void* address )
788 {
789  if ( ! address || *(ptrdiff_t*)address == 0 ) {
790  Py_INCREF( gNullPtrObject );
791  return gNullPtrObject;
792  }
793  return BufFac_t::Instance()->PyBuffer_FromMemory( (Long_t*)*(ptrdiff_t**)address, sizeof(void*) );
794 }
795 
796 ////////////////////////////////////////////////////////////////////////////////
797 /// just convert pointer if it is a ROOT object
798 
799 Bool_t PyROOT::TVoidArrayConverter::ToMemory( PyObject* value, void* address )
800 {
801  if ( ObjectProxy_Check( value ) ) {
802  // depending on memory policy, some objects are no longer owned when passed to C++
803  if ( ! fKeepControl && TCallContext::sMemoryPolicy != TCallContext::kUseStrict )
804  ((ObjectProxy*)value)->Release();
805 
806  // set pointer (may be null) and declare success
807  *(void**)address = ((ObjectProxy*)value)->GetObject();
808  return kTRUE;
809  }
810 
811 // handle special cases
812  void* ptr = 0;
813  if ( GetAddressSpecialCase( value, ptr ) ) {
814  *(void**)address = ptr;
815  return kTRUE;
816  }
817 
818 // final try: attempt to get buffer
819  void* buf = 0;
820  int buflen = Utility::GetBuffer( value, '*', 1, buf, kFALSE );
821  if ( ! buf || buflen == 0 )
822  return kFALSE;
823 
824  *(void**)address = buf;
825  return kTRUE;
826 }
827 
828 ////////////////////////////////////////////////////////////////////////////////
829 
830 #define PYROOT_IMPLEMENT_ARRAY_CONVERTER( name, type, code ) \
831 Bool_t PyROOT::T##name##ArrayConverter::SetArg( \
832  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ ) \
833 { \
834  return CArraySetArg( pyobject, para, code, sizeof(type) ); \
835 } \
836  \
837 Bool_t PyROOT::T##name##ArrayRefConverter::SetArg( \
838  PyObject* pyobject, TParameter& para, TCallContext* ctxt ) \
839 { \
840  Bool_t result = T##name##ArrayConverter::SetArg( pyobject, para, ctxt ); \
841  para.fTypeCode = 'V'; \
842  return result; \
843 } \
844  \
845 PyObject* PyROOT::T##name##ArrayConverter::FromMemory( void* address ) \
846 { \
847  return BufFac_t::Instance()->PyBuffer_FromMemory( *(type**)address, fSize * sizeof(type) );\
848 } \
849  \
850 Bool_t PyROOT::T##name##ArrayConverter::ToMemory( PyObject* value, void* address )\
851 { \
852  void* buf = 0; \
853  int buflen = Utility::GetBuffer( value, code, sizeof(type), buf ); \
854  if ( ! buf || buflen == 0 ) \
855  return kFALSE; \
856  if ( 0 <= fSize ) { \
857  if ( fSize < buflen/(int)sizeof(type) ) { \
858  PyErr_SetString( PyExc_ValueError, "buffer too large for value" ); \
859  return kFALSE; \
860  } \
861  memcpy( *(type**)address, buf, 0 < buflen ? ((size_t) buflen) : sizeof(type) );\
862  } else \
863  *(type**)address = (type*)buf; \
864  return kTRUE; \
865 }
866 
867 ////////////////////////////////////////////////////////////////////////////////
868 
869 PYROOT_IMPLEMENT_ARRAY_CONVERTER( Bool, Bool_t, 'b' ) // signed char
870 PYROOT_IMPLEMENT_ARRAY_CONVERTER( Short, Short_t, 'h' )
871 PYROOT_IMPLEMENT_ARRAY_CONVERTER( UShort, UShort_t, 'H' )
872 PYROOT_IMPLEMENT_ARRAY_CONVERTER( Int, Int_t, 'i' )
873 PYROOT_IMPLEMENT_ARRAY_CONVERTER( UInt, UInt_t, 'I' )
874 PYROOT_IMPLEMENT_ARRAY_CONVERTER( Long, Long_t, 'l' )
875 PYROOT_IMPLEMENT_ARRAY_CONVERTER( ULong, ULong_t, 'L' )
876 PYROOT_IMPLEMENT_ARRAY_CONVERTER( Float, Float_t, 'f' )
877 PYROOT_IMPLEMENT_ARRAY_CONVERTER( Double, Double_t, 'd' )
878 
879 ////////////////////////////////////////////////////////////////////////////////
880 /// convert `pyobject` to C++ long long*, set arg for call
881 
882 Bool_t PyROOT::TLongLongArrayConverter::SetArg(
883  PyObject* pyobject, TParameter& para, TCallContext* ctxt )
884 {
885  PyObject* pytc = PyObject_GetAttr( pyobject, PyStrings::gTypeCode );
886  if ( pytc != 0 ) { // iow, this array has a known type, but there's no
887  Py_DECREF( pytc ); // such thing for long long in module array
888  return kFALSE;
889  }
890 
891  return TVoidArrayConverter::SetArg( pyobject, para, ctxt );
892 }
893 
894 
895 //- converters for special cases ----------------------------------------------
896 
897 static std::tuple<const char*,Py_ssize_t> getStringAndSizeSTLString(PyObject* pyobject) {
898 #if PY_VERSION_HEX >= 0x03030000
899  // Support non-ASCII strings (get the right length in bytes)
900  Py_ssize_t size = 0;
901  auto charArr = PyROOT_PyUnicode_AsStringAndSize(pyobject, &size);
902 #else
903  auto size = PyROOT_PyUnicode_GET_SIZE(pyobject);
904  auto charArr = PyROOT_PyUnicode_AsString(pyobject);
905 #endif
906  return std::tuple<const char*,Py_ssize_t>(charArr, size);
907 }
908 
909 #define PYROOT_IMPLEMENT_STRING_AS_PRIMITIVE_CONVERTER( name, type, F1, F2 ) \
910 PyROOT::T##name##Converter::T##name##Converter( Bool_t keepControl ) : \
911  TCppObjectConverter( Cppyy::GetScope( #type ), keepControl ) {} \
912  \
913 Bool_t PyROOT::T##name##Converter::SetArg( \
914  PyObject* pyobject, TParameter& para, TCallContext* ctxt ) \
915 { \
916  if ( PyROOT_PyUnicode_Check( pyobject ) ) { \
917  auto strAndSize = getStringAndSizeSTLString(pyobject); \
918  fBuffer = type(std::get<0>(strAndSize), std::get<1>(strAndSize)); \
919  para.fValue.fVoidp = &fBuffer; \
920  para.fTypeCode = 'V'; \
921  return kTRUE; \
922  } \
923  \
924  if (PyBytes_Check(pyobject)) { \
925  auto s = PyBytes_AsString(pyobject); \
926  auto size = PyBytes_GET_SIZE(pyobject); \
927  fBuffer = type(s, size); \
928  para.fValue.fVoidp = &fBuffer; \
929  para.fTypeCode = 'V'; \
930  return kTRUE; \
931  } \
932  \
933  if ( ! ( PyInt_Check( pyobject ) || PyLong_Check( pyobject ) ) ) { \
934  Bool_t result = TCppObjectConverter::SetArg( pyobject, para, ctxt ); \
935  para.fTypeCode = 'V'; \
936  return result; \
937  } \
938  return kFALSE; \
939 } \
940  \
941 PyObject* PyROOT::T##name##Converter::FromMemory( void* address ) \
942 { \
943  if ( address ) \
944  return PyROOT_PyUnicode_FromStringAndSize( ((type*)address)->F1(), ((type*)address)->F2() );\
945  Py_INCREF( PyStrings::gEmptyString ); \
946  return PyStrings::gEmptyString; \
947 } \
948  \
949 Bool_t PyROOT::T##name##Converter::ToMemory( PyObject* value, void* address ) \
950 { \
951  if ( PyROOT_PyUnicode_Check( value ) ) { \
952  *((type*)address) = PyROOT_PyUnicode_AsString( value ); \
953  return kTRUE; \
954  } \
955  \
956  return TCppObjectConverter::ToMemory( value, address ); \
957 }
958 
959 PYROOT_IMPLEMENT_STRING_AS_PRIMITIVE_CONVERTER( TString, TString, Data, Length )
960 PYROOT_IMPLEMENT_STRING_AS_PRIMITIVE_CONVERTER( STLString, std::string, c_str, size )
961 PYROOT_IMPLEMENT_STRING_AS_PRIMITIVE_CONVERTER( STLStringView, std::string_view, data, size )
962 
963 ////////////////////////////////////////////////////////////////////////////////
964 /// convert `pyobject` to C++ instance*, set arg for call
965 
966 Bool_t PyROOT::TCppObjectConverter::SetArg(
967  PyObject* pyobject, TParameter& para, TCallContext* ctxt )
968 {
969  if ( ! ObjectProxy_Check( pyobject ) ) {
970  if ( GetAddressSpecialCase( pyobject, para.fValue.fVoidp ) ) {
971  para.fTypeCode = 'p'; // allow special cases such as NULL
972  return kTRUE;
973  }
974 
975  // not a PyROOT object (TODO: handle SWIG etc.)
976  return kFALSE;
977  }
978 
979  ObjectProxy* pyobj = (ObjectProxy*)pyobject;
980  if ( pyobj->ObjectIsA() && Cppyy::IsSubtype( pyobj->ObjectIsA(), fClass ) ) {
981  // depending on memory policy, some objects need releasing when passed into functions
982  if ( ! KeepControl() && ! UseStrictOwnership( ctxt ) )
983  ((ObjectProxy*)pyobject)->Release();
984 
985  // calculate offset between formal and actual arguments
986  para.fValue.fVoidp = pyobj->GetObject();
987  if ( pyobj->ObjectIsA() != fClass ) {
988  para.fValue.fLong += Cppyy::GetBaseOffset(
989  pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */ );
990  }
991 
992  // set pointer (may be null) and declare success
993  para.fTypeCode = 'p';
994  return kTRUE;
995 
996  } else if ( ! TClass::GetClass( Cppyy::GetFinalName( fClass ).c_str() )->GetClassInfo() ) {
997  // assume "user knows best" to allow anonymous pointer passing
998  para.fValue.fVoidp = pyobj->GetObject();
999  para.fTypeCode = 'p';
1000  return kTRUE;
1001  }
1002 
1003  return kFALSE;
1004 }
1005 
1006 ////////////////////////////////////////////////////////////////////////////////
1007 /// construct python object from C++ instance read at <address>
1008 
1009 PyObject* PyROOT::TCppObjectConverter::FromMemory( void* address )
1010 {
1011  return BindCppObject( address, fClass, kFALSE );
1012 }
1013 
1014 ////////////////////////////////////////////////////////////////////////////////
1015 /// convert <value> to C++ instance, write it at <address>
1016 
1017 Bool_t PyROOT::TCppObjectConverter::ToMemory( PyObject* value, void* address )
1018 {
1019  if ( ! ObjectProxy_Check( value ) ) {
1020  void* ptr = 0;
1021  if ( GetAddressSpecialCase( value, ptr ) ) {
1022  *(void**)address = ptr; // allow special cases such as NULL
1023  return kTRUE;
1024  }
1025 
1026  // not a PyROOT object (TODO: handle SWIG etc.)
1027  return kFALSE;
1028  }
1029 
1030  if ( Cppyy::IsSubtype( ((ObjectProxy*)value)->ObjectIsA(), fClass ) ) {
1031  // depending on memory policy, some objects need releasing when passed into functions
1032  if ( ! KeepControl() && TCallContext::sMemoryPolicy != TCallContext::kUseStrict )
1033  ((ObjectProxy*)value)->Release();
1034 
1035  // call assignment operator through a temporarily wrapped object proxy
1036  PyObject* pyobj = BindCppObjectNoCast( address, fClass );
1037  ((ObjectProxy*)pyobj)->Release(); // TODO: might be recycled (?)
1038  PyObject* result = PyObject_CallMethod( pyobj, (char*)"__assign__", (char*)"O", value );
1039  Py_DECREF( pyobj );
1040  if ( result ) {
1041  Py_DECREF( result );
1042  return kTRUE;
1043  }
1044  }
1045 
1046  return kFALSE;
1047 }
1048 
1049 // TODO: CONSOLIDATE ValueCpp, RefCpp, and CppObject ...
1050 
1051 ////////////////////////////////////////////////////////////////////////////////
1052 /// convert `pyobject` to C++ instance, set arg for call
1053 
1054 Bool_t PyROOT::TValueCppObjectConverter::SetArg(
1055  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
1056 {
1057  if ( ObjectProxy_Check( pyobject ) ) {
1058  ObjectProxy* pyobj = (ObjectProxy*)pyobject;
1059  if ( pyobj->ObjectIsA() && Cppyy::IsSubtype( pyobj->ObjectIsA(), fClass ) ) {
1060  // calculate offset between formal and actual arguments
1061  para.fValue.fVoidp = pyobj->GetObject();
1062  if ( ! para.fValue.fVoidp )
1063  return kFALSE;
1064 
1065  if ( pyobj->ObjectIsA() != fClass ) {
1066  para.fValue.fLong += Cppyy::GetBaseOffset(
1067  pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */ );
1068  }
1069 
1070  para.fTypeCode = 'V';
1071  return kTRUE;
1072  }
1073  }
1074  else if ( PyTuple_Check( pyobject ) ){ // It is a Python tuple (equivalent to a C++ initializer list)
1075 
1076  // instantiate an object proxy of this class
1077  if( ! fObjProxy ) {
1078  // retrieve the python class from which we will create an instance
1079  PyObject* pyclass = CreateScopeProxy( fClass );
1080  if ( ! pyclass ) return kFALSE; // error has been set in CreateScopeProxy
1081  fObjProxy = (ObjectProxy*)((PyTypeObject*)pyclass)->tp_new( (PyTypeObject*)pyclass, NULL, NULL );
1082  Py_DECREF( pyclass );
1083  }
1084 
1085  if( fObjProxy->GetObject() ) {
1086  // the actual C++ object was already created (in a previous call), so we need to destroy it
1087  Cppyy::CallDestructor( fObjProxy->ObjectIsA(), fObjProxy->GetObject() );
1088  Cppyy::Deallocate( fObjProxy->ObjectIsA(), fObjProxy->GetObject() );
1089  fObjProxy->Set(nullptr);
1090  }
1091 
1092  // get the constructor (i.e. __init__)
1093  PyObject* constructor = PyObject_GetAttr( (PyObject*)fObjProxy, PyStrings::gInit );
1094  if( ! constructor ) return kFALSE;
1095 
1096  // call the constructor with the arguments in the given tuple
1097  PyObject* obj = PyObject_CallObject( constructor, pyobject );
1098  Py_DECREF( constructor );
1099  if ( ! obj ) return kFALSE;
1100  Py_DECREF( obj );
1101 
1102  para.fValue.fVoidp = fObjProxy->GetObject();
1103  para.fTypeCode = 'V';
1104  return kTRUE;
1105 
1106  }
1107  return kFALSE;
1108 }
1109 
1110 ////////////////////////////////////////////////////////////////////////////////
1111 /// convert `pyobject` to C++ instance&, set arg for call
1112 
1113 Bool_t PyROOT::TRefCppObjectConverter::SetArg(
1114  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
1115 {
1116  if ( ObjectProxy_Check( pyobject ) ) { // It is PyROOT object
1117  ObjectProxy* pyobj = (ObjectProxy*)pyobject;
1118  if ( pyobj->ObjectIsA() && Cppyy::IsSubtype( pyobj->ObjectIsA(), fClass ) ) {
1119  // calculate offset between formal and actual arguments
1120  para.fValue.fVoidp = pyobj->GetObject();
1121  if ( pyobj->ObjectIsA() != fClass ) {
1122  para.fValue.fLong += Cppyy::GetBaseOffset(
1123  pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */ );
1124  }
1125 
1126  para.fTypeCode = 'V';
1127  return kTRUE;
1128  } else if ( ! TClass::GetClass( Cppyy::GetFinalName( fClass ).c_str() )->GetClassInfo() ) {
1129  // assume "user knows best" to allow anonymous reference passing
1130  para.fValue.fVoidp = pyobj->GetObject();
1131  para.fTypeCode = 'V';
1132  return kTRUE;
1133  }
1134  }
1135  else if ( PyTuple_Check( pyobject ) ){ // It is a Python tuple (equivalent to a C++ initializer list)
1136 
1137  // instantiate an object proxy of this class
1138  if( ! fObjProxy ) {
1139  // retrieve the python class from which we will create an instance
1140  PyObject* pyclass = CreateScopeProxy( fClass );
1141  if ( ! pyclass ) return kFALSE; // error has been set in CreateScopeProxy
1142  fObjProxy = (ObjectProxy*)((PyTypeObject*)pyclass)->tp_new( (PyTypeObject*)pyclass, NULL, NULL );
1143  Py_DECREF( pyclass );
1144  }
1145 
1146  if( fObjProxy->GetObject() ) {
1147  // the actual C++ object was already created (in a previous call), so we need to destroy it
1148  Cppyy::CallDestructor( fObjProxy->ObjectIsA(), fObjProxy->GetObject() );
1149  Cppyy::Deallocate( fObjProxy->ObjectIsA(), fObjProxy->GetObject() );
1150  fObjProxy->Set(nullptr);
1151  }
1152 
1153  // get the constructor (i.e. __init__)
1154  PyObject* constructor = PyObject_GetAttr( (PyObject*)fObjProxy, PyStrings::gInit );
1155  if( ! constructor ) return kFALSE;
1156 
1157  // call the constructor with the arguments in the given tuple
1158  PyObject* obj = PyObject_CallObject( constructor, pyobject );
1159  Py_DECREF( constructor );
1160  if ( ! obj ) return kFALSE;
1161  Py_DECREF( obj );
1162 
1163  para.fValue.fVoidp = fObjProxy->GetObject();
1164  para.fTypeCode = 'V';
1165  return kTRUE;
1166  }
1167 
1168  return kFALSE;
1169 }
1170 
1171 ////////////////////////////////////////////////////////////////////////////////
1172 /// convert `pyobject` to C++ instance**, set arg for call
1173 
1174 template <bool ISREFERENCE>
1175 Bool_t PyROOT::TCppObjectPtrConverter<ISREFERENCE>::SetArg(
1176  PyObject* pyobject, TParameter& para, TCallContext* ctxt )
1177 {
1178  if ( ! ObjectProxy_Check( pyobject ) )
1179  return kFALSE; // not a PyROOT object (TODO: handle SWIG etc.)
1180 
1181  if ( Cppyy::IsSubtype( ((ObjectProxy*)pyobject)->ObjectIsA(), fClass ) ) {
1182  // depending on memory policy, some objects need releasing when passed into functions
1183  if ( ! KeepControl() && ! UseStrictOwnership( ctxt ) )
1184  ((ObjectProxy*)pyobject)->Release();
1185 
1186  // set pointer (may be null) and declare success
1187  if( ((ObjectProxy*)pyobject)->fFlags & ObjectProxy::kIsReference)
1188  // If given object is already a reference (aka pointer) then we should not take the address of it
1189  para.fValue.fVoidp = ((ObjectProxy*)pyobject)->fObject;
1190  else
1191  para.fValue.fVoidp = &((ObjectProxy*)pyobject)->fObject;
1192  para.fTypeCode = ISREFERENCE ? 'V' : 'p';
1193  return kTRUE;
1194  }
1195 
1196  return kFALSE;
1197 }
1198 
1199 ////////////////////////////////////////////////////////////////////////////////
1200 /// construct python object from C++ instance* read at <address>
1201 
1202 template <bool ISREFERENCE>
1203 PyObject* PyROOT::TCppObjectPtrConverter<ISREFERENCE>::FromMemory( void* address )
1204 {
1205  return BindCppObject( address, fClass, kTRUE );
1206 }
1207 
1208 ////////////////////////////////////////////////////////////////////////////////
1209 /// convert <value> to C++ instance*, write it at <address>
1210 
1211 template <bool ISREFERENCE>
1212 Bool_t PyROOT::TCppObjectPtrConverter<ISREFERENCE>::ToMemory( PyObject* value, void* address )
1213 {
1214  if ( ! ObjectProxy_Check( value ) )
1215  return kFALSE; // not a PyROOT object (TODO: handle SWIG etc.)
1216 
1217  if ( Cppyy::IsSubtype( ((ObjectProxy*)value)->ObjectIsA(), fClass ) ) {
1218  // depending on memory policy, some objects need releasing when passed into functions
1219  if ( ! KeepControl() && TCallContext::sMemoryPolicy != TCallContext::kUseStrict )
1220  ((ObjectProxy*)value)->Release();
1221 
1222  // set pointer (may be null) and declare success
1223  *(void**)address = ((ObjectProxy*)value)->GetObject();
1224  return kTRUE;
1225  }
1226 
1227  return kFALSE;
1228 }
1229 
1230 
1231 namespace PyROOT {
1232 ////////////////////////////////////////////////////////////////////////////////
1233 /// Instantiate the templates
1234 
1235 template class TCppObjectPtrConverter<true>;
1236 template class TCppObjectPtrConverter<false>;
1237 }
1238 
1239 ////////////////////////////////////////////////////////////////////////////////
1240 /// convert `pyobject` to C++ instance**, set arg for call
1241 
1242 Bool_t PyROOT::TCppObjectArrayConverter::SetArg(
1243  PyObject* pyobject, TParameter& para, TCallContext* /* txt */ )
1244 {
1245  if ( ! TTupleOfInstances_CheckExact( pyobject ) )
1246  return kFALSE; // no guarantee that the tuple is okay
1247 
1248 // treat the first instance of the tuple as the start of the array, and pass it
1249 // by pointer (TODO: store and check sizes)
1250  if ( PyTuple_Size( pyobject ) < 1 )
1251  return kFALSE;
1252 
1253  PyObject* first = PyTuple_GetItem( pyobject, 0 );
1254  if ( ! ObjectProxy_Check( first ) )
1255  return kFALSE; // should not happen
1256 
1257  if ( Cppyy::IsSubtype( ((ObjectProxy*)first)->ObjectIsA(), fClass ) ) {
1258  // no memory policies supported; set pointer (may be null) and declare success
1259  para.fValue.fVoidp = ((ObjectProxy*)first)->fObject;
1260  para.fTypeCode = 'p';
1261  return kTRUE;
1262  }
1263 
1264  return kFALSE;
1265 }
1266 
1267 ////////////////////////////////////////////////////////////////////////////////
1268 /// construct python tuple of instances from C++ array read at <address>
1269 
1270 PyObject* PyROOT::TCppObjectArrayConverter::FromMemory( void* address )
1271 {
1272  if ( m_size <= 0 ) // if size unknown, just hand out the first object
1273  return BindCppObjectNoCast( address, fClass );
1274 
1275  return BindCppObjectArray( address, fClass, m_size );
1276 }
1277 
1278 ////////////////////////////////////////////////////////////////////////////////
1279 /// convert <value> to C++ array of instances, write it at <address>
1280 
1281 Bool_t PyROOT::TCppObjectArrayConverter::ToMemory( PyObject* /* value */, void* /* address */ )
1282 {
1283 // TODO: need to have size both for the array and from the input
1284  PyErr_SetString( PyExc_NotImplementedError,
1285  "access to C-arrays of objects not yet implemented!" );
1286  return kFALSE;
1287 }
1288 
1289 //____________________________________________________________________________
1290 // CLING WORKAROUND -- classes for STL iterators are completely undefined in that
1291 // they come in a bazillion different guises, so just do whatever
1292 Bool_t PyROOT::TSTLIteratorConverter::SetArg(
1293  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
1294 {
1295  if ( ! ObjectProxy_Check( pyobject ) )
1296  return kFALSE;
1297 
1298 // just set the pointer value, no check
1299  ObjectProxy* pyobj = (ObjectProxy*)pyobject;
1300  para.fValue.fVoidp = pyobj->GetObject();
1301  para.fTypeCode = 'V';
1302  return kTRUE;
1303 }
1304 // -- END CLING WORKAROUND
1305 
1306 ////////////////////////////////////////////////////////////////////////////////
1307 /// convert `pyobject` to C++ void*&, set arg for call
1308 
1309 Bool_t PyROOT::TVoidPtrRefConverter::SetArg(
1310  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
1311 {
1312  if ( ObjectProxy_Check( pyobject ) ) {
1313  para.fValue.fVoidp = &((ObjectProxy*)pyobject)->fObject;
1314  para.fTypeCode = 'V';
1315  return kTRUE;
1316  }
1317 
1318  return kFALSE;
1319 }
1320 
1321 ////////////////////////////////////////////////////////////////////////////////
1322 /// convert `pyobject` to C++ void**, set arg for call
1323 
1324 Bool_t PyROOT::TVoidPtrPtrConverter::SetArg(
1325  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
1326 {
1327  if ( ObjectProxy_Check( pyobject ) ) {
1328  // this is a ROOT object, take and set its address
1329  para.fValue.fVoidp = &((ObjectProxy*)pyobject)->fObject;
1330  para.fTypeCode = 'p';
1331  return kTRUE;
1332  }
1333 
1334 // buffer objects are allowed under "user knows best"
1335  int buflen = Utility::GetBuffer( pyobject, '*', 1, para.fValue.fVoidp, kFALSE );
1336 
1337 // ok if buffer exists (can't perform any useful size checks)
1338  if ( para.fValue.fVoidp && buflen != 0 ) {
1339  para.fTypeCode = 'p';
1340  return kTRUE;
1341  }
1342 
1343  return kFALSE;
1344 }
1345 
1346 ////////////////////////////////////////////////////////////////////////////////
1347 /// read a void** from address; since this is unknown, long is used (user can cast)
1348 
1349 PyObject* PyROOT::TVoidPtrPtrConverter::FromMemory( void* address )
1350 {
1351  if ( ! address || *(ptrdiff_t*)address == 0 ) {
1352  Py_INCREF( gNullPtrObject );
1353  return gNullPtrObject;
1354  }
1355  return BufFac_t::Instance()->PyBuffer_FromMemory( (Long_t*)*(ptrdiff_t**)address, sizeof(void*) );
1356 }
1357 
1358 ////////////////////////////////////////////////////////////////////////////////
1359 /// by definition: set and declare success
1360 
1361 Bool_t PyROOT::TPyObjectConverter::SetArg(
1362  PyObject* pyobject, TParameter& para, TCallContext* /* ctxt */ )
1363 {
1364  para.fValue.fVoidp = pyobject;
1365  para.fTypeCode = 'p';
1366  return kTRUE;
1367 }
1368 
1369 PyObject* PyROOT::TPyObjectConverter::FromMemory( void* address )
1370 {
1371 // construct python object from C++ PyObject* read at <address>
1372  PyObject* pyobject = *((PyObject**)address);
1373 
1374  if ( ! pyobject ) {
1375  Py_INCREF( Py_None );
1376  return Py_None;
1377  }
1378 
1379  Py_INCREF( pyobject );
1380  return pyobject;
1381 }
1382 
1383 Bool_t PyROOT::TPyObjectConverter::ToMemory( PyObject* value, void* address )
1384 {
1385 // no conversion needed, write <value> at <address>
1386  Py_INCREF( value );
1387  *((PyObject**)address) = value;
1388  return kTRUE;
1389 }
1390 
1391 
1392 ////////////////////////////////////////////////////////////////////////////////
1393 /// smart pointer converter
1394 
1395 Bool_t PyROOT::TSmartPtrCppObjectConverter::SetArg(
1396  PyObject* pyobject, TParameter& para, TCallContext* ctxt )
1397 {
1398  char typeCode = fHandlePtr ? 'p' : 'V';
1399 
1400  if ( ! ObjectProxy_Check( pyobject ) ) {
1401  if ( fHandlePtr && GetAddressSpecialCase( pyobject, para.fValue.fVoidp ) ) {
1402  para.fTypeCode = typeCode; // allow special cases such as NULL
1403  return kTRUE;
1404  }
1405 
1406  return kFALSE;
1407  }
1408 
1409  ObjectProxy* pyobj = (ObjectProxy*)pyobject;
1410 
1411 // for the case where we have a 'hidden' smart pointer:
1412  if ( pyobj->fFlags & ObjectProxy::kIsSmartPtr && Cppyy::IsSubtype( pyobj->fSmartPtrType, fClass ) ) {
1413  // depending on memory policy, some objects need releasing when passed into functions
1414  if ( fKeepControl && ! UseStrictOwnership( ctxt ) )
1415  ((ObjectProxy*)pyobject)->Release();
1416 
1417  // calculate offset between formal and actual arguments
1418  para.fValue.fVoidp = pyobj->fSmartPtr;
1419  if ( pyobj->fSmartPtrType != fClass ) {
1420  para.fValue.fLong += Cppyy::GetBaseOffset(
1421  pyobj->fSmartPtrType, fClass, para.fValue.fVoidp, 1 /* up-cast */ );
1422  }
1423 
1424  // set pointer (may be null) and declare success
1425  para.fTypeCode = typeCode;
1426  return kTRUE;
1427  }
1428 
1429 // for the case where we have an 'exposed' smart pointer:
1430  if ( pyobj->ObjectIsA() && Cppyy::IsSubtype( pyobj->ObjectIsA(), fClass ) ) {
1431  // calculate offset between formal and actual arguments
1432  para.fValue.fVoidp = pyobj->GetObject();
1433  if ( pyobj->ObjectIsA() != fClass ) {
1434  para.fValue.fLong += Cppyy::GetBaseOffset(
1435  pyobj->ObjectIsA(), fClass, para.fValue.fVoidp, 1 /* up-cast */ );
1436  }
1437 
1438  // set pointer (may be null) and declare success
1439  para.fTypeCode = typeCode;
1440  return kTRUE;
1441  }
1442 
1443  return kFALSE;
1444 }
1445 
1446 PyObject* PyROOT::TSmartPtrCppObjectConverter::FromMemory( void* address )
1447 {
1448  if ( !address || !fClass )
1449  return nullptr;
1450 
1451 // obtain raw pointer
1452  std::vector<TParameter> args;
1453  ObjectProxy* pyobj = (ObjectProxy*) BindCppObject(
1454  Cppyy::CallR( (Cppyy::TCppMethod_t)fDereferencer, address, &args ), fRawPtrType );
1455  if ( pyobj )
1456  pyobj->SetSmartPtr( (void*)address, fClass );
1457 
1458  return (PyObject*)pyobj;
1459 }
1460 
1461 
1462 ////////////////////////////////////////////////////////////////////////////////
1463 /// raise a NotImplemented exception to take a method out of overload resolution
1464 
1465 Bool_t PyROOT::TNotImplementedConverter::SetArg( PyObject*, TParameter&, TCallContext* )
1466 {
1467  PyErr_SetString( PyExc_NotImplementedError, "this method can not (yet) be called" );
1468  return kFALSE;
1469 }
1470 
1471 
1472 //- factories -----------------------------------------------------------------
1473 PyROOT::TConverter* PyROOT::CreateConverter( const std::string& fullType, Long_t size )
1474 {
1475 // The matching of the fulltype to a converter factory goes through up to five levels:
1476 // 1) full, exact match
1477 // 2) match of decorated, unqualified type
1478 // 3) accept const ref as by value
1479 // 4) accept ref as pointer
1480 // 5) generalized cases (covers basically all ROOT classes)
1481 //
1482 // If all fails, void is used, which will generate a run-time warning when used.
1483 
1484 // an exactly matching converter is best
1485  ConvFactories_t::iterator h = gConvFactories.find( fullType );
1486  if ( h != gConvFactories.end() )
1487  return (h->second)( size );
1488 
1489 // resolve typedefs etc.
1490  std::string resolvedType = Cppyy::ResolveName( fullType );
1491 
1492 // a full, qualified matching converter is preferred
1493  h = gConvFactories.find( resolvedType );
1494  if ( h != gConvFactories.end() )
1495  return (h->second)( size );
1496 
1497 //-- nothing? ok, collect information about the type and possible qualifiers/decorators
1498  const std::string& cpd = Utility::Compound( resolvedType );
1499  std::string realType = TClassEdit::ShortType( resolvedType.c_str(), 1 );
1500 
1501 // accept unqualified type (as python does not know about qualifiers)
1502  h = gConvFactories.find( realType + cpd );
1503  if ( h != gConvFactories.end() )
1504  return (h->second)( size );
1505 
1506 // CLING WORKAROUND -- if the type is a fixed-size array, it will have a funky
1507 // resolved type like MyClass(&)[N], which TClass::GetClass() fails on. So, strip
1508 // it down:
1509  if ( cpd == "[]" )
1510  realType = TClassEdit::CleanType( realType.substr( 0, realType.rfind("(") ).c_str(), 1 );
1511 // -- CLING WORKAROUND
1512 
1513 //-- still nothing? try pointer instead of array (for builtins)
1514  if ( cpd == "[]" ) {
1515  h = gConvFactories.find( realType + "*" );
1516  if ( h != gConvFactories.end() )
1517  return (h->second)( size );
1518  }
1519 
1520 //-- still nothing? use a generalized converter
1521  Bool_t isConst = resolvedType.substr(0, 5) == "const";
1522  Bool_t control = cpd == "&" || isConst;
1523 
1524 // converters for known/ROOT classes and default (void*)
1525  TConverter* result = 0;
1526  if ( Cppyy::TCppScope_t klass = Cppyy::GetScope( realType ) ) {
1527  if ( Cppyy::IsSmartPtr( realType ) ) {
1528  const std::vector< Cppyy::TCppMethod_t > methods = Cppyy::GetMethodsFromName( klass, "operator->", /*bases?*/ true );
1529  if ( ! methods.empty() ) {
1530  Cppyy::TCppType_t rawPtrType = Cppyy::GetScope(
1531  TClassEdit::ShortType( Cppyy::GetMethodResultType( methods[0] ).c_str(), 1 ) );
1532  if ( rawPtrType ) {
1533  if ( cpd == "" ) {
1534  result = new TSmartPtrCppObjectConverter( klass, rawPtrType, methods[0], control );
1535  } else if ( cpd == "&" ) {
1536  result = new TSmartPtrCppObjectConverter( klass, rawPtrType, methods[0] );
1537  } else if ( cpd == "*" && size <= 0 ) {
1538  result = new TSmartPtrCppObjectConverter( klass, rawPtrType, methods[0], control, kTRUE );
1539  } /* else if ( cpd == "**" || cpd == "*&" || cpd == "&*" ) {
1540  } else if ( cpd == "[]" || size > 0 ) {
1541  } else {
1542  } */
1543  }
1544  }
1545  }
1546 
1547  if ( ! result ) {
1548  // CLING WORKAROUND -- special case for STL iterators
1549  if ( realType.find( "__gnu_cxx::__normal_iterator", 0 ) /* vector */ == 0 )
1550  result = new TSTLIteratorConverter();
1551  else
1552  // -- CLING WORKAROUND
1553  if ( cpd == "**" || cpd == "&*" )
1554  result = new TCppObjectPtrConverter<false>( klass, control);
1555  else if ( cpd == "*&" )
1556  result = new TCppObjectPtrConverter<true>( klass, control);
1557  else if ( cpd == "*" && size <= 0 )
1558  result = new TCppObjectConverter( klass, control );
1559  else if ( cpd == "&" )
1560  result = new TRefCppObjectConverter( klass );
1561  else if ( cpd == "[]" || size > 0 )
1562  result = new TCppObjectArrayConverter( klass, size, kFALSE );
1563  else if ( cpd == "" ) // by value
1564  result = new TValueCppObjectConverter( klass, kTRUE );
1565  }
1566  } else if ( Cppyy::IsEnum( realType ) ) {
1567  // Get underlying type of enum
1568  std::string et(TClassEdit::ResolveTypedef(Cppyy::ResolveEnum(realType).c_str()));
1569  if (cpd == "&") {
1570  auto reft = et + "&";
1571  h = isConst ? gConvFactories.find("const " + reft) : gConvFactories.find(reft);
1572  } else
1573  h = gConvFactories.find(et);
1574  } else if ( realType.find( "(*)" ) != std::string::npos ||
1575  ( realType.find( "::*)" ) != std::string::npos ) ) {
1576  // this is a function function pointer
1577  // TODO: find better way of finding the type
1578  // TODO: a converter that generates wrappers as appropriate
1579  h = gConvFactories.find( "void*" );
1580  }
1581 
1582  if ( ! result && cpd == "&&" ) // moves
1583  result = new TNotImplementedConverter();
1584 
1585  if ( ! result && h != gConvFactories.end() )
1586  // converter factory available, use it to create converter
1587  result = (h->second)( size );
1588  else if ( ! result ) {
1589  if ( cpd != "" ) {
1590  std::stringstream s;
1591  s << "creating converter for unknown type \"" << fullType << "\"" << std::ends;
1592  PyErr_Warn( PyExc_RuntimeWarning, (char*)s.str().c_str() );
1593  result = new TVoidArrayConverter(); // "user knows best"
1594  } else
1595  result = new TVoidConverter(); // fails on use
1596  }
1597 
1598  return result;
1599 }
1600 
1601 ////////////////////////////////////////////////////////////////////////////////
1602 
1603 #define PYROOT_BASIC_CONVERTER_FACTORY( name ) \
1604 TConverter* Create##name##Converter( Long_t ) \
1605 { \
1606  return new T##name##Converter(); \
1607 }
1608 
1609 #define PYROOT_ARRAY_CONVERTER_FACTORY( name ) \
1610 TConverter* Create##name##Converter( Long_t size ) \
1611 { \
1612  return new T##name##Converter( size ); \
1613 }
1614 
1615 ////////////////////////////////////////////////////////////////////////////////
1616 
1617 namespace {
1618  using namespace PyROOT;
1619 
1620 // use macro rather than template for portability ...
1621  PYROOT_BASIC_CONVERTER_FACTORY( Bool )
1622  PYROOT_BASIC_CONVERTER_FACTORY( ConstBoolRef )
1623  PYROOT_BASIC_CONVERTER_FACTORY( Char )
1624  PYROOT_BASIC_CONVERTER_FACTORY( ConstCharRef )
1625  PYROOT_BASIC_CONVERTER_FACTORY( UChar )
1626  PYROOT_BASIC_CONVERTER_FACTORY( ConstUCharRef )
1627  PYROOT_BASIC_CONVERTER_FACTORY( Short )
1628  PYROOT_BASIC_CONVERTER_FACTORY( ConstShortRef )
1629  PYROOT_BASIC_CONVERTER_FACTORY( UShort )
1630  PYROOT_BASIC_CONVERTER_FACTORY( ConstUShortRef )
1631  PYROOT_BASIC_CONVERTER_FACTORY( Int )
1632  PYROOT_BASIC_CONVERTER_FACTORY( IntRef )
1633  PYROOT_BASIC_CONVERTER_FACTORY( ConstIntRef )
1634  PYROOT_BASIC_CONVERTER_FACTORY( UInt )
1635  PYROOT_BASIC_CONVERTER_FACTORY( ConstUIntRef )
1636  PYROOT_BASIC_CONVERTER_FACTORY( Long )
1637  PYROOT_BASIC_CONVERTER_FACTORY( LongRef )
1638  PYROOT_BASIC_CONVERTER_FACTORY( ConstLongRef )
1639  PYROOT_BASIC_CONVERTER_FACTORY( ULong )
1640  PYROOT_BASIC_CONVERTER_FACTORY( ConstULongRef )
1641  PYROOT_BASIC_CONVERTER_FACTORY( Float )
1642  PYROOT_BASIC_CONVERTER_FACTORY( ConstFloatRef )
1643  PYROOT_BASIC_CONVERTER_FACTORY( Double )
1644  PYROOT_BASIC_CONVERTER_FACTORY( DoubleRef )
1645  PYROOT_BASIC_CONVERTER_FACTORY( ConstDoubleRef )
1646  PYROOT_BASIC_CONVERTER_FACTORY( LongDouble )
1647  PYROOT_BASIC_CONVERTER_FACTORY( ConstLongDoubleRef )
1648  PYROOT_BASIC_CONVERTER_FACTORY( Void )
1649  PYROOT_BASIC_CONVERTER_FACTORY( LongLong )
1650  PYROOT_BASIC_CONVERTER_FACTORY( ConstLongLongRef )
1651  PYROOT_BASIC_CONVERTER_FACTORY( ULongLong )
1652  PYROOT_BASIC_CONVERTER_FACTORY( ConstULongLongRef )
1653  PYROOT_ARRAY_CONVERTER_FACTORY( CString )
1654  PYROOT_ARRAY_CONVERTER_FACTORY( NonConstCString )
1655  PYROOT_ARRAY_CONVERTER_FACTORY( NonConstUCString )
1656  PYROOT_ARRAY_CONVERTER_FACTORY( BoolArray )
1657  PYROOT_BASIC_CONVERTER_FACTORY( BoolArrayRef )
1658  PYROOT_ARRAY_CONVERTER_FACTORY( ShortArray )
1659  PYROOT_ARRAY_CONVERTER_FACTORY( ShortArrayRef )
1660  PYROOT_ARRAY_CONVERTER_FACTORY( UShortArray )
1661  PYROOT_ARRAY_CONVERTER_FACTORY( UShortArrayRef )
1662  PYROOT_ARRAY_CONVERTER_FACTORY( IntArray )
1663  PYROOT_ARRAY_CONVERTER_FACTORY( UIntArray )
1664  PYROOT_ARRAY_CONVERTER_FACTORY( UIntArrayRef )
1665  PYROOT_ARRAY_CONVERTER_FACTORY( LongArray )
1666  PYROOT_ARRAY_CONVERTER_FACTORY( ULongArray )
1667  PYROOT_ARRAY_CONVERTER_FACTORY( ULongArrayRef )
1668  PYROOT_ARRAY_CONVERTER_FACTORY( FloatArray )
1669  PYROOT_ARRAY_CONVERTER_FACTORY( FloatArrayRef )
1670  PYROOT_ARRAY_CONVERTER_FACTORY( DoubleArray )
1671  PYROOT_BASIC_CONVERTER_FACTORY( VoidArray )
1672  PYROOT_BASIC_CONVERTER_FACTORY( LongLongArray )
1673  PYROOT_BASIC_CONVERTER_FACTORY( TString )
1674  PYROOT_BASIC_CONVERTER_FACTORY( STLString )
1675  PYROOT_BASIC_CONVERTER_FACTORY( STLStringView )
1676  PYROOT_BASIC_CONVERTER_FACTORY( VoidPtrRef )
1677  PYROOT_BASIC_CONVERTER_FACTORY( VoidPtrPtr )
1678  PYROOT_BASIC_CONVERTER_FACTORY( PyObject )
1679 
1680 // converter factories for ROOT types
1681  typedef std::pair< const char*, ConverterFactory_t > NFp_t;
1682 
1683  // clang-format off
1684  NFp_t factories_[] = {
1685  // factories for built-ins
1686  NFp_t( "bool", &CreateBoolConverter ),
1687  NFp_t( "const bool&", &CreateConstBoolRefConverter ),
1688  NFp_t( "char", &CreateCharConverter ),
1689  NFp_t( "const char&", &CreateConstCharRefConverter ),
1690  NFp_t( "signed char", &CreateCharConverter ),
1691  NFp_t( "const signed char&", &CreateConstCharRefConverter ),
1692  NFp_t( "unsigned char", &CreateUCharConverter ),
1693  NFp_t( "const unsigned char&", &CreateConstUCharRefConverter ),
1694  NFp_t( "short", &CreateShortConverter ),
1695  NFp_t( "const short&", &CreateConstShortRefConverter ),
1696  NFp_t( "unsigned short", &CreateUShortConverter ),
1697  NFp_t( "const unsigned short&", &CreateConstUShortRefConverter ),
1698  NFp_t( "int", &CreateIntConverter ),
1699  NFp_t( "int&", &CreateIntRefConverter ),
1700  NFp_t( "const int&", &CreateConstIntRefConverter ),
1701  NFp_t( "unsigned int", &CreateUIntConverter ),
1702  NFp_t( "const unsigned int&", &CreateConstUIntRefConverter ),
1703  NFp_t( "long", &CreateLongConverter ),
1704  NFp_t( "long&", &CreateLongRefConverter ),
1705  NFp_t( "const long&", &CreateConstLongRefConverter ),
1706  NFp_t( "unsigned long", &CreateULongConverter ),
1707  NFp_t( "const unsigned long&", &CreateConstULongRefConverter ),
1708  NFp_t( "long long", &CreateLongLongConverter ),
1709  NFp_t( "const long long&", &CreateConstLongLongRefConverter ),
1710  NFp_t( "Long64_t", &CreateLongLongConverter ),
1711  NFp_t( "const Long64_t&", &CreateConstLongLongRefConverter ),
1712  NFp_t( "unsigned long long", &CreateULongLongConverter ),
1713  NFp_t( "const unsigned long long&", &CreateConstULongLongRefConverter ),
1714  NFp_t( "ULong64_t", &CreateULongLongConverter ),
1715  NFp_t( "const ULong64_t&", &CreateConstULongLongRefConverter ),
1716 
1717  NFp_t( "float", &CreateFloatConverter ),
1718  NFp_t( "const float&", &CreateConstFloatRefConverter ),
1719  NFp_t( "double", &CreateDoubleConverter ),
1720  NFp_t( "double&", &CreateDoubleRefConverter ),
1721  NFp_t( "const double&", &CreateConstDoubleRefConverter ),
1722  NFp_t( "long double", &CreateLongDoubleConverter ),
1723  NFp_t( "const long double&", &CreateConstLongDoubleRefConverter ),
1724  NFp_t( "void", &CreateVoidConverter ),
1725 
1726  // pointer/array factories
1727  NFp_t( "bool*", &CreateBoolArrayConverter ),
1728  NFp_t( "bool&", &CreateBoolArrayRefConverter ),
1729  NFp_t( "const unsigned char*", &CreateCStringConverter ),
1730  NFp_t( "unsigned char*", &CreateNonConstUCStringConverter ),
1731  NFp_t( "short*", &CreateShortArrayConverter ),
1732  NFp_t( "short&", &CreateShortArrayRefConverter ),
1733  NFp_t( "unsigned short*", &CreateUShortArrayConverter ),
1734  NFp_t( "unsigned short&", &CreateUShortArrayRefConverter ),
1735  NFp_t( "int*", &CreateIntArrayConverter ),
1736  NFp_t( "unsigned int*", &CreateUIntArrayConverter ),
1737  NFp_t( "unsigned int&", &CreateUIntArrayRefConverter ),
1738  NFp_t( "long*", &CreateLongArrayConverter ),
1739  NFp_t( "unsigned long*", &CreateULongArrayConverter ),
1740  NFp_t( "unsigned long&", &CreateULongArrayRefConverter ),
1741  NFp_t( "float*", &CreateFloatArrayConverter ),
1742  NFp_t( "float&", &CreateFloatArrayRefConverter ),
1743  NFp_t( "double*", &CreateDoubleArrayConverter ),
1744  NFp_t( "long long*", &CreateLongLongArrayConverter ),
1745  NFp_t( "Long64_t*", &CreateLongLongArrayConverter ),
1746  NFp_t( "unsigned long long*", &CreateLongLongArrayConverter ), // TODO: ULongLong
1747  NFp_t( "ULong64_t*", &CreateLongLongArrayConverter ), // TODO: ULongLong
1748  NFp_t( "void*", &CreateVoidArrayConverter ),
1749 
1750  // factories for special cases
1751  NFp_t( "const char*", &CreateCStringConverter ),
1752  NFp_t( "char*", &CreateNonConstCStringConverter ),
1753  NFp_t( "TString", &CreateTStringConverter ),
1754  NFp_t( "const TString&", &CreateTStringConverter ),
1755  NFp_t( "std::string", &CreateSTLStringConverter ),
1756  NFp_t( "string", &CreateSTLStringConverter ),
1757  NFp_t( "const std::string&", &CreateSTLStringConverter ),
1758  NFp_t( "const string&", &CreateSTLStringConverter ),
1759  NFp_t( "std::string_view", &CreateSTLStringViewConverter ),
1760  NFp_t( "string_view", &CreateSTLStringViewConverter ),
1761  NFp_t( "experimental::basic_string_view<char,char_traits<char> >",&CreateSTLStringViewConverter),
1762  NFp_t( "basic_string_view<char,char_traits<char> >",&CreateSTLStringViewConverter),
1763  NFp_t( "void*&", &CreateVoidPtrRefConverter ),
1764  NFp_t( "void**", &CreateVoidPtrPtrConverter ),
1765  NFp_t( "PyObject*", &CreatePyObjectConverter ),
1766  NFp_t( "_object*", &CreatePyObjectConverter ),
1767  NFp_t( "FILE*", &CreateVoidArrayConverter ),
1768  NFp_t( "Float16_t", &CreateFloatConverter ),
1769  NFp_t( "const Float16_t&", &CreateConstFloatRefConverter ),
1770  NFp_t( "Double32_t", &CreateDoubleConverter ),
1771  NFp_t( "Double32_t&", &CreateDoubleRefConverter ),
1772  NFp_t( "const Double32_t&", &CreateConstDoubleRefConverter )
1773  };
1774  // clang-format on
1775 
1776  struct InitConvFactories_t {
1777  public:
1778  InitConvFactories_t()
1779  {
1780  // load all converter factories in the global map 'gConvFactories'
1781  int nf = sizeof( factories_ ) / sizeof( factories_[ 0 ] );
1782  for ( int i = 0; i < nf; ++i ) {
1783  gConvFactories[ factories_[ i ].first ] = factories_[ i ].second;
1784  }
1785  }
1786  } initConvFactories_;
1787 
1788 } // unnamed namespace