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}
_object PyObject
Definition: PyResult.h:13
PyObject * GetArrayInterface(PyObject *obj)
Get Numpy array interface and perform error handling.
unsigned long long GetDataPointerFromArrayInterface(PyObject *obj)
Get data pointer from Numpy array interface and perform error handling.
std::string GetCppTypeFromNumpyType(const std::string &dtype)
Convert Numpy data-type string to the according C++ data-type string.
std::string GetTypestrFromArrayInterface(PyObject *obj)
Get type string from Numpy array interface and perform error handling.
bool CheckEndianessFromTypestr(const std::string &typestr)
Check whether endianess in type string matches the endianess of ROOT.
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
#define gInterpreter
Definition: TInterpreter.h:560
PyObject * BindCppObject(Cppyy::TCppObject_t object, Cppyy::TCppType_t klass, const unsigned flags=0)
TCppScope_t TCppType_t
Definition: cpp_cppyy.h:19
RPY_EXPORTED TCppScope_t GetScope(const std::string &scope_name)
PyObject * AsRVec(PyObject *self, PyObject *obj)
Adopt memory of a Python object with array interface using an RVec.
Definition: RVecPyz.cxx:28