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

42
NPY_NO_EXPORT PyArray_Descr **userdescrs=NULL;
43

44
static int
45 1
_append_new(int **p_types, int insert)
46
{
47 1
    int n = 0;
48
    int *newtypes;
49 1
    int *types = *p_types;
50

51 1
    while (types[n] != NPY_NOTYPE) {
52 0
        n++;
53
    }
54 1
    newtypes = (int *)realloc(types, (n + 2)*sizeof(int));
55 1
    if (newtypes == NULL) {
56 0
        PyErr_NoMemory();
57 0
        return -1;
58
    }
59 1
    newtypes[n] = insert;
60 1
    newtypes[n + 1] = NPY_NOTYPE;
61

62
    /* Replace the passed-in pointer */
63 1
    *p_types = newtypes;
64 1
    return 0;
65
}
66

67
static npy_bool
68 0
_default_nonzero(void *ip, void *arr)
69
{
70 0
    int elsize = PyArray_ITEMSIZE(arr);
71 0
    char *ptr = ip;
72 0
    while (elsize--) {
73 0
        if (*ptr++ != 0) {
74
            return NPY_TRUE;
75
        }
76
    }
77
    return NPY_FALSE;
78
}
79

80
static void
81 0
_default_copyswapn(void *dst, npy_intp dstride, void *src,
82
                   npy_intp sstride, npy_intp n, int swap, void *arr)
83
{
84
    npy_intp i;
85
    PyArray_CopySwapFunc *copyswap;
86 0
    char *dstptr = dst;
87 0
    char *srcptr = src;
88

89 0
    copyswap = PyArray_DESCR(arr)->f->copyswap;
90

91 0
    for (i = 0; i < n; i++) {
92 0
        copyswap(dstptr, srcptr, swap, arr);
93 0
        dstptr += dstride;
94 0
        srcptr += sstride;
95
    }
96
}
97

98
/*NUMPY_API
99
  Initialize arrfuncs to NULL
100
*/
101
NPY_NO_EXPORT void
102 1
PyArray_InitArrFuncs(PyArray_ArrFuncs *f)
103
{
104
    int i;
105

106 1
    for(i = 0; i < NPY_NTYPES_ABI_COMPATIBLE; i++) {
107 1
        f->cast[i] = NULL;
108
    }
109 1
    f->getitem = NULL;
110 1
    f->setitem = NULL;
111 1
    f->copyswapn = NULL;
112 1
    f->copyswap = NULL;
113 1
    f->compare = NULL;
114 1
    f->argmax = NULL;
115 1
    f->argmin = NULL;
116 1
    f->dotfunc = NULL;
117 1
    f->scanfunc = NULL;
118 1
    f->fromstr = NULL;
119 1
    f->nonzero = NULL;
120 1
    f->fill = NULL;
121 1
    f->fillwithscalar = NULL;
122 1
    for(i = 0; i < NPY_NSORTS; i++) {
123 1
        f->sort[i] = NULL;
124 1
        f->argsort[i] = NULL;
125
    }
126 1
    f->castdict = NULL;
127 1
    f->scalarkind = NULL;
128 1
    f->cancastscalarkindto = NULL;
129 1
    f->cancastto = NULL;
130 1
    f->fastclip = NULL;
131 1
    f->fastputmask = NULL;
132 1
    f->fasttake = NULL;
133
}
134

135

