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""" 49from libc.string cimport strcat, strncat, \ 50 memset, memchr, memcmp, memcpy, memmove 51 52from cpython.object cimport Py_SIZE 53from cpython.ref cimport PyTypeObject, Py_TYPE 54from cpython.exc cimport PyErr_BadArgument 55from cpython.mem cimport PyMem_Malloc, PyMem_Free 56 57cdef 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 128cdef 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 137cdef 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 143cdef 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 153cdef 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 159cdef 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