1
#define PY_SSIZE_T_CLEAN
2
#include <Python.h>
3
#include "structmember.h"
4

5
#include <npy_config.h>
6

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

13
#include "common.h"
14
#include "arrayobject.h"
15
#include "ctors.h"
16
#include "mapping.h"
17
#include "lowlevel_strided_loops.h"
18
#include "scalartypes.h"
19
#include "array_assign.h"
20

21
#include "convert.h"
22

23
int
24
fallocate(int fd, int mode, off_t offset, off_t len);
25

26
/*
27
 * allocate nbytes of diskspace for file fp
28
 * this allows the filesystem to make smarter allocation decisions and gives a
29
 * fast exit on not enough free space
30
 * returns -1 and raises exception on no space, ignores all other errors
31
 */
32
static int
33 1
npy_fallocate(npy_intp nbytes, FILE * fp)
34
{
35
    /*
36
     * unknown behavior on non-linux so don't try it
37
     * we don't want explicit zeroing to happen
38
     */
39
#if defined(HAVE_FALLOCATE) && defined(__linux__)
40
    int r;
41
    /* small files not worth the system call */
42 1
    if (nbytes < 16 * 1024 * 1024) {
43
        return 0;
44
    }
45

46
    /* btrfs can take a while to allocate making release worthwhile */
47 1
    NPY_BEGIN_ALLOW_THREADS;
48
    /*
49
     * flush in case there might be some unexpected interactions between the
50
     * fallocate call and unwritten data in the descriptor
51
     */
52 1
    fflush(fp);
53
    /*
54
     * the flag "1" (=FALLOC_FL_KEEP_SIZE) is needed for the case of files
55
     * opened in append mode (issue #8329)
56
     */
57 1
    r = fallocate(fileno(fp), 1, npy_ftell(fp), nbytes);
58 1
    NPY_END_ALLOW_THREADS;
59

60
    /*
61
     * early exit on no space, other errors will also get found during fwrite
62
     */
63 1
    if (r == -1 && errno == ENOSPC) {
64 0
        PyErr_Format(PyExc_IOError, "Not enough free space to write "
65
                     "%"NPY_INTP_FMT" bytes", nbytes);
66 0
        return -1;
67
    }
68
#endif
69
    return 0;
70
}
71

72
/*
73
 * Converts a subarray of 'self' into lists, with starting data pointer
74
 * 'dataptr' and from dimension 'startdim' to the last dimension of 'self'.
75
 *
76
 * Returns a new reference.
77
 */
78
static PyObject *
79 1
recursive_tolist(PyArrayObject *self, char *dataptr, int startdim)
80
{
81
    npy_intp i, n, stride;
82
    PyObject *ret, *item;
83

84
    /* Base case */
85 1
    if (startdim >= PyArray_NDIM(self)) {
86 1
        return PyArray_GETITEM(self, dataptr);
87
    }
88

89 1
    n = PyArray_DIM(self, startdim);
90 1
    stride = PyArray_STRIDE(self, startdim);
91

92 1
    ret = PyList_New(n);
93 1
    if (ret == NULL) {
94
        return NULL;
95
    }
96

97 1
    for (i = 0; i < n; ++i) {
98 1
        item = recursive_tolist(self, dataptr, startdim+1);
99 1
        if (item == NULL) {
100 0
            Py_DECREF(ret);
101
            return NULL;
102
        }
103 1
        PyList_SET_ITEM(ret, i, item);
104

105 1
        dataptr += stride;
106
    }
107

108
    return ret;
109
}
110

111
/*NUMPY_API
112
 * To List
113
 */
114
NPY_NO_EXPORT PyObject *
115 1
PyArray_ToList(PyArrayObject *self)
116
{
117 1
    return recursive_tolist(self, PyArray_DATA(self), 0);
118
}
119

120
/* XXX: FIXME --- add ordering argument to
121
   Allow Fortran ordering on write
122
   This will need the addition of a Fortran-order iterator.
123
 */
124

