|
|
""" |
|
|
array.pxd |
|
|
|
|
|
Cython interface to Python's array.array module. |
|
|
|
|
|
* 1D contiguous data view |
|
|
* tools for fast array creation, maximum C-speed and handiness |
|
|
* suitable as allround light weight auto-array within Cython code too |
|
|
|
|
|
Usage: |
|
|
|
|
|
>>> cimport array |
|
|
|
|
|
Usage through Cython buffer interface (Py2.3+): |
|
|
|
|
|
>>> def f(arg1, unsigned i, double dx) |
|
|
... array.array[double] a = arg1 |
|
|
... a[i] += dx |
|
|
|
|
|
Fast C-level new_array(_zeros), resize_array, copy_array, Py_SIZE(obj), |
|
|
zero_array |
|
|
|
|
|
cdef array.array[double] k = array.copy(d) |
|
|
cdef array.array[double] n = array.array(d, Py_SIZE(d) * 2 ) |
|
|
cdef array.array[double] m = array.zeros_like(FLOAT_TEMPLATE) |
|
|
array.resize(f, 200000) |
|
|
|
|
|
Zero overhead with naked data pointer views by union: |
|
|
_f, _d, _i, _c, _u, ... |
|
|
=> Original C array speed + Python dynamic memory management |
|
|
|
|
|
cdef array.array a = inarray |
|
|
if |
|
|
a._d[2] += 0.66 # use as double array without extra casting |
|
|
|
|
|
float *subview = vector._f + 10 # starting from 10th element |
|
|
unsigned char *subview_buffer = vector._B + 4 |
|
|
|
|
|
Suitable as lightweight arrays intra Cython without speed penalty. |
|
|
Replacement for C stack/malloc arrays; no trouble with refcounting, |
|
|
mem.leaks; seamless Python compatibility, buffer() optional |
|
|
|
|
|
|
|
|
last changes: 2009-05-15 rk |
|
|
: 2009-12-06 bp |
|
|
: 2012-05-02 andreasvc |
|
|
: (see revision control) |
|
|
""" |
|
|
from libc.string cimport strcat, strncat, \ |
|
|
memset, memchr, memcmp, memcpy, memmove |
|
|
|
|
|
from cpython.object cimport Py_SIZE |
|
|
from cpython.ref cimport PyTypeObject, Py_TYPE |
|
|
from cpython.exc cimport PyErr_BadArgument |
|
|
from cpython.mem cimport PyObject_Malloc, PyObject_Free |
|
|
|
|
|
cdef extern from *: |
|
|
ctypedef class array.array [object arrayobject] |
|
|
ctypedef object GETF(array a, Py_ssize_t ix) |
|
|
ctypedef object SETF(array a, Py_ssize_t ix, object o) |
|
|
ctypedef struct arraydescr: |
|
|
char typecode |
|
|
int itemsize |
|
|
GETF getitem |
|
|
SETF setitem |
|
|
|
|
|
ctypedef union __data_union: |
|
|
|
|
|
float* as_floats |
|
|
double* as_doubles |
|
|
int* as_ints |
|
|
unsigned int *as_uints |
|
|
unsigned char *as_uchars |
|
|
signed char *as_schars |
|
|
char *as_chars |
|
|
unsigned long *as_ulongs |
|
|
long *as_longs |
|
|
unsigned long long *as_ulonglongs |
|
|
long long *as_longlongs |
|
|
short *as_shorts |
|
|
unsigned short *as_ushorts |
|
|
Py_UNICODE *as_pyunicodes |
|
|
void *as_voidptr |
|
|
|
|
|
ctypedef class array.array [object arrayobject]: |
|
|
cdef __cythonbufferdefaults__ = {'ndim' : 1, 'mode':'c'} |
|
|
|
|
|
cdef: |
|
|
Py_ssize_t ob_size |
|
|
arraydescr* ob_descr |
|
|
__data_union data |
|
|
|
|
|
def __getbuffer__(self, Py_buffer* info, int flags): |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
item_count = Py_SIZE(self) |
|
|
|
|
|
info.suboffsets = NULL |
|
|
info.buf = self.data.as_chars |
|
|
info.readonly = 0 |
|
|
info.ndim = 1 |
|
|
info.itemsize = self.ob_descr.itemsize |
|
|
info.len = info.itemsize * item_count |
|
|
|
|
|
info.shape = <Py_ssize_t*> PyObject_Malloc(sizeof(Py_ssize_t) + 2) |
|
|
if not info.shape: |
|
|
raise MemoryError() |
|
|
info.shape[0] = item_count |
|
|
info.strides = &info.itemsize |
|
|
|
|
|
info.format = <char*> (info.shape + 1) |
|
|
info.format[0] = self.ob_descr.typecode |
|
|
info.format[1] = 0 |
|
|
info.obj = self |
|
|
|
|
|
def __releasebuffer__(self, Py_buffer* info): |
|
|
PyObject_Free(info.shape) |
|
|
|
|
|
array newarrayobject(PyTypeObject* type, Py_ssize_t size, arraydescr *descr) |
|
|
|
|
|
|
|
|
|
|
|
int resize(array self, Py_ssize_t n) except -1 |
|
|
|
|
|
int resize_smart(array self, Py_ssize_t n) except -1 |
|
|
|
|
|
|
|
|
cdef inline array clone(array template, Py_ssize_t length, bint zero): |
|
|
""" fast creation of a new array, given a template array. |
|
|
type will be same as template. |
|
|
if zero is true, new array will be initialized with zeroes.""" |
|
|
cdef array op = newarrayobject(Py_TYPE(template), length, template.ob_descr) |
|
|
if zero and op is not None: |
|
|
memset(op.data.as_chars, 0, length * op.ob_descr.itemsize) |
|
|
return op |
|
|
|
|
|
cdef inline array copy(array self): |
|
|
""" make a copy of an array. """ |
|
|
cdef array op = newarrayobject(Py_TYPE(self), Py_SIZE(self), self.ob_descr) |
|
|
memcpy(op.data.as_chars, self.data.as_chars, Py_SIZE(op) * op.ob_descr.itemsize) |
|
|
return op |
|
|
|
|
|
cdef inline int extend_buffer(array self, char* stuff, Py_ssize_t n) except -1: |
|
|
""" efficient appending of new stuff of same type |
|
|
(e.g. of same array type) |
|
|
n: number of elements (not number of bytes!) """ |
|
|
cdef Py_ssize_t itemsize = self.ob_descr.itemsize |
|
|
cdef Py_ssize_t origsize = Py_SIZE(self) |
|
|
resize_smart(self, origsize + n) |
|
|
memcpy(self.data.as_chars + origsize * itemsize, stuff, n * itemsize) |
|
|
return 0 |
|
|
|
|
|
cdef inline int extend(array self, array other) except -1: |
|
|
""" extend array with data from another array; types must match. """ |
|
|
if self.ob_descr.typecode != other.ob_descr.typecode: |
|
|
PyErr_BadArgument() |
|
|
return extend_buffer(self, other.data.as_chars, Py_SIZE(other)) |
|
|
|
|
|
cdef inline void zero(array self): |
|
|
""" set all elements of array to zero. """ |
|
|
memset(self.data.as_chars, 0, Py_SIZE(self) * self.ob_descr.itemsize) |
|
|
|