ApplyAt.hpp
Go to the documentation of this file.
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 /// \file
5 /// Utilities to retrieve values from maps in tagged containers
6 
7 #pragma once
8 
9 #include <tuple>
10 #include <utility>
11 
14 #include "Utilities/Gsl.hpp"
15 #include "Utilities/TMPL.hpp"
16 #include "Utilities/TaggedTuple.hpp"
17 #include "Utilities/TupleSlice.hpp"
18 
19 namespace elliptic::util {
20 namespace detail {
21 
22 template <bool PassThrough, typename... MapKeys>
23 struct unmap_arg;
24 
25 template <typename... MapKeys>
26 struct unmap_arg<true, MapKeys...> {
27  template <typename T>
28  static constexpr const T& apply(
29  const T& arg, const std::tuple<MapKeys...>& /*map_keys*/) noexcept {
30  return arg;
31  }
32 
33  template <typename T>
34  static constexpr gsl::not_null<T*> apply(
35  const gsl::not_null<T*> arg,
36  const std::tuple<MapKeys...>& /*map_keys*/) noexcept {
37  return arg;
38  }
39 };
40 
41 template <typename FirstMapKey, typename... MapKeys>
42 struct unmap_arg<false, FirstMapKey, MapKeys...> {
43  template <typename T>
44  static constexpr decltype(auto) apply(
45  const T& arg,
46  const std::tuple<FirstMapKey, MapKeys...>& map_keys) noexcept {
47  return unmap_arg<sizeof...(MapKeys) == 0, MapKeys...>::apply(
48  arg.at(std::get<0>(map_keys)),
49  tuple_tail<sizeof...(MapKeys)>(map_keys));
50  }
51 
52  template <typename T>
53  static constexpr decltype(auto) apply(
54  const gsl::not_null<T*> arg,
55  const std::tuple<FirstMapKey, MapKeys...>& map_keys) noexcept {
56  return unmap_arg<sizeof...(MapKeys) == 0, MapKeys...>::apply(
57  make_not_null(&arg->operator[](std::get<0>(map_keys))),
58  tuple_tail<sizeof...(MapKeys)>(map_keys));
59  }
60 };
61 
62 template <typename... ArgumentTags, typename PassthroughArgumentTags,
63  typename F, typename TaggedContainer, typename... MapKeys,
64  typename... Args>
65 SPECTRE_ALWAYS_INLINE decltype(auto) apply_at(
66  F&& f, const TaggedContainer& box, const std::tuple<MapKeys...>& map_keys,
67  tmpl::list<ArgumentTags...> /*meta*/, PassthroughArgumentTags /*meta*/,
68  Args&&... args) noexcept {
69  using ::db::apply;
70  using ::tuples::apply;
71  return apply<tmpl::list<ArgumentTags...>>(
72  [&f, &map_keys, &args...](const auto&... args_items) noexcept {
73  (void)map_keys;
74  return std::forward<F>(f)(
75  unmap_arg<
76  tmpl::list_contains_v<PassthroughArgumentTags, ArgumentTags>,
77  MapKeys...>::apply(args_items, map_keys)...,
78  std::forward<Args>(args)...);
79  },
80  box);
81 }
82 
83 } // namespace detail
84 
85 /// @{
86 /*!
87  * \brief Apply the invokable `f` with arguments from maps in the DataBox
88  *
89  * Retrieves the `ArgumentTags` from the DataBox, evaluates them at the
90  * `map_key(s)` (by calling their `at` member function for every map key in
91  * turn) and calls the invokable `f` with the unmapped arguments. The tags in
92  * `PassthroughArgumentTags` are passed directly to `f` without unmapping them.
93  *
94  * For example, a DataBox may have these tags of which two are maps:
95  *
96  * \snippet Test_ApplyAt.cpp apply_at_tags
97  *
98  * You can use `apply_at` to evaluate a function at a particular key for these
99  * maps:
100  *
101  * \snippet Test_ApplyAt.cpp apply_at_example
102  *
103  * \see db::apply
104  */
105 template <typename ArgumentTags, typename PassthroughArgumentTags,
106  typename... MapKeys, typename F, typename TaggedContainer,
107  typename... Args>
108 SPECTRE_ALWAYS_INLINE decltype(auto) apply_at(
109  F&& f, const TaggedContainer& box, const std::tuple<MapKeys...>& map_keys,
110  Args&&... args) noexcept {
111  return detail::apply_at(std::forward<F>(f), box, map_keys, ArgumentTags{},
112  PassthroughArgumentTags{},
113  std::forward<Args>(args)...);
114 }
115 
116 template <typename ArgumentTags, typename PassthroughArgumentTags,
117  typename MapKey, typename F, typename TaggedContainer,
118  typename... Args>
119 SPECTRE_ALWAYS_INLINE decltype(auto) apply_at(F&& f, const TaggedContainer& box,
120  const MapKey& map_key,
121  Args&&... args) noexcept {
122  return detail::apply_at(
123  std::forward<F>(f), box, std::forward_as_tuple(map_key), ArgumentTags{},
124  PassthroughArgumentTags{}, std::forward<Args>(args)...);
125 }
126 /// @}
127 
128 namespace detail {
129 
130 template <typename... ReturnTags, typename... ArgumentTags,
131  typename PassthroughTags, typename F, typename TaggedContainer,
132  typename... MapKeys, typename... Args>
133 SPECTRE_ALWAYS_INLINE void mutate_apply_at(
134  F&& f, const gsl::not_null<TaggedContainer*> box,
135  const std::tuple<MapKeys...>& map_keys, tmpl::list<ReturnTags...> /*meta*/,
136  tmpl::list<ArgumentTags...> /*meta*/, PassthroughTags /*meta*/,
137  Args&&... args) noexcept {
138  using ::db::apply;
139  using ::db::mutate_apply;
140  using ::tuples::apply;
141  const auto args_items = apply<tmpl::list<ArgumentTags...>>(
142  [](const auto&... expanded_args_items) noexcept {
143  return std::forward_as_tuple(expanded_args_items...);
144  },
145  *box);
146  mutate_apply<tmpl::list<ReturnTags...>, tmpl::list<>>(
147  [&f, &map_keys, &args_items,
148  &args...](const auto... mutated_items) noexcept {
149  (void)map_keys;
150  (void)args_items;
151  std::forward<F>(f)(
152  unmap_arg<tmpl::list_contains_v<PassthroughTags, ReturnTags>,
153  MapKeys...>::apply(mutated_items, map_keys)...,
154  unmap_arg<tmpl::list_contains_v<PassthroughTags, ArgumentTags>,
155  MapKeys...>::
156  apply(std::get<tmpl::index_of<tmpl::list<ArgumentTags...>,
157  ArgumentTags>::value>(args_items),
158  map_keys)...,
159  std::forward<Args>(args)...);
160  },
161  box);
162 }
163 
164 } // namespace detail
165 
166 /// @{
167 /*!
168  * \brief Apply the invokable `f` to mutate items in maps in the DataBox
169  *
170  * Retrieves the `MutateTags` and `ArgumentTags` from the DataBox, evaluates
171  * them at the `map_key(s)` (by calling their `at` member function for every map
172  * key in turn) and calls the invokable `f` with the unmapped arguments. The
173  * tags in `PassthroughTags` are passed directly to `f` without unmapping them.
174  *
175  * For example, a DataBox may have these tags of which two are maps:
176  *
177  * \snippet Test_ApplyAt.cpp apply_at_tags
178  *
179  * You can use `mutate_apply_at` to mutate items at a particular key for these
180  * maps:
181  *
182  * \snippet Test_ApplyAt.cpp mutate_apply_at_example
183  *
184  * \see db::mutate_apply
185  */
186 template <typename MutateTags, typename ArgumentTags, typename PassthroughTags,
187  typename F, typename TaggedContainer, typename... MapKeys,
188  typename... Args>
189 SPECTRE_ALWAYS_INLINE void mutate_apply_at(
190  F&& f, const gsl::not_null<TaggedContainer*> box,
191  const std::tuple<MapKeys...>& map_keys, Args&&... args) noexcept {
192  detail::mutate_apply_at(std::forward<F>(f), box, map_keys, MutateTags{},
193  ArgumentTags{}, PassthroughTags{},
194  std::forward<Args>(args)...);
195 }
196 
197 template <typename MutateTags, typename ArgumentTags, typename PassthroughTags,
198  typename F, typename TaggedContainer, typename MapKey,
199  typename... Args>
200 SPECTRE_ALWAYS_INLINE void mutate_apply_at(
201  F&& f, const gsl::not_null<TaggedContainer*> box, const MapKey& map_key,
202  Args&&... args) noexcept {
203  detail::mutate_apply_at(
204  std::forward<F>(f), box, std::forward_as_tuple(map_key), MutateTags{},
205  ArgumentTags{}, PassthroughTags{}, std::forward<Args>(args)...);
206 }
207 /// @}
208 
209 } // namespace elliptic::util
std::apply
T apply(T... args)
utility
tuple
db::get
const auto & get(const DataBox< TagList > &box) noexcept
Retrieve the item with tag Tag from the DataBox.
Definition: DataBox.hpp:791
TupleSlice.hpp
DataBox.hpp
SPECTRE_ALWAYS_INLINE
#define SPECTRE_ALWAYS_INLINE
Definition: ForceInline.hpp:16
tuple_tail
constexpr auto tuple_tail(Tuple &&tuple) noexcept
Definition: TupleSlice.hpp:46
Gsl.hpp
ForceInline.hpp
make_not_null
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion,...
Definition: Gsl.hpp:880
gsl
Implementations from the Guideline Support Library.
Definition: ReadSpecPiecewisePolynomial.hpp:11
TMPL.hpp
gsl::not_null
Require a pointer to not be a nullptr
Definition: ReadSpecPiecewisePolynomial.hpp:13