1
/*
2
 * This module corresponds to the `Special functions for NPY_OBJECT`
3
 * section in the numpy reference for C-API.
4
 */
5

6
#define PY_SSIZE_T_CLEAN
7
#include <Python.h>
8
#include "structmember.h"
9

10
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
11
#define _MULTIARRAYMODULE
12
#include "numpy/arrayobject.h"
13
#include "numpy/arrayscalars.h"
14
#include "iterators.h"
15

16
#include "npy_config.h"
17

18
#include "npy_pycompat.h"
19

20
static void
21
_fillobject(char *optr, PyObject *obj, PyArray_Descr *dtype);
22

23

24
/*NUMPY_API
25
 * XINCREF all objects in a single array item. This is complicated for
26
 * structured datatypes where the position of objects needs to be extracted.
27
 * The function is execute recursively for each nested field or subarrays dtype
28
 * such as as `np.dtype([("field1", "O"), ("field2", "f,O", (3,2))])`
29
 */
30
NPY_NO_EXPORT void
31 1
PyArray_Item_INCREF(char *data, PyArray_Descr *descr)
32
{
33
    PyObject *temp;
34

35 1
    if (!PyDataType_REFCHK(descr)) {
36
        return;
37
    }
38 1
    if (descr->type_num == NPY_OBJECT) {
39 1
        memcpy(&temp, data, sizeof(temp));
40 1
        Py_XINCREF(temp);
41
    }
42 1
    else if (PyDataType_HASFIELDS(descr)) {
43 1
        PyObject *key, *value, *title = NULL;
44
        PyArray_Descr *new;
45
        int offset;
46 1
        Py_ssize_t pos = 0;
47

48 1
        while (PyDict_Next(descr->fields, &pos, &key, &value)) {
49 1
            if (NPY_TITLE_KEY(key, value)) {
50 0
                continue;
51
            }
52 1
            if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset,
53
                                  &title)) {
54 0
                return;
55
            }
56 1
            PyArray_Item_INCREF(data + offset, new);
57
        }
58
    }
59 1
    else if (PyDataType_HASSUBARRAY(descr)) {
60
        int size, i, inner_elsize;
61

62 1
        inner_elsize = descr->subarray->base->elsize;
63 1
        if (inner_elsize == 0) {
64
            /* There cannot be any elements, so return */
65
            return;
66
        }
67
        /* Subarrays are always contiguous in memory */
68 1
        size = descr->elsize / inner_elsize;
69

70 1
        for (i = 0; i < size; i++){
71
            /* Recursively increment the reference count of subarray elements */
72 1
            PyArray_Item_INCREF(data + i * inner_elsize,
73 1
                                descr->subarray->base);
74
        }
75
    }
76
    else {
77
        /* This path should not be reachable. */
78
        assert(0);
79
    }
80
    return;
81
}
82

83

84
/*NUMPY_API
85
 *
86
 * XDECREF all objects in a single array item. This is complicated for
87
 * structured datatypes where the position of objects needs to be extracted.
88
 * The function is execute recursively for each nested field or subarrays dtype
89
 * such as as `np.dtype([("field1", "O"), ("field2", "f,O", (3,2))])`
90
 */
91
NPY_NO_EXPORT void
92 1
PyArray_Item_XDECREF(char *data, PyArray_Descr *descr)
93
{
94
    PyObject *temp;
95

96 1
    if (!PyDataType_REFCHK(descr)) {
97
        return;
98
    }
99

100 1
    if (descr->type_num == NPY_OBJECT) {
101 1
        memcpy(&temp, data, sizeof(temp));
102 1
        Py_XDECREF(temp);
103
    }
104 1
    else if (PyDataType_HASFIELDS(descr)) {
105 1
            PyObject *key, *value, *title = NULL;
106
            PyArray_Descr *new;
107
            int offset;
108 1
            Py_ssize_t pos = 0;
109

110 1
            while (PyDict_Next(descr->fields, &pos, &key, &value)) {
111 1
                if (NPY_TITLE_KEY(key, value)) {
112 1
                    continue;
113
                }
114 1
                if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset,
115
                                      &title)) {
116 0
                    return;
117
                }
118 1
                PyArray_Item_XDECREF(data + offset, new);
119
            }
120
        }
