1
/* Array Descr 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

11
#include "npy_config.h"
12
#include "npy_pycompat.h"
13
#include "npy_import.h"
14

15
#include "common.h"
16
#include "conversion_utils.h"
17
#include "ctors.h"
18
#include "scalartypes.h"
19
#include "descriptor.h"
20
#include "getset.h"
21
#include "arrayobject.h"
22
#include "mem_overlap.h"
23
#include "alloc.h"
24
#include "npy_buffer.h"
25

26
/*******************  array attribute get and set routines ******************/
27

28
static PyObject *
29 1
array_ndim_get(PyArrayObject *self)
30
{
31 1
    return PyLong_FromLong(PyArray_NDIM(self));
32
}
33

34
static PyObject *
35 1
array_flags_get(PyArrayObject *self)
36
{
37 1
    return PyArray_NewFlagsObject((PyObject *)self);
38
}
39

40
static PyObject *
41 1
array_shape_get(PyArrayObject *self)
42
{
43 1
    return PyArray_IntTupleFromIntp(PyArray_NDIM(self), PyArray_DIMS(self));
44
}
45

46

47
static int
48 1
array_shape_set(PyArrayObject *self, PyObject *val)
49
{
50
    int nd;
51
    PyArrayObject *ret;
52

53 1
    if (val == NULL) {
54 1
        PyErr_SetString(PyExc_AttributeError,
55
                "Cannot delete array shape");
56 1
        return -1;
57
    }
58
    /* Assumes C-order */
59 1
    ret = (PyArrayObject *)PyArray_Reshape(self, val);
60 1
    if (ret == NULL) {
61
        return -1;
62
    }
63 1
    if (PyArray_DATA(ret) != PyArray_DATA(self)) {
64 1
        Py_DECREF(ret);
65 1
        PyErr_SetString(PyExc_AttributeError,
66
                        "Incompatible shape for in-place modification. Use "
67
                        "`.reshape()` to make a copy with the desired shape.");
68 1
        return -1;
69
    }
70

71 1
    nd = PyArray_NDIM(ret);
72 1
    if (nd > 0) {
73
        /* create new dimensions and strides */
74 1
        npy_intp *_dimensions = npy_alloc_cache_dim(2 * nd);
75 1
        if (_dimensions == NULL) {
76 0
            Py_DECREF(ret);
77 0
            PyErr_NoMemory();
78 0
            return -1;
79
        }
80
        /* Free old dimensions and strides */
81 1
        npy_free_cache_dim_array(self);
82 1
        ((PyArrayObject_fields *)self)->nd = nd;
83 1
        ((PyArrayObject_fields *)self)->dimensions = _dimensions; 
84 1
        ((PyArrayObject_fields *)self)->strides = _dimensions + nd;
85

86
        if (nd) {
87 1
            memcpy(PyArray_DIMS(self), PyArray_DIMS(ret), nd*sizeof(npy_intp));
88 1
            memcpy(PyArray_STRIDES(self), PyArray_STRIDES(ret), nd*sizeof(npy_intp));
89
        }
90
    }
91
    else {
92
        /* Free old dimensions and strides */
93 1
        npy_free_cache_dim_array(self);        
94 1
        ((PyArrayObject_fields *)self)->nd = 0;
95 1
        ((PyArrayObject_fields *)self)->dimensions = NULL;
96 1
        ((PyArrayObject_fields *)self)->strides = NULL;
97
    }
98

99 1
    Py_DECREF(ret);
100 1
    PyArray_UpdateFlags(self, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS);
101 1
    return 0;
102
}
103

104

105
static PyObject *
106 1
array_strides_get(PyArrayObject *self)
107
{
108 1
    return PyArray_IntTupleFromIntp(PyArray_NDIM(self), PyArray_STRIDES(self));
109
}
110

