1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
|
/*
* This file implements some helper functions for the array assignment
* routines. The actual assignment routines are in array_assign_*.c
*
* Written by Mark Wiebe (mwwiebe@gmail.com)
* Copyright (c) 2011 by Enthought, Inc.
*
* See LICENSE.txt for the license.
*/
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <numpy/ndarraytypes.h>
#include "npy_config.h"
#include "npy_pycompat.h"
#include "shape.h"
#include "array_assign.h"
#include "common.h"
#include "lowlevel_strided_loops.h"
#include "mem_overlap.h"
/* See array_assign.h for parameter documentation */
NPY_NO_EXPORT int
broadcast_strides(int ndim, npy_intp const *shape,
int strides_ndim, npy_intp const *strides_shape, npy_intp const *strides,
char const *strides_name,
npy_intp *out_strides)
{
int idim, idim_start = ndim - strides_ndim;
/* Can't broadcast to fewer dimensions */
if (idim_start < 0) {
goto broadcast_error;
}
/*
* Process from the end to the start, so that 'strides' and 'out_strides'
* can point to the same memory.
*/
for (idim = ndim - 1; idim >= idim_start; --idim) {
npy_intp strides_shape_value = strides_shape[idim - idim_start];
/* If it doesn't have dimension one, it must match */
if (strides_shape_value == 1) {
out_strides[idim] = 0;
}
else if (strides_shape_value != shape[idim]) {
goto broadcast_error;
}
else {
out_strides[idim] = strides[idim - idim_start];
}
}
/* New dimensions get a zero stride */
for (idim = 0; idim < idim_start; ++idim) {
out_strides[idim] = 0;
}
return 0;
broadcast_error: {
PyObject *shape1 = convert_shape_to_string(strides_ndim,
strides_shape, "");
if (shape1 == NULL) {
return -1;
}
PyObject *shape2 = convert_shape_to_string(ndim, shape, "");
if (shape2 == NULL) {
Py_DECREF(shape1);
return -1;
}
PyErr_Format(PyExc_ValueError,
"could not broadcast %s from shape %S into shape %S",
strides_name, shape1, shape2);
Py_DECREF(shape1);
Py_DECREF(shape2);
return -1;
}
}
/* See array_assign.h for parameter documentation */
NPY_NO_EXPORT int
raw_array_is_aligned(int ndim, npy_intp const *shape,
char *data, npy_intp const *strides, int alignment)
{
/*
* The code below expects the following:
* * that alignment is a power of two, as required by the C standard.
* * that casting from pointer to uintp gives a sensible representation
* we can use bitwise operations on (perhaps *not* req. by C std,
* but assumed by glibc so it should be fine)
* * that casting stride from intp to uintp (to avoid dependence on the
* signed int representation) preserves remainder wrt alignment, so
* stride%a is the same as ((unsigned intp)stride)%a. Req. by C std.
*
* The code checks whether the lowest log2(alignment) bits of `data`
* and all `strides` are 0, as this implies that
* (data + n*stride)%alignment == 0 for all integers n.
*/
if (alignment > 1) {
npy_uintp align_check = (npy_uintp)data;
int i;
for (i = 0; i < ndim; i++) {
/* skip dim == 1 as it is not required to have stride 0 */
if (shape[i] > 1) {
/* if shape[i] == 1, the stride is never used */
align_check |= (npy_uintp)strides[i];
}
else if (shape[i] == 0) {
/* an array with zero elements is always aligned */
return 1;
}
}
return npy_is_aligned((void *)align_check, alignment);
}
else if (alignment == 1) {
return 1;
}
else {
/* always return false for alignment == 0, which means cannot-be-aligned */
return 0;
}
}
NPY_NO_EXPORT int
IsAligned(PyArrayObject *ap)
{
return raw_array_is_aligned(PyArray_NDIM(ap), PyArray_DIMS(ap),
PyArray_DATA(ap), PyArray_STRIDES(ap),
PyArray_DESCR(ap)->alignment);
}
NPY_NO_EXPORT int
IsUintAligned(PyArrayObject *ap)
{
return raw_array_is_aligned(PyArray_NDIM(ap), PyArray_DIMS(ap),
PyArray_DATA(ap), PyArray_STRIDES(ap),
npy_uint_alignment(PyArray_DESCR(ap)->elsize));
}
/* Returns 1 if the arrays have overlapping data, 0 otherwise */
NPY_NO_EXPORT int
arrays_overlap(PyArrayObject *arr1, PyArrayObject *arr2)
{
mem_overlap_t result;
result = solve_may_share_memory(arr1, arr2, NPY_MAY_SHARE_BOUNDS);
if (result == MEM_OVERLAP_NO) {
return 0;
}
else {
return 1;
}
}
|