Line data Source code
1 0 : // Distributed under the MIT License. 2 : // See LICENSE.txt for details. 3 : 4 : #pragma once 5 : 6 : #include <complex> 7 : #include <cstddef> 8 : #include <type_traits> 9 : 10 : #include "Utilities/ForceInline.hpp" 11 : #include "Utilities/Gsl.hpp" 12 : #include "Utilities/TypeTraits/IsComplexOfFundamental.hpp" 13 : 14 : /// \ingroup UtilitiesGroup 15 : /// \brief Callable struct which retrieves the `t.size()` for operand `t`. This 16 : /// will cause a compiler error if no such function exists. 17 1 : struct GetContainerSize { 18 : template <typename T> 19 0 : SPECTRE_ALWAYS_INLINE decltype(auto) operator()(const T& t) const { 20 : return t.size(); 21 : } 22 : }; 23 : 24 : /// \ingroup UtilitiesGroup 25 : /// \brief Callable struct for the subscript operator. Returns `t[i]` 26 1 : struct GetContainerElement { 27 : template <typename T> 28 0 : SPECTRE_ALWAYS_INLINE decltype(auto) operator()(T& t, const size_t i) const { 29 : return t[i]; 30 : } 31 : }; 32 : 33 : namespace ContainerHelpers_detail { 34 : // implementation struct for get_element and get_size 35 : template <bool IsFundamentalOrComplexOfFundamental> 36 : struct ContainerImpls; 37 : 38 : template <> 39 : struct ContainerImpls<true> { 40 : template <typename T, typename SubscriptFunction> 41 : static SPECTRE_ALWAYS_INLINE decltype(auto) get_element( 42 : T& t, const size_t /*i*/, const SubscriptFunction /*at*/) { 43 : return t; 44 : } 45 : 46 : template <typename T, typename SizeFunction> 47 : static SPECTRE_ALWAYS_INLINE size_t get_size(const T& /*t*/, 48 : const SizeFunction /*size*/) { 49 : return 1; 50 : } 51 : }; 52 : 53 : template <> 54 : struct ContainerImpls<false> { 55 : template <typename T, typename SubscriptFunction> 56 : static SPECTRE_ALWAYS_INLINE decltype(auto) get_element( 57 : T& t, const size_t i, SubscriptFunction at) { 58 : return at(t, i); 59 : } 60 : 61 : template <typename T, typename SizeFunction> 62 : static SPECTRE_ALWAYS_INLINE decltype(auto) get_size(const T& t, 63 : SizeFunction size) { 64 : return size(t); 65 : } 66 : }; 67 : } // namespace ContainerHelpers_detail 68 : 69 : /*! 70 : * \ingroup UtilitiesGroup 71 : * \brief Returns the `i`th element if `T` has a subscript operator, otherwise 72 : * if `T` is fundamental or a `std::complex` of a fundamental type, returns 73 : * `t`. 74 : * 75 : * \details This function also optionally takes the user-defined subscript 76 : * function `at`, which can be used to specify a custom indexing function. For 77 : * instance, for a type which is a `std::array` of a `std::array`s, the indexing 78 : * function could be the below callable struct: 79 : * \snippet Test_ContainerHelpers.cpp get_element_example_indexing_callable 80 : * 81 : * which would index the data structure in a manner in which the outer array 82 : * index varies fastest. The indexing function must take as arguments the 83 : * applicable container and a `size_t` index, in that order. This follows the 84 : * convention of `gsl::at`. 85 : * \note `std::complex` are regarded as non-indexable (despite a predictable 86 : * memory layout), so this function acts as the identity on `std::complex` of 87 : * fundamental types 88 : */ 89 : template <typename T, typename SubscriptFunction = GetContainerElement> 90 1 : SPECTRE_ALWAYS_INLINE decltype(auto) get_element( 91 : T& t, const size_t i, SubscriptFunction at = GetContainerElement{}) { 92 : return ContainerHelpers_detail::ContainerImpls<( 93 : tt::is_complex_of_fundamental_v<std::remove_cv_t<T>> or 94 : std::is_fundamental_v<std::remove_cv_t<T>>)>::get_element(t, i, at); 95 : } 96 : 97 : /*! 98 : * \ingroup UtilitiesGroup 99 : * \brief Retrieve the size of `t` if `t.size()` is a valid expression, 100 : * otherwise if `T` is fundamental or a `std::complex` of a fundamental type, 101 : * returns 1. 102 : * 103 : * \details This function also optionally takes the user-defined `size` 104 : * function, which can be used to specify a custom size function. For 105 : * instance, for a type which is a `std::array` of a `std::array`, the size 106 : * function could be the below callable struct: 107 : * \snippet Test_ContainerHelpers.cpp get_size_example_size_callable 108 : * 109 : * The `size` function must take the single argument of the applicable 110 : * container, and should return a `size_t`. This follows the convention of 111 : * `std::size()` as of C++17. 112 : * \note `std::complex` are regarded as non-indexable (despite a predictable 113 : * memory layout), so this function will return 1 for a `std::complex` of a 114 : * fundamental type 115 : */ 116 : template <typename T, typename SizeFunction = GetContainerSize> 117 1 : SPECTRE_ALWAYS_INLINE decltype(auto) get_size( 118 : const T& t, SizeFunction size = GetContainerSize{}) { 119 : return ContainerHelpers_detail::ContainerImpls<( 120 : tt::is_complex_of_fundamental_v<std::remove_cv_t<T>> or 121 : std::is_fundamental_v<std::remove_cv_t<T>>)>::get_size(t, size); 122 : } 123 : 124 : /// Fall-back that allows using `min(x)` where `x` can be a vector or a double 125 1 : SPECTRE_ALWAYS_INLINE double min(const double val) { return val; } 126 : 127 : /// Fall-back that allows using `max(x)` where `x` can be a vector or a double 128 1 : SPECTRE_ALWAYS_INLINE double max(const double val) { return val; }