111
static int
112 1
array_strides_set(PyArrayObject *self, PyObject *obj)
113
{
114 1
    PyArray_Dims newstrides = {NULL, -1};
115
    PyArrayObject *new;
116 1
    npy_intp numbytes = 0;
117 1
    npy_intp offset = 0;
118 1
    npy_intp lower_offset = 0;
119 1
    npy_intp upper_offset = 0;
120
    Py_buffer view;
121

122 1
    if (obj == NULL) {
123 1
        PyErr_SetString(PyExc_AttributeError,
124
                "Cannot delete array strides");
125 1
        return -1;
126
    }
127 1
    if (!PyArray_OptionalIntpConverter(obj, &newstrides) ||
128 1
        newstrides.len == -1) {
129 1
        PyErr_SetString(PyExc_TypeError, "invalid strides");
130 1
        return -1;
131
    }
132 1
    if (newstrides.len != PyArray_NDIM(self)) {
133 0
        PyErr_Format(PyExc_ValueError, "strides must be "       \
134
                     " same length as shape (%d)", PyArray_NDIM(self));
135 0
        goto fail;
136
    }
137
    new = self;
138 1
    while(PyArray_BASE(new) && PyArray_Check(PyArray_BASE(new))) {
139 1
        new = (PyArrayObject *)(PyArray_BASE(new));
140
    }
141
    /*
142
     * Get the available memory through the buffer interface on
143
     * PyArray_BASE(new) or if that fails from the current new
144
     */
145 1
    if (PyArray_BASE(new) &&
146 1
            PyObject_GetBuffer(PyArray_BASE(new), &view, PyBUF_SIMPLE) >= 0) {
147 0
        offset = PyArray_BYTES(self) - (char *)view.buf;
148 0
        numbytes = view.len + offset;
149 0
        PyBuffer_Release(&view);
150
    }
151
    else {
152 1
        PyErr_Clear();
153 1
        offset_bounds_from_strides(PyArray_ITEMSIZE(new), PyArray_NDIM(new),
154 1
                                   PyArray_DIMS(new), PyArray_STRIDES(new),
155
                                   &lower_offset, &upper_offset);
156

157 1
        offset = PyArray_BYTES(self) - (PyArray_BYTES(new) + lower_offset);
158 1
        numbytes = upper_offset - lower_offset;
159
    }
160

161
    /* numbytes == 0 is special here, but the 0-size array case always works */
162 1
    if (!PyArray_CheckStrides(PyArray_ITEMSIZE(self), PyArray_NDIM(self),
163
                              numbytes, offset,
164 1
                              PyArray_DIMS(self), newstrides.ptr)) {
165 1
        PyErr_SetString(PyExc_ValueError, "strides is not "\
166
                        "compatible with available memory");
167 1
        goto fail;
168
    }
169 1
    if (newstrides.len) {
170 1
        memcpy(PyArray_STRIDES(self), newstrides.ptr, sizeof(npy_intp)*newstrides.len);
171
    }
172 1
    PyArray_UpdateFlags(self, NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS |
173
                              NPY_ARRAY_ALIGNED);
174 1
    npy_free_cache_dim_obj(newstrides);
175 1
    return 0;
176

177 1
 fail:
178 1
    npy_free_cache_dim_obj(newstrides);
179 1
    return -1;
180
}
181

182

183

184
static PyObject *
185 1
array_priority_get(PyArrayObject *NPY_UNUSED(self))
186
{
187 1
    return PyFloat_FromDouble(NPY_PRIORITY);
188
}
189

190
static PyObject *
191
array_typestr_get(PyArrayObject *self)
192
{
193 1
    return arraydescr_protocol_typestr_get(PyArray_DESCR(self));
194
}
195

196
static PyObject *
197 1
array_descr_get(PyArrayObject *self)
198
{
199 1
    Py_INCREF(PyArray_DESCR(self));
200 1
    return (PyObject *)PyArray_DESCR(self);
201
}
202

203
static PyObject *
204 1
array_protocol_descr_get(PyArrayObject *self)
205
{
206
    PyObject *res;
207
    PyObject *dobj;
208

209 1
    res = arraydescr_protocol_descr_get(PyArray_DESCR(self));
210 1
    if (res) {
211
        return res;
212
    }
213 1
    PyErr_Clear();
214

215
    /* get default */
216 1
    dobj = PyTuple_New(2);
217 1
    if (dobj == NULL) {
218
        return NULL;
219
    }
220 1
    PyTuple_SET_ITEM(dobj, 0, PyUnicode_FromString(""));
221 1
    PyTuple_SET_ITEM(dobj, 1, array_typestr_get(self));
222 1
    res = PyList_New(1);
223 1
    if (res == NULL) {
224 0
        Py_DECREF(dobj);
225
        return NULL;
226
    }
227 1
    PyList_SET_ITEM(res, 0, dobj);
228 1
    return res;
229
}
230

231
static PyObject *
232 1
array_protocol_strides_get(PyArrayObject *self)
233
{
234 1
    if (PyArray_ISCONTIGUOUS(self)) {
235 1
        Py_RETURN_NONE;
236
    }
237 1
    return PyArray_IntTupleFromIntp(PyArray_NDIM(self), PyArray_STRIDES(self));
238
}
239

240

241

242
static PyObject *
243 1
array_dataptr_get(PyArrayObject *self)
244
{
245 1
    return Py_BuildValue("NO",
246
                         PyLong_FromVoidPtr(PyArray_DATA(self)),
247 1
                         ((PyArray_FLAGS(self) & NPY_ARRAY_WRITEABLE) &&
248 1
                          !(PyArray_FLAGS(self) & NPY_ARRAY_WARN_ON_WRITE)) ?
249
                         Py_False : Py_True);
250
}
251

252
static PyObject *
253 1
array_ctypes_get(PyArrayObject *self)
254
{
255
    PyObject *_numpy_internal;
256
    PyObject *ret;
257 1
    _numpy_internal = PyImport_ImportModule("numpy.core._internal");
258 1
    if (_numpy_internal == NULL) {
259
        return NULL;
260
    }
261 1
    ret = PyObject_CallMethod(_numpy_internal, "_ctypes", "ON", self,
262
                              PyLong_FromVoidPtr(PyArray_DATA(self)));
263 1
    Py_DECREF(_numpy_internal);
264
    return ret;
265
}
266

