Commit 1b8a867f by abonin

switch to the new cython interface to array.array

parent 9a9bd6c6
\ No newline at end of file
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
>>> 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, .length,
cdef array.array[double] k = array.copy(d)
cdef array.array[double] n = array.array(d, d.length * 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
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() option
IMPORTANT: arrayarray.h (arrayobject, arraydescr) is not part of
the official Python C-API so far; arrayarray.h is located
next to this file copy it to PythonXX/include or local or
somewhere on your -I path
last changes: 2009-05-15 rk
: 2009-12-06 bp
cimport stdlib
cdef extern from "stdlib.h" nogil:
void *memset(void *str, int c, size_t n)
char *strcat(char *str1, char *str2)
char *strncat(char *str1, char *str2, size_t n)
void *memchr(void *str, int c, size_t n)
int memcmp(void *str1, void *str2, size_t n)
void *memcpy(void *str1, void *str2, size_t n)
void *memmove(void *str1, void *str2, size_t n)
cdef extern from "arrayarray.h":
ctypedef void PyTypeObject
ctypedef short Py_UNICODE
int PyErr_BadArgument()
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: # [object arraydescr]:
int typecode
int itemsize
GETF getitem # PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
SETF setitem # int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
ctypedef class array.array [object arrayobject]:
cdef __cythonbufferdefaults__ = {'ndim' : 1, 'mode':'c'}
PyTypeObject* ob_type
int ob_size # number of valid items;
unsigned length # == ob_size (by union)
char* ob_item # to first item
Py_ssize_t allocated # bytes
arraydescr* ob_descr # struct arraydescr *ob_descr;
object weakreflist # /* List of weak references */
# view's of ob_item:
float* _f # direct float pointer access to buffer
double* _d # double ...
int* _i
unsigned *_I
unsigned char *_B
signed char *_b
char *_c
unsigned long *_L
long *_l
short *_h
unsigned short *_H
void* _v
def __getbuffer__(array self, Py_buffer* info, int flags):
# This implementation of getbuffer is geared towards Cython
# requirements, and does not yet fullfill the PEP.
# In particular strided access is always provided regardless
# of flags
cdef unsigned rows, columns, itemsize
info.suboffsets = NULL
info.buf = self.ob_item
info.readonly = 0
info.ndim = 1
info.itemsize = itemsize = self.ob_descr.itemsize # e.g. sizeof(float)
info.strides = <Py_ssize_t*> \
stdlib.malloc(sizeof(Py_ssize_t) * info.ndim * 2 + 2)
info.shape = info.strides + 1
info.shape[0] = self.ob_size # number of items
info.strides[0] = info.itemsize
info.format = <char*>(info.strides + 2 * info.ndim)
info.format[0] = self.ob_descr.typecode
info.format[1] = 0
info.obj = self
def __releasebuffer__(array self, Py_buffer* info):
#if PyArray_HASFIELDS(self):
#if sizeof(npy_intp) != sizeof(Py_ssize_t):
array newarrayobject(PyTypeObject* type, Py_ssize_t size,
arraydescr *descr)
# fast resize/realloc
# not suitable for small increments; reallocation 'to the point'
int resize(array self, Py_ssize_t n)
# efficient for small increments (not in Py2.3-)
int resize_smart(array self, Py_ssize_t n)
# fast creation of a new array - init with zeros
# yet you need a (any) template array of the same item type (but not same size)
cdef inline array zeros_like(array sametype):
cdef array op = newarrayobject(<PyTypeObject*>sametype.ob_type, sametype.ob_size, sametype.ob_descr)
if op:
memset(op.ob_item, 0, op.ob_size * op.ob_descr.itemsize)
return op
# fast creation of a new array - no init with zeros
cdef inline array empty_like(array sametype):
return newarrayobject(<PyTypeObject*>sametype.ob_type, sametype.op.ob_size,
cdef inline array copy(array self):
cdef array op = newarrayobject(<PyTypeObject*>self.ob_type, self.ob_size,
memcpy(op.ob_item, self.ob_item, op.ob_size * op.ob_descr.itemsize)
return op
cdef inline int extend_buffer(array self, char* stuff, Py_ssize_t n):
""" efficent 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, orgsize = self.ob_size
if -1 == resize_smart(self, orgsize + n):
return -1
memcpy( self.ob_item + orgsize * itemsize, stuff, n * itemsize )
cdef inline int extend(array self, array other):
if self.ob_descr.typecode != self.ob_descr.typecode:
return -1
return extend_buffer(self, other.ob_item, other.ob_size)
cdef inline void zero(array op):
memset(op.ob_item, 0, op.ob_size * op.ob_descr.itemsize)
/* arrayarray.h
artificial C-API for Python's
<array.array> type.
copy this file to your -I path, e.g. .../pythonXX/include
See array.pxd next to this file
last changes: 2009-05-15 rk
#include <Python.h>
struct arrayobject; /* Forward */
/* All possible arraydescr values are defined in the vector "descriptors"
* below. That's defined later because the appropriate get and set
* functions aren't visible yet.
typedef struct arraydescr {
int typecode;
int itemsize;
PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
#if PY_VERSION_HEX >= 0x03000000
char *formats;
} arraydescr;
typedef struct arrayobject {
union {
int ob_size;
unsigned length;
union {
char *ob_item;
float *_f;
double *_d;
int *_i;
unsigned *_I;
unsigned char *_BYTES;
signed char *_b;
char *_c;
unsigned long *_LONG;
long *_l;
short *_h;
unsigned short *_H;
void *_v;
#if PY_VERSION_HEX >= 0x02040000
Py_ssize_t allocated;
struct arraydescr *ob_descr;
#if PY_VERSION_HEX >= 0x02040000
PyObject *weakreflist; /* List of weak references */
#if PY_VERSION_HEX >= 0x03000000
int ob_exports; /* Number of exported buffers */
} arrayobject;
* fast creation of a new array - init with zeros
static inline PyObject *
newarrayobject(PyTypeObject *type, Py_ssize_t size, struct arraydescr *descr)
arrayobject *op;
size_t nbytes;
if (size < 0) {
return NULL;
nbytes = size * descr->itemsize;
/* Check for overflow */
if (nbytes / descr->itemsize != (size_t)size) {
return PyErr_NoMemory();
op = (arrayobject *) type->tp_alloc(type, 0);
if (op == NULL) {
return NULL;
op->ob_descr = descr;
#if !( PY_VERSION_HEX < 0x02040000 )
op->allocated = size;
op->weakreflist = NULL;
Py_SIZE(op) = size;
if (size <= 0) {
op->ob_item = NULL;
else {
op->ob_item = PyMem_NEW(char, nbytes);
if (op->ob_item == NULL) {
return PyErr_NoMemory();
return (PyObject *) op;
PyObject *
newarrayobject(PyTypeObject *type, Py_ssize_t size, struct arraydescr *descr);
/* fast resize (reallocation to the point)
not designed for filing small increments (but for fast opaque array apps) */
static inline int resize(arrayobject *self, Py_ssize_t n)
char *item=self->ob_item;
PyMem_RESIZE(item, char, (unsigned)(n * self->ob_descr->itemsize));
if (item == NULL) {
return -1;
self->ob_item = item;
self->ob_size = n;
#if PY_VERSION_HEX >= 0x02040000
self->allocated = n;
return 0;
/* suitable for small increments; over allocation 50% ;
Remains non-smart in Python 2.3- ; but exists for compatibility */
static inline int resize_smart(arrayobject *self, Py_ssize_t n)
char *item=self->ob_item;
#if PY_VERSION_HEX >= 0x02040000
if (n < self->allocated) {
if (n*4 > self->allocated) {
self->ob_size = n;
return 0;
Py_ssize_t newsize = n * 3 / 2 + 1;
PyMem_RESIZE(item, char, (unsigned)(newsize * self->ob_descr->itemsize));
if (item == NULL) {
return -1;
self->ob_item = item;
self->ob_size = n;
self->allocated = newsize;
return 0;
return resize(self, n) /* Python 2.3 has no 'allocated' */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment