1
/* Array Flags Object */
2

3
#define PY_SSIZE_T_CLEAN
4
#include <Python.h>
5
#include "structmember.h"
6

7
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
8
#define _MULTIARRAYMODULE
9
#include "numpy/arrayobject.h"
10
#include "arrayobject.h"
11
#include "numpy/arrayscalars.h"
12

13
#include "npy_config.h"
14

15
#include "npy_pycompat.h"
16
#include "array_assign.h"
17

18
#include "common.h"
19

20
static void
21
_UpdateContiguousFlags(PyArrayObject *ap);
22

23
/*NUMPY_API
24
 *
25
 * Get New ArrayFlagsObject
26
 */
27
NPY_NO_EXPORT PyObject *
28 1
PyArray_NewFlagsObject(PyObject *obj)
29
{
30
    PyObject *flagobj;
31
    int flags;
32

33 1
    if (obj == NULL) {
34
        flags = NPY_ARRAY_C_CONTIGUOUS |
35
                NPY_ARRAY_OWNDATA |
36
                NPY_ARRAY_F_CONTIGUOUS |
37
                NPY_ARRAY_ALIGNED;
38
    }
39
    else {
40 1
        if (!PyArray_Check(obj)) {
41 0
            PyErr_SetString(PyExc_ValueError,
42
                    "Need a NumPy array to create a flags object");
43 0
            return NULL;
44
        }
45

46 1
        flags = PyArray_FLAGS((PyArrayObject *)obj);
47
    }
48 1
    flagobj = PyArrayFlags_Type.tp_alloc(&PyArrayFlags_Type, 0);
49 1
    if (flagobj == NULL) {
50
        return NULL;
51
    }
52 1
    Py_XINCREF(obj);
53 1
    ((PyArrayFlagsObject *)flagobj)->arr = obj;
54 1
    ((PyArrayFlagsObject *)flagobj)->flags = flags;
55 1
    return flagobj;
56
}
57

58
/*NUMPY_API
59
 * Update Several Flags at once.
60
 */
61
NPY_NO_EXPORT void
62 1
PyArray_UpdateFlags(PyArrayObject *ret, int flagmask)
63
{
64
    /* Always update both, as its not trivial to guess one from the other */
65 1
    if (flagmask & (NPY_ARRAY_F_CONTIGUOUS | NPY_ARRAY_C_CONTIGUOUS)) {
66 1
        _UpdateContiguousFlags(ret);
67
    }
68 1
    if (flagmask & NPY_ARRAY_ALIGNED) {
69 1
        if (IsAligned(ret)) {
70
            PyArray_ENABLEFLAGS(ret, NPY_ARRAY_ALIGNED);
71
        }
72
        else {
73
            PyArray_CLEARFLAGS(ret, NPY_ARRAY_ALIGNED);
74
        }
75
    }
76
    /*
77
     * This is not checked by default WRITEABLE is not
78
     * part of UPDATE_ALL
79
     */
80 1
    if (flagmask & NPY_ARRAY_WRITEABLE) {
81 0
        if (_IsWriteable(ret)) {
82
            PyArray_ENABLEFLAGS(ret, NPY_ARRAY_WRITEABLE);
83
        }
84
        else {
85
            PyArray_CLEARFLAGS(ret, NPY_ARRAY_WRITEABLE);
86
        }
87
    }
88 1
    return;
89
}
90

