PyBufferFactory.cxx

Go to the documentation of this file.
00001 // @(#)root/pyroot:$Id: PyBufferFactory.cxx 36709 2010-11-17 00:25:40Z wlav $
00002 // Author: Wim Lavrijsen, Apr 2004
00003 
00004 // Bindings
00005 #include "PyROOT.h"
00006 #include "PyBufferFactory.h"
00007 
00008 // Standard
00009 #include <map>
00010 
00011 #if PY_VERSION_HEX >= 0x03000000
00012 static PyObject* PyBuffer_FromReadWriteMemory( void* ptr, int size ) {
00013    Py_buffer bufinfo = { ptr, NULL, size, 1, 0, 1, NULL, NULL, NULL, NULL, { 0, 0 }, NULL };
00014    return PyMemoryView_FromBuffer( &bufinfo );
00015 }
00016 #endif
00017 
00018 
00019 //- data ---------------------------------------------------------------------
00020 namespace {
00021 
00022 // top of buffer (rest of buffer object has changed across python versions)
00023    struct PyBufferTop_t {
00024       PyObject_HEAD
00025       PyObject*  fBase;            // b_base in python
00026       void*      fPtr;             // b_ptr in python
00027       Py_ssize_t fSize;            // b_size in python
00028    };
00029 
00030 // size callback label
00031    char* sizeCallback = const_cast< char* >( "_size" );
00032    PyObject* sizeCallbackString_ = PyROOT_PyUnicode_FromString( sizeCallback );
00033 
00034 // callable cache
00035    std::map< PyObject*, PyObject* > gSizeCallbacks;
00036 
00037 // create buffer types and copy methods to be adjusted
00038 #define PYROOT_PREPARE_PYBUFFER_TYPE( name )                                 \
00039    PyTypeObject      Py##name##Buffer_Type;                                  \
00040    PySequenceMethods Py##name##Buffer_SeqMethods = *(PyBuffer_Type.tp_as_sequence);\
00041    PyMappingMethods  Py##name##Buffer_MapMethods;
00042 
00043    PYROOT_PREPARE_PYBUFFER_TYPE( Short )
00044    PYROOT_PREPARE_PYBUFFER_TYPE( UShort )
00045    PYROOT_PREPARE_PYBUFFER_TYPE( Int )
00046    PYROOT_PREPARE_PYBUFFER_TYPE( UInt )
00047    PYROOT_PREPARE_PYBUFFER_TYPE( Long )
00048    PYROOT_PREPARE_PYBUFFER_TYPE( ULong )
00049    PYROOT_PREPARE_PYBUFFER_TYPE( Float )
00050    PYROOT_PREPARE_PYBUFFER_TYPE( Double )
00051 
00052 // implement get, str, and length functions
00053    Py_ssize_t buffer_length( PyObject* self )
00054    {
00055 #if PY_VERSION_HEX < 0x03000000
00056       Py_ssize_t nlen = (*(PyBuffer_Type.tp_as_sequence->sq_length))(self);
00057 #else
00058       Py_buffer bufinfo;
00059       (*(Py_TYPE(self)->tp_as_buffer->bf_getbuffer))( self, &bufinfo, PyBUF_SIMPLE );
00060       Py_ssize_t nlen = bufinfo.len;
00061 #endif
00062       if ( nlen != INT_MAX )  // INT_MAX is the default, i.e. unknown actual length
00063          return nlen;
00064 
00065       std::map< PyObject*, PyObject* >::iterator iscbp = gSizeCallbacks.find( self );
00066       if ( iscbp != gSizeCallbacks.end() ) {
00067          PyObject* pylen = PyObject_CallObject( iscbp->second, NULL );
00068          Py_ssize_t nlen2 = PyInt_AsSsize_t( pylen );
00069          Py_DECREF( pylen );
00070 
00071          if ( nlen2 == (Py_ssize_t)-1 && PyErr_Occurred() )
00072             PyErr_Clear();
00073          else
00074             return nlen2;
00075       }
00076 
00077       return nlen;            // return nlen after all, since have nothing better
00078    }
00079 
00080 //____________________________________________________________________________
00081    const char* buffer_get( PyObject* self, int idx )
00082    {
00083       if ( idx < 0 || idx >= buffer_length( self ) ) {
00084          PyErr_SetString( PyExc_IndexError, "buffer index out of range" );
00085          return 0;
00086       }
00087 
00088 #if PY_VERSION_HEX < 0x02050000
00089       const char* buf = 0;
00090 #else
00091       char* buf = 0;     // interface change in 2.5, no other way to handle it
00092 #endif
00093 #if PY_VERSION_HEX < 0x03000000
00094       (*(PyBuffer_Type.tp_as_buffer->bf_getcharbuffer))( self, 0, &buf );
00095 #else
00096       Py_buffer bufinfo;
00097       (*(PyBuffer_Type.tp_as_buffer->bf_getbuffer))( self, &bufinfo, PyBUF_SIMPLE );
00098       buf = (char*)bufinfo.buf;
00099 #endif
00100 
00101       if ( ! buf )
00102          PyErr_SetString( PyExc_IndexError, "attempt to index a null-buffer" );
00103 
00104       return buf;
00105    }
00106 
00107 //____________________________________________________________________________
00108 #define PYROOT_IMPLEMENT_PYBUFFER_METHODS( name, type, stype, F1, F2 )       \
00109    PyObject* name##_buffer_str( PyObject* self )                             \
00110    {                                                                         \
00111       Py_ssize_t l = buffer_length( self );                                  \
00112       return PyROOT_PyUnicode_FromFormat( "<"#type" buffer, size "PY_SSIZE_T_FORMAT">", l );\
00113    }                                                                         \
00114                                                                              \
00115    PyObject* name##_buffer_item( PyObject* self, Py_ssize_t idx ) {          \
00116       const char* buf = buffer_get( self, idx );                             \
00117       if ( buf )                                                             \
00118          return F1( (stype)*((type*)buf + idx) );                            \
00119       return 0;                                                              \
00120    }                                                                         \
00121                                                                              \
00122    int name##_buffer_ass_item( PyObject* self, Py_ssize_t idx, PyObject* val ) {\
00123       const char* buf = buffer_get( self, idx );                             \
00124       if ( ! buf )                                                           \
00125          return -1;                                                          \
00126                                                                              \
00127       type value = F2( val );                                                \
00128       if ( value == (type)-1 && PyErr_Occurred() )                           \
00129          return -1;                                                          \
00130                                                                              \
00131       *((type*)buf+idx) = (type)value;                                       \
00132        return 0;                                                             \
00133    }                                                                         \
00134                                                                              \
00135    PyObject* name##_buffer_subscript( PyObject* self, PyObject* item ) {     \
00136       if ( PyIndex_Check( item ) ) {                                         \
00137           Py_ssize_t idx = PyNumber_AsSsize_t( item, PyExc_IndexError );     \
00138           if ( idx == -1 && PyErr_Occurred() )                               \
00139                return 0;                                                     \
00140           return name##_buffer_item( self, idx );                            \
00141       }                                                                      \
00142       return 0;                                                              \
00143    }
00144 
00145    PYROOT_IMPLEMENT_PYBUFFER_METHODS( Short,  Short_t,  Long_t,   PyInt_FromLong, PyInt_AsLong )
00146    PYROOT_IMPLEMENT_PYBUFFER_METHODS( UShort, UShort_t, Long_t,   PyInt_FromLong, PyInt_AsLong )
00147    PYROOT_IMPLEMENT_PYBUFFER_METHODS( Int,    Int_t,    Long_t,   PyInt_FromLong, PyInt_AsLong )
00148    PYROOT_IMPLEMENT_PYBUFFER_METHODS( UInt,   UInt_t,   Long_t,   PyInt_FromLong, PyInt_AsLong )
00149    PYROOT_IMPLEMENT_PYBUFFER_METHODS( Long,   Long_t,   Long_t,   PyLong_FromLong, PyLong_AsLong )
00150    PYROOT_IMPLEMENT_PYBUFFER_METHODS( ULong,  ULong_t,  ULong_t,  PyLong_FromUnsignedLong, PyLong_AsUnsignedLong )
00151    PYROOT_IMPLEMENT_PYBUFFER_METHODS( Float,  Float_t,  Double_t, PyFloat_FromDouble, PyFloat_AsDouble )
00152    PYROOT_IMPLEMENT_PYBUFFER_METHODS( Double, Double_t, Double_t, PyFloat_FromDouble, PyFloat_AsDouble )
00153 
00154    int pyroot_buffer_ass_subscript( PyObject* self, PyObject* idx, PyObject* val ) {
00155       if ( PyIndex_Check( idx ) ) {
00156          Py_ssize_t i = PyNumber_AsSsize_t( idx, PyExc_IndexError );
00157          if ( i == -1 && PyErr_Occurred() )
00158             return -1;
00159          return Py_TYPE(self)->tp_as_sequence->sq_ass_item( self, i, val );
00160       } else {
00161          PyErr_SetString( PyExc_TypeError, "buffer indices must be integers" );
00162          return -1;
00163       }
00164    }
00165 
00166 
00167 //____________________________________________________________________________
00168    PyObject* buffer_setsize( PyObject* self, PyObject* pynlen )
00169    {
00170       Py_ssize_t nlen = PyInt_AsSsize_t( pynlen );
00171       if ( nlen == -1 && PyErr_Occurred() )
00172          return 0;
00173 
00174 #if PY_VERSION_HEX < 0x03000000
00175       ((PyBufferTop_t*)self)->fSize = nlen;
00176 #else
00177       PyMemoryView_GET_BUFFER(self)->len = nlen;
00178 #endif
00179 
00180       Py_INCREF( Py_None );
00181       return Py_None;
00182    }
00183 
00184 //____________________________________________________________________________
00185    PyObject* buf_typecode( PyObject* pyobject, void* )
00186    {
00187    // return a typecode in the style of module array
00188       if ( PyObject_TypeCheck( pyobject, &PyShortBuffer_Type ) )
00189          return PyBytes_FromString( (char*)"h" );
00190       else if ( PyObject_TypeCheck( pyobject, &PyUShortBuffer_Type ) )
00191          return PyBytes_FromString( (char*)"H" );
00192       else if ( PyObject_TypeCheck( pyobject, &PyIntBuffer_Type ) )
00193          return PyBytes_FromString( (char*)"i" );
00194       else if ( PyObject_TypeCheck( pyobject, &PyUIntBuffer_Type ) )
00195          return PyBytes_FromString( (char*)"I" );
00196       else if ( PyObject_TypeCheck( pyobject, &PyLongBuffer_Type ) )
00197          return PyBytes_FromString( (char*)"l" );
00198       else if ( PyObject_TypeCheck( pyobject, &PyULongBuffer_Type ) )
00199          return PyBytes_FromString( (char*)"L" );
00200       else if ( PyObject_TypeCheck( pyobject, &PyFloatBuffer_Type ) )
00201          return PyBytes_FromString( (char*)"f" );
00202       else if ( PyObject_TypeCheck( pyobject, &PyDoubleBuffer_Type ) )
00203          return PyBytes_FromString( (char*)"d" );
00204 
00205       PyErr_SetString( PyExc_TypeError, "received unknown buffer object" );
00206       return 0;
00207    }
00208 
00209 //____________________________________________________________________________
00210    PyGetSetDef buffer_getset[] = {
00211       { (char*)"typecode", (getter)buf_typecode, NULL, NULL, NULL },
00212       { (char*)NULL, NULL, NULL, NULL, NULL }
00213    };
00214 
00215 //____________________________________________________________________________
00216    PyMethodDef buffer_methods[] = {
00217       { (char*)"SetSize", (PyCFunction)buffer_setsize, METH_O, NULL },
00218       { (char*)NULL, NULL, 0, NULL }
00219    };
00220 
00221 } // unnamed namespace
00222 
00223 
00224 //- instance handler ------------------------------------------------------------
00225 PyROOT::TPyBufferFactory* PyROOT::TPyBufferFactory::Instance()
00226 {
00227 // singleton factory
00228    static TPyBufferFactory* fac = new TPyBufferFactory;
00229    return fac;
00230 }
00231 
00232 
00233 //- constructor/destructor ------------------------------------------------------
00234 #define PYROOT_INSTALL_PYBUFFER_METHODS( name, type )                           \
00235    Py##name##Buffer_Type.tp_name            = (char*)"ROOT.Py"#name"Buffer";    \
00236    Py##name##Buffer_Type.tp_base            = &PyBuffer_Type;                   \
00237    Py##name##Buffer_Type.tp_as_buffer       = PyBuffer_Type.tp_as_buffer;       \
00238    Py##name##Buffer_SeqMethods.sq_item      = (ssizeargfunc)name##_buffer_item; \
00239    Py##name##Buffer_SeqMethods.sq_ass_item  = (ssizeobjargproc)name##_buffer_ass_item;\
00240    Py##name##Buffer_SeqMethods.sq_length    = (lenfunc)buffer_length;           \
00241    Py##name##Buffer_Type.tp_as_sequence     = &Py##name##Buffer_SeqMethods;     \
00242    if ( PyBuffer_Type.tp_as_mapping ) { /* p2.6 and later */                    \
00243       Py##name##Buffer_MapMethods.mp_length    = (lenfunc)buffer_length;        \
00244       Py##name##Buffer_MapMethods.mp_subscript = (binaryfunc)name##_buffer_subscript;\
00245       Py##name##Buffer_MapMethods.mp_ass_subscript = (objobjargproc)pyroot_buffer_ass_subscript;\
00246       Py##name##Buffer_Type.tp_as_mapping      = &Py##name##Buffer_MapMethods;  \
00247    }                                                                            \
00248    Py##name##Buffer_Type.tp_str             = (reprfunc)name##_buffer_str;      \
00249    Py##name##Buffer_Type.tp_methods         = buffer_methods;                   \
00250    Py##name##Buffer_Type.tp_getset          = buffer_getset;                    \
00251    PyType_Ready( &Py##name##Buffer_Type );
00252 
00253 PyROOT::TPyBufferFactory::TPyBufferFactory()
00254 {
00255 // construct python buffer types
00256    PYROOT_INSTALL_PYBUFFER_METHODS( Short,  Short_t )
00257    PYROOT_INSTALL_PYBUFFER_METHODS( UShort, UShort_t )
00258    PYROOT_INSTALL_PYBUFFER_METHODS( Int,    Int_t )
00259    PYROOT_INSTALL_PYBUFFER_METHODS( UInt,   UInt_t )
00260    PYROOT_INSTALL_PYBUFFER_METHODS( Long,   Long_t )
00261    PYROOT_INSTALL_PYBUFFER_METHODS( ULong,  ULong_t )
00262    PYROOT_INSTALL_PYBUFFER_METHODS( Float,  Float_t )
00263    PYROOT_INSTALL_PYBUFFER_METHODS( Double, Double_t )
00264 }
00265 
00266 //____________________________________________________________________________
00267 PyROOT::TPyBufferFactory::~TPyBufferFactory()
00268 {
00269 }
00270 
00271 
00272 //- public members --------------------------------------------------------------
00273 #define PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( name, type )                     \
00274 PyObject* PyROOT::TPyBufferFactory::PyBuffer_FromMemory( type* address, Py_ssize_t size )\
00275 {                                                                               \
00276    size = size < 0 ? INT_MAX : size;                                            \
00277    PyObject* buf = PyBuffer_FromReadWriteMemory( (void*)address, size );        \
00278    if ( buf ) {                                                                 \
00279       Py_INCREF( (PyObject*)(void*)&Py##name##Buffer_Type );                    \
00280       buf->ob_type = &Py##name##Buffer_Type;                                    \
00281    }                                                                            \
00282    return buf;                                                                  \
00283 }                                                                               \
00284                                                                                 \
00285 PyObject* PyROOT::TPyBufferFactory::PyBuffer_FromMemory( type* address, PyObject* scb )\
00286 {                                                                               \
00287    PyObject* buf = PyBuffer_FromMemory( address, Py_ssize_t(0) );               \
00288    if ( buf != 0 && PyCallable_Check( scb ) ) {                                 \
00289       Py_INCREF( scb );                                                         \
00290       gSizeCallbacks[ buf ] = scb;                                              \
00291    }                                                                            \
00292    return buf;                                                                  \
00293 }
00294 
00295 PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( Short,  Short_t )
00296 PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( UShort, UShort_t )
00297 PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( Int,    Int_t )
00298 PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( UInt,   UInt_t )
00299 PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( Long,   Long_t )
00300 PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( ULong,  ULong_t )
00301 PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( Float,  Float_t )
00302 PYROOT_IMPLEMENT_PYBUFFER_FROM_MEMORY( Double, Double_t )

Generated on Tue Jul 5 14:10:13 2011 for ROOT_528-00b_version by  doxygen 1.5.1