125
/*NUMPY_API
126
  To File
127
*/
128
NPY_NO_EXPORT int
129 1
PyArray_ToFile(PyArrayObject *self, FILE *fp, char *sep, char *format)
130
{
131
    npy_intp size;
132
    npy_intp n, n2;
133
    size_t n3, n4;
134
    PyArrayIterObject *it;
135
    PyObject *obj, *strobj, *tupobj, *byteobj;
136

137 1
    n3 = (sep ? strlen((const char *)sep) : 0);
138 1
    if (n3 == 0) {
139
        /* binary data */
140 1
        if (PyDataType_FLAGCHK(PyArray_DESCR(self), NPY_LIST_PICKLE)) {
141 0
            PyErr_SetString(PyExc_IOError,
142
                    "cannot write object arrays to a file in binary mode");
143 0
            return -1;
144
        }
145 1
        if (PyArray_DESCR(self)->elsize == 0) {
146
            /* For zero-width data types there's nothing to write */
147
            return 0;
148
        }
149 1
        if (npy_fallocate(PyArray_NBYTES(self), fp) != 0) {
150
            return -1;
151
        }
152

153 1
        if (PyArray_ISCONTIGUOUS(self)) {
154 1
            size = PyArray_SIZE(self);
155 1
            NPY_BEGIN_ALLOW_THREADS;
156

157
#if defined (_MSC_VER) && defined(_WIN64)
158
            /* Workaround Win64 fwrite() bug. Ticket #1660 */
159
            {
160
                npy_intp maxsize = 2147483648 / PyArray_DESCR(self)->elsize;
161
                npy_intp chunksize;
162

163
                n = 0;
164
                while (size > 0) {
165
                    chunksize = (size > maxsize) ? maxsize : size;
166
                    n2 = fwrite((const void *)
167
                             ((char *)PyArray_DATA(self) + (n * PyArray_DESCR(self)->elsize)),
168
                             (size_t) PyArray_DESCR(self)->elsize,
169
                             (size_t) chunksize, fp);
170
                    if (n2 < chunksize) {
171
                        break;
172
                    }
173
                    n += n2;
174
                    size -= chunksize;
175
                }
176
                size = PyArray_SIZE(self);
177
            }
178
#else
179 1
            n = fwrite((const void *)PyArray_DATA(self),
180 1
                    (size_t) PyArray_DESCR(self)->elsize,
181
                    (size_t) size, fp);
182
#endif
183 1
            NPY_END_ALLOW_THREADS;
184 1
            if (n < size) {
185 0
                PyErr_Format(PyExc_IOError,
186
                        "%ld requested and %ld written",
187
                        (long) size, (long) n);
188 0
                return -1;
189
            }
190
        }
191
        else {
192 1
            NPY_BEGIN_THREADS_DEF;
193

194 1
            it = (PyArrayIterObject *) PyArray_IterNew((PyObject *)self);
195 1
            NPY_BEGIN_THREADS;
196 1
            while (it->index < it->size) {
197 1
                if (fwrite((const void *)it->dataptr,
198 1
                            (size_t) PyArray_DESCR(self)->elsize,
199
                            1, fp) < 1) {
200 0
                    NPY_END_THREADS;
201 0
                    PyErr_Format(PyExc_IOError,
202
                            "problem writing element %" NPY_INTP_FMT
203
                            " to file", it->index);
204 0
                    Py_DECREF(it);
205
                    return -1;
206
                }
207 1
                PyArray_ITER_NEXT(it);
208
            }
209 1
            NPY_END_THREADS;
210 1
            Py_DECREF(it);
211
        }
212
    }
213
    else {
214
        /*
215
         * text data
216
         */
217

218 1
        it = (PyArrayIterObject *)
219
            PyArray_IterNew((PyObject *)self);
220 1
        n4 = (format ? strlen((const char *)format) : 0);
221 1
        while (it->index < it->size) {
222 1
            obj = PyArray_GETITEM(self, it->dataptr);
223 1
            if (obj == NULL) {
224 0
                Py_DECREF(it);
225
                return -1;
226
            }
227 1
            if (n4 == 0) {
228
                /*
229
                 * standard writing
230
                 */
231 1
                strobj = PyObject_Repr(obj);
232 1
                Py_DECREF(obj);
233 1
                if (strobj == NULL) {
234 0
                    Py_DECREF(it);
235
                    return -1;
236
                }
237
            }
238
            else {
239
                /*
240
                 * use format string
241
                 */
242 1
                tupobj = PyTuple_New(1);
243 1
                if (tupobj == NULL) {
244 0
                    Py_DECREF(it);
245
                    return -1;
246
                }
247 1
                PyTuple_SET_ITEM(tupobj,0,obj);
248 1
                obj = PyUnicode_FromString((const char *)format);
249 1
                if (obj == NULL) {
250 0
                    Py_DECREF(tupobj);
251 0
                    Py_DECREF(it);
252
                    return -1;
253
                }
254 1
                strobj = PyUnicode_Format(obj, tupobj);
255 1
                Py_DECREF(obj);
256 1
                Py_DECREF(tupobj);
257 1
                if (strobj == NULL) {
258 0
                    Py_DECREF(it);
259
                    return -1;
260
                }
261
            }
262 1
            byteobj = PyUnicode_AsASCIIString(strobj);
263 1
            NPY_BEGIN_ALLOW_THREADS;
264 1
            n2 = PyBytes_GET_SIZE(byteobj);
265 1
            n = fwrite(PyBytes_AS_STRING(byteobj), 1, n2, fp);
266 1
            NPY_END_ALLOW_THREADS;
267 1
            Py_DECREF(byteobj);
268 1
            if (n < n2) {
269 0
                PyErr_Format(PyExc_IOError,
270
                        "problem writing element %" NPY_INTP_FMT
271
                        " to file", it->index);
272 0
                Py_DECREF(strobj);
273 0
                Py_DECREF(it);
274
                return -1;
275
            }
276
            /* write separator for all but last one */
277 1
            if (it->index != it->size-1) {
278 1
                if (fwrite(sep, 1, n3, fp) < n3) {
279 0
                    PyErr_Format(PyExc_IOError,
280
                            "problem writing separator to file");
281 0
                    Py_DECREF(strobj);
282 0
                    Py_DECREF(it);
283
                    return -1;
284
                }
285
            }
286 1
            Py_DECREF(strobj);
287 1
            PyArray_ITER_NEXT(it);
288
        }
289 1
        Py_DECREF(it);
290
    }
291
    return 0;
292
}
293

