| File: | numpy/core/src/multiarray/usertypes.c |
| Warning: | line 296, 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 "common.h" | |||
| 36 | ||||
| 37 | #include "npy_pycompat.h" | |||
| 38 | ||||
| 39 | #include "usertypes.h" | |||
| 40 | #include "dtypemeta.h" | |||
| 41 | #include "scalartypes.h" | |||
| 42 | #include "array_method.h" | |||
| 43 | #include "convert_datatype.h" | |||
| 44 | #include "legacy_dtype_implementation.h" | |||
| 45 | ||||
| 46 | ||||
| 47 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyArray_Descr **userdescrs=NULL((void*)0); | |||
| 48 | ||||
| 49 | static int | |||
| 50 | _append_new(int **p_types, int insert) | |||
| 51 | { | |||
| 52 | int n = 0; | |||
| 53 | int *newtypes; | |||
| 54 | int *types = *p_types; | |||
| 55 | ||||
| 56 | while (types[n] != NPY_NOTYPE) { | |||
| 57 | n++; | |||
| 58 | } | |||
| 59 | newtypes = (int *)realloc(types, (n + 2)*sizeof(int)); | |||
| 60 | if (newtypes == NULL((void*)0)) { | |||
| 61 | PyErr_NoMemory(); | |||
| 62 | return -1; | |||
| 63 | } | |||
| 64 | newtypes[n] = insert; | |||
| 65 | newtypes[n + 1] = NPY_NOTYPE; | |||
| 66 | ||||
| 67 | /* Replace the passed-in pointer */ | |||
| 68 | *p_types = newtypes; | |||
| 69 | return 0; | |||
| 70 | } | |||
| 71 | ||||
| 72 | static npy_bool | |||
| 73 | _default_nonzero(void *ip, void *arr) | |||
| 74 | { | |||
| 75 | int elsize = PyArray_ITEMSIZE(arr); | |||
| 76 | char *ptr = ip; | |||
| 77 | while (elsize--) { | |||
| 78 | if (*ptr++ != 0) { | |||
| 79 | return NPY_TRUE1; | |||
| 80 | } | |||
| 81 | } | |||
| 82 | return NPY_FALSE0; | |||
| 83 | } | |||
| 84 | ||||
| 85 | static void | |||
| 86 | _default_copyswapn(void *dst, npy_intp dstride, void *src, | |||
| 87 | npy_intp sstride, npy_intp n, int swap, void *arr) | |||
| 88 | { | |||
| 89 | npy_intp i; | |||
| 90 | PyArray_CopySwapFunc *copyswap; | |||
| 91 | char *dstptr = dst; | |||
| 92 | char *srcptr = src; | |||
| 93 | ||||
| 94 | copyswap = PyArray_DESCR(arr)->f->copyswap; | |||
| 95 | ||||
| 96 | for (i = 0; i < n; i++) { | |||
| 97 | copyswap(dstptr, srcptr, swap, arr); | |||
| 98 | dstptr += dstride; | |||
| 99 | srcptr += sstride; | |||
| 100 | } | |||
| 101 | } | |||
| 102 | ||||
| 103 | /*NUMPY_API | |||
| 104 | Initialize arrfuncs to NULL | |||
| 105 | */ | |||
| 106 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) void | |||
| 107 | PyArray_InitArrFuncs(PyArray_ArrFuncs *f) | |||
| 108 | { | |||
| 109 | int i; | |||
| 110 | ||||
| 111 | for(i = 0; i < NPY_NTYPES_ABI_COMPATIBLE; i++) { | |||
| 112 | f->cast[i] = NULL((void*)0); | |||
| 113 | } | |||
| 114 | f->getitem = NULL((void*)0); | |||
| 115 | f->setitem = NULL((void*)0); | |||
| 116 | f->copyswapn = NULL((void*)0); | |||
| 117 | f->copyswap = NULL((void*)0); | |||
| 118 | f->compare = NULL((void*)0); | |||
| 119 | f->argmax = NULL((void*)0); | |||
| 120 | f->argmin = NULL((void*)0); | |||
| 121 | f->dotfunc = NULL((void*)0); | |||
| 122 | f->scanfunc = NULL((void*)0); | |||
| 123 | f->fromstr = NULL((void*)0); | |||
| 124 | f->nonzero = NULL((void*)0); | |||
| 125 | f->fill = NULL((void*)0); | |||
| 126 | f->fillwithscalar = NULL((void*)0); | |||
| 127 | for(i = 0; i < NPY_NSORTS(NPY_STABLESORT + 1); i++) { | |||
| 128 | f->sort[i] = NULL((void*)0); | |||
| 129 | f->argsort[i] = NULL((void*)0); | |||
| 130 | } | |||
| 131 | f->castdict = NULL((void*)0); | |||
| 132 | f->scalarkind = NULL((void*)0); | |||
| 133 | f->cancastscalarkindto = NULL((void*)0); | |||
| 134 | f->cancastto = NULL((void*)0); | |||
| 135 | f->fastclip = NULL((void*)0); | |||
| 136 | f->fastputmask = NULL((void*)0); | |||
| 137 | f->fasttake = NULL((void*)0); | |||
| 138 | } | |||
| 139 | ||||
| 140 | ||||
| 141 | static int | |||
| 142 | test_deprecated_arrfuncs_members(PyArray_ArrFuncs *f) { | |||
| 143 | /* NumPy 1.19, 2020-01-15 */ | |||
| 144 | if (f->fastputmask != NULL((void*)0)) { | |||
| 145 | if (DEPRECATE(PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastputmask member of custom dtypes is ignored; " "setting it may be an error in the future.\n" "The custom dtype you are using must be revised, but " "results will not be affected.",1) | |||
| 146 | "The ->f->fastputmask member of custom dtypes is ignored; "PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastputmask member of custom dtypes is ignored; " "setting it may be an error in the future.\n" "The custom dtype you are using must be revised, but " "results will not be affected.",1) | |||
| 147 | "setting it may be an error in the future.\n"PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastputmask member of custom dtypes is ignored; " "setting it may be an error in the future.\n" "The custom dtype you are using must be revised, but " "results will not be affected.",1) | |||
| 148 | "The custom dtype you are using must be revised, but "PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastputmask member of custom dtypes is ignored; " "setting it may be an error in the future.\n" "The custom dtype you are using must be revised, but " "results will not be affected.",1) | |||
| 149 | "results will not be affected.")PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastputmask member of custom dtypes is ignored; " "setting it may be an error in the future.\n" "The custom dtype you are using must be revised, but " "results will not be affected.",1) < 0) { | |||
| 150 | return -1; | |||
| 151 | } | |||
| 152 | } | |||
| 153 | /* NumPy 1.19, 2020-01-15 */ | |||
| 154 | if (f->fasttake != NULL((void*)0)) { | |||
| 155 | if (DEPRECATE(PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastputmask member of custom dtypes is ignored; " "setting it may be an error in the future.\n" "The custom dtype you are using must be revised, but " "results will not be affected.",1) | |||
| 156 | "The ->f->fastputmask member of custom dtypes is ignored; "PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastputmask member of custom dtypes is ignored; " "setting it may be an error in the future.\n" "The custom dtype you are using must be revised, but " "results will not be affected.",1) | |||
| 157 | "setting it may be an error in the future.\n"PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastputmask member of custom dtypes is ignored; " "setting it may be an error in the future.\n" "The custom dtype you are using must be revised, but " "results will not be affected.",1) | |||
| 158 | "The custom dtype you are using must be revised, but "PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastputmask member of custom dtypes is ignored; " "setting it may be an error in the future.\n" "The custom dtype you are using must be revised, but " "results will not be affected.",1) | |||
| 159 | "results will not be affected.")PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastputmask member of custom dtypes is ignored; " "setting it may be an error in the future.\n" "The custom dtype you are using must be revised, but " "results will not be affected.",1) < 0) { | |||
| 160 | return -1; | |||
| 161 | } | |||
| 162 | } | |||
| 163 | /* NumPy 1.19, 2020-01-15 */ | |||
| 164 | if (f->fastclip != NULL((void*)0)) { | |||
| 165 | /* fastclip was already deprecated at execution time in 1.17. */ | |||
| 166 | if (DEPRECATE(PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastclip member of custom dtypes is deprecated; " "setting it will be an error in the future.\n" "The custom dtype you are using must be changed to use " "PyUFunc_RegisterLoopForDescr to attach a custom loop to " "np.core.umath.clip, np.minimum, and np.maximum" ,1) | |||
| 167 | "The ->f->fastclip member of custom dtypes is deprecated; "PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastclip member of custom dtypes is deprecated; " "setting it will be an error in the future.\n" "The custom dtype you are using must be changed to use " "PyUFunc_RegisterLoopForDescr to attach a custom loop to " "np.core.umath.clip, np.minimum, and np.maximum" ,1) | |||
| 168 | "setting it will be an error in the future.\n"PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastclip member of custom dtypes is deprecated; " "setting it will be an error in the future.\n" "The custom dtype you are using must be changed to use " "PyUFunc_RegisterLoopForDescr to attach a custom loop to " "np.core.umath.clip, np.minimum, and np.maximum" ,1) | |||
| 169 | "The custom dtype you are using must be changed to use "PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastclip member of custom dtypes is deprecated; " "setting it will be an error in the future.\n" "The custom dtype you are using must be changed to use " "PyUFunc_RegisterLoopForDescr to attach a custom loop to " "np.core.umath.clip, np.minimum, and np.maximum" ,1) | |||
| 170 | "PyUFunc_RegisterLoopForDescr to attach a custom loop to "PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastclip member of custom dtypes is deprecated; " "setting it will be an error in the future.\n" "The custom dtype you are using must be changed to use " "PyUFunc_RegisterLoopForDescr to attach a custom loop to " "np.core.umath.clip, np.minimum, and np.maximum" ,1) | |||
| 171 | "np.core.umath.clip, np.minimum, and np.maximum")PyErr_WarnEx(PyExc_DeprecationWarning,"The ->f->fastclip member of custom dtypes is deprecated; " "setting it will be an error in the future.\n" "The custom dtype you are using must be changed to use " "PyUFunc_RegisterLoopForDescr to attach a custom loop to " "np.core.umath.clip, np.minimum, and np.maximum" ,1) < 0) { | |||
| 172 | return -1; | |||
| 173 | } | |||
| 174 | } | |||
| 175 | return 0; | |||
| 176 | } | |||
| 177 | ||||
| 178 | /* | |||
| 179 | returns typenum to associate with this type >=NPY_USERDEF. | |||
| 180 | needs the userdecrs table and PyArray_NUMUSER variables | |||
| 181 | defined in arraytypes.inc | |||
| 182 | */ | |||
| 183 | /*NUMPY_API | |||
| 184 | Register Data type | |||
| 185 | Does not change the reference count of descr | |||
| 186 | */ | |||
| 187 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
| 188 | PyArray_RegisterDataType(PyArray_Descr *descr) | |||
| 189 | { | |||
| 190 | PyArray_Descr *descr2; | |||
| 191 | int typenum; | |||
| 192 | int i; | |||
| 193 | PyArray_ArrFuncs *f; | |||
| 194 | ||||
| 195 | /* See if this type is already registered */ | |||
| 196 | for (i = 0; i < NPY_NUMUSERTYPES; i++) { | |||
| 197 | descr2 = userdescrs[i]; | |||
| 198 | if (descr2 == descr) { | |||
| 199 | return descr->type_num; | |||
| 200 | } | |||
| 201 | } | |||
| 202 | typenum = NPY_USERDEF + NPY_NUMUSERTYPES; | |||
| 203 | descr->type_num = -1; | |||
| 204 | if (PyDataType_ISUNSIZED(descr)((descr)->elsize == 0 && !(((PyArray_Descr *)(descr ))->names != ((void*)0)))) { | |||
| 205 | PyErr_SetString(PyExc_ValueError, "cannot register a" \ | |||
| 206 | "flexible data-type"); | |||
| 207 | return -1; | |||
| 208 | } | |||
| 209 | f = descr->f; | |||
| 210 | if (f->nonzero == NULL((void*)0)) { | |||
| 211 | f->nonzero = _default_nonzero; | |||
| 212 | } | |||
| 213 | if (f->copyswapn == NULL((void*)0)) { | |||
| 214 | f->copyswapn = _default_copyswapn; | |||
| 215 | } | |||
| 216 | if (f->copyswap == NULL((void*)0) || f->getitem == NULL((void*)0) || | |||
| 217 | f->setitem == NULL((void*)0)) { | |||
| 218 | PyErr_SetString(PyExc_ValueError, "a required array function" \ | |||
| 219 | " is missing."); | |||
| 220 | return -1; | |||
| 221 | } | |||
| 222 | if (descr->typeobj == NULL((void*)0)) { | |||
| 223 | PyErr_SetString(PyExc_ValueError, "missing typeobject"); | |||
| 224 | return -1; | |||
| 225 | } | |||
| 226 | if (descr->flags & (NPY_ITEM_IS_POINTER0x04 | NPY_ITEM_REFCOUNT0x01)) { | |||
| 227 | /* | |||
| 228 | * User dtype can't actually do reference counting, however, there | |||
| 229 | * are existing hacks (e.g. xpress), which use a structured one: | |||
| 230 | * dtype((xpress.var, [('variable', 'O')])) | |||
| 231 | * so we have to support this. But such a structure must be constant | |||
| 232 | * (i.e. fixed at registration time, this is the case for `xpress`). | |||
| 233 | */ | |||
| 234 | if (descr->names == NULL((void*)0) || descr->fields == NULL((void*)0) || | |||
| 235 | !PyDict_CheckExact(descr->fields)((((PyObject*)(descr->fields))->ob_type) == &PyDict_Type )) { | |||
| 236 | PyErr_Format(PyExc_ValueError, | |||
| 237 | "Failed to register dtype for %S: Legacy user dtypes " | |||
| 238 | "using `NPY_ITEM_IS_POINTER` or `NPY_ITEM_REFCOUNT` are " | |||
| 239 | "unsupported. It is possible to create such a dtype only " | |||
| 240 | "if it is a structured dtype with names and fields " | |||
| 241 | "hardcoded at registration time.\n" | |||
| 242 | "Please contact the NumPy developers if this used to work " | |||
| 243 | "but now fails.", descr->typeobj); | |||
| 244 | return -1; | |||
| 245 | } | |||
| 246 | } | |||
| 247 | ||||
| 248 | if (test_deprecated_arrfuncs_members(f) < 0) { | |||
| 249 | return -1; | |||
| 250 | } | |||
| 251 | ||||
| 252 | userdescrs = realloc(userdescrs, | |||
| 253 | (NPY_NUMUSERTYPES+1)*sizeof(void *)); | |||
| 254 | if (userdescrs == NULL((void*)0)) { | |||
| 255 | PyErr_SetString(PyExc_MemoryError, "RegisterDataType"); | |||
| 256 | return -1; | |||
| 257 | } | |||
| 258 | ||||
| 259 | userdescrs[NPY_NUMUSERTYPES++] = descr; | |||
| 260 | ||||
| 261 | descr->type_num = typenum; | |||
| 262 | if (dtypemeta_wrap_legacy_descriptor(descr) < 0) { | |||
| 263 | descr->type_num = -1; | |||
| 264 | NPY_NUMUSERTYPES--; | |||
| 265 | return -1; | |||
| 266 | } | |||
| 267 | ||||
| 268 | return typenum; | |||
| 269 | } | |||
| 270 | ||||
| 271 | /*NUMPY_API | |||
| 272 | Register Casting Function | |||
| 273 | Replaces any function currently stored. | |||
| 274 | */ | |||
| 275 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
| 276 | PyArray_RegisterCastFunc(PyArray_Descr *descr, int totype, | |||
| 277 | PyArray_VectorUnaryFunc *castfunc) | |||
| 278 | { | |||
| 279 | PyObject *cobj, *key; | |||
| 280 | int ret; | |||
| 281 | ||||
| 282 | if (totype < NPY_NTYPES_ABI_COMPATIBLE) { | |||
| ||||
| 283 | descr->f->cast[totype] = castfunc; | |||
| 284 | return 0; | |||
| 285 | } | |||
| 286 | if (totype >= NPY_NTYPES && !PyTypeNum_ISUSERDEF(totype)(((totype) >= NPY_USERDEF) && ((totype) < NPY_USERDEF + NPY_NUMUSERTYPES))) { | |||
| 287 | PyErr_SetString(PyExc_TypeError, "invalid type number."); | |||
| 288 | return -1; | |||
| 289 | } | |||
| 290 | if (descr->f->castdict == NULL((void*)0)) { | |||
| 291 | descr->f->castdict = PyDict_New(); | |||
| 292 | if (descr->f->castdict == NULL((void*)0)) { | |||
| 293 | return -1; | |||
| 294 | } | |||
| 295 | } | |||
| 296 | key = PyLong_FromLong(totype); | |||
| ||||
| 297 | if (PyErr_Occurred()) { | |||
| 298 | return -1; | |||
| 299 | } | |||
| 300 | cobj = PyCapsule_New((void *)castfunc, NULL((void*)0), NULL((void*)0)); | |||
| 301 | if (cobj == NULL((void*)0)) { | |||
| 302 | Py_DECREF(key)_Py_DECREF(((PyObject*)(key))); | |||
| 303 | return -1; | |||
| 304 | } | |||
| 305 | ret = PyDict_SetItem(descr->f->castdict, key, cobj); | |||
| 306 | Py_DECREF(key)_Py_DECREF(((PyObject*)(key))); | |||
| 307 | Py_DECREF(cobj)_Py_DECREF(((PyObject*)(cobj))); | |||
| 308 | return ret; | |||
| 309 | } | |||
| 310 | ||||
| 311 | /*NUMPY_API | |||
| 312 | * Register a type number indicating that a descriptor can be cast | |||
| 313 | * to it safely | |||
| 314 | */ | |||
| 315 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
| 316 | PyArray_RegisterCanCast(PyArray_Descr *descr, int totype, | |||
| 317 | NPY_SCALARKIND scalar) | |||
| 318 | { | |||
| 319 | /* | |||
| 320 | * If we were to allow this, the casting lookup table for | |||
| 321 | * built-in types needs to be modified, as cancastto is | |||
| 322 | * not checked for them. | |||
| 323 | */ | |||
| 324 | if (!PyTypeNum_ISUSERDEF(descr->type_num)(((descr->type_num) >= NPY_USERDEF) && ((descr-> type_num) < NPY_USERDEF+ NPY_NUMUSERTYPES)) && | |||
| 325 | !PyTypeNum_ISUSERDEF(totype)(((totype) >= NPY_USERDEF) && ((totype) < NPY_USERDEF + NPY_NUMUSERTYPES))) { | |||
| 326 | PyErr_SetString(PyExc_ValueError, | |||
| 327 | "At least one of the types provided to " | |||
| 328 | "RegisterCanCast must be user-defined."); | |||
| 329 | return -1; | |||
| 330 | } | |||
| 331 | ||||
| 332 | if (scalar == NPY_NOSCALAR) { | |||
| 333 | /* | |||
| 334 | * register with cancastto | |||
| 335 | * These lists won't be freed once created | |||
| 336 | * -- they become part of the data-type | |||
| 337 | */ | |||
| 338 | if (descr->f->cancastto == NULL((void*)0)) { | |||
| 339 | descr->f->cancastto = (int *)malloc(1*sizeof(int)); | |||
| 340 | if (descr->f->cancastto == NULL((void*)0)) { | |||
| 341 | PyErr_NoMemory(); | |||
| 342 | return -1; | |||
| 343 | } | |||
| 344 | descr->f->cancastto[0] = NPY_NOTYPE; | |||
| 345 | } | |||
| 346 | return _append_new(&descr->f->cancastto, totype); | |||
| 347 | } | |||
| 348 | else { | |||
| 349 | /* register with cancastscalarkindto */ | |||
| 350 | if (descr->f->cancastscalarkindto == NULL((void*)0)) { | |||
| 351 | int i; | |||
| 352 | descr->f->cancastscalarkindto = | |||
| 353 | (int **)malloc(NPY_NSCALARKINDS(NPY_OBJECT_SCALAR + 1)* sizeof(int*)); | |||
| 354 | if (descr->f->cancastscalarkindto == NULL((void*)0)) { | |||
| 355 | PyErr_NoMemory(); | |||
| 356 | return -1; | |||
| 357 | } | |||
| 358 | for (i = 0; i < NPY_NSCALARKINDS(NPY_OBJECT_SCALAR + 1); i++) { | |||
| 359 | descr->f->cancastscalarkindto[i] = NULL((void*)0); | |||
| 360 | } | |||
| 361 | } | |||
| 362 | if (descr->f->cancastscalarkindto[scalar] == NULL((void*)0)) { | |||
| 363 | descr->f->cancastscalarkindto[scalar] = | |||
| 364 | (int *)malloc(1*sizeof(int)); | |||
| 365 | if (descr->f->cancastscalarkindto[scalar] == NULL((void*)0)) { | |||
| 366 | PyErr_NoMemory(); | |||
| 367 | return -1; | |||
| 368 | } | |||
| 369 | descr->f->cancastscalarkindto[scalar][0] = | |||
| 370 | NPY_NOTYPE; | |||
| 371 | } | |||
| 372 | return _append_new(&descr->f->cancastscalarkindto[scalar], totype); | |||
| 373 | } | |||
| 374 | } | |||
| 375 | ||||
| 376 | ||||
| 377 | /* | |||
| 378 | * Legacy user DTypes implemented the common DType operation | |||
| 379 | * (as used in type promotion/result_type, and e.g. the type for | |||
| 380 | * concatenation), by using "safe cast" logic. | |||
| 381 | * | |||
| 382 | * New DTypes do have this behaviour generally, but we use can-cast | |||
| 383 | * when legacy user dtypes are involved. | |||
| 384 | */ | |||
| 385 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) PyArray_DTypeMeta * | |||
| 386 | legacy_userdtype_common_dtype_function( | |||
| 387 | PyArray_DTypeMeta *cls, PyArray_DTypeMeta *other) | |||
| 388 | { | |||
| 389 | int skind1 = NPY_NOSCALAR, skind2 = NPY_NOSCALAR, skind; | |||
| 390 | ||||
| 391 | if (!other->legacy) { | |||
| 392 | /* legacy DTypes can always defer to new style ones */ | |||
| 393 | Py_INCREF(Py_NotImplemented)_Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct)))); | |||
| 394 | return (PyArray_DTypeMeta *)Py_NotImplemented(&_Py_NotImplementedStruct); | |||
| 395 | } | |||
| 396 | /* Defer so that only one of the types handles the cast */ | |||
| 397 | if (cls->type_num < other->type_num) { | |||
| 398 | Py_INCREF(Py_NotImplemented)_Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct)))); | |||
| 399 | return (PyArray_DTypeMeta *)Py_NotImplemented(&_Py_NotImplementedStruct); | |||
| 400 | } | |||
| 401 | ||||
| 402 | /* Check whether casting is possible from one type to the other */ | |||
| 403 | if (PyArray_CanCastSafely(cls->type_num, other->type_num)) { | |||
| 404 | Py_INCREF(other)_Py_INCREF(((PyObject*)(other))); | |||
| 405 | return other; | |||
| 406 | } | |||
| 407 | if (PyArray_CanCastSafely(other->type_num, cls->type_num)) { | |||
| 408 | Py_INCREF(cls)_Py_INCREF(((PyObject*)(cls))); | |||
| 409 | return cls; | |||
| 410 | } | |||
| 411 | ||||
| 412 | /* | |||
| 413 | * The following code used to be part of PyArray_PromoteTypes(). | |||
| 414 | * We can expect that this code is never used. | |||
| 415 | * In principle, it allows for promotion of two different user dtypes | |||
| 416 | * to a single NumPy dtype of the same "kind". In practice | |||
| 417 | * using the same `kind` as NumPy was never possible due to an | |||
| 418 | * simplification where `PyArray_EquivTypes(descr1, descr2)` will | |||
| 419 | * return True if both kind and element size match (e.g. bfloat16 and | |||
| 420 | * float16 would be equivalent). | |||
| 421 | * The option is also very obscure and not used in the examples. | |||
| 422 | */ | |||
| 423 | ||||
| 424 | /* Convert the 'kind' char into a scalar kind */ | |||
| 425 | switch (cls->kind) { | |||
| 426 | case 'b': | |||
| 427 | skind1 = NPY_BOOL_SCALAR; | |||
| 428 | break; | |||
| 429 | case 'u': | |||
| 430 | skind1 = NPY_INTPOS_SCALAR; | |||
| 431 | break; | |||
| 432 | case 'i': | |||
| 433 | skind1 = NPY_INTNEG_SCALAR; | |||
| 434 | break; | |||
| 435 | case 'f': | |||
| 436 | skind1 = NPY_FLOAT_SCALAR; | |||
| 437 | break; | |||
| 438 | case 'c': | |||
| 439 | skind1 = NPY_COMPLEX_SCALAR; | |||
| 440 | break; | |||
| 441 | } | |||
| 442 | switch (other->kind) { | |||
| 443 | case 'b': | |||
| 444 | skind2 = NPY_BOOL_SCALAR; | |||
| 445 | break; | |||
| 446 | case 'u': | |||
| 447 | skind2 = NPY_INTPOS_SCALAR; | |||
| 448 | break; | |||
| 449 | case 'i': | |||
| 450 | skind2 = NPY_INTNEG_SCALAR; | |||
| 451 | break; | |||
| 452 | case 'f': | |||
| 453 | skind2 = NPY_FLOAT_SCALAR; | |||
| 454 | break; | |||
| 455 | case 'c': | |||
| 456 | skind2 = NPY_COMPLEX_SCALAR; | |||
| 457 | break; | |||
| 458 | } | |||
| 459 | ||||
| 460 | /* If both are scalars, there may be a promotion possible */ | |||
| 461 | if (skind1 != NPY_NOSCALAR && skind2 != NPY_NOSCALAR) { | |||
| 462 | ||||
| 463 | /* Start with the larger scalar kind */ | |||
| 464 | skind = (skind1 > skind2) ? skind1 : skind2; | |||
| 465 | int ret_type_num = _npy_smallest_type_of_kind_table[skind]; | |||
| 466 | ||||
| 467 | for (;;) { | |||
| 468 | ||||
| 469 | /* If there is no larger type of this kind, try a larger kind */ | |||
| 470 | if (ret_type_num < 0) { | |||
| 471 | ++skind; | |||
| 472 | /* Use -1 to signal no promoted type found */ | |||
| 473 | if (skind < NPY_NSCALARKINDS(NPY_OBJECT_SCALAR + 1)) { | |||
| 474 | ret_type_num = _npy_smallest_type_of_kind_table[skind]; | |||
| 475 | } | |||
| 476 | else { | |||
| 477 | break; | |||
| 478 | } | |||
| 479 | } | |||
| 480 | ||||
| 481 | /* If we found a type to which we can promote both, done! */ | |||
| 482 | if (PyArray_CanCastSafely(cls->type_num, ret_type_num) && | |||
| 483 | PyArray_CanCastSafely(other->type_num, ret_type_num)) { | |||
| 484 | return PyArray_DTypeFromTypeNum(ret_type_num); | |||
| 485 | } | |||
| 486 | ||||
| 487 | /* Try the next larger type of this kind */ | |||
| 488 | ret_type_num = _npy_next_larger_type_table[ret_type_num]; | |||
| 489 | } | |||
| 490 | } | |||
| 491 | ||||
| 492 | Py_INCREF(Py_NotImplemented)_Py_INCREF(((PyObject*)((&_Py_NotImplementedStruct)))); | |||
| 493 | return (PyArray_DTypeMeta *)Py_NotImplemented(&_Py_NotImplementedStruct); | |||
| 494 | } | |||
| 495 | ||||
| 496 | ||||
| 497 | /** | |||
| 498 | * This function wraps a legacy cast into an array-method. This is mostly | |||
| 499 | * used for legacy user-dtypes, but for example numeric to/from datetime | |||
| 500 | * casts were only defined that way as well. | |||
| 501 | * | |||
| 502 | * @param from | |||
| 503 | * @param to | |||
| 504 | * @param casting If `NPY_NO_CASTING` will check the legacy registered cast, | |||
| 505 | * otherwise uses the provided cast. | |||
| 506 | */ | |||
| 507 | NPY_NO_EXPORT__attribute__((visibility("hidden"))) int | |||
| 508 | PyArray_AddLegacyWrapping_CastingImpl( | |||
| 509 | PyArray_DTypeMeta *from, PyArray_DTypeMeta *to, NPY_CASTING casting) | |||
| 510 | { | |||
| 511 | if (casting < 0) { | |||
| 512 | if (from == to) { | |||
| 513 | casting = NPY_NO_CASTING; | |||
| 514 | } | |||
| 515 | else if (PyArray_LegacyCanCastTypeTo( | |||
| 516 | from->singleton, to->singleton, NPY_SAFE_CASTING)) { | |||
| 517 | casting = NPY_SAFE_CASTING; | |||
| 518 | } | |||
| 519 | else if (PyArray_LegacyCanCastTypeTo( | |||
| 520 | from->singleton, to->singleton, NPY_SAME_KIND_CASTING)) { | |||
| 521 | casting = NPY_SAME_KIND_CASTING; | |||
| 522 | } | |||
| 523 | else { | |||
| 524 | casting = NPY_UNSAFE_CASTING; | |||
| 525 | } | |||
| 526 | } | |||
| 527 | ||||
| 528 | PyArray_DTypeMeta *dtypes[2] = {from, to}; | |||
| 529 | PyArrayMethod_Spec spec = { | |||
| 530 | /* Name is not actually used, but allows identifying these. */ | |||
| 531 | .name = "legacy_cast", | |||
| 532 | .nin = 1, | |||
| 533 | .nout = 1, | |||
| 534 | .casting = casting, | |||
| 535 | .dtypes = dtypes, | |||
| 536 | }; | |||
| 537 | ||||
| 538 | if (from == to) { | |||
| 539 | spec.flags = NPY_METH_REQUIRES_PYAPI | NPY_METH_SUPPORTS_UNALIGNED; | |||
| 540 | PyType_Slot slots[] = { | |||
| 541 | {NPY_METH_get_loop2, &legacy_cast_get_strided_loop}, | |||
| 542 | {NPY_METH_resolve_descriptors1, &legacy_same_dtype_resolve_descriptors}, | |||
| 543 | {0, NULL((void*)0)}}; | |||
| 544 | spec.slots = slots; | |||
| 545 | return PyArray_AddCastingImplementation_FromSpec(&spec, 1); | |||
| 546 | } | |||
| 547 | else { | |||
| 548 | spec.flags = NPY_METH_REQUIRES_PYAPI; | |||
| 549 | PyType_Slot slots[] = { | |||
| 550 | {NPY_METH_get_loop2, &legacy_cast_get_strided_loop}, | |||
| 551 | {NPY_METH_resolve_descriptors1, &simple_cast_resolve_descriptors}, | |||
| 552 | {0, NULL((void*)0)}}; | |||
| 553 | spec.slots = slots; | |||
| 554 | return PyArray_AddCastingImplementation_FromSpec(&spec, 1); | |||
| 555 | } | |||
| 556 | } |
| 1 | #ifndef PyLong_FromLong |
| 2 | struct _object; |
| 3 | typedef struct _object PyObject; |
| 4 | PyObject* clang_analyzer_PyObject_New_Reference(); |
| 5 | PyObject* PyLong_FromLong(long v) { |
| 6 | return clang_analyzer_PyObject_New_Reference(); |
| 7 | } |
| 8 | #else |
| 9 | #warning "API PyLong_FromLong is defined as a macro." |
| 10 | #endif |