Logo ROOT  
Reference Guide
RVecPyz.cxx
Go to the documentation of this file.
1 // Author: Stefan Wunsch CERN 02/2019
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 #include "CPyCppyy.h"
13 #include "CPPInstance.h"
14 #include "ProxyWrappers.h"
15 #include "PyROOTPythonize.h"
16 #include "TInterpreter.h"
17 #include "PyzCppHelpers.hxx"
18 
19 #include <sstream>
20 
21 ////////////////////////////////////////////////////////////////////////////
22 /// \brief Adopt memory of a Python object with array interface using an RVec
23 /// \param[in] obj PyObject with array interface
24 ///
25 /// This function returns an RVec which adopts the memory of the given
26 /// PyObject. The RVec takes the data pointer and the size from the array
27 /// interface dictionary.
29 {
30  if (!obj) {
31  PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Invalid Python object.");
32  return NULL;
33  }
34 
35  // Get array interface of object
36  auto pyinterface = GetArrayInterface(obj);
37  if (pyinterface == NULL)
38  return NULL;
39 
40  // Get the data-pointer
41  const auto data = GetDataPointerFromArrayInterface(pyinterface);
42  if (data == 0)
43  return NULL;
44 
45  // Get the size of the contiguous memory
46  auto pyshape = PyDict_GetItemString(pyinterface, "shape");
47  if (!pyshape) {
48  PyErr_SetString(PyExc_RuntimeError, "Object not convertible: __array_interface__['shape'] does not exist.");
49  return NULL;
50  }
51  long size = 0;
52  for (int i = 0; i < PyTuple_Size(pyshape); i++) {
53  if (size == 0) size = 1;
54  size *= PyLong_AsLong(PyTuple_GetItem(pyshape, i));
55  }
56 
57  // Get the typestring and properties thereof
58  const auto typestr = GetTypestrFromArrayInterface(pyinterface);
59  if (typestr.compare("") == 0)
60  return NULL;
61  if (!CheckEndianessFromTypestr(typestr))
62  return NULL;
63 
64  const auto dtype = typestr.substr(1, typestr.size());
65  std::string cppdtype = GetCppTypeFromNumpyType(dtype);
66  if (cppdtype.compare("") == 0)
67  return NULL;
68 
69  // Construct an RVec of the correct data-type
70  const std::string klassname = "ROOT::VecOps::RVec<" + cppdtype + ">";
71  std::stringstream prefix;
72 #ifdef _MSC_VER
73  prefix << "0x";
74 #endif
75  auto address = (void*) gInterpreter->Calc("new " + klassname + "(reinterpret_cast<" + cppdtype + "*>(" + prefix.str() + data + ")," + size + ")");
76 
77  // Bind the object to a Python-side proxy
78  auto klass = (Cppyy::TCppType_t)Cppyy::GetScope(klassname);
79  auto pyobj = CPyCppyy::BindCppObject(address, klass);
80 
81  // Give Python the ownership of the underlying C++ object
82  ((CPyCppyy::CPPInstance*)pyobj)->PythonOwns();
83 
84  // Bind pyobject holding adopted memory to the RVec
85  if (PyObject_SetAttrString(pyobj, "__adopted__", obj)) {
86  PyErr_SetString(PyExc_RuntimeError, "Object not convertible: Failed to set Python object as attribute __adopted__.");
87  return NULL;
88  }
89 
90  // Clean-up and return
91  Py_DECREF(pyinterface);
92  return pyobj;
93 }
CPPInstance.h
PyObject
_object PyObject
Definition: PyMethodBase.h:42
GetTypestrFromArrayInterface
std::string GetTypestrFromArrayInterface(PyObject *obj)
Get type string from Numpy array interface and perform error handling.
Definition: PyzCppHelpers.cxx:110
PyROOTPythonize.h
gInterpreter
#define gInterpreter
Definition: TInterpreter.h:560
CPyCppyy::CPPInstance
Definition: CPPInstance.h:26
GetCppTypeFromNumpyType
std::string GetCppTypeFromNumpyType(const std::string &dtype)
Convert Numpy data-type string to the according C++ data-type string.
Definition: PyzCppHelpers.cxx:55
Cppyy::GetScope
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
Definition: clingwrapper.cxx:497
CPyCppyy::BindCppObject
PyObject * BindCppObject(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
Definition: ProxyWrappers.cxx:873
CheckEndianessFromTypestr
bool CheckEndianessFromTypestr(const std::string &typestr)
Check whether endianess in type string matches the endianess of ROOT.
Definition: PyzCppHelpers.cxx:142
ProxyWrappers.h
GetDataPointerFromArrayInterface
unsigned long long GetDataPointerFromArrayInterface(PyObject *obj)
Get data pointer from Numpy array interface and perform error handling.
Definition: PyzCppHelpers.cxx:96
GetArrayInterface
PyObject * GetArrayInterface(PyObject *obj)
Get Numpy array interface and perform error handling.
Definition: PyzCppHelpers.cxx:78
PyROOT::AsRVec
PyObject * AsRVec(PyObject *self, PyObject *obj)
Adopt memory of a Python object with array interface using an RVec.
Definition: RVecPyz.cxx:28
CPyCppyy.h
Cppyy::TCppType_t
TCppScope_t TCppType_t
Definition: cpp_cppyy.h:19
PyzCppHelpers.hxx
TInterpreter.h