91
/*
92
 * Check whether the given array is stored contiguously
93
 * in memory. And update the passed in ap flags appropriately.
94
 *
95
 * The traditional rule is that for an array to be flagged as C contiguous,
96
 * the following must hold:
97
 *
98
 * strides[-1] == itemsize
99
 * strides[i] == shape[i+1] * strides[i + 1]
100
 *
101
 * And for an array to be flagged as F contiguous, the obvious reversal:
102
 *
103
 * strides[0] == itemsize
104
 * strides[i] == shape[i - 1] * strides[i - 1]
105
 *
106
 * According to these rules, a 0- or 1-dimensional array is either both
107
 * C- and F-contiguous, or neither; and an array with 2+ dimensions
108
 * can be C- or F- contiguous, or neither, but not both. Though there
109
 * there are exceptions for arrays with zero or one item, in the first
110
 * case the check is relaxed up to and including the first dimension
111
 * with shape[i] == 0. In the second case `strides == itemsize` will
112
 * can be true for all dimensions and both flags are set.
113
 *
114
 * When NPY_RELAXED_STRIDES_CHECKING is set, we use a more accurate
115
 * definition of C- and F-contiguity, in which all 0-sized arrays are
116
 * contiguous (regardless of dimensionality), and if shape[i] == 1
117
 * then we ignore strides[i] (since it has no affect on memory layout).
118
 * With these new rules, it is possible for e.g. a 10x1 array to be both
119
 * C- and F-contiguous -- but, they break downstream code which assumes
120
 * that for contiguous arrays strides[-1] (resp. strides[0]) always
121
 * contains the itemsize.
122
 */
123
static void
124 1
_UpdateContiguousFlags(PyArrayObject *ap)
125
{
126
    npy_intp sd;
127
    npy_intp dim;
128
    int i;
129 1
    npy_bool is_c_contig = 1;
130

131 1
    sd = PyArray_ITEMSIZE(ap);
132 1
    for (i = PyArray_NDIM(ap) - 1; i >= 0; --i) {
133 1
        dim = PyArray_DIMS(ap)[i];
134
#if NPY_RELAXED_STRIDES_CHECKING
135
        /* contiguous by definition */
136 1
        if (dim == 0) {
137 1
            PyArray_ENABLEFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS);
138
            PyArray_ENABLEFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS);
139
            return;
140
        }
141 1
        if (dim != 1) {
142 1
            if (PyArray_STRIDES(ap)[i] != sd) {
143 1
                is_c_contig = 0;
144
            }
145 1
            sd *= dim;
146
        }
147
#else /* not NPY_RELAXED_STRIDES_CHECKING */
148
        if (PyArray_STRIDES(ap)[i] != sd) {
149
            is_c_contig = 0;
150
            break;
151
        }
152
        /* contiguous, if it got this far */
153
        if (dim == 0) {
154
            break;
155
        }
156
        sd *= dim;
157
#endif /* not NPY_RELAXED_STRIDES_CHECKING */
158
    }
159 1
    if (is_c_contig) {
160
        PyArray_ENABLEFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS);
161
    }
162
    else {
163
        PyArray_CLEARFLAGS(ap, NPY_ARRAY_C_CONTIGUOUS);
164
    }
165

166
    /* check if fortran contiguous */
167
    sd = PyArray_ITEMSIZE(ap);
168 1
    for (i = 0; i < PyArray_NDIM(ap); ++i) {
169 1
        dim = PyArray_DIMS(ap)[i];
170
#if NPY_RELAXED_STRIDES_CHECKING
171 1
        if (dim != 1) {
172 1
            if (PyArray_STRIDES(ap)[i] != sd) {
173
                PyArray_CLEARFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS);
174
                return;
175
            }
176 1
            sd *= dim;
177
        }
178
#else /* not NPY_RELAXED_STRIDES_CHECKING */
179
        if (PyArray_STRIDES(ap)[i] != sd) {
180
            PyArray_CLEARFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS);
181
            return;
182
        }
183
        if (dim == 0) {
184
            break;
185
        }
186
        sd *= dim;
187
#endif /* not NPY_RELAXED_STRIDES_CHECKING */
188
    }
189
    PyArray_ENABLEFLAGS(ap, NPY_ARRAY_F_CONTIGUOUS);
190
    return;
191
}
192

193
static void
194 1
arrayflags_dealloc(PyArrayFlagsObject *self)
195
{
196 1
    Py_XDECREF(self->arr);
197 1
    Py_TYPE(self)->tp_free((PyObject *)self);
198
}
199

200

