Logo ROOT  
Reference Guide
PyzPythonHelpers.cxx
Go to the documentation of this file.
1// Author: Stefan Wunsch CERN 08/2018
2// Original PyROOT code by Wim Lavrijsen, LBL
3
4/*************************************************************************
5 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/**
13
14Set of helper functions that are invoked from the pythonizors, on the
15Python side. For that purpose, they are included in the interface of the
16PyROOT extension module.
17
18*/
19
20#include "CPyCppyy.h"
21#include "CPPInstance.h"
22#include "CPPOverload.h"
23#include "PyStrings.h"
24
25#include "PyROOTPythonize.h"
26
27#include "RConfig.h"
28#include "TInterpreter.h"
29
30#include <sstream>
31
32////////////////////////////////////////////////////////////////////////////
33/// \brief Get size of C++ data-type
34/// \param[in] self Always null, since this is a module function.
35/// \param[in] args C++ data-type as Python string
36///
37/// This function returns the length of a C++ data-type in bytes
38/// as a Python integer.
40{
41 // Get name of data-type
42 PyObject *pydtype = PyTuple_GetItem(args, 0);
43 std::string dtype = CPyCppyy_PyText_AsString(pydtype);
44
45 // Call interpreter to get size of data-type using `sizeof`
46 long size = 0;
47 std::stringstream code;
48 code << "*((long*)" << &size << ") = (long)sizeof(" << dtype << ")";
49 gInterpreter->Calc(code.str().c_str());
50
51 // Return size of data-type as integer
52 PyObject *pysize = PyInt_FromLong(size);
53 return pysize;
54}
55
56////////////////////////////////////////////////////////////////////////////
57/// \brief Get pointer to the data of an object
58/// \param[in] self Always null, since this is a module function.
59/// \param[in] args[0] Python representation of the C++ object.
60/// \param[in] args[1] Data-type of the C++ object as Python string
61/// \param[in] args[2] Method to be called on the C++ object to get the data pointer as Python string
62///
63/// This function returns the pointer to the data of an object as an Python
64/// integer retrieved by the given method.
66{
67 // Get pointer of C++ object
68 PyObject *pyobj = PyTuple_GetItem(args, 0);
69 auto instance = (CPyCppyy::CPPInstance *)(pyobj);
70 auto cppobj = instance->GetObject();
71
72 // Get name of C++ object as string
73 PyObject *pycppname = PyTuple_GetItem(args, 1);
74 std::string cppname = CPyCppyy_PyText_AsString(pycppname);
75
76 // Get name of method to be called to get the data pointer
77 PyObject *pymethodname = PyTuple_GetItem(args, 2);
78 std::string methodname = CPyCppyy_PyText_AsString(pymethodname);
79
80 // Call interpreter to get pointer to data
81 unsigned long long pointer = 0;
82 std::stringstream code;
83 code << "*((long*)" << &pointer << ") = reinterpret_cast<long>(reinterpret_cast<"
84 << cppname << "*>(" << cppobj << ")->" << methodname << "())";
85 gInterpreter->Calc(code.str().c_str());
86
87 // Return pointer as integer
88 PyObject *pypointer = PyLong_FromUnsignedLongLong(pointer);
89 return pypointer;
90}
91
92////////////////////////////////////////////////////////////////////////////
93/// \brief Get endianess of the system
94/// \param[in] self Always null, since this is a module function.
95/// \param[in] args Pointer to an empty Python tuple.
96/// \param[out] Endianess as Python string
97///
98/// This function returns endianess of the system as a Python integer. The
99/// return value is either '<' or '>' for little or big endian, respectively.
100PyObject *PyROOT::GetEndianess(PyObject * /* self */, PyObject * /* args */)
101{
102#ifdef R__BYTESWAP
103 return CPyCppyy_PyText_FromString("<");
104#else
105 return CPyCppyy_PyText_FromString(">");
106#endif
107}
108
109using namespace CPyCppyy;
110
111// Helper to add base class methods to the derived class one
112static bool AddUsingToClass(PyObject *pyclass, const char *method)
113{
114 CPPOverload *derivedMethod = (CPPOverload *)PyObject_GetAttrString(pyclass, const_cast<char *>(method));
115 if (!CPPOverload_Check(derivedMethod)) {
116 Py_XDECREF(derivedMethod);
117 return false;
118 }
119
120 PyObject *mro = PyObject_GetAttr(pyclass, PyStrings::gMRO);
121 if (!mro || !PyTuple_Check(mro)) {
122 Py_XDECREF(mro);
123 Py_DECREF(derivedMethod);
124 return false;
125 }
126
127 CPPOverload *baseMethod = nullptr;
128 for (int i = 1; i < PyTuple_GET_SIZE(mro); ++i) {
129 baseMethod = (CPPOverload *)PyObject_GetAttrString(PyTuple_GET_ITEM(mro, i), const_cast<char *>(method));
130
131 if (!baseMethod) {
132 PyErr_Clear();
133 continue;
134 }
135
136 if (CPPOverload_Check(baseMethod))
137 break;
138
139 Py_DECREF(baseMethod);
140 baseMethod = nullptr;
141 }
142
143 Py_DECREF(mro);
144
145 if (!CPPOverload_Check(baseMethod)) {
146 Py_XDECREF(baseMethod);
147 Py_DECREF(derivedMethod);
148 return false;
149 }
150
151 for (PyCallable *pc : baseMethod->fMethodInfo->fMethods) {
152 derivedMethod->AdoptMethod(pc->Clone());
153 }
154
155 Py_DECREF(baseMethod);
156 Py_DECREF(derivedMethod);
157
158 return true;
159}
160
161////////////////////////////////////////////////////////////////////////////
162/// \brief Add base class overloads of a given method to a derived class
163/// \param[in] self Always null, since this is a module function.
164/// \param[in] args[0] Derived class.
165/// \param[in] args[1] Name of the method whose base class overloads to
166/// inject in the derived class.
167///
168/// This function adds base class overloads to a derived class for a given
169/// method. This covers the 'using' case, which is not supported by default
170/// by the bindings.
172{
173 // Get derived class to pythonize
174 PyObject *pyclass = PyTuple_GetItem(args, 0);
175
176 // Get method name where to add overloads
177 PyObject *pyname = PyTuple_GetItem(args, 1);
178 auto cppname = CPyCppyy_PyText_AsString(pyname);
179
180 AddUsingToClass(pyclass, cppname);
181
183}
#define CPyCppyy_PyText_AsString
Definition: CPyCppyy.h:97
#define Py_RETURN_NONE
Definition: CPyCppyy.h:281
#define CPyCppyy_PyText_FromString
Definition: CPyCppyy.h:102
PyInt_FromLong
Definition: Converters.cxx:858
_object PyObject
Definition: PyMethodBase.h:41
static bool AddUsingToClass(PyObject *pyclass, const char *method)
#define gInterpreter
Definition: TInterpreter.h:556
#define pyname
Definition: TMCParticle.cxx:19
void AdoptMethod(PyCallable *pc)
MethodInfo_t * fMethodInfo
Definition: CPPOverload.h:68
bool CPPOverload_Check(T *object)
Definition: CPPOverload.h:79
PyObject * GetEndianess(PyObject *self, PyObject *args)
Get endianess of the system.
PyObject * GetDataPointer(PyObject *self, PyObject *args)
Get pointer to the data of an object.
PyObject * GetSizeOfType(PyObject *self, PyObject *args)
Set of helper functions that are invoked from the pythonizors, on the Python side.
PyObject * AddUsingToClass(PyObject *self, PyObject *args)
Add base class overloads of a given method to a derived class.
static Roo_reg_AGKInteg1D instance
static constexpr double pc
CPPOverload::Methods_t fMethods
Definition: CPPOverload.h:47