136
static int
137 1
test_deprecated_arrfuncs_members(PyArray_ArrFuncs *f) {
138
    /* NumPy 1.19, 2020-01-15 */
139 1
    if (f->fastputmask != NULL) {
140 0
        if (DEPRECATE(
141
                "The ->f->fastputmask member of custom dtypes is ignored; "
142
                "setting it may be an error in the future.\n"
143
                "The custom dtype you are using must be revised, but "
144
                "results will not be affected.") < 0) {
145
            return -1;
146
        }
147
    }
148
    /* NumPy 1.19, 2020-01-15 */
149 1
    if (f->fasttake != NULL) {
150 0
        if (DEPRECATE(
151
                "The ->f->fastputmask member of custom dtypes is ignored; "
152
                "setting it may be an error in the future.\n"
153
                "The custom dtype you are using must be revised, but "
154
                "results will not be affected.") < 0) {
155
            return -1;
156
        }
157
    }
158
    /* NumPy 1.19, 2020-01-15 */
159 1
    if (f->fastclip != NULL) {
160
        /* fastclip was already deprecated at execution time in 1.17. */
161 0
        if (DEPRECATE(
162
                "The ->f->fastclip member of custom dtypes is deprecated; "
163
                "setting it will be an error in the future.\n"
164
                "The custom dtype you are using must be changed to use "
165
                "PyUFunc_RegisterLoopForDescr to attach a custom loop to "
166
                "np.core.umath.clip, np.minimum, and np.maximum") < 0) {
167
            return -1;
168
        }
169
    }
170
    return 0;
171
}
172

173
/*
174
  returns typenum to associate with this type >=NPY_USERDEF.
175
  needs the userdecrs table and PyArray_NUMUSER variables
176
  defined in arraytypes.inc
177
*/
178
/*NUMPY_API
179
  Register Data type
180
  Does not change the reference count of descr
181
*/
182
NPY_NO_EXPORT int
183 1
PyArray_RegisterDataType(PyArray_Descr *descr)
184
{
185
    PyArray_Descr *descr2;
186
    int typenum;
187
    int i;
188
    PyArray_ArrFuncs *f;
189

190
    /* See if this type is already registered */
191 1
    for (i = 0; i < NPY_NUMUSERTYPES; i++) {
192 0
        descr2 = userdescrs[i];
193 0
        if (descr2 == descr) {
194 0
            return descr->type_num;
195
        }
196
    }
197 1
    typenum = NPY_USERDEF + NPY_NUMUSERTYPES;
198 1
    descr->type_num = typenum;
199 1
    if (PyDataType_ISUNSIZED(descr)) {
200 0
        PyErr_SetString(PyExc_ValueError, "cannot register a" \
201
                        "flexible data-type");
202 0
        return -1;
203
    }
204 1
    f = descr->f;
205 1
    if (f->nonzero == NULL) {
206 0
        f->nonzero = _default_nonzero;
207
    }
208 1
    if (f->copyswapn == NULL) {
209 0
        f->copyswapn = _default_copyswapn;
210
    }
211 1
    if (f->copyswap == NULL || f->getitem == NULL ||
212 1
        f->setitem == NULL) {
213 0
        PyErr_SetString(PyExc_ValueError, "a required array function"   \
214
                        " is missing.");
215 0
        return -1;
216
    }
217 1
    if (descr->flags & (NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT)) {
218 0
        PyErr_SetString(PyExc_ValueError,
219
                "Legacy user dtypes referencing python objects or generally "
220
                "allocated memory are unsupported. "
221
                "If you see this error in an existing, working code base, "
222
                "please contact the NumPy developers.");
223 0
        return -1;
224
    }
225 1
    if (descr->typeobj == NULL) {
226 0
        PyErr_SetString(PyExc_ValueError, "missing typeobject");
227 0
        return -1;
228
    }
229

230 1
    if (test_deprecated_arrfuncs_members(f) < 0) {
231
        return -1;
232
    }
233

234 1
    userdescrs = realloc(userdescrs,
235 1
                         (NPY_NUMUSERTYPES+1)*sizeof(void *));
236 1
    if (userdescrs == NULL) {
237 0
        PyErr_SetString(PyExc_MemoryError, "RegisterDataType");
238 0
        return -1;
239
    }
240 1
    userdescrs[NPY_NUMUSERTYPES++] = descr;
241

242 1
    if (dtypemeta_wrap_legacy_descriptor(descr) < 0) {
243
        return -1;
244
    }
245

246 1
    return typenum;
247
}
248

249
/*NUMPY_API
250
  Register Casting Function
251
  Replaces any function currently stored.
252
*/
253
NPY_NO_EXPORT int
254 1
PyArray_RegisterCastFunc(PyArray_Descr *descr, int totype,
255
                         PyArray_VectorUnaryFunc *castfunc)
