Logo ROOT   6.12/07
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 
12 namespace PyROOT {
13 
14  enum ETypeDetails {
15  kNone = 0,
20  };
21 
22 namespace {
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 
129 //= PyROOT property proxy type ===============================================
130 PyTypeObject PropertyProxy_Type = {
131  PyVarObject_HEAD_INIT( &PyType_Type, 0 )
132  (char*)"ROOT.PropertyProxy", // tp_name
133  sizeof(PropertyProxy), // tp_basicsize
134  0, // tp_itemsize
135  (destructor)pp_dealloc, // tp_dealloc
136  0, // tp_print
137  0, // tp_getattr
138  0, // tp_setattr
139  0, // tp_compare
140  0, // tp_repr
141  0, // tp_as_number
142  0, // tp_as_sequence
143  0, // tp_as_mapping
144  0, // tp_hash
145  0, // tp_call
146  0, // tp_str
147  0, // tp_getattro
148  0, // tp_setattro
149  0, // tp_as_buffer
150  Py_TPFLAGS_DEFAULT, // tp_flags
151  (char*)"PyROOT property proxy (internal)", // tp_doc
152  0, // tp_traverse
153  0, // tp_clear
154  0, // tp_richcompare
155  0, // tp_weaklistoffset
156  0, // tp_iter
157  0, // tp_iternext
158  0, // tp_methods
159  0, // tp_members
160  0, // tp_getset
161  0, // tp_base
162  0, // tp_dict
163  (descrgetfunc)pp_get, // tp_descr_get
164  (descrsetfunc)pp_set, // tp_descr_set
165  0, // tp_dictoffset
166  0, // tp_init
167  0, // tp_alloc
168  (newfunc)pp_new, // tp_new
169  0, // tp_free
170  0, // tp_is_gc
171  0, // tp_bases
172  0, // tp_mro
173  0, // tp_cache
174  0, // tp_subclasses
175  0 // tp_weaklist
176 #if PY_VERSION_HEX >= 0x02030000
177  , 0 // tp_del
178 #endif
179 #if PY_VERSION_HEX >= 0x02060000
180  , 0 // tp_version_tag
181 #endif
182 #if PY_VERSION_HEX >= 0x03040000
183  , 0 // tp_finalize
184 #endif
185 };
186 
187 } // namespace PyROOT
188 
189 
190 //- public members -----------------------------------------------------------
192 {
193  fEnclosingScope = scope;
194  fName = Cppyy::GetDatamemberName( scope, idata );
195  fOffset = Cppyy::GetDatamemberOffset( scope, idata );
196  fProperty = Cppyy::IsStaticData( scope, idata ) ? kIsStaticData : 0;
197 
198  Int_t size = Cppyy::GetDimensionSize( scope, idata, 0 );
199  if ( 0 < size )
200  fProperty |= kIsArrayType;
201 
202  std::string fullType = Cppyy::GetDatamemberType( scope, idata );
203  if ( Cppyy::IsEnumData( scope, idata ) ) {
204  fullType = "UInt_t";
205  fProperty |= kIsEnumData;
206  }
207 
208  if ( Cppyy::IsConstData( scope, idata ) )
209  fProperty |= kIsConstData;
210 
211  fConverter = CreateConverter( fullType, size );
212 }
213 
214 ////////////////////////////////////////////////////////////////////////////////
215 
216 void PyROOT::PropertyProxy::Set( Cppyy::TCppScope_t scope, const std::string& name, void* address )
217 {
218  fEnclosingScope = scope;
219  fName = name;
220  fOffset = (ptrdiff_t)address;
221  fProperty = (kIsStaticData | kIsConstData | kIsEnumData /* true, but may chance */ );
222  fConverter = CreateConverter( "UInt_t", -1 );
223 }
224 
225 ////////////////////////////////////////////////////////////////////////////////
226 /// class attributes, global properties
227 
229  if ( fProperty & kIsStaticData )
230  return (void*)fOffset;
231 
232 // special case: non-static lookup through class
233  if ( ! pyobj )
234  return 0;
235 
236 // instance attributes; requires valid object for full address
237  if ( ! ObjectProxy_Check( pyobj ) ) {
238  PyErr_Format( PyExc_TypeError,
239  "object instance required for access to property \"%s\"", GetName().c_str() );
240  return 0;
241  }
242 
243  void* obj = pyobj->GetObject();
244  if ( ! obj ) {
245  PyErr_SetString( PyExc_ReferenceError, "attempt to access a null-pointer" );
246  return 0;
247  }
248 
249 // the proxy's internal offset is calculated from the enclosing class
250  ptrdiff_t offset = 0;
251  if ( pyobj->ObjectIsA() != fEnclosingScope)
252  offset = Cppyy::GetBaseOffset( pyobj->ObjectIsA(), fEnclosingScope, obj, 1 /* up-cast */ );
253 
254  return (void*)((ptrdiff_t)obj + offset + fOffset);
255 }
std::string GetName(const std::string &scope_name)
Definition: Cppyy.cxx:145
virtual Bool_t ToMemory(PyObject *value, void *address)
could happen if no derived class override
Definition: Converters.cxx:145
TConverter * fConverter
Definition: PropertyProxy.h:37
ptrdiff_t GetBaseOffset(TCppType_t derived, TCppType_t base, TCppObject_t address, int direction, bool rerror=false)
Definition: Cppyy.cxx:620
PyTypeObject PropertyProxy_Type
ptrdiff_t GetDatamemberOffset(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:946
int Int_t
Definition: RtypesCore.h:41
Bool_t IsEnumData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:1022
std::string GetDatamemberType(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:911
STL namespace.
Int_t GetDimensionSize(TCppScope_t scope, TCppIndex_t idata, int dimension)
Definition: Cppyy.cxx:1036
#define PyVarObject_HEAD_INIT(type, size)
Definition: PyROOT.h:149
void * GetAddress(ObjectProxy *pyobj)
class attributes, global properties
virtual PyObject * FromMemory(void *address)
Definition: Converters.cxx:135
Bool_t IsConstData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:1008
TConverter * CreateConverter(const std::string &fullType, Long_t size=-1)
Bool_t ObjectProxy_Check(T *object)
Definition: ObjectProxy.h:91
void Set(Cppyy::TCppScope_t scope, Cppyy::TCppIndex_t idata)
PyObject_HEAD ptrdiff_t fOffset
Definition: PropertyProxy.h:35
R__EXTERN PyObject * gLifeLine
Definition: PyStrings.h:30
std::string GetDatamemberName(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:899
Bool_t IsStaticData(TCppScope_t scope, TCppIndex_t idata)
Definition: Cppyy.cxx:997
#define Py_TYPE(ob)
Definition: PyROOT.h:151
Long_t TCppIndex_t
Definition: Cppyy.h:17
void * GetObject() const
Definition: ObjectProxy.h:47
Cppyy::TCppScope_t fEnclosingScope
Definition: PropertyProxy.h:38
ptrdiff_t TCppScope_t
Definition: Cppyy.h:12
std::string GetName()
Definition: PropertyProxy.h:30
char name[80]
Definition: TGX11.cxx:109
_object PyObject
Definition: TPyArg.h:20
Cppyy::TCppType_t ObjectIsA() const
Definition: ObjectProxy.h:66