Logo ROOT  
Reference Guide
PropertyProxy.cxx
Go to the documentation of this file.
1// @(#)root/pyroot:$Id$
2// Author: Wim Lavrijsen, Jan 2005
3
4// Bindings
5#include "PyROOT.h"
6#include "PyStrings.h"
7#include "PropertyProxy.h"
8#include "ObjectProxy.h"
9#include "Utility.h"
10
11
12namespace PyROOT {
13
15 kNone = 0,
19 kIsArrayType = 8
20 };
21
22namespace {
23
24//= PyROOT property proxy property behaviour =================================
25 PyObject* pp_get( PropertyProxy* pyprop, ObjectProxy* pyobj, PyObject* )
26 {
27 // normal getter access
28 void* address = pyprop->GetAddress( pyobj );
29 if ( ! address || (ptrdiff_t)address == -1 /* Cling error */ )
30 return 0;
31
32 // for fixed size arrays
33 void* ptr = address;
34 if ( pyprop->fProperty & kIsArrayType )
35 ptr = &address;
36
37 // not-initialized or public data accesses through class (e.g. by help())
38 if ( ! ptr || (ptrdiff_t)ptr == -1 /* Cling error */ ) {
39 Py_INCREF( pyprop );
40 return (PyObject*)pyprop;
41 }
42
43 if ( pyprop->fConverter != 0 ) {
44 PyObject* result = pyprop->fConverter->FromMemory( ptr );
45 if ( ! result )
46 return result;
47
48 // ensure that the encapsulating class does not go away for the duration
49 // of the data member's lifetime, if it is a bound type (it doesn't matter
50 // for builtin types, b/c those are copied over into python types and thus
51 // end up being "stand-alone")
52 if ( pyobj && ObjectProxy_Check( result ) ) {
53 if ( PyObject_SetAttr( result, PyStrings::gLifeLine, (PyObject*)pyobj ) == -1 )
54 PyErr_Clear(); // ignored
55 }
56 return result;
57 }
58
59 PyErr_Format( PyExc_NotImplementedError,
60 "no converter available for \"%s\"", pyprop->GetName().c_str() );
61 return 0;
62 }
63
64////////////////////////////////////////////////////////////////////////////////
65/// Set the value of the C++ datum held.
66
67 int pp_set( PropertyProxy* pyprop, ObjectProxy* pyobj, PyObject* value )
68 {
69 const int errret = -1;
70
71 // filter const objects to prevent changing their values
72 if ( ( pyprop->fProperty & kIsConstData ) ) {
73 PyErr_SetString( PyExc_TypeError, "assignment to const data not allowed" );
74 return errret;
75 }
76
77 ptrdiff_t address = (ptrdiff_t)pyprop->GetAddress( pyobj );
78 if ( ! address || address == -1 /* Cling error */ )
79 return errret;
80
81 // for fixed size arrays
82 void* ptr = (void*)address;
83 if ( pyprop->fProperty & kIsArrayType )
84 ptr = &address;
85
86 // actual conversion; return on success
87 if ( pyprop->fConverter && pyprop->fConverter->ToMemory( value, ptr ) )
88 return 0;
89
90 // set a python error, if not already done
91 if ( ! PyErr_Occurred() )
92 PyErr_SetString( PyExc_RuntimeError, "property type mismatch or assignment not allowed" );
93
94 // failure ...
95 return errret;
96 }
97
98//= PyROOT property proxy construction/destruction ===========================
99 PropertyProxy* pp_new( PyTypeObject* pytype, PyObject*, PyObject* )
100 {
101 // Create and initialize a new property descriptor.
102 PropertyProxy* pyprop = (PropertyProxy*)pytype->tp_alloc( pytype, 0 );
103
104 pyprop->fOffset = 0;
105 pyprop->fProperty = 0;
106 pyprop->fConverter = 0;
107 pyprop->fEnclosingScope = 0;
108 new ( &pyprop->fName ) std::string();
109
110 return pyprop;
111 }
112
113////////////////////////////////////////////////////////////////////////////////
114/// Deallocate memory held by this descriptor.
115
116 void pp_dealloc( PropertyProxy* pyprop )
117 {
118 using namespace std;
119 delete pyprop->fConverter;
120 pyprop->fName.~string();
121
122 Py_TYPE(pyprop)->tp_free( (PyObject*)pyprop );
123 }
124
125
126} // unnamed namespace
127
128#if !defined(_MSC_VER)
129#pragma GCC diagnostic push
130#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
131#endif
132
133//= PyROOT property proxy type ===============================================
134PyTypeObject PropertyProxy_Type = {
135 PyVarObject_HEAD_INIT( &PyType_Type, 0 )
136 (char*)"ROOT.PropertyProxy", // tp_name
137 sizeof(PropertyProxy), // tp_basicsize
138 0, // tp_itemsize
139 (destructor)pp_dealloc, // tp_dealloc
140 0, // tp_print (python < 3.8)
141 // tp_vectorcall_offset (python >= 3.8)
142 0, // tp_getattr
143 0, // tp_setattr
144 0, // tp_compare
145 0, // tp_repr
146 0, // tp_as_number
147 0, // tp_as_sequence
148 0, // tp_as_mapping
149 0, // tp_hash
150 0, // tp_call
151 0, // tp_str
152 0, // tp_getattro
153 0, // tp_setattro
154 0, // tp_as_buffer
155 Py_TPFLAGS_DEFAULT, // tp_flags
156 (char*)"PyROOT property proxy (internal)", // tp_doc
157 0, // tp_traverse
158 0, // tp_clear
159 0, // tp_richcompare
160 0, // tp_weaklistoffset
161 0, // tp_iter
162 0, // tp_iternext
163 0, // tp_methods
164 0, // tp_members
165 0, // tp_getset
166 0, // tp_base
167 0, // tp_dict
168 (descrgetfunc)pp_get, // tp_descr_get
169 (descrsetfunc)pp_set, // tp_descr_set
170 0, // tp_dictoffset
171 0, // tp_init
172 0, // tp_alloc
173 (newfunc)pp_new, // tp_new
174 0, // tp_free
175 0, // tp_is_gc
176 0, // tp_bases
177 0, // tp_mro
178 0, // tp_cache
179 0, // tp_subclasses
180 0 // tp_weaklist
181#if PY_VERSION_HEX >= 0x02030000
182 , 0 // tp_del
183#endif
184#if PY_VERSION_HEX >= 0x02060000
185 , 0 // tp_version_tag
186#endif
187#if PY_VERSION_HEX >= 0x03040000
188 , 0 // tp_finalize
189#endif
190#if PY_VERSION_HEX >= 0x03080000
191 , 0 // tp_vectorcall
192#if PY_VERSION_HEX < 0x03090000
193 , 0 // tp_print (python 3.8 only)
194#endif
195#endif
196};
197
198#if !defined(_MSC_VER)
199#pragma GCC diagnostic pop
200#endif
201
202} // namespace PyROOT
203
204
205//- public members -----------------------------------------------------------
207{
208 fEnclosingScope = scope;
209 fName = Cppyy::GetDatamemberName( scope, idata );
210 fOffset = Cppyy::GetDatamemberOffset( scope, idata );
211 fProperty = Cppyy::IsStaticData( scope, idata ) ? kIsStaticData : 0;
212
213 Int_t size = Cppyy::GetDimensionSize( scope, idata, 0 );
214 if ( 0 < size )
216
217 std::string fullType = Cppyy::GetDatamemberType( scope, idata );
218 if ( Cppyy::IsEnumData( scope, idata ) ) {
219 // Get underlying type of enum
220 fullType = Cppyy::ResolveEnum(fullType);
222 }
223
224 if ( Cppyy::IsConstData( scope, idata ) )
226
227 fConverter = CreateConverter( fullType, size );
228}
229
230////////////////////////////////////////////////////////////////////////////////
231
232void PyROOT::PropertyProxy::Set( Cppyy::TCppScope_t scope, const std::string& name, void* address, TEnum* en )
233{
234 std::string cppType = Cppyy::ResolveEnum(en);
235
236 fEnclosingScope = scope;
237 fName = name;
238 fOffset = (ptrdiff_t)address;
239 fProperty = (kIsStaticData | kIsConstData | kIsEnumData /* true, but may chance */ );
240 fConverter = CreateConverter( cppType, -1 );
241}
242
243////////////////////////////////////////////////////////////////////////////////
244/// class attributes, global properties
245
247 if ( fProperty & kIsStaticData )
248 return (void*)fOffset;
249
250// special case: non-static lookup through class
251 if ( ! pyobj )
252 return 0;
253
254// instance attributes; requires valid object for full address
255 if ( ! ObjectProxy_Check( pyobj ) ) {
256 PyErr_Format( PyExc_TypeError,
257 "object instance required for access to property \"%s\"", GetName().c_str() );
258 return 0;
259 }
260
261 void* obj = pyobj->GetObject();
262 if ( ! obj ) {
263 PyErr_SetString( PyExc_ReferenceError, "attempt to access a null-pointer" );
264 return 0;
265 }
266
267// the proxy's internal offset is calculated from the enclosing class
268 ptrdiff_t offset = 0;
269 if ( pyobj->ObjectIsA() != fEnclosingScope)
270 offset = Cppyy::GetBaseOffset( pyobj->ObjectIsA(), fEnclosingScope, obj, 1 /* up-cast */ );
271
272 return (void*)((ptrdiff_t)obj + offset + fOffset);
273}
#define Py_TYPE(ob)
Definition: PyROOT.h:166
#define PyVarObject_HEAD_INIT(type, size)
Definition: PyROOT.h:164
int Int_t
Definition: RtypesCore.h:41
char name[80]
Definition: TGX11.cxx:109
_object PyObject
Definition: TPyArg.h:20
Cppyy::TCppType_t ObjectIsA() const
Definition: ObjectProxy.h:66
void * GetObject() const
Definition: ObjectProxy.h:47
TConverter * fConverter
Definition: PropertyProxy.h:37
PyObject_HEAD ptrdiff_t fOffset
Definition: PropertyProxy.h:35
void Set(Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata)
Cppyy::TCppScope_t fEnclosingScope
Definition: PropertyProxy.h:38
void * GetAddress(ObjectProxy *pyobj)
class attributes, global properties
The TEnum class implements the enum type.
Definition: TEnum.h:33
ptrdiff_t GetBaseOffset(TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror=false)
Definition: Cppyy.cxx:644
ptrdiff_t TCppScope_t
Definition: Cppyy.h:15
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:150
Int_t GetDimensionSize(TCppScope_t scope, TCppIndex_t idata, int dimension)
Definition: Cppyy.cxx:1087
Bool_t IsEnumData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:1073
Bool_t IsStaticData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:1048
Long_t TCppIndex_t
Definition: Cppyy.h:21
std::string GetDatamemberType(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:962
ptrdiff_t GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:997
std::string GetDatamemberName(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:950
std::string ResolveEnum(const TEnum *en)
Definition: Cppyy.cxx:181
Bool_t IsConstData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:1059
R__EXTERN PyObject * gLifeLine
Definition: PyStrings.h:30
Bool_t ObjectProxy_Check(T *object)
Definition: ObjectProxy.h:91
TConverter * CreateConverter(const std::string &fullType, Long_t size=-1)
PyTypeObject PropertyProxy_Type