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 |