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
PyArray_Item_INCREF(char * data,PyArray_Descr * descr)31 PyArray_Item_INCREF(char *data, PyArray_Descr *descr)
32 {
33 PyObject *temp;
34
35 if (!PyDataType_REFCHK(descr)) {
36 return;
37 }
38 if (descr->type_num == NPY_OBJECT) {
39 memcpy(&temp, data, sizeof(temp));
40 Py_XINCREF(temp);
41 }
42 else if (PyDataType_HASFIELDS(descr)) {
43 PyObject *key, *value, *title = NULL;
44 PyArray_Descr *new;
45 int offset;
46 Py_ssize_t pos = 0;
47
48 while (PyDict_Next(descr->fields, &pos, &key, &value)) {
49 if (NPY_TITLE_KEY(key, value)) {
50 continue;
51 }
52 if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset,
53 &title)) {
54 return;
55 }
56 PyArray_Item_INCREF(data + offset, new);
57 }
58 }
59 else if (PyDataType_HASSUBARRAY(descr)) {
60 int size, i, inner_elsize;
61
62 inner_elsize = descr->subarray->base->elsize;
63 if (inner_elsize == 0) {
64 /* There cannot be any elements, so return */
65 return;
66 }
67 /* Subarrays are always contiguous in memory */
68 size = descr->elsize / inner_elsize;
69
70 for (i = 0; i < size; i++){
71 /* Recursively increment the reference count of subarray elements */
72 PyArray_Item_INCREF(data + i * inner_elsize,
73 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
PyArray_Item_XDECREF(char * data,PyArray_Descr * descr)92 PyArray_Item_XDECREF(char *data, PyArray_Descr *descr)
93 {
94 PyObject *temp;
95
96 if (!PyDataType_REFCHK(descr)) {
97 return;
98 }
99
100 if (descr->type_num == NPY_OBJECT) {
101 memcpy(&temp, data, sizeof(temp));
102 Py_XDECREF(temp);
103 }
104 else if (PyDataType_HASFIELDS(descr)) {
105 PyObject *key, *value, *title = NULL;
106 PyArray_Descr *new;
107 int offset;
108 Py_ssize_t pos = 0;
109
110 while (PyDict_Next(descr->fields, &pos, &key, &value)) {
111 if (NPY_TITLE_KEY(key, value)) {
112 continue;
113 }
114 if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset,
115 &title)) {
116 return;
117 }
118 PyArray_Item_XDECREF(data + offset, new);
119 }
120 }
121 else if (PyDataType_HASSUBARRAY(descr)) {
122 int size, i, inner_elsize;
123
124 inner_elsize = descr->subarray->base->elsize;
125 if (inner_elsize == 0) {
126 /* There cannot be any elements, so return */
127 return;
128 }
129 /* Subarrays are always contiguous in memory */
130 size = descr->elsize / inner_elsize;
131
132 for (i = 0; i < size; i++){
133 /* Recursively decrement the reference count of subarray elements */
134 PyArray_Item_XDECREF(data + i * inner_elsize,
135 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
PyArray_INCREF(PyArrayObject * mp)151 PyArray_INCREF(PyArrayObject *mp)
152 {
153 npy_intp i, n;
154 PyObject **data;
155 PyObject *temp;
156 PyArrayIterObject *it;
157
158 if (!PyDataType_REFCHK(PyArray_DESCR(mp))) {
159 return 0;
160 }
161 if (PyArray_DESCR(mp)->type_num != NPY_OBJECT) {
162 it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp);
163 if (it == NULL) {
164 return -1;
165 }
166 while(it->index < it->size) {
167 PyArray_Item_INCREF(it->dataptr, PyArray_DESCR(mp));
168 PyArray_ITER_NEXT(it);
169 }
170 Py_DECREF(it);
171 return 0;
172 }
173
174 if (PyArray_ISONESEGMENT(mp)) {
175 data = (PyObject **)PyArray_DATA(mp);
176 n = PyArray_SIZE(mp);
177 if (PyArray_ISALIGNED(mp)) {
178 for (i = 0; i < n; i++, data++) {
179 Py_XINCREF(*data);
180 }
181 }
182 else {
183 for( i = 0; i < n; i++, data++) {
184 memcpy(&temp, data, sizeof(temp));
185 Py_XINCREF(temp);
186 }
187 }
188 }
189 else { /* handles misaligned data too */
190 it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)mp);
191 if (it == NULL) {
192 return -1;
193 }
194 while(it->index < it->size) {
195 memcpy(&temp, it->dataptr, sizeof(temp));
196 Py_XINCREF(temp);
197 PyArray_ITER_NEXT(it);
198 }
199 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
PyArray_XDECREF(PyArrayObject * mp)209 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 if (!PyDataType_REFCHK(PyArray_DESCR(mp))) {
222 return 0;
223 }
224 if (PyArray_DESCR(mp)->type_num != NPY_OBJECT) {
225 PyArray_RawIterBaseInit(&it, mp);
226 while(it.index < it.size) {
227 PyArray_Item_XDECREF(it.dataptr, PyArray_DESCR(mp));
228 PyArray_ITER_NEXT(&it);
229 }
230 return 0;
231 }
232
233 if (PyArray_ISONESEGMENT(mp)) {
234 data = (PyObject **)PyArray_DATA(mp);
235 n = PyArray_SIZE(mp);
236 if (PyArray_ISALIGNED(mp)) {
237 for (i = 0; i < n; i++, data++) Py_XDECREF(*data);
238 }
239 else {
240 for (i = 0; i < n; i++, data++) {
241 memcpy(&temp, data, sizeof(temp));
242 Py_XDECREF(temp);
243 }
244 }
245 }
246 else { /* handles misaligned data too */
247 PyArray_RawIterBaseInit(&it, mp);
248 while(it.index < it.size) {
249 memcpy(&temp, it.dataptr, sizeof(temp));
250 Py_XDECREF(temp);
251 PyArray_ITER_NEXT(&it);
252 }
253 }
254 return 0;
255 }
256
257 /*NUMPY_API
258 * Assumes contiguous
259 */
260 NPY_NO_EXPORT void
PyArray_FillObjectArray(PyArrayObject * arr,PyObject * obj)261 PyArray_FillObjectArray(PyArrayObject *arr, PyObject *obj)
262 {
263 npy_intp i,n;
264 n = PyArray_SIZE(arr);
265 if (PyArray_DESCR(arr)->type_num == NPY_OBJECT) {
266 PyObject **optr;
267 optr = (PyObject **)(PyArray_DATA(arr));
268 n = PyArray_SIZE(arr);
269 if (obj == NULL) {
270 for (i = 0; i < n; i++) {
271 *optr++ = NULL;
272 }
273 }
274 else {
275 for (i = 0; i < n; i++) {
276 Py_INCREF(obj);
277 *optr++ = obj;
278 }
279 }
280 }
281 else {
282 char *optr;
283 optr = PyArray_DATA(arr);
284 for (i = 0; i < n; i++) {
285 _fillobject(optr, obj, PyArray_DESCR(arr));
286 optr += PyArray_DESCR(arr)->elsize;
287 }
288 }
289 }
290
291 static void
_fillobject(char * optr,PyObject * obj,PyArray_Descr * dtype)292 _fillobject(char *optr, PyObject *obj, PyArray_Descr *dtype)
293 {
294 if (!PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)) {
295 PyObject *arr;
296
297 if ((obj == Py_None) ||
298 (PyLong_Check(obj) && PyLong_AsLong(obj) == 0)) {
299 return;
300 }
301 /* Clear possible long conversion error */
302 PyErr_Clear();
303 Py_INCREF(dtype);
304 arr = PyArray_NewFromDescr(&PyArray_Type, dtype,
305 0, NULL, NULL, NULL,
306 0, NULL);
307 if (arr!=NULL) {
308 dtype->f->setitem(obj, optr, arr);
309 }
310 Py_XDECREF(arr);
311 }
312 if (dtype->type_num == NPY_OBJECT) {
313 Py_XINCREF(obj);
314 memcpy(optr, &obj, sizeof(obj));
315 }
316 else if (PyDataType_HASFIELDS(dtype)) {
317 PyObject *key, *value, *title = NULL;
318 PyArray_Descr *new;
319 int offset;
320 Py_ssize_t pos = 0;
321
322 while (PyDict_Next(dtype->fields, &pos, &key, &value)) {
323 if (NPY_TITLE_KEY(key, value)) {
324 continue;
325 }
326 if (!PyArg_ParseTuple(value, "Oi|O", &new, &offset, &title)) {
327 return;
328 }
329 _fillobject(optr + offset, obj, new);
330 }
331 }
332 else if (PyDataType_HASSUBARRAY(dtype)) {
333 int size, i, inner_elsize;
334
335 inner_elsize = dtype->subarray->base->elsize;
336 if (inner_elsize == 0) {
337 /* There cannot be any elements, so return */
338 return;
339 }
340 /* Subarrays are always contiguous in memory */
341 size = dtype->elsize / inner_elsize;
342
343 /* Call _fillobject on each item recursively. */
344 for (i = 0; i < size; i++){
345 _fillobject(optr, obj, dtype->subarray->base);
346 optr += inner_elsize;
347 }
348 }
349 else {
350 /* This path should not be reachable. */
351 assert(0);
352 }
353 return;
354 }
355