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