201
#define _define_get(UPPER, lower) \
202
    static PyObject * \
203
    arrayflags_ ## lower ## _get(PyArrayFlagsObject *self) \
204
    { \
205
        return PyBool_FromLong((self->flags & (UPPER)) == (UPPER)); \
206
    }
207

208
static char *msg = "future versions will not create a writeable "
209
    "array from broadcast_array. Set the writable flag explicitly to "
210
    "avoid this warning.";
211

212
#define _define_get_warn(UPPER, lower) \
213
    static PyObject * \
214
    arrayflags_ ## lower ## _get(PyArrayFlagsObject *self) \
215
    { \
216
        if (self->flags & NPY_ARRAY_WARN_ON_WRITE) { \
217
            if (PyErr_Warn(PyExc_FutureWarning, msg) < 0) {\
218
                return NULL; \
219
            } \
220
        }\
221
        return PyBool_FromLong((self->flags & (UPPER)) == (UPPER)); \
222
    }
223

224

225 1
_define_get(NPY_ARRAY_C_CONTIGUOUS, contiguous)
226 1
_define_get(NPY_ARRAY_F_CONTIGUOUS, fortran)
227 1
_define_get(NPY_ARRAY_WRITEBACKIFCOPY, writebackifcopy)
228 1
_define_get(NPY_ARRAY_OWNDATA, owndata)
229 1
_define_get(NPY_ARRAY_ALIGNED, aligned)
230 1
_define_get(NPY_ARRAY_WRITEABLE, writeable_no_warn)
231 1
_define_get_warn(NPY_ARRAY_WRITEABLE, writeable)
232 1
_define_get_warn(NPY_ARRAY_ALIGNED|
233
            NPY_ARRAY_WRITEABLE, behaved)
234 1
_define_get_warn(NPY_ARRAY_ALIGNED|
235
            NPY_ARRAY_WRITEABLE|
236
            NPY_ARRAY_C_CONTIGUOUS, carray)
237

238
static PyObject *
239 1
arrayflags_updateifcopy_get(PyArrayFlagsObject *self)
240
{
241
    PyObject *item;
242
    /* 2017-Nov-10 1.14 */
243 1
    if(DEPRECATE("UPDATEIFCOPY deprecated, use WRITEBACKIFCOPY instead") < 0) {
244
        return NULL;
245
    }
246 1
    if ((self->flags & (NPY_ARRAY_UPDATEIFCOPY)) == (NPY_ARRAY_UPDATEIFCOPY)) {
247
        item = Py_True;
248
    }
249
    else {
250 1
        item = Py_False;
251
    }
252 1
    Py_INCREF(item);
253 1
    return item;
254
}
255

256

257
static PyObject *
258 1
arrayflags_forc_get(PyArrayFlagsObject *self)
259
{
260
    PyObject *item;
261

262 1
    if (((self->flags & NPY_ARRAY_F_CONTIGUOUS) == NPY_ARRAY_F_CONTIGUOUS) ||
263
        ((self->flags & NPY_ARRAY_C_CONTIGUOUS) == NPY_ARRAY_C_CONTIGUOUS)) {
264
        item = Py_True;
265
    }
266
    else {
267 0
        item = Py_False;
268
    }
269 1
    Py_INCREF(item);
270 1
    return item;
271
}
272

273
static PyObject *
274 1
arrayflags_fnc_get(PyArrayFlagsObject *self)
275
{
276
    PyObject *item;
277

278 1
    if (((self->flags & NPY_ARRAY_F_CONTIGUOUS) == NPY_ARRAY_F_CONTIGUOUS) &&
279
        !((self->flags & NPY_ARRAY_C_CONTIGUOUS) == NPY_ARRAY_C_CONTIGUOUS)) {
280
        item = Py_True;
281
    }
282
    else {
283 1
        item = Py_False;
284
    }
285 1
    Py_INCREF(item);
286 1
    return item;
287
}
288