294
/*NUMPY_API*/
295
NPY_NO_EXPORT PyObject *
296 1
PyArray_ToString(PyArrayObject *self, NPY_ORDER order)
297
{
298
    npy_intp numbytes;
299
    npy_intp i;
300
    char *dptr;
301
    int elsize;
302
    PyObject *ret;
303
    PyArrayIterObject *it;
304

305 1
    if (order == NPY_ANYORDER)
306 1
        order = PyArray_ISFORTRAN(self);
307

308
    /*        if (PyArray_TYPE(self) == NPY_OBJECT) {
309
              PyErr_SetString(PyExc_ValueError, "a string for the data" \
310
              "in an object array is not appropriate");
311
              return NULL;
312
              }
313
    */
314

315 1
    numbytes = PyArray_NBYTES(self);
316 1
    if ((PyArray_IS_C_CONTIGUOUS(self) && (order == NPY_CORDER))
317 1
        || (PyArray_IS_F_CONTIGUOUS(self) && (order == NPY_FORTRANORDER))) {
318 1
        ret = PyBytes_FromStringAndSize(PyArray_DATA(self), (Py_ssize_t) numbytes);
319
    }
320
    else {
321
        PyObject *new;
322 1
        if (order == NPY_FORTRANORDER) {
323
            /* iterators are always in C-order */
324 1
            new = PyArray_Transpose(self, NULL);
325 1
            if (new == NULL) {
326
                return NULL;
327
            }
328
        }
329
        else {
330 1
            Py_INCREF(self);
331 1
            new = (PyObject *)self;
332
        }
333 1
        it = (PyArrayIterObject *)PyArray_IterNew(new);
334 1
        Py_DECREF(new);
335 1
        if (it == NULL) {
336
            return NULL;
337
        }
338 1
        ret = PyBytes_FromStringAndSize(NULL, (Py_ssize_t) numbytes);
339 1
        if (ret == NULL) {
340 0
            Py_DECREF(it);
341
            return NULL;
342
        }
343 1
        dptr = PyBytes_AS_STRING(ret);
344 1
        i = it->size;
345 1
        elsize = PyArray_DESCR(self)->elsize;
346 1
        while (i--) {
347 1
            memcpy(dptr, it->dataptr, elsize);
348 1
            dptr += elsize;
349 1
            PyArray_ITER_NEXT(it);
350
        }
351 1
        Py_DECREF(it);
352
    }
353
    return ret;
354
}
355