256
{
257
    PyObject *cobj, *key;
258
    int ret;
259

260 1
    if (totype < NPY_NTYPES_ABI_COMPATIBLE) {
261 1
        descr->f->cast[totype] = castfunc;
262 1
        return 0;
263
    }
264 1
    if (totype >= NPY_NTYPES && !PyTypeNum_ISUSERDEF(totype)) {
265 0
        PyErr_SetString(PyExc_TypeError, "invalid type number.");
266 0
        return -1;
267
    }
268 1
    if (descr->f->castdict == NULL) {
269 0
        descr->f->castdict = PyDict_New();
270 0
        if (descr->f->castdict == NULL) {
271
            return -1;
272
        }
273
    }
274 1
    key = PyLong_FromLong(totype);
275 1
    if (PyErr_Occurred()) {
276
        return -1;
277
    }
278 1
    cobj = PyCapsule_New((void *)castfunc, NULL, NULL);
279 1
    if (cobj == NULL) {
280 0
        Py_DECREF(key);
281
        return -1;
282
    }
283 1
    ret = PyDict_SetItem(descr->f->castdict, key, cobj);
284 1
    Py_DECREF(key);
285 1
    Py_DECREF(cobj);
286
    return ret;
287
}
288

289
/*NUMPY_API
290
 * Register a type number indicating that a descriptor can be cast
291
 * to it safely
292
 */
293
NPY_NO_EXPORT int
294 1
PyArray_RegisterCanCast(PyArray_Descr *descr, int totype,
295
                        NPY_SCALARKIND scalar)
296
{
297
    /*
298
     * If we were to allow this, the casting lookup table for
299
     * built-in types needs to be modified, as cancastto is
300
     * not checked for them.
301
     */
302 1
    if (!PyTypeNum_ISUSERDEF(descr->type_num) &&
303 1
                                        !PyTypeNum_ISUSERDEF(totype)) {
304 0
        PyErr_SetString(PyExc_ValueError,
305
                        "At least one of the types provided to"
306
                        "RegisterCanCast must be user-defined.");
307 0
        return -1;
308
    }
309

310 1
    if (scalar == NPY_NOSCALAR) {
311
        /*
312
         * register with cancastto
313
         * These lists won't be freed once created
314
         * -- they become part of the data-type
315
         */
316 1
        if (descr->f->cancastto == NULL) {
317 1
            descr->f->cancastto = (int *)malloc(1*sizeof(int));
318 1
            if (descr->f->cancastto == NULL) {
319 0
                PyErr_NoMemory();
320 0
                return -1;
321
            }
322 1
            descr->f->cancastto[0] = NPY_NOTYPE;
323
        }
324 1
        return _append_new(&descr->f->cancastto, totype);
325
    }
326
    else {
327
        /* register with cancastscalarkindto */
328 0
        if (descr->f->cancastscalarkindto == NULL) {
329
            int i;
330 0
            descr->f->cancastscalarkindto =
331 0
                (int **)malloc(NPY_NSCALARKINDS* sizeof(int*));
332 0
            if (descr->f->cancastscalarkindto == NULL) {
333 0
                PyErr_NoMemory();
334 0
                return -1;
335
            }
336 0
            for (i = 0; i < NPY_NSCALARKINDS; i++) {
337 0
                descr->f->cancastscalarkindto[i] = NULL;
338
            }
339
        }
340 0
        if (descr->f->cancastscalarkindto[scalar] == NULL) {
341 0
            descr->f->cancastscalarkindto[scalar] =
342 0
                (int *)malloc(1*sizeof(int));
343 0
            if (descr->f->cancastscalarkindto[scalar] == NULL) {
344 0
                PyErr_NoMemory();
345 0
                return -1;
346
            }
347 0
            descr->f->cancastscalarkindto[scalar][0] =
348
                NPY_NOTYPE;
349
        }
350 0
        return _append_new(&descr->f->cancastscalarkindto[scalar], totype);
351
    }
352
}

Read our documentation on viewing source code .

Loading