289
static PyObject *
290 1
arrayflags_farray_get(PyArrayFlagsObject *self)
291
{
292
    PyObject *item;
293

294 1
    if (((self->flags & (NPY_ARRAY_ALIGNED|
295
                         NPY_ARRAY_WRITEABLE|
296 1
                         NPY_ARRAY_F_CONTIGUOUS)) != 0) &&
297 1
        !((self->flags & NPY_ARRAY_C_CONTIGUOUS) != 0)) {
298
        item = Py_True;
299
    }
300
    else {
301 1
        item = Py_False;
302
    }
303 1
    Py_INCREF(item);
304 1
    return item;
305
}
306

307
static PyObject *
308 1
arrayflags_num_get(PyArrayFlagsObject *self)
309
{
310 1
    return PyLong_FromLong(self->flags);
311
}
312

313
/* relies on setflags order being write, align, uic */
314
static int
315 1
arrayflags_updateifcopy_set(PyArrayFlagsObject *self, PyObject *obj)
316
{
317
    PyObject *res;
318

319 1
    if (obj == NULL) {
320 1
        PyErr_SetString(PyExc_AttributeError,
321
                "Cannot delete flags updateifcopy attribute");
322 1
        return -1;
323
    }
324 0
    if (self->arr == NULL) {
325 0
        PyErr_SetString(PyExc_ValueError,
326
                "Cannot set flags on array scalars.");
327 0
        return -1;
328
    }
329
    /* 2017-Nov-10 1.14 */
330 0
    if(DEPRECATE("UPDATEIFCOPY deprecated, use WRITEBACKIFCOPY instead") < 0) {
331
        return -1;
332
    }
333 0
    res = PyObject_CallMethod(self->arr, "setflags", "OOO", Py_None, Py_None,
334 0
                              (PyObject_IsTrue(obj) ? Py_True : Py_False));
335 0
    if (res == NULL) {
336
        return -1;
337
    }
338 0
    Py_DECREF(res);
339
    return 0;
340
}
341

342
/* relies on setflags order being write, align, uic */
343
static int
344 1
arrayflags_writebackifcopy_set(PyArrayFlagsObject *self, PyObject *obj)
345
{
346
    PyObject *res;
347

348 1
    if (obj == NULL) {
349 1
        PyErr_SetString(PyExc_AttributeError,
350
                "Cannot delete flags writebackifcopy attribute");
351 1
        return -1;
352
    }
353 0
    if (self->arr == NULL) {
354 0
        PyErr_SetString(PyExc_ValueError,
355
                "Cannot set flags on array scalars.");
356 0
        return -1;
357
    }
358 0
    res = PyObject_CallMethod(self->arr, "setflags", "OOO", Py_None, Py_None,
359 0
                              (PyObject_IsTrue(obj) ? Py_True : Py_False));
360 0
    if (res == NULL) {
361
        return -1;
362
    }
363 0
    Py_DECREF(res);
364
    return 0;
365
}
366

367
static int
368 1
arrayflags_aligned_set(PyArrayFlagsObject *self, PyObject *obj)
369
{
370
    PyObject *res;
371

372 1
    if (obj == NULL) {
373 1
        PyErr_SetString(PyExc_AttributeError,
374
                "Cannot delete flags aligned attribute");
375 1
        return -1;
376
    }
377 0
    if (self->arr == NULL) {
378 0
        PyErr_SetString(PyExc_ValueError,
379
                "Cannot set flags on array scalars.");
380 0
        return -1;
381
    }
382 0
    res = PyObject_CallMethod(self->arr, "setflags", "OOO", Py_None,
383 0
                              (PyObject_IsTrue(obj) ? Py_True : Py_False),
384
                              Py_None);
385 0
    if (res == NULL) {
386
        return -1;
387
    }
388 0
    Py_DECREF(res);
389
    return 0;
390
}
391