356
/*NUMPY_API*/
357
NPY_NO_EXPORT int
358 1
PyArray_FillWithScalar(PyArrayObject *arr, PyObject *obj)
359
{
360 1
    PyArray_Descr *dtype = NULL;
361
    npy_longlong value_buffer[4];
362 1
    char *value = NULL;
363 1
    int retcode = 0;
364

365
    /*
366
     * If 'arr' is an object array, copy the object as is unless
367
     * 'obj' is a zero-dimensional array, in which case we copy
368
     * the element in that array instead.
369
     */
370 1
    if (PyArray_DESCR(arr)->type_num == NPY_OBJECT &&
371 1
                        !(PyArray_Check(obj) &&
372 0
                          PyArray_NDIM((PyArrayObject *)obj) == 0)) {
373 1
        value = (char *)&obj;
374

375 1
        dtype = PyArray_DescrFromType(NPY_OBJECT);
376 1
        if (dtype == NULL) {
377
            return -1;
378
        }
379
    }
380
    /* NumPy scalar */
381 1
    else if (PyArray_IsScalar(obj, Generic)) {
382 1
        dtype = PyArray_DescrFromScalar(obj);
383 1
        if (dtype == NULL) {
384
            return -1;
385
        }
386 1
        value = scalar_value(obj, dtype);
387 1
        if (value == NULL) {
388 0
            Py_DECREF(dtype);
389
            return -1;
390
        }
391
    }
392
    /* Python boolean */
393 1
    else if (PyBool_Check(obj)) {
394 1
        value = (char *)value_buffer;
395 1
        *value = (obj == Py_True);
396

397 1
        dtype = PyArray_DescrFromType(NPY_BOOL);
398 1
        if (dtype == NULL) {
399
            return -1;
400
        }
401
    }
402
    /* Python integer */
403 1
    else if (PyLong_Check(obj)) {
404
        /* Try long long before unsigned long long */
405 1
        npy_longlong ll_v = PyLong_AsLongLong(obj);
406 1
        if (error_converting(ll_v)) {
407
            /* Long long failed, try unsigned long long */
408
            npy_ulonglong ull_v;
409 1
            PyErr_Clear();
410 1
            ull_v = PyLong_AsUnsignedLongLong(obj);
411 1
            if (ull_v == (unsigned long long)-1 && PyErr_Occurred()) {
412
                return -1;
413
            }
414 1
            value = (char *)value_buffer;
415 1
            *(npy_ulonglong *)value = ull_v;
416

417 1
            dtype = PyArray_DescrFromType(NPY_ULONGLONG);
418 1
            if (dtype == NULL) {
419
                return -1;
420
            }
421
        }
422
        else {
423
            /* Long long succeeded */
424 1
            value = (char *)value_buffer;
425 1
            *(npy_longlong *)value = ll_v;
426

427 1
            dtype = PyArray_DescrFromType(NPY_LONGLONG);
428 1
            if (dtype == NULL) {
429
                return -1;
430
            }
431
        }
432
    }
433
    /* Python float */
434 1
    else if (PyFloat_Check(obj)) {
435 1
        npy_double v = PyFloat_AsDouble(obj);
436 1
        if (error_converting(v)) {
437
            return -1;
438
        }
439 1
        value = (char *)value_buffer;
440 1
        *(npy_double *)value = v;
441

442 1
        dtype = PyArray_DescrFromType(NPY_DOUBLE);
443 1
        if (dtype == NULL) {
444
            return -1;
445
        }
446
    }
447
    /* Python complex */
448 1
    else if (PyComplex_Check(obj)) {
449
        npy_double re, im;
450

451 0
        re = PyComplex_RealAsDouble(obj);
452 0
        if (error_converting(re)) {
453
            return -1;
454
        }
455 0
        im = PyComplex_ImagAsDouble(obj);
456 0
        if (error_converting(im)) {
457
            return -1;
458
        }
459 0
        value = (char *)value_buffer;
460 0
        ((npy_double *)value)[0] = re;
461 0
        ((npy_double *)value)[1] = im;
462

463 0
        dtype = PyArray_DescrFromType(NPY_CDOUBLE);
464 0
        if (dtype == NULL) {
465
            return -1;
466
        }
467
    }
468

469
    /* Use the value pointer we got if possible */
470 1
    if (value != NULL) {
471
        /* TODO: switch to SAME_KIND casting */
472 1
        retcode = PyArray_AssignRawScalar(arr, dtype, value,
473
                                NULL, NPY_UNSAFE_CASTING);
474 1
        Py_DECREF(dtype);
475
        return retcode;
476
    }
477
    /* Otherwise convert to an array to do the assignment */
478
    else {
479
        PyArrayObject *src_arr;
480

481
        /**
482
         * The dtype of the destination is used when converting
483
         * from the pyobject, so that for example a tuple gets
484
         * recognized as a struct scalar of the required type.
485
         */
486 1
        Py_INCREF(PyArray_DTYPE(arr));
487 1
        src_arr = (PyArrayObject *)PyArray_FromAny(obj,
488
                        PyArray_DTYPE(arr), 0, 0, 0, NULL);
489 1
        if (src_arr == NULL) {
490
            return -1;
491
        }
492

493 1
        if (PyArray_NDIM(src_arr) != 0) {
494 0
            PyErr_SetString(PyExc_ValueError,
495
                    "Input object to FillWithScalar is not a scalar");
496 0
            Py_DECREF(src_arr);
497
            return -1;
498
        }
499

500 1
        retcode = PyArray_CopyInto(arr, src_arr);
501

502 1
        Py_DECREF(src_arr);
503
        return retcode;
504
    }
505
}
506

