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 : #pragma once 6 : 7 : #include <algorithm> 8 : 9 : #include <boost/iterator/iterator_facade.hpp> 10 : 11 : #include "scipp/core/dimensions.h" 12 : #include "scipp/core/sizes.h" 13 : #include "scipp/core/strides.h" 14 : #include "scipp/core/view_index.h" 15 : 16 : namespace scipp::core { 17 : 18 : struct SCIPP_CORE_EXPORT BucketParams { 19 5235681 : explicit operator bool() const noexcept { return dim != Dim::Invalid; } 20 : Dim dim{Dim::Invalid}; 21 : Dimensions dims{}; 22 : Strides strides{}; 23 : const std::pair<scipp::index, scipp::index> *indices{nullptr}; 24 : }; 25 : 26 : template <class T> 27 : class ElementArrayViewParams_iterator 28 : : public boost::iterator_facade<ElementArrayViewParams_iterator<T>, T, 29 : boost::random_access_traversal_tag> { 30 : public: 31 2322437 : ElementArrayViewParams_iterator(T *variable, 32 : const Dimensions &targetDimensions, 33 : const Strides &strides, 34 : const scipp::index index) 35 2322437 : : m_variable(variable), m_index(targetDimensions, strides) { 36 2322437 : m_index.set_index(index); 37 2322437 : } 38 : 39 : private: 40 : friend class boost::iterator_core_access; 41 : 42 11664651 : bool equal(const ElementArrayViewParams_iterator &other) const { 43 11664651 : return m_index == other.m_index; 44 : } 45 22686268 : constexpr void increment() noexcept { m_index.increment(); } 46 22783829 : auto &dereference() const { return m_variable[m_index.get()]; } 47 : void decrement() { m_index.set_index(m_index.index() - 1); } 48 95525 : void advance(int64_t delta) { 49 95525 : if (delta == 1) 50 1232 : increment(); 51 : else 52 94293 : m_index.set_index(m_index.index() + delta); 53 95525 : } 54 1052768 : int64_t distance_to(const ElementArrayViewParams_iterator &other) const { 55 1052768 : return static_cast<int64_t>(other.m_index.index()) - 56 1052768 : static_cast<int64_t>(m_index.index()); 57 : } 58 : 59 : T *m_variable; 60 : ViewIndex m_index; 61 : }; 62 : 63 : /// Base class for ElementArrayView<T> with functionality independent of T. 64 : class SCIPP_CORE_EXPORT ElementArrayViewParams { 65 : public: 66 : ElementArrayViewParams(scipp::index offset, const Dimensions &iter_dims, 67 : const Strides &strides, 68 : const BucketParams &bucket_params); 69 : ElementArrayViewParams(const ElementArrayViewParams &other, 70 : const Dimensions &iterDims); 71 : 72 3066846 : [[nodiscard]] scipp::index size() const { return m_iterDims.volume(); } 73 : [[nodiscard]] constexpr scipp::index offset() const noexcept { 74 : return m_offset; 75 : } 76 2040640 : [[nodiscard]] constexpr const Dimensions &dims() const noexcept { 77 2040640 : return m_iterDims; 78 : } 79 4880674 : [[nodiscard]] const Strides &strides() const noexcept { return m_strides; } 80 5392670 : [[nodiscard]] constexpr const BucketParams &bucketParams() const noexcept { 81 5392670 : return m_bucketParams; 82 : } 83 : 84 : [[nodiscard]] bool overlaps(const ElementArrayViewParams &other) const; 85 : 86 : protected: 87 : void requireContiguous() const; 88 : scipp::index m_offset{0}; 89 : Dimensions m_iterDims; 90 : Strides m_strides; 91 : BucketParams m_bucketParams{}; 92 : }; 93 : 94 : /// A view into multi-dimensional data, supporting slicing, index reordering, 95 : /// and broadcasting. 96 : template <class T> class ElementArrayView : public ElementArrayViewParams { 97 : public: 98 : using element_type = T; 99 : using value_type = std::remove_cv_t<T>; 100 : using iterator = ElementArrayViewParams_iterator<T>; 101 : 102 : /// Construct an ElementArrayView over given buffer. 103 : ElementArrayView(T *buffer, const scipp::index offset, 104 : const Dimensions &iterDims, const Strides &strides, 105 : const BucketParams &bucketParams = BucketParams{}) 106 : : ElementArrayViewParams(offset, iterDims, strides, bucketParams), 107 : m_buffer(buffer) {} 108 : 109 : /// Construct an ElementArrayView over given buffer. 110 7940837 : ElementArrayView(const ElementArrayViewParams &base, T *buffer) 111 7940837 : : ElementArrayViewParams(base), m_buffer(buffer) {} 112 : 113 : /// Construct a ElementArrayView from another ElementArrayView, with different 114 : /// iteration dimensions. 115 : template <class Other> 116 3416897 : ElementArrayView(const Other &other, const Dimensions &iterDims) 117 3416897 : : ElementArrayViewParams(other, iterDims), m_buffer(other.buffer()) {} 118 : 119 1209012 : iterator begin() const { 120 1209012 : return {m_buffer + m_offset, m_iterDims, m_strides, 0}; 121 : } 122 1113425 : iterator end() const { 123 1113425 : return {m_buffer + m_offset, m_iterDims, m_strides, size()}; 124 : } 125 94215 : auto &operator[](const scipp::index i) const { return *(begin() + i); } 126 : 127 : auto &front() const { return *begin(); } 128 : auto &back() const { return *(begin() + (size() - 1)); } 129 : 130 : const T *data() const { return m_buffer + m_offset; } 131 1349787383 : T *data() { return m_buffer + m_offset; } 132 : 133 : auto as_span() const { 134 : requireContiguous(); 135 : return scipp::span(data(), data() + size()); 136 : } 137 : 138 75969 : auto as_span() { 139 75969 : requireContiguous(); 140 75969 : return scipp::span(data(), data() + size()); 141 : } 142 : 143 : bool operator==(const ElementArrayView<T> &other) const { 144 : if (dims() != other.dims()) 145 : return false; 146 : return std::equal(begin(), end(), other.begin()); 147 : } 148 : 149 511401 : template <class T2> bool overlaps(const ElementArrayView<T2> &other) const { 150 511401 : if (buffer() && buffer() == other.buffer()) 151 488 : return ElementArrayViewParams::overlaps(other); 152 510913 : return false; 153 : } 154 : 155 4940320 : constexpr T *buffer() const noexcept { return m_buffer; } 156 : 157 : private: 158 : T *m_buffer; 159 : }; 160 : 161 : } // namespace scipp::core 162 : 163 : namespace scipp { 164 : using core::ElementArrayView; 165 : } 166 : 167 : // Specializations of ElementArrayView: 168 : #include "scipp/core/bucket_array_view.h"