267
static PyObject *
268 1
array_interface_get(PyArrayObject *self)
269
{
270
    PyObject *dict;
271
    PyObject *obj;
272

273 1
    dict = PyDict_New();
274 1
    if (dict == NULL) {
275
        return NULL;
276
    }
277

278
    int ret;
279

280
    /* dataptr */
281 1
    obj = array_dataptr_get(self);
282 1
    ret = PyDict_SetItemString(dict, "data", obj);
283 1
    Py_DECREF(obj);
284 1
    if (ret < 0) {
285 0
        Py_DECREF(dict);
286
        return NULL;
287
    }
288

289 1
    obj = array_protocol_strides_get(self);
290 1
    ret = PyDict_SetItemString(dict, "strides", obj);
291 1
    Py_DECREF(obj);
292 1
    if (ret < 0) {
293 0
        Py_DECREF(dict);
294
        return NULL;
295
    }
296

297 1
    obj = array_protocol_descr_get(self);
298 1
    ret = PyDict_SetItemString(dict, "descr", obj);
299 1
    Py_DECREF(obj);
300 1
    if (ret < 0) {
301 0
        Py_DECREF(dict);
302
        return NULL;
303
    }
304

305 1
    obj = arraydescr_protocol_typestr_get(PyArray_DESCR(self));
306 1
    ret = PyDict_SetItemString(dict, "typestr", obj);
307 1
    Py_DECREF(obj);
308 1
    if (ret < 0) {
309 0
        Py_DECREF(dict);
310
        return NULL;
311
    }
312

313 1
    obj = array_shape_get(self);
314 1
    ret = PyDict_SetItemString(dict, "shape", obj);
315 1
    Py_DECREF(obj);
316 1
    if (ret < 0) {
317 0
        Py_DECREF(dict);
318
        return NULL;
319
    }
320

321 1
    obj = PyLong_FromLong(3);
322 1
    ret = PyDict_SetItemString(dict, "version", obj);
323 1
    Py_DECREF(obj);
324 1
    if (ret < 0) {
325 0
        Py_DECREF(dict);
326
        return NULL;
327
    }
328

329
    return dict;
330
}
331

332
static PyObject *
333 1
array_data_get(PyArrayObject *self)
334
{
335 1
    return PyMemoryView_FromObject((PyObject *)self);
336
}
337

338
static int
339 1
array_data_set(PyArrayObject *self, PyObject *op)
340
{
341
    void *buf;
342
    Py_ssize_t buf_len;
343 1
    int writeable=1;
344
    Py_buffer view;
345

346
    /* 2016-19-02, 1.12 */
347 1
    int ret = DEPRECATE("Assigning the 'data' attribute is an "
348
                        "inherently unsafe operation and will "
349
                        "be removed in the future.");
350 1
    if (ret < 0) {
351
        return -1;
352
    }
353

354 1
    if (op == NULL) {
355 1
        PyErr_SetString(PyExc_AttributeError,
356
                "Cannot delete array data");
357 1
        return -1;
358
    }
359 1
    if (PyObject_GetBuffer(op, &view, PyBUF_WRITABLE|PyBUF_SIMPLE) < 0) {
360 0
        writeable = 0;
361 0
        PyErr_Clear();
362 0
        if (PyObject_GetBuffer(op, &view, PyBUF_SIMPLE) < 0) {
363
            return -1;
364
        }
365
    }
366 1
    buf = view.buf;
367 1
    buf_len = view.len;
368
    /*
369
     * In Python 3 both of the deprecated functions PyObject_AsWriteBuffer and
370
     * PyObject_AsReadBuffer that this code replaces release the buffer. It is
371
     * up to the object that supplies the buffer to guarantee that the buffer
372
     * sticks around after the release.
373
     */
374 1
    PyBuffer_Release(&view);
375

376 1
    if (!PyArray_ISONESEGMENT(self)) {
377 0
        PyErr_SetString(PyExc_AttributeError,
378
                "cannot set single-segment buffer for discontiguous array");
379 0
        return -1;
380
    }
381 1
    if (PyArray_NBYTES(self) > buf_len) {
382 0
        PyErr_SetString(PyExc_AttributeError, "not enough data for array");
383 0
        return -1;
384
    }
385 1
    if (PyArray_FLAGS(self) & NPY_ARRAY_OWNDATA) {
386 1
        PyArray_XDECREF(self);
387 1
        PyDataMem_FREE(PyArray_DATA(self));
388
    }
389 1
    if (PyArray_BASE(self)) {
390 0
        if ((PyArray_FLAGS(self) & NPY_ARRAY_WRITEBACKIFCOPY) ||
391 0
            (PyArray_FLAGS(self) & NPY_ARRAY_UPDATEIFCOPY)) {
392 0
            PyArray_ENABLEFLAGS((PyArrayObject *)PyArray_BASE(self),
393
                                                NPY_ARRAY_WRITEABLE);
394 0
            PyArray_CLEARFLAGS(self, NPY_ARRAY_WRITEBACKIFCOPY);
395
            PyArray_CLEARFLAGS(self, NPY_ARRAY_UPDATEIFCOPY);
396
        }
397 0
        Py_DECREF(PyArray_BASE(self));
398 0
        ((PyArrayObject_fields *)self)->base = NULL;
399
    }
400 1
    Py_INCREF(op);
401 1
    if (PyArray_SetBaseObject(self, op) < 0) {
402
        return -1;
403
    }
404 1
    ((PyArrayObject_fields *)self)->data = buf;
405 1
    ((PyArrayObject_fields *)self)->flags = NPY_ARRAY_CARRAY;
406 1
    if (!writeable) {
407
        PyArray_CLEARFLAGS(self, ~NPY_ARRAY_WRITEABLE);
408
    }
409
    return 0;
410
}
411

412

413
static PyObject *
414 1
array_itemsize_get(PyArrayObject *self)
415
{
416 1
    return PyLong_FromLong((long) PyArray_DESCR(self)->elsize);
417
}
418

419
static PyObject *
420 1
array_size_get(PyArrayObject *self)
421
{
422 1
    npy_intp size=PyArray_SIZE(self);
423
#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG
424 1
    return PyLong_FromLong((long) size);
425
#else
426
    if (size > NPY_MAX_LONG || size < NPY_MIN_LONG) {
427
        return PyLong_FromLongLong(size);
428
    }
429
    else {
430
        return PyLong_FromLong((long) size);
431
    }
432
#endif
433
}
434

435
static PyObject *
436 1
array_nbytes_get(PyArrayObject *self)
437
{
438 1
    npy_intp nbytes = PyArray_NBYTES(self);
439
#if NPY_SIZEOF_INTP <= NPY_SIZEOF_LONG
440 1
    return PyLong_FromLong((long) nbytes);
441
#else
442
    if (nbytes > NPY_MAX_LONG || nbytes < NPY_MIN_LONG) {
443
        return PyLong_FromLongLong(nbytes);
444
    }
445
    else {
446
        return PyLong_FromLong((long) nbytes);
447
    }
448
#endif
449
}
450

451

452
/*
453
 * If the type is changed.
454
 * Also needing change: strides, itemsize
455
 *
456
 * Either itemsize is exactly the same or the array is single-segment
457
 * (contiguous or fortran) with compatible dimensions The shape and strides
458
 * will be adjusted in that case as well.
459
 */
