Logo ROOT   6.14/05
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
12 static 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 ---------------------------------------------------------------------
32 namespace {
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 
309 const char* getBoolFormat() { return "b";}
310 const char* getCharFormat() { return "b";}
311 const char* getUCharFormat() { return "B";}
312 const char* getShortFormat() { return "h";}
313 const char* getUShortFormat() { return "H";}
314 const char* getIntFormat() { return "i";}
315 const char* getUIntFormat() { return "I";}
316 const char* getLongFormat() { return "l";}
317 const char* getULongFormat() { return "L";}
318 const char* getFloatFormat() { return "f";}
319 const 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 ) \
331 PyObject* 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  \
344 PyObject* 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 
const char * getBoolFormat()
#define PyROOT_PyUnicode_FromString
Definition: PyROOT.h:71
const char * getCharFormat()
float Float_t
Definition: RtypesCore.h:53
const char * Int
unsigned short UShort_t
Definition: RtypesCore.h:36
const char * getULongFormat()
const char * Long
int Int_t
Definition: RtypesCore.h:41
bool Bool_t
Definition: RtypesCore.h:59
Py_ssize_t PyNumber_AsSsize_t(PyObject *obj, PyObject *)
Definition: PyROOT.h:171
const char * Char
const char * getDoubleFormat()
const char * UShort
const char * UInt
const char * getLongFormat()
const char * UChar
const char * Float
const char * getIntFormat()
#define PYROOT_INSTALL_PYBUFFER_METHODS(name, type)
#define PyInt_AsSsize_t
Definition: PyROOT.h:157
unsigned int UInt_t
Definition: RtypesCore.h:42
const char * ULong
const char * getUIntFormat()
short Short_t
Definition: RtypesCore.h:35
const char * getUShortFormat()
const char * Double
long Long_t
Definition: RtypesCore.h:50
const char * getShortFormat()
double Double_t
Definition: RtypesCore.h:55
unsigned long ULong_t
Definition: RtypesCore.h:51
static RooMathCoreReg dummy
const char * getFloatFormat()
Factory for python buffers of non-string type.
const char * Bool
char Char_t
Definition: RtypesCore.h:29
#define Py_TYPE(ob)
Definition: PyROOT.h:151
#define PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY(name, type)
int Py_ssize_t
Definition: PyROOT.h:156
static TPyBufferFactory * Instance()
#define PyBool_FromLong
Definition: PyROOT.h:192
#define PyIndex_Check(obj)
Definition: PyROOT.h:168
unsigned char UChar_t
Definition: RtypesCore.h:34
#define PYROOT_PREPARE_PYBUFFER_TYPE(name)
#define PYROOT_IMPLEMENT_PYBUFFER_METHODS(name, type, stype, F1, F2)
_object PyObject
Definition: TPyArg.h:20
const char * getUCharFormat()
const char * Short