forked from root-project/root
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathTClassPyz.cxx
More file actions
96 lines (81 loc) · 3.53 KB
/
TClassPyz.cxx
File metadata and controls
96 lines (81 loc) · 3.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// Author: Enric Tejedor CERN 02/2019
// Original PyROOT code by Wim Lavrijsen, LBL
/*************************************************************************
* Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
// Bindings
#include "CPyCppyy/API.h"
#include "../../cppyy/CPyCppyy/src/Cppyy.h"
#include "../../cppyy/CPyCppyy/src/Utility.h"
#include "PyROOTPythonize.h"
// ROOT
#include "TClass.h"
using namespace CPyCppyy;
namespace PyROOT{
void GetBuffer(PyObject *pyobject, void *&buf);
}
// Cast the void* returned by TClass::DynamicCast to the right type
PyObject *TClassDynamicCastPyz(PyObject *self, PyObject *args)
{
// Parse arguments
PyObject *pyclass = nullptr;
PyObject *pyobject = nullptr;
int up = 1;
if (!PyArg_ParseTuple(args, "OO|i:DynamicCast", &pyclass, &pyobject, &up))
return nullptr;
if (!CPyCppyy::Instance_Check(pyclass)) {
PyObject *type = PyObject_Type(pyclass);
if (!type) {
return nullptr;
}
PyObject *name = PyObject_Str(type);
Py_DecRef(type);
const char *nameStr = name ? PyUnicode_AsUTF8AndSize(name, nullptr) : nullptr;
if (nameStr) {
PyErr_Format(PyExc_TypeError, "DynamicCast argument 1 must be a cppyy instance, got '%s'", nameStr);
} else {
PyErr_SetString(PyExc_TypeError, "DynamicCast argument 1 must be a cppyy instance");
}
Py_DecRef(name);
return nullptr;
}
// Perform actual cast - calls default implementation of DynamicCast
TClass *cl1 = (TClass *)CPyCppyy::Instance_AsVoidPtr(self);
TClass *cl2 = (TClass *)CPyCppyy::Instance_AsVoidPtr(pyclass);
void *address = cl1->DynamicCast(cl2, CPyCppyy::Instance_AsVoidPtr(pyobject), up);
if (CPyCppyy::Instance_Check(pyobject)) {
address = CPyCppyy::Instance_AsVoidPtr(pyobject);
} else {
long long value = PyLong_AsLongLong(pyobject);
if (!PyErr_Occurred()) {
address = (void *)value; // pyobject was indeed a PyLong
} else {
PyErr_Clear();
PyROOT::GetBuffer(pyobject, address);
}
}
// Now use binding to return a usable class. Upcast: result is a base.
// Downcast: result is a derived.
TClass *tcl = TClass::GetClass(CPyCppyy::Instance_GetScopedFinalName(up ? pyclass : self).c_str());
TClass *klass = (TClass *)tcl->DynamicCast(TClass::Class(), up ? CPyCppyy::Instance_AsVoidPtr(pyclass) : cl1);
return CPyCppyy::Instance_FromVoidPtr(address, klass->GetName());
}
////////////////////////////////////////////////////////////////////////////
/// \brief Add pythonization for TClass::DynamicCast.
/// \param[in] self Always null, since this is a module function.
/// \param[in] args Pointer to a Python tuple object containing the arguments
/// received from Python.
///
/// TClass::DynamicCast returns a void* that the user still has to cast (it
/// will have the proper offset, though). Fix this by providing the requested
/// binding if the cast succeeded.
PyObject *PyROOT::AddTClassDynamicCastPyz(PyObject * /* self */, PyObject *args)
{
PyObject *pyclass = PyTuple_GetItem(args, 0);
Utility::AddToClass(pyclass, "DynamicCast", (PyCFunction)TClassDynamicCastPyz);
Py_RETURN_NONE;
}