SpECTRE Documentation Coverage Report
Current view: top level - Elliptic/Utilities - ApplyAt.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 83.3 % 6 5
Test Date: 2026-10-22 17:29:42
Legend: Lines:     hit not hit

            Line data    Source code
       1            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              : 
      12              : #include "DataStructures/DataBox/DataBox.hpp"
      13              : #include "DataStructures/TaggedTuple.hpp"
      14              : #include "Utilities/ForceInline.hpp"
      15              : #include "Utilities/Gsl.hpp"
      16              : #include "Utilities/TMPL.hpp"
      17              : #include "Utilities/TupleSlice.hpp"
      18              : #include "Utilities/TypeTraits/CreateIsCallable.hpp"
      19              : #include "Utilities/TypeTraits/IsMaplike.hpp"
      20              : 
      21            0 : namespace elliptic::util {
      22              : namespace detail {
      23              : CREATE_IS_CALLABLE(apply)
      24              : CREATE_IS_CALLABLE_V(apply)
      25              : 
      26              : template <typename F, typename Args>
      27              : struct ApplyImpl;
      28              : 
      29              : template <typename F, typename... Args>
      30              : struct ApplyImpl<F, std::tuple<Args...>> {
      31              :   // Dispatch to static apply function or call operator, whichever is available
      32              :   static constexpr decltype(auto) apply(F&& f, Args&&... args) {
      33              :     if constexpr (is_apply_callable_v<F, Args...>) {
      34              :       return F::apply(std::forward<Args>(args)...);
      35              :     } else {
      36              :       return std::forward<F>(f)(std::forward<Args>(args)...);
      37              :     }
      38              :   }
      39              : };
      40              : 
      41              : template <bool PassThrough, typename... MapKeys>
      42              : struct unmap_arg;
      43              : 
      44              : template <typename... MapKeys>
      45              : struct unmap_arg<true, MapKeys...> {
      46              :   template <typename T>
      47              :   static constexpr const T& apply(const T& arg,
      48              :                                   const std::tuple<MapKeys...>& /*map_keys*/) {
      49              :     return arg;
      50              :   }
      51              : 
      52              :   template <typename T>
      53              :   static constexpr gsl::not_null<T*> apply(
      54              :       const gsl::not_null<T*> arg, const std::tuple<MapKeys...>& /*map_keys*/) {
      55              :     return arg;
      56              :   }
      57              : };
      58              : 
      59              : template <typename FirstMapKey, typename... MapKeys>
      60              : struct unmap_arg<false, FirstMapKey, MapKeys...> {
      61              :   template <typename T>
      62              :   static constexpr decltype(auto) apply(
      63              :       const T& arg, const std::tuple<FirstMapKey, MapKeys...>& map_keys) {
      64              :     return unmap_arg<((sizeof...(MapKeys) == 0) or
      65              :                       (not tt::is_maplike_v<typename T::mapped_type>)),
      66              :                      MapKeys...>::apply(arg.at(std::get<0>(map_keys)),
      67              :                                         tuple_tail<sizeof...(MapKeys)>(
      68              :                                             map_keys));
      69              :   }
      70              : 
      71              :   template <typename T>
      72              :   static constexpr decltype(auto) apply(
      73              :       const gsl::not_null<T*> arg,
      74              :       const std::tuple<FirstMapKey, MapKeys...>& map_keys) {
      75              :     return unmap_arg<((sizeof...(MapKeys) == 0) or
      76              :                       (not tt::is_maplike_v<typename T::mapped_type>)),
      77              :                      MapKeys...>::apply(make_not_null(&arg->
      78              :                                                        operator[](std::get<0>(
      79              :                                                            map_keys))),
      80              :                                         tuple_tail<sizeof...(MapKeys)>(
      81              :                                             map_keys));
      82              :   }
      83              : };
      84              : 
      85              : template <typename... ArgumentTags, typename PassthroughArgumentTags,
      86              :           typename F, typename TaggedContainer, typename... MapKeys,
      87              :           typename... Args>
      88              : SPECTRE_ALWAYS_INLINE decltype(auto) apply_at(
      89              :     F&& f, const TaggedContainer& box, const std::tuple<MapKeys...>& map_keys,
      90              :     tmpl::list<ArgumentTags...> /*meta*/, PassthroughArgumentTags /*meta*/,
      91              :     Args&&... args) {
      92              :   using ::db::apply;
      93              :   using ::tuples::apply;
      94              :   return apply<tmpl::list<ArgumentTags...>>(
      95              :       [&f, &map_keys, &args...](const auto&... args_items) {
      96              :         (void)map_keys;
      97              :         return std::forward<F>(f)(
      98              :             unmap_arg<
      99              :                 tmpl::list_contains_v<PassthroughArgumentTags, ArgumentTags>,
     100              :                 MapKeys...>::apply(args_items, map_keys)...,
     101              :             std::forward<Args>(args)...);
     102              :       },
     103              :       box);
     104              : }
     105              : 
     106              : }  // namespace detail
     107              : 
     108              : /// @{
     109              : /*!
     110              :  * \brief Apply the invokable `f` with arguments from maps in the DataBox
     111              :  *
     112              :  * Retrieves the `ArgumentTags` from the DataBox, evaluates them at the
     113              :  * `map_key(s)` (by calling their `at` member function for every map key in
     114              :  * turn) and calls the invokable `f` with the unmapped arguments. The tags in
     115              :  * `PassthroughArgumentTags` are passed directly to `f` without unmapping them.
     116              :  *
     117              :  * For example, a DataBox may have these tags of which two are maps:
     118              :  *
     119              :  * \snippet Test_ApplyAt.cpp apply_at_tags
     120              :  *
     121              :  * You can use `apply_at` to evaluate a function at a particular key for these
     122              :  * maps:
     123              :  *
     124              :  * \snippet Test_ApplyAt.cpp apply_at_example
     125              :  *
     126              :  * \see db::apply
     127              :  */
     128              : template <typename ArgumentTags, typename PassthroughArgumentTags,
     129              :           typename... MapKeys, typename F, typename TaggedContainer,
     130              :           typename... Args>
     131            1 : SPECTRE_ALWAYS_INLINE decltype(auto) apply_at(
     132              :     F&& f, const TaggedContainer& box, const std::tuple<MapKeys...>& map_keys,
     133              :     Args&&... args) {
     134              :   return detail::apply_at(std::forward<F>(f), box, map_keys, ArgumentTags{},
     135              :                           PassthroughArgumentTags{},
     136              :                           std::forward<Args>(args)...);
     137              : }
     138              : 
     139              : template <typename ArgumentTags, typename PassthroughArgumentTags,
     140              :           typename MapKey, typename F, typename TaggedContainer,
     141              :           typename... Args>
     142            1 : SPECTRE_ALWAYS_INLINE decltype(auto) apply_at(F&& f, const TaggedContainer& box,
     143              :                                               const MapKey& map_key,
     144              :                                               Args&&... args) {
     145              :   return detail::apply_at(
     146              :       std::forward<F>(f), box, std::forward_as_tuple(map_key), ArgumentTags{},
     147              :       PassthroughArgumentTags{}, std::forward<Args>(args)...);
     148              : }
     149              : /// @}
     150              : 
     151              : namespace detail {
     152              : 
     153              : template <typename... ReturnTags, typename... ArgumentTags,
     154              :           typename PassthroughTags, typename F, typename TaggedContainer,
     155              :           typename... MapKeys, typename... Args>
     156              : SPECTRE_ALWAYS_INLINE void mutate_apply_at(
     157              :     F&& f, const gsl::not_null<TaggedContainer*> box,
     158              :     const std::tuple<MapKeys...>& map_keys, tmpl::list<ReturnTags...> /*meta*/,
     159              :     tmpl::list<ArgumentTags...> /*meta*/, PassthroughTags /*meta*/,
     160              :     Args&&... args) {
     161              :   using ::db::apply;
     162              :   using ::db::mutate_apply;
     163              :   using ::tuples::apply;
     164              :   const auto args_items = apply<tmpl::list<ArgumentTags...>>(
     165              :       [](const auto&... expanded_args_items) {
     166              :         return std::forward_as_tuple(expanded_args_items...);
     167              :       },
     168              :       *box);
     169              :   using argument_tags = tmpl::list<ArgumentTags...>;
     170              :   mutate_apply<tmpl::list<ReturnTags...>, tmpl::list<>>(
     171              :       [&f, &map_keys, &args_items, &args...](const auto... mutated_items) {
     172              :         (void)map_keys;
     173              :         (void)args_items;
     174              :         auto all_args = std::tuple_cat(
     175              :             std::make_tuple(
     176              :                 unmap_arg<tmpl::list_contains_v<PassthroughTags, ReturnTags>,
     177              :                           MapKeys...>::apply(mutated_items, map_keys)...),
     178              :             std::forward_as_tuple(
     179              :                 unmap_arg<tmpl::list_contains_v<PassthroughTags, ArgumentTags>,
     180              :                           MapKeys...>::
     181              :                     apply(std::get<tmpl::index_of<argument_tags,
     182              :                                                   ArgumentTags>::value>(
     183              :                               args_items),
     184              :                           map_keys)...,
     185              :                 args...));
     186              :         std::apply(
     187              :             [&f](auto&&... expanded_args) {
     188              :               ApplyImpl<F, std::decay_t<decltype(all_args)>>::apply(
     189              :                   std::forward<F>(f), std::move(expanded_args)...);
     190              :             },
     191              :             std::move(all_args));
     192              :       },
     193              :       box);
     194              : }
     195              : 
     196              : }  // namespace detail
     197              : 
     198              : /// @{
     199              : /*!
     200              :  * \brief Apply the invokable `f` to mutate items in maps in the DataBox
     201              :  *
     202              :  * Retrieves the `MutateTags` and `ArgumentTags` from the DataBox, evaluates
     203              :  * them at the `map_key(s)` (by calling their `at` member function for every map
     204              :  * key in turn) and calls the invokable `f` with the unmapped arguments. The
     205              :  * tags in `PassthroughTags` are passed directly to `f` without unmapping them.
     206              :  *
     207              :  * For example, a DataBox may have these tags of which two are maps:
     208              :  *
     209              :  * \snippet Test_ApplyAt.cpp apply_at_tags
     210              :  *
     211              :  * You can use `mutate_apply_at` to mutate items at a particular key for these
     212              :  * maps:
     213              :  *
     214              :  * \snippet Test_ApplyAt.cpp mutate_apply_at_example
     215              :  *
     216              :  * \see db::mutate_apply
     217              :  */
     218              : template <typename MutateTags, typename ArgumentTags, typename PassthroughTags,
     219              :           typename F, typename TaggedContainer, typename... MapKeys,
     220              :           typename... Args>
     221            1 : SPECTRE_ALWAYS_INLINE void mutate_apply_at(
     222              :     F&& f, const gsl::not_null<TaggedContainer*> box,
     223              :     const std::tuple<MapKeys...>& map_keys, Args&&... args) {
     224              :   detail::mutate_apply_at(std::forward<F>(f), box, map_keys, MutateTags{},
     225              :                           ArgumentTags{}, PassthroughTags{},
     226              :                           std::forward<Args>(args)...);
     227              : }
     228              : 
     229              : template <typename MutateTags, typename ArgumentTags, typename PassthroughTags,
     230              :           typename F, typename TaggedContainer, typename MapKey,
     231              :           typename... Args>
     232            1 : SPECTRE_ALWAYS_INLINE void mutate_apply_at(
     233              :     F&& f, const gsl::not_null<TaggedContainer*> box, const MapKey& map_key,
     234              :     Args&&... args) {
     235              :   detail::mutate_apply_at(
     236              :       std::forward<F>(f), box, std::forward_as_tuple(map_key), MutateTags{},
     237              :       ArgumentTags{}, PassthroughTags{}, std::forward<Args>(args)...);
     238              : }
     239              : /// @}
     240              : 
     241              : }  // namespace elliptic::util
        

Generated by: LCOV version 2.0-1