Logo ROOT   6.16/01
Reference Guide
TPyBufferFactory.cxx
Go to the documentation of this file.
1// @(#)root/pyroot:$Id$
2// Author: Wim Lavrijsen, Apr 2004
3
4// Bindings
5#include "PyROOT.h"
6#include "TPyBufferFactory.h"
7
8// Standard
9#include <map>
10
11#if PY_VERSION_HEX >= 0x03000000
12static PyObject* PyBuffer_FromReadWriteMemory( void* ptr, int size ) {
13#if PY_VERSION_HEX > 0x03000000
14 if ( !ptr ) { // p3 will set an exception if nullptr, just rely on size == 0
15 static long dummy[1];
16 ptr = dummy;
17 size = 0;
18 }
19#endif
20
21 Py_buffer bufinfo = { ptr, NULL, size, 1, 0, 1, NULL, NULL, NULL, NULL,
22#if PY_VERSION_HEX < 0x03030000
23 { 0, 0 },
24#endif
25 NULL };
26 return PyMemoryView_FromBuffer( &bufinfo );
27}
28#endif
29
30
31//- data ---------------------------------------------------------------------
32namespace {
33
34// top of buffer (rest of buffer object has changed across python versions)
35 struct PyBufferTop_t {
36 PyObject_HEAD
37 PyObject* fBase; // b_base in python
38 void* fPtr; // b_ptr in python
39 Py_ssize_t fSize; // b_size in python
40 Py_ssize_t fItemSize; // b_itemsize in python
41 };
42
43// callable cache
44 std::map< PyObject*, PyObject* > gSizeCallbacks;
45
46// create buffer types and copy methods to be adjusted
47#define PYROOT_PREPARE_PYBUFFER_TYPE( name ) \
48 PyTypeObject Py##name##Buffer_Type; \
49 PySequenceMethods Py##name##Buffer_SeqMethods = *(PyBuffer_Type.tp_as_sequence);\
50 PyMappingMethods Py##name##Buffer_MapMethods;
51
63
64// implement get, str, and length functions
65 Py_ssize_t buffer_length( PyObject* self )
66 {
67 // Retrieve the (type-strided) size of the the buffer; may be a guess.
68#if PY_VERSION_HEX < 0x03000000
69 Py_ssize_t nlen = ((PyBufferTop_t*)self)->fSize;
70 Py_ssize_t item = ((PyBufferTop_t*)self)->fItemSize;
71#else
72 Py_buffer* bufinfo = PyMemoryView_GET_BUFFER(self);
73 Py_ssize_t nlen = bufinfo->len;
74 Py_ssize_t item = bufinfo->itemsize;
75#endif
76 if ( nlen != INT_MAX ) // INT_MAX is the default, i.e. unknown actual length
77 return nlen/item;
78
79 std::map< PyObject*, PyObject* >::iterator iscbp = gSizeCallbacks.find( self );
80 if ( iscbp != gSizeCallbacks.end() ) {
81 PyObject* pylen = PyObject_CallObject( iscbp->second, NULL );
82 Py_ssize_t nlen2 = PyInt_AsSsize_t( pylen );
83 Py_DECREF( pylen );
84
85 if ( nlen2 == (Py_ssize_t)-1 && PyErr_Occurred() )
86 PyErr_Clear();
87 else
88 return nlen2;
89 }
90
91 return nlen; // return nlen after all, since have nothing better
92 }
93
94////////////////////////////////////////////////////////////////////////////////
95/// Retrieve the buffer as a linear char array.
96
97 const char* buffer_get( PyObject* self, int idx )
98 {
99 if ( idx < 0 || idx >= buffer_length( self ) ) {
100 PyErr_SetString( PyExc_IndexError, "buffer index out of range" );
101 return 0;
102 }
103
104#if PY_VERSION_HEX < 0x02050000
105 const char* buf = 0;
106#else
107 char* buf = 0; // interface change in 2.5, no other way to handle it
108#endif
109#if PY_VERSION_HEX < 0x03000000
110 (*(PyBuffer_Type.tp_as_buffer->bf_getcharbuffer))( self, 0, &buf );
111#else
112 Py_buffer bufinfo;
113 (*(PyBuffer_Type.tp_as_buffer->bf_getbuffer))( self, &bufinfo, PyBUF_SIMPLE );
114 buf = (char*)bufinfo.buf;
115 (*(PyBuffer_Type.tp_as_buffer->bf_releasebuffer))(self, &bufinfo);
116 Py_DECREF(bufinfo.obj);
117#endif
118
119 if ( ! buf )
120 PyErr_SetString( PyExc_IndexError, "attempt to index a null-buffer" );
121
122 return buf;
123 }
124
125////////////////////////////////////////////////////////////////////////////////
126
127#define PYROOT_IMPLEMENT_PYBUFFER_METHODS( name, type, stype, F1, F2 ) \
128 PyObject* name##_buffer_str( PyObject* self ) \
129 { \
130 Py_ssize_t l = buffer_length( self ); \
131 return PyROOT_PyUnicode_FromFormat( "<"#type" buffer, size " PY_SSIZE_T_FORMAT ">", l );\
132 } \
133 \
134 PyObject* name##_buffer_item( PyObject* self, Py_ssize_t idx ) { \
135 const char* buf = buffer_get( self, idx ); \
136 if ( buf ) \
137 return F1( (stype)*((type*)buf + idx) ); \
138 return 0; \
139 } \
140 \
141 int name##_buffer_ass_item( PyObject* self, Py_ssize_t idx, PyObject* val ) {\
142 const char* buf = buffer_get( self, idx ); \
143 if ( ! buf ) \
144 return -1; \
145 \
146 type value = F2( val ); \
147 if ( value == (type)-1 && PyErr_Occurred() ) \
148 return -1; \
149 \
150 *((type*)buf+idx) = (type)value; \
151 return 0; \
152 } \
153 \
154 PyObject* name##_buffer_subscript( PyObject* self, PyObject* item ) { \
155 if ( PyIndex_Check( item ) ) { \
156 Py_ssize_t idx = PyNumber_AsSsize_t( item, PyExc_IndexError ); \
157 if ( idx == -1 && PyErr_Occurred() ) \
158 return 0; \
159 return name##_buffer_item( self, idx ); \
160 } \
161 return 0; \
162 }
163
165 PYROOT_IMPLEMENT_PYBUFFER_METHODS( Char, Char_t, Long_t, PyInt_FromLong, PyInt_AsLong )
166 PYROOT_IMPLEMENT_PYBUFFER_METHODS( UChar, UChar_t, Long_t, PyInt_FromLong, PyInt_AsLong )
167 PYROOT_IMPLEMENT_PYBUFFER_METHODS( Short, Short_t, Long_t, PyInt_FromLong, PyInt_AsLong )
168 PYROOT_IMPLEMENT_PYBUFFER_METHODS( UShort, UShort_t, Long_t, PyInt_FromLong, PyInt_AsLong )
169 PYROOT_IMPLEMENT_PYBUFFER_METHODS( Int, Int_t, Long_t, PyInt_FromLong, PyInt_AsLong )
170 PYROOT_IMPLEMENT_PYBUFFER_METHODS( UInt, UInt_t, Long_t, PyInt_FromLong, PyInt_AsLong )
171 PYROOT_IMPLEMENT_PYBUFFER_METHODS( Long, Long_t, Long_t, PyLong_FromLong, PyLong_AsLong )
172 PYROOT_IMPLEMENT_PYBUFFER_METHODS( ULong, ULong_t, ULong_t, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong )
173 PYROOT_IMPLEMENT_PYBUFFER_METHODS( Float, Float_t, Double_t, PyFloat_FromDouble, PyFloat_AsDouble )
174 PYROOT_IMPLEMENT_PYBUFFER_METHODS( Double, Double_t, Double_t, PyFloat_FromDouble, PyFloat_AsDouble )
175
176 int pyroot_buffer_ass_subscript( PyObject* self, PyObject* idx, PyObject* val ) {
177 // Assign the given value 'val' to the item at index 'idx.'
178 if ( PyIndex_Check( idx ) ) {
179 Py_ssize_t i = PyNumber_AsSsize_t( idx, PyExc_IndexError );
180 if ( i == -1 && PyErr_Occurred() )
181 return -1;
182 return Py_TYPE(self)->tp_as_sequence->sq_ass_item( self, i, val );
183 } else {
184 PyErr_SetString( PyExc_TypeError, "buffer indices must be integers" );
185 return -1;
186 }
187 }
188
189
190////////////////////////////////////////////////////////////////////////////////
191/// Allow the user to fix up the actual (type-strided) size of the buffer.
192
193 PyObject* buffer_setsize( PyObject* self, PyObject* pynlen )
194 {
195 Py_ssize_t nlen = PyInt_AsSsize_t( pynlen );
196 if ( nlen == -1 && PyErr_Occurred() )
197 return 0;
198
199#if PY_VERSION_HEX < 0x03000000
200 ((PyBufferTop_t*)self)->fSize = nlen * ((PyBufferTop_t*)self)->fItemSize;
201#else
202 PyMemoryView_GET_BUFFER(self)->len = nlen * PyMemoryView_GET_BUFFER(self)->itemsize;
203#endif
204
205 Py_INCREF( Py_None );
206 return Py_None;
207 }
208
209////////////////////////////////////////////////////////////////////////////////
210/// return a typecode in the style of module array
211
212 PyObject* buf_typecode( PyObject* pyobject, void* )
213 {
214 if ( PyObject_TypeCheck( pyobject, &PyBoolBuffer_Type ) )
215 return PyROOT_PyUnicode_FromString( (char*)"b" );
216 else if ( PyObject_TypeCheck( pyobject, &PyCharBuffer_Type ) )
217 return PyROOT_PyUnicode_FromString( (char*)"b" );
218 else if ( PyObject_TypeCheck( pyobject, &PyUCharBuffer_Type ) )
219 return PyROOT_PyUnicode_FromString( (char*)"B" );
220 else if ( PyObject_TypeCheck( pyobject, &PyShortBuffer_Type ) )
221 return PyROOT_PyUnicode_FromString( (char*)"h" );
222 else if ( PyObject_TypeCheck( pyobject, &PyUShortBuffer_Type ) )
223 return PyROOT_PyUnicode_FromString( (char*)"H" );
224 else if ( PyObject_TypeCheck( pyobject, &PyIntBuffer_Type ) )
225 return PyROOT_PyUnicode_FromString( (char*)"i" );
226 else if ( PyObject_TypeCheck( pyobject, &PyUIntBuffer_Type ) )
227 return PyROOT_PyUnicode_FromString( (char*)"I" );
228 else if ( PyObject_TypeCheck( pyobject, &PyLongBuffer_Type ) )
229 return PyROOT_PyUnicode_FromString( (char*)"l" );
230 else if ( PyObject_TypeCheck( pyobject, &PyULongBuffer_Type ) )
231 return PyROOT_PyUnicode_FromString( (char*)"L" );
232 else if ( PyObject_TypeCheck( pyobject, &PyFloatBuffer_Type ) )
233 return PyROOT_PyUnicode_FromString( (char*)"f" );
234 else if ( PyObject_TypeCheck( pyobject, &PyDoubleBuffer_Type ) )
235 return PyROOT_PyUnicode_FromString( (char*)"d" );
236
237 PyErr_SetString( PyExc_TypeError, "received unknown buffer object" );
238 return 0;
239 }
240
241////////////////////////////////////////////////////////////////////////////////
242
243 PyGetSetDef buffer_getset[] = {
244 { (char*)"typecode", (getter)buf_typecode, NULL, NULL, NULL },
245 { (char*)NULL, NULL, NULL, NULL, NULL }
246 };
247
248////////////////////////////////////////////////////////////////////////////////
249
250 PyMethodDef buffer_methods[] = {
251 { (char*)"SetSize", (PyCFunction)buffer_setsize, METH_O, NULL },
252 { (char*)NULL, NULL, 0, NULL }
253 };
254
255} // unnamed namespace
256
257
258//- instance handler ------------------------------------------------------------
260{
261// singleton factory
262 static TPyBufferFactory* fac = new TPyBufferFactory;
263 return fac;
264}
265
266
267//- constructor/destructor ------------------------------------------------------
268#define PYROOT_INSTALL_PYBUFFER_METHODS( name, type ) \
269 Py##name##Buffer_Type.tp_name = (char*)"ROOT.Py"#name"Buffer"; \
270 Py##name##Buffer_Type.tp_base = &PyBuffer_Type; \
271 Py##name##Buffer_Type.tp_as_buffer = PyBuffer_Type.tp_as_buffer; \
272 Py##name##Buffer_SeqMethods.sq_item = (ssizeargfunc)name##_buffer_item; \
273 Py##name##Buffer_SeqMethods.sq_ass_item = (ssizeobjargproc)name##_buffer_ass_item;\
274 Py##name##Buffer_SeqMethods.sq_length = (lenfunc)buffer_length; \
275 Py##name##Buffer_Type.tp_as_sequence = &Py##name##Buffer_SeqMethods; \
276 if ( PyBuffer_Type.tp_as_mapping ) { /* p2.6 and later */ \
277 Py##name##Buffer_MapMethods.mp_length = (lenfunc)buffer_length; \
278 Py##name##Buffer_MapMethods.mp_subscript = (binaryfunc)name##_buffer_subscript;\
279 Py##name##Buffer_MapMethods.mp_ass_subscript = (objobjargproc)pyroot_buffer_ass_subscript;\
280 Py##name##Buffer_Type.tp_as_mapping = &Py##name##Buffer_MapMethods; \
281 } \
282 Py##name##Buffer_Type.tp_str = (reprfunc)name##_buffer_str; \
283 Py##name##Buffer_Type.tp_methods = buffer_methods; \
284 Py##name##Buffer_Type.tp_getset = buffer_getset; \
285 PyType_Ready( &Py##name##Buffer_Type );
286
288{
289// construct python buffer types
301}
302
303////////////////////////////////////////////////////////////////////////////////
304
306{
307}
308
309const char* getBoolFormat() { return "b";}
310const char* getCharFormat() { return "b";}
311const char* getUCharFormat() { return "B";}
312const char* getShortFormat() { return "h";}
313const char* getUShortFormat() { return "H";}
314const char* getIntFormat() { return "i";}
315const char* getUIntFormat() { return "I";}
316const char* getLongFormat() { return "l";}
317const char* getULongFormat() { return "L";}
318const char* getFloatFormat() { return "f";}
319const char* getDoubleFormat() { return "d";}
320
321#if PY_VERSION_HEX < 0x03000000
322 #define PYBUFFER_SETITEMSIZE(buf,type) ((PyBufferTop_t*)buf)->fItemSize = Py_ssize_t(sizeof(type))
323 #define PYBUFFER_SETFORMAT(buf,name)
324#else
325 #define PYBUFFER_SETITEMSIZE(buf,type) PyMemoryView_GET_BUFFER(buf)->itemsize = Py_ssize_t(sizeof(type))
326 #define PYBUFFER_SETFORMAT(buf,name) PyMemoryView_GET_BUFFER(buf)->format = (char *)get##name##Format()
327#endif
328
329//- public members --------------------------------------------------------------
330#define PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( name, type ) \
331PyObject* PyROOT::TPyBufferFactory::PyBuffer_FromMemory( type* address, Py_ssize_t size )\
332{ \
333 size = size < 0 ? INT_MAX : size; \
334 PyObject* buf = PyBuffer_FromReadWriteMemory( (void*)address, size ); \
335 if ( buf ) { \
336 Py_INCREF( (PyObject*)(void*)&Py##name##Buffer_Type ); \
337 buf->ob_type = &Py##name##Buffer_Type; \
338 PYBUFFER_SETITEMSIZE(buf,type); \
339 PYBUFFER_SETFORMAT(buf, name); \
340 } \
341 return buf; \
342} \
343 \
344PyObject* PyROOT::TPyBufferFactory::PyBuffer_FromMemory( type* address, PyObject* scb )\
345{ \
346 PyObject* buf = PyBuffer_FromMemory( address, Py_ssize_t(0) ); \
347 if ( buf != 0 && PyCallable_Check( scb ) ) { \
348 Py_INCREF( scb ); \
349 gSizeCallbacks[ buf ] = scb; \
350 } \
351 return buf; \
352}
353
#define Py_TYPE(ob)
Definition: PyROOT.h:161
Py_ssize_t PyNumber_AsSsize_t(PyObject *obj, PyObject *)
Definition: PyROOT.h:181
int Py_ssize_t
Definition: PyROOT.h:166
#define PyInt_AsSsize_t
Definition: PyROOT.h:167
#define PyBool_FromLong
Definition: PyROOT.h:202
#define PyROOT_PyUnicode_FromString
Definition: PyROOT.h:82
#define PyIndex_Check(obj)
Definition: PyROOT.h:178
static RooMathCoreReg dummy
unsigned short UShort_t
Definition: RtypesCore.h:36
int Int_t
Definition: RtypesCore.h:41
unsigned char UChar_t
Definition: RtypesCore.h:34
char Char_t
Definition: RtypesCore.h:29
unsigned int UInt_t
Definition: RtypesCore.h:42
unsigned long ULong_t
Definition: RtypesCore.h:51
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
short Short_t
Definition: RtypesCore.h:35
double Double_t
Definition: RtypesCore.h:55
float Float_t
Definition: RtypesCore.h:53
_object PyObject
Definition: TPyArg.h:20
#define PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY(name, type)
const char * getShortFormat()
const char * getUShortFormat()
const char * getIntFormat()
#define PYROOT_PREPARE_PYBUFFER_TYPE(name)
const char * getULongFormat()
const char * getUCharFormat()
const char * getBoolFormat()
const char * getUIntFormat()
#define PYROOT_INSTALL_PYBUFFER_METHODS(name, type)
const char * getFloatFormat()
const char * getLongFormat()
#define PYROOT_IMPLEMENT_PYBUFFER_METHODS(name, type, stype, F1, F2)
const char * getDoubleFormat()
const char * getCharFormat()
Factory for python buffers of non-string type.
static TPyBufferFactory * Instance()
const char * Long
const char * ULong
const char * Float
const char * Double
const char * UChar
const char * Short
const char * Int
const char * UInt
const char * UShort
const char * Bool
const char * Char