SpECTRE Documentation Coverage Report
Current view: top level - Elliptic/Utilities - ApplyAt.hpp Hit Total Coverage
Commit: 3c072f0ce967e2e56649d3fa12aa2a0e4fe2a42e Lines: 5 6 83.3 %
Date: 2024-04-23 20:50:18
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 "Utilities/ForceInline.hpp"
      14             : #include "Utilities/Gsl.hpp"
      15             : #include "Utilities/TMPL.hpp"
      16             : #include "Utilities/TaggedTuple.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             :   mutate_apply<tmpl::list<ReturnTags...>, tmpl::list<>>(
     170             :       [&f, &map_keys, &args_items, &args...](const auto... mutated_items) {
     171             :         (void)map_keys;
     172             :         (void)args_items;
     173             :         auto all_args = std::tuple_cat(
     174             :             std::make_tuple(
     175             :                 unmap_arg<tmpl::list_contains_v<PassthroughTags, ReturnTags>,
     176             :                           MapKeys...>::apply(mutated_items, map_keys)...),
     177             :             std::forward_as_tuple(
     178             :                 unmap_arg<tmpl::list_contains_v<PassthroughTags, ArgumentTags>,
     179             :                           MapKeys...>::
     180             :                     apply(std::get<tmpl::index_of<tmpl::list<ArgumentTags...>,
     181             :                                                   ArgumentTags>::value>(
     182             :                               args_items),
     183             :                           map_keys)...,
     184             :                 args...));
     185             :         std::apply(
     186             :             [&f](auto&&... expanded_args) {
     187             :               ApplyImpl<F, std::decay_t<decltype(all_args)>>::apply(
     188             :                   std::forward<F>(f), std::move(expanded_args)...);
     189             :             },
     190             :             std::move(all_args));
     191             :       },
     192             :       box);
     193             : }
     194             : 
     195             : }  // namespace detail
     196             : 
     197             : /// @{
     198             : /*!
     199             :  * \brief Apply the invokable `f` to mutate items in maps in the DataBox
     200             :  *
     201             :  * Retrieves the `MutateTags` and `ArgumentTags` from the DataBox, evaluates
     202             :  * them at the `map_key(s)` (by calling their `at` member function for every map
     203             :  * key in turn) and calls the invokable `f` with the unmapped arguments. The
     204             :  * tags in `PassthroughTags` are passed directly to `f` without unmapping them.
     205             :  *
     206             :  * For example, a DataBox may have these tags of which two are maps:
     207             :  *
     208             :  * \snippet Test_ApplyAt.cpp apply_at_tags
     209             :  *
     210             :  * You can use `mutate_apply_at` to mutate items at a particular key for these
     211             :  * maps:
     212             :  *
     213             :  * \snippet Test_ApplyAt.cpp mutate_apply_at_example
     214             :  *
     215             :  * \see db::mutate_apply
     216             :  */
     217             : template <typename MutateTags, typename ArgumentTags, typename PassthroughTags,
     218             :           typename F, typename TaggedContainer, typename... MapKeys,
     219             :           typename... Args>
     220           1 : SPECTRE_ALWAYS_INLINE void mutate_apply_at(
     221             :     F&& f, const gsl::not_null<TaggedContainer*> box,
     222             :     const std::tuple<MapKeys...>& map_keys, Args&&... args) {
     223             :   detail::mutate_apply_at(std::forward<F>(f), box, map_keys, MutateTags{},
     224             :                           ArgumentTags{}, PassthroughTags{},
     225             :                           std::forward<Args>(args)...);
     226             : }
     227             : 
     228             : template <typename MutateTags, typename ArgumentTags, typename PassthroughTags,
     229             :           typename F, typename TaggedContainer, typename MapKey,
     230             :           typename... Args>
     231           1 : SPECTRE_ALWAYS_INLINE void mutate_apply_at(
     232             :     F&& f, const gsl::not_null<TaggedContainer*> box, const MapKey& map_key,
     233             :     Args&&... args) {
     234             :   detail::mutate_apply_at(
     235             :       std::forward<F>(f), box, std::forward_as_tuple(map_key), MutateTags{},
     236             :       ArgumentTags{}, PassthroughTags{}, std::forward<Args>(args)...);
     237             : }
     238             : /// @}
     239             : 
     240             : }  // namespace elliptic::util

Generated by: LCOV version 1.14