460
static int
461 1
array_descr_set(PyArrayObject *self, PyObject *arg)
462
{
463 1
    PyArray_Descr *newtype = NULL;
464

465 1
    if (arg == NULL) {
466 1
        PyErr_SetString(PyExc_AttributeError,
467
                "Cannot delete array dtype");
468 1
        return -1;
469
    }
470

471 1
    if (!(PyArray_DescrConverter(arg, &newtype)) ||
472 1
        newtype == NULL) {
473 0
        PyErr_SetString(PyExc_TypeError,
474
                "invalid data-type for array");
475 0
        return -1;
476
    }
477

478
    /* check that we are not reinterpreting memory containing Objects. */
479 1
    if (_may_have_objects(PyArray_DESCR(self)) || _may_have_objects(newtype)) {
480
        static PyObject *checkfunc = NULL;
481
        PyObject *safe;
482

483 1
        npy_cache_import("numpy.core._internal", "_view_is_safe", &checkfunc);
484 1
        if (checkfunc == NULL) {
485
            goto fail;
486
        }
487

488 1
        safe = PyObject_CallFunction(checkfunc, "OO",
489
                                     PyArray_DESCR(self), newtype);
490 1
        if (safe == NULL) {
491
            goto fail;
492
        }
493 1
        Py_DECREF(safe);
494
    }
495

496
    /*
497
     * Viewing as an unsized void implies a void dtype matching the size of the
498
     * current dtype.
499
     */
500 1
    if (newtype->type_num == NPY_VOID &&
501 1
            PyDataType_ISUNSIZED(newtype) &&
502 1
            newtype->elsize != PyArray_DESCR(self)->elsize) {
503 0
        PyArray_DESCR_REPLACE(newtype);
504 0
        if (newtype == NULL) {
505
            return -1;
506
        }
507 0
        newtype->elsize = PyArray_DESCR(self)->elsize;
508
    }
509

510
    /* Changing the size of the dtype results in a shape change */
511 1
    if (newtype->elsize != PyArray_DESCR(self)->elsize) {
512
        int axis;
513
        npy_intp newdim;
514

515
        /* forbidden cases */
516 1
        if (PyArray_NDIM(self) == 0) {
517 0
            PyErr_SetString(PyExc_ValueError,
518
                    "Changing the dtype of a 0d array is only supported "
519
                    "if the itemsize is unchanged");
520 0
            goto fail;
521
        }
522 1
        else if (PyDataType_HASSUBARRAY(newtype)) {
523 0
            PyErr_SetString(PyExc_ValueError,
524
                    "Changing the dtype to a subarray type is only supported "
525
                    "if the total itemsize is unchanged");
526 0
            goto fail;
527
        }
528

529
        /* determine which axis to resize */
530 1
        if (PyArray_IS_C_CONTIGUOUS(self)) {
531 1
            axis = PyArray_NDIM(self) - 1;
532
        }
533 1
        else if (PyArray_IS_F_CONTIGUOUS(self)) {
534
            /* 2015-11-27 1.11.0, gh-6747 */
535 1
            if (DEPRECATE(
536
                        "Changing the shape of an F-contiguous array by "
537
                        "descriptor assignment is deprecated. To maintain the "
538
                        "Fortran contiguity of a multidimensional Fortran "
539
                        "array, use 'a.T.view(...).T' instead") < 0) {
540
                goto fail;
541
            }
542
            axis = 0;
543
        }
544
        else {
545
            /* Don't mention the deprecated F-contiguous support */
546 0
            PyErr_SetString(PyExc_ValueError,
547
                    "To change to a dtype of a different size, the array must "
548
                    "be C-contiguous");
549 0
            goto fail;
550
        }
551

552 1
        if (newtype->elsize < PyArray_DESCR(self)->elsize) {
553
            /* if it is compatible, increase the size of the relevant axis */
554 1
            if (newtype->elsize == 0 ||
555 1
                    PyArray_DESCR(self)->elsize % newtype->elsize != 0) {
556 1
                PyErr_SetString(PyExc_ValueError,
557
                        "When changing to a smaller dtype, its size must be a "
558
                        "divisor of the size of original dtype");
559 1
                goto fail;
560
            }
561 1
            newdim = PyArray_DESCR(self)->elsize / newtype->elsize;
562 1
            PyArray_DIMS(self)[axis] *= newdim;
563 1
            PyArray_STRIDES(self)[axis] = newtype->elsize;
564
        }
565 1
        else if (newtype->elsize > PyArray_DESCR(self)->elsize) {
566
            /* if it is compatible, decrease the size of the relevant axis */
567 1
            newdim = PyArray_DIMS(self)[axis] * PyArray_DESCR(self)->elsize;
568 1
            if ((newdim % newtype->elsize) != 0) {
569 0
                PyErr_SetString(PyExc_ValueError,
570
                        "When changing to a larger dtype, its size must be a "
571
                        "divisor of the total size in bytes of the last axis "
572
                        "of the array.");
573 0
                goto fail;
574
            }
575 1
            PyArray_DIMS(self)[axis] = newdim / newtype->elsize;
576 1
            PyArray_STRIDES(self)[axis] = newtype->elsize;
577
        }
578
    }
579

580
    /* Viewing as a subarray increases the number of dimensions */
581 1
    if (PyDataType_HASSUBARRAY(newtype)) {
582
        /*
583
         * create new array object from data and update
584
         * dimensions, strides and descr from it
585
         */
586
        PyArrayObject *temp;
587
        /*
588
         * We would decref newtype here.
589
         * temp will steal a reference to it
590
         */
591 1
        temp = (PyArrayObject *)
592 1
            PyArray_NewFromDescr(&PyArray_Type, newtype, PyArray_NDIM(self),
593 1
                                 PyArray_DIMS(self), PyArray_STRIDES(self),
594
                                 PyArray_DATA(self), PyArray_FLAGS(self), NULL);
595 1
        if (temp == NULL) {
596
            return -1;
597
        }
598 1
        npy_free_cache_dim_array(self);
599 1
        ((PyArrayObject_fields *)self)->dimensions = PyArray_DIMS(temp);
600 1
        ((PyArrayObject_fields *)self)->nd = PyArray_NDIM(temp);
601 1
        ((PyArrayObject_fields *)self)->strides = PyArray_STRIDES(temp);
602 1
        newtype = PyArray_DESCR(temp);
603 1
        Py_INCREF(PyArray_DESCR(temp));
604
        /* Fool deallocator not to delete these*/
605 1
        ((PyArrayObject_fields *)temp)->nd = 0;
606 1
        ((PyArrayObject_fields *)temp)->dimensions = NULL;
607 1
        Py_DECREF(temp);
608
    }
609

610 1
    Py_DECREF(PyArray_DESCR(self));
611 1
    ((PyArrayObject_fields *)self)->descr = newtype;
612 1
    PyArray_UpdateFlags(self, NPY_ARRAY_UPDATE_ALL);
613 1
    return 0;
614

615 1
 fail:
616 1
    Py_DECREF(newtype);
617
    return -1;
618
}
619

