* An array assignment function for copying arrays, broadcasting 'src' into * 'dst'. This function makes a temporary copy of 'src' if 'src' and * 'dst' overlap, to be able to handle views of the same data with * different strides. * * dst: The destination array. * src: The source array. * wheremask: If non-NULL, a boolean mask specifying where to copy. * casting: An exception is raised if t
| 292 | * Returns 0 on success, -1 on failure. |
| 293 | */ |
| 294 | NPY_NO_EXPORT int |
| 295 | PyArray_AssignArray(PyArrayObject *dst, PyArrayObject *src, |
| 296 | PyArrayObject *wheremask, |
| 297 | NPY_CASTING casting) |
| 298 | { |
| 299 | int copied_src = 0; |
| 300 | |
| 301 | npy_intp src_strides[NPY_MAXDIMS]; |
| 302 | |
| 303 | /* Use array_assign_scalar if 'src' NDIM is 0 */ |
| 304 | if (PyArray_NDIM(src) == 0) { |
| 305 | return PyArray_AssignRawScalar( |
| 306 | dst, PyArray_DESCR(src), PyArray_DATA(src), |
| 307 | wheremask, casting); |
| 308 | } |
| 309 | |
| 310 | /* |
| 311 | * Performance fix for expressions like "a[1000:6000] += x". In this |
| 312 | * case, first an in-place add is done, followed by an assignment, |
| 313 | * equivalently expressed like this: |
| 314 | * |
| 315 | * tmp = a[1000:6000] # Calls array_subscript in mapping.c |
| 316 | * np.add(tmp, x, tmp) |
| 317 | * a[1000:6000] = tmp # Calls array_assign_subscript in mapping.c |
| 318 | * |
| 319 | * In the assignment the underlying data type, shape, strides, and |
| 320 | * data pointers are identical, but src != dst because they are separately |
| 321 | * generated slices. By detecting this and skipping the redundant |
| 322 | * copy of values to themselves, we potentially give a big speed boost. |
| 323 | * |
| 324 | * Note that we don't call EquivTypes, because usually the exact same |
| 325 | * dtype object will appear, and we don't want to slow things down |
| 326 | * with a complicated comparison. The comparisons are ordered to |
| 327 | * try and reject this with as little work as possible. |
| 328 | */ |
| 329 | if (PyArray_DATA(src) == PyArray_DATA(dst) && |
| 330 | PyArray_DESCR(src) == PyArray_DESCR(dst) && |
| 331 | PyArray_NDIM(src) == PyArray_NDIM(dst) && |
| 332 | PyArray_CompareLists(PyArray_DIMS(src), |
| 333 | PyArray_DIMS(dst), |
| 334 | PyArray_NDIM(src)) && |
| 335 | PyArray_CompareLists(PyArray_STRIDES(src), |
| 336 | PyArray_STRIDES(dst), |
| 337 | PyArray_NDIM(src))) { |
| 338 | /*printf("Redundant copy operation detected\n");*/ |
| 339 | return 0; |
| 340 | } |
| 341 | |
| 342 | if (PyArray_FailUnlessWriteable(dst, "assignment destination") < 0) { |
| 343 | goto fail; |
| 344 | } |
| 345 | |
| 346 | /* Check the casting rule */ |
| 347 | if (!PyArray_CanCastTypeTo(PyArray_DESCR(src), |
| 348 | PyArray_DESCR(dst), casting)) { |
| 349 | npy_set_invalid_cast_error( |
| 350 | PyArray_DESCR(src), PyArray_DESCR(dst), casting, NPY_FALSE); |
| 351 | goto fail; |
no test coverage detected