Home | History | Annotate | Download | only in cpython
      1 """
      2   array.pxd
      3   
      4   Cython interface to Python's array.array module.
      5   
      6   * 1D contiguous data view
      7   * tools for fast array creation, maximum C-speed and handiness
      8   * suitable as allround light weight auto-array within Cython code too
      9   
     10   Usage:
     11   
     12   >>> cimport array
     13 
     14   Usage through Cython buffer interface (Py2.3+):  
     15   
     16     >>> def f(arg1, unsigned i, double dx)
     17     ...     array.array[double] a = arg1
     18     ...     a[i] += dx
     19   
     20   Fast C-level new_array(_zeros), resize_array, copy_array, Py_SIZE(obj),
     21   zero_array
     22   
     23     cdef array.array[double] k = array.copy(d) 
     24     cdef array.array[double] n = array.array(d, Py_SIZE(d) * 2 )
     25     cdef array.array[double] m = array.zeros_like(FLOAT_TEMPLATE)
     26     array.resize(f, 200000)
     27   
     28   Zero overhead with naked data pointer views by union: 
     29   _f, _d, _i, _c, _u, ... 
     30   => Original C array speed + Python dynamic memory management
     31 
     32     cdef array.array a = inarray
     33     if 
     34     a._d[2] += 0.66   # use as double array without extra casting
     35   
     36     float *subview = vector._f + 10  # starting from 10th element
     37     unsigned char *subview_buffer = vector._B + 4  
     38     
     39   Suitable as lightweight arrays intra Cython without speed penalty. 
     40   Replacement for C stack/malloc arrays; no trouble with refcounting, 
     41   mem.leaks; seamless Python compatibility, buffer() optional
     42   
     43 
     44   last changes: 2009-05-15 rk
     45               : 2009-12-06 bp
     46               : 2012-05-02 andreasvc
     47               : (see revision control)
     48 """
     49 from libc.string cimport strcat, strncat, \
     50     memset, memchr, memcmp, memcpy, memmove
     51 
     52 from cpython.object cimport Py_SIZE
     53 from cpython.ref cimport PyTypeObject, Py_TYPE
     54 from cpython.exc cimport PyErr_BadArgument
     55 from cpython.mem cimport PyMem_Malloc, PyMem_Free
     56 
     57 cdef extern from *:  # Hard-coded utility code hack.
     58     ctypedef class array.array [object arrayobject]
     59     ctypedef object GETF(array a, Py_ssize_t ix)
     60     ctypedef object SETF(array a, Py_ssize_t ix, object o)
     61     ctypedef struct arraydescr:  # [object arraydescr]:
     62             int typecode
     63             int itemsize
     64             GETF getitem    # PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
     65             SETF setitem    # int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
     66 
     67     ctypedef union __data_union:
     68         # views of ob_item:
     69         float* as_floats        # direct float pointer access to buffer
     70         double* as_doubles      # double ...
     71         int*    as_ints
     72         unsigned int *as_uints
     73         unsigned char *as_uchars
     74         signed char *as_schars
     75         char *as_chars
     76         unsigned long *as_ulongs
     77         long *as_longs
     78         short *as_shorts
     79         unsigned short *as_ushorts
     80         Py_UNICODE *as_pyunicodes
     81         void *as_voidptr
     82 
     83     ctypedef class array.array [object arrayobject]:
     84         cdef __cythonbufferdefaults__ = {'ndim' : 1, 'mode':'c'}
     85 
     86         cdef:
     87             Py_ssize_t ob_size
     88             arraydescr* ob_descr    # struct arraydescr *ob_descr;
     89             __data_union data
     90 
     91         def __getbuffer__(self, Py_buffer* info, int flags):
     92             # This implementation of getbuffer is geared towards Cython
     93             # requirements, and does not yet fullfill the PEP.
     94             # In particular strided access is always provided regardless
     95             # of flags
     96             item_count = Py_SIZE(self)
     97 
     98             info.suboffsets = NULL
     99             info.buf = self.data.as_chars
    100             info.readonly = 0
    101             info.ndim = 1
    102             info.itemsize = self.ob_descr.itemsize   # e.g. sizeof(float)
    103             info.len = info.itemsize * item_count
    104 
    105             info.shape = <Py_ssize_t*> PyMem_Malloc(sizeof(Py_ssize_t) + 2)
    106             if not info.shape:
    107                 raise MemoryError()
    108             info.shape[0] = item_count      # constant regardless of resizing
    109             info.strides = &info.itemsize
    110 
    111             info.format = <char*> (info.shape + 1)
    112             info.format[0] = self.ob_descr.typecode
    113             info.format[1] = 0
    114             info.obj = self
    115 
    116         def __releasebuffer__(self, Py_buffer* info):
    117             PyMem_Free(info.shape)
    118 
    119     array newarrayobject(PyTypeObject* type, Py_ssize_t size, arraydescr *descr)
    120 
    121     # fast resize/realloc
    122     # not suitable for small increments; reallocation 'to the point'
    123     int resize(array self, Py_ssize_t n) except -1
    124     # efficient for small increments (not in Py2.3-)
    125     int resize_smart(array self, Py_ssize_t n) except -1
    126 
    127 
    128 cdef inline array clone(array template, Py_ssize_t length, bint zero):
    129     """ fast creation of a new array, given a template array.
    130     type will be same as template.
    131     if zero is true, new array will be initialized with zeroes."""
    132     op = newarrayobject(Py_TYPE(template), length, template.ob_descr)
    133     if zero and op is not None:
    134         memset(op.data.as_chars, 0, length * op.ob_descr.itemsize)
    135     return op
    136 
    137 cdef inline array copy(array self):
    138     """ make a copy of an array. """
    139     op = newarrayobject(Py_TYPE(self), Py_SIZE(self), self.ob_descr)
    140     memcpy(op.data.as_chars, self.data.as_chars, Py_SIZE(op) * op.ob_descr.itemsize)
    141     return op
    142 
    143 cdef inline int extend_buffer(array self, char* stuff, Py_ssize_t n) except -1:
    144     """ efficent appending of new stuff of same type
    145     (e.g. of same array type)
    146     n: number of elements (not number of bytes!) """
    147     cdef Py_ssize_t itemsize = self.ob_descr.itemsize
    148     cdef Py_ssize_t origsize = Py_SIZE(self)
    149     resize_smart(self, origsize + n)
    150     memcpy(self.data.as_chars + origsize * itemsize, stuff, n * itemsize)
    151     return 0
    152 
    153 cdef inline int extend(array self, array other) except -1:
    154     """ extend array with data from another array; types must match. """
    155     if self.ob_descr.typecode != other.ob_descr.typecode:
    156         PyErr_BadArgument()
    157     return extend_buffer(self, other.data.as_chars, Py_SIZE(other))
    158 
    159 cdef inline void zero(array self):
    160     """ set all elements of array to zero. """
    161     memset(self.data.as_chars, 0, Py_SIZE(self) * self.ob_descr.itemsize)
    162