392
static int
393 1
arrayflags_writeable_set(PyArrayFlagsObject *self, PyObject *obj)
394
{
395
    PyObject *res;
396

397 1
    if (obj == NULL) {
398 1
        PyErr_SetString(PyExc_AttributeError,
399
                "Cannot delete flags writeable attribute");
400 1
        return -1;
401
    }
402 1
    if (self->arr == NULL) {
403 0
        PyErr_SetString(PyExc_ValueError,
404
                "Cannot set flags on array scalars.");
405 0
        return -1;
406
    }
407 1
    res = PyObject_CallMethod(self->arr, "setflags", "OOO",
408 1
                              (PyObject_IsTrue(obj) ? Py_True : Py_False),
409
                              Py_None, Py_None);
410 1
    if (res == NULL) {
411
        return -1;
412
    }
413 1
    Py_DECREF(res);
414
    return 0;
415
}
416

417
static int
418 1
arrayflags_warn_on_write_set(PyArrayFlagsObject *self, PyObject *obj)
419
{
420
    /*
421
     * This code should go away in a future release, so do not mangle the
422
     * array_setflags function with an extra kwarg
423
     */
424
    int ret;
425 1
    if (obj == NULL) {
426 0
        PyErr_SetString(PyExc_AttributeError,
427
                "Cannot delete flags _warn_on_write attribute");
428 0
        return -1;
429
    }
430 1
    ret = PyObject_IsTrue(obj);
431 1
    if (ret > 0) {
432 1
        if (!(PyArray_FLAGS((PyArrayObject*)self->arr) & NPY_ARRAY_WRITEABLE)) {
433 0
            PyErr_SetString(PyExc_ValueError,
434
                        "cannot set '_warn_on_write' flag when 'writable' is "
435
                        "False");
436 0
            return -1;
437
        }
438 1
        PyArray_ENABLEFLAGS((PyArrayObject*)self->arr, NPY_ARRAY_WARN_ON_WRITE);
439
    }
440 0
    else if (ret < 0) {
441
        return -1;
442
    }
443
    else {
444 0
        PyErr_SetString(PyExc_ValueError,
445
                        "cannot clear '_warn_on_write', set "
446
                        "writeable True to clear this private flag");
447 0
        return -1;
448
    }
449 1
    return 0;
450
}
451

452
static PyGetSetDef arrayflags_getsets[] = {
453
    {"contiguous",
454
        (getter)arrayflags_contiguous_get,
455
        NULL,
456
        NULL, NULL},
457
    {"c_contiguous",
458
        (getter)arrayflags_contiguous_get,
459
        NULL,
460
        NULL, NULL},
461
    {"f_contiguous",
462
        (getter)arrayflags_fortran_get,
463
        NULL,
464
        NULL, NULL},
465
    {"fortran",
466
        (getter)arrayflags_fortran_get,
467
        NULL,
468
        NULL, NULL},
469
    {"updateifcopy",
470
        (getter)arrayflags_updateifcopy_get,
471
        (setter)arrayflags_updateifcopy_set,
472
        NULL, NULL},
473
    {"writebackifcopy",
474
        (getter)arrayflags_writebackifcopy_get,
475
        (setter)arrayflags_writebackifcopy_set,
476
        NULL, NULL},
477
    {"owndata",
478
        (getter)arrayflags_owndata_get,
479
        NULL,
480
        NULL, NULL},
481
    {"aligned",
482
        (getter)arrayflags_aligned_get,
483
        (setter)arrayflags_aligned_set,
484
        NULL, NULL},
485
    {"writeable",
486
        (getter)arrayflags_writeable_get,
487
        (setter)arrayflags_writeable_set,
488
        NULL, NULL},
489
    {"_writeable_no_warn",
490
        (getter)arrayflags_writeable_no_warn_get,
491
        (setter)NULL,
492
        NULL, NULL},
493
    {"_warn_on_write",
494
        (getter)NULL,
495
        (setter)arrayflags_warn_on_write_set,
496
        NULL, NULL},
497
    {"fnc",
498
        (getter)arrayflags_fnc_get,
499
        NULL,
500
        NULL, NULL},
501
    {"forc",
502
        (getter)arrayflags_forc_get,
503
        NULL,
504
        NULL, NULL},
505
    {"behaved",
506
        (getter)arrayflags_behaved_get,
507
        NULL,
508
        NULL, NULL},
509
    {"carray",
510
        (getter)arrayflags_carray_get,
511
        NULL,
512
        NULL, NULL},
513
    {"farray",
514
        (getter)arrayflags_farray_get,
515
        NULL,
516
        NULL, NULL},
517
    {"num",
518
        (getter)arrayflags_num_get,
519
        NULL,
520
        NULL, NULL},
521
    {NULL, NULL, NULL, NULL, NULL},
522
};
523