620
static PyObject *
621 1
array_struct_get(PyArrayObject *self)
622
{
623
    PyArrayInterface *inter;
624

625 1
    inter = (PyArrayInterface *)PyArray_malloc(sizeof(PyArrayInterface));
626 1
    if (inter==NULL) {
627 0
        return PyErr_NoMemory();
628
    }
629 1
    inter->two = 2;
630 1
    inter->nd = PyArray_NDIM(self);
631 1
    inter->typekind = PyArray_DESCR(self)->kind;
632 1
    inter->itemsize = PyArray_DESCR(self)->elsize;
633 1
    inter->flags = PyArray_FLAGS(self);
634 1
    if (inter->flags & NPY_ARRAY_WARN_ON_WRITE) {
635
        /* Export a warn-on-write array as read-only */
636 1
        inter->flags = inter->flags & ~NPY_ARRAY_WARN_ON_WRITE;
637 1
        inter->flags = inter->flags & ~NPY_ARRAY_WRITEABLE;
638
    }
639
    /* reset unused flags */
640 1
    inter->flags &= ~(NPY_ARRAY_WRITEBACKIFCOPY | NPY_ARRAY_UPDATEIFCOPY |NPY_ARRAY_OWNDATA);
641 1
    if (PyArray_ISNOTSWAPPED(self)) inter->flags |= NPY_ARRAY_NOTSWAPPED;
642
    /*
643
     * Copy shape and strides over since these can be reset
644
     *when the array is "reshaped".
645
     */
646 1
    if (PyArray_NDIM(self) > 0) {
647 1
        inter->shape = (npy_intp *)PyArray_malloc(2*sizeof(npy_intp)*PyArray_NDIM(self));
648 1
        if (inter->shape == NULL) {
649 0
            PyArray_free(inter);
650 0
            return PyErr_NoMemory();
651
        }
652 1
        inter->strides = inter->shape + PyArray_NDIM(self);
653 1
        if (PyArray_NDIM(self)) {
654 1
            memcpy(inter->shape, PyArray_DIMS(self), sizeof(npy_intp)*PyArray_NDIM(self));
655 1
            memcpy(inter->strides, PyArray_STRIDES(self), sizeof(npy_intp)*PyArray_NDIM(self));
656
        }
657
    }
658
    else {
659 1
        inter->shape = NULL;
660 1
        inter->strides = NULL;
661
    }
662 1
    inter->data = PyArray_DATA(self);
663 1
    if (PyDataType_HASFIELDS(PyArray_DESCR(self))) {
664 1
        inter->descr = arraydescr_protocol_descr_get(PyArray_DESCR(self));
665 1
        if (inter->descr == NULL) {
666 0
            PyErr_Clear();
667
        }
668
        else {
669 1
            inter->flags &= NPY_ARR_HAS_DESCR;
670
        }
671
    }
672
    else {
673 1
        inter->descr = NULL;
674
    }
675 1
    PyObject *ret = PyCapsule_New(inter, NULL, gentype_struct_free);
676 1
    if (ret == NULL) {
677
        return NULL;
678
    }
679 1
    Py_INCREF(self);
680 1
    if (PyCapsule_SetContext(ret, self) < 0) {
681
        return NULL;
682
    }
683 1
    return ret;
684
}
685

686
static PyObject *
687 1
array_base_get(PyArrayObject *self)
688
{
689 1
    if (PyArray_BASE(self) == NULL) {
690 1
        Py_RETURN_NONE;
691
    }
692
    else {
693 1
        Py_INCREF(PyArray_BASE(self));
694 1
        return PyArray_BASE(self);
695
    }
696
}
697

698
/*
699
 * Create a view of a complex array with an equivalent data-type
700
 * except it is real instead of complex.
701
 */
702
static PyArrayObject *
703 1
_get_part(PyArrayObject *self, int imag)
704
{
705
    int float_type_num;
706
    PyArray_Descr *type;
707
    PyArrayObject *ret;
708
    int offset;
709

710 1
    switch (PyArray_DESCR(self)->type_num) {
711
        case NPY_CFLOAT:
712
            float_type_num = NPY_FLOAT;
713
            break;
714 1
        case NPY_CDOUBLE:
715 1
            float_type_num = NPY_DOUBLE;
716 1
            break;
717 1
        case NPY_CLONGDOUBLE:
718 1
            float_type_num = NPY_LONGDOUBLE;
719 1
            break;
720 0
        default:
721 0
            PyErr_Format(PyExc_ValueError,
722
                     "Cannot convert complex type number %d to float",
723 0
                     PyArray_DESCR(self)->type_num);
724 0
            return NULL;
725

726
    }
727 1
    type = PyArray_DescrFromType(float_type_num);
728

729 1
    offset = (imag ? type->elsize : 0);
730

731 1
    if (!PyArray_ISNBO(PyArray_DESCR(self)->byteorder)) {
732
        PyArray_Descr *new;
733 1
        new = PyArray_DescrNew(type);
734 1
        new->byteorder = PyArray_DESCR(self)->byteorder;
735 1
        Py_DECREF(type);
736
        type = new;
737
    }
738 1
    ret = (PyArrayObject *)PyArray_NewFromDescrAndBase(
739 1
            Py_TYPE(self),
740
            type,
741
            PyArray_NDIM(self),
742 1
            PyArray_DIMS(self),
743 1
            PyArray_STRIDES(self),
744 1
            PyArray_BYTES(self) + offset,
745
            PyArray_FLAGS(self), (PyObject *)self, (PyObject *)self);
746 1
    if (ret == NULL) {
747
        return NULL;
748
    }
749 1
    return ret;
750
}
751

752
/* For Object arrays, we need to get and set the
753
   real part of each element.
754
 */
755

