summaryrefslogtreecommitdiff
path: root/Cython/Includes/cpython/array.pxd
blob: 8431f7b66021ba7e8b7e08aa34420bae9bf15352 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
"""
  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)
"""

cdef extern from *:
    """
    #if CYTHON_COMPILING_IN_PYPY
    #ifdef _MSC_VER
    #pragma message ("This module uses CPython specific internals of 'array.array', which are not available in PyPy.")
    #else
    #warning This module uses CPython specific internals of 'array.array', which are not available in PyPy.
    #endif
    #endif
    """

from libc.string cimport memset, memcpy

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 *:  # Hard-coded utility code hack.
    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]:
            char typecode
            int itemsize
            GETF getitem    # PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
            SETF setitem    # int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);

    ctypedef union __data_union:
        # views of ob_item:
        float* as_floats        # direct float pointer access to buffer
        double* as_doubles      # double ...
        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    # struct arraydescr *ob_descr;
            __data_union data

        def __getbuffer__(self, Py_buffer* info, int flags):
            # This implementation of getbuffer is geared towards Cython
            # requirements, and does not yet fulfill the PEP.
            # In particular strided access is always provided regardless
            # of 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   # e.g. sizeof(float)
            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      # constant regardless of resizing
            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)

    # fast resize/realloc
    # not suitable for small increments; reallocation 'to the point'
    int resize(array self, Py_ssize_t n) except -1
    # efficient for small increments (not in Py2.3-)
    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)