Logo ROOT   6.16/01
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
13namespace PyROOT {
14
15//= float type allowed for reference passing =================================
16PyTypeObject 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 ==================================
75PyTypeObject 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 ================
134static PyMethodObject* free_list;
135static 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
184static 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
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
212static 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
255static 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
SVector< double, 2 > v
Definition: Dict.h:5
int Py_ssize_t
Definition: PyROOT.h:166
#define PyVarObject_HEAD_INIT(type, size)
Definition: PyROOT.h:159
#define PyMethod_MAXFREELIST
_object PyObject
Definition: TPyArg.h:20
typedef void((*Func_t)())
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.
static PyMethodObject * free_list
static void im_dealloc(PyMethodObject *im)
from instancemethod, but with custom type (at issue is that instancemethod is not meant to be derived...
static PyObject * im_descr_get(PyObject *meth, PyObject *obj, PyObject *pyclass)
from instancemethod: don't rebind an already bound method, or an unbound method of a class that's not...
PyTypeObject TCustomInstanceMethod_Type
PyTypeObject TCustomInt_Type
static int numfree
PyTypeObject TCustomFloat_Type
Custom builtins, detectable by type, for pass by ref.
PyObject * TCustomInstanceMethod_New(PyObject *func, PyObject *self, PyObject *pyclass)