File: | numpy/core/src/multiarray/array_coercion.c |
Warning: | line 1075, column 11 PyObject ownership leak with reference count of 1 |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | Provide multidimensional arrays as a basic object type in python. | |||
3 | ||||
4 | Based on Original Numeric implementation | |||
5 | Copyright (c) 1995, 1996, 1997 Jim Hugunin, hugunin@mit.edu | |||
6 | ||||
7 | with contributions from many Numeric Python developers 1995-2004 | |||
8 | ||||
9 | Heavily modified in 2005 with inspiration from Numarray | |||
10 | ||||
11 | by | |||
12 | ||||
13 | Travis Oliphant, oliphant@ee.byu.edu | |||
14 | Brigham Young University | |||
15 | ||||
16 | ||||
17 | maintainer email: oliphant.travis@ieee.org | |||
18 | ||||
19 | Numarray design (which provided guidance) by | |||
20 | Space Science Telescope Institute | |||
21 | (J. Todd Miller, Perry Greenfield, Rick White) | |||
22 | */ | |||
23 | #define PY_SSIZE_T_CLEAN | |||
24 | #include <Python.h> | |||
25 | #include "structmember.h" | |||
26 | ||||
27 | /*#include <stdio.h>*/ | |||
28 | #define NPY_NO_DEPRECATED_API0x0000000E NPY_API_VERSION0x0000000E | |||
29 | #define _MULTIARRAYMODULE | |||
30 | #include "numpy/arrayobject.h" | |||
31 | #include "numpy/arrayscalars.h" | |||
32 | ||||
33 | #include "npy_config.h" | |||
34 | ||||
35 | #include "npy_pycompat.h" | |||
36 | ||||
37 | #include "common.h" | |||
38 | ||||
39 | #include "number.h" | |||
40 | #include "usertypes.h" | |||
41 | #include "arraytypes.h" | |||
42 | #include "scalartypes.h" | |||
43 | #include "arrayobject.h" | |||
44 | #include "conversion_utils.h" | |||
45 | #include "ctors.h" | |||
46 | #include "dtypemeta.h" | |||
47 | #include "methods.h" | |||
48 | #include "descriptor.h" | |||
49 | #include "iterators.h" | |||
50 | #include "mapping.h" | |||
51 | #include "getset.h" | |||
52 | #include "sequence.h" | |||
53 | #include "npy_buffer.h" | |||
54 | #include "array_assign.h" | |||
55 | #include "alloc.h" | |||
56 | #include "mem_overlap.h" | |||
57 | #include "numpyos.h" | |||
58 | #include "strfuncs.h" | |||
59 | ||||
60 | #include "binop_override.h" | |||
61 | #include "array_coercion.h" | |||
62 | ||||
63 | /*NUMPY_API | |||
64 | Compute the size of an array (in number of items) | |||
65 | */ | |||
66 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) npy_intp | |||
67 | PyArray_Size(PyObject *op) | |||
68 | { | |||
69 | if (PyArray_Check(op)((((PyObject*)(op))->ob_type) == (&PyArray_Type) || PyType_IsSubtype ((((PyObject*)(op))->ob_type), (&PyArray_Type)))) { | |||
70 | return PyArray_SIZE((PyArrayObject *)op)PyArray_MultiplyList(PyArray_DIMS((PyArrayObject *)op), PyArray_NDIM ((PyArrayObject *)op)); | |||
71 | } | |||
72 | else { | |||
73 | return 0; | |||
74 | } | |||
75 | } | |||
76 | ||||
77 | /*NUMPY_API | |||
78 | * | |||
79 | * Precondition: 'arr' is a copy of 'base' (though possibly with different | |||
80 | * strides, ordering, etc.). This function sets the UPDATEIFCOPY flag and the | |||
81 | * ->base pointer on 'arr', so that when 'arr' is destructed, it will copy any | |||
82 | * changes back to 'base'. DEPRECATED, use PyArray_SetWritebackIfCopyBase | |||
83 | * | |||
84 | * Steals a reference to 'base'. | |||
85 | * | |||
86 | * Returns 0 on success, -1 on failure. | |||
87 | */ | |||
88 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
89 | PyArray_SetUpdateIfCopyBase(PyArrayObject *arr, PyArrayObject *base) | |||
90 | { | |||
91 | int ret; | |||
92 | /* 2017-Nov -10 1.14 (for PyPy only) */ | |||
93 | /* 2018-April-21 1.15 (all Python implementations) */ | |||
94 | if (DEPRECATE("PyArray_SetUpdateIfCopyBase is deprecated, use "PyErr_WarnEx(PyExc_DeprecationWarning,"PyArray_SetUpdateIfCopyBase is deprecated, use " "PyArray_SetWritebackIfCopyBase instead, and be sure to call " "PyArray_ResolveWritebackIfCopy before the array is deallocated, " "i.e. before the last call to Py_DECREF. If cleaning up from an " "error, PyArray_DiscardWritebackIfCopy may be called instead to " "throw away the scratch buffer.",1) | |||
95 | "PyArray_SetWritebackIfCopyBase instead, and be sure to call "PyErr_WarnEx(PyExc_DeprecationWarning,"PyArray_SetUpdateIfCopyBase is deprecated, use " "PyArray_SetWritebackIfCopyBase instead, and be sure to call " "PyArray_ResolveWritebackIfCopy before the array is deallocated, " "i.e. before the last call to Py_DECREF. If cleaning up from an " "error, PyArray_DiscardWritebackIfCopy may be called instead to " "throw away the scratch buffer.",1) | |||
96 | "PyArray_ResolveWritebackIfCopy before the array is deallocated, "PyErr_WarnEx(PyExc_DeprecationWarning,"PyArray_SetUpdateIfCopyBase is deprecated, use " "PyArray_SetWritebackIfCopyBase instead, and be sure to call " "PyArray_ResolveWritebackIfCopy before the array is deallocated, " "i.e. before the last call to Py_DECREF. If cleaning up from an " "error, PyArray_DiscardWritebackIfCopy may be called instead to " "throw away the scratch buffer.",1) | |||
97 | "i.e. before the last call to Py_DECREF. If cleaning up from an "PyErr_WarnEx(PyExc_DeprecationWarning,"PyArray_SetUpdateIfCopyBase is deprecated, use " "PyArray_SetWritebackIfCopyBase instead, and be sure to call " "PyArray_ResolveWritebackIfCopy before the array is deallocated, " "i.e. before the last call to Py_DECREF. If cleaning up from an " "error, PyArray_DiscardWritebackIfCopy may be called instead to " "throw away the scratch buffer.",1) | |||
98 | "error, PyArray_DiscardWritebackIfCopy may be called instead to "PyErr_WarnEx(PyExc_DeprecationWarning,"PyArray_SetUpdateIfCopyBase is deprecated, use " "PyArray_SetWritebackIfCopyBase instead, and be sure to call " "PyArray_ResolveWritebackIfCopy before the array is deallocated, " "i.e. before the last call to Py_DECREF. If cleaning up from an " "error, PyArray_DiscardWritebackIfCopy may be called instead to " "throw away the scratch buffer.",1) | |||
99 | "throw away the scratch buffer.")PyErr_WarnEx(PyExc_DeprecationWarning,"PyArray_SetUpdateIfCopyBase is deprecated, use " "PyArray_SetWritebackIfCopyBase instead, and be sure to call " "PyArray_ResolveWritebackIfCopy before the array is deallocated, " "i.e. before the last call to Py_DECREF. If cleaning up from an " "error, PyArray_DiscardWritebackIfCopy may be called instead to " "throw away the scratch buffer.",1) < 0) | |||
100 | return -1; | |||
101 | ret = PyArray_SetWritebackIfCopyBase(arr, base); | |||
102 | if (ret >=0) { | |||
103 | PyArray_ENABLEFLAGS(arr, NPY_ARRAY_UPDATEIFCOPY0x1000); | |||
104 | PyArray_CLEARFLAGS(arr, NPY_ARRAY_WRITEBACKIFCOPY0x2000); | |||
105 | } | |||
106 | return ret; | |||
107 | } | |||
108 | ||||
109 | /*NUMPY_API | |||
110 | * | |||
111 | * Precondition: 'arr' is a copy of 'base' (though possibly with different | |||
112 | * strides, ordering, etc.). This function sets the WRITEBACKIFCOPY flag and the | |||
113 | * ->base pointer on 'arr', call PyArray_ResolveWritebackIfCopy to copy any | |||
114 | * changes back to 'base' before deallocating the array. | |||
115 | * | |||
116 | * Steals a reference to 'base'. | |||
117 | * | |||
118 | * Returns 0 on success, -1 on failure. | |||
119 | */ | |||
120 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
121 | PyArray_SetWritebackIfCopyBase(PyArrayObject *arr, PyArrayObject *base) | |||
122 | { | |||
123 | if (base == NULL((void*)0)) { | |||
124 | PyErr_SetString(PyExc_ValueError, | |||
125 | "Cannot WRITEBACKIFCOPY to NULL array"); | |||
126 | return -1; | |||
127 | } | |||
128 | if (PyArray_BASE(arr) != NULL((void*)0)) { | |||
129 | PyErr_SetString(PyExc_ValueError, | |||
130 | "Cannot set array with existing base to WRITEBACKIFCOPY"); | |||
131 | goto fail; | |||
132 | } | |||
133 | if (PyArray_FailUnlessWriteable(base, "WRITEBACKIFCOPY base") < 0) { | |||
134 | goto fail; | |||
135 | } | |||
136 | ||||
137 | /* | |||
138 | * Any writes to 'arr' will magically turn into writes to 'base', so we | |||
139 | * should warn if necessary. | |||
140 | */ | |||
141 | if (PyArray_FLAGS(base) & NPY_ARRAY_WARN_ON_WRITE) { | |||
142 | PyArray_ENABLEFLAGS(arr, NPY_ARRAY_WARN_ON_WRITE); | |||
143 | } | |||
144 | ||||
145 | /* | |||
146 | * Unlike PyArray_SetBaseObject, we do not compress the chain of base | |||
147 | * references. | |||
148 | */ | |||
149 | ((PyArrayObject_fields *)arr)->base = (PyObject *)base; | |||
150 | PyArray_ENABLEFLAGS(arr, NPY_ARRAY_WRITEBACKIFCOPY0x2000); | |||
151 | PyArray_CLEARFLAGS(base, NPY_ARRAY_WRITEABLE0x0400); | |||
152 | ||||
153 | return 0; | |||
154 | ||||
155 | fail: | |||
156 | Py_DECREF(base)_Py_DECREF(((PyObject*)(base))); | |||
157 | return -1; | |||
158 | } | |||
159 | ||||
160 | /*NUMPY_API | |||
161 | * Sets the 'base' attribute of the array. This steals a reference | |||
162 | * to 'obj'. | |||
163 | * | |||
164 | * Returns 0 on success, -1 on failure. | |||
165 | */ | |||
166 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
167 | PyArray_SetBaseObject(PyArrayObject *arr, PyObject *obj) | |||
168 | { | |||
169 | if (obj == NULL((void*)0)) { | |||
170 | PyErr_SetString(PyExc_ValueError, | |||
171 | "Cannot set the NumPy array 'base' " | |||
172 | "dependency to NULL after initialization"); | |||
173 | return -1; | |||
174 | } | |||
175 | /* | |||
176 | * Allow the base to be set only once. Once the object which | |||
177 | * owns the data is set, it doesn't make sense to change it. | |||
178 | */ | |||
179 | if (PyArray_BASE(arr) != NULL((void*)0)) { | |||
180 | Py_DECREF(obj)_Py_DECREF(((PyObject*)(obj))); | |||
181 | PyErr_SetString(PyExc_ValueError, | |||
182 | "Cannot set the NumPy array 'base' " | |||
183 | "dependency more than once"); | |||
184 | return -1; | |||
185 | } | |||
186 | ||||
187 | /* | |||
188 | * Don't allow infinite chains of views, always set the base | |||
189 | * to the first owner of the data. | |||
190 | * That is, either the first object which isn't an array, | |||
191 | * or the first object which owns its own data. | |||
192 | */ | |||
193 | ||||
194 | while (PyArray_Check(obj)((((PyObject*)(obj))->ob_type) == (&PyArray_Type) || PyType_IsSubtype ((((PyObject*)(obj))->ob_type), (&PyArray_Type))) && (PyObject *)arr != obj) { | |||
195 | PyArrayObject *obj_arr = (PyArrayObject *)obj; | |||
196 | PyObject *tmp; | |||
197 | ||||
198 | /* Propagate WARN_ON_WRITE through views. */ | |||
199 | if (PyArray_FLAGS(obj_arr) & NPY_ARRAY_WARN_ON_WRITE) { | |||
200 | PyArray_ENABLEFLAGS(arr, NPY_ARRAY_WARN_ON_WRITE); | |||
201 | } | |||
202 | ||||
203 | /* If this array owns its own data, stop collapsing */ | |||
204 | if (PyArray_CHKFLAGS(obj_arr, NPY_ARRAY_OWNDATA0x0004)) { | |||
205 | break; | |||
206 | } | |||
207 | ||||
208 | tmp = PyArray_BASE(obj_arr); | |||
209 | /* If there's no base, stop collapsing */ | |||
210 | if (tmp == NULL((void*)0)) { | |||
211 | break; | |||
212 | } | |||
213 | /* Stop the collapse new base when the would not be of the same | |||
214 | * type (i.e. different subclass). | |||
215 | */ | |||
216 | if (Py_TYPE(tmp)(((PyObject*)(tmp))->ob_type) != Py_TYPE(arr)(((PyObject*)(arr))->ob_type)) { | |||
217 | break; | |||
218 | } | |||
219 | ||||
220 | ||||
221 | Py_INCREF(tmp)_Py_INCREF(((PyObject*)(tmp))); | |||
222 | Py_DECREF(obj)_Py_DECREF(((PyObject*)(obj))); | |||
223 | obj = tmp; | |||
224 | } | |||
225 | ||||
226 | /* Disallow circular references */ | |||
227 | if ((PyObject *)arr == obj) { | |||
228 | Py_DECREF(obj)_Py_DECREF(((PyObject*)(obj))); | |||
229 | PyErr_SetString(PyExc_ValueError, | |||
230 | "Cannot create a circular NumPy array 'base' dependency"); | |||
231 | return -1; | |||
232 | } | |||
233 | ||||
234 | ((PyArrayObject_fields *)arr)->base = obj; | |||
235 | ||||
236 | return 0; | |||
237 | } | |||
238 | ||||
239 | ||||
240 | /** | |||
241 | * Assign an arbitrary object a NumPy array. This is largely basically | |||
242 | * identical to PyArray_FromAny, but assigns directly to the output array. | |||
243 | * | |||
244 | * @param dest Array to be written to | |||
245 | * @param src_object Object to be assigned, array-coercion rules apply. | |||
246 | * @return 0 on success -1 on failures. | |||
247 | */ | |||
248 | /*NUMPY_API*/ | |||
249 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
250 | PyArray_CopyObject(PyArrayObject *dest, PyObject *src_object) | |||
251 | { | |||
252 | int ret = 0; | |||
253 | PyArrayObject *view; | |||
254 | PyArray_Descr *dtype = NULL((void*)0); | |||
255 | int ndim; | |||
256 | npy_intp dims[NPY_MAXDIMS32]; | |||
257 | coercion_cache_obj *cache = NULL((void*)0); | |||
258 | ||||
259 | /* | |||
260 | * We have to set the maximum number of dimensions here to support | |||
261 | * sequences within object arrays. | |||
262 | */ | |||
263 | ndim = PyArray_DiscoverDTypeAndShape(src_object, | |||
| ||||
264 | PyArray_NDIM(dest), dims, &cache, | |||
265 | NPY_DTYPE(PyArray_DESCR(dest))((PyArray_DTypeMeta *)(((PyObject*)(PyArray_DESCR(dest)))-> ob_type)), PyArray_DESCR(dest), &dtype); | |||
266 | if (ndim < 0) { | |||
267 | return -1; | |||
268 | } | |||
269 | ||||
270 | if (cache != NULL((void*)0) && !(cache->sequence)) { | |||
271 | /* The input is an array or array object, so assign directly */ | |||
272 | assert(cache->converted_obj == src_object)((void) (0)); | |||
273 | view = (PyArrayObject *)cache->arr_or_sequence; | |||
274 | Py_DECREF(dtype)_Py_DECREF(((PyObject*)(dtype))); | |||
275 | ret = PyArray_AssignArray(dest, view, NULL((void*)0), NPY_UNSAFE_CASTING); | |||
276 | npy_free_coercion_cache(cache); | |||
277 | return ret; | |||
278 | } | |||
279 | ||||
280 | /* | |||
281 | * We may need to broadcast, due to shape mismatches, in this case | |||
282 | * create a temporary array first, and assign that after filling | |||
283 | * it from the sequences/scalar. | |||
284 | */ | |||
285 | if (ndim != PyArray_NDIM(dest) || | |||
286 | !PyArray_CompareLists(PyArray_DIMS(dest), dims, ndim)) { | |||
287 | /* | |||
288 | * Broadcasting may be necessary, so assign to a view first. | |||
289 | * This branch could lead to a shape mismatch error later. | |||
290 | */ | |||
291 | assert (ndim <= PyArray_NDIM(dest))((void) (0)); /* would error during discovery */ | |||
292 | view = (PyArrayObject *) PyArray_NewFromDescr( | |||
293 | &PyArray_Type, dtype, ndim, dims, NULL((void*)0), NULL((void*)0), | |||
294 | PyArray_FLAGS(dest) & NPY_ARRAY_F_CONTIGUOUS0x0002, NULL((void*)0)); | |||
295 | if (view == NULL((void*)0)) { | |||
296 | npy_free_coercion_cache(cache); | |||
297 | return -1; | |||
298 | } | |||
299 | } | |||
300 | else { | |||
301 | Py_DECREF(dtype)_Py_DECREF(((PyObject*)(dtype))); | |||
302 | view = dest; | |||
303 | } | |||
304 | ||||
305 | /* Assign the values to `view` (whichever array that is) */ | |||
306 | if (cache == NULL((void*)0)) { | |||
307 | /* single (non-array) item, assign immediately */ | |||
308 | if (PyArray_Pack( | |||
309 | PyArray_DESCR(view), PyArray_DATA(view), src_object) < 0) { | |||
310 | goto fail; | |||
311 | } | |||
312 | } | |||
313 | else { | |||
314 | if (PyArray_AssignFromCache(view, cache) < 0) { | |||
315 | goto fail; | |||
316 | } | |||
317 | } | |||
318 | if (view == dest) { | |||
319 | return 0; | |||
320 | } | |||
321 | ret = PyArray_AssignArray(dest, view, NULL((void*)0), NPY_UNSAFE_CASTING); | |||
322 | Py_DECREF(view)_Py_DECREF(((PyObject*)(view))); | |||
323 | return ret; | |||
324 | ||||
325 | fail: | |||
326 | if (view != dest) { | |||
327 | Py_DECREF(view)_Py_DECREF(((PyObject*)(view))); | |||
328 | } | |||
329 | return -1; | |||
330 | } | |||
331 | ||||
332 | ||||
333 | /* returns an Array-Scalar Object of the type of arr | |||
334 | from the given pointer to memory -- main Scalar creation function | |||
335 | default new method calls this. | |||
336 | */ | |||
337 | ||||
338 | /* Ideally, here the descriptor would contain all the information needed. | |||
339 | So, that we simply need the data and the descriptor, and perhaps | |||
340 | a flag | |||
341 | */ | |||
342 | ||||
343 | ||||
344 | /* | |||
345 | Given a string return the type-number for | |||
346 | the data-type with that string as the type-object name. | |||
347 | Returns NPY_NOTYPE without setting an error if no type can be | |||
348 | found. Only works for user-defined data-types. | |||
349 | */ | |||
350 | ||||
351 | /*NUMPY_API | |||
352 | */ | |||
353 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
354 | PyArray_TypeNumFromName(char const *str) | |||
355 | { | |||
356 | int i; | |||
357 | PyArray_Descr *descr; | |||
358 | ||||
359 | for (i = 0; i < NPY_NUMUSERTYPES; i++) { | |||
360 | descr = userdescrs[i]; | |||
361 | if (strcmp(descr->typeobj->tp_name, str) == 0) { | |||
362 | return descr->type_num; | |||
363 | } | |||
364 | } | |||
365 | return NPY_NOTYPE; | |||
366 | } | |||
367 | ||||
368 | /*NUMPY_API | |||
369 | * | |||
370 | * If WRITEBACKIFCOPY and self has data, reset the base WRITEABLE flag, | |||
371 | * copy the local data to base, release the local data, and set flags | |||
372 | * appropriately. Return 0 if not relevant, 1 if success, < 0 on failure | |||
373 | */ | |||
374 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
375 | PyArray_ResolveWritebackIfCopy(PyArrayObject * self) | |||
376 | { | |||
377 | PyArrayObject_fields *fa = (PyArrayObject_fields *)self; | |||
378 | if (fa && fa->base) { | |||
379 | if ((fa->flags & NPY_ARRAY_UPDATEIFCOPY0x1000) || (fa->flags & NPY_ARRAY_WRITEBACKIFCOPY0x2000)) { | |||
380 | /* | |||
381 | * UPDATEIFCOPY or WRITEBACKIFCOPY means that fa->base's data | |||
382 | * should be updated with the contents | |||
383 | * of self. | |||
384 | * fa->base->flags is not WRITEABLE to protect the relationship | |||
385 | * unlock it. | |||
386 | */ | |||
387 | int retval = 0; | |||
388 | PyArray_ENABLEFLAGS(((PyArrayObject *)fa->base), | |||
389 | NPY_ARRAY_WRITEABLE0x0400); | |||
390 | PyArray_CLEARFLAGS(self, NPY_ARRAY_UPDATEIFCOPY0x1000); | |||
391 | PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEBACKIFCOPY0x2000); | |||
392 | retval = PyArray_CopyAnyInto((PyArrayObject *)fa->base, self); | |||
393 | Py_DECREF(fa->base)_Py_DECREF(((PyObject*)(fa->base))); | |||
394 | fa->base = NULL((void*)0); | |||
395 | if (retval < 0) { | |||
396 | /* this should never happen, how did the two copies of data | |||
397 | * get out of sync? | |||
398 | */ | |||
399 | return retval; | |||
400 | } | |||
401 | return 1; | |||
402 | } | |||
403 | } | |||
404 | return 0; | |||
405 | } | |||
406 | ||||
407 | /*********************** end C-API functions **********************/ | |||
408 | ||||
409 | ||||
410 | /* dealloc must not raise an error, best effort try to write | |||
411 | to stderr and clear the error | |||
412 | */ | |||
413 | ||||
414 | static NPY_INLINEinline void | |||
415 | WARN_IN_DEALLOC(PyObject* warning, const char * msg) { | |||
416 | if (PyErr_WarnEx(warning, msg, 1) < 0) { | |||
417 | PyObject * s; | |||
418 | ||||
419 | s = PyUnicode_FromString("array_dealloc"); | |||
420 | if (s) { | |||
421 | PyErr_WriteUnraisable(s); | |||
422 | Py_DECREF(s)_Py_DECREF(((PyObject*)(s))); | |||
423 | } | |||
424 | else { | |||
425 | PyErr_WriteUnraisable(Py_None(&_Py_NoneStruct)); | |||
426 | } | |||
427 | } | |||
428 | } | |||
429 | ||||
430 | /* array object functions */ | |||
431 | ||||
432 | static void | |||
433 | array_dealloc(PyArrayObject *self) | |||
434 | { | |||
435 | PyArrayObject_fields *fa = (PyArrayObject_fields *)self; | |||
436 | ||||
437 | if (_buffer_info_free(fa->_buffer_info, (PyObject *)self) < 0) { | |||
438 | PyErr_WriteUnraisable(NULL((void*)0)); | |||
439 | } | |||
440 | ||||
441 | if (fa->weakreflist != NULL((void*)0)) { | |||
442 | PyObject_ClearWeakRefs((PyObject *)self); | |||
443 | } | |||
444 | if (fa->base) { | |||
445 | int retval; | |||
446 | if (PyArray_FLAGS(self) & NPY_ARRAY_WRITEBACKIFCOPY0x2000) | |||
447 | { | |||
448 | char const * msg = "WRITEBACKIFCOPY detected in array_dealloc. " | |||
449 | " Required call to PyArray_ResolveWritebackIfCopy or " | |||
450 | "PyArray_DiscardWritebackIfCopy is missing."; | |||
451 | /* | |||
452 | * prevent reaching 0 twice and thus recursing into dealloc. | |||
453 | * Increasing sys.gettotalrefcount, but path should not be taken. | |||
454 | */ | |||
455 | Py_INCREF(self)_Py_INCREF(((PyObject*)(self))); | |||
456 | WARN_IN_DEALLOC(PyExc_RuntimeWarning, msg); | |||
457 | retval = PyArray_ResolveWritebackIfCopy(self); | |||
458 | if (retval < 0) | |||
459 | { | |||
460 | PyErr_Print(); | |||
461 | PyErr_Clear(); | |||
462 | } | |||
463 | } | |||
464 | if (PyArray_FLAGS(self) & NPY_ARRAY_UPDATEIFCOPY0x1000) { | |||
465 | /* DEPRECATED, remove once the flag is removed */ | |||
466 | char const * msg = "UPDATEIFCOPY detected in array_dealloc. " | |||
467 | " Required call to PyArray_ResolveWritebackIfCopy or " | |||
468 | "PyArray_DiscardWritebackIfCopy is missing"; | |||
469 | /* | |||
470 | * prevent reaching 0 twice and thus recursing into dealloc. | |||
471 | * Increasing sys.gettotalrefcount, but path should not be taken. | |||
472 | */ | |||
473 | Py_INCREF(self)_Py_INCREF(((PyObject*)(self))); | |||
474 | /* 2017-Nov-10 1.14 */ | |||
475 | WARN_IN_DEALLOC(PyExc_DeprecationWarning, msg); | |||
476 | retval = PyArray_ResolveWritebackIfCopy(self); | |||
477 | if (retval < 0) | |||
478 | { | |||
479 | PyErr_Print(); | |||
480 | PyErr_Clear(); | |||
481 | } | |||
482 | } | |||
483 | /* | |||
484 | * If fa->base is non-NULL, it is something | |||
485 | * to DECREF -- either a view or a buffer object | |||
486 | */ | |||
487 | Py_XDECREF(fa->base)_Py_XDECREF(((PyObject*)(fa->base))); | |||
488 | } | |||
489 | ||||
490 | if ((fa->flags & NPY_ARRAY_OWNDATA0x0004) && fa->data) { | |||
491 | /* Free internal references if an Object array */ | |||
492 | if (PyDataType_FLAGCHK(fa->descr, NPY_ITEM_REFCOUNT)(((fa->descr)->flags & (0x01)) == (0x01))) { | |||
493 | PyArray_XDECREF(self); | |||
494 | } | |||
495 | npy_free_cache(fa->data, PyArray_NBYTES(self)(PyArray_ITEMSIZE(self) * PyArray_MultiplyList(PyArray_DIMS(self ), PyArray_NDIM(self)))); | |||
496 | } | |||
497 | ||||
498 | /* must match allocation in PyArray_NewFromDescr */ | |||
499 | npy_free_cache_dim(fa->dimensions, 2 * fa->nd); | |||
500 | Py_DECREF(fa->descr)_Py_DECREF(((PyObject*)(fa->descr))); | |||
501 | Py_TYPE(self)(((PyObject*)(self))->ob_type)->tp_free((PyObject *)self); | |||
502 | } | |||
503 | ||||
504 | /*NUMPY_API | |||
505 | * Prints the raw data of the ndarray in a form useful for debugging | |||
506 | * low-level C issues. | |||
507 | */ | |||
508 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) void | |||
509 | PyArray_DebugPrint(PyArrayObject *obj) | |||
510 | { | |||
511 | int i; | |||
512 | PyArrayObject_fields *fobj = (PyArrayObject_fields *)obj; | |||
513 | ||||
514 | printf("-------------------------------------------------------\n")__printf_chk (2 - 1, "-------------------------------------------------------\n" ); | |||
515 | printf(" Dump of NumPy ndarray at address %p\n", obj)__printf_chk (2 - 1, " Dump of NumPy ndarray at address %p\n" , obj); | |||
516 | if (obj == NULL((void*)0)) { | |||
517 | printf(" It's NULL!\n")__printf_chk (2 - 1, " It's NULL!\n"); | |||
518 | printf("-------------------------------------------------------\n")__printf_chk (2 - 1, "-------------------------------------------------------\n" ); | |||
519 | fflush(stdoutstdout); | |||
520 | return; | |||
521 | } | |||
522 | printf(" ndim : %d\n", fobj->nd)__printf_chk (2 - 1, " ndim : %d\n", fobj->nd); | |||
523 | printf(" shape :")__printf_chk (2 - 1, " shape :"); | |||
524 | for (i = 0; i < fobj->nd; ++i) { | |||
525 | printf(" %" NPY_INTP_FMT, fobj->dimensions[i])__printf_chk (2 - 1, " %" "ld", fobj->dimensions[i]); | |||
526 | } | |||
527 | printf("\n")__printf_chk (2 - 1, "\n"); | |||
528 | ||||
529 | printf(" dtype : ")__printf_chk (2 - 1, " dtype : "); | |||
530 | PyObject_Print((PyObject *)fobj->descr, stdoutstdout, 0); | |||
531 | printf("\n")__printf_chk (2 - 1, "\n"); | |||
532 | printf(" data : %p\n", fobj->data)__printf_chk (2 - 1, " data : %p\n", fobj->data); | |||
533 | printf(" strides:")__printf_chk (2 - 1, " strides:"); | |||
534 | for (i = 0; i < fobj->nd; ++i) { | |||
535 | printf(" %" NPY_INTP_FMT, fobj->strides[i])__printf_chk (2 - 1, " %" "ld", fobj->strides[i]); | |||
536 | } | |||
537 | printf("\n")__printf_chk (2 - 1, "\n"); | |||
538 | ||||
539 | printf(" base : %p\n", fobj->base)__printf_chk (2 - 1, " base : %p\n", fobj->base); | |||
540 | ||||
541 | printf(" flags :")__printf_chk (2 - 1, " flags :"); | |||
542 | if (fobj->flags & NPY_ARRAY_C_CONTIGUOUS0x0001) | |||
543 | printf(" NPY_C_CONTIGUOUS")__printf_chk (2 - 1, " NPY_C_CONTIGUOUS"); | |||
544 | if (fobj->flags & NPY_ARRAY_F_CONTIGUOUS0x0002) | |||
545 | printf(" NPY_F_CONTIGUOUS")__printf_chk (2 - 1, " NPY_F_CONTIGUOUS"); | |||
546 | if (fobj->flags & NPY_ARRAY_OWNDATA0x0004) | |||
547 | printf(" NPY_OWNDATA")__printf_chk (2 - 1, " NPY_OWNDATA"); | |||
548 | if (fobj->flags & NPY_ARRAY_ALIGNED0x0100) | |||
549 | printf(" NPY_ALIGNED")__printf_chk (2 - 1, " NPY_ALIGNED"); | |||
550 | if (fobj->flags & NPY_ARRAY_WRITEABLE0x0400) | |||
551 | printf(" NPY_WRITEABLE")__printf_chk (2 - 1, " NPY_WRITEABLE"); | |||
552 | if (fobj->flags & NPY_ARRAY_UPDATEIFCOPY0x1000) | |||
553 | printf(" NPY_UPDATEIFCOPY")__printf_chk (2 - 1, " NPY_UPDATEIFCOPY"); | |||
554 | if (fobj->flags & NPY_ARRAY_WRITEBACKIFCOPY0x2000) | |||
555 | printf(" NPY_WRITEBACKIFCOPY")__printf_chk (2 - 1, " NPY_WRITEBACKIFCOPY"); | |||
556 | printf("\n")__printf_chk (2 - 1, "\n"); | |||
557 | ||||
558 | if (fobj->base != NULL((void*)0) && PyArray_Check(fobj->base)((((PyObject*)(fobj->base))->ob_type) == (&PyArray_Type ) || PyType_IsSubtype((((PyObject*)(fobj->base))->ob_type ), (&PyArray_Type)))) { | |||
559 | printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n")__printf_chk (2 - 1, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n" ); | |||
560 | printf("Dump of array's BASE:\n")__printf_chk (2 - 1, "Dump of array's BASE:\n"); | |||
561 | PyArray_DebugPrint((PyArrayObject *)fobj->base); | |||
562 | printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n")__printf_chk (2 - 1, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" ); | |||
563 | } | |||
564 | printf("-------------------------------------------------------\n")__printf_chk (2 - 1, "-------------------------------------------------------\n" ); | |||
565 | fflush(stdoutstdout); | |||
566 | } | |||
567 | ||||
568 | ||||
569 | /*NUMPY_API | |||
570 | * This function is scheduled to be removed | |||
571 | * | |||
572 | * TO BE REMOVED - NOT USED INTERNALLY. | |||
573 | */ | |||
574 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) void | |||
575 | PyArray_SetDatetimeParseFunction(PyObject *NPY_UNUSED(op)(__NPY_UNUSED_TAGGEDop) __attribute__ ((__unused__))) | |||
576 | { | |||
577 | } | |||
578 | ||||
579 | /*NUMPY_API | |||
580 | */ | |||
581 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
582 | PyArray_CompareUCS4(npy_ucs4 const *s1, npy_ucs4 const *s2, size_t len) | |||
583 | { | |||
584 | npy_ucs4 c1, c2; | |||
585 | while(len-- > 0) { | |||
586 | c1 = *s1++; | |||
587 | c2 = *s2++; | |||
588 | if (c1 != c2) { | |||
589 | return (c1 < c2) ? -1 : 1; | |||
590 | } | |||
591 | } | |||
592 | return 0; | |||
593 | } | |||
594 | ||||
595 | /*NUMPY_API | |||
596 | */ | |||
597 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
598 | PyArray_CompareString(const char *s1, const char *s2, size_t len) | |||
599 | { | |||
600 | const unsigned char *c1 = (unsigned char *)s1; | |||
601 | const unsigned char *c2 = (unsigned char *)s2; | |||
602 | size_t i; | |||
603 | ||||
604 | for(i = 0; i < len; ++i) { | |||
605 | if (c1[i] != c2[i]) { | |||
606 | return (c1[i] > c2[i]) ? 1 : -1; | |||
607 | } | |||
608 | } | |||
609 | return 0; | |||
610 | } | |||
611 | ||||
612 | ||||
613 | /* Call this from contexts where an array might be written to, but we have no | |||
614 | * way to tell. (E.g., when converting to a read-write buffer.) | |||
615 | */ | |||
616 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
617 | array_might_be_written(PyArrayObject *obj) | |||
618 | { | |||
619 | const char *msg = | |||
620 | "Numpy has detected that you (may be) writing to an array with\n" | |||
621 | "overlapping memory from np.broadcast_arrays. If this is intentional\n" | |||
622 | "set the WRITEABLE flag True or make a copy immediately before writing."; | |||
623 | if (PyArray_FLAGS(obj) & NPY_ARRAY_WARN_ON_WRITE) { | |||
624 | if (DEPRECATE(msg)PyErr_WarnEx(PyExc_DeprecationWarning,msg,1) < 0) { | |||
625 | return -1; | |||
626 | } | |||
627 | /* Only warn once per array */ | |||
628 | while (1) { | |||
629 | PyArray_CLEARFLAGS(obj, NPY_ARRAY_WARN_ON_WRITE); | |||
630 | if (!PyArray_BASE(obj) || !PyArray_Check(PyArray_BASE(obj))((((PyObject*)(PyArray_BASE(obj)))->ob_type) == (&PyArray_Type ) || PyType_IsSubtype((((PyObject*)(PyArray_BASE(obj)))->ob_type ), (&PyArray_Type)))) { | |||
631 | break; | |||
632 | } | |||
633 | obj = (PyArrayObject *)PyArray_BASE(obj); | |||
634 | } | |||
635 | } | |||
636 | return 0; | |||
637 | } | |||
638 | ||||
639 | /*NUMPY_API | |||
640 | * | |||
641 | * This function does nothing if obj is writeable, and raises an exception | |||
642 | * (and returns -1) if obj is not writeable. It may also do other | |||
643 | * house-keeping, such as issuing warnings on arrays which are transitioning | |||
644 | * to become views. Always call this function at some point before writing to | |||
645 | * an array. | |||
646 | * | |||
647 | * 'name' is a name for the array, used to give better error | |||
648 | * messages. Something like "assignment destination", "output array", or even | |||
649 | * just "array". | |||
650 | */ | |||
651 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
652 | PyArray_FailUnlessWriteable(PyArrayObject *obj, const char *name) | |||
653 | { | |||
654 | if (!PyArray_ISWRITEABLE(obj)PyArray_CHKFLAGS((obj), 0x0400)) { | |||
655 | PyErr_Format(PyExc_ValueError, "%s is read-only", name); | |||
656 | return -1; | |||
657 | } | |||
658 | if (array_might_be_written(obj) < 0) { | |||
659 | return -1; | |||
660 | } | |||
661 | return 0; | |||
662 | } | |||
663 | ||||
664 | /* This also handles possibly mis-aligned data */ | |||
665 | /* Compare s1 and s2 which are not necessarily NULL-terminated. | |||
666 | s1 is of length len1 | |||
667 | s2 is of length len2 | |||
668 | If they are NULL terminated, then stop comparison. | |||
669 | */ | |||
670 | static int | |||
671 | _myunincmp(npy_ucs4 const *s1, npy_ucs4 const *s2, int len1, int len2) | |||
672 | { | |||
673 | npy_ucs4 const *sptr; | |||
674 | npy_ucs4 *s1t = NULL((void*)0); | |||
675 | npy_ucs4 *s2t = NULL((void*)0); | |||
676 | int val; | |||
677 | npy_intp size; | |||
678 | int diff; | |||
679 | ||||
680 | /* Replace `s1` and `s2` with aligned copies if needed */ | |||
681 | if ((npy_intp)s1 % sizeof(npy_ucs4) != 0) { | |||
682 | size = len1*sizeof(npy_ucs4); | |||
683 | s1t = malloc(size); | |||
684 | memcpy(s1t, s1, size); | |||
685 | s1 = s1t; | |||
686 | } | |||
687 | if ((npy_intp)s2 % sizeof(npy_ucs4) != 0) { | |||
688 | size = len2*sizeof(npy_ucs4); | |||
689 | s2t = malloc(size); | |||
690 | memcpy(s2t, s2, size); | |||
691 | s2 = s1t; | |||
692 | } | |||
693 | ||||
694 | val = PyArray_CompareUCS4(s1, s2, PyArray_MIN(len1,len2)(((len1)<(len2))?(len1):(len2))); | |||
695 | if ((val != 0) || (len1 == len2)) { | |||
696 | goto finish; | |||
697 | } | |||
698 | if (len2 > len1) { | |||
699 | sptr = s2+len1; | |||
700 | val = -1; | |||
701 | diff = len2-len1; | |||
702 | } | |||
703 | else { | |||
704 | sptr = s1+len2; | |||
705 | val = 1; | |||
706 | diff=len1-len2; | |||
707 | } | |||
708 | while (diff--) { | |||
709 | if (*sptr != 0) { | |||
710 | goto finish; | |||
711 | } | |||
712 | sptr++; | |||
713 | } | |||
714 | val = 0; | |||
715 | ||||
716 | finish: | |||
717 | /* Cleanup the aligned copies */ | |||
718 | if (s1t) { | |||
719 | free(s1t); | |||
720 | } | |||
721 | if (s2t) { | |||
722 | free(s2t); | |||
723 | } | |||
724 | return val; | |||
725 | } | |||
726 | ||||
727 | ||||
728 | ||||
729 | ||||
730 | /* | |||
731 | * Compare s1 and s2 which are not necessarily NULL-terminated. | |||
732 | * s1 is of length len1 | |||
733 | * s2 is of length len2 | |||
734 | * If they are NULL terminated, then stop comparison. | |||
735 | */ | |||
736 | static int | |||
737 | _mystrncmp(char const *s1, char const *s2, int len1, int len2) | |||
738 | { | |||
739 | char const *sptr; | |||
740 | int val; | |||
741 | int diff; | |||
742 | ||||
743 | val = memcmp(s1, s2, PyArray_MIN(len1, len2)(((len1)<(len2))?(len1):(len2))); | |||
744 | if ((val != 0) || (len1 == len2)) { | |||
745 | return val; | |||
746 | } | |||
747 | if (len2 > len1) { | |||
748 | sptr = s2 + len1; | |||
749 | val = -1; | |||
750 | diff = len2 - len1; | |||
751 | } | |||
752 | else { | |||
753 | sptr = s1 + len2; | |||
754 | val = 1; | |||
755 | diff = len1 - len2; | |||
756 | } | |||
757 | while (diff--) { | |||
758 | if (*sptr != 0) { | |||
759 | return val; | |||
760 | } | |||
761 | sptr++; | |||
762 | } | |||
763 | return 0; /* Only happens if NULLs are everywhere */ | |||
764 | } | |||
765 | ||||
766 | /* Borrowed from Numarray */ | |||
767 | ||||
768 | #define SMALL_STRING 2048 | |||
769 | ||||
770 | static void _rstripw(char *s, int n) | |||
771 | { | |||
772 | int i; | |||
773 | for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */ | |||
774 | int c = s[i]; | |||
775 | ||||
776 | if (!c || NumPyOS_ascii_isspace((int)c)) { | |||
777 | s[i] = 0; | |||
778 | } | |||
779 | else { | |||
780 | break; | |||
781 | } | |||
782 | } | |||
783 | } | |||
784 | ||||
785 | static void _unistripw(npy_ucs4 *s, int n) | |||
786 | { | |||
787 | int i; | |||
788 | for (i = n - 1; i >= 1; i--) { /* Never strip to length 0. */ | |||
789 | npy_ucs4 c = s[i]; | |||
790 | if (!c || NumPyOS_ascii_isspace((int)c)) { | |||
791 | s[i] = 0; | |||
792 | } | |||
793 | else { | |||
794 | break; | |||
795 | } | |||
796 | } | |||
797 | } | |||
798 | ||||
799 | ||||
800 | static char * | |||
801 | _char_copy_n_strip(char const *original, char *temp, int nc) | |||
802 | { | |||
803 | if (nc > SMALL_STRING) { | |||
804 | temp = malloc(nc); | |||
805 | if (!temp) { | |||
806 | PyErr_NoMemory(); | |||
807 | return NULL((void*)0); | |||
808 | } | |||
809 | } | |||
810 | memcpy(temp, original, nc); | |||
811 | _rstripw(temp, nc); | |||
812 | return temp; | |||
813 | } | |||
814 | ||||
815 | static void | |||
816 | _char_release(char *ptr, int nc) | |||
817 | { | |||
818 | if (nc > SMALL_STRING) { | |||
819 | free(ptr); | |||
820 | } | |||
821 | } | |||
822 | ||||
823 | static char * | |||
824 | _uni_copy_n_strip(char const *original, char *temp, int nc) | |||
825 | { | |||
826 | if (nc*sizeof(npy_ucs4) > SMALL_STRING) { | |||
827 | temp = malloc(nc*sizeof(npy_ucs4)); | |||
828 | if (!temp) { | |||
829 | PyErr_NoMemory(); | |||
830 | return NULL((void*)0); | |||
831 | } | |||
832 | } | |||
833 | memcpy(temp, original, nc*sizeof(npy_ucs4)); | |||
834 | _unistripw((npy_ucs4 *)temp, nc); | |||
835 | return temp; | |||
836 | } | |||
837 | ||||
838 | static void | |||
839 | _uni_release(char *ptr, int nc) | |||
840 | { | |||
841 | if (nc*sizeof(npy_ucs4) > SMALL_STRING) { | |||
842 | free(ptr); | |||
843 | } | |||
844 | } | |||
845 | ||||
846 | ||||
847 | /* End borrowed from numarray */ | |||
848 | ||||
849 | #define _rstrip_loop(CMP) { \ | |||
850 | void *aptr, *bptr; \ | |||
851 | char atemp[SMALL_STRING], btemp[SMALL_STRING]; \ | |||
852 | while(size--) { \ | |||
853 | aptr = stripfunc(iself->dataptr, atemp, N1); \ | |||
854 | if (!aptr) return -1; \ | |||
855 | bptr = stripfunc(iother->dataptr, btemp, N2); \ | |||
856 | if (!bptr) { \ | |||
857 | relfunc(aptr, N1); \ | |||
858 | return -1; \ | |||
859 | } \ | |||
860 | val = compfunc(aptr, bptr, N1, N2); \ | |||
861 | *dptr = (val CMP 0); \ | |||
862 | PyArray_ITER_NEXT(iself)do { ((PyArrayIterObject *)(iself))->index++; if (((PyArrayIterObject *)(iself))->nd_m1 == 0) { do { (((PyArrayIterObject *)(iself )))->dataptr += ((PyArrayIterObject *)(((PyArrayIterObject *)(iself))))->strides[0]; (((PyArrayIterObject *)(iself)) )->coordinates[0]++; } while (0); } else if (((PyArrayIterObject *)(iself))->contiguous) ((PyArrayIterObject *)(iself))-> dataptr += PyArray_DESCR(((PyArrayIterObject *)(iself))->ao )->elsize; else if (((PyArrayIterObject *)(iself))->nd_m1 == 1) { do { if ((((PyArrayIterObject *)(iself)))->coordinates [1] < (((PyArrayIterObject *)(iself)))->dims_m1[1]) { ( ((PyArrayIterObject *)(iself)))->coordinates[1]++; (((PyArrayIterObject *)(iself)))->dataptr += (((PyArrayIterObject *)(iself)))-> strides[1]; } else { (((PyArrayIterObject *)(iself)))->coordinates [1] = 0; (((PyArrayIterObject *)(iself)))->coordinates[0]++ ; (((PyArrayIterObject *)(iself)))->dataptr += (((PyArrayIterObject *)(iself)))->strides[0] - (((PyArrayIterObject *)(iself)) )->backstrides[1]; } } while (0); } else { int __npy_i; for (__npy_i=((PyArrayIterObject *)(iself))->nd_m1; __npy_i >= 0; __npy_i--) { if (((PyArrayIterObject *)(iself))->coordinates [__npy_i] < ((PyArrayIterObject *)(iself))->dims_m1[__npy_i ]) { ((PyArrayIterObject *)(iself))->coordinates[__npy_i]++ ; ((PyArrayIterObject *)(iself))->dataptr += ((PyArrayIterObject *)(iself))->strides[__npy_i]; break; } else { ((PyArrayIterObject *)(iself))->coordinates[__npy_i] = 0; ((PyArrayIterObject *)(iself))->dataptr -= ((PyArrayIterObject *)(iself))-> backstrides[__npy_i]; } } } } while (0); \ | |||
863 | PyArray_ITER_NEXT(iother)do { ((PyArrayIterObject *)(iother))->index++; if (((PyArrayIterObject *)(iother))->nd_m1 == 0) { do { (((PyArrayIterObject *)(iother )))->dataptr += ((PyArrayIterObject *)(((PyArrayIterObject *)(iother))))->strides[0]; (((PyArrayIterObject *)(iother )))->coordinates[0]++; } while (0); } else if (((PyArrayIterObject *)(iother))->contiguous) ((PyArrayIterObject *)(iother))-> dataptr += PyArray_DESCR(((PyArrayIterObject *)(iother))-> ao)->elsize; else if (((PyArrayIterObject *)(iother))-> nd_m1 == 1) { do { if ((((PyArrayIterObject *)(iother)))-> coordinates[1] < (((PyArrayIterObject *)(iother)))->dims_m1 [1]) { (((PyArrayIterObject *)(iother)))->coordinates[1]++ ; (((PyArrayIterObject *)(iother)))->dataptr += (((PyArrayIterObject *)(iother)))->strides[1]; } else { (((PyArrayIterObject * )(iother)))->coordinates[1] = 0; (((PyArrayIterObject *)(iother )))->coordinates[0]++; (((PyArrayIterObject *)(iother)))-> dataptr += (((PyArrayIterObject *)(iother)))->strides[0] - (((PyArrayIterObject *)(iother)))->backstrides[1]; } } while (0); } else { int __npy_i; for (__npy_i=((PyArrayIterObject * )(iother))->nd_m1; __npy_i >= 0; __npy_i--) { if (((PyArrayIterObject *)(iother))->coordinates[__npy_i] < ((PyArrayIterObject *)(iother))->dims_m1[__npy_i]) { ((PyArrayIterObject *)(iother ))->coordinates[__npy_i]++; ((PyArrayIterObject *)(iother) )->dataptr += ((PyArrayIterObject *)(iother))->strides[ __npy_i]; break; } else { ((PyArrayIterObject *)(iother))-> coordinates[__npy_i] = 0; ((PyArrayIterObject *)(iother))-> dataptr -= ((PyArrayIterObject *)(iother))->backstrides[__npy_i ]; } } } } while (0); \ | |||
864 | dptr += 1; \ | |||
865 | relfunc(aptr, N1); \ | |||
866 | relfunc(bptr, N2); \ | |||
867 | } \ | |||
868 | } | |||
869 | ||||
870 | #define _reg_loop(CMP) { \ | |||
871 | while(size--) { \ | |||
872 | val = compfunc((void *)iself->dataptr, \ | |||
873 | (void *)iother->dataptr, \ | |||
874 | N1, N2); \ | |||
875 | *dptr = (val CMP 0); \ | |||
876 | PyArray_ITER_NEXT(iself)do { ((PyArrayIterObject *)(iself))->index++; if (((PyArrayIterObject *)(iself))->nd_m1 == 0) { do { (((PyArrayIterObject *)(iself )))->dataptr += ((PyArrayIterObject *)(((PyArrayIterObject *)(iself))))->strides[0]; (((PyArrayIterObject *)(iself)) )->coordinates[0]++; } while (0); } else if (((PyArrayIterObject *)(iself))->contiguous) ((PyArrayIterObject *)(iself))-> dataptr += PyArray_DESCR(((PyArrayIterObject *)(iself))->ao )->elsize; else if (((PyArrayIterObject *)(iself))->nd_m1 == 1) { do { if ((((PyArrayIterObject *)(iself)))->coordinates [1] < (((PyArrayIterObject *)(iself)))->dims_m1[1]) { ( ((PyArrayIterObject *)(iself)))->coordinates[1]++; (((PyArrayIterObject *)(iself)))->dataptr += (((PyArrayIterObject *)(iself)))-> strides[1]; } else { (((PyArrayIterObject *)(iself)))->coordinates [1] = 0; (((PyArrayIterObject *)(iself)))->coordinates[0]++ ; (((PyArrayIterObject *)(iself)))->dataptr += (((PyArrayIterObject *)(iself)))->strides[0] - (((PyArrayIterObject *)(iself)) )->backstrides[1]; } } while (0); } else { int __npy_i; for (__npy_i=((PyArrayIterObject *)(iself))->nd_m1; __npy_i >= 0; __npy_i--) { if (((PyArrayIterObject *)(iself))->coordinates [__npy_i] < ((PyArrayIterObject *)(iself))->dims_m1[__npy_i ]) { ((PyArrayIterObject *)(iself))->coordinates[__npy_i]++ ; ((PyArrayIterObject *)(iself))->dataptr += ((PyArrayIterObject *)(iself))->strides[__npy_i]; break; } else { ((PyArrayIterObject *)(iself))->coordinates[__npy_i] = 0; ((PyArrayIterObject *)(iself))->dataptr -= ((PyArrayIterObject *)(iself))-> backstrides[__npy_i]; } } } } while (0); \ | |||
877 | PyArray_ITER_NEXT(iother)do { ((PyArrayIterObject *)(iother))->index++; if (((PyArrayIterObject *)(iother))->nd_m1 == 0) { do { (((PyArrayIterObject *)(iother )))->dataptr += ((PyArrayIterObject *)(((PyArrayIterObject *)(iother))))->strides[0]; (((PyArrayIterObject *)(iother )))->coordinates[0]++; } while (0); } else if (((PyArrayIterObject *)(iother))->contiguous) ((PyArrayIterObject *)(iother))-> dataptr += PyArray_DESCR(((PyArrayIterObject *)(iother))-> ao)->elsize; else if (((PyArrayIterObject *)(iother))-> nd_m1 == 1) { do { if ((((PyArrayIterObject *)(iother)))-> coordinates[1] < (((PyArrayIterObject *)(iother)))->dims_m1 [1]) { (((PyArrayIterObject *)(iother)))->coordinates[1]++ ; (((PyArrayIterObject *)(iother)))->dataptr += (((PyArrayIterObject *)(iother)))->strides[1]; } else { (((PyArrayIterObject * )(iother)))->coordinates[1] = 0; (((PyArrayIterObject *)(iother )))->coordinates[0]++; (((PyArrayIterObject *)(iother)))-> dataptr += (((PyArrayIterObject *)(iother)))->strides[0] - (((PyArrayIterObject *)(iother)))->backstrides[1]; } } while (0); } else { int __npy_i; for (__npy_i=((PyArrayIterObject * )(iother))->nd_m1; __npy_i >= 0; __npy_i--) { if (((PyArrayIterObject *)(iother))->coordinates[__npy_i] < ((PyArrayIterObject *)(iother))->dims_m1[__npy_i]) { ((PyArrayIterObject *)(iother ))->coordinates[__npy_i]++; ((PyArrayIterObject *)(iother) )->dataptr += ((PyArrayIterObject *)(iother))->strides[ __npy_i]; break; } else { ((PyArrayIterObject *)(iother))-> coordinates[__npy_i] = 0; ((PyArrayIterObject *)(iother))-> dataptr -= ((PyArrayIterObject *)(iother))->backstrides[__npy_i ]; } } } } while (0); \ | |||
878 | dptr += 1; \ | |||
879 | } \ | |||
880 | } | |||
881 | ||||
882 | static int | |||
883 | _compare_strings(PyArrayObject *result, PyArrayMultiIterObject *multi, | |||
884 | int cmp_op, void *func, int rstrip) | |||
885 | { | |||
886 | PyArrayIterObject *iself, *iother; | |||
887 | npy_bool *dptr; | |||
888 | npy_intp size; | |||
889 | int val; | |||
890 | int N1, N2; | |||
891 | int (*compfunc)(void *, void *, int, int); | |||
892 | void (*relfunc)(char *, int); | |||
893 | char* (*stripfunc)(char const *, char *, int); | |||
894 | ||||
895 | compfunc = func; | |||
896 | dptr = (npy_bool *)PyArray_DATA(result); | |||
897 | iself = multi->iters[0]; | |||
898 | iother = multi->iters[1]; | |||
899 | size = multi->size; | |||
900 | N1 = PyArray_DESCR(iself->ao)->elsize; | |||
901 | N2 = PyArray_DESCR(iother->ao)->elsize; | |||
902 | if ((void *)compfunc == (void *)_myunincmp) { | |||
903 | N1 >>= 2; | |||
904 | N2 >>= 2; | |||
905 | stripfunc = _uni_copy_n_strip; | |||
906 | relfunc = _uni_release; | |||
907 | } | |||
908 | else { | |||
909 | stripfunc = _char_copy_n_strip; | |||
910 | relfunc = _char_release; | |||
911 | } | |||
912 | switch (cmp_op) { | |||
913 | case Py_EQ2: | |||
914 | if (rstrip) { | |||
915 | _rstrip_loop(==); | |||
916 | } else { | |||
917 | _reg_loop(==); | |||
918 | } | |||
919 | break; | |||
920 | case Py_NE3: | |||
921 | if (rstrip) { | |||
922 | _rstrip_loop(!=); | |||
923 | } else { | |||
924 | _reg_loop(!=); | |||
925 | } | |||
926 | break; | |||
927 | case Py_LT0: | |||
928 | if (rstrip) { | |||
929 | _rstrip_loop(<); | |||
930 | } else { | |||
931 | _reg_loop(<); | |||
932 | } | |||
933 | break; | |||
934 | case Py_LE1: | |||
935 | if (rstrip) { | |||
936 | _rstrip_loop(<=); | |||
937 | } else { | |||
938 | _reg_loop(<=); | |||
939 | } | |||
940 | break; | |||
941 | case Py_GT4: | |||
942 | if (rstrip) { | |||
943 | _rstrip_loop(>); | |||
944 | } else { | |||
945 | _reg_loop(>); | |||
946 | } | |||
947 | break; | |||
948 | case Py_GE5: | |||
949 | if (rstrip) { | |||
950 | _rstrip_loop(>=); | |||
951 | } else { | |||
952 | _reg_loop(>=); | |||
953 | } | |||
954 | break; | |||
955 | default: | |||
956 | PyErr_SetString(PyExc_RuntimeError, "bad comparison operator"); | |||
957 | return -1; | |||
958 | } | |||
959 | return 0; | |||
960 | } | |||
961 | ||||
962 | #undef _reg_loop | |||
963 | #undef _rstrip_loop | |||
964 | #undef SMALL_STRING | |||
965 | ||||
966 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | |||
967 | _strings_richcompare(PyArrayObject *self, PyArrayObject *other, int cmp_op, | |||
968 | int rstrip) | |||
969 | { | |||
970 | PyArrayObject *result; | |||
971 | PyArrayMultiIterObject *mit; | |||
972 | int val; | |||
973 | ||||
974 | /* Cast arrays to a common type */ | |||
975 | if (PyArray_TYPE(self) != PyArray_DESCR(other)->type_num) { | |||
976 | /* | |||
977 | * Comparison between Bytes and Unicode is not defined in Py3K; | |||
978 | * we follow. | |||
979 | */ | |||
980 | Py_INCREF(Py_NotImplemented)_Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct)))); | |||
981 | return Py_NotImplemented(&_Py_NotImplementedStruct); | |||
982 | } | |||
983 | if (PyArray_ISNOTSWAPPED(self)((PyArray_DESCR(self)->byteorder) != '>') != PyArray_ISNOTSWAPPED(other)((PyArray_DESCR(other)->byteorder) != '>')) { | |||
984 | PyObject *new; | |||
985 | if (PyArray_TYPE(self) == NPY_STRING && | |||
986 | PyArray_DESCR(other)->type_num == NPY_UNICODE) { | |||
987 | PyArray_Descr* unicode = PyArray_DescrNew(PyArray_DESCR(other)); | |||
988 | unicode->elsize = PyArray_DESCR(self)->elsize << 2; | |||
989 | new = PyArray_FromAny((PyObject *)self, unicode, | |||
990 | 0, 0, 0, NULL((void*)0)); | |||
991 | if (new == NULL((void*)0)) { | |||
992 | return NULL((void*)0); | |||
993 | } | |||
994 | Py_INCREF(other)_Py_INCREF(((PyObject*)(other))); | |||
995 | self = (PyArrayObject *)new; | |||
996 | } | |||
997 | else if ((PyArray_TYPE(self) == NPY_UNICODE) && | |||
998 | ((PyArray_DESCR(other)->type_num == NPY_STRING) || | |||
999 | (PyArray_ISNOTSWAPPED(self)((PyArray_DESCR(self)->byteorder) != '>') != PyArray_ISNOTSWAPPED(other)((PyArray_DESCR(other)->byteorder) != '>')))) { | |||
1000 | PyArray_Descr* unicode = PyArray_DescrNew(PyArray_DESCR(self)); | |||
1001 | ||||
1002 | if (PyArray_DESCR(other)->type_num == NPY_STRING) { | |||
1003 | unicode->elsize = PyArray_DESCR(other)->elsize << 2; | |||
1004 | } | |||
1005 | else { | |||
1006 | unicode->elsize = PyArray_DESCR(other)->elsize; | |||
1007 | } | |||
1008 | new = PyArray_FromAny((PyObject *)other, unicode, | |||
1009 | 0, 0, 0, NULL((void*)0)); | |||
1010 | if (new == NULL((void*)0)) { | |||
1011 | return NULL((void*)0); | |||
1012 | } | |||
1013 | Py_INCREF(self)_Py_INCREF(((PyObject*)(self))); | |||
1014 | other = (PyArrayObject *)new; | |||
1015 | } | |||
1016 | else { | |||
1017 | PyErr_SetString(PyExc_TypeError, | |||
1018 | "invalid string data-types " | |||
1019 | "in comparison"); | |||
1020 | return NULL((void*)0); | |||
1021 | } | |||
1022 | } | |||
1023 | else { | |||
1024 | Py_INCREF(self)_Py_INCREF(((PyObject*)(self))); | |||
1025 | Py_INCREF(other)_Py_INCREF(((PyObject*)(other))); | |||
1026 | } | |||
1027 | ||||
1028 | /* Broad-cast the arrays to a common shape */ | |||
1029 | mit = (PyArrayMultiIterObject *)PyArray_MultiIterNew(2, self, other); | |||
1030 | Py_DECREF(self)_Py_DECREF(((PyObject*)(self))); | |||
1031 | Py_DECREF(other)_Py_DECREF(((PyObject*)(other))); | |||
1032 | if (mit == NULL((void*)0)) { | |||
1033 | return NULL((void*)0); | |||
1034 | } | |||
1035 | ||||
1036 | result = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, | |||
1037 | PyArray_DescrFromType(NPY_BOOL), | |||
1038 | mit->nd, | |||
1039 | mit->dimensions, | |||
1040 | NULL((void*)0), NULL((void*)0), 0, | |||
1041 | NULL((void*)0)); | |||
1042 | if (result == NULL((void*)0)) { | |||
1043 | goto finish; | |||
1044 | } | |||
1045 | ||||
1046 | if (PyArray_TYPE(self) == NPY_UNICODE) { | |||
1047 | val = _compare_strings(result, mit, cmp_op, _myunincmp, rstrip); | |||
1048 | } | |||
1049 | else { | |||
1050 | val = _compare_strings(result, mit, cmp_op, _mystrncmp, rstrip); | |||
1051 | } | |||
1052 | ||||
1053 | if (val < 0) { | |||
1054 | Py_DECREF(result)_Py_DECREF(((PyObject*)(result))); | |||
1055 | result = NULL((void*)0); | |||
1056 | } | |||
1057 | ||||
1058 | finish: | |||
1059 | Py_DECREF(mit)_Py_DECREF(((PyObject*)(mit))); | |||
1060 | return (PyObject *)result; | |||
1061 | } | |||
1062 | ||||
1063 | /* | |||
1064 | * VOID-type arrays can only be compared equal and not-equal | |||
1065 | * in which case the fields are all compared by extracting the fields | |||
1066 | * and testing one at a time... | |||
1067 | * equality testing is performed using logical_ands on all the fields. | |||
1068 | * in-equality testing is performed using logical_ors on all the fields. | |||
1069 | * | |||
1070 | * VOID-type arrays without fields are compared for equality by comparing their | |||
1071 | * memory at each location directly (using string-code). | |||
1072 | */ | |||
1073 | static PyObject * | |||
1074 | _void_compare(PyArrayObject *self, PyArrayObject *other, int cmp_op) | |||
1075 | { | |||
1076 | if (!(cmp_op == Py_EQ2 || cmp_op == Py_NE3)) { | |||
1077 | PyErr_SetString(PyExc_ValueError, | |||
1078 | "Void-arrays can only be compared for equality."); | |||
1079 | return NULL((void*)0); | |||
1080 | } | |||
1081 | if (PyArray_HASFIELDS(self)(((PyArray_Descr *)(PyArray_DESCR(self)))->names != ((void *)0))) { | |||
1082 | PyObject *res = NULL((void*)0), *temp, *a, *b; | |||
1083 | PyObject *key, *value, *temp2; | |||
1084 | PyObject *op; | |||
1085 | Py_ssize_t pos = 0; | |||
1086 | npy_intp result_ndim = PyArray_NDIM(self) > PyArray_NDIM(other) ? | |||
1087 | PyArray_NDIM(self) : PyArray_NDIM(other); | |||
1088 | ||||
1089 | op = (cmp_op == Py_EQ2 ? n_ops.logical_and : n_ops.logical_or); | |||
1090 | while (PyDict_Next(PyArray_DESCR(self)->fields, &pos, &key, &value)) { | |||
1091 | if (NPY_TITLE_KEY(key, value)(NPY_TITLE_KEY_check((key), (value)))) { | |||
1092 | continue; | |||
1093 | } | |||
1094 | a = array_subscript_asarray(self, key); | |||
1095 | if (a == NULL((void*)0)) { | |||
1096 | Py_XDECREF(res)_Py_XDECREF(((PyObject*)(res))); | |||
1097 | return NULL((void*)0); | |||
1098 | } | |||
1099 | b = array_subscript_asarray(other, key); | |||
1100 | if (b == NULL((void*)0)) { | |||
1101 | Py_XDECREF(res)_Py_XDECREF(((PyObject*)(res))); | |||
1102 | Py_DECREF(a)_Py_DECREF(((PyObject*)(a))); | |||
1103 | return NULL((void*)0); | |||
1104 | } | |||
1105 | temp = array_richcompare((PyArrayObject *)a,b,cmp_op); | |||
1106 | Py_DECREF(a)_Py_DECREF(((PyObject*)(a))); | |||
1107 | Py_DECREF(b)_Py_DECREF(((PyObject*)(b))); | |||
1108 | if (temp == NULL((void*)0)) { | |||
1109 | Py_XDECREF(res)_Py_XDECREF(((PyObject*)(res))); | |||
1110 | return NULL((void*)0); | |||
1111 | } | |||
1112 | ||||
1113 | /* | |||
1114 | * If the field type has a non-trivial shape, additional | |||
1115 | * dimensions will have been appended to `a` and `b`. | |||
1116 | * In that case, reduce them using `op`. | |||
1117 | */ | |||
1118 | if (PyArray_Check(temp)((((PyObject*)(temp))->ob_type) == (&PyArray_Type) || PyType_IsSubtype ((((PyObject*)(temp))->ob_type), (&PyArray_Type))) && | |||
1119 | PyArray_NDIM((PyArrayObject *)temp) > result_ndim) { | |||
1120 | /* If the type was multidimensional, collapse that part to 1-D | |||
1121 | */ | |||
1122 | if (PyArray_NDIM((PyArrayObject *)temp) != result_ndim+1) { | |||
1123 | npy_intp dimensions[NPY_MAXDIMS32]; | |||
1124 | PyArray_Dims newdims; | |||
1125 | ||||
1126 | newdims.ptr = dimensions; | |||
1127 | newdims.len = result_ndim+1; | |||
1128 | if (result_ndim) { | |||
1129 | memcpy(dimensions, PyArray_DIMS((PyArrayObject *)temp), | |||
1130 | sizeof(npy_intp)*result_ndim); | |||
1131 | } | |||
1132 | dimensions[result_ndim] = -1; | |||
1133 | temp2 = PyArray_Newshape((PyArrayObject *)temp, | |||
1134 | &newdims, NPY_ANYORDER); | |||
1135 | if (temp2 == NULL((void*)0)) { | |||
1136 | Py_DECREF(temp)_Py_DECREF(((PyObject*)(temp))); | |||
1137 | Py_XDECREF(res)_Py_XDECREF(((PyObject*)(res))); | |||
1138 | return NULL((void*)0); | |||
1139 | } | |||
1140 | Py_DECREF(temp)_Py_DECREF(((PyObject*)(temp))); | |||
1141 | temp = temp2; | |||
1142 | } | |||
1143 | /* Reduce the extra dimension of `temp` using `op` */ | |||
1144 | temp2 = PyArray_GenericReduceFunction((PyArrayObject *)temp, | |||
1145 | op, result_ndim, | |||
1146 | NPY_BOOL, NULL((void*)0)); | |||
1147 | if (temp2 == NULL((void*)0)) { | |||
1148 | Py_DECREF(temp)_Py_DECREF(((PyObject*)(temp))); | |||
1149 | Py_XDECREF(res)_Py_XDECREF(((PyObject*)(res))); | |||
1150 | return NULL((void*)0); | |||
1151 | } | |||
1152 | Py_DECREF(temp)_Py_DECREF(((PyObject*)(temp))); | |||
1153 | temp = temp2; | |||
1154 | } | |||
1155 | ||||
1156 | if (res == NULL((void*)0)) { | |||
1157 | res = temp; | |||
1158 | } | |||
1159 | else { | |||
1160 | temp2 = PyObject_CallFunction_PyObject_CallFunction_SizeT(op, "OO", res, temp); | |||
1161 | Py_DECREF(temp)_Py_DECREF(((PyObject*)(temp))); | |||
1162 | Py_DECREF(res)_Py_DECREF(((PyObject*)(res))); | |||
1163 | if (temp2 == NULL((void*)0)) { | |||
1164 | return NULL((void*)0); | |||
1165 | } | |||
1166 | res = temp2; | |||
1167 | } | |||
1168 | } | |||
1169 | if (res == NULL((void*)0) && !PyErr_Occurred()) { | |||
1170 | /* these dtypes had no fields. Use a MultiIter to broadcast them | |||
1171 | * to an output array, and fill with True (for EQ)*/ | |||
1172 | PyArrayMultiIterObject *mit = (PyArrayMultiIterObject *) | |||
1173 | PyArray_MultiIterNew(2, self, other); | |||
1174 | if (mit == NULL((void*)0)) { | |||
1175 | return NULL((void*)0); | |||
1176 | } | |||
1177 | ||||
1178 | res = PyArray_NewFromDescr(&PyArray_Type, | |||
1179 | PyArray_DescrFromType(NPY_BOOL), | |||
1180 | mit->nd, mit->dimensions, | |||
1181 | NULL((void*)0), NULL((void*)0), 0, NULL((void*)0)); | |||
1182 | Py_DECREF(mit)_Py_DECREF(((PyObject*)(mit))); | |||
1183 | if (res) { | |||
1184 | PyArray_FILLWBYTE((PyArrayObject *)res,memset(PyArray_DATA((PyArrayObject *)res), cmp_op == 2 ? 1 : 0 , (PyArray_ITEMSIZE((PyArrayObject *)res) * PyArray_MultiplyList (PyArray_DIMS((PyArrayObject *)res), PyArray_NDIM((PyArrayObject *)res)))) | |||
1185 | cmp_op == Py_EQ ? 1 : 0)memset(PyArray_DATA((PyArrayObject *)res), cmp_op == 2 ? 1 : 0 , (PyArray_ITEMSIZE((PyArrayObject *)res) * PyArray_MultiplyList (PyArray_DIMS((PyArrayObject *)res), PyArray_NDIM((PyArrayObject *)res)))); | |||
1186 | } | |||
1187 | } | |||
1188 | return res; | |||
1189 | } | |||
1190 | else { | |||
1191 | /* compare as a string. Assumes self and other have same descr->type */ | |||
1192 | return _strings_richcompare(self, other, cmp_op, 0); | |||
1193 | } | |||
1194 | } | |||
1195 | ||||
1196 | /* | |||
1197 | * Silence the current error and emit a deprecation warning instead. | |||
1198 | * | |||
1199 | * If warnings are raised as errors, this sets the warning __cause__ to the | |||
1200 | * silenced error. | |||
1201 | */ | |||
1202 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
1203 | DEPRECATE_silence_error(const char *msg) { | |||
1204 | PyObject *exc, *val, *tb; | |||
1205 | PyErr_Fetch(&exc, &val, &tb); | |||
1206 | if (DEPRECATE(msg)PyErr_WarnEx(PyExc_DeprecationWarning,msg,1) < 0) { | |||
1207 | npy_PyErr_ChainExceptionsCause(exc, val, tb); | |||
1208 | return -1; | |||
1209 | } | |||
1210 | Py_XDECREF(exc)_Py_XDECREF(((PyObject*)(exc))); | |||
1211 | Py_XDECREF(val)_Py_XDECREF(((PyObject*)(val))); | |||
1212 | Py_XDECREF(tb)_Py_XDECREF(((PyObject*)(tb))); | |||
1213 | return 0; | |||
1214 | } | |||
1215 | ||||
1216 | /* | |||
1217 | * Comparisons can fail, but we do not always want to pass on the exception | |||
1218 | * (see comment in array_richcompare below), but rather return NotImplemented. | |||
1219 | * Here, an exception should be set on entrance. | |||
1220 | * Returns either NotImplemented with the exception cleared, or NULL | |||
1221 | * with the exception set. | |||
1222 | * Raises deprecation warnings for cases where behaviour is meant to change | |||
1223 | * (2015-05-14, 1.10) | |||
1224 | */ | |||
1225 | ||||
1226 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | |||
1227 | _failed_comparison_workaround(PyArrayObject *self, PyObject *other, int cmp_op) | |||
1228 | { | |||
1229 | PyObject *exc, *val, *tb; | |||
1230 | PyArrayObject *array_other; | |||
1231 | int other_is_flexible, ndim_other; | |||
1232 | int self_is_flexible = PyTypeNum_ISFLEXIBLE(PyArray_DESCR(self)->type_num)(((PyArray_DESCR(self)->type_num) >=NPY_STRING) && ((PyArray_DESCR(self)->type_num) <=NPY_VOID)); | |||
1233 | ||||
1234 | PyErr_Fetch(&exc, &val, &tb); | |||
1235 | /* | |||
1236 | * Determine whether other has a flexible dtype; here, inconvertible | |||
1237 | * is counted as inflexible. (This repeats work done in the ufunc, | |||
1238 | * but OK to waste some time in an unlikely path.) | |||
1239 | */ | |||
1240 | array_other = (PyArrayObject *)PyArray_FROM_O(other)PyArray_FromAny(other, ((void*)0), 0, 0, 0, ((void*)0)); | |||
1241 | if (array_other) { | |||
1242 | other_is_flexible = PyTypeNum_ISFLEXIBLE((((PyArray_DESCR(array_other)->type_num) >=NPY_STRING) && ((PyArray_DESCR(array_other)->type_num) <=NPY_VOID)) | |||
1243 | PyArray_DESCR(array_other)->type_num)(((PyArray_DESCR(array_other)->type_num) >=NPY_STRING) && ((PyArray_DESCR(array_other)->type_num) <=NPY_VOID)); | |||
1244 | ndim_other = PyArray_NDIM(array_other); | |||
1245 | Py_DECREF(array_other)_Py_DECREF(((PyObject*)(array_other))); | |||
1246 | } | |||
1247 | else { | |||
1248 | PyErr_Clear(); /* we restore the original error if needed */ | |||
1249 | other_is_flexible = 0; | |||
1250 | ndim_other = 0; | |||
1251 | } | |||
1252 | if (cmp_op == Py_EQ2 || cmp_op == Py_NE3) { | |||
1253 | /* | |||
1254 | * note: for == and !=, a structured dtype self cannot get here, | |||
1255 | * but a string can. Other can be string or structured. | |||
1256 | */ | |||
1257 | if (other_is_flexible || self_is_flexible) { | |||
1258 | /* | |||
1259 | * For scalars, returning NotImplemented is correct. | |||
1260 | * For arrays, we emit a future deprecation warning. | |||
1261 | * When this warning is removed, a correctly shaped | |||
1262 | * array of bool should be returned. | |||
1263 | */ | |||
1264 | if (ndim_other != 0 || PyArray_NDIM(self) != 0) { | |||
1265 | /* 2015-05-14, 1.10 */ | |||
1266 | if (DEPRECATE_FUTUREWARNING(PyErr_WarnEx(PyExc_FutureWarning,"elementwise comparison failed; returning scalar " "instead, but in the future will perform " "elementwise comparison" ,1) | |||
1267 | "elementwise comparison failed; returning scalar "PyErr_WarnEx(PyExc_FutureWarning,"elementwise comparison failed; returning scalar " "instead, but in the future will perform " "elementwise comparison" ,1) | |||
1268 | "instead, but in the future will perform "PyErr_WarnEx(PyExc_FutureWarning,"elementwise comparison failed; returning scalar " "instead, but in the future will perform " "elementwise comparison" ,1) | |||
1269 | "elementwise comparison")PyErr_WarnEx(PyExc_FutureWarning,"elementwise comparison failed; returning scalar " "instead, but in the future will perform " "elementwise comparison" ,1) < 0) { | |||
1270 | goto fail; | |||
1271 | } | |||
1272 | } | |||
1273 | } | |||
1274 | else { | |||
1275 | /* | |||
1276 | * If neither self nor other had a flexible dtype, the error cannot | |||
1277 | * have been caused by a lack of implementation in the ufunc. | |||
1278 | * | |||
1279 | * 2015-05-14, 1.10 | |||
1280 | */ | |||
1281 | if (DEPRECATE(PyErr_WarnEx(PyExc_DeprecationWarning,"elementwise comparison failed; " "this will raise an error in the future.",1) | |||
1282 | "elementwise comparison failed; "PyErr_WarnEx(PyExc_DeprecationWarning,"elementwise comparison failed; " "this will raise an error in the future.",1) | |||
1283 | "this will raise an error in the future.")PyErr_WarnEx(PyExc_DeprecationWarning,"elementwise comparison failed; " "this will raise an error in the future.",1) < 0) { | |||
1284 | goto fail; | |||
1285 | } | |||
1286 | } | |||
1287 | Py_XDECREF(exc)_Py_XDECREF(((PyObject*)(exc))); | |||
1288 | Py_XDECREF(val)_Py_XDECREF(((PyObject*)(val))); | |||
1289 | Py_XDECREF(tb)_Py_XDECREF(((PyObject*)(tb))); | |||
1290 | Py_INCREF(Py_NotImplemented)_Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct)))); | |||
1291 | return Py_NotImplemented(&_Py_NotImplementedStruct); | |||
1292 | } | |||
1293 | else if (other_is_flexible || self_is_flexible) { | |||
1294 | /* | |||
1295 | * For LE, LT, GT, GE and a flexible self or other, we return | |||
1296 | * NotImplemented, which is the correct answer since the ufuncs do | |||
1297 | * not in fact implement loops for those. This will get us the | |||
1298 | * desired TypeError. | |||
1299 | */ | |||
1300 | Py_XDECREF(exc)_Py_XDECREF(((PyObject*)(exc))); | |||
1301 | Py_XDECREF(val)_Py_XDECREF(((PyObject*)(val))); | |||
1302 | Py_XDECREF(tb)_Py_XDECREF(((PyObject*)(tb))); | |||
1303 | Py_INCREF(Py_NotImplemented)_Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct)))); | |||
1304 | return Py_NotImplemented(&_Py_NotImplementedStruct); | |||
1305 | } | |||
1306 | else { | |||
1307 | /* LE, LT, GT, or GE with non-flexible other; just pass on error */ | |||
1308 | goto fail; | |||
1309 | } | |||
1310 | ||||
1311 | fail: | |||
1312 | /* | |||
1313 | * Reraise the original exception, possibly chaining with a new one. | |||
1314 | */ | |||
1315 | npy_PyErr_ChainExceptionsCause(exc, val, tb); | |||
1316 | return NULL((void*)0); | |||
1317 | } | |||
1318 | ||||
1319 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | |||
1320 | array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op) | |||
1321 | { | |||
1322 | PyArrayObject *array_other; | |||
1323 | PyObject *obj_self = (PyObject *)self; | |||
1324 | PyObject *result = NULL((void*)0); | |||
1325 | ||||
1326 | /* Special case for string arrays (which don't and currently can't have | |||
1327 | * ufunc loops defined, so there's no point in trying). | |||
1328 | */ | |||
1329 | if (PyArray_ISSTRING(self)(((PyArray_TYPE(self)) == NPY_STRING) || ((PyArray_TYPE(self) ) == NPY_UNICODE))) { | |||
1330 | array_other = (PyArrayObject *)PyArray_FromObject(other,PyArray_FromAny(other, PyArray_DescrFromType(NPY_NOTYPE), 0, 0 , (0x0100 | 0x0400) | 0x0040, ((void*)0)) | |||
1331 | NPY_NOTYPE, 0, 0)PyArray_FromAny(other, PyArray_DescrFromType(NPY_NOTYPE), 0, 0 , (0x0100 | 0x0400) | 0x0040, ((void*)0)); | |||
1332 | if (array_other == NULL((void*)0)) { | |||
1333 | PyErr_Clear(); | |||
1334 | /* Never mind, carry on, see what happens */ | |||
1335 | } | |||
1336 | else if (!PyArray_ISSTRING(array_other)(((PyArray_TYPE(array_other)) == NPY_STRING) || ((PyArray_TYPE (array_other)) == NPY_UNICODE))) { | |||
1337 | Py_DECREF(array_other)_Py_DECREF(((PyObject*)(array_other))); | |||
1338 | /* Never mind, carry on, see what happens */ | |||
1339 | } | |||
1340 | else { | |||
1341 | result = _strings_richcompare(self, array_other, cmp_op, 0); | |||
1342 | Py_DECREF(array_other)_Py_DECREF(((PyObject*)(array_other))); | |||
1343 | return result; | |||
1344 | } | |||
1345 | /* If we reach this point, it means that we are not comparing | |||
1346 | * string-to-string. It's possible that this will still work out, | |||
1347 | * e.g. if the other array is an object array, then both will be cast | |||
1348 | * to object or something? I don't know how that works actually, but | |||
1349 | * it does, b/c this works: | |||
1350 | * l = ["a", "b"] | |||
1351 | * assert np.array(l, dtype="S1") == np.array(l, dtype="O") | |||
1352 | * So we fall through and see what happens. | |||
1353 | */ | |||
1354 | } | |||
1355 | ||||
1356 | switch (cmp_op) { | |||
1357 | case Py_LT0: | |||
1358 | RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other)do { if (binop_should_defer((PyObject*)obj_self, (PyObject*)other , 0)) { _Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct )))); return (&_Py_NotImplementedStruct); } } while (0); | |||
1359 | result = PyArray_GenericBinaryFunction( | |||
1360 | (PyObject *)self, other, n_ops.less); | |||
1361 | break; | |||
1362 | case Py_LE1: | |||
1363 | RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other)do { if (binop_should_defer((PyObject*)obj_self, (PyObject*)other , 0)) { _Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct )))); return (&_Py_NotImplementedStruct); } } while (0); | |||
1364 | result = PyArray_GenericBinaryFunction( | |||
1365 | (PyObject *)self, other, n_ops.less_equal); | |||
1366 | break; | |||
1367 | case Py_EQ2: | |||
1368 | RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other)do { if (binop_should_defer((PyObject*)obj_self, (PyObject*)other , 0)) { _Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct )))); return (&_Py_NotImplementedStruct); } } while (0); | |||
1369 | /* | |||
1370 | * The ufunc does not support void/structured types, so these | |||
1371 | * need to be handled specifically. Only a few cases are supported. | |||
1372 | */ | |||
1373 | ||||
1374 | if (PyArray_TYPE(self) == NPY_VOID) { | |||
1375 | int _res; | |||
1376 | ||||
1377 | array_other = (PyArrayObject *)PyArray_FROM_O(other)PyArray_FromAny(other, ((void*)0), 0, 0, 0, ((void*)0)); | |||
1378 | /* | |||
1379 | * If not successful, indicate that the items cannot be compared | |||
1380 | * this way. | |||
1381 | */ | |||
1382 | if (array_other == NULL((void*)0)) { | |||
1383 | /* 2015-05-07, 1.10 */ | |||
1384 | if (DEPRECATE_silence_error( | |||
1385 | "elementwise == comparison failed and returning scalar " | |||
1386 | "instead; this will raise an error in the future.") < 0) { | |||
1387 | return NULL((void*)0); | |||
1388 | } | |||
1389 | Py_INCREF(Py_NotImplemented)_Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct)))); | |||
1390 | return Py_NotImplemented(&_Py_NotImplementedStruct); | |||
1391 | } | |||
1392 | ||||
1393 | _res = PyArray_CanCastTypeTo(PyArray_DESCR(self), | |||
1394 | PyArray_DESCR(array_other), | |||
1395 | NPY_EQUIV_CASTING); | |||
1396 | if (_res == 0) { | |||
1397 | /* 2015-05-07, 1.10 */ | |||
1398 | Py_DECREF(array_other)_Py_DECREF(((PyObject*)(array_other))); | |||
1399 | if (DEPRECATE_FUTUREWARNING(PyErr_WarnEx(PyExc_FutureWarning,"elementwise == comparison failed and returning scalar " "instead; this will raise an error or perform " "elementwise comparison in the future." ,1) | |||
1400 | "elementwise == comparison failed and returning scalar "PyErr_WarnEx(PyExc_FutureWarning,"elementwise == comparison failed and returning scalar " "instead; this will raise an error or perform " "elementwise comparison in the future." ,1) | |||
1401 | "instead; this will raise an error or perform "PyErr_WarnEx(PyExc_FutureWarning,"elementwise == comparison failed and returning scalar " "instead; this will raise an error or perform " "elementwise comparison in the future." ,1) | |||
1402 | "elementwise comparison in the future.")PyErr_WarnEx(PyExc_FutureWarning,"elementwise == comparison failed and returning scalar " "instead; this will raise an error or perform " "elementwise comparison in the future." ,1) < 0) { | |||
1403 | return NULL((void*)0); | |||
1404 | } | |||
1405 | Py_INCREF(Py_False)_Py_INCREF(((PyObject*)(((PyObject *) &_Py_FalseStruct))) ); | |||
1406 | return Py_False((PyObject *) &_Py_FalseStruct); | |||
1407 | } | |||
1408 | else { | |||
1409 | result = _void_compare(self, array_other, cmp_op); | |||
1410 | } | |||
1411 | Py_DECREF(array_other)_Py_DECREF(((PyObject*)(array_other))); | |||
1412 | return result; | |||
1413 | } | |||
1414 | ||||
1415 | result = PyArray_GenericBinaryFunction( | |||
1416 | (PyObject *)self, (PyObject *)other, n_ops.equal); | |||
1417 | break; | |||
1418 | case Py_NE3: | |||
1419 | RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other)do { if (binop_should_defer((PyObject*)obj_self, (PyObject*)other , 0)) { _Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct )))); return (&_Py_NotImplementedStruct); } } while (0); | |||
1420 | /* | |||
1421 | * The ufunc does not support void/structured types, so these | |||
1422 | * need to be handled specifically. Only a few cases are supported. | |||
1423 | */ | |||
1424 | ||||
1425 | if (PyArray_TYPE(self) == NPY_VOID) { | |||
1426 | int _res; | |||
1427 | ||||
1428 | array_other = (PyArrayObject *)PyArray_FROM_O(other)PyArray_FromAny(other, ((void*)0), 0, 0, 0, ((void*)0)); | |||
1429 | /* | |||
1430 | * If not successful, indicate that the items cannot be compared | |||
1431 | * this way. | |||
1432 | */ | |||
1433 | if (array_other == NULL((void*)0)) { | |||
1434 | /* 2015-05-07, 1.10 */ | |||
1435 | if (DEPRECATE_silence_error( | |||
1436 | "elementwise != comparison failed and returning scalar " | |||
1437 | "instead; this will raise an error in the future.") < 0) { | |||
1438 | return NULL((void*)0); | |||
1439 | } | |||
1440 | Py_INCREF(Py_NotImplemented)_Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct)))); | |||
1441 | return Py_NotImplemented(&_Py_NotImplementedStruct); | |||
1442 | } | |||
1443 | ||||
1444 | _res = PyArray_CanCastTypeTo(PyArray_DESCR(self), | |||
1445 | PyArray_DESCR(array_other), | |||
1446 | NPY_EQUIV_CASTING); | |||
1447 | if (_res == 0) { | |||
1448 | /* 2015-05-07, 1.10 */ | |||
1449 | Py_DECREF(array_other)_Py_DECREF(((PyObject*)(array_other))); | |||
1450 | if (DEPRECATE_FUTUREWARNING(PyErr_WarnEx(PyExc_FutureWarning,"elementwise != comparison failed and returning scalar " "instead; this will raise an error or perform " "elementwise comparison in the future." ,1) | |||
1451 | "elementwise != comparison failed and returning scalar "PyErr_WarnEx(PyExc_FutureWarning,"elementwise != comparison failed and returning scalar " "instead; this will raise an error or perform " "elementwise comparison in the future." ,1) | |||
1452 | "instead; this will raise an error or perform "PyErr_WarnEx(PyExc_FutureWarning,"elementwise != comparison failed and returning scalar " "instead; this will raise an error or perform " "elementwise comparison in the future." ,1) | |||
1453 | "elementwise comparison in the future.")PyErr_WarnEx(PyExc_FutureWarning,"elementwise != comparison failed and returning scalar " "instead; this will raise an error or perform " "elementwise comparison in the future." ,1) < 0) { | |||
1454 | return NULL((void*)0); | |||
1455 | } | |||
1456 | Py_INCREF(Py_True)_Py_INCREF(((PyObject*)(((PyObject *) &_Py_TrueStruct)))); | |||
1457 | return Py_True((PyObject *) &_Py_TrueStruct); | |||
1458 | } | |||
1459 | else { | |||
1460 | result = _void_compare(self, array_other, cmp_op); | |||
1461 | Py_DECREF(array_other)_Py_DECREF(((PyObject*)(array_other))); | |||
1462 | } | |||
1463 | return result; | |||
1464 | } | |||
1465 | ||||
1466 | result = PyArray_GenericBinaryFunction( | |||
1467 | (PyObject *)self, (PyObject *)other, n_ops.not_equal); | |||
1468 | break; | |||
1469 | case Py_GT4: | |||
1470 | RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other)do { if (binop_should_defer((PyObject*)obj_self, (PyObject*)other , 0)) { _Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct )))); return (&_Py_NotImplementedStruct); } } while (0); | |||
1471 | result = PyArray_GenericBinaryFunction( | |||
1472 | (PyObject *)self, other, n_ops.greater); | |||
1473 | break; | |||
1474 | case Py_GE5: | |||
1475 | RICHCMP_GIVE_UP_IF_NEEDED(obj_self, other)do { if (binop_should_defer((PyObject*)obj_self, (PyObject*)other , 0)) { _Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct )))); return (&_Py_NotImplementedStruct); } } while (0); | |||
1476 | result = PyArray_GenericBinaryFunction( | |||
1477 | (PyObject *)self, other, n_ops.greater_equal); | |||
1478 | break; | |||
1479 | default: | |||
1480 | Py_INCREF(Py_NotImplemented)_Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct)))); | |||
1481 | return Py_NotImplemented(&_Py_NotImplementedStruct); | |||
1482 | } | |||
1483 | if (result == NULL((void*)0)) { | |||
1484 | /* | |||
1485 | * 2015-05-14, 1.10; updated 2018-06-18, 1.16. | |||
1486 | * | |||
1487 | * Comparisons can raise errors when element-wise comparison is not | |||
1488 | * possible. Some of these, though, should not be passed on. | |||
1489 | * In particular, the ufuncs do not have loops for flexible dtype, | |||
1490 | * so those should be treated separately. Furthermore, for EQ and NE, | |||
1491 | * we should never fail. | |||
1492 | * | |||
1493 | * Our ideal behaviour would be: | |||
1494 | * | |||
1495 | * 1. For EQ and NE: | |||
1496 | * - If self and other are scalars, return NotImplemented, | |||
1497 | * so that python can assign True of False as appropriate. | |||
1498 | * - If either is an array, return an array of False or True. | |||
1499 | * | |||
1500 | * 2. For LT, LE, GE, GT: | |||
1501 | * - If self or other was flexible, return NotImplemented | |||
1502 | * (as is in fact the case), so python can raise a TypeError. | |||
1503 | * - If other is not convertible to an array, pass on the error | |||
1504 | * (MHvK, 2018-06-18: not sure about this, but it's what we have). | |||
1505 | * | |||
1506 | * However, for backwards compatibility, we cannot yet return arrays, | |||
1507 | * so we raise warnings instead. | |||
1508 | */ | |||
1509 | result = _failed_comparison_workaround(self, other, cmp_op); | |||
1510 | } | |||
1511 | return result; | |||
1512 | } | |||
1513 | ||||
1514 | /*NUMPY_API | |||
1515 | */ | |||
1516 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
1517 | PyArray_ElementStrides(PyObject *obj) | |||
1518 | { | |||
1519 | PyArrayObject *arr; | |||
1520 | int itemsize; | |||
1521 | int i, ndim; | |||
1522 | npy_intp *strides; | |||
1523 | ||||
1524 | if (!PyArray_Check(obj)((((PyObject*)(obj))->ob_type) == (&PyArray_Type) || PyType_IsSubtype ((((PyObject*)(obj))->ob_type), (&PyArray_Type)))) { | |||
1525 | return 0; | |||
1526 | } | |||
1527 | ||||
1528 | arr = (PyArrayObject *)obj; | |||
1529 | ||||
1530 | itemsize = PyArray_ITEMSIZE(arr); | |||
1531 | ndim = PyArray_NDIM(arr); | |||
1532 | strides = PyArray_STRIDES(arr); | |||
1533 | ||||
1534 | for (i = 0; i < ndim; i++) { | |||
1535 | if ((strides[i] % itemsize) != 0) { | |||
1536 | return 0; | |||
1537 | } | |||
1538 | } | |||
1539 | return 1; | |||
1540 | } | |||
1541 | ||||
1542 | /* | |||
1543 | * This routine checks to see if newstrides (of length nd) will not | |||
1544 | * ever be able to walk outside of the memory implied numbytes and offset. | |||
1545 | * | |||
1546 | * The available memory is assumed to start at -offset and proceed | |||
1547 | * to numbytes-offset. The strides are checked to ensure | |||
1548 | * that accessing memory using striding will not try to reach beyond | |||
1549 | * this memory for any of the axes. | |||
1550 | * | |||
1551 | * If numbytes is 0 it will be calculated using the dimensions and | |||
1552 | * element-size. | |||
1553 | * | |||
1554 | * This function checks for walking beyond the beginning and right-end | |||
1555 | * of the buffer and therefore works for any integer stride (positive | |||
1556 | * or negative). | |||
1557 | */ | |||
1558 | ||||
1559 | /*NUMPY_API*/ | |||
1560 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) npy_bool | |||
1561 | PyArray_CheckStrides(int elsize, int nd, npy_intp numbytes, npy_intp offset, | |||
1562 | npy_intp const *dims, npy_intp const *newstrides) | |||
1563 | { | |||
1564 | npy_intp begin, end; | |||
1565 | npy_intp lower_offset; | |||
1566 | npy_intp upper_offset; | |||
1567 | ||||
1568 | if (numbytes == 0) { | |||
1569 | numbytes = PyArray_MultiplyList(dims, nd) * elsize; | |||
1570 | } | |||
1571 | ||||
1572 | begin = -offset; | |||
1573 | end = numbytes - offset; | |||
1574 | ||||
1575 | offset_bounds_from_strides(elsize, nd, dims, newstrides, | |||
1576 | &lower_offset, &upper_offset); | |||
1577 | ||||
1578 | if ((upper_offset > end) || (lower_offset < begin)) { | |||
1579 | return NPY_FALSE0; | |||
1580 | } | |||
1581 | return NPY_TRUE1; | |||
1582 | } | |||
1583 | ||||
1584 | ||||
1585 | static PyObject * | |||
1586 | array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) | |||
1587 | { | |||
1588 | static char *kwlist[] = {"shape", "dtype", "buffer", "offset", "strides", | |||
1589 | "order", NULL((void*)0)}; | |||
1590 | PyArray_Descr *descr = NULL((void*)0); | |||
1591 | int itemsize; | |||
1592 | PyArray_Dims dims = {NULL((void*)0), 0}; | |||
1593 | PyArray_Dims strides = {NULL((void*)0), -1}; | |||
1594 | PyArray_Chunk buffer; | |||
1595 | npy_longlong offset = 0; | |||
1596 | NPY_ORDER order = NPY_CORDER; | |||
1597 | int is_f_order = 0; | |||
1598 | PyArrayObject *ret; | |||
1599 | ||||
1600 | buffer.ptr = NULL((void*)0); | |||
1601 | /* | |||
1602 | * Usually called with shape and type but can also be called with buffer, | |||
1603 | * strides, and swapped info For now, let's just use this to create an | |||
1604 | * empty, contiguous array of a specific type and shape. | |||
1605 | */ | |||
1606 | if (!PyArg_ParseTupleAndKeywords_PyArg_ParseTupleAndKeywords_SizeT(args, kwds, "O&|O&O&LO&O&:ndarray", | |||
1607 | kwlist, PyArray_IntpConverter, | |||
1608 | &dims, | |||
1609 | PyArray_DescrConverter, | |||
1610 | &descr, | |||
1611 | PyArray_BufferConverter, | |||
1612 | &buffer, | |||
1613 | &offset, | |||
1614 | &PyArray_OptionalIntpConverter, | |||
1615 | &strides, | |||
1616 | &PyArray_OrderConverter, | |||
1617 | &order)) { | |||
1618 | goto fail; | |||
1619 | } | |||
1620 | if (order == NPY_FORTRANORDER) { | |||
1621 | is_f_order = 1; | |||
1622 | } | |||
1623 | if (descr == NULL((void*)0)) { | |||
1624 | descr = PyArray_DescrFromType(NPY_DEFAULT_TYPENPY_DOUBLE); | |||
1625 | } | |||
1626 | ||||
1627 | itemsize = descr->elsize; | |||
1628 | ||||
1629 | if (strides.len != -1) { | |||
1630 | npy_intp nb, off; | |||
1631 | if (strides.len != dims.len) { | |||
1632 | PyErr_SetString(PyExc_ValueError, | |||
1633 | "strides, if given, must be " \ | |||
1634 | "the same length as shape"); | |||
1635 | goto fail; | |||
1636 | } | |||
1637 | ||||
1638 | if (buffer.ptr == NULL((void*)0)) { | |||
1639 | nb = 0; | |||
1640 | off = 0; | |||
1641 | } | |||
1642 | else { | |||
1643 | nb = buffer.len; | |||
1644 | off = (npy_intp) offset; | |||
1645 | } | |||
1646 | ||||
1647 | ||||
1648 | if (!PyArray_CheckStrides(itemsize, dims.len, | |||
1649 | nb, off, | |||
1650 | dims.ptr, strides.ptr)) { | |||
1651 | PyErr_SetString(PyExc_ValueError, | |||
1652 | "strides is incompatible " \ | |||
1653 | "with shape of requested " \ | |||
1654 | "array and size of buffer"); | |||
1655 | goto fail; | |||
1656 | } | |||
1657 | } | |||
1658 | ||||
1659 | if (buffer.ptr == NULL((void*)0)) { | |||
1660 | ret = (PyArrayObject *) | |||
1661 | PyArray_NewFromDescr_int(subtype, descr, | |||
1662 | (int)dims.len, | |||
1663 | dims.ptr, | |||
1664 | strides.ptr, NULL((void*)0), is_f_order, NULL((void*)0), NULL((void*)0), | |||
1665 | 0, 1); | |||
1666 | if (ret == NULL((void*)0)) { | |||
1667 | descr = NULL((void*)0); | |||
1668 | goto fail; | |||
1669 | } | |||
1670 | if (PyDataType_FLAGCHK(descr, NPY_ITEM_HASOBJECT)(((descr)->flags & (0x01)) == (0x01))) { | |||
1671 | /* place Py_None in object positions */ | |||
1672 | PyArray_FillObjectArray(ret, Py_None(&_Py_NoneStruct)); | |||
1673 | if (PyErr_Occurred()) { | |||
1674 | descr = NULL((void*)0); | |||
1675 | goto fail; | |||
1676 | } | |||
1677 | } | |||
1678 | } | |||
1679 | else { | |||
1680 | /* buffer given -- use it */ | |||
1681 | if (dims.len == 1 && dims.ptr[0] == -1) { | |||
1682 | dims.ptr[0] = (buffer.len-(npy_intp)offset) / itemsize; | |||
1683 | } | |||
1684 | else if ((strides.ptr == NULL((void*)0)) && | |||
1685 | (buffer.len < (offset + (((npy_intp)itemsize)* | |||
1686 | PyArray_MultiplyList(dims.ptr, | |||
1687 | dims.len))))) { | |||
1688 | PyErr_SetString(PyExc_TypeError, | |||
1689 | "buffer is too small for " \ | |||
1690 | "requested array"); | |||
1691 | goto fail; | |||
1692 | } | |||
1693 | /* get writeable and aligned */ | |||
1694 | if (is_f_order) { | |||
1695 | buffer.flags |= NPY_ARRAY_F_CONTIGUOUS0x0002; | |||
1696 | } | |||
1697 | ret = (PyArrayObject *)PyArray_NewFromDescr_int( | |||
1698 | subtype, descr, | |||
1699 | dims.len, dims.ptr, strides.ptr, offset + (char *)buffer.ptr, | |||
1700 | buffer.flags, NULL((void*)0), buffer.base, | |||
1701 | 0, 1); | |||
1702 | if (ret == NULL((void*)0)) { | |||
1703 | descr = NULL((void*)0); | |||
1704 | goto fail; | |||
1705 | } | |||
1706 | } | |||
1707 | ||||
1708 | npy_free_cache_dim_obj(dims); | |||
1709 | npy_free_cache_dim_obj(strides); | |||
1710 | return (PyObject *)ret; | |||
1711 | ||||
1712 | fail: | |||
1713 | Py_XDECREF(descr)_Py_XDECREF(((PyObject*)(descr))); | |||
1714 | npy_free_cache_dim_obj(dims); | |||
1715 | npy_free_cache_dim_obj(strides); | |||
1716 | return NULL((void*)0); | |||
1717 | } | |||
1718 | ||||
1719 | ||||
1720 | static PyObject * | |||
1721 | array_iter(PyArrayObject *arr) | |||
1722 | { | |||
1723 | if (PyArray_NDIM(arr) == 0) { | |||
1724 | PyErr_SetString(PyExc_TypeError, | |||
1725 | "iteration over a 0-d array"); | |||
1726 | return NULL((void*)0); | |||
1727 | } | |||
1728 | return PySeqIter_New((PyObject *)arr); | |||
1729 | } | |||
1730 | ||||
1731 | static PyObject * | |||
1732 | array_alloc(PyTypeObject *type, Py_ssize_t NPY_UNUSED(nitems)(__NPY_UNUSED_TAGGEDnitems) __attribute__ ((__unused__))) | |||
1733 | { | |||
1734 | /* nitems will always be 0 */ | |||
1735 | PyObject *obj = PyObject_Malloc(type->tp_basicsize); | |||
1736 | PyObject_Init(obj, type); | |||
1737 | return obj; | |||
1738 | } | |||
1739 | ||||
1740 | static void | |||
1741 | array_free(PyObject * v) | |||
1742 | { | |||
1743 | /* avoid same deallocator as PyBaseObject, see gentype_free */ | |||
1744 | PyObject_Free(v); | |||
1745 | } | |||
1746 | ||||
1747 | ||||
1748 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyTypeObject PyArray_Type = { | |||
1749 | PyVarObject_HEAD_INIT(NULL, 0){ { 1, ((void*)0) }, 0 }, | |||
1750 | .tp_name = "numpy.ndarray", | |||
1751 | .tp_basicsize = sizeof(PyArrayObject_fields), | |||
1752 | /* methods */ | |||
1753 | .tp_dealloc = (destructor)array_dealloc, | |||
1754 | .tp_repr = (reprfunc)array_repr, | |||
1755 | .tp_as_number = &array_as_number, | |||
1756 | .tp_as_sequence = &array_as_sequence, | |||
1757 | .tp_as_mapping = &array_as_mapping, | |||
1758 | .tp_str = (reprfunc)array_str, | |||
1759 | .tp_as_buffer = &array_as_buffer, | |||
1760 | .tp_flags =(Py_TPFLAGS_DEFAULT( 0 | (1UL << 18) | 0) | Py_TPFLAGS_BASETYPE(1UL << 10)), | |||
1761 | ||||
1762 | .tp_richcompare = (richcmpfunc)array_richcompare, | |||
1763 | .tp_weaklistoffset = offsetof(PyArrayObject_fields, weakreflist)__builtin_offsetof(PyArrayObject_fields, weakreflist), | |||
1764 | .tp_iter = (getiterfunc)array_iter, | |||
1765 | .tp_methods = array_methods, | |||
1766 | .tp_getset = array_getsetlist, | |||
1767 | .tp_alloc = (allocfunc)array_alloc, | |||
1768 | .tp_new = (newfunc)array_new, | |||
1769 | .tp_free = (freefunc)array_free, | |||
1770 | }; |
1 | #define NPY_NO_DEPRECATED_API0x0000000E NPY_API_VERSION0x0000000E | ||||||
2 | #define _UMATHMODULE | ||||||
3 | #define _MULTIARRAYMODULE | ||||||
4 | |||||||
5 | #include "Python.h" | ||||||
6 | |||||||
7 | #include "numpy/npy_3kcompat.h" | ||||||
8 | |||||||
9 | #include "lowlevel_strided_loops.h" | ||||||
10 | #include "numpy/arrayobject.h" | ||||||
11 | |||||||
12 | #include "descriptor.h" | ||||||
13 | #include "convert_datatype.h" | ||||||
14 | #include "common_dtype.h" | ||||||
15 | #include "dtypemeta.h" | ||||||
16 | |||||||
17 | #include "array_coercion.h" | ||||||
18 | #include "ctors.h" | ||||||
19 | #include "common.h" | ||||||
20 | #include "_datetime.h" | ||||||
21 | #include "npy_import.h" | ||||||
22 | |||||||
23 | |||||||
24 | /* | ||||||
25 | * This file defines helpers for some of the ctors.c functions which | ||||||
26 | * create an array from Python sequences and types. | ||||||
27 | * When creating an array with ``np.array(...)`` we have to do two main things: | ||||||
28 | * | ||||||
29 | * 1. Find the exact shape of the resulting array | ||||||
30 | * 2. Find the correct dtype of the resulting array. | ||||||
31 | * | ||||||
32 | * In most cases these two things are can be done in a single processing step. | ||||||
33 | * There are in principle three different calls that should be distinguished: | ||||||
34 | * | ||||||
35 | * 1. The user calls ``np.array(..., dtype=np.dtype("<f8"))`` | ||||||
36 | * 2. The user calls ``np.array(..., dtype="S")`` | ||||||
37 | * 3. The user calls ``np.array(...)`` | ||||||
38 | * | ||||||
39 | * In the first case, in principle only the shape needs to be found. In the | ||||||
40 | * second case, the DType class (e.g. string) is already known but the DType | ||||||
41 | * instance (e.g. length of the string) has to be found. | ||||||
42 | * In the last case the DType class needs to be found as well. Note that | ||||||
43 | * it is not necessary to find the DType class of the entire array, but | ||||||
44 | * the DType class needs to be found for each element before the actual | ||||||
45 | * dtype instance can be found. | ||||||
46 | * | ||||||
47 | * Further, there are a few other things to keep in mind when coercing arrays: | ||||||
48 | * | ||||||
49 | * * For UFunc promotion, Python scalars need to be handled specially to | ||||||
50 | * allow value based casting. This requires python complex/float to | ||||||
51 | * have their own DTypes. | ||||||
52 | * * It is necessary to decide whether or not a sequence is an element. | ||||||
53 | * For example tuples are considered elements for structured dtypes, but | ||||||
54 | * otherwise are considered sequences. | ||||||
55 | * This means that if a dtype is given (either as a class or instance), | ||||||
56 | * it can effect the dimension discovery part. | ||||||
57 | * For the "special" NumPy types structured void and "c" (single character) | ||||||
58 | * this is special cased. For future user-types, this is currently | ||||||
59 | * handled by providing calling an `is_known_scalar` method. This method | ||||||
60 | * currently ensures that Python numerical types are handled quickly. | ||||||
61 | * | ||||||
62 | * In the initial version of this implementation, it is assumed that dtype | ||||||
63 | * discovery can be implemented sufficiently fast. That is, it is not | ||||||
64 | * necessary to create fast paths that only find the correct shape e.g. when | ||||||
65 | * ``dtype=np.dtype("f8")`` is given. | ||||||
66 | * | ||||||
67 | * The code here avoid multiple conversion of array-like objects (including | ||||||
68 | * sequences). These objects are cached after conversion, which will require | ||||||
69 | * additional memory, but can drastically speed up coercion from from array | ||||||
70 | * like objects. | ||||||
71 | */ | ||||||
72 | |||||||
73 | |||||||
74 | /* | ||||||
75 | * For finding a DType quickly from a type, it is easiest to have a | ||||||
76 | * a mapping of pytype -> DType. | ||||||
77 | * TODO: This mapping means that it is currently impossible to delete a | ||||||
78 | * pair of pytype <-> DType. To resolve this, it is necessary to | ||||||
79 | * weakly reference the pytype. As long as the pytype is alive, we | ||||||
80 | * want to be able to use `np.array([pytype()])`. | ||||||
81 | * It should be possible to retrofit this without too much trouble | ||||||
82 | * (all type objects support weak references). | ||||||
83 | */ | ||||||
84 | PyObject *_global_pytype_to_type_dict = NULL((void*)0); | ||||||
85 | |||||||
86 | |||||||
87 | /* Enum to track or signal some things during dtype and shape discovery */ | ||||||
88 | enum _dtype_discovery_flags { | ||||||
89 | FOUND_RAGGED_ARRAY = 1 << 0, | ||||||
90 | GAVE_SUBCLASS_WARNING = 1 << 1, | ||||||
91 | PROMOTION_FAILED = 1 << 2, | ||||||
92 | DISCOVER_STRINGS_AS_SEQUENCES = 1 << 3, | ||||||
93 | DISCOVER_TUPLES_AS_ELEMENTS = 1 << 4, | ||||||
94 | MAX_DIMS_WAS_REACHED = 1 << 5, | ||||||
95 | DESCRIPTOR_WAS_SET = 1 << 6, | ||||||
96 | }; | ||||||
97 | |||||||
98 | |||||||
99 | /** | ||||||
100 | * Adds known sequence types to the global type dictionary, note that when | ||||||
101 | * a DType is passed in, this lookup may be ignored. | ||||||
102 | * | ||||||
103 | * @return -1 on error 0 on success | ||||||
104 | */ | ||||||
105 | static int | ||||||
106 | _prime_global_pytype_to_type_dict(void) | ||||||
107 | { | ||||||
108 | int res; | ||||||
109 | |||||||
110 | /* Add the basic Python sequence types */ | ||||||
111 | res = PyDict_SetItem(_global_pytype_to_type_dict, | ||||||
112 | (PyObject *)&PyList_Type, Py_None(&_Py_NoneStruct)); | ||||||
113 | if (res < 0) { | ||||||
114 | return -1; | ||||||
115 | } | ||||||
116 | res = PyDict_SetItem(_global_pytype_to_type_dict, | ||||||
117 | (PyObject *)&PyTuple_Type, Py_None(&_Py_NoneStruct)); | ||||||
118 | if (res < 0) { | ||||||
119 | return -1; | ||||||
120 | } | ||||||
121 | /* NumPy Arrays are not handled as scalars */ | ||||||
122 | res = PyDict_SetItem(_global_pytype_to_type_dict, | ||||||
123 | (PyObject *)&PyArray_Type, Py_None(&_Py_NoneStruct)); | ||||||
124 | if (res < 0) { | ||||||
125 | return -1; | ||||||
126 | } | ||||||
127 | return 0; | ||||||
128 | } | ||||||
129 | |||||||
130 | |||||||
131 | /** | ||||||
132 | * Add a new mapping from a python type to the DType class. For a user | ||||||
133 | * defined legacy dtype, this function does nothing unless the pytype | ||||||
134 | * subclass from `np.generic`. | ||||||
135 | * | ||||||
136 | * This assumes that the DType class is guaranteed to hold on the | ||||||
137 | * python type (this assumption is guaranteed). | ||||||
138 | * This functionality supercedes ``_typenum_fromtypeobj``. | ||||||
139 | * | ||||||
140 | * @param DType DType to map the python type to | ||||||
141 | * @param pytype Python type to map from | ||||||
142 | * @param userdef Whether or not it is user defined. We ensure that user | ||||||
143 | * defined scalars subclass from our scalars (for now). | ||||||
144 | */ | ||||||
145 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||
146 | _PyArray_MapPyTypeToDType( | ||||||
147 | PyArray_DTypeMeta *DType, PyTypeObject *pytype, npy_bool userdef) | ||||||
148 | { | ||||||
149 | PyObject *Dtype_obj = (PyObject *)DType; | ||||||
150 | |||||||
151 | if (userdef && !PyObject_IsSubclass( | ||||||
152 | (PyObject *)pytype, (PyObject *)&PyGenericArrType_Type)) { | ||||||
153 | /* | ||||||
154 | * We expect that user dtypes (for now) will subclass some numpy | ||||||
155 | * scalar class to allow automatic discovery. | ||||||
156 | */ | ||||||
157 | if (DType->legacy) { | ||||||
158 | /* | ||||||
159 | * For legacy user dtypes, discovery relied on subclassing, but | ||||||
160 | * arbitrary type objects are supported, so do nothing. | ||||||
161 | */ | ||||||
162 | return 0; | ||||||
163 | } | ||||||
164 | /* | ||||||
165 | * We currently enforce that user DTypes subclass from `np.generic` | ||||||
166 | * (this should become a `np.generic` base class and may be lifted | ||||||
167 | * entirely). | ||||||
168 | */ | ||||||
169 | PyErr_Format(PyExc_RuntimeError, | ||||||
170 | "currently it is only possible to register a DType " | ||||||
171 | "for scalars deriving from `np.generic`, got '%S'.", | ||||||
172 | (PyObject *)pytype); | ||||||
173 | return -1; | ||||||
174 | } | ||||||
175 | |||||||
176 | /* Create the global dictionary if it does not exist */ | ||||||
177 | if (NPY_UNLIKELY(_global_pytype_to_type_dict == NULL)__builtin_expect(!!(_global_pytype_to_type_dict == ((void*)0) ), 0)) { | ||||||
178 | _global_pytype_to_type_dict = PyDict_New(); | ||||||
179 | if (_global_pytype_to_type_dict == NULL((void*)0)) { | ||||||
180 | return -1; | ||||||
181 | } | ||||||
182 | if (_prime_global_pytype_to_type_dict() < 0) { | ||||||
183 | return -1; | ||||||
184 | } | ||||||
185 | } | ||||||
186 | |||||||
187 | int res = PyDict_Contains(_global_pytype_to_type_dict, (PyObject *)pytype); | ||||||
188 | if (res < 0) { | ||||||
189 | return -1; | ||||||
190 | } | ||||||
191 | else if (res) { | ||||||
192 | PyErr_SetString(PyExc_RuntimeError, | ||||||
193 | "Can only map one python type to DType."); | ||||||
194 | return -1; | ||||||
195 | } | ||||||
196 | |||||||
197 | return PyDict_SetItem(_global_pytype_to_type_dict, | ||||||
198 | (PyObject *)pytype, Dtype_obj); | ||||||
199 | } | ||||||
200 | |||||||
201 | |||||||
202 | /** | ||||||
203 | * Lookup the DType for a registered known python scalar type. | ||||||
204 | * | ||||||
205 | * @param pytype Python Type to look up | ||||||
206 | * @return DType, None if it a known non-scalar, or NULL if an unknown object. | ||||||
207 | */ | ||||||
208 | static NPY_INLINEinline PyArray_DTypeMeta * | ||||||
209 | npy_discover_dtype_from_pytype(PyTypeObject *pytype) | ||||||
210 | { | ||||||
211 | PyObject *DType; | ||||||
212 | |||||||
213 | if (pytype == &PyArray_Type) { | ||||||
214 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | ||||||
215 | return (PyArray_DTypeMeta *)Py_None(&_Py_NoneStruct); | ||||||
216 | } | ||||||
217 | |||||||
218 | DType = PyDict_GetItem(_global_pytype_to_type_dict, (PyObject *)pytype); | ||||||
219 | if (DType == NULL((void*)0)) { | ||||||
220 | /* the python type is not known */ | ||||||
221 | return NULL((void*)0); | ||||||
222 | } | ||||||
223 | |||||||
224 | Py_INCREF(DType)_Py_INCREF(((PyObject*)(DType))); | ||||||
225 | if (DType == Py_None(&_Py_NoneStruct)) { | ||||||
226 | return (PyArray_DTypeMeta *)Py_None(&_Py_NoneStruct); | ||||||
227 | } | ||||||
228 | assert(PyObject_TypeCheck(DType, (PyTypeObject *)&PyArrayDTypeMeta_Type))((void) (0)); | ||||||
229 | return (PyArray_DTypeMeta *)DType; | ||||||
230 | } | ||||||
231 | |||||||
232 | |||||||
233 | /** | ||||||
234 | * Find the correct DType class for the given python type. If flags is NULL | ||||||
235 | * this is not used to discover a dtype, but only for conversion to an | ||||||
236 | * existing dtype. In that case the Python (not NumPy) scalar subclass | ||||||
237 | * checks are skipped. | ||||||
238 | * | ||||||
239 | * @param obj The python object, mainly type(pyobj) is used, the object | ||||||
240 | * is passed to reuse existing code at this time only. | ||||||
241 | * @param flags Flags used to know if warnings were already given. If | ||||||
242 | * flags is NULL, this is not | ||||||
243 | * @param fixed_DType if not NULL, will be checked first for whether or not | ||||||
244 | * it can/wants to handle the (possible) scalar value. | ||||||
245 | * @return New reference to either a DType class, Py_None, or NULL on error. | ||||||
246 | */ | ||||||
247 | static NPY_INLINEinline PyArray_DTypeMeta * | ||||||
248 | discover_dtype_from_pyobject( | ||||||
249 | PyObject *obj, enum _dtype_discovery_flags *flags, | ||||||
250 | PyArray_DTypeMeta *fixed_DType) | ||||||
251 | { | ||||||
252 | if (fixed_DType != NULL((void*)0)) { | ||||||
253 | /* | ||||||
254 | * Let the given DType handle the discovery. This is when the | ||||||
255 | * scalar-type matches exactly, or the DType signals that it can | ||||||
256 | * handle the scalar-type. (Even if it cannot handle here it may be | ||||||
257 | * asked to attempt to do so later, if no other matching DType exists.) | ||||||
258 | */ | ||||||
259 | if ((Py_TYPE(obj)(((PyObject*)(obj))->ob_type) == fixed_DType->scalar_type) || | ||||||
260 | (fixed_DType->is_known_scalar_type != NULL((void*)0) && | ||||||
261 | fixed_DType->is_known_scalar_type(fixed_DType, Py_TYPE(obj)(((PyObject*)(obj))->ob_type)))) { | ||||||
262 | Py_INCREF(fixed_DType)_Py_INCREF(((PyObject*)(fixed_DType))); | ||||||
263 | return fixed_DType; | ||||||
264 | } | ||||||
265 | } | ||||||
266 | |||||||
267 | PyArray_DTypeMeta *DType = npy_discover_dtype_from_pytype(Py_TYPE(obj)(((PyObject*)(obj))->ob_type)); | ||||||
268 | if (DType != NULL((void*)0)) { | ||||||
269 | return DType; | ||||||
270 | } | ||||||
271 | /* | ||||||
272 | * At this point we have not found a clear mapping, but mainly for | ||||||
273 | * backward compatibility we have to make some further attempts at | ||||||
274 | * interpreting the input as a known scalar type. | ||||||
275 | */ | ||||||
276 | PyArray_Descr *legacy_descr; | ||||||
277 | if (PyArray_IsScalar(obj, Generic)(((((PyObject*)(obj))->ob_type) == (&PyGenericArrType_Type ) || PyType_IsSubtype((((PyObject*)(obj))->ob_type), (& PyGenericArrType_Type))))) { | ||||||
278 | legacy_descr = PyArray_DescrFromScalar(obj); | ||||||
279 | if (legacy_descr == NULL((void*)0)) { | ||||||
280 | return NULL((void*)0); | ||||||
281 | } | ||||||
282 | } | ||||||
283 | else if (flags == NULL((void*)0)) { | ||||||
284 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | ||||||
285 | return (PyArray_DTypeMeta *)Py_None(&_Py_NoneStruct); | ||||||
286 | } | ||||||
287 | else if (PyBytes_Check(obj)((((((PyObject*)(obj))->ob_type))->tp_flags & ((1UL << 27))) != 0)) { | ||||||
288 | legacy_descr = PyArray_DescrFromType(NPY_BYTE); | ||||||
289 | } | ||||||
290 | else if (PyUnicode_Check(obj)((((((PyObject*)(obj))->ob_type))->tp_flags & ((1UL << 28))) != 0)) { | ||||||
291 | legacy_descr = PyArray_DescrFromType(NPY_UNICODE); | ||||||
292 | } | ||||||
293 | else { | ||||||
294 | legacy_descr = _array_find_python_scalar_type(obj); | ||||||
295 | } | ||||||
296 | |||||||
297 | if (legacy_descr != NULL((void*)0)) { | ||||||
298 | DType = NPY_DTYPE(legacy_descr)((PyArray_DTypeMeta *)(((PyObject*)(legacy_descr))->ob_type )); | ||||||
299 | Py_INCREF(DType)_Py_INCREF(((PyObject*)(DType))); | ||||||
300 | Py_DECREF(legacy_descr)_Py_DECREF(((PyObject*)(legacy_descr))); | ||||||
301 | /* TODO: Enable warning about subclass handling */ | ||||||
302 | if ((0) && !((*flags) & GAVE_SUBCLASS_WARNING)) { | ||||||
303 | if (DEPRECATE_FUTUREWARNING(PyErr_WarnEx(PyExc_FutureWarning,"in the future NumPy will not automatically find the " "dtype for subclasses of scalars known to NumPy (i.e. " "python types). Use the appropriate `dtype=...` to create " "this array. This will use the `object` dtype or raise " "an error in the future." ,1) | ||||||
304 | "in the future NumPy will not automatically find the "PyErr_WarnEx(PyExc_FutureWarning,"in the future NumPy will not automatically find the " "dtype for subclasses of scalars known to NumPy (i.e. " "python types). Use the appropriate `dtype=...` to create " "this array. This will use the `object` dtype or raise " "an error in the future." ,1) | ||||||
305 | "dtype for subclasses of scalars known to NumPy (i.e. "PyErr_WarnEx(PyExc_FutureWarning,"in the future NumPy will not automatically find the " "dtype for subclasses of scalars known to NumPy (i.e. " "python types). Use the appropriate `dtype=...` to create " "this array. This will use the `object` dtype or raise " "an error in the future." ,1) | ||||||
306 | "python types). Use the appropriate `dtype=...` to create "PyErr_WarnEx(PyExc_FutureWarning,"in the future NumPy will not automatically find the " "dtype for subclasses of scalars known to NumPy (i.e. " "python types). Use the appropriate `dtype=...` to create " "this array. This will use the `object` dtype or raise " "an error in the future." ,1) | ||||||
307 | "this array. This will use the `object` dtype or raise "PyErr_WarnEx(PyExc_FutureWarning,"in the future NumPy will not automatically find the " "dtype for subclasses of scalars known to NumPy (i.e. " "python types). Use the appropriate `dtype=...` to create " "this array. This will use the `object` dtype or raise " "an error in the future." ,1) | ||||||
308 | "an error in the future.")PyErr_WarnEx(PyExc_FutureWarning,"in the future NumPy will not automatically find the " "dtype for subclasses of scalars known to NumPy (i.e. " "python types). Use the appropriate `dtype=...` to create " "this array. This will use the `object` dtype or raise " "an error in the future." ,1) < 0) { | ||||||
309 | return NULL((void*)0); | ||||||
310 | } | ||||||
311 | *flags |= GAVE_SUBCLASS_WARNING; | ||||||
312 | } | ||||||
313 | return DType; | ||||||
314 | } | ||||||
315 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | ||||||
316 | return (PyArray_DTypeMeta *)Py_None(&_Py_NoneStruct); | ||||||
317 | } | ||||||
318 | |||||||
319 | |||||||
320 | /** | ||||||
321 | * Discover the correct descriptor from a known DType class and scalar. | ||||||
322 | * If the fixed DType can discover a dtype instance/descr all is fine, | ||||||
323 | * if it cannot and DType is used instead, a cast will have to be tried. | ||||||
324 | * | ||||||
325 | * @param fixed_DType A user provided fixed DType, can be NULL | ||||||
326 | * @param DType A discovered DType (by discover_dtype_from_pyobject); | ||||||
327 | * this can be identical to `fixed_DType`, if it obj is a | ||||||
328 | * known scalar. Can be `NULL` indicating no known type. | ||||||
329 | * @param obj The Python scalar object. At the time of calling this function | ||||||
330 | * it must be known that `obj` should represent a scalar. | ||||||
331 | */ | ||||||
332 | static NPY_INLINEinline PyArray_Descr * | ||||||
333 | find_scalar_descriptor( | ||||||
334 | PyArray_DTypeMeta *fixed_DType, PyArray_DTypeMeta *DType, | ||||||
335 | PyObject *obj) | ||||||
336 | { | ||||||
337 | PyArray_Descr *descr; | ||||||
338 | |||||||
339 | if (DType == NULL((void*)0) && fixed_DType == NULL((void*)0)) { | ||||||
340 | /* No known DType and no fixed one means we go to object. */ | ||||||
341 | return PyArray_DescrFromType(NPY_OBJECT); | ||||||
342 | } | ||||||
343 | else if (DType == NULL((void*)0)) { | ||||||
344 | /* | ||||||
345 | * If no DType is known/found, give the fixed give one a second | ||||||
346 | * chance. This allows for example string, to call `str(obj)` to | ||||||
347 | * figure out the length for arbitrary objects. | ||||||
348 | */ | ||||||
349 | descr = fixed_DType->discover_descr_from_pyobject(fixed_DType, obj); | ||||||
350 | } | ||||||
351 | else { | ||||||
352 | descr = DType->discover_descr_from_pyobject(DType, obj); | ||||||
353 | } | ||||||
354 | if (descr == NULL((void*)0)) { | ||||||
355 | return NULL((void*)0); | ||||||
356 | } | ||||||
357 | if (fixed_DType == NULL((void*)0)) { | ||||||
358 | return descr; | ||||||
359 | } | ||||||
360 | |||||||
361 | Py_SETREF(descr, PyArray_CastDescrToDType(descr, fixed_DType))do { PyObject *_py_tmp = ((PyObject*)(descr)); (descr) = (PyArray_CastDescrToDType (descr, fixed_DType)); _Py_DECREF(((PyObject*)(_py_tmp))); } while (0); | ||||||
362 | return descr; | ||||||
363 | } | ||||||
364 | |||||||
365 | |||||||
366 | /** | ||||||
367 | * Assign a single element in an array from a python value. | ||||||
368 | * | ||||||
369 | * The dtypes SETITEM should only be trusted to generally do the right | ||||||
370 | * thing if something is known to be a scalar *and* is of a python type known | ||||||
371 | * to the DType (which should include all basic Python math types), but in | ||||||
372 | * general a cast may be necessary. | ||||||
373 | * This function handles the cast, which is for example hit when assigning | ||||||
374 | * a float128 to complex128. | ||||||
375 | * | ||||||
376 | * At this time, this function does not support arrays (historically we | ||||||
377 | * mainly supported arrays through `__float__()`, etc.). Such support should | ||||||
378 | * possibly be added (although when called from `PyArray_AssignFromCache` | ||||||
379 | * the input cannot be an array). | ||||||
380 | * Note that this is also problematic for some array-likes, such as | ||||||
381 | * `astropy.units.Quantity` and `np.ma.masked`. These are used to us calling | ||||||
382 | * `__float__`/`__int__` for 0-D instances in many cases. | ||||||
383 | * Eventually, we may want to define this as wrong: They must use DTypes | ||||||
384 | * instead of (only) subclasses. Until then, here as well as in | ||||||
385 | * `PyArray_AssignFromCache` (which already does this), we need to special | ||||||
386 | * case 0-D array-likes to behave like arbitrary (unknown!) Python objects. | ||||||
387 | * | ||||||
388 | * @param descr | ||||||
389 | * @param item | ||||||
390 | * @param value | ||||||
391 | * @return 0 on success -1 on failure. | ||||||
392 | */ | ||||||
393 | /* | ||||||
394 | * TODO: This function should possibly be public API. | ||||||
395 | */ | ||||||
396 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||
397 | PyArray_Pack(PyArray_Descr *descr, char *item, PyObject *value) | ||||||
398 | { | ||||||
399 | PyArrayObject_fields arr_fields = { | ||||||
400 | .flags = NPY_ARRAY_WRITEABLE0x0400, /* assume array is not behaved. */ | ||||||
401 | }; | ||||||
402 | Py_SET_TYPE(&arr_fields, &PyArray_Type)(((((PyObject*)(&arr_fields))->ob_type) = (&PyArray_Type )), (void)0); | ||||||
403 | Py_SET_REFCNT(&arr_fields, 1)(((((PyObject*)(&arr_fields))->ob_refcnt) = (1)), (void )0); | ||||||
404 | |||||||
405 | if (NPY_UNLIKELY(descr->type_num == NPY_OBJECT)__builtin_expect(!!(descr->type_num == NPY_OBJECT), 0)) { | ||||||
406 | /* | ||||||
407 | * We always have store objects directly, casting will lose some | ||||||
408 | * type information. Any other dtype discards the type information. | ||||||
409 | * TODO: For a Categorical[object] this path may be necessary? | ||||||
410 | */ | ||||||
411 | arr_fields.descr = descr; | ||||||
412 | return descr->f->setitem(value, item, &arr_fields); | ||||||
413 | } | ||||||
414 | |||||||
415 | /* discover_dtype_from_pyobject includes a check for is_known_scalar_type */ | ||||||
416 | PyArray_DTypeMeta *DType = discover_dtype_from_pyobject( | ||||||
417 | value, NULL((void*)0), NPY_DTYPE(descr)((PyArray_DTypeMeta *)(((PyObject*)(descr))->ob_type))); | ||||||
418 | if (DType == NULL((void*)0)) { | ||||||
419 | return -1; | ||||||
420 | } | ||||||
421 | if (DType == NPY_DTYPE(descr)((PyArray_DTypeMeta *)(((PyObject*)(descr))->ob_type)) || DType == (PyArray_DTypeMeta *)Py_None(&_Py_NoneStruct)) { | ||||||
422 | /* We can set the element directly (or at least will try to) */ | ||||||
423 | Py_XDECREF(DType)_Py_XDECREF(((PyObject*)(DType))); | ||||||
424 | arr_fields.descr = descr; | ||||||
425 | return descr->f->setitem(value, item, &arr_fields); | ||||||
426 | } | ||||||
427 | PyArray_Descr *tmp_descr; | ||||||
428 | tmp_descr = DType->discover_descr_from_pyobject(DType, value); | ||||||
429 | Py_DECREF(DType)_Py_DECREF(((PyObject*)(DType))); | ||||||
430 | if (tmp_descr == NULL((void*)0)) { | ||||||
431 | return -1; | ||||||
432 | } | ||||||
433 | |||||||
434 | char *data = PyObject_Malloc(tmp_descr->elsize); | ||||||
435 | if (data == NULL((void*)0)) { | ||||||
436 | PyErr_NoMemory(); | ||||||
437 | Py_DECREF(tmp_descr)_Py_DECREF(((PyObject*)(tmp_descr))); | ||||||
438 | return -1; | ||||||
439 | } | ||||||
440 | if (PyDataType_FLAGCHK(tmp_descr, NPY_NEEDS_INIT)(((tmp_descr)->flags & (0x08)) == (0x08))) { | ||||||
441 | memset(data, 0, tmp_descr->elsize); | ||||||
442 | } | ||||||
443 | arr_fields.descr = tmp_descr; | ||||||
444 | if (tmp_descr->f->setitem(value, data, &arr_fields) < 0) { | ||||||
445 | PyObject_Free(data); | ||||||
446 | Py_DECREF(tmp_descr)_Py_DECREF(((PyObject*)(tmp_descr))); | ||||||
447 | return -1; | ||||||
448 | } | ||||||
449 | if (PyDataType_REFCHK(tmp_descr)(((tmp_descr)->flags & (0x01)) == (0x01))) { | ||||||
450 | /* We could probably use move-references above */ | ||||||
451 | PyArray_Item_INCREF(data, tmp_descr); | ||||||
452 | } | ||||||
453 | |||||||
454 | int res = 0; | ||||||
455 | int needs_api = 0; | ||||||
456 | NPY_cast_info cast_info; | ||||||
457 | if (PyArray_GetDTypeTransferFunction( | ||||||
458 | 0, 0, 0, tmp_descr, descr, 0, &cast_info, | ||||||
459 | &needs_api) == NPY_FAIL0) { | ||||||
460 | res = -1; | ||||||
461 | goto finish; | ||||||
462 | } | ||||||
463 | char *args[2] = {data, item}; | ||||||
464 | const npy_intp strides[2] = {0, 0}; | ||||||
465 | const npy_intp length = 1; | ||||||
466 | if (cast_info.func(&cast_info.context, | ||||||
467 | args, &length, strides, cast_info.auxdata) < 0) { | ||||||
468 | res = -1; | ||||||
469 | } | ||||||
470 | NPY_cast_info_xfree(&cast_info); | ||||||
471 | |||||||
472 | finish: | ||||||
473 | if (PyDataType_REFCHK(tmp_descr)(((tmp_descr)->flags & (0x01)) == (0x01))) { | ||||||
474 | /* We could probably use move-references above */ | ||||||
475 | PyArray_Item_XDECREF(data, tmp_descr); | ||||||
476 | } | ||||||
477 | PyObject_Free(data); | ||||||
478 | Py_DECREF(tmp_descr)_Py_DECREF(((PyObject*)(tmp_descr))); | ||||||
479 | return res; | ||||||
480 | } | ||||||
481 | |||||||
482 | |||||||
483 | static int | ||||||
484 | update_shape(int curr_ndim, int *max_ndim, | ||||||
485 | npy_intp out_shape[NPY_MAXDIMS32], int new_ndim, | ||||||
486 | const npy_intp new_shape[NPY_MAXDIMS32], npy_bool sequence, | ||||||
487 | enum _dtype_discovery_flags *flags) | ||||||
488 | { | ||||||
489 | int success = 0; /* unsuccessful if array is ragged */ | ||||||
490 | const npy_bool max_dims_reached = *flags & MAX_DIMS_WAS_REACHED; | ||||||
491 | |||||||
492 | if (curr_ndim + new_ndim > *max_ndim) { | ||||||
493 | success = -1; | ||||||
494 | /* Only update/check as many dims as possible, max_ndim is unchanged */ | ||||||
495 | new_ndim = *max_ndim - curr_ndim; | ||||||
496 | } | ||||||
497 | else if (!sequence && (*max_ndim != curr_ndim + new_ndim)) { | ||||||
498 | /* | ||||||
499 | * Sequences do not update max_ndim, otherwise shrink and check. | ||||||
500 | * This is depth first, so if it is already set, `out_shape` is filled. | ||||||
501 | */ | ||||||
502 | *max_ndim = curr_ndim + new_ndim; | ||||||
503 | /* If a shape was already set, this is also ragged */ | ||||||
504 | if (max_dims_reached) { | ||||||
505 | success = -1; | ||||||
506 | } | ||||||
507 | } | ||||||
508 | for (int i = 0; i < new_ndim; i++) { | ||||||
509 | npy_intp curr_dim = out_shape[curr_ndim + i]; | ||||||
510 | npy_intp new_dim = new_shape[i]; | ||||||
511 | |||||||
512 | if (!max_dims_reached) { | ||||||
513 | out_shape[curr_ndim + i] = new_dim; | ||||||
514 | } | ||||||
515 | else if (new_dim != curr_dim) { | ||||||
516 | /* The array is ragged, and this dimension is unusable already */ | ||||||
517 | success = -1; | ||||||
518 | if (!sequence) { | ||||||
519 | /* Remove dimensions that we cannot use: */ | ||||||
520 | *max_ndim -= new_ndim - i; | ||||||
521 | } | ||||||
522 | else { | ||||||
523 | assert(i == 0)((void) (0)); | ||||||
524 | /* max_ndim is usually not updated for sequences, so set now: */ | ||||||
525 | *max_ndim = curr_ndim; | ||||||
526 | } | ||||||
527 | break; | ||||||
528 | } | ||||||
529 | } | ||||||
530 | if (!sequence) { | ||||||
531 | *flags |= MAX_DIMS_WAS_REACHED; | ||||||
532 | } | ||||||
533 | return success; | ||||||
534 | } | ||||||
535 | |||||||
536 | |||||||
537 | #define COERCION_CACHE_CACHE_SIZE 5 | ||||||
538 | static int _coercion_cache_num = 0; | ||||||
539 | static coercion_cache_obj *_coercion_cache_cache[COERCION_CACHE_CACHE_SIZE]; | ||||||
540 | |||||||
541 | /* | ||||||
542 | * Steals a reference to the object. | ||||||
543 | */ | ||||||
544 | static NPY_INLINEinline int | ||||||
545 | npy_new_coercion_cache( | ||||||
546 | PyObject *converted_obj, PyObject *arr_or_sequence, npy_bool sequence, | ||||||
547 | coercion_cache_obj ***next_ptr, int ndim) | ||||||
548 | { | ||||||
549 | coercion_cache_obj *cache; | ||||||
550 | if (_coercion_cache_num > 0) { | ||||||
551 | _coercion_cache_num--; | ||||||
552 | cache = _coercion_cache_cache[_coercion_cache_num]; | ||||||
553 | } | ||||||
554 | else { | ||||||
555 | cache = PyMem_Malloc(sizeof(coercion_cache_obj)); | ||||||
556 | } | ||||||
557 | if (cache == NULL((void*)0)) { | ||||||
558 | PyErr_NoMemory(); | ||||||
559 | return -1; | ||||||
560 | } | ||||||
561 | cache->converted_obj = converted_obj; | ||||||
562 | cache->arr_or_sequence = arr_or_sequence; | ||||||
563 | cache->sequence = sequence; | ||||||
564 | cache->depth = ndim; | ||||||
565 | cache->next = NULL((void*)0); | ||||||
566 | **next_ptr = cache; | ||||||
567 | *next_ptr = &(cache->next); | ||||||
568 | return 0; | ||||||
569 | } | ||||||
570 | |||||||
571 | /** | ||||||
572 | * Unlink coercion cache item. | ||||||
573 | * | ||||||
574 | * @param current | ||||||
575 | * @return next coercion cache object (or NULL) | ||||||
576 | */ | ||||||
577 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) coercion_cache_obj * | ||||||
578 | npy_unlink_coercion_cache(coercion_cache_obj *current) | ||||||
579 | { | ||||||
580 | coercion_cache_obj *next = current->next; | ||||||
581 | Py_DECREF(current->arr_or_sequence)_Py_DECREF(((PyObject*)(current->arr_or_sequence))); | ||||||
582 | if (_coercion_cache_num < COERCION_CACHE_CACHE_SIZE) { | ||||||
583 | _coercion_cache_cache[_coercion_cache_num] = current; | ||||||
584 | _coercion_cache_num++; | ||||||
585 | } | ||||||
586 | else { | ||||||
587 | PyMem_Free(current); | ||||||
588 | } | ||||||
589 | return next; | ||||||
590 | } | ||||||
591 | |||||||
592 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) void | ||||||
593 | npy_free_coercion_cache(coercion_cache_obj *next) { | ||||||
594 | /* We only need to check from the last used cache pos */ | ||||||
595 | while (next != NULL((void*)0)) { | ||||||
596 | next = npy_unlink_coercion_cache(next); | ||||||
597 | } | ||||||
598 | } | ||||||
599 | |||||||
600 | #undef COERCION_CACHE_CACHE_SIZE | ||||||
601 | |||||||
602 | /** | ||||||
603 | * Do the promotion step and possible casting. This function should | ||||||
604 | * never be called if a descriptor was requested. In that case the output | ||||||
605 | * dtype is not of importance, so we must not risk promotion errors. | ||||||
606 | * | ||||||
607 | * @param out_descr The current descriptor. | ||||||
608 | * @param descr The newly found descriptor to promote with | ||||||
609 | * @param fixed_DType The user provided (fixed) DType or NULL | ||||||
610 | * @param flags dtype discover flags to signal failed promotion. | ||||||
611 | * @return -1 on error, 0 on success. | ||||||
612 | */ | ||||||
613 | static NPY_INLINEinline int | ||||||
614 | handle_promotion(PyArray_Descr **out_descr, PyArray_Descr *descr, | ||||||
615 | PyArray_DTypeMeta *fixed_DType, enum _dtype_discovery_flags *flags) | ||||||
616 | { | ||||||
617 | assert(!(*flags & DESCRIPTOR_WAS_SET))((void) (0)); | ||||||
618 | |||||||
619 | if (*out_descr == NULL((void*)0)) { | ||||||
620 | Py_INCREF(descr)_Py_INCREF(((PyObject*)(descr))); | ||||||
621 | *out_descr = descr; | ||||||
622 | return 0; | ||||||
623 | } | ||||||
624 | PyArray_Descr *new_descr = PyArray_PromoteTypes(descr, *out_descr); | ||||||
625 | if (NPY_UNLIKELY(new_descr == NULL)__builtin_expect(!!(new_descr == ((void*)0)), 0)) { | ||||||
626 | if (fixed_DType != NULL((void*)0) || PyErr_ExceptionMatches(PyExc_FutureWarning)) { | ||||||
627 | /* | ||||||
628 | * If a DType is fixed, promotion must not fail. Do not catch | ||||||
629 | * FutureWarning (raised for string+numeric promotions). We could | ||||||
630 | * only catch TypeError here or even always raise the error. | ||||||
631 | */ | ||||||
632 | return -1; | ||||||
633 | } | ||||||
634 | PyErr_Clear(); | ||||||
635 | *flags |= PROMOTION_FAILED; | ||||||
636 | /* Continue with object, since we may need the dimensionality */ | ||||||
637 | new_descr = PyArray_DescrFromType(NPY_OBJECT); | ||||||
638 | } | ||||||
639 | Py_SETREF(*out_descr, new_descr)do { PyObject *_py_tmp = ((PyObject*)(*out_descr)); (*out_descr ) = (new_descr); _Py_DECREF(((PyObject*)(_py_tmp))); } while ( 0); | ||||||
640 | return 0; | ||||||
641 | } | ||||||
642 | |||||||
643 | |||||||
644 | /** | ||||||
645 | * Handle a leave node (known scalar) during dtype and shape discovery. | ||||||
646 | * | ||||||
647 | * @param obj The python object or nested sequence to convert | ||||||
648 | * @param curr_dims The current number of dimensions (depth in the recursion) | ||||||
649 | * @param max_dims The maximum number of dimensions. | ||||||
650 | * @param out_shape The discovered output shape, will be filled | ||||||
651 | * @param fixed_DType The user provided (fixed) DType or NULL | ||||||
652 | * @param flags used signal that this is a ragged array, used internally and | ||||||
653 | * can be expanded if necessary. | ||||||
654 | * @param DType the DType class that should be used, or NULL, if not provided. | ||||||
655 | * | ||||||
656 | * @return 0 on success -1 on error | ||||||
657 | */ | ||||||
658 | static NPY_INLINEinline int | ||||||
659 | handle_scalar( | ||||||
660 | PyObject *obj, int curr_dims, int *max_dims, | ||||||
661 | PyArray_Descr **out_descr, npy_intp *out_shape, | ||||||
662 | PyArray_DTypeMeta *fixed_DType, | ||||||
663 | enum _dtype_discovery_flags *flags, PyArray_DTypeMeta *DType) | ||||||
664 | { | ||||||
665 | PyArray_Descr *descr; | ||||||
666 | |||||||
667 | if (update_shape(curr_dims, max_dims, out_shape, | ||||||
668 | 0, NULL((void*)0), NPY_FALSE0, flags) < 0) { | ||||||
669 | *flags |= FOUND_RAGGED_ARRAY; | ||||||
670 | return *max_dims; | ||||||
671 | } | ||||||
672 | if (*flags & DESCRIPTOR_WAS_SET) { | ||||||
673 | /* no need to do any promotion */ | ||||||
674 | return *max_dims; | ||||||
675 | } | ||||||
676 | /* This is a scalar, so find the descriptor */ | ||||||
677 | descr = find_scalar_descriptor(fixed_DType, DType, obj); | ||||||
678 | if (descr == NULL((void*)0)) { | ||||||
679 | return -1; | ||||||
680 | } | ||||||
681 | if (handle_promotion(out_descr, descr, fixed_DType, flags) < 0) { | ||||||
682 | Py_DECREF(descr)_Py_DECREF(((PyObject*)(descr))); | ||||||
683 | return -1; | ||||||
684 | } | ||||||
685 | Py_DECREF(descr)_Py_DECREF(((PyObject*)(descr))); | ||||||
686 | return *max_dims; | ||||||
687 | } | ||||||
688 | |||||||
689 | |||||||
690 | /** | ||||||
691 | * Return the correct descriptor given an array object and a DType class. | ||||||
692 | * | ||||||
693 | * This is identical to casting the arrays descriptor/dtype to the new | ||||||
694 | * DType class | ||||||
695 | * | ||||||
696 | * @param arr The array object. | ||||||
697 | * @param DType The DType class to cast to (or NULL for convenience) | ||||||
698 | * @param out_descr The output descriptor will set. The result can be NULL | ||||||
699 | * when the array is of object dtype and has no elements. | ||||||
700 | * | ||||||
701 | * @return -1 on failure, 0 on success. | ||||||
702 | */ | ||||||
703 | static int | ||||||
704 | find_descriptor_from_array( | ||||||
705 | PyArrayObject *arr, PyArray_DTypeMeta *DType, PyArray_Descr **out_descr) | ||||||
706 | { | ||||||
707 | enum _dtype_discovery_flags flags = 0; | ||||||
708 | *out_descr = NULL((void*)0); | ||||||
709 | |||||||
710 | if (DType == NULL((void*)0)) { | ||||||
711 | *out_descr = PyArray_DESCR(arr); | ||||||
712 | Py_INCREF(*out_descr)_Py_INCREF(((PyObject*)(*out_descr))); | ||||||
713 | return 0; | ||||||
714 | } | ||||||
715 | |||||||
716 | if (NPY_UNLIKELY(DType->parametric && PyArray_ISOBJECT(arr))__builtin_expect(!!(DType->parametric && ((PyArray_TYPE (arr)) == NPY_OBJECT)), 0)) { | ||||||
717 | /* | ||||||
718 | * We have one special case, if (and only if) the input array is of | ||||||
719 | * object DType and the dtype is not fixed already but parametric. | ||||||
720 | * Then, we allow inspection of all elements, treating them as | ||||||
721 | * elements. We do this recursively, so nested 0-D arrays can work, | ||||||
722 | * but nested higher dimensional arrays will lead to an error. | ||||||
723 | */ | ||||||
724 | assert(DType->type_num != NPY_OBJECT)((void) (0)); /* not parametric */ | ||||||
725 | |||||||
726 | PyArrayIterObject *iter; | ||||||
727 | iter = (PyArrayIterObject *)PyArray_IterNew((PyObject *)arr); | ||||||
728 | if (iter == NULL((void*)0)) { | ||||||
729 | return -1; | ||||||
730 | } | ||||||
731 | while (iter->index < iter->size) { | ||||||
732 | PyArray_DTypeMeta *item_DType; | ||||||
733 | /* | ||||||
734 | * Note: If the array contains typed objects we may need to use | ||||||
735 | * the dtype to use casting for finding the correct instance. | ||||||
736 | */ | ||||||
737 | PyObject *elem = PyArray_GETITEM(arr, iter->dataptr); | ||||||
738 | if (elem == NULL((void*)0)) { | ||||||
739 | Py_DECREF(iter)_Py_DECREF(((PyObject*)(iter))); | ||||||
740 | return -1; | ||||||
741 | } | ||||||
742 | item_DType = discover_dtype_from_pyobject(elem, &flags, DType); | ||||||
743 | if (item_DType == NULL((void*)0)) { | ||||||
744 | Py_DECREF(iter)_Py_DECREF(((PyObject*)(iter))); | ||||||
745 | Py_DECREF(elem)_Py_DECREF(((PyObject*)(elem))); | ||||||
746 | return -1; | ||||||
747 | } | ||||||
748 | if (item_DType == (PyArray_DTypeMeta *)Py_None(&_Py_NoneStruct)) { | ||||||
749 | Py_SETREF(item_DType, NULL)do { PyObject *_py_tmp = ((PyObject*)(item_DType)); (item_DType ) = (((void*)0)); _Py_DECREF(((PyObject*)(_py_tmp))); } while (0); | ||||||
750 | } | ||||||
751 | int flat_max_dims = 0; | ||||||
752 | if (handle_scalar(elem, 0, &flat_max_dims, out_descr, | ||||||
753 | NULL((void*)0), DType, &flags, item_DType) < 0) { | ||||||
754 | Py_DECREF(iter)_Py_DECREF(((PyObject*)(iter))); | ||||||
755 | Py_DECREF(elem)_Py_DECREF(((PyObject*)(elem))); | ||||||
756 | Py_XDECREF(*out_descr)_Py_XDECREF(((PyObject*)(*out_descr))); | ||||||
757 | Py_XDECREF(item_DType)_Py_XDECREF(((PyObject*)(item_DType))); | ||||||
758 | return -1; | ||||||
759 | } | ||||||
760 | Py_XDECREF(item_DType)_Py_XDECREF(((PyObject*)(item_DType))); | ||||||
761 | Py_DECREF(elem)_Py_DECREF(((PyObject*)(elem))); | ||||||
762 | PyArray_ITER_NEXT(iter)do { ((PyArrayIterObject *)(iter))->index++; if (((PyArrayIterObject *)(iter))->nd_m1 == 0) { do { (((PyArrayIterObject *)(iter )))->dataptr += ((PyArrayIterObject *)(((PyArrayIterObject *)(iter))))->strides[0]; (((PyArrayIterObject *)(iter)))-> coordinates[0]++; } while (0); } else if (((PyArrayIterObject *)(iter))->contiguous) ((PyArrayIterObject *)(iter))-> dataptr += PyArray_DESCR(((PyArrayIterObject *)(iter))->ao )->elsize; else if (((PyArrayIterObject *)(iter))->nd_m1 == 1) { do { if ((((PyArrayIterObject *)(iter)))->coordinates [1] < (((PyArrayIterObject *)(iter)))->dims_m1[1]) { (( (PyArrayIterObject *)(iter)))->coordinates[1]++; (((PyArrayIterObject *)(iter)))->dataptr += (((PyArrayIterObject *)(iter)))-> strides[1]; } else { (((PyArrayIterObject *)(iter)))->coordinates [1] = 0; (((PyArrayIterObject *)(iter)))->coordinates[0]++ ; (((PyArrayIterObject *)(iter)))->dataptr += (((PyArrayIterObject *)(iter)))->strides[0] - (((PyArrayIterObject *)(iter)))-> backstrides[1]; } } while (0); } else { int __npy_i; for (__npy_i =((PyArrayIterObject *)(iter))->nd_m1; __npy_i >= 0; __npy_i --) { if (((PyArrayIterObject *)(iter))->coordinates[__npy_i ] < ((PyArrayIterObject *)(iter))->dims_m1[__npy_i]) { ( (PyArrayIterObject *)(iter))->coordinates[__npy_i]++; ((PyArrayIterObject *)(iter))->dataptr += ((PyArrayIterObject *)(iter))->strides [__npy_i]; break; } else { ((PyArrayIterObject *)(iter))-> coordinates[__npy_i] = 0; ((PyArrayIterObject *)(iter))->dataptr -= ((PyArrayIterObject *)(iter))->backstrides[__npy_i]; } } } } while (0); | ||||||
763 | } | ||||||
764 | Py_DECREF(iter)_Py_DECREF(((PyObject*)(iter))); | ||||||
765 | } | ||||||
766 | else if (NPY_UNLIKELY(DType->type_num == NPY_DATETIME)__builtin_expect(!!(DType->type_num == NPY_DATETIME), 0) && | ||||||
767 | PyArray_ISSTRING(arr)(((PyArray_TYPE(arr)) == NPY_STRING) || ((PyArray_TYPE(arr)) == NPY_UNICODE))) { | ||||||
768 | /* | ||||||
769 | * TODO: This branch should be deprecated IMO, the workaround is | ||||||
770 | * to cast to the object to a string array. Although a specific | ||||||
771 | * function (if there is even any need) would be better. | ||||||
772 | * This is value based casting! | ||||||
773 | * Unless of course we actually want to support this kind of thing | ||||||
774 | * in general (not just for object dtype)... | ||||||
775 | */ | ||||||
776 | PyArray_DatetimeMetaData meta; | ||||||
777 | meta.base = NPY_FR_GENERIC; | ||||||
778 | meta.num = 1; | ||||||
779 | |||||||
780 | if (find_string_array_datetime64_type(arr, &meta) < 0) { | ||||||
781 | return -1; | ||||||
782 | } | ||||||
783 | else { | ||||||
784 | *out_descr = create_datetime_dtype(NPY_DATETIME, &meta); | ||||||
785 | if (*out_descr == NULL((void*)0)) { | ||||||
786 | return -1; | ||||||
787 | } | ||||||
788 | } | ||||||
789 | } | ||||||
790 | else { | ||||||
791 | /* | ||||||
792 | * If this is not an object array figure out the dtype cast, | ||||||
793 | * or simply use the returned DType. | ||||||
794 | */ | ||||||
795 | *out_descr = PyArray_CastDescrToDType(PyArray_DESCR(arr), DType); | ||||||
796 | if (*out_descr == NULL((void*)0)) { | ||||||
797 | return -1; | ||||||
798 | } | ||||||
799 | } | ||||||
800 | return 0; | ||||||
801 | } | ||||||
802 | |||||||
803 | /** | ||||||
804 | * Given a dtype or DType object, find the correct descriptor to cast the | ||||||
805 | * array to. | ||||||
806 | * | ||||||
807 | * This function is identical to normal casting using only the dtype, however, | ||||||
808 | * it supports inspecting the elements when the array has object dtype | ||||||
809 | * (and the given datatype describes a parametric DType class). | ||||||
810 | * | ||||||
811 | * @param arr | ||||||
812 | * @param dtype A dtype instance or class. | ||||||
813 | * @return A concrete dtype instance or NULL | ||||||
814 | */ | ||||||
815 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyArray_Descr * | ||||||
816 | PyArray_AdaptDescriptorToArray(PyArrayObject *arr, PyObject *dtype) | ||||||
817 | { | ||||||
818 | /* If the requested dtype is flexible, adapt it */ | ||||||
819 | PyArray_Descr *new_dtype; | ||||||
820 | PyArray_DTypeMeta *new_DType; | ||||||
821 | int res; | ||||||
822 | |||||||
823 | res = PyArray_ExtractDTypeAndDescriptor((PyObject *)dtype, | ||||||
824 | &new_dtype, &new_DType); | ||||||
825 | if (res < 0) { | ||||||
826 | return NULL((void*)0); | ||||||
827 | } | ||||||
828 | if (new_dtype == NULL((void*)0)) { | ||||||
829 | res = find_descriptor_from_array(arr, new_DType, &new_dtype); | ||||||
830 | if (res < 0) { | ||||||
831 | Py_DECREF(new_DType)_Py_DECREF(((PyObject*)(new_DType))); | ||||||
832 | return NULL((void*)0); | ||||||
833 | } | ||||||
834 | if (new_dtype == NULL((void*)0)) { | ||||||
835 | /* This is an object array but contained no elements, use default */ | ||||||
836 | new_dtype = new_DType->default_descr(new_DType); | ||||||
837 | } | ||||||
838 | } | ||||||
839 | Py_DECREF(new_DType)_Py_DECREF(((PyObject*)(new_DType))); | ||||||
840 | return new_dtype; | ||||||
841 | } | ||||||
842 | |||||||
843 | |||||||
844 | /** | ||||||
845 | * Recursion helper for `PyArray_DiscoverDTypeAndShape`. See its | ||||||
846 | * documentation for additional details. | ||||||
847 | * | ||||||
848 | * @param obj The current (possibly nested) object | ||||||
849 | * @param curr_dims The current depth, i.e. initially 0 and increasing. | ||||||
850 | * @param max_dims Maximum number of dimensions, modified during discovery. | ||||||
851 | * @param out_descr dtype instance (or NULL) to promoted and update. | ||||||
852 | * @param out_shape The current shape (updated) | ||||||
853 | * @param coercion_cache_tail_ptr The tail of the linked list of coercion | ||||||
854 | * cache objects, which hold on to converted sequences and arrays. | ||||||
855 | * This is a pointer to the `->next` slot of the previous cache so | ||||||
856 | * that we can append a new cache object (and update this pointer). | ||||||
857 | * (Initially it is a pointer to the user-provided head pointer). | ||||||
858 | * @param fixed_DType User provided fixed DType class | ||||||
859 | * @param flags Discovery flags (reporting and behaviour flags, see def.) | ||||||
860 | * @return The updated number of maximum dimensions (i.e. scalars will set | ||||||
861 | * this to the current dimensions). | ||||||
862 | */ | ||||||
863 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||
864 | PyArray_DiscoverDTypeAndShape_Recursive( | ||||||
865 | PyObject *obj, int curr_dims, int max_dims, PyArray_Descr**out_descr, | ||||||
866 | npy_intp out_shape[NPY_MAXDIMS32], | ||||||
867 | coercion_cache_obj ***coercion_cache_tail_ptr, | ||||||
868 | PyArray_DTypeMeta *fixed_DType, enum _dtype_discovery_flags *flags) | ||||||
869 | { | ||||||
870 | PyArrayObject *arr = NULL((void*)0); | ||||||
871 | PyObject *seq; | ||||||
872 | |||||||
873 | /* | ||||||
874 | * The first step is to find the DType class if it was not provided, | ||||||
875 | * alternatively we have to find out that this is not a scalar at all | ||||||
876 | * (which could fail and lead us to `object` dtype). | ||||||
877 | */ | ||||||
878 | PyArray_DTypeMeta *DType = NULL((void*)0); | ||||||
879 | |||||||
880 | if (NPY_UNLIKELY(*flags & DISCOVER_STRINGS_AS_SEQUENCES)__builtin_expect(!!(*flags & DISCOVER_STRINGS_AS_SEQUENCES ), 0)) { | ||||||
881 | /* | ||||||
882 | * We currently support that bytes/strings are considered sequences, | ||||||
883 | * if the dtype is np.dtype('c'), this should be deprecated probably, | ||||||
884 | * but requires hacks right now. | ||||||
885 | */ | ||||||
886 | if (PyBytes_Check(obj)((((((PyObject*)(obj))->ob_type))->tp_flags & ((1UL << 27))) != 0) && PyBytes_Size(obj) != 1) { | ||||||
887 | goto force_sequence_due_to_char_dtype; | ||||||
888 | } | ||||||
889 | else if (PyUnicode_Check(obj)((((((PyObject*)(obj))->ob_type))->tp_flags & ((1UL << 28))) != 0) && PyUnicode_GetLength(obj) != 1) { | ||||||
890 | goto force_sequence_due_to_char_dtype; | ||||||
891 | } | ||||||
892 | } | ||||||
893 | |||||||
894 | /* If this is a known scalar, find the corresponding DType class */ | ||||||
895 | DType = discover_dtype_from_pyobject(obj, flags, fixed_DType); | ||||||
896 | if (DType == NULL((void*)0)) { | ||||||
897 | return -1; | ||||||
898 | } | ||||||
899 | else if (DType == (PyArray_DTypeMeta *)Py_None(&_Py_NoneStruct)) { | ||||||
900 | Py_DECREF(Py_None)_Py_DECREF(((PyObject*)((&_Py_NoneStruct)))); | ||||||
901 | } | ||||||
902 | else { | ||||||
903 | max_dims = handle_scalar( | ||||||
904 | obj, curr_dims, &max_dims, out_descr, out_shape, fixed_DType, | ||||||
905 | flags, DType); | ||||||
906 | Py_DECREF(DType)_Py_DECREF(((PyObject*)(DType))); | ||||||
907 | return max_dims; | ||||||
908 | } | ||||||
909 | |||||||
910 | /* | ||||||
911 | * At this point we expect to find either a sequence, or an array-like. | ||||||
912 | * Although it is still possible that this fails and we have to use | ||||||
913 | * `object`. | ||||||
914 | */ | ||||||
915 | if (PyArray_Check(obj)((((PyObject*)(obj))->ob_type) == (&PyArray_Type) || PyType_IsSubtype ((((PyObject*)(obj))->ob_type), (&PyArray_Type)))) { | ||||||
916 | arr = (PyArrayObject *)obj; | ||||||
917 | Py_INCREF(arr)_Py_INCREF(((PyObject*)(arr))); | ||||||
918 | } | ||||||
919 | else { | ||||||
920 | PyArray_Descr *requested_descr = NULL((void*)0); | ||||||
921 | if (*flags & DESCRIPTOR_WAS_SET) { | ||||||
922 | /* __array__ may be passed the requested descriptor if provided */ | ||||||
923 | requested_descr = *out_descr; | ||||||
924 | } | ||||||
925 | arr = (PyArrayObject *)_array_from_array_like(obj, | ||||||
926 | requested_descr, 0, NULL((void*)0)); | ||||||
927 | if (arr == NULL((void*)0)) { | ||||||
928 | return -1; | ||||||
929 | } | ||||||
930 | else if (arr == (PyArrayObject *)Py_NotImplemented(&_Py_NotImplementedStruct)) { | ||||||
931 | Py_DECREF(arr)_Py_DECREF(((PyObject*)(arr))); | ||||||
932 | arr = NULL((void*)0); | ||||||
933 | } | ||||||
934 | else if (curr_dims > 0 && curr_dims != max_dims) { | ||||||
935 | /* | ||||||
936 | * Deprecated 2020-12-09, NumPy 1.20 | ||||||
937 | * | ||||||
938 | * See https://github.com/numpy/numpy/issues/17965 | ||||||
939 | * Shapely had objects which are not sequences but did export | ||||||
940 | * the array-interface (and so are arguably array-like). | ||||||
941 | * Previously numpy would not use array-like information during | ||||||
942 | * shape discovery, so that it ended up acting as if this was | ||||||
943 | * an (unknown) scalar but with the specified dtype. | ||||||
944 | * Thus we ignore "scalars" here, as the value stored in the | ||||||
945 | * array should be acceptable. | ||||||
946 | */ | ||||||
947 | if (PyArray_NDIM(arr) > 0 && NPY_UNLIKELY(!PySequence_Check(obj))__builtin_expect(!!(!PySequence_Check(obj)), 0)) { | ||||||
948 | if (PyErr_WarnFormat(PyExc_FutureWarning, 1, | ||||||
949 | "The input object of type '%s' is an array-like " | ||||||
950 | "implementing one of the corresponding protocols " | ||||||
951 | "(`__array__`, `__array_interface__` or " | ||||||
952 | "`__array_struct__`); but not a sequence (or 0-D). " | ||||||
953 | "In the future, this object will be coerced as if it " | ||||||
954 | "was first converted using `np.array(obj)`. " | ||||||
955 | "To retain the old behaviour, you have to either " | ||||||
956 | "modify the type '%s', or assign to an empty array " | ||||||
957 | "created with `np.empty(correct_shape, dtype=object)`.", | ||||||
958 | Py_TYPE(obj)(((PyObject*)(obj))->ob_type)->tp_name, Py_TYPE(obj)(((PyObject*)(obj))->ob_type)->tp_name) < 0) { | ||||||
959 | Py_DECREF(arr)_Py_DECREF(((PyObject*)(arr))); | ||||||
960 | return -1; | ||||||
961 | } | ||||||
962 | /* | ||||||
963 | * Strangely enough, even though we threw away the result here, | ||||||
964 | * we did use it during descriptor discovery, so promote it: | ||||||
965 | */ | ||||||
966 | if (update_shape(curr_dims, &max_dims, out_shape, | ||||||
967 | 0, NULL((void*)0), NPY_FALSE0, flags) < 0) { | ||||||
968 | *flags |= FOUND_RAGGED_ARRAY; | ||||||
969 | Py_DECREF(arr)_Py_DECREF(((PyObject*)(arr))); | ||||||
970 | return max_dims; | ||||||
971 | } | ||||||
972 | if (!(*flags & DESCRIPTOR_WAS_SET) && handle_promotion( | ||||||
973 | out_descr, PyArray_DESCR(arr), fixed_DType, flags) < 0) { | ||||||
974 | Py_DECREF(arr)_Py_DECREF(((PyObject*)(arr))); | ||||||
975 | return -1; | ||||||
976 | } | ||||||
977 | Py_DECREF(arr)_Py_DECREF(((PyObject*)(arr))); | ||||||
978 | return max_dims; | ||||||
979 | } | ||||||
980 | } | ||||||
981 | } | ||||||
982 | if (arr != NULL((void*)0)) { | ||||||
983 | /* | ||||||
984 | * This is an array object which will be added to the cache, keeps | ||||||
985 | * the reference to the array alive (takes ownership). | ||||||
986 | */ | ||||||
987 | if (npy_new_coercion_cache(obj, (PyObject *)arr, | ||||||
988 | 0, coercion_cache_tail_ptr, curr_dims) < 0) { | ||||||
989 | return -1; | ||||||
990 | } | ||||||
991 | |||||||
992 | if (curr_dims == 0) { | ||||||
993 | /* | ||||||
994 | * Special case for reverse broadcasting, ignore max_dims if this | ||||||
995 | * is a single array-like object; needed for PyArray_CopyObject. | ||||||
996 | */ | ||||||
997 | memcpy(out_shape, PyArray_SHAPE(arr), | ||||||
998 | PyArray_NDIM(arr) * sizeof(npy_intp)); | ||||||
999 | max_dims = PyArray_NDIM(arr); | ||||||
1000 | } | ||||||
1001 | else if (update_shape(curr_dims, &max_dims, out_shape, | ||||||
1002 | PyArray_NDIM(arr), PyArray_SHAPE(arr), NPY_FALSE0, flags) < 0) { | ||||||
1003 | *flags |= FOUND_RAGGED_ARRAY; | ||||||
1004 | return max_dims; | ||||||
1005 | } | ||||||
1006 | |||||||
1007 | if (*flags & DESCRIPTOR_WAS_SET) { | ||||||
1008 | return max_dims; | ||||||
1009 | } | ||||||
1010 | /* | ||||||
1011 | * For arrays we may not just need to cast the dtype to the user | ||||||
1012 | * provided fixed_DType. If this is an object array, the elements | ||||||
1013 | * may need to be inspected individually. | ||||||
1014 | * Note, this finds the descriptor of the array first and only then | ||||||
1015 | * promotes here (different associativity). | ||||||
1016 | */ | ||||||
1017 | PyArray_Descr *cast_descr; | ||||||
1018 | if (find_descriptor_from_array(arr, fixed_DType, &cast_descr) < 0) { | ||||||
1019 | return -1; | ||||||
1020 | } | ||||||
1021 | if (cast_descr == NULL((void*)0)) { | ||||||
1022 | /* object array with no elements, no need to promote/adjust. */ | ||||||
1023 | return max_dims; | ||||||
1024 | } | ||||||
1025 | if (handle_promotion(out_descr, cast_descr, fixed_DType, flags) < 0) { | ||||||
1026 | Py_DECREF(cast_descr)_Py_DECREF(((PyObject*)(cast_descr))); | ||||||
1027 | return -1; | ||||||
1028 | } | ||||||
1029 | Py_DECREF(cast_descr)_Py_DECREF(((PyObject*)(cast_descr))); | ||||||
1030 | return max_dims; | ||||||
1031 | } | ||||||
1032 | |||||||
1033 | /* | ||||||
1034 | * The last step is to assume the input should be handled as a sequence | ||||||
1035 | * and to handle it recursively. That is, unless we have hit the | ||||||
1036 | * dimension limit. | ||||||
1037 | */ | ||||||
1038 | npy_bool is_sequence = PySequence_Check(obj); | ||||||
1039 | if (is_sequence) { | ||||||
1040 | is_sequence = PySequence_Size(obj) >= 0; | ||||||
1041 | if (NPY_UNLIKELY(!is_sequence)__builtin_expect(!!(!is_sequence), 0)) { | ||||||
1042 | /* NOTE: This should likely just raise all errors */ | ||||||
1043 | if (PyErr_ExceptionMatches(PyExc_RecursionError) || | ||||||
1044 | PyErr_ExceptionMatches(PyExc_MemoryError)) { | ||||||
1045 | /* | ||||||
1046 | * Consider these unrecoverable errors, continuing execution | ||||||
1047 | * might crash the interpreter. | ||||||
1048 | */ | ||||||
1049 | return -1; | ||||||
1050 | } | ||||||
1051 | PyErr_Clear(); | ||||||
1052 | } | ||||||
1053 | } | ||||||
1054 | if (NPY_UNLIKELY(*flags & DISCOVER_TUPLES_AS_ELEMENTS)__builtin_expect(!!(*flags & DISCOVER_TUPLES_AS_ELEMENTS) , 0) && | ||||||
1055 | PyTuple_Check(obj)((((((PyObject*)(obj))->ob_type))->tp_flags & ((1UL << 26))) != 0)) { | ||||||
1056 | is_sequence = NPY_FALSE0; | ||||||
1057 | } | ||||||
1058 | if (curr_dims == max_dims || !is_sequence) { | ||||||
1059 | /* Clear any PySequence_Size error which would corrupts further calls */ | ||||||
1060 | max_dims = handle_scalar( | ||||||
1061 | obj, curr_dims, &max_dims, out_descr, out_shape, fixed_DType, | ||||||
1062 | flags, NULL((void*)0)); | ||||||
1063 | if (is_sequence) { | ||||||
1064 | /* Flag as ragged or too deep array */ | ||||||
1065 | *flags |= FOUND_RAGGED_ARRAY; | ||||||
1066 | } | ||||||
1067 | return max_dims; | ||||||
1068 | } | ||||||
1069 | /* If we stop supporting bytes/str subclasses, more may be required here: */ | ||||||
1070 | assert(!PyBytes_Check(obj) && !PyUnicode_Check(obj))((void) (0)); | ||||||
1071 | |||||||
1072 | force_sequence_due_to_char_dtype: | ||||||
1073 | |||||||
1074 | /* Ensure we have a sequence (required for PyPy) */ | ||||||
1075 | seq = PySequence_Fast(obj, "Could not convert object to sequence"); | ||||||
| |||||||
1076 | if (seq == NULL((void*)0)) { | ||||||
1077 | /* | ||||||
1078 | * Specifically do not fail on things that look like a dictionary, | ||||||
1079 | * instead treat them as scalar. | ||||||
1080 | */ | ||||||
1081 | if (PyErr_ExceptionMatches(PyExc_KeyError)) { | ||||||
1082 | PyErr_Clear(); | ||||||
1083 | max_dims = handle_scalar( | ||||||
1084 | obj, curr_dims, &max_dims, out_descr, out_shape, fixed_DType, | ||||||
1085 | flags, NULL((void*)0)); | ||||||
1086 | return max_dims; | ||||||
1087 | } | ||||||
1088 | return -1; | ||||||
1089 | } | ||||||
1090 | /* The cache takes ownership of the sequence here. */ | ||||||
1091 | if (npy_new_coercion_cache(obj, seq, 1, coercion_cache_tail_ptr, curr_dims) < 0) { | ||||||
1092 | return -1; | ||||||
1093 | } | ||||||
1094 | |||||||
1095 | npy_intp size = PySequence_Fast_GET_SIZE(seq)(((((((PyObject*)(seq))->ob_type))->tp_flags & ((1UL << 25))) != 0) ? (((void) (0)), (((PyVarObject*)(seq)) ->ob_size)) : (((PyVarObject*)((((void) (0)), (PyTupleObject *)(seq))))->ob_size)); | ||||||
1096 | PyObject **objects = PySequence_Fast_ITEMS(seq)(((((((PyObject*)(seq))->ob_type))->tp_flags & ((1UL << 25))) != 0) ? ((PyListObject *)(seq))->ob_item : ((PyTupleObject *)(seq))->ob_item); | ||||||
1097 | |||||||
1098 | if (update_shape(curr_dims, &max_dims, | ||||||
1099 | out_shape, 1, &size, NPY_TRUE1, flags) < 0) { | ||||||
1100 | /* But do update, if there this is a ragged case */ | ||||||
1101 | *flags |= FOUND_RAGGED_ARRAY; | ||||||
1102 | return max_dims; | ||||||
1103 | } | ||||||
1104 | if (size == 0) { | ||||||
1105 | /* If the sequence is empty, this must be the last dimension */ | ||||||
1106 | *flags |= MAX_DIMS_WAS_REACHED; | ||||||
1107 | return curr_dims + 1; | ||||||
1108 | } | ||||||
1109 | |||||||
1110 | /* Allow keyboard interrupts. See gh issue 18117. */ | ||||||
1111 | if (PyErr_CheckSignals() < 0) { | ||||||
1112 | return -1; | ||||||
1113 | } | ||||||
1114 | |||||||
1115 | /* Recursive call for each sequence item */ | ||||||
1116 | for (Py_ssize_t i = 0; i < size; i++) { | ||||||
1117 | max_dims = PyArray_DiscoverDTypeAndShape_Recursive( | ||||||
1118 | objects[i], curr_dims + 1, max_dims, | ||||||
1119 | out_descr, out_shape, coercion_cache_tail_ptr, fixed_DType, | ||||||
1120 | flags); | ||||||
1121 | |||||||
1122 | if (max_dims < 0) { | ||||||
1123 | return -1; | ||||||
1124 | } | ||||||
1125 | } | ||||||
1126 | return max_dims; | ||||||
1127 | } | ||||||
1128 | |||||||
1129 | |||||||
1130 | /** | ||||||
1131 | * Finds the DType and shape of an arbitrary nested sequence. This is the | ||||||
1132 | * general purpose function to find the parameters of the array (but not | ||||||
1133 | * the array itself) as returned by `np.array()` | ||||||
1134 | * | ||||||
1135 | * Note: Before considering to make part of this public, we should consider | ||||||
1136 | * whether things such as `out_descr != NULL` should be supported in | ||||||
1137 | * a public API. | ||||||
1138 | * | ||||||
1139 | * @param obj Scalar or nested sequences. | ||||||
1140 | * @param max_dims Maximum number of dimensions (after this scalars are forced) | ||||||
1141 | * @param out_shape Will be filled with the output shape (more than the actual | ||||||
1142 | * shape may be written). | ||||||
1143 | * @param coercion_cache NULL initialized reference to a cache pointer. | ||||||
1144 | * May be set to the first coercion_cache, and has to be freed using | ||||||
1145 | * npy_free_coercion_cache. | ||||||
1146 | * This should be stored in a thread-safe manner (i.e. function static) | ||||||
1147 | * and is designed to be consumed by `PyArray_AssignFromCache`. | ||||||
1148 | * If not consumed, must be freed using `npy_free_coercion_cache`. | ||||||
1149 | * @param fixed_DType A user provided fixed DType class. | ||||||
1150 | * @param requested_descr A user provided fixed descriptor. This is always | ||||||
1151 | * returned as the discovered descriptor, but currently only used | ||||||
1152 | * for the ``__array__`` protocol. | ||||||
1153 | * @param out_descr Set to the discovered output descriptor. This may be | ||||||
1154 | * non NULL but only when fixed_DType/requested_descr are not given. | ||||||
1155 | * If non NULL, it is the first dtype being promoted and used if there | ||||||
1156 | * are no elements. | ||||||
1157 | * The result may be unchanged (remain NULL) when converting a | ||||||
1158 | * sequence with no elements. In this case it is callers responsibility | ||||||
1159 | * to choose a default. | ||||||
1160 | * @return dimensions of the discovered object or -1 on error. | ||||||
1161 | * WARNING: If (and only if) the output is a single array, the ndim | ||||||
1162 | * returned _can_ exceed the maximum allowed number of dimensions. | ||||||
1163 | * It might be nice to deprecate this? But it allows things such as | ||||||
1164 | * `arr1d[...] = np.array([[1,2,3,4]])` | ||||||
1165 | */ | ||||||
1166 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||
1167 | PyArray_DiscoverDTypeAndShape( | ||||||
1168 | PyObject *obj, int max_dims, | ||||||
1169 | npy_intp out_shape[NPY_MAXDIMS32], | ||||||
1170 | coercion_cache_obj **coercion_cache, | ||||||
1171 | PyArray_DTypeMeta *fixed_DType, PyArray_Descr *requested_descr, | ||||||
1172 | PyArray_Descr **out_descr) | ||||||
1173 | { | ||||||
1174 | coercion_cache_obj **coercion_cache_head = coercion_cache; | ||||||
1175 | *coercion_cache = NULL((void*)0); | ||||||
1176 | enum _dtype_discovery_flags flags = 0; | ||||||
1177 | |||||||
1178 | /* | ||||||
1179 | * Support a passed in descriptor (but only if nothing was specified). | ||||||
1180 | */ | ||||||
1181 | assert(*out_descr == NULL || fixed_DType == NULL)((void) (0)); | ||||||
1182 | /* Validate input of requested descriptor and DType */ | ||||||
1183 | if (fixed_DType != NULL((void*)0)) { | ||||||
1184 | assert(PyObject_TypeCheck(((void) (0)) | ||||||
1185 | (PyObject *)fixed_DType, (PyTypeObject *)&PyArrayDTypeMeta_Type))((void) (0)); | ||||||
1186 | } | ||||||
1187 | |||||||
1188 | if (requested_descr
| ||||||
1189 | assert(fixed_DType == NPY_DTYPE(requested_descr))((void) (0)); | ||||||
1190 | /* The output descriptor must be the input. */ | ||||||
1191 | Py_INCREF(requested_descr)_Py_INCREF(((PyObject*)(requested_descr))); | ||||||
1192 | *out_descr = requested_descr; | ||||||
1193 | flags |= DESCRIPTOR_WAS_SET; | ||||||
1194 | } | ||||||
1195 | |||||||
1196 | /* | ||||||
1197 | * Call the recursive function, the setup for this may need expanding | ||||||
1198 | * to handle caching better. | ||||||
1199 | */ | ||||||
1200 | |||||||
1201 | /* Legacy discovery flags */ | ||||||
1202 | if (requested_descr
| ||||||
1203 | if (requested_descr->type_num == NPY_STRING && | ||||||
1204 | requested_descr->type == 'c') { | ||||||
1205 | /* Character dtype variation of string (should be deprecated...) */ | ||||||
1206 | flags |= DISCOVER_STRINGS_AS_SEQUENCES; | ||||||
1207 | } | ||||||
1208 | else if (requested_descr->type_num == NPY_VOID && | ||||||
1209 | (requested_descr->names || requested_descr->subarray)) { | ||||||
1210 | /* Void is a chimera, in that it may or may not be structured... */ | ||||||
1211 | flags |= DISCOVER_TUPLES_AS_ELEMENTS; | ||||||
1212 | } | ||||||
1213 | } | ||||||
1214 | |||||||
1215 | int ndim = PyArray_DiscoverDTypeAndShape_Recursive( | ||||||
1216 | obj, 0, max_dims, out_descr, out_shape, &coercion_cache, | ||||||
1217 | fixed_DType, &flags); | ||||||
1218 | if (ndim < 0) { | ||||||
1219 | goto fail; | ||||||
1220 | } | ||||||
1221 | |||||||
1222 | if (NPY_UNLIKELY(flags & FOUND_RAGGED_ARRAY)__builtin_expect(!!(flags & FOUND_RAGGED_ARRAY), 0)) { | ||||||
1223 | /* | ||||||
1224 | * If max-dims was reached and the dimensions reduced, this is ragged. | ||||||
1225 | * Otherwise, we merely reached the maximum dimensions, which is | ||||||
1226 | * slightly different. This happens for example for `[1, [2, 3]]` | ||||||
1227 | * where the maximum dimensions is 1, but then a sequence found. | ||||||
1228 | * | ||||||
1229 | * In this case we need to inform the user and clean out the cache | ||||||
1230 | * since it may be too deep. | ||||||
1231 | */ | ||||||
1232 | |||||||
1233 | /* Handle reaching the maximum depth differently: */ | ||||||
1234 | int too_deep = ndim == max_dims; | ||||||
1235 | |||||||
1236 | if (fixed_DType == NULL((void*)0)) { | ||||||
1237 | /* This is discovered as object, but deprecated */ | ||||||
1238 | static PyObject *visibleDeprecationWarning = NULL((void*)0); | ||||||
1239 | npy_cache_import( | ||||||
1240 | "numpy", "VisibleDeprecationWarning", | ||||||
1241 | &visibleDeprecationWarning); | ||||||
1242 | if (visibleDeprecationWarning == NULL((void*)0)) { | ||||||
1243 | goto fail; | ||||||
1244 | } | ||||||
1245 | if (!too_deep) { | ||||||
1246 | /* NumPy 1.19, 2019-11-01 */ | ||||||
1247 | if (PyErr_WarnEx(visibleDeprecationWarning, | ||||||
1248 | "Creating an ndarray from ragged nested sequences (which " | ||||||
1249 | "is a list-or-tuple of lists-or-tuples-or ndarrays with " | ||||||
1250 | "different lengths or shapes) is deprecated. If you " | ||||||
1251 | "meant to do this, you must specify 'dtype=object' " | ||||||
1252 | "when creating the ndarray.", 1) < 0) { | ||||||
1253 | goto fail; | ||||||
1254 | } | ||||||
1255 | } | ||||||
1256 | else { | ||||||
1257 | /* NumPy 1.20, 2020-05-08 */ | ||||||
1258 | /* Note, max_dims should normally always be NPY_MAXDIMS here */ | ||||||
1259 | if (PyErr_WarnFormat(visibleDeprecationWarning, 1, | ||||||
1260 | "Creating an ndarray from nested sequences exceeding " | ||||||
1261 | "the maximum number of dimensions of %d is deprecated. " | ||||||
1262 | "If you mean to do this, you must specify " | ||||||
1263 | "'dtype=object' when creating the ndarray.", | ||||||
1264 | max_dims) < 0) { | ||||||
1265 | goto fail; | ||||||
1266 | } | ||||||
1267 | } | ||||||
1268 | /* Ensure that ragged arrays always return object dtype */ | ||||||
1269 | Py_XSETREF(*out_descr, PyArray_DescrFromType(NPY_OBJECT))do { PyObject *_py_tmp = ((PyObject*)(*out_descr)); (*out_descr ) = (PyArray_DescrFromType(NPY_OBJECT)); _Py_XDECREF(((PyObject *)(_py_tmp))); } while (0); | ||||||
1270 | } | ||||||
1271 | else if (fixed_DType->type_num != NPY_OBJECT) { | ||||||
1272 | /* Only object DType supports ragged cases unify error */ | ||||||
1273 | |||||||
1274 | /* | ||||||
1275 | * We used to let certain ragged arrays pass if they also | ||||||
1276 | * support e.g. conversion using `float(arr)`, which currently | ||||||
1277 | * works for arrays with only one element. | ||||||
1278 | * Thus we catch at least most of such cases here and give a | ||||||
1279 | * DeprecationWarning instead of an error. | ||||||
1280 | * Note that some of these will actually error later on when | ||||||
1281 | * attempting to do the actual assign. | ||||||
1282 | */ | ||||||
1283 | int deprecate_single_element_ragged = 0; | ||||||
1284 | coercion_cache_obj *current = *coercion_cache_head; | ||||||
1285 | while (current != NULL((void*)0)) { | ||||||
1286 | if (current->sequence) { | ||||||
1287 | if (current->depth == ndim) { | ||||||
1288 | /* | ||||||
1289 | * Assume that only array-likes will allow the deprecated | ||||||
1290 | * behaviour | ||||||
1291 | */ | ||||||
1292 | deprecate_single_element_ragged = 0; | ||||||
1293 | break; | ||||||
1294 | } | ||||||
1295 | /* check next converted sequence/array-like */ | ||||||
1296 | current = current->next; | ||||||
1297 | continue; | ||||||
1298 | } | ||||||
1299 | PyArrayObject *arr = (PyArrayObject *)(current->arr_or_sequence); | ||||||
1300 | assert(PyArray_NDIM(arr) + current->depth >= ndim)((void) (0)); | ||||||
1301 | if (PyArray_NDIM(arr) != ndim - current->depth) { | ||||||
1302 | /* This array is not compatible with the final shape */ | ||||||
1303 | if (PyArray_SIZE(arr)PyArray_MultiplyList(PyArray_DIMS(arr), PyArray_NDIM(arr)) != 1) { | ||||||
1304 | deprecate_single_element_ragged = 0; | ||||||
1305 | break; | ||||||
1306 | } | ||||||
1307 | deprecate_single_element_ragged = 1; | ||||||
1308 | } | ||||||
1309 | current = current->next; | ||||||
1310 | } | ||||||
1311 | |||||||
1312 | if (deprecate_single_element_ragged) { | ||||||
1313 | /* Deprecated 2020-07-24, NumPy 1.20 */ | ||||||
1314 | if (DEPRECATE(PyErr_WarnEx(PyExc_DeprecationWarning,"setting an array element with a sequence. " "This was supported in some cases where the elements " "are arrays with a single element. For example " "`np.array([1, np.array([2])], dtype=int)`. " "In the future this will raise the same ValueError as " "`np.array([1, [2]], dtype=int)`.",1) | ||||||
1315 | "setting an array element with a sequence. "PyErr_WarnEx(PyExc_DeprecationWarning,"setting an array element with a sequence. " "This was supported in some cases where the elements " "are arrays with a single element. For example " "`np.array([1, np.array([2])], dtype=int)`. " "In the future this will raise the same ValueError as " "`np.array([1, [2]], dtype=int)`.",1) | ||||||
1316 | "This was supported in some cases where the elements "PyErr_WarnEx(PyExc_DeprecationWarning,"setting an array element with a sequence. " "This was supported in some cases where the elements " "are arrays with a single element. For example " "`np.array([1, np.array([2])], dtype=int)`. " "In the future this will raise the same ValueError as " "`np.array([1, [2]], dtype=int)`.",1) | ||||||
1317 | "are arrays with a single element. For example "PyErr_WarnEx(PyExc_DeprecationWarning,"setting an array element with a sequence. " "This was supported in some cases where the elements " "are arrays with a single element. For example " "`np.array([1, np.array([2])], dtype=int)`. " "In the future this will raise the same ValueError as " "`np.array([1, [2]], dtype=int)`.",1) | ||||||
1318 | "`np.array([1, np.array([2])], dtype=int)`. "PyErr_WarnEx(PyExc_DeprecationWarning,"setting an array element with a sequence. " "This was supported in some cases where the elements " "are arrays with a single element. For example " "`np.array([1, np.array([2])], dtype=int)`. " "In the future this will raise the same ValueError as " "`np.array([1, [2]], dtype=int)`.",1) | ||||||
1319 | "In the future this will raise the same ValueError as "PyErr_WarnEx(PyExc_DeprecationWarning,"setting an array element with a sequence. " "This was supported in some cases where the elements " "are arrays with a single element. For example " "`np.array([1, np.array([2])], dtype=int)`. " "In the future this will raise the same ValueError as " "`np.array([1, [2]], dtype=int)`.",1) | ||||||
1320 | "`np.array([1, [2]], dtype=int)`.")PyErr_WarnEx(PyExc_DeprecationWarning,"setting an array element with a sequence. " "This was supported in some cases where the elements " "are arrays with a single element. For example " "`np.array([1, np.array([2])], dtype=int)`. " "In the future this will raise the same ValueError as " "`np.array([1, [2]], dtype=int)`.",1) < 0) { | ||||||
1321 | goto fail; | ||||||
1322 | } | ||||||
1323 | } | ||||||
1324 | else if (!too_deep) { | ||||||
1325 | PyObject *shape = PyArray_IntTupleFromIntp(ndim, out_shape); | ||||||
1326 | PyErr_Format(PyExc_ValueError, | ||||||
1327 | "setting an array element with a sequence. The " | ||||||
1328 | "requested array has an inhomogeneous shape after " | ||||||
1329 | "%d dimensions. The detected shape was " | ||||||
1330 | "%R + inhomogeneous part.", | ||||||
1331 | ndim, shape); | ||||||
1332 | Py_DECREF(shape)_Py_DECREF(((PyObject*)(shape))); | ||||||
1333 | goto fail; | ||||||
1334 | } | ||||||
1335 | else { | ||||||
1336 | PyErr_Format(PyExc_ValueError, | ||||||
1337 | "setting an array element with a sequence. The " | ||||||
1338 | "requested array would exceed the maximum number of " | ||||||
1339 | "dimension of %d.", | ||||||
1340 | max_dims); | ||||||
1341 | goto fail; | ||||||
1342 | } | ||||||
1343 | } | ||||||
1344 | |||||||
1345 | /* | ||||||
1346 | * If the array is ragged, the cache may be too deep, so clean it. | ||||||
1347 | * The cache is left at the same depth as the array though. | ||||||
1348 | */ | ||||||
1349 | coercion_cache_obj **next_ptr = coercion_cache_head; | ||||||
1350 | coercion_cache_obj *current = *coercion_cache_head; /* item to check */ | ||||||
1351 | while (current != NULL((void*)0)) { | ||||||
1352 | if (current->depth > ndim) { | ||||||
1353 | /* delete "next" cache item and advanced it (unlike later) */ | ||||||
1354 | current = npy_unlink_coercion_cache(current); | ||||||
1355 | continue; | ||||||
1356 | } | ||||||
1357 | /* advance both prev and next, and set prev->next to new item */ | ||||||
1358 | *next_ptr = current; | ||||||
1359 | next_ptr = &(current->next); | ||||||
1360 | current = current->next; | ||||||
1361 | } | ||||||
1362 | *next_ptr = NULL((void*)0); | ||||||
1363 | } | ||||||
1364 | /* We could check here for max-ndims being reached as well */ | ||||||
1365 | |||||||
1366 | if (requested_descr != NULL((void*)0)) { | ||||||
1367 | /* descriptor was provided, we did not accidentally change it */ | ||||||
1368 | assert(*out_descr == requested_descr)((void) (0)); | ||||||
1369 | } | ||||||
1370 | else if (NPY_UNLIKELY(*out_descr == NULL)__builtin_expect(!!(*out_descr == ((void*)0)), 0)) { | ||||||
1371 | /* | ||||||
1372 | * When the object contained no elements (sequence of length zero), | ||||||
1373 | * the no descriptor may have been found. When a DType was requested | ||||||
1374 | * we use it to define the output dtype. | ||||||
1375 | * Otherwise, out_descr will remain NULL and the caller has to set | ||||||
1376 | * the correct default. | ||||||
1377 | */ | ||||||
1378 | if (fixed_DType != NULL((void*)0)) { | ||||||
1379 | *out_descr = fixed_DType->default_descr(fixed_DType); | ||||||
1380 | if (*out_descr == NULL((void*)0)) { | ||||||
1381 | goto fail; | ||||||
1382 | } | ||||||
1383 | } | ||||||
1384 | } | ||||||
1385 | return ndim; | ||||||
1386 | |||||||
1387 | fail: | ||||||
1388 | npy_free_coercion_cache(*coercion_cache_head); | ||||||
1389 | *coercion_cache_head = NULL((void*)0); | ||||||
1390 | Py_XSETREF(*out_descr, NULL)do { PyObject *_py_tmp = ((PyObject*)(*out_descr)); (*out_descr ) = (((void*)0)); _Py_XDECREF(((PyObject*)(_py_tmp))); } while (0); | ||||||
1391 | return -1; | ||||||
1392 | } | ||||||
1393 | |||||||
1394 | |||||||
1395 | |||||||
1396 | /** | ||||||
1397 | * Check the descriptor is a legacy "flexible" DType instance, this is | ||||||
1398 | * an instance which is (normally) not attached to an array, such as a string | ||||||
1399 | * of length 0 or a datetime with no unit. | ||||||
1400 | * These should be largely deprecated, and represent only the DType class | ||||||
1401 | * for most `dtype` parameters. | ||||||
1402 | * | ||||||
1403 | * TODO: This function should eventually recieve a deprecation warning and | ||||||
1404 | * be removed. | ||||||
1405 | * | ||||||
1406 | * @param descr | ||||||
1407 | * @return 1 if this is not a concrete dtype instance 0 otherwise | ||||||
1408 | */ | ||||||
1409 | static int | ||||||
1410 | descr_is_legacy_parametric_instance(PyArray_Descr *descr) | ||||||
1411 | { | ||||||
1412 | if (PyDataType_ISUNSIZED(descr)((descr)->elsize == 0 && !(((PyArray_Descr *)(descr ))->names != ((void*)0)))) { | ||||||
1413 | return 1; | ||||||
1414 | } | ||||||
1415 | /* Flexible descr with generic time unit (which can be adapted) */ | ||||||
1416 | if (PyDataType_ISDATETIME(descr)(((((PyArray_Descr*)(descr))->type_num) >=NPY_DATETIME) && ((((PyArray_Descr*)(descr))->type_num) <=NPY_TIMEDELTA ))) { | ||||||
1417 | PyArray_DatetimeMetaData *meta; | ||||||
1418 | meta = get_datetime_metadata_from_dtype(descr); | ||||||
1419 | if (meta->base == NPY_FR_GENERIC) { | ||||||
1420 | return 1; | ||||||
1421 | } | ||||||
1422 | } | ||||||
1423 | return 0; | ||||||
1424 | } | ||||||
1425 | |||||||
1426 | |||||||
1427 | /** | ||||||
1428 | * Given either a DType instance or class, (or legacy flexible instance), | ||||||
1429 | * ands sets output dtype instance and DType class. Both results may be | ||||||
1430 | * NULL, but if `out_descr` is set `out_DType` will always be the | ||||||
1431 | * corresponding class. | ||||||
1432 | * | ||||||
1433 | * @param dtype | ||||||
1434 | * @param out_descr | ||||||
1435 | * @param out_DType | ||||||
1436 | * @return 0 on success -1 on failure | ||||||
1437 | */ | ||||||
1438 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | ||||||
1439 | PyArray_ExtractDTypeAndDescriptor(PyObject *dtype, | ||||||
1440 | PyArray_Descr **out_descr, PyArray_DTypeMeta **out_DType) | ||||||
1441 | { | ||||||
1442 | *out_DType = NULL((void*)0); | ||||||
1443 | *out_descr = NULL((void*)0); | ||||||
1444 | |||||||
1445 | if (dtype != NULL((void*)0)) { | ||||||
1446 | if (PyObject_TypeCheck(dtype, (PyTypeObject *)&PyArrayDTypeMeta_Type)((((PyObject*)(dtype))->ob_type) == ((PyTypeObject *)& PyArrayDTypeMeta_Type) || PyType_IsSubtype((((PyObject*)(dtype ))->ob_type), ((PyTypeObject *)&PyArrayDTypeMeta_Type) ))) { | ||||||
1447 | assert(dtype != (PyObject * )&PyArrayDescr_Type)((void) (0)); /* not np.dtype */ | ||||||
1448 | *out_DType = (PyArray_DTypeMeta *)dtype; | ||||||
1449 | Py_INCREF(*out_DType)_Py_INCREF(((PyObject*)(*out_DType))); | ||||||
1450 | } | ||||||
1451 | else if (PyObject_TypeCheck((PyObject *)Py_TYPE(dtype),((((PyObject*)((PyObject *)(((PyObject*)(dtype))->ob_type) ))->ob_type) == ((PyTypeObject *)&PyArrayDTypeMeta_Type ) || PyType_IsSubtype((((PyObject*)((PyObject *)(((PyObject*) (dtype))->ob_type)))->ob_type), ((PyTypeObject *)&PyArrayDTypeMeta_Type ))) | ||||||
1452 | (PyTypeObject *)&PyArrayDTypeMeta_Type)((((PyObject*)((PyObject *)(((PyObject*)(dtype))->ob_type) ))->ob_type) == ((PyTypeObject *)&PyArrayDTypeMeta_Type ) || PyType_IsSubtype((((PyObject*)((PyObject *)(((PyObject*) (dtype))->ob_type)))->ob_type), ((PyTypeObject *)&PyArrayDTypeMeta_Type )))) { | ||||||
1453 | *out_DType = NPY_DTYPE(dtype)((PyArray_DTypeMeta *)(((PyObject*)(dtype))->ob_type)); | ||||||
1454 | Py_INCREF(*out_DType)_Py_INCREF(((PyObject*)(*out_DType))); | ||||||
1455 | if (!descr_is_legacy_parametric_instance((PyArray_Descr *)dtype)) { | ||||||
1456 | *out_descr = (PyArray_Descr *)dtype; | ||||||
1457 | Py_INCREF(*out_descr)_Py_INCREF(((PyObject*)(*out_descr))); | ||||||
1458 | } | ||||||
1459 | } | ||||||
1460 | else { | ||||||
1461 | PyErr_SetString(PyExc_TypeError, | ||||||
1462 | "dtype parameter must be a DType instance or class."); | ||||||
1463 | return -1; | ||||||
1464 | } | ||||||
1465 | } | ||||||
1466 | return 0; | ||||||
1467 | } | ||||||
1468 | |||||||
1469 | |||||||
1470 | /* | ||||||
1471 | * Python API function to expose the dtype+shape discovery functionality | ||||||
1472 | * directly. | ||||||
1473 | */ | ||||||
1474 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyObject * | ||||||
1475 | _discover_array_parameters(PyObject *NPY_UNUSED(self)(__NPY_UNUSED_TAGGEDself) __attribute__ ((__unused__)), | ||||||
1476 | PyObject *args, PyObject *kwargs) | ||||||
1477 | { | ||||||
1478 | static char *kwlist[] = {"obj", "dtype", NULL((void*)0)}; | ||||||
1479 | |||||||
1480 | PyObject *obj; | ||||||
1481 | PyObject *dtype = NULL((void*)0); | ||||||
1482 | PyArray_Descr *fixed_descriptor = NULL((void*)0); | ||||||
1483 | PyArray_DTypeMeta *fixed_DType = NULL((void*)0); | ||||||
1484 | npy_intp shape[NPY_MAXDIMS32]; | ||||||
1485 | |||||||
1486 | if (!PyArg_ParseTupleAndKeywords_PyArg_ParseTupleAndKeywords_SizeT( | ||||||
1487 | args, kwargs, "O|O:_discover_array_parameters", kwlist, | ||||||
1488 | &obj, &dtype)) { | ||||||
1489 | return NULL((void*)0); | ||||||
1490 | } | ||||||
1491 | |||||||
1492 | if (PyArray_ExtractDTypeAndDescriptor(dtype, | ||||||
1493 | &fixed_descriptor, &fixed_DType) < 0) { | ||||||
1494 | return NULL((void*)0); | ||||||
1495 | } | ||||||
1496 | |||||||
1497 | coercion_cache_obj *coercion_cache = NULL((void*)0); | ||||||
1498 | PyObject *out_dtype = NULL((void*)0); | ||||||
1499 | int ndim = PyArray_DiscoverDTypeAndShape( | ||||||
1500 | obj, NPY_MAXDIMS32, shape, | ||||||
1501 | &coercion_cache, | ||||||
1502 | fixed_DType, fixed_descriptor, (PyArray_Descr **)&out_dtype); | ||||||
1503 | Py_XDECREF(fixed_DType)_Py_XDECREF(((PyObject*)(fixed_DType))); | ||||||
1504 | Py_XDECREF(fixed_descriptor)_Py_XDECREF(((PyObject*)(fixed_descriptor))); | ||||||
1505 | if (ndim < 0) { | ||||||
1506 | return NULL((void*)0); | ||||||
1507 | } | ||||||
1508 | npy_free_coercion_cache(coercion_cache); | ||||||
1509 | if (out_dtype == NULL((void*)0)) { | ||||||
1510 | /* Empty sequence, report this as None. */ | ||||||
1511 | out_dtype = Py_None(&_Py_NoneStruct); | ||||||
1512 | Py_INCREF(Py_None)_Py_INCREF(((PyObject*)((&_Py_NoneStruct)))); | ||||||
1513 | } | ||||||
1514 | |||||||
1515 | PyObject *shape_tuple = PyArray_IntTupleFromIntp(ndim, shape); | ||||||
1516 | if (shape_tuple == NULL((void*)0)) { | ||||||
1517 | return NULL((void*)0); | ||||||
1518 | } | ||||||
1519 | |||||||
1520 | PyObject *res = PyTuple_Pack(2, (PyObject *)out_dtype, shape_tuple); | ||||||
1521 | Py_DECREF(out_dtype)_Py_DECREF(((PyObject*)(out_dtype))); | ||||||
1522 | Py_DECREF(shape_tuple)_Py_DECREF(((PyObject*)(shape_tuple))); | ||||||
1523 | return res; | ||||||
1524 | } |
1 | #ifndef PySequence_Fast |
2 | struct _object; |
3 | typedef struct _object PyObject; |
4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
5 | PyObject* PySequence_Fast(PyObject *o, const char *m) { |
6 | return clang_analyzer_PyObject_New_Reference(); |
7 | } |
8 | #else |
9 | #warning "API PySequence_Fast is defined as a macro." |
10 | #endif |