121 1
    else if (PyDataType_HASSUBARRAY(descr)) {
122
        int size, i, inner_elsize;
123

124 1
        inner_elsize = descr->subarray->base->elsize;
125 1
        if (inner_elsize == 0) {
126
            /* There cannot be any elements, so return */
127
            return;
128
        }
129
        /* Subarrays are always contiguous in memory */
130 1
        size = descr->elsize / inner_elsize;
131

132 1
        for (i = 0; i < size; i++){
133
            /* Recursively decrement the reference count of subarray elements */
134 1
            PyArray_Item_XDECREF(data + i * inner_elsize,
135 1
                                 descr->subarray->base);
136
        }
137
    }
138
    else {
139
        /* This path should not be reachable. */
140
        assert(0);
141
    }
142
    return;
143
}
144

145
/* Used for arrays of python objects to increment the reference count of */
146
/* every python object in the array. */
147
/*NUMPY_API
148
  For object arrays, increment all internal references.
149
*/
150
NPY_NO_EXPORT int
151 1
PyArray_INCREF(PyArrayObject *mp)
152
{
153
    npy_intp i, n;
154
    PyObject **data;
155
    PyObject *temp;
156
    PyArrayIterObject *it;
157

158 1
    if (!PyDataType_REFCHK(PyArray_DESCR(mp))) {
159
        return 0;
160
    }
161 1
    if (PyArray_DESCR(mp)->type_num != NPY_OBJECT) {
162 1
        it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp);
163 1
        if (it == NULL) {
164
            return -1;
165
        }
166 1
        while(it->index < it->size) {
167 1
            PyArray_Item_INCREF(it->dataptr, PyArray_DESCR(mp));
168 1
            PyArray_ITER_NEXT(it);
169
        }
170 1
        Py_DECREF(it);
171
        return 0;
172
    }
173

174 1
    if (PyArray_ISONESEGMENT(mp)) {
175 1
        data = (PyObject **)PyArray_DATA(mp);
176 1
        n = PyArray_SIZE(mp);
177 1
        if (PyArray_ISALIGNED(mp)) {
178 1
            for (i = 0; i < n; i++, data++) {
179 1
                Py_XINCREF(*data);
180
            }
181
        }
182
        else {
183 0
            for( i = 0; i < n; i++, data++) {
184 0
                memcpy(&temp, data, sizeof(temp));
185 0
                Py_XINCREF(temp);
186
            }
187
        }
188
    }
189
    else { /* handles misaligned data too */
190 0
        it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp);
191 0
        if (it == NULL) {
192
            return -1;
193
        }
194 0
        while(it->index < it->size) {
195 0
            memcpy(&temp, it->dataptr, sizeof(temp));
196 0
            Py_XINCREF(temp);
197 0
            PyArray_ITER_NEXT(it);
198
        }
199 0
        Py_DECREF(it);
200
    }
201
    return 0;
202
}
203

204
/*NUMPY_API
205
  Decrement all internal references for object arrays.
206
  (or arrays with object fields)
207
*/
208
NPY_NO_EXPORT int
209 1
PyArray_XDECREF(PyArrayObject *mp)
210
{
211
    npy_intp i, n;
212
    PyObject **data;
213
    PyObject *temp;
214
    /*
215
     * statically allocating it allows this function to not modify the
216
     * reference count of the array for use during dealloc.
217
     * (statically is not necessary as such)
218
     */
219
    PyArrayIterObject it;
220

221 1
    if (!PyDataType_REFCHK(PyArray_DESCR(mp))) {
222
        return 0;
223
    }
224 1
    if (PyArray_DESCR(mp)->type_num != NPY_OBJECT) {
225 1
        PyArray_RawIterBaseInit(&it, mp);
226 1
        while(it.index < it.size) {
227 1
            PyArray_Item_XDECREF(it.dataptr, PyArray_DESCR(mp));
228 1
            PyArray_ITER_NEXT(&it);
229
        }
230
        return 0;
231
    }
232

233 1
    if (PyArray_ISONESEGMENT(mp)) {
234 1
        data = (PyObject **)PyArray_DATA(mp);
235 1
        n = PyArray_SIZE(mp);
236 1
        if (PyArray_ISALIGNED(mp)) {
237 1
            for (i = 0; i < n; i++, data++) Py_XDECREF(*data);
238
        }
239
        else {
240 0
            for (i = 0; i < n; i++, data++) {
241 0
                memcpy(&temp, data, sizeof(temp));
242 0
                Py_XDECREF(temp);
243
            }
244
        }
245
    }
246
    else { /* handles misaligned data too */
247 0
        PyArray_RawIterBaseInit(&it, mp);
248 0
        while(it.index < it.size) {
249 0
            memcpy(&temp, it.dataptr, sizeof(temp));
250 0
            Py_XDECREF(temp);
251 0
            PyArray_ITER_NEXT(&it);
252
        }
253
    }
254
    return 0;
255
}
256

