1
/*
2
 * This file implements some helper functions for the array assignment
3
 * routines. The actual assignment routines are in array_assign_*.c
4
 *
5
 * Written by Mark Wiebe (mwwiebe@gmail.com)
6
 * Copyright (c) 2011 by Enthought, Inc.
7
 *
8
 * See LICENSE.txt for the license.
9
 */
10

11
#define PY_SSIZE_T_CLEAN
12
#include <Python.h>
13

14
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
15
#define _MULTIARRAYMODULE
16
#include <numpy/ndarraytypes.h>
17
#include "npy_config.h"
18
#include "npy_pycompat.h"
19

20
#include "shape.h"
21

22
#include "array_assign.h"
23
#include "common.h"
24
#include "lowlevel_strided_loops.h"
25
#include "mem_overlap.h"
26

27
/* See array_assign.h for parameter documentation */
28
NPY_NO_EXPORT int
29 1
broadcast_strides(int ndim, npy_intp const *shape,
30
                int strides_ndim, npy_intp const *strides_shape, npy_intp const *strides,
31
                char const *strides_name,
32
                npy_intp *out_strides)
33
{
34 1
    int idim, idim_start = ndim - strides_ndim;
35

36
    /* Can't broadcast to fewer dimensions */
37 1
    if (idim_start < 0) {
38
        goto broadcast_error;
39
    }
40

41
    /*
42
     * Process from the end to the start, so that 'strides' and 'out_strides'
43
     * can point to the same memory.
44
     */
45 1
    for (idim = ndim - 1; idim >= idim_start; --idim) {
46 1
        npy_intp strides_shape_value = strides_shape[idim - idim_start];
47
        /* If it doesn't have dimension one, it must match */
48 1
        if (strides_shape_value == 1) {
49 1
            out_strides[idim] = 0;
50
        }
51 1
        else if (strides_shape_value != shape[idim]) {
52
            goto broadcast_error;
53
        }
54
        else {
55 1
            out_strides[idim] = strides[idim - idim_start];
56
        }
57
    }
58

59
    /* New dimensions get a zero stride */
60 1
    for (idim = 0; idim < idim_start; ++idim) {
61 1
        out_strides[idim] = 0;
62
    }
63

64
    return 0;
65

66 1
broadcast_error: {
67
        PyObject *errmsg;
68

69 1
        errmsg = PyUnicode_FromFormat("could not broadcast %s from shape ",
70
                                strides_name);
71 1
        PyUString_ConcatAndDel(&errmsg,
72
                build_shape_string(strides_ndim, strides_shape));
73 1
        PyUString_ConcatAndDel(&errmsg,
74
                PyUnicode_FromString(" into shape "));
75 1
        PyUString_ConcatAndDel(&errmsg,
76
                build_shape_string(ndim, shape));
77 1
        PyErr_SetObject(PyExc_ValueError, errmsg);
78 1
        Py_DECREF(errmsg);
79

80
        return -1;
81
    }
82
}
83

84
/* See array_assign.h for parameter documentation */
85
NPY_NO_EXPORT int
86 1
raw_array_is_aligned(int ndim, npy_intp const *shape,
87
                     char *data, npy_intp const *strides, int alignment)
88
{
89

90
    /*
91
     * The code below expects the following:
92
     *  * that alignment is a power of two, as required by the C standard.
93
     *  * that casting from pointer to uintp gives a sensible representation
94
     *    we can use bitwise operations on (perhaps *not* req. by C std,
95
     *    but assumed by glibc so it should be fine)
96
     *  * that casting stride from intp to uintp (to avoid dependence on the
97
     *    signed int representation) preserves remainder wrt alignment, so
98
     *    stride%a is the same as ((unsigned intp)stride)%a. Req. by C std.
99
     *
100
     *  The code checks whether the lowest log2(alignment) bits of `data`
101
     *  and all `strides` are 0, as this implies that
102
     *  (data + n*stride)%alignment == 0 for all integers n.
103
     */
104

105 1
    if (alignment > 1) {
106 1
        npy_uintp align_check = (npy_uintp)data;
107
        int i;
108

109 1
        for (i = 0; i < ndim; i++) {
110
#if NPY_RELAXED_STRIDES_CHECKING
111
            /* skip dim == 1 as it is not required to have stride 0 */
112 1
            if (shape[i] > 1) {
113
                /* if shape[i] == 1, the stride is never used */
114 1
                align_check |= (npy_uintp)strides[i];
115
            }
116 1
            else if (shape[i] == 0) {
117
                /* an array with zero elements is always aligned */
118
                return 1;
119
            }
120
#else /* not NPY_RELAXED_STRIDES_CHECKING */
121
            align_check |= (npy_uintp)strides[i];
122
#endif /* not NPY_RELAXED_STRIDES_CHECKING */
123
        }
124

125 1
        return npy_is_aligned((void *)align_check, alignment);
126
    }
127 1
    else if (alignment == 1) {
128
        return 1;
129
    }
130
    else {
131
        /* always return false for alignment == 0, which means cannot-be-aligned */
132 1
        return 0;
133
    }
134
}
135

136
NPY_NO_EXPORT int
137 1
IsAligned(PyArrayObject *ap)
138
{
139 1
    return raw_array_is_aligned(PyArray_NDIM(ap), PyArray_DIMS(ap),
140 1
                                PyArray_DATA(ap), PyArray_STRIDES(ap),
141 1
                                PyArray_DESCR(ap)->alignment);
142
}
143

144
NPY_NO_EXPORT int
145 1
IsUintAligned(PyArrayObject *ap)
146
{
147 1
    return raw_array_is_aligned(PyArray_NDIM(ap), PyArray_DIMS(ap),
148 1
                                PyArray_DATA(ap), PyArray_STRIDES(ap),
149 1
                                npy_uint_alignment(PyArray_DESCR(ap)->elsize));
150
}
151

152

153

154
/* Returns 1 if the arrays have overlapping data, 0 otherwise */
155
NPY_NO_EXPORT int
156 1
arrays_overlap(PyArrayObject *arr1, PyArrayObject *arr2)
157
{
158
    mem_overlap_t result;
159

160 1
    result = solve_may_share_memory(arr1, arr2, NPY_MAY_SHARE_BOUNDS);
161 1
    if (result == MEM_OVERLAP_NO) {
162
        return 0;
163
    }
164
    else {
165 1
        return 1;
166
    }
167
}

Read our documentation on viewing source code .

Loading