524
static PyObject *
525 1
arrayflags_getitem(PyArrayFlagsObject *self, PyObject *ind)
526
{
527 1
    char *key = NULL;
528
    char buf[16];
529
    int n;
530 1
    if (PyUnicode_Check(ind)) {
531
        PyObject *tmp_str;
532 1
        tmp_str = PyUnicode_AsASCIIString(ind);
533 1
        if (tmp_str == NULL) {
534
            return NULL;
535
        }
536 1
        key = PyBytes_AS_STRING(tmp_str);
537 1
        n = PyBytes_GET_SIZE(tmp_str);
538 1
        if (n > 16) {
539 0
            Py_DECREF(tmp_str);
540
            goto fail;
541
        }
542 1
        memcpy(buf, key, n);
543 1
        Py_DECREF(tmp_str);
544
        key = buf;
545
    }
546 0
    else if (PyBytes_Check(ind)) {
547 0
        key = PyBytes_AS_STRING(ind);
548 0
        n = PyBytes_GET_SIZE(ind);
549
    }
550
    else {
551
        goto fail;
552
    }
553 1
    switch(n) {
554 1
    case 1:
555 1
        switch(key[0]) {
556 1
        case 'C':
557 1
            return arrayflags_contiguous_get(self);
558 1
        case 'F':
559 1
            return arrayflags_fortran_get(self);
560 1
        case 'W':
561 1
            return arrayflags_writeable_get(self);
562 0
        case 'B':
563 0
            return arrayflags_behaved_get(self);
564 1
        case 'O':
565 1
            return arrayflags_owndata_get(self);
566 1
        case 'A':
567 1
            return arrayflags_aligned_get(self);
568 1
        case 'X':
569 1
            return arrayflags_writebackifcopy_get(self);
570 1
        case 'U':
571 1
            return arrayflags_updateifcopy_get(self);
572
        default:
573
            goto fail;
574
        }
575
        break;
576 0
    case 2:
577 0
        if (strncmp(key, "CA", n) == 0) {
578 0
            return arrayflags_carray_get(self);
579
        }
580 0
        if (strncmp(key, "FA", n) == 0) {
581 0
            return arrayflags_farray_get(self);
582
        }
583
        break;
584 0
    case 3:
585 0
        if (strncmp(key, "FNC", n) == 0) {
586 0
            return arrayflags_fnc_get(self);
587
        }
588
        break;
589 0
    case 4:
590 0
        if (strncmp(key, "FORC", n) == 0) {
591 0
            return arrayflags_forc_get(self);
592
        }
593
        break;
594 0
    case 6:
595 0
        if (strncmp(key, "CARRAY", n) == 0) {
596 0
            return arrayflags_carray_get(self);
597
        }
598 0
        if (strncmp(key, "FARRAY", n) == 0) {
599 0
            return arrayflags_farray_get(self);
600
        }
601
        break;
602 1
    case 7:
603 1
        if (strncmp(key,"FORTRAN",n) == 0) {
604 1
            return arrayflags_fortran_get(self);
605
        }
606 1
        if (strncmp(key,"BEHAVED",n) == 0) {
607 0
            return arrayflags_behaved_get(self);
608
        }
609 1
        if (strncmp(key,"OWNDATA",n) == 0) {
610 1
            return arrayflags_owndata_get(self);
611
        }
612 1
        if (strncmp(key,"ALIGNED",n) == 0) {
613 1
            return arrayflags_aligned_get(self);
614
        }
615
        break;
616 1
    case 9:
617 1
        if (strncmp(key,"WRITEABLE",n) == 0) {
618 1
            return arrayflags_writeable_get(self);
619
        }
620
        break;
621 1
    case 10:
622 1
        if (strncmp(key,"CONTIGUOUS",n) == 0) {
623 1
            return arrayflags_contiguous_get(self);
624
        }
625
        break;
626 1
    case 12:
627 1
        if (strncmp(key, "UPDATEIFCOPY", n) == 0) {
628 1
            return arrayflags_updateifcopy_get(self);
629
        }
630 1
        if (strncmp(key, "C_CONTIGUOUS", n) == 0) {
631 1
            return arrayflags_contiguous_get(self);
632
        }
633 1
        if (strncmp(key, "F_CONTIGUOUS", n) == 0) {
634 1
            return arrayflags_fortran_get(self);
635
        }
636
        break;
637 1
    case 15:
638 1
        if (strncmp(key, "WRITEBACKIFCOPY", n) == 0) {
639 1
            return arrayflags_writebackifcopy_get(self);
640
        }
641
        break;
642
    }
643

644 0
 fail:
645 0
    PyErr_SetString(PyExc_KeyError, "Unknown flag");
646 0
    return NULL;
647
}
648