257
/*NUMPY_API
258
 * Assumes contiguous
259
 */
260
NPY_NO_EXPORT void
261 1
PyArray_FillObjectArray(PyArrayObject *arr, PyObject *obj)
262
{
263
    npy_intp i,n;
264 1
    n = PyArray_SIZE(arr);
265 1
    if (PyArray_DESCR(arr)->type_num == NPY_OBJECT) {
266
        PyObject **optr;
267 1
        optr = (PyObject **)(PyArray_DATA(arr));
268 1
        n = PyArray_SIZE(arr);
269 1
        if (obj == NULL) {
270 0
            for (i = 0; i < n; i++) {
271 0
                *optr++ = NULL;
272
            }
273
        }
274
        else {
275 1
            for (i = 0; i < n; i++) {
276 1
                Py_INCREF(obj);
277 1
                *optr++ = obj;
278
            }
279
        }
280
    }
281
    else {
282
        char *optr;
283 1
        optr = PyArray_DATA(arr);
284 1
        for (i = 0; i < n; i++) {
285 1
            _fillobject(optr, obj, PyArray_DESCR(arr));
286 1
            optr += PyArray_DESCR(arr)->elsize;
287
        }
288
    }
289
}
290

291
static void
292 1
_fillobject(char *optr, PyObject *obj, PyArray_Descr *dtype)
293
{
294 1
    if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) {
295 1
        if ((obj == Py_None) || (PyInt_Check(obj) && PyLong_AsLong(obj)==0)) {
296
            return;
297
        }
298
        else {
299
            PyObject *arr;
300 0
            Py_INCREF(dtype);
301 0
            arr = PyArray_NewFromDescr(&PyArray_Type, dtype,
302
                                       0, NULL, NULL, NULL,
303
                                       0, NULL);
304 0
            if (arr!=NULL) {
305 0
                dtype->f->setitem(obj, optr, arr);
306
            }
307 0
            Py_XDECREF(arr);
308
        }
309
    }
310 1
    if (dtype->type_num == NPY_OBJECT) {
311 1
        Py_XINCREF(obj);
312
        memcpy(optr, &obj, sizeof(obj));
313
    }
314 1
    else if (PyDataType_HASFIELDS(dtype)) {
315 1
        PyObject *key, *value, *title = NULL;
316
        PyArray_Descr *new;
317
        int offset;
318 1
        Py_ssize_t pos = 0;
319

320 1
        while (PyDict_Next(dtype->fields, &pos, &key, &value)) {
321 1
            if (NPY_TITLE_KEY(key, value)) {
322 0
                continue;
323
            }
324 1
            if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) {
325 0
                return;
326
            }
327 1
            _fillobject(optr + offset, obj, new);
328
        }
329
    }
330 1
    else if (PyDataType_HASSUBARRAY(dtype)) {
331
        int size, i, inner_elsize;
332

333 1
        inner_elsize = dtype->subarray->base->elsize;
334 1
        if (inner_elsize == 0) {
335
            /* There cannot be any elements, so return */
336
            return;
337
        }
338
        /* Subarrays are always contiguous in memory */
339 1
        size = dtype->elsize / inner_elsize;
340

341
        /* Call _fillobject on each item recursively. */
342 1
        for (i = 0; i < size; i++){
343 1
            _fillobject(optr, obj, dtype->subarray->base);
344 1
            optr += inner_elsize;
345
        }
346
    }
347
    else {
348
        /* This path should not be reachable. */
349
        assert(0);
350
    }
351
    return;
352
}

Read our documentation on viewing source code .

Loading