ContainerHelpers.hpp
1 // 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 
11 #include "Utilities/Gsl.hpp"
12 #include "Utilities/Requires.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.
18  template <typename T>
19  SPECTRE_ALWAYS_INLINE decltype(auto) operator()(const T& t) noexcept {
20  return t.size();
21  }
22 };
23 
24 /// \ingroup UtilitiesGroup
25 /// \brief Callable struct for the subscript operator. Returns `t[i]`
27  template <typename T>
28  SPECTRE_ALWAYS_INLINE decltype(auto) operator()(T& t,
29  const size_t i) noexcept {
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 GetImpls;
38 
39 template <>
40 struct GetImpls<true> {
41  template <typename T, typename SubscriptFunction>
42  static SPECTRE_ALWAYS_INLINE decltype(auto) get_element(
43  T& t, const size_t /*i*/, const SubscriptFunction /*at*/) noexcept {
44  return t;
45  }
46 
47  template <typename T, typename SizeFunction>
48  static SPECTRE_ALWAYS_INLINE size_t
49  get_size(const T& /*t*/, const SizeFunction /*size*/) noexcept {
50  return 1;
51  }
52 };
53 
54 template <>
55 struct GetImpls<false> {
56  template <typename T, typename SubscriptFunction>
57  static SPECTRE_ALWAYS_INLINE decltype(auto) get_element(
58  T& t, const size_t i, SubscriptFunction at) noexcept {
59  return at(t, i);
60  }
61 
62  template <typename T, typename SizeFunction>
63  static SPECTRE_ALWAYS_INLINE decltype(auto) get_size(
64  const T& t, SizeFunction size) noexcept {
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>
92  T& t, const size_t i,
93  SubscriptFunction at = GetContainerElement{}) noexcept {
94  return ContainerHelpers_detail::GetImpls<(
95  tt::is_complex_of_fundamental_v<std::remove_cv_t<T>> or
96  cpp17::is_fundamental_v<std::remove_cv_t<T>>)>::get_element(t, i, at);
97 }
98 
99 /*!
100  * \ingroup UtilitiesGroup
101  * \brief Retrieve the size of `t` if `t.size()` is a valid expression,
102  * otherwise if `T` is fundamental or a `std::complex` of a fundamental type,
103  * returns 1.
104  *
105  * \details This function also optionally takes the user-defined `size`
106  * function, which can be used to specify a custom size function. For
107  * instance, for a type which is a `std::array` of a `std::array`, the size
108  * function could be the below callable struct:
109  * \snippet Test_ContainerHelpers.cpp get_size_example_size_callable
110  *
111  * The `size` function must take the single argument of the applicable
112  * container, and should return a `size_t`. This follows the convention of
113  * `std::size()` as of C++17.
114  * \note `std::complex` are regarded as non-indexable (despite a predictable
115  * memory layout), so this function will return 1 for a `std::complex` of a
116  * fundamental type
117  */
118 template <typename T, typename SizeFunction = GetContainerSize>
120  const T& t, SizeFunction size = GetContainerSize{}) noexcept {
121  return ContainerHelpers_detail::GetImpls<(
122  tt::is_complex_of_fundamental_v<std::remove_cv_t<T>> or
123  cpp17::is_fundamental_v<std::remove_cv_t<T>>)>::get_size(t, size);
124 }
Callable struct which retrieves the t.size() for operand t. This will cause a compiler error if no su...
Definition: ContainerHelpers.hpp:17
decltype(auto) get_size(const T &t, SizeFunction size=GetContainerSize{}) noexcept
Retrieve the size of t if t.size() is a valid expression, otherwise if T is fundamental or a std::com...
Definition: ContainerHelpers.hpp:119
Defines the type alias Requires.
Definition: ContainerHelpers.hpp:34
#define SPECTRE_ALWAYS_INLINE
Always inline a function. Only use this if you benchmarked the code.
Definition: ForceInline.hpp:20
Defines macro to always inline a function.
Defines functions and classes from the GSL.
Callable struct for the subscript operator. Returns t[i]
Definition: ContainerHelpers.hpp:26
decltype(auto) get_element(T &t, const size_t i, SubscriptFunction at=GetContainerElement{}) noexcept
Returns the ith element if T has a subscript operator, otherwise if T is fundamental or a std::comple...
Definition: ContainerHelpers.hpp:91
constexpr T & at(std::array< T, N > &arr, Size index)
Retrieve a entry from a container, with checks in Debug mode that the index being retrieved is valid...
Definition: Gsl.hpp:124