Logo ROOT   6.08/07
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 
61 
62 // implement get, str, and length functions
63  Py_ssize_t buffer_length( PyObject* self )
64  {
65  // Retrieve the (type-strided) size of the the buffer; may be a guess.
66 #if PY_VERSION_HEX < 0x03000000
67  Py_ssize_t nlen = ((PyBufferTop_t*)self)->fSize;
68  Py_ssize_t item = ((PyBufferTop_t*)self)->fItemSize;
69 #else
70  Py_buffer* bufinfo = PyMemoryView_GET_BUFFER(self);
71  Py_ssize_t nlen = bufinfo->len;
72  Py_ssize_t item = bufinfo->itemsize;
73 #endif
74  if ( nlen != INT_MAX ) // INT_MAX is the default, i.e. unknown actual length
75  return nlen/item;
76 
77  std::map< PyObject*, PyObject* >::iterator iscbp = gSizeCallbacks.find( self );
78  if ( iscbp != gSizeCallbacks.end() ) {
79  PyObject* pylen = PyObject_CallObject( iscbp->second, NULL );
80  Py_ssize_t nlen2 = PyInt_AsSsize_t( pylen );
81  Py_DECREF( pylen );
82 
83  if ( nlen2 == (Py_ssize_t)-1 && PyErr_Occurred() )
84  PyErr_Clear();
85  else
86  return nlen2;
87  }
88 
89  return nlen; // return nlen after all, since have nothing better
90  }
91 
92 ////////////////////////////////////////////////////////////////////////////////
93 /// Retrieve the buffer as a linear char array.
94 
95  const char* buffer_get( PyObject* self, int idx )
96  {
97  if ( idx < 0 || idx >= buffer_length( self ) ) {
98  PyErr_SetString( PyExc_IndexError, "buffer index out of range" );
99  return 0;
100  }
101 
102 #if PY_VERSION_HEX < 0x02050000
103  const char* buf = 0;
104 #else
105  char* buf = 0; // interface change in 2.5, no other way to handle it
106 #endif
107 #if PY_VERSION_HEX < 0x03000000
108  (*(PyBuffer_Type.tp_as_buffer->bf_getcharbuffer))( self, 0, &buf );
109 #else
110  Py_buffer bufinfo;
111  (*(PyBuffer_Type.tp_as_buffer->bf_getbuffer))( self, &bufinfo, PyBUF_SIMPLE );
112  buf = (char*)bufinfo.buf;
113 #endif
114 
115  if ( ! buf )
116  PyErr_SetString( PyExc_IndexError, "attempt to index a null-buffer" );
117 
118  return buf;
119  }
120 
121 ////////////////////////////////////////////////////////////////////////////////
122 
123 #define PYROOT_IMPLEMENT_PYBUFFER_METHODS( name, type, stype, F1, F2 ) \
124  PyObject* name##_buffer_str( PyObject* self ) \
125  { \
126  Py_ssize_t l = buffer_length( self ); \
127  return PyROOT_PyUnicode_FromFormat( "<"#type" buffer, size " PY_SSIZE_T_FORMAT ">", l );\
128  } \
129  \
130  PyObject* name##_buffer_item( PyObject* self, Py_ssize_t idx ) { \
131  const char* buf = buffer_get( self, idx ); \
132  if ( buf ) \
133  return F1( (stype)*((type*)buf + idx) ); \
134  return 0; \
135  } \
136  \
137  int name##_buffer_ass_item( PyObject* self, Py_ssize_t idx, PyObject* val ) {\
138  const char* buf = buffer_get( self, idx ); \
139  if ( ! buf ) \
140  return -1; \
141  \
142  type value = F2( val ); \
143  if ( value == (type)-1 && PyErr_Occurred() ) \
144  return -1; \
145  \
146  *((type*)buf+idx) = (type)value; \
147  return 0; \
148  } \
149  \
150  PyObject* name##_buffer_subscript( PyObject* self, PyObject* item ) { \
151  if ( PyIndex_Check( item ) ) { \
152  Py_ssize_t idx = PyNumber_AsSsize_t( item, PyExc_IndexError ); \
153  if ( idx == -1 && PyErr_Occurred() ) \
154  return 0; \
155  return name##_buffer_item( self, idx ); \
156  } \
157  return 0; \
158  }
159 
161  PYROOT_IMPLEMENT_PYBUFFER_METHODS( Short, Short_t, Long_t, PyInt_FromLong, PyInt_AsLong )
162  PYROOT_IMPLEMENT_PYBUFFER_METHODS( UShort, UShort_t, Long_t, PyInt_FromLong, PyInt_AsLong )
163  PYROOT_IMPLEMENT_PYBUFFER_METHODS( Int, Int_t, Long_t, PyInt_FromLong, PyInt_AsLong )
164  PYROOT_IMPLEMENT_PYBUFFER_METHODS( UInt, UInt_t, Long_t, PyInt_FromLong, PyInt_AsLong )
165  PYROOT_IMPLEMENT_PYBUFFER_METHODS( Long, Long_t, Long_t, PyLong_FromLong, PyLong_AsLong )
166  PYROOT_IMPLEMENT_PYBUFFER_METHODS( ULong, ULong_t, ULong_t, PyLong_FromUnsignedLong, PyLong_AsUnsignedLong )
167  PYROOT_IMPLEMENT_PYBUFFER_METHODS( Float, Float_t, Double_t, PyFloat_FromDouble, PyFloat_AsDouble )
168  PYROOT_IMPLEMENT_PYBUFFER_METHODS( Double, Double_t, Double_t, PyFloat_FromDouble, PyFloat_AsDouble )
169 
170  int pyroot_buffer_ass_subscript( PyObject* self, PyObject* idx, PyObject* val ) {
171  // Assign the given value 'val' to the item at index 'idx.'
172  if ( PyIndex_Check( idx ) ) {
173  Py_ssize_t i = PyNumber_AsSsize_t( idx, PyExc_IndexError );
174  if ( i == -1 && PyErr_Occurred() )
175  return -1;
176  return Py_TYPE(self)->tp_as_sequence->sq_ass_item( self, i, val );
177  } else {
178  PyErr_SetString( PyExc_TypeError, "buffer indices must be integers" );
179  return -1;
180  }
181  }
182 
183 
184 ////////////////////////////////////////////////////////////////////////////////
185 /// Allow the user to fix up the actual (type-strided) size of the buffer.
186 
187  PyObject* buffer_setsize( PyObject* self, PyObject* pynlen )
188  {
189  Py_ssize_t nlen = PyInt_AsSsize_t( pynlen );
190  if ( nlen == -1 && PyErr_Occurred() )
191  return 0;
192 
193 #if PY_VERSION_HEX < 0x03000000
194  ((PyBufferTop_t*)self)->fSize = nlen * ((PyBufferTop_t*)self)->fItemSize;
195 #else
196  PyMemoryView_GET_BUFFER(self)->len = nlen * PyMemoryView_GET_BUFFER(self)->itemsize;
197 #endif
198 
199  Py_INCREF( Py_None );
200  return Py_None;
201  }
202 
203 ////////////////////////////////////////////////////////////////////////////////
204 /// return a typecode in the style of module array
205 
206  PyObject* buf_typecode( PyObject* pyobject, void* )
207  {
208  if ( PyObject_TypeCheck( pyobject, &PyBoolBuffer_Type ) )
209  return PyROOT_PyUnicode_FromString( (char*)"b" );
210  else if ( PyObject_TypeCheck( pyobject, &PyShortBuffer_Type ) )
211  return PyROOT_PyUnicode_FromString( (char*)"h" );
212  else if ( PyObject_TypeCheck( pyobject, &PyUShortBuffer_Type ) )
213  return PyROOT_PyUnicode_FromString( (char*)"H" );
214  else if ( PyObject_TypeCheck( pyobject, &PyIntBuffer_Type ) )
215  return PyROOT_PyUnicode_FromString( (char*)"i" );
216  else if ( PyObject_TypeCheck( pyobject, &PyUIntBuffer_Type ) )
217  return PyROOT_PyUnicode_FromString( (char*)"I" );
218  else if ( PyObject_TypeCheck( pyobject, &PyLongBuffer_Type ) )
219  return PyROOT_PyUnicode_FromString( (char*)"l" );
220  else if ( PyObject_TypeCheck( pyobject, &PyULongBuffer_Type ) )
221  return PyROOT_PyUnicode_FromString( (char*)"L" );
222  else if ( PyObject_TypeCheck( pyobject, &PyFloatBuffer_Type ) )
223  return PyROOT_PyUnicode_FromString( (char*)"f" );
224  else if ( PyObject_TypeCheck( pyobject, &PyDoubleBuffer_Type ) )
225  return PyROOT_PyUnicode_FromString( (char*)"d" );
226 
227  PyErr_SetString( PyExc_TypeError, "received unknown buffer object" );
228  return 0;
229  }
230 
231 ////////////////////////////////////////////////////////////////////////////////
232 
233  PyGetSetDef buffer_getset[] = {
234  { (char*)"typecode", (getter)buf_typecode, NULL, NULL, NULL },
235  { (char*)NULL, NULL, NULL, NULL, NULL }
236  };
237 
238 ////////////////////////////////////////////////////////////////////////////////
239 
240  PyMethodDef buffer_methods[] = {
241  { (char*)"SetSize", (PyCFunction)buffer_setsize, METH_O, NULL },
242  { (char*)NULL, NULL, 0, NULL }
243  };
244 
245 } // unnamed namespace
246 
247 
248 //- instance handler ------------------------------------------------------------
250 {
251 // singleton factory
252  static TPyBufferFactory* fac = new TPyBufferFactory;
253  return fac;
254 }
255 
256 
257 //- constructor/destructor ------------------------------------------------------
258 #define PYROOT_INSTALL_PYBUFFER_METHODS( name, type ) \
259  Py##name##Buffer_Type.tp_name = (char*)"ROOT.Py"#name"Buffer"; \
260  Py##name##Buffer_Type.tp_base = &PyBuffer_Type; \
261  Py##name##Buffer_Type.tp_as_buffer = PyBuffer_Type.tp_as_buffer; \
262  Py##name##Buffer_SeqMethods.sq_item = (ssizeargfunc)name##_buffer_item; \
263  Py##name##Buffer_SeqMethods.sq_ass_item = (ssizeobjargproc)name##_buffer_ass_item;\
264  Py##name##Buffer_SeqMethods.sq_length = (lenfunc)buffer_length; \
265  Py##name##Buffer_Type.tp_as_sequence = &Py##name##Buffer_SeqMethods; \
266  if ( PyBuffer_Type.tp_as_mapping ) { /* p2.6 and later */ \
267  Py##name##Buffer_MapMethods.mp_length = (lenfunc)buffer_length; \
268  Py##name##Buffer_MapMethods.mp_subscript = (binaryfunc)name##_buffer_subscript;\
269  Py##name##Buffer_MapMethods.mp_ass_subscript = (objobjargproc)pyroot_buffer_ass_subscript;\
270  Py##name##Buffer_Type.tp_as_mapping = &Py##name##Buffer_MapMethods; \
271  } \
272  Py##name##Buffer_Type.tp_str = (reprfunc)name##_buffer_str; \
273  Py##name##Buffer_Type.tp_methods = buffer_methods; \
274  Py##name##Buffer_Type.tp_getset = buffer_getset; \
275  PyType_Ready( &Py##name##Buffer_Type );
276 
278 {
279 // construct python buffer types
289 }
290 
291 ////////////////////////////////////////////////////////////////////////////////
292 
294 {
295 }
296 
297 const char* getBoolFormat() { return "b";}
298 const char* getShortFormat() { return "h";}
299 const char* getUShortFormat() { return "H";}
300 const char* getIntFormat() { return "i";}
301 const char* getUIntFormat() { return "I";}
302 const char* getLongFormat() { return "l";}
303 const char* getULongFormat() { return "L";}
304 const char* getFloatFormat() { return "f";}
305 const char* getDoubleFormat() { return "d";}
306 
307 #if PY_VERSION_HEX < 0x03000000
308  #define PYBUFFER_SETITEMSIZE(buf,type) ((PyBufferTop_t*)buf)->fItemSize = Py_ssize_t(sizeof(type))
309  #define PYBUFFER_SETFORMAT(buf,name)
310 #else
311  #define PYBUFFER_SETITEMSIZE(buf,type) PyMemoryView_GET_BUFFER(buf)->itemsize = Py_ssize_t(sizeof(type))
312  #define PYBUFFER_SETFORMAT(buf,name) PyMemoryView_GET_BUFFER(buf)->format = (char *)get##name##Format()
313 #endif
314 
315 //- public members --------------------------------------------------------------
316 #define PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( name, type ) \
317 PyObject* PyROOT::TPyBufferFactory::PyBuffer_FromMemory( type* address, Py_ssize_t size )\
318 { \
319  size = size < 0 ? INT_MAX : size; \
320  PyObject* buf = PyBuffer_FromReadWriteMemory( (void*)address, size ); \
321  if ( buf ) { \
322  Py_INCREF( (PyObject*)(void*)&Py##name##Buffer_Type ); \
323  buf->ob_type = &Py##name##Buffer_Type; \
324  PYBUFFER_SETITEMSIZE(buf,type); \
325  PYBUFFER_SETFORMAT(buf, name); \
326  } \
327  return buf; \
328 } \
329  \
330 PyObject* PyROOT::TPyBufferFactory::PyBuffer_FromMemory( type* address, PyObject* scb )\
331 { \
332  PyObject* buf = PyBuffer_FromMemory( address, Py_ssize_t(0) ); \
333  if ( buf != 0 && PyCallable_Check( scb ) ) { \
334  Py_INCREF( scb ); \
335  gSizeCallbacks[ buf ] = scb; \
336  } \
337  return buf; \
338 }
339 
const char * getBoolFormat()
#define PyROOT_PyUnicode_FromString
Definition: PyROOT.h:71
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 * getDoubleFormat()
const char * UShort
const char * UInt
const char * getLongFormat()
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
#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 NULL
Definition: Rtypes.h:82
#define PyIndex_Check(obj)
Definition: PyROOT.h:168
#define PYROOT_PREPARE_PYBUFFER_TYPE(name)
#define PYROOT_IMPLEMENT_PYBUFFER_METHODS(name, type, stype, F1, F2)
_object PyObject
Definition: TPyArg.h:22
if(line.BeginsWith("/*"))
Definition: HLFactory.cxx:443
const char * Short