756
static PyObject *
757 1
array_real_get(PyArrayObject *self)
758
{
759
    PyArrayObject *ret;
760

761 1
    if (PyArray_ISCOMPLEX(self)) {
762 1
        ret = _get_part(self, 0);
763 1
        return (PyObject *)ret;
764
    }
765
    else {
766 1
        Py_INCREF(self);
767 1
        return (PyObject *)self;
768
    }
769
}
770

771

772
static int
773 1
array_real_set(PyArrayObject *self, PyObject *val)
774
{
775
    PyArrayObject *ret;
776
    PyArrayObject *new;
777
    int retcode;
778

779 1
    if (val == NULL) {
780 1
        PyErr_SetString(PyExc_AttributeError,
781
                "Cannot delete array real part");
782 1
        return -1;
783
    }
784 1
    if (PyArray_ISCOMPLEX(self)) {
785 1
        ret = _get_part(self, 0);
786 1
        if (ret == NULL) {
787
            return -1;
788
        }
789
    }
790
    else {
791 0
        Py_INCREF(self);
792 0
        ret = self;
793
    }
794 1
    new = (PyArrayObject *)PyArray_FROM_O(val);
795 1
    if (new == NULL) {
796 0
        Py_DECREF(ret);
797
        return -1;
798
    }
799 1
    retcode = PyArray_MoveInto(ret, new);
800 1
    Py_DECREF(ret);
801 1
    Py_DECREF(new);
802
    return retcode;
803
}
804

805
/* For Object arrays we need to get
806
   and set the imaginary part of
807
   each element
808
*/
809

810
static PyObject *
811 1
array_imag_get(PyArrayObject *self)
812
{
813
    PyArrayObject *ret;
814

815 1
    if (PyArray_ISCOMPLEX(self)) {
816 1
        ret = _get_part(self, 1);
817
    }
818
    else {
819 1
        Py_INCREF(PyArray_DESCR(self));
820 1
        ret = (PyArrayObject *)PyArray_NewFromDescr(Py_TYPE(self),
821
                                                    PyArray_DESCR(self),
822
                                                    PyArray_NDIM(self),
823 1
                                                    PyArray_DIMS(self),
824
                                                    NULL, NULL,
825 1
                                                    PyArray_ISFORTRAN(self),
826
                                                    (PyObject *)self);
827 1
        if (ret == NULL) {
828
            return NULL;
829
        }
830 1
        if (_zerofill(ret) < 0) {
831
            return NULL;
832
        }
833
        PyArray_CLEARFLAGS(ret, NPY_ARRAY_WRITEABLE);
834
    }
835
    return (PyObject *) ret;
836
}
837

838
static int
839 1
array_imag_set(PyArrayObject *self, PyObject *val)
840
{
841 1
    if (val == NULL) {
842 1
        PyErr_SetString(PyExc_AttributeError,
843
                "Cannot delete array imaginary part");
844 1
        return -1;
845
    }
846 1
    if (PyArray_ISCOMPLEX(self)) {
847
        PyArrayObject *ret;
848
        PyArrayObject *new;
849
        int retcode;
850

851 1
        ret = _get_part(self, 1);
852 1
        if (ret == NULL) {
853
            return -1;
854
        }
855 1
        new = (PyArrayObject *)PyArray_FROM_O(val);
856 1
        if (new == NULL) {
857 0
            Py_DECREF(ret);
858
            return -1;
859
        }
860 1
        retcode = PyArray_MoveInto(ret, new);
861 1
        Py_DECREF(ret);
862 1
        Py_DECREF(new);
863
        return retcode;
864
    }
865
    else {
866 0
        PyErr_SetString(PyExc_TypeError,
867
                "array does not have imaginary part to set");
868 0
        return -1;
869
    }
870
}
871

872
static PyObject *
873 1
array_flat_get(PyArrayObject *self)
874
{
875 1
    return PyArray_IterNew((PyObject *)self);
876
}
877

