| 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 |