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 : 9 : #include "scipp/common/overloaded.h" 10 : #include "scipp/core/except.h" 11 : #include "scipp/core/value_and_variance.h" 12 : #include "scipp/core/values_and_variances.h" 13 : 14 : namespace scipp::core { 15 : 16 : template <class... Ts> struct pair_self { 17 : using type = std::tuple<std::tuple<Ts, Ts>...>; 18 : }; 19 : template <class... Ts> struct pair_custom { 20 : using type = std::tuple<Ts...>; 21 : }; 22 : template <class... Ts> struct pair_ { 23 : template <class RHS> using type = std::tuple<std::tuple<Ts, RHS>...>; 24 : }; 25 : 26 : template <class... Ts> using pair_self_t = typename pair_self<Ts...>::type; 27 : template <class... Ts> using pair_custom_t = typename pair_custom<Ts...>::type; 28 : 29 : template <class... Ts> struct pair_product { 30 : template <class T> using type = std::tuple<std::tuple<T, Ts>...>; 31 : }; 32 : 33 : template <class... Ts> 34 : using pair_product_t = decltype(std::tuple_cat( 35 : typename pair_product<Ts...>::template type<Ts>{}...)); 36 : 37 : using arithmetic_type_pairs = pair_product_t<float, double, int32_t, int64_t>; 38 : using arithmetic_type_pairs_with_bool = 39 : pair_product_t<float, double, int32_t, int64_t, bool>; 40 : 41 : static constexpr auto keep_unit = 42 : overloaded{[](const units::Unit &) {}, 43 : [](const units::Unit &, const units::Unit &) {}}; 44 : 45 : static constexpr auto dimensionless_unit_check = 46 : [](units::Unit &varUnit, const units::Unit &otherUnit) { 47 : expect::equals(units::one, varUnit); 48 : expect::equals(units::one, otherUnit); 49 : }; 50 : 51 : static constexpr auto dimensionless_unit_check_return = 52 29111 : overloaded{[](const units::Unit &a) { 53 29116 : expect::equals(units::one, a); 54 29106 : return units::one; 55 : }, 56 269 : [](const units::Unit &a, const units::Unit &b) { 57 269 : expect::equals(units::one, a); 58 269 : expect::equals(units::one, b); 59 269 : return units::one; 60 : }}; 61 : 62 : template <typename Op> struct assign_unary : Op { 63 : template <typename Out, typename... In> 64 145 : void operator()(Out &out, In &&...in) { 65 145 : out = Op::operator()(std::forward<In>(in)...); 66 145 : } 67 : }; 68 : template <typename Op> assign_unary(Op) -> assign_unary<Op>; 69 : 70 : /// Flags for transform, added as overloads to the operator. These are never 71 : /// actually called since flag presence is checked via the base class of the 72 : /// operator. 73 : namespace transform_flags { 74 : 75 : /// Base and NULL flag. Do not test for this type. 76 : struct Flag { 77 : void operator()() const {}; 78 : }; 79 : 80 : /// Helper to conditionally apply a given flag under condition (B) otherwise 81 : /// Null Flag 82 : template <bool B> 83 : constexpr auto conditional_flag = 84 : [](auto flag) { return std::conditional_t<B, decltype(flag), Flag>{}; }; 85 : 86 : namespace { 87 : 88 : struct no_out_variance_t : Flag {}; 89 : /// Add this to overloaded operator to indicate that the operation does not 90 : /// return data with variances, regardless of whether inputs have variances. 91 : constexpr auto no_out_variance = no_out_variance_t{}; 92 : 93 : template <int N> struct expect_no_variance_arg_t : Flag {}; 94 : /// Add this to overloaded operator to indicate that the operation does not 95 : /// support variances in the specified argument. 96 : template <int N> 97 : constexpr auto expect_no_variance_arg = expect_no_variance_arg_t<N>{}; 98 : 99 : struct expect_no_in_variance_if_out_cannot_have_variance_t : Flag {}; 100 : /// Add this to overloaded operator to indicate that if the output dtype 101 : /// does not support variance none of the inputs should have a variance. 102 : constexpr auto expect_no_in_variance_if_out_cannot_have_variance = 103 : expect_no_in_variance_if_out_cannot_have_variance_t{}; 104 : 105 : template <int N> struct expect_variance_arg_t : Flag {}; 106 : /// Add this to overloaded operator to indicate that the operation requires 107 : /// variances in the specified argument. 108 : template <int N> 109 : constexpr auto expect_variance_arg = expect_variance_arg_t<N>{}; 110 : 111 : struct expect_in_variance_if_out_variance_t : Flag {}; 112 : /// Add this to overloaded operator to indicate that the in-place operation 113 : /// requires inputs to have a variance if the output has a variance. 114 : constexpr auto expect_in_variance_if_out_variance = 115 : expect_in_variance_if_out_variance_t{}; 116 : 117 : struct expect_all_or_none_have_variance_t : Flag {}; 118 : constexpr auto expect_all_or_none_have_variance = 119 : expect_all_or_none_have_variance_t{}; 120 : 121 : struct force_variance_broadcast_t : Flag {}; 122 : /// Add this to overloaded operator to indicate to skip the check for variance 123 : /// broadcast. This is used to implement "copy", which we want to work on 124 : /// explicitly broadcasted inputs, even in the presence of variances. 125 : constexpr auto force_variance_broadcast = force_variance_broadcast_t{}; 126 : 127 : } // namespace 128 : } // namespace transform_flags 129 : 130 : } // namespace scipp::core