Logo ROOT   6.10/09
Reference Guide
TCustomPyTypes.cxx
Go to the documentation of this file.
1 // Author: Wim Lavrijsen, Dec 2006
2 
3 // Bindings
4 #include "PyROOT.h"
5 #include "TCustomPyTypes.h"
6 
7 #if PY_VERSION_HEX >= 0x03000000
8 // TODO: this will break functionality
9 #define PyMethod_GET_CLASS( meth ) Py_None
10 #endif
11 
12 
13 namespace PyROOT {
14 
15 //= float type allowed for reference passing =================================
16 PyTypeObject TCustomFloat_Type = { // python float is a C/C++ double
17  PyVarObject_HEAD_INIT( &PyType_Type, 0 )
18  (char*)"ROOT.double", // tp_name
19  0, // tp_basicsize
20  0, // tp_itemsize
21  0, // tp_dealloc
22  0, // tp_print
23  0, // tp_getattr
24  0, // tp_setattr
25  0, // tp_compare
26  0, // tp_repr
27  0, // tp_as_number
28  0, // tp_as_sequence
29  0, // tp_as_mapping
30  0, // tp_hash
31  0, // tp_call
32  0, // tp_str
33  0, // tp_getattro
34  0, // tp_setattro
35  0, // tp_as_buffer
36  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
37  Py_TPFLAGS_BASETYPE, // tp_flags
38  (char*)"PyROOT float object for pass by reference", // tp_doc
39  0, // tp_traverse
40  0, // tp_clear
41  0, // tp_richcompare
42  0, // tp_weaklistoffset
43  0, // tp_iter
44  0, // tp_iternext
45  0, // tp_methods
46  0, // tp_members
47  0, // tp_getset
48  &PyFloat_Type, // tp_base
49  0, // tp_dict
50  0, // tp_descr_get
51  0, // tp_descr_set
52  0, // tp_dictoffset
53  0, // tp_init
54  0, // tp_alloc
55  0, // tp_new
56  0, // tp_free
57  0, // tp_is_gc
58  0, // tp_bases
59  0, // tp_mro
60  0, // tp_cache
61  0, // tp_subclasses
62  0 // tp_weaklist
63 #if PY_VERSION_HEX >= 0x02030000
64  , 0 // tp_del
65 #endif
66 #if PY_VERSION_HEX >= 0x02060000
67  , 0 // tp_version_tag
68 #endif
69 #if PY_VERSION_HEX >= 0x03040000
70  , 0 // tp_finalize
71 #endif
72 };
73 
74 //= long type allowed for reference passing ==================================
75 PyTypeObject TCustomInt_Type = { // python int is a C/C++ long
76  PyVarObject_HEAD_INIT( &PyType_Type, 0 )
77  (char*)"ROOT.long", // tp_name
78  0, // tp_basicsize
79  0, // tp_itemsize
80  0, // tp_dealloc
81  0, // tp_print
82  0, // tp_getattr
83  0, // tp_setattr
84  0, // tp_compare
85  0, // tp_repr
86  0, // tp_as_number
87  0, // tp_as_sequence
88  0, // tp_as_mapping
89  0, // tp_hash
90  0, // tp_call
91  0, // tp_str
92  0, // tp_getattro
93  0, // tp_setattro
94  0, // tp_as_buffer
95  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
96  Py_TPFLAGS_BASETYPE, // tp_flags
97  (char*)"PyROOT long object for pass by reference", // tp_doc
98  0, // tp_traverse
99  0, // tp_clear
100  0, // tp_richcompare
101  0, // tp_weaklistoffset
102  0, // tp_iter
103  0, // tp_iternext
104  0, // tp_methods
105  0, // tp_members
106  0, // tp_getset
107  &PyInt_Type, // tp_base
108  0, // tp_dict
109  0, // tp_descr_get
110  0, // tp_descr_set
111  0, // tp_dictoffset
112  0, // tp_init
113  0, // tp_alloc
114  0, // tp_new
115  0, // tp_free
116  0, // tp_is_gc
117  0, // tp_bases
118  0, // tp_mro
119  0, // tp_cache
120  0, // tp_subclasses
121  0 // tp_weaklist
122 #if PY_VERSION_HEX >= 0x02030000
123  , 0 // tp_del
124 #endif
125 #if PY_VERSION_HEX >= 0x02060000
126  , 0 // tp_version_tag
127 #endif
128 #if PY_VERSION_HEX >= 0x03040000
129  , 0 // tp_finalize
130 #endif
131 };
132 
133 //= instancemethod object with a more efficient call function ================
134 static PyMethodObject* free_list;
135 static int numfree = 0;
136 #ifndef PyMethod_MAXFREELIST
137 #define PyMethod_MAXFREELIST 256
138 #endif
139 
141 #if PY_VERSION_HEX < 0x03000000
142  pyclass
143 #endif
144  )
145 {
146 // from instancemethod, but with custom type (at issue is that instancemethod is not
147 // meant to be derived from)
148  PyMethodObject* im;
149  if ( ! PyCallable_Check( func ) ) {
150  PyErr_Format( PyExc_SystemError,
151  "%s:%d: bad argument to internal function",
152  __FILE__, __LINE__ );
153  return NULL;
154  }
155 
156  im = free_list;
157  if ( im != NULL ) {
158  free_list = (PyMethodObject*)( im->im_self );
159  (void)PyObject_INIT( im, &TCustomInstanceMethod_Type );
160  }
161  else {
162  im = PyObject_GC_New( PyMethodObject, &TCustomInstanceMethod_Type );
163  if ( im == NULL )
164  return NULL;
165  }
166 
167  im->im_weakreflist = NULL;
168  Py_INCREF( func );
169  im->im_func = func;
170  Py_XINCREF( self );
171  im->im_self = self;
172 #if PY_VERSION_HEX < 0x03000000
173  Py_XINCREF( pyclass );
174  im->im_class = pyclass;
175 #endif
176  PyObject_GC_Track( im );
177  return (PyObject*)im;
178 }
179 
180 ////////////////////////////////////////////////////////////////////////////////
181 /// from instancemethod, but with custom type (at issue is that instancemethod is not
182 /// meant to be derived from)
183 
184 static void im_dealloc( PyMethodObject* im )
185 {
186  PyObject_GC_UnTrack( im );
187 
188  if ( im->im_weakreflist != NULL )
189  PyObject_ClearWeakRefs( (PyObject*) im );
190 
191  Py_DECREF( im->im_func );
192  Py_XDECREF( im->im_self );
193 #if PY_VERSION_HEX < 0x03000000
194  Py_XDECREF( im->im_class );
195 #endif
196 
197  if ( numfree < PyMethod_MAXFREELIST ) {
198  im->im_self = (PyObject*)free_list;
199  free_list = im;
200  numfree++;
201  } else {
202  PyObject_GC_Del(im);
203  }
204 }
205 
206 ////////////////////////////////////////////////////////////////////////////////
207 /// The mapping from a method to a function involves reshuffling of self back
208 /// into the list of arguments. However, the pythonized methods will then have
209 /// to undo that shuffling, which is inefficient. This method is the same as
210 /// the one for the instancemethod object, except for the shuffling.
211 
212 static PyObject* im_call( PyObject* meth, PyObject* args, PyObject* kw )
213 {
214  PyObject* self = PyMethod_GET_SELF( meth );
215 
216  if ( ! self ) {
217  // unbound methods must be called with an instance of the class (or a
218  // derived class) as first argument
219  Py_ssize_t argc = PyTuple_GET_SIZE( args );
220  PyObject* pyclass = PyMethod_GET_CLASS( meth );
221  if ( 1 <= argc && PyObject_IsInstance( PyTuple_GET_ITEM( args, 0 ), pyclass ) == 1 ) {
222  self = PyTuple_GET_ITEM( args, 0 );
223 
224  PyObject* newArgs = PyTuple_New( argc - 1 );
225  for ( int i = 1; i < argc; ++i ) {
226  PyObject* v = PyTuple_GET_ITEM( args, i );
227  Py_INCREF( v );
228  PyTuple_SET_ITEM( newArgs, i-1, v );
229  }
230 
231  args = newArgs;
232 
233  } else
234  return PyMethod_Type.tp_call( meth, args, kw ); // will set proper error msg
235 
236  } else
237  Py_INCREF( args );
238 
239  PyCFunctionObject* func = (PyCFunctionObject*)PyMethod_GET_FUNCTION( meth );
240 
241 // the function is globally shared, so set and reset its "self" (ok, b/c of GIL)
242  Py_INCREF( self );
243  func->m_self = self;
244  PyObject* result = PyCFunction_Call( (PyObject*)func, args, kw );
245  func->m_self = 0;
246  Py_DECREF( self );
247  Py_DECREF( args );
248  return result;
249 }
250 
251 ////////////////////////////////////////////////////////////////////////////////
252 /// from instancemethod: don't rebind an already bound method, or an unbound method
253 /// of a class that's not a base class of pyclass
254 
255 static PyObject* im_descr_get( PyObject* meth, PyObject* obj, PyObject* pyclass )
256 {
257  if ( PyMethod_GET_SELF( meth ) != NULL
258 #if PY_VERSION_HEX < 0x03000000
259  || ( PyMethod_GET_CLASS( meth ) != NULL &&
260  ! PyObject_IsSubclass( pyclass, PyMethod_GET_CLASS(meth) ) )
261 #endif
262  ) {
263  Py_INCREF( meth );
264  return meth;
265  }
266 
267  if ( obj == Py_None )
268  obj = NULL;
269 
270  return TCustomInstanceMethod_New( PyMethod_GET_FUNCTION( meth ), obj, pyclass );
271 }
272 
273 //= PyROOT custom instance method type =======================================
275  PyVarObject_HEAD_INIT( &PyType_Type, 0 )
276  (char*)"ROOT.InstanceMethod", // tp_name
277  0, // tp_basicsize
278  0, // tp_itemsize
279  (destructor)im_dealloc, // tp_dealloc
280  0, // tp_print
281  0, // tp_getattr
282  0, // tp_setattr
283  0, // tp_compare
284  0, // tp_repr
285  0, // tp_as_number
286  0, // tp_as_sequence
287  0, // tp_as_mapping
288  0, // tp_hash
289  im_call, // tp_call
290  0, // tp_str
291  0, // tp_getattro
292  0, // tp_setattro
293  0, // tp_as_buffer
294  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES |
295  Py_TPFLAGS_BASETYPE, // tp_flags
296  (char*)"PyROOT custom instance method (internal)", // tp_doc
297  0, // tp_traverse
298  0, // tp_clear
299  0, // tp_richcompare
300  0, // tp_weaklistoffset
301  0, // tp_iter
302  0, // tp_iternext
303  0, // tp_methods
304  0, // tp_members
305  0, // tp_getset
306  &PyMethod_Type, // tp_base
307  0, // tp_dict
308  im_descr_get, // tp_descr_get
309  0, // tp_descr_set
310  0, // tp_dictoffset
311  0, // tp_init
312  0, // tp_alloc
313  0, // tp_new
314  0, // tp_free
315  0, // tp_is_gc
316  0, // tp_bases
317  0, // tp_mro
318  0, // tp_cache
319  0, // tp_subclasses
320  0 // tp_weaklist
321 #if PY_VERSION_HEX >= 0x02030000
322  , 0 // tp_del
323 #endif
324 #if PY_VERSION_HEX >= 0x02060000
325  , 0 // tp_version_tag
326 #endif
327 #if PY_VERSION_HEX >= 0x03040000
328  , 0 // tp_finalize
329 #endif
330 };
331 
332 } // namespace PyROOT
PyObject * TCustomInstanceMethod_New(PyObject *func, PyObject *self, PyObject *pyclass)
#define NULL
Definition: RtypesCore.h:88
static PyObject * im_descr_get(PyObject *meth, PyObject *obj, PyObject *pyclass)
from instancemethod: don&#39;t rebind an already bound method, or an unbound method of a class that&#39;s not...
#define PyVarObject_HEAD_INIT(type, size)
Definition: PyROOT.h:149
PyTypeObject TCustomInt_Type
#define PyMethod_MAXFREELIST
static int numfree
SVector< double, 2 > v
Definition: Dict.h:5
static PyMethodObject * free_list
PyTypeObject TCustomInstanceMethod_Type
double func(double *x, double *p)
Definition: stressTF1.cxx:213
typedef void((*Func_t)())
int Py_ssize_t
Definition: PyROOT.h:156
PyTypeObject TCustomFloat_Type
Custom builtins, detectable by type, for pass by ref.
double result[121]
static PyObject * im_call(PyObject *meth, PyObject *args, PyObject *kw)
The mapping from a method to a function involves reshuffling of self back into the list of arguments...
_object PyObject
Definition: TPyArg.h:20
static void im_dealloc(PyMethodObject *im)
from instancemethod, but with custom type (at issue is that instancemethod is not meant to be derived...