649
static int
650 1
arrayflags_setitem(PyArrayFlagsObject *self, PyObject *ind, PyObject *item)
651
{
652
    char *key;
653
    char buf[16];
654
    int n;
655 1
    if (PyUnicode_Check(ind)) {
656
        PyObject *tmp_str;
657 1
        tmp_str = PyUnicode_AsASCIIString(ind);
658 1
        key = PyBytes_AS_STRING(tmp_str);
659 1
        n = PyBytes_GET_SIZE(tmp_str);
660 1
        if (n > 16) n = 16;
661 1
        memcpy(buf, key, n);
662 1
        Py_DECREF(tmp_str);
663
        key = buf;
664
    }
665 0
    else if (PyBytes_Check(ind)) {
666 0
        key = PyBytes_AS_STRING(ind);
667 0
        n = PyBytes_GET_SIZE(ind);
668
    }
669
    else {
670
        goto fail;
671
    }
672 1
    if (((n==9) && (strncmp(key, "WRITEABLE", n) == 0)) ||
673 0
        ((n==1) && (strncmp(key, "W", n) == 0))) {
674 1
        return arrayflags_writeable_set(self, item);
675
    }
676 0
    else if (((n==7) && (strncmp(key, "ALIGNED", n) == 0)) ||
677 0
             ((n==1) && (strncmp(key, "A", n) == 0))) {
678 0
        return arrayflags_aligned_set(self, item);
679
    }
680 0
    else if (((n==12) && (strncmp(key, "UPDATEIFCOPY", n) == 0)) ||
681 0
             ((n==1) && (strncmp(key, "U", n) == 0))) {
682 0
        return arrayflags_updateifcopy_set(self, item);
683
    }
684 0
    else if (((n==15) && (strncmp(key, "WRITEBACKIFCOPY", n) == 0)) ||
685 0
             ((n==1) && (strncmp(key, "X", n) == 0))) {
686 0
        return arrayflags_writebackifcopy_set(self, item);
687
    }
688

689 0
 fail:
690 0
    PyErr_SetString(PyExc_KeyError, "Unknown flag");
691 0
    return -1;
692
}
693

694
static char *
695
_torf_(int flags, int val)
696
{
697 1
    if ((flags & val) == val) {
698
        return "True";
699
    }
700
    else {
701
        return "False";
702
    }
703
}
704

