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 <tuple> 8 : #include <utility> 9 : #include <variant> 10 : 11 : #include "scipp/core/bucket.h" 12 : #include "scipp/variable/variable_factory.h" 13 : 14 : namespace scipp::variable { 15 : 16 : /// Access wrapper for a variable with known dtype. 17 : /// 18 : /// This uses VariableFactory to obtain views of the underlying data type, e.g., 19 : /// to access the double values for bucket<Variable> or bucket<DataArray>. 20 : /// DataArray is not known in scipp::variable so the dynamic factory is used for 21 : /// decoupling this. 22 : template <class T, class Var> struct VariableAccess { 23 4575960 : VariableAccess(Var &var) : m_var(&var) {} 24 : using value_type = T; 25 3391379 : Dimensions dims() const { return m_var->dims(); } 26 962 : auto strides() const { return m_var->strides(); } 27 5598518 : auto values() const { return variableFactory().values<T>(*m_var); } 28 26880 : auto variances() const { return variableFactory().variances<T>(*m_var); } 29 6012274 : bool has_variances() const { return variableFactory().has_variances(*m_var); } 30 1891127 : bool is_bins() const { return variableFactory().is_bins(*m_var); } 31 179 : Variable clone() const { return copy(*m_var); } 32 : Var *m_var{nullptr}; 33 : }; 34 4575781 : template <class T, class Var> auto variable_access(Var &var) { 35 4575781 : return VariableAccess<T, Var>(var); 36 : } 37 : 38 : namespace visit_detail { 39 : 40 : template <template <class...> class Tuple, class... T, class... V> 41 7611331 : static bool holds_alternatives(Tuple<T...> &&, const V &...v) noexcept { 42 7611331 : return ((dtype<T> == variableFactory().elem_dtype(v)) && ...); 43 : } 44 : 45 : template <template <class...> class Tuple, class... T, class... V> 46 1821264 : static auto get_args(Tuple<T...> &&, V &&...v) noexcept { 47 1821264 : return std::tuple(variable_access<T>(v)...); 48 : } 49 : 50 : template <class... Tuple, class F, class... V> 51 1821277 : decltype(auto) invoke(F &&f, V &&...v) { 52 : // Determine return type from call based on first set of allowed inputs, this 53 : // should give either Variable or void. 54 : using Ret = decltype(std::apply( 55 : std::forward<F>(f), 56 : get_args(std::tuple_element_t<0, std::tuple<Tuple...>>{}, 57 : std::forward<V>(v)...))); 58 : 59 : if constexpr (!std::is_same_v<void, Ret>) { 60 1184907 : Ret ret; 61 1802106 : if (!((holds_alternatives(Tuple{}, v...) 62 3591078 : ? (ret = std::apply(std::forward<F>(f), 63 2997728 : get_args(Tuple{}, std::forward<V>(v)...)), 64 : true) 65 : : false) || 66 : ...)) 67 3 : throw std::bad_variant_access{}; 68 2369756 : return ret; 69 1184907 : } else { 70 1043398 : if (!((holds_alternatives(Tuple{}, v...) 71 1272943 : ? (std::apply(std::forward<F>(f), 72 1380505 : get_args(Tuple{}, std::forward<V>(v)...)), 73 : true) 74 : : false) || 75 : ...)) 76 10 : throw std::bad_variant_access{}; 77 : } 78 636328 : } 79 : 80 : template <class> struct is_tuple : std::false_type {}; 81 : template <class... T> struct is_tuple<std::tuple<T...>> : std::true_type {}; 82 : 83 : template <class> struct is_array : std::false_type {}; 84 : template <class T, size_t N> 85 : struct is_array<std::array<T, N>> : std::true_type {}; 86 : 87 : /// Typedef for T if T is a tuple, else std::tuple<T, T, T, ...>, with T 88 : /// replicated sizeof...(V) times. 89 : template <class T, class... V> 90 : using maybe_duplicate = 91 : std::conditional_t<is_tuple<T>::value, T, 92 : std::tuple<std::conditional_t<true, T, V>...>>; 93 : } // namespace visit_detail 94 : 95 : /// Apply callable to variants, similar to std::visit. 96 : /// 97 : /// Does not generate code for all possible combinations of alternatives, 98 : /// instead the tuples Ts provide a list of type combinations to try. 99 : template <class... Ts> struct visit { 100 1821277 : template <class F, class... V> static decltype(auto) apply(F &&f, V &&...v) { 101 : using namespace visit_detail; 102 : // For a single input or if same type required for all inputs, Ts is not a 103 : // tuple. In that case we wrap it and expand it to the correct sizeof...(V). 104 636370 : return invoke<maybe_duplicate<Ts, V...>...>(std::forward<F>(f), 105 1821235 : std::forward<V>(v)...); 106 : } 107 : }; 108 : 109 : } // namespace scipp::variable