Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
Executors.cxx
Go to the documentation of this file.
1// Bindings
2#include "cpyrt.h"
3
4using namespace cppjit;
5#include "CPPInstance.h"
6#include "DeclareExecutors.h"
7#include "LowLevelViews.h"
8#include "ProxyWrappers.h"
9#include "PyStrings.h"
10#include "TypeManip.h"
11#include "Utility.h"
12#include "cppjit_interop.h"
13
14// Standard
15#include <complex>
16#include <cstring>
17#include <map>
18#include <new>
19#include <sstream>
20#include <sys/types.h>
21#include <utility>
22
23//- data _____________________________________________________________________
24namespace cppjit::cpyrt {
25typedef std::unordered_map<std::string, ef_t> ExecFactories_t;
27
29
30extern std::set<std::string> gIteratorTypes;
31} // namespace cppjit::cpyrt
32
33//- helpers ------------------------------------------------------------------
34namespace {
35
36#ifdef WITH_THREAD
37class GILControl {
38public:
39 GILControl() : fSave(PyEval_SaveThread()) {}
40 ~GILControl() { PyEval_RestoreThread(fSave); }
41
42private:
43 PyThreadState* fSave;
44};
45#endif
46
47} // unnamed namespace
48
49#ifdef WITH_THREAD
50#define CPPJIT_IMPL_GILCALL(rtype, tcode) \
51 static inline rtype GILCall##tcode(interop::TCppMethod_t method, \
52 interop::TCppObject_t self, \
53 cpyrt::CallContext* ctxt) { \
54 if (!ReleasesGIL(ctxt)) \
55 return interop::Call##tcode(method, self, ctxt->GetEncodedSize(), \
56 ctxt->GetArgs()); \
57 GILControl gc{}; \
58 return interop::Call##tcode(method, self, ctxt->GetEncodedSize(), \
59 ctxt->GetArgs()); \
60 }
61#else
62#define CPPJIT_IMPL_GILCALL(rtype, tcode) \
63 static inline rtype GILCall##tcode(interop::TCppMethod_t method, \
64 interop::TCppObject_t self, \
65 cpyrt::CallContext* ctxt) { \
66 return interop::Call##tcode(method, self, ctxt->GetEncodedSize(), \
67 ctxt->GetArgs()); \
68 }
69#endif
70
71// clang-format off
73CPPJIT_IMPL_GILCALL(unsigned char, B)
83// clang-format on
84
85static inline interop::TCppObject_t GILCallO(interop::TCppMethod_t method,
86 interop::TCppObject_t self,
87 cpyrt::CallContext* ctxt,
88 interop::TCppScope_t klass) {
90#ifdef WITH_THREAD
91 if (!ReleasesGIL(ctxt))
92#endif
93 return interop::CallO(method, self, ctxt->GetEncodedSize(), ctxt->GetArgs(),
94 klass_ty);
95#ifdef WITH_THREAD
96 GILControl gc{};
97 return interop::CallO(method, self, ctxt->GetEncodedSize(), ctxt->GetArgs(),
98 klass_ty);
99#endif
100}
101
102static inline interop::TCppObject_t
104 cpyrt::CallContext* ctxt) {
105#ifdef WITH_THREAD
106 if (!ReleasesGIL(ctxt))
107#endif
108 return interop::CallConstructor(method, klass, ctxt->GetEncodedSize(),
109 ctxt->GetArgs());
110#ifdef WITH_THREAD
111 GILControl gc{};
112 return interop::CallConstructor(method, klass, ctxt->GetEncodedSize(),
113 ctxt->GetArgs());
114#endif
115}
116
117static inline PyObject* cpyrt_PyText_FromLong(long cl) {
118 // python chars are range(256)
119 if (cl < -256 || cl > 255) {
120 PyErr_SetString(PyExc_ValueError, "char conversion out of range");
121 return nullptr;
122 }
123 int c = (int)cl;
124 if (c < 0)
125 return PyUnicode_FromFormat("%c", 256 - std::abs(c));
126 return PyUnicode_FromFormat("%c", c);
127}
128
129static inline PyObject* cpyrt_PyText_FromULong(unsigned long uc) {
130 // TODO: range check here?
131 if (255 < uc) {
132 PyErr_SetString(PyExc_ValueError, "char conversion out of range");
133 return nullptr;
134 }
135 int c = (int)uc;
136 return PyUnicode_FromFormat("%c", c);
137}
138
139static inline PyObject* cpyrt_PyBool_FromLong(long b) {
140 PyObject* result = (bool)b ? Py_True : Py_False;
141 Py_INCREF(result);
142 return result;
143}
144
145//- base executor implementation ---------------------------------------------
147
148//- executors for built-ins --------------------------------------------------
149PyObject* cpyrt::BoolExecutor::Execute(interop::TCppMethod_t method,
151 CallContext* ctxt) {
152 // execute <method> with argument <self, ctxt>, construct python bool return
153 // value
154 bool retval = GILCallB(method, self, ctxt);
155 PyObject* result = retval ? Py_True : Py_False;
156 Py_INCREF(result);
157 return result;
158}
159
160//----------------------------------------------------------------------------
161PyObject* cpyrt::BoolConstRefExecutor::Execute(interop::TCppMethod_t method,
163 CallContext* ctxt) {
164 // execute <method> with argument <self, ctxt>, construct python bool return
165 // value
166 return cpyrt_PyBool_FromLong(*((bool*)GILCallR(method, self, ctxt)));
167}
168
169//----------------------------------------------------------------------------
170PyObject* cpyrt::CharExecutor::Execute(interop::TCppMethod_t method,
172 CallContext* ctxt) {
173 // execute <method with argument <self, ctxt>, construct python string return
174 // value with the single char
175 return cpyrt_PyText_FromLong((int)GILCallC(method, self, ctxt));
176}
177
178//----------------------------------------------------------------------------
179PyObject* cpyrt::CharConstRefExecutor::Execute(interop::TCppMethod_t method,
181 CallContext* ctxt) {
182 // execute <method> with argument <self, ctxt>, construct python string return
183 // value with the single char
184 return cpyrt_PyText_FromLong(*((char*)GILCallR(method, self, ctxt)));
185}
186
187//----------------------------------------------------------------------------
188PyObject* cpyrt::UCharExecutor::Execute(interop::TCppMethod_t method,
190 CallContext* ctxt) {
191 // execute <method> with argument <self, args>, construct python string return
192 // value with the single char
193 return cpyrt_PyText_FromLong((unsigned char)GILCallB(method, self, ctxt));
194}
195
196//----------------------------------------------------------------------------
197PyObject* cpyrt::UCharConstRefExecutor::Execute(interop::TCppMethod_t method,
199 CallContext* ctxt) {
200 // execute <method> with argument <self, ctxt>, construct python string return
201 // value with the single char from the pointer return
202 return cpyrt_PyText_FromLong(*((unsigned char*)GILCallR(method, self, ctxt)));
203}
204
205//----------------------------------------------------------------------------
206PyObject* cpyrt::Int8ConstRefExecutor::Execute(interop::TCppMethod_t method,
208 CallContext* ctxt) {
209 return PyLong_FromLong(*((int8_t*)GILCallR(method, self, ctxt)));
210}
211
212//----------------------------------------------------------------------------
213PyObject* cpyrt::UInt8ConstRefExecutor::Execute(interop::TCppMethod_t method,
215 CallContext* ctxt) {
216 return PyLong_FromLong(*((uint8_t*)GILCallR(method, self, ctxt)));
217}
218
219//----------------------------------------------------------------------------
220PyObject* cpyrt::WCharExecutor::Execute(interop::TCppMethod_t method,
222 CallContext* ctxt) {
223 // execute <method> with argument <self, args>, construct python string return
224 // value with the single wide char
225 wchar_t res = (wchar_t)GILCallL(method, self, ctxt);
226 return PyUnicode_FromWideChar(&res, 1);
227}
228
229//----------------------------------------------------------------------------
230PyObject* cpyrt::Char16Executor::Execute(interop::TCppMethod_t method,
232 CallContext* ctxt) {
233 // execute <method> with argument <self, args>, construct python string return
234 // value with the single char16
235 char16_t res = (char16_t)GILCallL(method, self, ctxt);
236 return PyUnicode_DecodeUTF16((const char*)&res, sizeof(char16_t), nullptr,
237 nullptr);
238}
239
240//----------------------------------------------------------------------------
241PyObject* cpyrt::Char32Executor::Execute(interop::TCppMethod_t method,
243 CallContext* ctxt) {
244 // execute <method> with argument <self, args>, construct python string return
245 // value with the single char32
246 char32_t res = (char32_t)GILCallL(method, self, ctxt);
247 return PyUnicode_DecodeUTF32((const char*)&res, sizeof(char32_t), nullptr,
248 nullptr);
249}
250
251//----------------------------------------------------------------------------
252PyObject* cpyrt::IntExecutor::Execute(interop::TCppMethod_t method,
254 CallContext* ctxt) {
255 // execute <method> with argument <self, ctxt>, construct python int return
256 // value
257 return PyLong_FromLong((int)GILCallI(method, self, ctxt));
258}
259
260//----------------------------------------------------------------------------
261PyObject* cpyrt::Int8Executor::Execute(interop::TCppMethod_t method,
263 CallContext* ctxt) {
264 // execute <method> with argument <self, ctxt>, construct python int return
265 // value
266 return PyLong_FromLong((int8_t)GILCallC(method, self, ctxt));
267}
268
269//----------------------------------------------------------------------------
270PyObject* cpyrt::UInt8Executor::Execute(interop::TCppMethod_t method,
272 CallContext* ctxt) {
273 // execute <method> with argument <self, ctxt>, construct python int return
274 // value
275 return PyLong_FromLong((uint8_t)GILCallB(method, self, ctxt));
276}
277
278//----------------------------------------------------------------------------
279PyObject* cpyrt::ShortExecutor::Execute(interop::TCppMethod_t method,
281 CallContext* ctxt) {
282 // execute <method> with argument <self, ctxt>, construct python int return
283 // value
284 return PyLong_FromLong((short)GILCallH(method, self, ctxt));
285}
286
287//----------------------------------------------------------------------------
288PyObject* cpyrt::LongExecutor::Execute(interop::TCppMethod_t method,
290 CallContext* ctxt) {
291 // execute <method> with argument <self, ctxt>, construct python long return
292 // value
293 return PyLong_FromLong((long)GILCallL(method, self, ctxt));
294}
295
296//----------------------------------------------------------------------------
297PyObject* cpyrt::ULongExecutor::Execute(interop::TCppMethod_t method,
299 CallContext* ctxt) {
300 // execute <method> with argument <self, ctxt>, construct python unsigned long
301 // return value
302 return PyLong_FromUnsignedLong((unsigned long)GILCallLL(method, self, ctxt));
303}
304
305//----------------------------------------------------------------------------
306PyObject* cpyrt::LongLongExecutor::Execute(interop::TCppMethod_t method,
308 CallContext* ctxt) {
309 // execute <method> with argument <self, ctxt>, construct python long long
310 // return value
311 PY_LONG_LONG result = GILCallLL(method, self, ctxt);
312 return PyLong_FromLongLong(result);
313}
314
315//----------------------------------------------------------------------------
316PyObject* cpyrt::ULongLongExecutor::Execute(interop::TCppMethod_t method,
318 CallContext* ctxt) {
319 // execute <method> with argument <self, ctxt>, construct python unsigned long
320 // long return value
321 PY_ULONG_LONG result = (PY_ULONG_LONG)GILCallLL(method, self, ctxt);
322 return PyLong_FromUnsignedLongLong(result);
323}
324
325//----------------------------------------------------------------------------
326PyObject* cpyrt::FloatExecutor::Execute(interop::TCppMethod_t method,
328 CallContext* ctxt) {
329 // execute <method> with argument <self, ctxt>, construct python float return
330 // value
331 return PyFloat_FromDouble((double)GILCallF(method, self, ctxt));
332}
333
334//----------------------------------------------------------------------------
335PyObject* cpyrt::DoubleExecutor::Execute(interop::TCppMethod_t method,
337 CallContext* ctxt) {
338 // execute <method> with argument <self, ctxt>, construct python float return
339 // value
340 return PyFloat_FromDouble((double)GILCallD(method, self, ctxt));
341}
342
343//----------------------------------------------------------------------------
344PyObject* cpyrt::LongDoubleExecutor::Execute(interop::TCppMethod_t method,
346 CallContext* ctxt) {
347 // execute <method> with argument <self, ctxt>, construct python float return
348 // value
349 return PyFloat_FromDouble((double)GILCallLD(method, self, ctxt));
350}
351
352//----------------------------------------------------------------------------
354 // prepare "buffer" for by-ref returns, used with __setitem__
355 if (pyobject) {
356 Py_INCREF(pyobject);
357 fAssignable = pyobject;
358 return true;
359 }
360
361 fAssignable = nullptr;
362 return false;
363}
364
365//----------------------------------------------------------------------------
366#define CPPJIT_IMPL_REFEXEC(name, type, stype, F1, F2) \
367 PyObject* cpyrt::name##RefExecutor::Execute(interop::TCppMethod_t method, \
368 interop::TCppObject_t self, \
369 CallContext* ctxt) { \
370 type* ref = (type*)GILCallR(method, self, ctxt); \
371 if (!ref) { /* can happen if wrapper compilation fails */ \
372 PyErr_SetString(PyExc_ReferenceError, \
373 "attempt to access a null-pointer"); \
374 return nullptr; \
375 } \
376 if (!fAssignable) \
377 return F1((stype) * ref); \
378 else { \
379 *ref = (type)F2(fAssignable); \
380 Py_DECREF(fAssignable); \
381 fAssignable = nullptr; \
382 if (*ref == (type) - 1 && PyErr_Occurred()) \
383 return nullptr; \
384 Py_INCREF(Py_None); \
385 return Py_None; \
386 } \
387 }
388
389// clang-format off
390CPPJIT_IMPL_REFEXEC(Bool, bool, long, cpyrt_PyBool_FromLong, PyLong_AsLong)
391CPPJIT_IMPL_REFEXEC(Char, char, long, cpyrt_PyText_FromLong, PyLong_AsLong)
392CPPJIT_IMPL_REFEXEC(UChar, unsigned char, unsigned long, cpyrt_PyText_FromULong, PyLongOrInt_AsULong)
393CPPJIT_IMPL_REFEXEC(Int8, int8_t, long, PyLong_FromLong, PyLong_AsLong)
394CPPJIT_IMPL_REFEXEC(UInt8, uint8_t, unsigned long, PyLong_FromLong, PyLongOrInt_AsULong)
395CPPJIT_IMPL_REFEXEC(Short, short, long, PyLong_FromLong, PyLong_AsLong)
396CPPJIT_IMPL_REFEXEC(UShort, unsigned short, unsigned long, PyLong_FromLong, PyLongOrInt_AsULong)
397CPPJIT_IMPL_REFEXEC(Int, int, long, PyLong_FromLong, PyLong_AsLong)
398CPPJIT_IMPL_REFEXEC(UInt, unsigned int, unsigned long, PyLong_FromUnsignedLong, PyLongOrInt_AsULong)
399CPPJIT_IMPL_REFEXEC(Long, long, long, PyLong_FromLong, PyLong_AsLong)
400CPPJIT_IMPL_REFEXEC(ULong, unsigned long, unsigned long, PyLong_FromUnsignedLong, PyLongOrInt_AsULong)
401CPPJIT_IMPL_REFEXEC(LongLong, PY_LONG_LONG, PY_LONG_LONG, PyLong_FromLongLong, PyLong_AsLongLong)
402CPPJIT_IMPL_REFEXEC(ULongLong, PY_ULONG_LONG, PY_ULONG_LONG, PyLong_FromUnsignedLongLong, PyLongOrInt_AsULong64)
403CPPJIT_IMPL_REFEXEC(Float, float, double, PyFloat_FromDouble, PyFloat_AsDouble)
404CPPJIT_IMPL_REFEXEC(Double, double, double, PyFloat_FromDouble, PyFloat_AsDouble)
405CPPJIT_IMPL_REFEXEC(LongDouble, PY_LONG_DOUBLE, PY_LONG_DOUBLE, PyFloat_FromDouble, PyFloat_AsDouble)
406// clang-format on
407
408template <typename T>
409static inline PyObject* PyComplex_FromComplex(const std::complex<T>& c) {
410 return PyComplex_FromDoubles(c.real(), c.imag());
411}
412
413template <typename T>
414static inline std::complex<T> PyComplex_AsComplex(PyObject* pycplx) {
415 Py_complex cplx = PyComplex_AsCComplex(pycplx);
416 return std::complex<T>(cplx.real, cplx.imag);
417}
418
419CPPJIT_IMPL_REFEXEC(ComplexD, std::complex<double>, std::complex<double>,
420 PyComplex_FromComplex<double>, PyComplex_AsComplex<double>)
421
422//----------------------------------------------------------------------------
423PyObject* cpyrt::STLStringRefExecutor::Execute(interop::TCppMethod_t method,
425 CallContext* ctxt) {
426 // execute <method> with argument <self, ctxt>, return python string return
427 // value
428 std::string* result = (std::string*)GILCallR(method, self, ctxt);
429 if (!fAssignable) {
430 return PyUnicode_FromStringAndSize(result->c_str(), result->size());
431 }
432
433 if (!PyUnicode_Check(fAssignable)) {
434 PyErr_Format(PyExc_TypeError, "wrong type in assignment (string expected)");
435 return nullptr;
436 }
437
438 *result = std::string(PyUnicode_AsUTF8(fAssignable),
439 PyUnicode_GET_LENGTH(fAssignable));
440
441 Py_DECREF(fAssignable);
442 fAssignable = nullptr;
443
445}
446
447//----------------------------------------------------------------------------
448PyObject* cpyrt::VoidExecutor::Execute(interop::TCppMethod_t method,
450 CallContext* ctxt) {
451 // execute <method> with argument <self, ctxt>, return None
452 GILCallV(method, self, ctxt);
453 if (PyErr_Occurred())
454 return nullptr;
456}
457
458//----------------------------------------------------------------------------
459PyObject* cpyrt::CStringExecutor::Execute(interop::TCppMethod_t method,
461 CallContext* ctxt) {
462 // execute <method> with argument <self, ctxt>, construct python string return
463 // value
464 char* result = (char*)GILCallR(method, self, ctxt);
465 if (!result) {
466 Py_INCREF(PyStrings::gEmptyString);
468 }
469
470 return PyUnicode_FromString(result);
471}
472
473//----------------------------------------------------------------------------
474PyObject* cpyrt::CStringRefExecutor::Execute(interop::TCppMethod_t method,
476 CallContext* ctxt) {
477 // execute <method> with argument <self, ctxt>, construct python string return
478 // value
479 char** result = (char**)GILCallR(method, self, ctxt);
480 if (!result || !*result) {
481 Py_INCREF(PyStrings::gEmptyString);
483 }
484
485 return PyUnicode_FromString(*result);
486}
487
488//----------------------------------------------------------------------------
489PyObject* cpyrt::WCStringExecutor::Execute(interop::TCppMethod_t method,
491 CallContext* ctxt) {
492 // execute <method> with argument <self, ctxt>, construct python unicode
493 // return value
494 wchar_t* result = (wchar_t*)GILCallR(method, self, ctxt);
495 if (!result) {
496 wchar_t w = L'\0';
497 return PyUnicode_FromWideChar(&w, 0);
498 }
499
500 return PyUnicode_FromWideChar(result, wcslen(result));
501}
502
503//----------------------------------------------------------------------------
504PyObject* cpyrt::CString16Executor::Execute(interop::TCppMethod_t method,
506 CallContext* ctxt) {
507 // execute <method> with argument <self, ctxt>, construct python unicode
508 // return value
509 char16_t* result = (char16_t*)GILCallR(method, self, ctxt);
510 if (!result) {
511 char16_t w = u'\0';
512 return PyUnicode_DecodeUTF16((const char*)&w, 0, nullptr, nullptr);
513 }
514
515 return PyUnicode_DecodeUTF16((const char*)result,
516 std::char_traits<char16_t>::length(result) *
517 sizeof(char16_t),
518 nullptr, nullptr);
519}
520
521//----------------------------------------------------------------------------
522PyObject* cpyrt::CString32Executor::Execute(interop::TCppMethod_t method,
524 CallContext* ctxt) {
525 // execute <method> with argument <self, ctxt>, construct python unicode
526 // return value
527 char32_t* result = (char32_t*)GILCallR(method, self, ctxt);
528 if (!result) {
529 char32_t w = U'\0';
530 return PyUnicode_DecodeUTF32((const char*)&w, 0, nullptr, nullptr);
531 }
532
533 return PyUnicode_DecodeUTF32((const char*)result,
534 std::char_traits<char32_t>::length(result) *
535 sizeof(char32_t),
536 nullptr, nullptr);
537}
538
539//- pointer/array executors --------------------------------------------------
540PyObject* cpyrt::VoidArrayExecutor::Execute(interop::TCppMethod_t method,
542 CallContext* ctxt) {
543 // execute <method> with argument <self, ctxt>, construct python long return
544 // value
545 intptr_t* result = (intptr_t*)GILCallR(method, self, ctxt);
546 if (!result) {
547 Py_INCREF(gNullPtrObject);
548 return gNullPtrObject;
549 }
551}
552
553//----------------------------------------------------------------------------
554#define CPPJIT_IMPL_ARRAY_EXEC(name, type, suffix) \
555 PyObject* cpyrt::name##ArrayExecutor::Execute(interop::TCppMethod_t method, \
556 interop::TCppObject_t self, \
557 CallContext* ctxt) { \
558 return CreateLowLevelView##suffix((type*)GILCallR(method, self, ctxt), \
559 fShape); \
560 }
561
562// clang-format off
563CPPJIT_IMPL_ARRAY_EXEC(Bool, bool, )
564CPPJIT_IMPL_ARRAY_EXEC(SChar, signed char, )
565CPPJIT_IMPL_ARRAY_EXEC(UChar, unsigned char, )
566CPPJIT_IMPL_ARRAY_EXEC(Byte, std::byte, )
567CPPJIT_IMPL_ARRAY_EXEC(Int8, int8_t, _i8)
568CPPJIT_IMPL_ARRAY_EXEC(UInt8, uint8_t, _i8)
569CPPJIT_IMPL_ARRAY_EXEC(Short, short, )
570CPPJIT_IMPL_ARRAY_EXEC(UShort, unsigned short, )
571CPPJIT_IMPL_ARRAY_EXEC(Int, int, )
572CPPJIT_IMPL_ARRAY_EXEC(UInt, unsigned int, )
573CPPJIT_IMPL_ARRAY_EXEC(Long, long, )
574CPPJIT_IMPL_ARRAY_EXEC(ULong, unsigned long, )
575CPPJIT_IMPL_ARRAY_EXEC(LLong, long long, )
576CPPJIT_IMPL_ARRAY_EXEC(ULLong, unsigned long long, )
577CPPJIT_IMPL_ARRAY_EXEC(Float, float, )
578CPPJIT_IMPL_ARRAY_EXEC(Double, double, )
579CPPJIT_IMPL_ARRAY_EXEC(LDouble, long double, )
580CPPJIT_IMPL_ARRAY_EXEC(ComplexF, std::complex<float>, )
581CPPJIT_IMPL_ARRAY_EXEC(ComplexD, std::complex<double>, )
582CPPJIT_IMPL_ARRAY_EXEC(ComplexI, std::complex<int>, )
583CPPJIT_IMPL_ARRAY_EXEC(ComplexL, std::complex<long>, )
584// clang-format on
585
586//- special cases ------------------------------------------------------------
587#define CPPJIT_COMPLEX_EXEC(code, type) \
588 PyObject* cpyrt::Complex##code##Executor::Execute( \
589 interop::TCppMethod_t method, interop::TCppObject_t self, \
590 CallContext* ctxt) { \
591 static interop::TCppScope_t scopeid = \
592 interop::GetScope("std::complex<" #type ">"); \
593 std::complex<type>* result = \
594 (std::complex<type>*)GILCallO(method, self, ctxt, scopeid).data; \
595 if (!result) { \
596 PyErr_SetString(PyExc_ValueError, \
597 "NULL result where temporary expected"); \
598 return nullptr; \
599 } \
600 \
601 PyObject* pyres = PyComplex_FromDoubles(result->real(), result->imag()); \
602 ::operator delete(result); /* interop::CallO calls ::operator new */ \
603 return pyres; \
604 }
605
606CPPJIT_COMPLEX_EXEC(D, double)
607
608//----------------------------------------------------------------------------
609PyObject* cpyrt::STLStringExecutor::Execute(interop::TCppMethod_t method,
611 CallContext* ctxt) {
612 // execute <method> with argument <self, ctxt>, construct python string return
613 // value
614
615 // TODO: make use of GILLCallS (?!)
616 static interop::TCppScope_t sSTLStringScope =
617 interop::GetFullScope("std::string");
618 std::string* result =
619 (std::string*)GILCallO(method, self, ctxt, sSTLStringScope).data;
620 if (!result) {
621 Py_INCREF(PyStrings::gEmptyString);
623 }
624 if (PyErr_Occurred()) {
625 delete result;
626 return nullptr;
627 }
628
629 PyObject* pyresult =
630 PyUnicode_FromStringAndSize(result->c_str(), result->size());
631 delete result; // interop::CallO allocates and constructs a string, so it must
632 // be properly destroyed
633
634 return pyresult;
635}
636
637//----------------------------------------------------------------------------
638PyObject* cpyrt::STLWStringExecutor::Execute(interop::TCppMethod_t method,
640 CallContext* ctxt) {
641 // execute <method> with argument <self, ctxt>, construct python string return
642 // value
643 static interop::TCppScope_t sSTLWStringScope =
644 interop::GetFullScope("std::wstring");
645 std::wstring* result =
646 (std::wstring*)GILCallO(method, self, ctxt, sSTLWStringScope).data;
647 if (!result) {
648 wchar_t w = L'\0';
649 return PyUnicode_FromWideChar(&w, 0);
650 }
651
652 PyObject* pyresult = PyUnicode_FromWideChar(result->c_str(), result->size());
653 delete result; // interop::CallO allocates and constructs a string, so it must
654 // be properly destroyed
655
656 return pyresult;
657}
658
659//----------------------------------------------------------------------------
660PyObject* cpyrt::InstancePtrExecutor::Execute(interop::TCppMethod_t method,
662 CallContext* ctxt) {
663 // execute <method> with argument <self, ctxt>, construct python proxy object
664 // return value
665 return BindCppObject((void*)GILCallR(method, self, ctxt), fClass);
666}
667
668//----------------------------------------------------------------------------
669cpyrt::InstanceExecutor::InstanceExecutor(interop::TCppScope_t klass)
670 : fClass(klass), fFlags(CPPInstance::kIsValue | CPPInstance::kIsOwner) {
671 /* empty */
672}
673
674//----------------------------------------------------------------------------
675PyObject* cpyrt::InstanceExecutor::Execute(interop::TCppMethod_t method,
677 CallContext* ctxt) {
678 // execution will bring a temporary in existence
679 interop::TCppObject_t value = GILCallO(method, self, ctxt, fClass);
680
681 if (!value) {
682 if (!PyErr_Occurred()) // callee may have set a python error itself
683 PyErr_Format(PyExc_ValueError,
684 "cannot allocate the temporary returned by '%s': the size "
685 "of its return type is unknown",
686 interop::GetMethodSignature(method, true).c_str());
687 return nullptr;
688 }
689
690 // the result can then be bound
692 if (!pyobj)
693 return nullptr;
694
695 // python ref counting will now control this object's life span; it will be
696 // deleted b/c it is marked as a by-value object owned by python (from fFlags)
697 return pyobj;
698}
699
700//----------------------------------------------------------------------------
701cpyrt::IteratorExecutor::IteratorExecutor(interop::TCppScope_t klass)
702 : InstanceExecutor(klass) {
704 CPPInstance::kNoWrapConv; // adds to flags from base class
705}
706
707//----------------------------------------------------------------------------
708PyObject* cpyrt::InstanceRefExecutor::Execute(interop::TCppMethod_t method,
710 CallContext* ctxt) {
711 // executor binds the result to the left-hand side, overwriting if an old
712 // object
713 PyObject* result = BindCppObject((void*)GILCallR(method, self, ctxt), fClass);
714 if (!result || !fAssignable)
715 return result;
716 else {
717 // this generic code is quite slow compared to its C++ equivalent ...
718 PyObject* assign = PyObject_GetAttr(result, PyStrings::gAssign);
719 if (!assign) {
720 PyErr_Clear();
721 PyObject* descr = PyObject_Str(result);
722 if (descr && PyUnicode_CheckExact(descr)) {
723 PyErr_Format(PyExc_TypeError, "cannot assign to return object (%s)",
724 PyUnicode_AsUTF8(descr));
725 } else {
726 PyErr_SetString(PyExc_TypeError, "cannot assign to result");
727 }
728 Py_XDECREF(descr);
729 Py_DECREF(result);
730 Py_DECREF(fAssignable);
731 fAssignable = nullptr;
732 return nullptr;
733 }
734
735 PyObject* res2 =
736 PyObject_CallFunction(assign, const_cast<char*>("O"), fAssignable);
737
738 Py_DECREF(assign);
739 Py_DECREF(result);
740 Py_DECREF(fAssignable);
741 fAssignable = nullptr;
742
743 if (res2) {
744 Py_DECREF(res2); // typically, *this from operator=()
746 }
747
748 return nullptr;
749 }
750}
751
752//----------------------------------------------------------------------------
754 PyObject* pystr = PyObject_Str(pyobj);
755 if (pystr) {
756 PyErr_Format(PyExc_TypeError, "C++ object expected, got %s",
757 PyUnicode_AsUTF8(pystr));
758 Py_DECREF(pystr);
759 } else
760 PyErr_SetString(PyExc_TypeError, "C++ object expected");
761 return nullptr;
762}
763
764PyObject* cpyrt::InstancePtrPtrExecutor::Execute(interop::TCppMethod_t method,
766 CallContext* ctxt) {
767 // execute <method> with argument <self, ctxt>, construct python C++ proxy
768 // object return ptr value
769 if (fAssignable && !CPPInstance_Check(fAssignable))
770 return SetInstanceCheckError(fAssignable);
771
772 void** result = (void**)GILCallR(method, self, ctxt);
773 if (!fAssignable)
774 return BindCppObject((void*)result, fClass,
776
777 CPPInstance* cppinst = (CPPInstance*)fAssignable;
778 *result = cppinst->GetObject();
779
780 Py_DECREF(fAssignable);
781 fAssignable = nullptr;
782
784}
785
786//----------------------------------------------------------------------------
787PyObject* cpyrt::InstancePtrRefExecutor::Execute(interop::TCppMethod_t method,
789 CallContext* ctxt) {
790 // execute <method> with argument <self, ctxt>, construct python C++ proxy
791 // object ignoring ref) return ptr value
792 if (fAssignable && !CPPInstance_Check(fAssignable))
793 return SetInstanceCheckError(fAssignable);
794
795 void** result = (void**)GILCallR(method, self, ctxt);
796 if (!fAssignable)
797 return BindCppObject(*result, fClass);
798
799 CPPInstance* cppinst = (CPPInstance*)fAssignable;
800 *result = cppinst->GetObject();
801
802 Py_DECREF(fAssignable);
803 fAssignable = nullptr;
804
806}
807
808//----------------------------------------------------------------------------
809PyObject* cpyrt::InstanceArrayExecutor::Execute(interop::TCppMethod_t method,
811 CallContext* ctxt) {
812 // execute <method> with argument <self, ctxt>, construct TupleOfInstances
813 // from return value
814 return BindCppObjectArray((void*)GILCallR(method, self, ctxt), fClass,
815 {fSize});
816}
817
818//----------------------------------------------------------------------------
819PyObject* cpyrt::ConstructorExecutor::Execute(interop::TCppMethod_t method,
821 CallContext* ctxt) {
822 // package return address in PyObject* for caller to handle appropriately (see
823 // CPPConstructor for the actual build of the PyObject)
824 return (PyObject*)GILCallConstructor(method, interop::TCppScope_t(klass.data),
825 ctxt)
826 .data;
827}
828
829//----------------------------------------------------------------------------
830PyObject* cpyrt::PyObjectExecutor::Execute(interop::TCppMethod_t method,
832 CallContext* ctxt) {
833 // execute <method> with argument <self, ctxt>, return python object
834 return (PyObject*)GILCallR(method, self, ctxt);
835}
836
837//----------------------------------------------------------------------------
838PyObject* cpyrt::FunctionPointerExecutor::Execute(interop::TCppMethod_t method,
840 CallContext* ctxt) {
841 // execute <method> with argument <self, ctxt>, return std::function from func
842 // ptr
843
844 // A function pointer in clang is represented by a Type, not a FunctionDecl
845 // and it's not possible to get the latter from the former: the backend will
846 // need to support both. Since that is far in the future, we'll use a
847 // std::function instead.
848 void* address = (void*)GILCallR(method, self, ctxt);
849 if (address)
851
852 // There's currently now way to return a typed function nullptr, but given
853 // that this is a return value (thus can not be set) and overloading function
854 // based on function pointer return type is likely uncommon ...
855 Py_INCREF(gNullPtrObject);
856 return gNullPtrObject;
857}
858
859//- factories ----------------------------------------------------------------
860cpyrt::Executor* cpyrt::CreateExecutor(const std::string& fullType,
861 cdims_t dims) {
862 // The matching of the fulltype to an executor factory goes through up to 4
863 // levels:
864 // 1) full, qualified match
865 // 2) drop '&' as by ref/full type is often pretty much the same python-wise
866 // 3) C++ classes, either by ref/ptr or by value
867 // 4) additional special case for enums
868 //
869 // If all fails, void is used, which will cause the return type to be ignored
870 // on use
871
872 if (fullType.empty())
873 return nullptr;
874
875 // an exactly matching executor is best
876 ExecFactories_t::iterator h = gExecFactories.find(fullType);
877 if (h != gExecFactories.end())
878 return (h->second)(dims);
879
880 // resolve typedefs etc.
881 const std::string resolvedType = interop::ResolveName(fullType);
882
883 // a full, qualified matching executor is preferred
884 if (resolvedType != fullType) {
885 h = gExecFactories.find(resolvedType);
886 if (h != gExecFactories.end())
887 return (h->second)(dims);
888 }
889
890 //-- nothing? ok, collect information about the type and possible
891 // qualifiers/decorators
892 bool isConst = strncmp(resolvedType.c_str(), "const", 5) == 0;
893 const std::string& cpd = TypeManip::compound(resolvedType);
894 std::string realType = TypeManip::clean_type(resolvedType, false);
895
896 // accept unqualified type (as python does not know about qualifiers)
897 h = gExecFactories.find(realType + cpd);
898 if (h != gExecFactories.end())
899 return (h->second)(dims);
900
901 // drop const, as that is mostly meaningless to python (with the exception
902 // of c-strings, but those are specialized in the converter map)
903 if (isConst) {
904 realType = TypeManip::remove_const(realType);
905 h = gExecFactories.find(realType + cpd);
906 if (h != gExecFactories.end())
907 return (h->second)(dims);
908 }
909
910 // simple array types
911 if (!cpd.empty() && (std::string::size_type)std::count(cpd.begin(), cpd.end(),
912 '*') == cpd.size()) {
913 h = gExecFactories.find(realType + " ptr");
914 if (h != gExecFactories.end())
915 return (h->second)((!dims || dims.ndim() < (dim_t)cpd.size())
916 ? dims_t(cpd.size())
917 : dims);
918 }
919
920 //-- still nothing? try pointer instead of array (for builtins)
921 if (cpd == "[]") {
922 h = gExecFactories.find(realType + "*");
923 if (h != gExecFactories.end())
924 return (h->second)(dims);
925 }
926
927 // C++ classes and special cases
928 Executor* result = 0;
929 if (interop::TCppScope_t klass = interop::GetFullScope(realType)) {
930 if (Utility::IsSTLIterator(realType) ||
931 gIteratorTypes.find(fullType) != gIteratorTypes.end()) {
932 if (cpd == "")
933 return new IteratorExecutor(klass);
934 }
935
936 if (cpd == "")
937 result = new InstanceExecutor(klass);
938 else if (cpd == "&")
939 result = new InstanceRefExecutor(klass);
940 else if (cpd == "**" || cpd == "*[]" || cpd == "&*")
941 result = new InstancePtrPtrExecutor(klass);
942 else if (cpd == "*&")
943 result = new InstancePtrRefExecutor(klass);
944 else if (cpd == "[]") {
945 Py_ssize_t asize = TypeManip::array_size(resolvedType);
946 if (0 < asize)
947 result = new InstanceArrayExecutor(klass, asize);
948 else
949 result = new InstancePtrRefExecutor(klass);
950 } else
951 result = new InstancePtrExecutor(klass);
952 } else if (resolvedType.find("(*)") != std::string::npos ||
953 (resolvedType.find("::*)") != std::string::npos)) {
954 // this is a function pointer
955 // TODO: find better way of finding the type
956 auto pos1 = resolvedType.find('(');
957 auto pos2 = resolvedType.find("*)");
958 auto pos3 = resolvedType.rfind(')');
959 result = new FunctionPointerExecutor(
960 resolvedType.substr(0, pos1),
961 resolvedType.substr(pos2 + 2, pos3 - pos2 - 1));
962 } else {
963 // unknown: void* may work ("user knows best"), void will fail on use of
964 // return value
965 h = (cpd == "") ? gExecFactories.find("void")
966 : gExecFactories.find("void ptr");
967 }
968
969 if (!result && h != gExecFactories.end())
970 // executor factory available, use it to create executor
971 result = (h->second)(dims);
972
973 return result; // may still be null
974}
975
977 // The matching of the fulltype to an executor factory goes through up to 4
978 // levels:
979 // 1) full, qualified match
980 // 2) drop '&' as by ref/full type is often pretty much the same python-wise
981 // 3) C++ classes, either by ref/ptr or by value
982 // 4) additional special case for enums
983 //
984 // If all fails, void is used, which will cause the return type to be ignored
985 // on use
986
987 // an exactly matching executor is best
988 std::string fullType = interop::GetTypeAsString(type);
989 if (fullType.size() >= 2 &&
990 fullType.compare(fullType.size() - 2, 2, " &") == 0)
991 fullType = fullType.substr(0, fullType.size() - 2) + "&";
992
993 ExecFactories_t::iterator h = gExecFactories.find(fullType);
994 if (h != gExecFactories.end())
995 return (h->second)(dims);
996
997 // resolve typedefs etc.
999 {
1000 // if resolvedType is a reference to enum
1001 // then it should be reduced to reference
1002 // to the underlying interger
1003 resolvedType = interop::ResolveEnumReferenceType(resolvedType);
1004 // similarly for pointers
1005 resolvedType = interop::ResolveEnumPointerType(resolvedType);
1006 }
1007 // FIXME: avoid string comparisons and parsing
1008 std::string resolvedTypeStr = interop::GetTypeAsString(resolvedType);
1009 if (interop::IsFunctionPointerType(resolvedType)) {
1010 resolvedTypeStr.erase(
1011 std::remove(resolvedTypeStr.begin(), resolvedTypeStr.end(), ' '),
1012 resolvedTypeStr.end());
1013 if (resolvedTypeStr.rfind("(void)") != std::string::npos)
1014 resolvedTypeStr =
1015 resolvedTypeStr.substr(0, resolvedTypeStr.size() - 6) + "()";
1016 }
1017
1018 // a full, qualified matching executor is preferred
1019 if (resolvedTypeStr != fullType) {
1020 h = gExecFactories.find(resolvedTypeStr);
1021 if (h != gExecFactories.end())
1022 return (h->second)(dims);
1023 }
1024
1025 //-- nothing? ok, collect information about the type and possible
1026 // qualifiers/decorators
1027 bool isConst = strncmp(resolvedTypeStr.c_str(), "const", 5) == 0;
1028 const std::string& cpd = TypeManip::compound(resolvedTypeStr);
1030 ? resolvedType
1031 : interop::GetRealType(resolvedType);
1032 std::string realTypeStr = interop::IsFunctionPointerType(resolvedType)
1033 ? resolvedTypeStr
1034 : interop::GetTypeAsString(realType);
1035 const std::string compounded = cpd.empty() ? realTypeStr : realTypeStr + cpd;
1036
1037 // accept unqualified type (as python does not know about qualifiers)
1038 h = gExecFactories.find(compounded);
1039 if (h != gExecFactories.end())
1040 return (h->second)(dims);
1041
1042 // drop const, as that is mostly meaningless to python (with the exception
1043 // of c-strings, but those are specialized in the converter map)
1044 if (isConst) {
1045 realTypeStr = TypeManip::remove_const(realTypeStr);
1046 h = gExecFactories.find(compounded);
1047 if (h != gExecFactories.end())
1048 return (h->second)(dims);
1049 }
1050
1051 // simple array types
1052 if (!cpd.empty() && (std::string::size_type)std::count(cpd.begin(), cpd.end(),
1053 '*') == cpd.size()) {
1054 h = gExecFactories.find(realTypeStr + " ptr");
1055 if (h != gExecFactories.end())
1056 return (h->second)((!dims || dims.ndim() < (dim_t)cpd.size())
1057 ? dims_t(cpd.size())
1058 : dims);
1059 }
1060
1061 //-- still nothing? try pointer instead of array (for builtins)
1062 if (cpd == "[]") {
1063 h = gExecFactories.find(realTypeStr + "*");
1064 if (h != gExecFactories.end())
1065 return (h->second)(dims);
1066 }
1067
1068 // C++ classes and special cases
1069 Executor* result = 0;
1070 if (interop::IsClassType(realType)) {
1072 if (resolvedTypeStr.find("iterator") != std::string::npos ||
1073 gIteratorTypes.find(fullType) != gIteratorTypes.end()) {
1074 if (cpd == "")
1075 return new IteratorExecutor(klass);
1076 }
1077
1078 if (cpd == "")
1079 result = new InstanceExecutor(klass);
1080 else if (cpd == "&")
1081 result = new InstanceRefExecutor(klass);
1082 else if (cpd == "**" || cpd == "*[]" || cpd == "&*")
1083 result = new InstancePtrPtrExecutor(klass);
1084 else if (cpd == "*&")
1085 result = new InstancePtrRefExecutor(klass);
1086 else if (cpd == "[]") {
1087 Py_ssize_t asize = TypeManip::array_size(resolvedTypeStr);
1088 if (0 < asize)
1089 result = new InstanceArrayExecutor(klass, asize);
1090 else
1091 result = new InstancePtrRefExecutor(klass);
1092 } else
1093 result = new InstancePtrExecutor(klass);
1094 } else if (realTypeStr.find("(*)") != std::string::npos ||
1095 (realTypeStr.find("::*)") != std::string::npos)) {
1096 // this is a function pointer
1097 // TODO: find better way of finding the type
1098 auto pos1 = realTypeStr.find('(');
1099 auto pos2 = realTypeStr.find("*)");
1100 auto pos3 = realTypeStr.rfind(')');
1101 result = new FunctionPointerExecutor(
1102 realTypeStr.substr(0, pos1),
1103 realTypeStr.substr(pos2 + 2, pos3 - pos2 - 1));
1104 } else {
1105 // unknown: void* may work ("user knows best"), void will fail on use of
1106 // return value
1107 h = (cpd == "") ? gExecFactories.find("void")
1108 : gExecFactories.find("void ptr");
1109 }
1110
1111 if (!result && h != gExecFactories.end())
1112 // executor factory available, use it to create executor
1113 result = (h->second)(dims);
1114
1115 return result; // may still be null
1116}
1117
1118//----------------------------------------------------------------------------
1121 if (p && p->HasState())
1122 delete p; // state-less executors are always shared
1123}
1124
1125//----------------------------------------------------------------------------
1127bool cpyrt::RegisterExecutor(const std::string& name, ef_t fac) {
1128 // register a custom executor
1129 auto f = gExecFactories.find(name);
1130 if (f != gExecFactories.end())
1131 return false;
1132
1133 gExecFactories[name] = fac;
1134 return true;
1135}
1136
1137//----------------------------------------------------------------------------
1139bool cpyrt::RegisterExecutorAlias(const std::string& name,
1140 const std::string& target) {
1141 // register a custom executor that is a reference to an existing converter
1142 auto f = gExecFactories.find(name);
1143 if (f != gExecFactories.end())
1144 return false;
1145
1146 auto t = gExecFactories.find(target);
1147 if (t == gExecFactories.end())
1148 return false;
1149
1150 gExecFactories[name] = t->second;
1151 return true;
1152}
1153
1154//----------------------------------------------------------------------------
1156bool cpyrt::UnregisterExecutor(const std::string& name) {
1157 // remove a custom executor
1158 auto f = gExecFactories.find(name);
1159 if (f != gExecFactories.end()) {
1160 gExecFactories.erase(f);
1161 return true;
1162 }
1163 return false;
1164}
1165
1166//----------------------------------------------------------------------------
1169 CallContext* ctxt) {
1170 return GILCallR(meth, obj, ctxt);
1171}
1172
1173//----------------------------------------------------------------------------
1174namespace {
1175
1176using namespace cppjit::cpyrt;
1177
1178#define WSTRING1 "std::basic_string<wchar_t>"
1179#define WSTRING2 \
1180 "std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_" \
1181 "t>>"
1182
1183//-- aliasing special case: C complex (is binary compatible with C++
1184// std::complex)
1185#ifndef _WIN32
1186#define CCOMPLEX_D "_Complex double"
1187#define CCOMPLEX_F "_Complex float"
1188#else
1189#define CCOMPLEX_D "_C_double_complex"
1190#define CCOMPLEX_F "_C_float_complex"
1191#endif
1192
1193struct InitExecFactories_t {
1194public:
1195 InitExecFactories_t() {
1196 // load all executor factories in the global map 'gExecFactories'
1198
1199 // factories for built-ins
1200 gf["bool"] = (ef_t) + [](cdims_t) {
1201 static BoolExecutor e{};
1202 return &e;
1203 };
1204 gf["bool&"] = (ef_t) + [](cdims_t) { return new BoolRefExecutor{}; };
1205 gf["const bool&"] = (ef_t) + [](cdims_t) {
1206 static BoolConstRefExecutor e{};
1207 return &e;
1208 };
1209 gf["char"] = (ef_t) + [](cdims_t) {
1210 static CharExecutor e{};
1211 return &e;
1212 };
1213 gf["signed char"] = gf["char"];
1214 gf["unsigned char"] = (ef_t) + [](cdims_t) {
1215 static UCharExecutor e{};
1216 return &e;
1217 };
1218 gf["char&"] = (ef_t) + [](cdims_t) { return new CharRefExecutor{}; };
1219 gf["signed char&"] = gf["char&"];
1220 gf["unsigned char&"] =
1221 (ef_t) + [](cdims_t) { return new UCharRefExecutor{}; };
1222 gf["const char&"] = (ef_t) + [](cdims_t) {
1223 static CharConstRefExecutor e{};
1224 return &e;
1225 };
1226 gf["const signed char&"] = gf["const char&"];
1227 gf["const unsigned char&"] = (ef_t) + [](cdims_t) {
1228 static UCharConstRefExecutor e{};
1229 return &e;
1230 };
1231 gf["wchar_t"] = (ef_t) + [](cdims_t) {
1232 static WCharExecutor e{};
1233 return &e;
1234 };
1235 gf["char16_t"] = (ef_t) + [](cdims_t) {
1236 static Char16Executor e{};
1237 return &e;
1238 };
1239 gf["char32_t"] = (ef_t) + [](cdims_t) {
1240 static Char32Executor e{};
1241 return &e;
1242 };
1243 gf["int8_t"] = (ef_t) + [](cdims_t) {
1244 static Int8Executor e{};
1245 return &e;
1246 };
1247 gf["int8_t&"] = (ef_t) + [](cdims_t) { return new Int8RefExecutor{}; };
1248 gf["const int8_t&"] = (ef_t) + [](cdims_t) {
1249 static Int8ConstRefExecutor e{};
1250 return &e;
1251 };
1252 gf["uint8_t"] = (ef_t) + [](cdims_t) {
1253 static UInt8Executor e{};
1254 return &e;
1255 };
1256 gf["uint8_t&"] = (ef_t) + [](cdims_t) { return new UInt8RefExecutor{}; };
1257 gf["const uint8_t&"] = (ef_t) + [](cdims_t) {
1258 static UInt8ConstRefExecutor e{};
1259 return &e;
1260 };
1261 gf["short"] = (ef_t) + [](cdims_t) {
1262 static ShortExecutor e{};
1263 return &e;
1264 };
1265 gf["short&"] = (ef_t) + [](cdims_t) { return new ShortRefExecutor{}; };
1266 gf["int"] = (ef_t) + [](cdims_t) {
1267 static IntExecutor e{};
1268 return &e;
1269 };
1270 gf["int&"] = (ef_t) + [](cdims_t) { return new IntRefExecutor{}; };
1271 gf["unsigned short"] = gf["int"];
1272 gf["unsigned short&"] =
1273 (ef_t) + [](cdims_t) { return new UShortRefExecutor{}; };
1274 gf["unsigned long"] = (ef_t) + [](cdims_t) {
1275 static ULongExecutor e{};
1276 return &e;
1277 };
1278 gf["unsigned long&"] =
1279 (ef_t) + [](cdims_t) { return new ULongRefExecutor{}; };
1280 gf["unsigned int"] = gf["unsigned long"];
1281 gf["unsigned int&"] =
1282 (ef_t) + [](cdims_t) { return new UIntRefExecutor{}; };
1283 gf["long"] = (ef_t) + [](cdims_t) {
1284 static LongExecutor e{};
1285 return &e;
1286 };
1287 gf["long&"] = (ef_t) + [](cdims_t) { return new LongRefExecutor{}; };
1288 gf["unsigned long"] = (ef_t) + [](cdims_t) {
1289 static ULongExecutor e{};
1290 return &e;
1291 };
1292 gf["unsigned long&"] =
1293 (ef_t) + [](cdims_t) { return new ULongRefExecutor{}; };
1294 gf["long long"] = (ef_t) + [](cdims_t) {
1295 static LongLongExecutor e{};
1296 return &e;
1297 };
1298 gf["long long&"] =
1299 (ef_t) + [](cdims_t) { return new LongLongRefExecutor{}; };
1300 gf["unsigned long long"] = (ef_t) + [](cdims_t) {
1301 static ULongLongExecutor e{};
1302 return &e;
1303 };
1304 gf["unsigned long long&"] =
1305 (ef_t) + [](cdims_t) { return new ULongLongRefExecutor{}; };
1306
1307 gf["float"] = (ef_t) + [](cdims_t) {
1308 static FloatExecutor e{};
1309 return &e;
1310 };
1311 gf["float&"] = (ef_t) + [](cdims_t) { return new FloatRefExecutor{}; };
1312 gf["double"] = (ef_t) + [](cdims_t) {
1313 static DoubleExecutor e{};
1314 return &e;
1315 };
1316 gf["double&"] = (ef_t) + [](cdims_t) { return new DoubleRefExecutor{}; };
1317 gf["long double"] = (ef_t) + [](cdims_t) {
1318 static LongDoubleExecutor e{};
1319 return &e;
1320 }; // TODO: lost precision
1321 gf["long double&"] =
1322 (ef_t) + [](cdims_t) { return new LongDoubleRefExecutor{}; };
1323 gf["std::complex<double>"] = (ef_t) + [](cdims_t) {
1324 static ComplexDExecutor e{};
1325 return &e;
1326 };
1327 gf["std::complex<double>&"] =
1328 (ef_t) + [](cdims_t) { return new ComplexDRefExecutor{}; };
1329 gf["void"] = (ef_t) + [](cdims_t) {
1330 static VoidExecutor e{};
1331 return &e;
1332 };
1333
1334 // pointer/array factories
1335 gf["void ptr"] =
1336 (ef_t) + [](cdims_t d) { return new VoidArrayExecutor{d}; };
1337 gf["bool ptr"] =
1338 (ef_t) + [](cdims_t d) { return new BoolArrayExecutor{d}; };
1339 gf["unsigned char ptr"] =
1340 (ef_t) + [](cdims_t d) { return new UCharArrayExecutor{d}; };
1341 gf["const unsigned char ptr"] = gf["unsigned char ptr"];
1342 gf["std::byte ptr"] =
1343 (ef_t) + [](cdims_t d) { return new ByteArrayExecutor{d}; };
1344 gf["const std::byte ptr"] = gf["std::byte ptr"];
1345 gf["int8_t ptr"] =
1346 (ef_t) + [](cdims_t d) { return new Int8ArrayExecutor{d}; };
1347 gf["uint8_t ptr"] =
1348 (ef_t) + [](cdims_t d) { return new UInt8ArrayExecutor{d}; };
1349 gf["short ptr"] =
1350 (ef_t) + [](cdims_t d) { return new ShortArrayExecutor{d}; };
1351 gf["unsigned short ptr"] =
1352 (ef_t) + [](cdims_t d) { return new UShortArrayExecutor{d}; };
1353 gf["int ptr"] = (ef_t) + [](cdims_t d) { return new IntArrayExecutor{d}; };
1354 gf["unsigned int ptr"] =
1355 (ef_t) + [](cdims_t d) { return new UIntArrayExecutor{d}; };
1356 gf["long ptr"] =
1357 (ef_t) + [](cdims_t d) { return new LongArrayExecutor{d}; };
1358 gf["unsigned long ptr"] =
1359 (ef_t) + [](cdims_t d) { return new ULongArrayExecutor{d}; };
1360 gf["long long ptr"] =
1361 (ef_t) + [](cdims_t d) { return new LLongArrayExecutor{d}; };
1362 gf["unsigned long long ptr"] =
1363 (ef_t) + [](cdims_t d) { return new ULLongArrayExecutor{d}; };
1364 gf["float ptr"] =
1365 (ef_t) + [](cdims_t d) { return new FloatArrayExecutor{d}; };
1366 gf["double ptr"] =
1367 (ef_t) + [](cdims_t d) { return new DoubleArrayExecutor{d}; };
1368 gf["long double ptr"] =
1369 (ef_t) + [](cdims_t d) { return new LDoubleArrayExecutor{d}; };
1370 gf["std::complex<float> ptr"] =
1371 (ef_t) + [](cdims_t d) { return new ComplexFArrayExecutor{d}; };
1372 gf["std::complex<double> ptr"] =
1373 (ef_t) + [](cdims_t d) { return new ComplexDArrayExecutor{d}; };
1374 gf["std::complex<int> ptr"] =
1375 (ef_t) + [](cdims_t d) { return new ComplexIArrayExecutor{d}; };
1376 gf["std::complex<long> ptr"] =
1377 (ef_t) + [](cdims_t d) { return new ComplexLArrayExecutor{d}; };
1378
1379 // aliases
1380 gf["internal_enum_type_t"] = gf["int"];
1381 gf["internal_enum_type_t&"] = gf["int&"];
1382 gf["internal_enum_type_t ptr"] = gf["int ptr"];
1383 gf["std::byte"] = gf["uint8_t"];
1384 gf["std::byte&"] = gf["uint8_t&"];
1385 gf["const std::byte&"] = gf["const uint8_t&"];
1386 gf["const byte&"] = gf["const uint8_t&"];
1387 gf["std::int8_t"] = gf["int8_t"];
1388 gf["std::int8_t&"] = gf["int8_t&"];
1389 gf["const std::int8_t&"] = gf["const int8_t&"];
1390 gf["std::int8_t ptr"] = gf["int8_t ptr"];
1391 gf["std::uint8_t"] = gf["uint8_t"];
1392 gf["std::uint8_t&"] = gf["uint8_t&"];
1393 gf["const std::uint8_t&"] = gf["const uint8_t&"];
1394 gf["std::uint8_t ptr"] = gf["uint8_t ptr"];
1395#ifdef _WIN32
1396 gf["__int64"] = gf["long long"];
1397 gf["__int64&"] = gf["long long&"];
1398 gf["__int64 ptr"] = gf["long long ptr"];
1399 gf["unsigned __int64"] = gf["unsigned long long"];
1400 gf["unsigned __int64&"] = gf["unsigned long long&"];
1401 gf["unsigned __int64 ptr"] = gf["unsigned long long ptr"];
1402#endif
1403 gf[CCOMPLEX_D] = gf["std::complex<double>"];
1404 gf[CCOMPLEX_D "&"] = gf["std::complex<double>&"];
1405 gf[CCOMPLEX_F " ptr"] = gf["std::complex<float> ptr"];
1406 gf[CCOMPLEX_D " ptr"] = gf["std::complex<double> ptr"];
1407
1408 // We always need these executors when cppjit is based on an unpatched
1409 // ROOT, because the "long long" types are always converted to Long64_t
1410 // and ULong64_t already at the ROOT Meta level.
1411 // See
1412 // https://github.com/root-project/root/issues/15872#issuecomment-2174092763
1413 gf["Long64_t"] = gf["long long"];
1414 gf["Long64_t&"] = gf["long long&"];
1415 gf["Long64_t ptr"] = gf["long long ptr"];
1416 gf["ULong64_t"] = gf["unsigned long long"];
1417 gf["ULong64_t&"] = gf["unsigned long long&"];
1418 gf["ULong64_t ptr"] = gf["unsigned long long ptr"];
1419
1420 // factories for special cases
1421 gf["const char*"] = (ef_t) + [](cdims_t) {
1422 static CStringExecutor e{};
1423 return &e;
1424 };
1425 gf["char*"] = gf["const char*"];
1426 gf["const char*&"] = (ef_t) + [](cdims_t) {
1427 static CStringRefExecutor e{};
1428 return &e;
1429 };
1430 gf["char*&"] = gf["const char*&"];
1431 gf["const signed char*"] = gf["const char*"];
1432 // gf["signed char*"] = gf["char*"];
1433 gf["signed char ptr"] =
1434 (ef_t) + [](cdims_t d) { return new SCharArrayExecutor{d}; };
1435 gf["wchar_t*"] = (ef_t) + [](cdims_t) {
1436 static WCStringExecutor e{};
1437 return &e;
1438 };
1439 gf["char16_t*"] = (ef_t) + [](cdims_t) {
1440 static CString16Executor e{};
1441 return &e;
1442 };
1443 gf["char32_t*"] = (ef_t) + [](cdims_t) {
1444 static CString32Executor e{};
1445 return &e;
1446 };
1447 gf["std::basic_string<char>"] = (ef_t) + [](cdims_t) {
1448 static STLStringExecutor e{};
1449 return &e;
1450 };
1451 gf["std::basic_string<char>&"] =
1452 (ef_t) + [](cdims_t) { return new STLStringRefExecutor{}; };
1453 gf["std::basic_string<wchar_t>"] = (ef_t) + [](cdims_t) {
1454 static STLWStringExecutor e{};
1455 return &e;
1456 };
1457 gf[WSTRING1] = gf["std::basic_string<wchar_t>"];
1458 gf[WSTRING2] = gf["std::basic_string<wchar_t>"];
1459 gf["__init__"] = (ef_t) + [](cdims_t) {
1460 static ConstructorExecutor e{};
1461 return &e;
1462 };
1463 gf["PyObject*"] = (ef_t) + [](cdims_t) {
1464 static PyObjectExecutor e{};
1465 return &e;
1466 };
1467 gf["_object*"] = gf["PyObject*"];
1468 gf["FILE*"] = gf["void ptr"];
1469 }
1470} initExecvFactories_;
1471
1472} // unnamed namespace
#define CCOMPLEX_D
#define CCOMPLEX_F
#define WSTRING1
#define WSTRING2
std::string fRetType
dims_t fShape
interop::TCppScope_t fClass
std::string fSignature
dim_t fSize
uint32_t fFlags
static interop::TCppObject_t GILCallConstructor(interop::TCppMethod_t method, interop::TCppScope_t klass, cpyrt::CallContext *ctxt)
static float GILCallF(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:79
static PyObject * PyComplex_FromComplex(const std::complex< T > &c)
static PY_LONG_LONG GILCallLL(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:78
static PyObject * SetInstanceCheckError(PyObject *pyobj)
static std::complex< T > PyComplex_AsComplex(PyObject *pycplx)
static interop::TCppObject_t GILCallO(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt, interop::TCppScope_t klass)
Definition Executors.cxx:85
static void GILCallV(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:72
static void * GILCallR(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:82
static short GILCallH(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:75
#define CPPJIT_IMPL_GILCALL(rtype, tcode)
Definition Executors.cxx:62
#define CPPJIT_COMPLEX_EXEC(code, type)
static double GILCallD(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:80
static long GILCallL(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:77
#define CPPJIT_IMPL_ARRAY_EXEC(name, type, suffix)
static PY_LONG_DOUBLE GILCallLD(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:81
static PyObject * cpyrt_PyBool_FromLong(long b)
static int GILCallI(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:76
static unsigned char GILCallB(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:73
static PyObject * cpyrt_PyText_FromULong(unsigned long uc)
#define CPPJIT_IMPL_REFEXEC(name, type, stype, F1, F2)
static char GILCallC(interop::TCppMethod_t method, interop::TCppObject_t self, cpyrt::CallContext *ctxt)
Definition Executors.cxx:74
static PyObject * cpyrt_PyText_FromLong(long cl)
_object PyObject
#define d(i)
Definition RSha256.hxx:102
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
#define c(i)
Definition RSha256.hxx:101
#define h(i)
Definition RSha256.hxx:106
#define e(i)
Definition RSha256.hxx:103
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t target
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void gc
char name[80]
Definition TGX11.cxx:142
#define CPYRT_EXPORT
Definition CommonDefs.h:25
virtual bool SetAssignable(PyObject *)
long double PY_LONG_DOUBLE
unsigned long long PY_ULONG_LONG
long long PY_LONG_LONG
#define Py_RETURN_NONE
Definition cpyrt.h:69
RooArgList L(Args_t &&... args)
Definition RooArgList.h:156
std::string remove_const(const std::string &cppname)
Definition TypeManip.cxx:80
std::string clean_type(const std::string &cppname, bool template_strip=true, bool const_strip=true)
Py_ssize_t array_size(const std::string &name)
std::string compound(const std::string &name)
bool IsSTLIterator(const std::string &classname)
Definition Utility.cxx:1422
PyObject * FuncPtr2StdFunction(const std::string &retType, const std::string &signature, void *address)
Definition Utility.cxx:1112
CPYRT_EXTERN bool RegisterExecutorAlias(const std::string &name, const std::string &target)
static ExecFactories_t gExecFactories
Definition Executors.cxx:26
PyObject * gNullPtrObject
PyObject * CreatePointerView(void *ptr, cdims_t shape=0)
PyObject * BindCppObject(interop::TCppObject_t object, interop::TCppScope_t klass, const unsigned flags=0)
PyObject * BindCppObjectArray(interop::TCppObject_t address, interop::TCppScope_t klass, cdims_t dims)
Py_ssize_t dim_t
Definition API.h:100
CPYRT_EXTERN Executor * CreateExecutor(const std::string &name, cdims_t=0)
bool ReleasesGIL(CallContext *ctxt)
Dimensions dims_t
Definition API.h:113
PyObject * BindCppObjectNoCast(interop::TCppObject_t object, interop::TCppScope_t klass, const unsigned flags=0)
CPYRT_EXPORT void DestroyExecutor(Executor *p)
unsigned long PyLongOrInt_AsULong(PyObject *pyobject)
Definition Utility.cxx:125
std::set< std::string > gIteratorTypes
bool CPPInstance_Check(T *object)
CPYRT_EXTERN bool UnregisterExecutor(const std::string &name)
PY_ULONG_LONG PyLongOrInt_AsULong64(PyObject *pyobject)
Definition Utility.cxx:152
std::unordered_map< std::string, ef_t > ExecFactories_t
Definition Executors.cxx:25
Executor *(* ef_t)(cdims_t)
Definition Executors.h:40
CPYRT_EXTERN void * CallVoidP(interop::TCppMethod_t, interop::TCppObject_t, CallContext *)
CPYRT_EXTERN bool RegisterExecutor(const std::string &name, ExecutorFactory_t)
Cpp::TypeRef TCppType_t
Definition API.h:42
TCppScope_t GetFullScope(const std::string &scope_name)
Cpp::ObjectRef TCppObject_t
Definition API.h:43
TCppType_t GetTypeFromScope(TCppScope_t klass)
std::string GetTypeAsString(TCppType_t type)
TCppType_t ResolveEnumPointerType(TCppType_t type)
bool IsClassType(TCppType_t type)
std::string ResolveName(const std::string &cppitem_name)
Cpp::FuncRef TCppMethod_t
Definition API.h:44
bool IsFunctionPointerType(TCppType_t type)
TCppObject_t CallO(TCppMethod_t method, TCppObject_t self, size_t nargs, void *args, TCppType_t result_type)
TCppType_t ResolveType(TCppType_t cppitem_name)
std::string GetMethodSignature(TCppMethod_t, bool show_formal_args, TCppIndex_t max_args=(TCppIndex_t) -1)
TCppObject_t CallConstructor(TCppMethod_t method, TCppScope_t klass, size_t nargs, void *args)
TCppScope_t GetScopeFromType(TCppType_t type)
TCppType_t GetRealType(TCppType_t type)
TCppType_t ResolveEnumReferenceType(TCppType_t type)
Cpp::DeclRef TCppScope_t
Definition API.h:41
Definition API.cxx:34
Parameter * GetArgs(size_t sz)
Definition CallContext.h:62