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
24#include "PyROOTPythonize.h"
25
26#include "RConfig.h"
27#include "TInterpreter.h"
28
29#include <sstream>
30
31// needed to properly resolve (dllimport) symbols on Windows
32namespace CPyCppyy {
33 namespace PyStrings {
35 }
36}
37
38////////////////////////////////////////////////////////////////////////////
39/// \brief Get size of C++ data-type
40/// \param[in] self Always null, since this is a module function.
41/// \param[in] args C++ data-type as Python string
42///
43/// This function returns the length of a C++ data-type in bytes
44/// as a Python integer.
46{
47 // Get name of data-type
48 PyObject *pydtype = PyTuple_GetItem(args, 0);
49 std::string dtype = CPyCppyy_PyText_AsString(pydtype);
50
51 // Call interpreter to get size of data-type using `sizeof`
52 size_t size = 0;
53 std::stringstream code;
54 code << "*((size_t*)" << std::showbase << (uintptr_t)&size << ") = (size_t)sizeof(" << dtype << ")";
55 gInterpreter->Calc(code.str().c_str());
56
57 // Return size of data-type as integer
58 PyObject *pysize = PyInt_FromLong(size);
59 return pysize;
60}
61
62////////////////////////////////////////////////////////////////////////////
63/// \brief Get pointer to the data of an object
64/// \param[in] self Always null, since this is a module function.
65/// \param[in] args[0] Python representation of the C++ object.
66/// \param[in] args[1] Data-type of the C++ object as Python string
67/// \param[in] args[2] Method to be called on the C++ object to get the data pointer as Python string
68///
69/// This function returns the pointer to the data of an object as an Python
70/// integer retrieved by the given method.
72{
73 // Get pointer of C++ object
74 PyObject *pyobj = PyTuple_GetItem(args, 0);
75 auto instance = (CPyCppyy::CPPInstance *)(pyobj);
76 auto cppobj = instance->GetObject();
77
78 // Get name of C++ object as string
79 PyObject *pycppname = PyTuple_GetItem(args, 1);
80 std::string cppname = CPyCppyy_PyText_AsString(pycppname);
81
82 // Get name of method to be called to get the data pointer
83 PyObject *pymethodname = PyTuple_GetItem(args, 2);
84 std::string methodname = CPyCppyy_PyText_AsString(pymethodname);
85
86 // Call interpreter to get pointer to data
87 uintptr_t pointer = 0;
88 std::stringstream code;
89 code << "*((intptr_t*)" << std::showbase << (uintptr_t)&pointer << ") = reinterpret_cast<uintptr_t>(reinterpret_cast<"
90 << cppname << "*>(" << std::showbase << (uintptr_t)cppobj << ")->" << methodname << "())";
91 gInterpreter->Calc(code.str().c_str());
92
93 // Return pointer as integer
94 PyObject *pypointer = PyLong_FromUnsignedLongLong(pointer);
95 return pypointer;
96}
97
98////////////////////////////////////////////////////////////////////////////
99/// \brief Get endianess of the system
100/// \param[in] self Always null, since this is a module function.
101/// \param[in] args Pointer to an empty Python tuple.
102/// \return Endianess as Python string
103///
104/// This function returns endianess of the system as a Python integer. The
105/// return value is either '<' or '>' for little or big endian, respectively.
106PyObject *PyROOT::GetEndianess(PyObject * /* self */, PyObject * /* args */)
107{
108#ifdef R__BYTESWAP
109 return CPyCppyy_PyText_FromString("<");
110#else
111 return CPyCppyy_PyText_FromString(">");
112#endif
113}
114
115using namespace CPyCppyy;
116
117// Helper to add base class methods to the derived class one
118static bool AddUsingToClass(PyObject *pyclass, const char *method)
119{
120 CPPOverload *derivedMethod = (CPPOverload *)PyObject_GetAttrString(pyclass, const_cast<char *>(method));
121 if (!CPPOverload_Check(derivedMethod)) {
122 Py_XDECREF(derivedMethod);
123 return false;
124 }
125
126 PyObject *mro = PyObject_GetAttr(pyclass, PyStrings::gMRO);
127 if (!mro || !PyTuple_Check(mro)) {
128 Py_XDECREF(mro);
129 Py_DECREF(derivedMethod);
130 return false;
131 }
132
133 CPPOverload *baseMethod = nullptr;
134 for (int i = 1; i < PyTuple_GET_SIZE(mro); ++i) {
135 baseMethod = (CPPOverload *)PyObject_GetAttrString(PyTuple_GET_ITEM(mro, i), const_cast<char *>(method));
136
137 if (!baseMethod) {
138 PyErr_Clear();
139 continue;
140 }
141
142 if (CPPOverload_Check(baseMethod))
143 break;
144
145 Py_DECREF(baseMethod);
146 baseMethod = nullptr;
147 }
148
149 Py_DECREF(mro);
150
151 if (!CPPOverload_Check(baseMethod)) {
152 Py_XDECREF(baseMethod);
153 Py_DECREF(derivedMethod);
154 return false;
155 }
156
157 for (PyCallable *pc : baseMethod->fMethodInfo->fMethods) {
158 derivedMethod->AdoptMethod(pc->Clone());
159 }
160
161 Py_DECREF(baseMethod);
162 Py_DECREF(derivedMethod);
163
164 return true;
165}
166
167////////////////////////////////////////////////////////////////////////////
168/// \brief Add base class overloads of a given method to a derived class
169/// \param[in] self Always null, since this is a module function.
170/// \param[in] args[0] Derived class.
171/// \param[in] args[1] Name of the method whose base class overloads to
172/// inject in the derived class.
173///
174/// This function adds base class overloads to a derived class for a given
175/// method. This covers the 'using' case, which is not supported by default
176/// by the bindings.
178{
179 // Get derived class to pythonize
180 PyObject *pyclass = PyTuple_GetItem(args, 0);
181
182 // Get method name where to add overloads
183 PyObject *pyname = PyTuple_GetItem(args, 1);
184 auto cppname = CPyCppyy_PyText_AsString(pyname);
185
186 AddUsingToClass(pyclass, cppname);
187
189}
#define CPyCppyy_PyText_AsString
Definition: CPyCppyy.h:97
#define Py_RETURN_NONE
Definition: CPyCppyy.h:289
#define CPyCppyy_PyText_FromString
Definition: CPyCppyy.h:102
PyInt_FromLong
Definition: Converters.cxx:876
#define R__EXTERN
Definition: DllImport.h:27
_object PyObject
Definition: PyMethodBase.h:42
static bool AddUsingToClass(PyObject *pyclass, const char *method)
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define gInterpreter
Definition: TInterpreter.h:562
#define pyname
Definition: TMCParticle.cxx:19
void AdoptMethod(PyCallable *pc)
MethodInfo_t * fMethodInfo
Definition: CPPOverload.h:68
Set of helper functions that are invoked from the pythonizors, on the Python side.
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)
Get size of C++ data-type.
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