LCOV - code coverage report
Current view: top level - variable/include/scipp/variable - visit.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 30 30 100.0 %
Date: 2024-04-28 01:25:40 Functions: 1114 1762 63.2 %

          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

Generated by: LCOV version 1.14