705
static PyObject *
706 1
arrayflags_print(PyArrayFlagsObject *self)
707
{
708 1
    int fl = self->flags;
709 1
    const char *_warn_on_write = "";
710

711 1
    if (fl & NPY_ARRAY_WARN_ON_WRITE) {
712 0
        _warn_on_write = "  (with WARN_ON_WRITE=True)";
713
    }
714 1
    return PyUnicode_FromFormat(
715
                        "  %s : %s\n  %s : %s\n"
716
                        "  %s : %s\n  %s : %s%s\n"
717
                        "  %s : %s\n  %s : %s\n"
718
                        "  %s : %s\n",
719
                        "C_CONTIGUOUS",    _torf_(fl, NPY_ARRAY_C_CONTIGUOUS),
720
                        "F_CONTIGUOUS",    _torf_(fl, NPY_ARRAY_F_CONTIGUOUS),
721
                        "OWNDATA",         _torf_(fl, NPY_ARRAY_OWNDATA),
722
                        "WRITEABLE",       _torf_(fl, NPY_ARRAY_WRITEABLE),
723
                        _warn_on_write,
724
                        "ALIGNED",         _torf_(fl, NPY_ARRAY_ALIGNED),
725
                        "WRITEBACKIFCOPY", _torf_(fl, NPY_ARRAY_WRITEBACKIFCOPY),
726
                        "UPDATEIFCOPY",    _torf_(fl, NPY_ARRAY_UPDATEIFCOPY)
727
    );
728
}
729

730
static PyObject*
731 1
arrayflags_richcompare(PyObject *self, PyObject *other, int cmp_op)
732
{
733 1
    if (!PyObject_TypeCheck(other, &PyArrayFlags_Type)) {
734 0
        Py_RETURN_NOTIMPLEMENTED;
735
    }
736

737 1
    npy_bool eq = ((PyArrayFlagsObject*) self)->flags ==
738 1
                   ((PyArrayFlagsObject*) other)->flags;
739

740 1
    if (cmp_op == Py_EQ) {
741 1
        return PyBool_FromLong(eq);
742
    }
743 0
    else if (cmp_op == Py_NE) {
744 0
        return PyBool_FromLong(!eq);
745
    }
746
    else {
747 0
        Py_RETURN_NOTIMPLEMENTED;
748
    }
749
}
750

751
static PyMappingMethods arrayflags_as_mapping = {
752
    (lenfunc)NULL,                       /*mp_length*/
753
    (binaryfunc)arrayflags_getitem,      /*mp_subscript*/
754
    (objobjargproc)arrayflags_setitem,   /*mp_ass_subscript*/
755
};
756

757

758
static PyObject *
759 0
arrayflags_new(PyTypeObject *NPY_UNUSED(self), PyObject *args, PyObject *NPY_UNUSED(kwds))
760
{
761 0
    PyObject *arg=NULL;
762 0
    if (!PyArg_UnpackTuple(args, "flagsobj", 0, 1, &arg)) {
763
        return NULL;
764
    }
765 0
    if ((arg != NULL) && PyArray_Check(arg)) {
766 0
        return PyArray_NewFlagsObject(arg);
767
    }
768
    else {
769 0
        return PyArray_NewFlagsObject(NULL);
770
    }
771
}
772

773
NPY_NO_EXPORT PyTypeObject PyArrayFlags_Type = {
774
    PyVarObject_HEAD_INIT(NULL, 0)
775
    .tp_name = "numpy.flagsobj",
776
    .tp_basicsize = sizeof(PyArrayFlagsObject),
777
    .tp_dealloc = (destructor)arrayflags_dealloc,
778
    .tp_repr = (reprfunc)arrayflags_print,
779
    .tp_as_mapping = &arrayflags_as_mapping,
780
    .tp_str = (reprfunc)arrayflags_print,
781
    .tp_flags =Py_TPFLAGS_DEFAULT,
782
    .tp_richcompare = arrayflags_richcompare,
783
    .tp_getset = arrayflags_getsets,
784
    .tp_new = arrayflags_new,
785
};

Read our documentation on viewing source code .

Loading