Line data Source code
1 : // SPDX-License-Identifier: BSD-3-Clause 2 : // Copyright (c) 2023 Scipp contributors (https://github.com/scipp) 3 : /// @file 4 : /// @author Simon Heybrock 5 : #include "scipp/core/element_array_view.h" 6 : #include "scipp/core/except.h" 7 : 8 : namespace scipp::core { 9 : 10 : namespace { 11 3628804 : void expectCanBroadcastFromTo(const Dimensions &source, 12 : const Dimensions &target) { 13 3628804 : if (source == target) 14 3387278 : return; 15 541946 : for (const auto &dim : target.labels()) 16 300421 : if (source.contains(dim) && (source[dim] < target[dim])) 17 1 : throw except::DimensionError("Cannot broadcast/slice dimension since " 18 : "data has mismatching but smaller " 19 2 : "dimension extent."); 20 : } 21 : } // namespace 22 : 23 : /// Construct ElementArrayViewParams. 24 : /// 25 : /// @param offset Start offset from beginning of array. 26 : /// @param iter_dims Dimensions to use for iteration. 27 : /// @param strides Strides in memory, order matches that of iterDims. 28 : /// @param bucket_params Optional, in case of view onto bucket-variable this 29 : /// holds parameters for accessing individual buckets. 30 8494507 : ElementArrayViewParams::ElementArrayViewParams( 31 : const scipp::index offset, const Dimensions &iter_dims, 32 8494507 : const Strides &strides, const BucketParams &bucket_params) 33 8494507 : : m_offset(offset), m_iterDims(iter_dims), m_strides(strides), 34 8494507 : m_bucketParams(bucket_params) {} 35 : 36 : /// Construct ElementArrayViewParams from another ElementArrayViewParams, with 37 : /// different iteration dimensions. 38 : /// 39 : /// A good way to think of this is of a non-contiguous underlying data array, 40 : /// e.g., since the other view may represent a slice. This also supports 41 : /// broadcasting the slice. 42 3628804 : ElementArrayViewParams::ElementArrayViewParams( 43 3628804 : const ElementArrayViewParams &other, const Dimensions &iterDims) 44 3628804 : : m_offset(other.m_offset), m_iterDims(iterDims), 45 3628804 : m_bucketParams(other.m_bucketParams) { 46 3628804 : expectCanBroadcastFromTo(other.m_iterDims, m_iterDims); 47 : 48 3628803 : m_strides.resize(iterDims.ndim()); 49 5724969 : for (scipp::index dim = 0; dim < iterDims.ndim(); ++dim) { 50 2096166 : auto label = iterDims.label(dim); 51 2096166 : if (other.m_iterDims.contains(label)) { 52 1819519 : m_strides[dim] = other.m_strides[other.m_iterDims.index(label)]; 53 : } else { 54 276647 : m_strides[dim] = 0; 55 : } 56 : } 57 3628806 : } 58 : 59 76512 : void ElementArrayViewParams::requireContiguous() const { 60 76512 : if (m_bucketParams || m_strides != Strides(m_iterDims)) 61 16 : throw std::runtime_error("Data is not contiguous"); 62 76496 : } 63 : 64 : [[nodiscard]] bool 65 510 : ElementArrayViewParams::overlaps(const ElementArrayViewParams &other) const { 66 838 : if (m_offset == other.m_offset && m_iterDims == other.m_iterDims && 67 328 : m_strides == other.m_strides) { 68 : // When both views are exactly the same, we should be fine without 69 : // making extra copies. 70 328 : return false; 71 : } 72 : // Otherwise check for partial overlap. 73 546 : const auto [this_begin, this_end] = memory_bounds( 74 546 : m_iterDims.shape().begin(), m_iterDims.shape().end(), m_strides.begin()); 75 182 : const auto [other_begin, other_end] = 76 182 : memory_bounds(other.m_iterDims.shape().begin(), 77 364 : other.m_iterDims.shape().end(), other.m_strides.begin()); 78 182 : return ((this_begin < other_end) && (this_end > other_begin)); 79 : } 80 : 81 : } // namespace scipp::core