507
/*
508
 * Fills an array with zeros.
509
 *
510
 * dst: The destination array.
511
 * wheremask: If non-NULL, a boolean mask specifying where to set the values.
512
 *
513
 * Returns 0 on success, -1 on failure.
514
 */
515
NPY_NO_EXPORT int
516 1
PyArray_AssignZero(PyArrayObject *dst,
517
                   PyArrayObject *wheremask)
518
{
519
    npy_bool value;
520
    PyArray_Descr *bool_dtype;
521
    int retcode;
522

523
    /* Create a raw bool scalar with the value False */
524 1
    bool_dtype = PyArray_DescrFromType(NPY_BOOL);
525 1
    if (bool_dtype == NULL) {
526
        return -1;
527
    }
528 1
    value = 0;
529

530 1
    retcode = PyArray_AssignRawScalar(dst, bool_dtype, (char *)&value,
531
                                      wheremask, NPY_SAFE_CASTING);
532

533 1
    Py_DECREF(bool_dtype);
534
    return retcode;
535
}
536

537

538
/*NUMPY_API
539
 * Copy an array.
540
 */
541
NPY_NO_EXPORT PyObject *
542 1
PyArray_NewCopy(PyArrayObject *obj, NPY_ORDER order)
543
{
544
    PyArrayObject *ret;
545

546 1
    ret = (PyArrayObject *)PyArray_NewLikeArray(obj, order, NULL, 1);
547 1
    if (ret == NULL) {
548
        return NULL;
549
    }
550

551 1
    if (PyArray_AssignArray(ret, obj, NULL, NPY_UNSAFE_CASTING) < 0) {
552 0
        Py_DECREF(ret);
553
        return NULL;
554
    }
555

556
    return (PyObject *)ret;
557
}
558

559
/*NUMPY_API
560
 * View
561
 * steals a reference to type -- accepts NULL
562
 */
563
NPY_NO_EXPORT PyObject *
564 1
PyArray_View(PyArrayObject *self, PyArray_Descr *type, PyTypeObject *pytype)
565
{
566 1
    PyArrayObject *ret = NULL;
567
    PyArray_Descr *dtype;
568
    PyTypeObject *subtype;
569
    int flags;
570

571 1
    if (pytype) {
572
        subtype = pytype;
573
    }
574
    else {
575 1
        subtype = Py_TYPE(self);
576
    }
577

578 1
    dtype = PyArray_DESCR(self);
579 1
    flags = PyArray_FLAGS(self);
580

581 1
    Py_INCREF(dtype);
582 1
    ret = (PyArrayObject *)PyArray_NewFromDescr_int(
583
            subtype, dtype,
584 1
            PyArray_NDIM(self), PyArray_DIMS(self), PyArray_STRIDES(self),
585
            PyArray_DATA(self),
586
            flags, (PyObject *)self, (PyObject *)self,
587
            0, 1);
588 1
    if (ret == NULL) {
589 1
        Py_XDECREF(type);
590
        return NULL;
591
    }
592

593 1
    if (type != NULL) {
594 1
        if (PyObject_SetAttrString((PyObject *)ret, "dtype",
595
                                   (PyObject *)type) < 0) {
596 1
            Py_DECREF(ret);
597 1
            Py_DECREF(type);
598
            return NULL;
599
        }
600 1
        Py_DECREF(type);
601
    }
602
    return (PyObject *)ret;
603
}

Read our documentation on viewing source code .

Loading