878
static int
879 1
array_flat_set(PyArrayObject *self, PyObject *val)
880
{
881 1
    PyArrayObject *arr = NULL;
882 1
    int retval = -1;
883 1
    PyArrayIterObject *selfit = NULL, *arrit = NULL;
884
    PyArray_Descr *typecode;
885
    int swap;
886
    PyArray_CopySwapFunc *copyswap;
887

888 1
    if (val == NULL) {
889 1
        PyErr_SetString(PyExc_AttributeError,
890
                "Cannot delete array flat iterator");
891 1
        return -1;
892
    }
893 1
    if (PyArray_FailUnlessWriteable(self, "array") < 0) return -1;
894 1
    typecode = PyArray_DESCR(self);
895 1
    Py_INCREF(typecode);
896 1
    arr = (PyArrayObject *)PyArray_FromAny(val, typecode,
897 1
                  0, 0, NPY_ARRAY_FORCECAST | PyArray_FORTRAN_IF(self), NULL);
898 1
    if (arr == NULL) {
899
        return -1;
900
    }
901 1
    arrit = (PyArrayIterObject *)PyArray_IterNew((PyObject *)arr);
902 1
    if (arrit == NULL) {
903
        goto exit;
904
    }
905 1
    selfit = (PyArrayIterObject *)PyArray_IterNew((PyObject *)self);
906 1
    if (selfit == NULL) {
907
        goto exit;
908
    }
909 1
    if (arrit->size == 0) {
910
        retval = 0;
911
        goto exit;
912
    }
913 1
    swap = PyArray_ISNOTSWAPPED(self) != PyArray_ISNOTSWAPPED(arr);
914 1
    copyswap = PyArray_DESCR(self)->f->copyswap;
915 1
    if (PyDataType_REFCHK(PyArray_DESCR(self))) {
916 0
        while (selfit->index < selfit->size) {
917 0
            PyArray_Item_XDECREF(selfit->dataptr, PyArray_DESCR(self));
918 0
            PyArray_Item_INCREF(arrit->dataptr, PyArray_DESCR(arr));
919 0
            memmove(selfit->dataptr, arrit->dataptr, sizeof(PyObject **));
920 0
            if (swap) {
921 0
                copyswap(selfit->dataptr, NULL, swap, self);
922
            }
923 0
            PyArray_ITER_NEXT(selfit);
924 0
            PyArray_ITER_NEXT(arrit);
925 0
            if (arrit->index == arrit->size) {
926 0
                PyArray_ITER_RESET(arrit);
927
            }
928
        }
929
        retval = 0;
930
        goto exit;
931
    }
932

933 1
    while(selfit->index < selfit->size) {
934 1
        copyswap(selfit->dataptr, arrit->dataptr, swap, self);
935 1
        PyArray_ITER_NEXT(selfit);
936 1
        PyArray_ITER_NEXT(arrit);
937 1
        if (arrit->index == arrit->size) {
938 1
            PyArray_ITER_RESET(arrit);
939
        }
940
    }
941
    retval = 0;
942

943 1
 exit:
944 1
    Py_XDECREF(selfit);
945 1
    Py_XDECREF(arrit);
946 1
    Py_XDECREF(arr);
947
    return retval;
948
}
949

950
static PyObject *
951 1
array_transpose_get(PyArrayObject *self)
952
{
953 1
    return PyArray_Transpose(self, NULL);
954
}
955

956
/* If this is None, no function call is made
957
   --- default sub-class behavior
958
*/
959
static PyObject *
960 1
array_finalize_get(PyArrayObject *NPY_UNUSED(self))
961
{
962 1
    Py_RETURN_NONE;
963
}
964

965
NPY_NO_EXPORT PyGetSetDef array_getsetlist[] = {
966
    {"ndim",
967
        (getter)array_ndim_get,
968
        NULL,
969
        NULL, NULL},
970
    {"flags",
971
        (getter)array_flags_get,
972
        NULL,
973
        NULL, NULL},
974
    {"shape",
975
        (getter)array_shape_get,
976
        (setter)array_shape_set,
977
        NULL, NULL},
978
    {"strides",
979
        (getter)array_strides_get,
980
        (setter)array_strides_set,
981
        NULL, NULL},
982
    {"data",
983
        (getter)array_data_get,
984
        (setter)array_data_set,
985
        NULL, NULL},
986
    {"itemsize",
987
        (getter)array_itemsize_get,
988
        NULL,
989
        NULL, NULL},
990
    {"size",
991
        (getter)array_size_get,
992
        NULL,
993
        NULL, NULL},
994
    {"nbytes",
995
        (getter)array_nbytes_get,
996
        NULL,
997
        NULL, NULL},
998
    {"base",
999
        (getter)array_base_get,
1000
        NULL,
1001
        NULL, NULL},
1002
    {"dtype",
1003
        (getter)array_descr_get,
1004
        (setter)array_descr_set,
1005
        NULL, NULL},
1006
    {"real",
1007
        (getter)array_real_get,
1008
        (setter)array_real_set,
1009
        NULL, NULL},
1010
    {"imag",
1011
        (getter)array_imag_get,
1012
        (setter)array_imag_set,
1013
        NULL, NULL},
1014
    {"flat",
1015
        (getter)array_flat_get,
1016
        (setter)array_flat_set,
1017
        NULL, NULL},
1018
    {"ctypes",
1019
        (getter)array_ctypes_get,
1020
        NULL,
1021
        NULL, NULL},
1022
    {"T",
1023
        (getter)array_transpose_get,
1024
        NULL,
1025
        NULL, NULL},
1026
    {"__array_interface__",
1027
        (getter)array_interface_get,
1028
        NULL,
1029
        NULL, NULL},
1030
    {"__array_struct__",
1031
        (getter)array_struct_get,
1032
        NULL,
1033
        NULL, NULL},
1034
    {"__array_priority__",
1035
        (getter)array_priority_get,
1036
        NULL,
1037
        NULL, NULL},
1038
    {"__array_finalize__",
1039
        (getter)array_finalize_get,
1040
        NULL,
1041
        NULL, NULL},
1042
    {NULL, NULL, NULL, NULL, NULL},  /* Sentinel */
1043
};
1044

1045
/****************** end of attribute get and set routines *******************/

Read our documentation on viewing source code .

Loading