SpECTRE Documentation Coverage Report
Current view: top level - Domain - InterfaceHelpers.hpp Hit Total Coverage
Commit: d0fc80462417e83e5cddfa1b9901bb4a9b6af4d6 Lines: 3 7 42.9 %
Date: 2024-03-29 00:33:31
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <cstddef>
       7             : 
       8             : #include "DataStructures/DataBox/DataBox.hpp"
       9             : #include "DataStructures/DataBox/DataBoxTag.hpp"
      10             : #include "Domain/Structure/Direction.hpp"
      11             : #include "Domain/Structure/DirectionMap.hpp"
      12             : #include "Domain/Tags.hpp"
      13             : #include "Utilities/TMPL.hpp"
      14             : #include "Utilities/TypeTraits/CreateIsCallable.hpp"
      15             : 
      16             : namespace InterfaceHelpers_detail {
      17             : 
      18             : template <typename T, typename = std::void_t<>>
      19             : struct get_volume_tags_impl {
      20             :   using type = tmpl::list<>;
      21             : };
      22             : template <typename T>
      23             : struct get_volume_tags_impl<T, std::void_t<typename T::volume_tags>> {
      24             :   using type = typename T::volume_tags;
      25             : };
      26             : 
      27             : }  // namespace InterfaceHelpers_detail
      28             : 
      29             : /// Retrieve `T::volume_tags`, defaulting to an empty list
      30             : template <typename T>
      31           1 : using get_volume_tags =
      32             :     tmpl::type_from<InterfaceHelpers_detail::get_volume_tags_impl<T>>;
      33             : 
      34             : template <typename Tag, typename DirectionsTag, typename VolumeTags>
      35           0 : struct make_interface_tag {
      36           0 :   using type = tmpl::conditional_t<tmpl::list_contains_v<VolumeTags, Tag>, Tag,
      37             :                                    domain::Tags::Interface<DirectionsTag, Tag>>;
      38             : };
      39             : 
      40             : template <typename TagsList, typename DirectionsTag,
      41             :           typename VolumeTags = tmpl::list<>>
      42           0 : using make_interface_tags =
      43             :     tmpl::transform<TagsList,
      44             :                     make_interface_tag<tmpl::_1, tmpl::pin<DirectionsTag>,
      45             :                                        tmpl::pin<VolumeTags>>>;
      46             : 
      47             : namespace InterfaceHelpers_detail {
      48             : 
      49             : // Retrieve the `argument_tags` from the `InterfaceInvokable` and wrap them in
      50             : // `::Tags::Interface` if they are not listed in
      51             : // `InterfaceInvokable::volume_tags`.
      52             : template <typename InterfaceInvokable, typename DirectionsTag>
      53             : using get_interface_argument_tags = tmpl::transform<
      54             :     typename InterfaceInvokable::argument_tags,
      55             :     make_interface_tag<tmpl::_1, tmpl::pin<DirectionsTag>,
      56             :                        tmpl::pin<get_volume_tags<InterfaceInvokable>>>>;
      57             : 
      58             : /// Pull the direction's entry from interface arguments, passing volume
      59             : /// arguments through unchanged.
      60             : template <bool IsVolumeTag>
      61             : struct unmap_interface_args;
      62             : 
      63             : template <>
      64             : struct unmap_interface_args<true> {
      65             :   template <typename T>
      66             :   using f = T;
      67             : 
      68             :   template <size_t VolumeDim, typename T>
      69             :   static constexpr const T& apply(const ::Direction<VolumeDim>& /*direction*/,
      70             :                                   const T& arg) {
      71             :     return arg;
      72             :   }
      73             : };
      74             : 
      75             : template <>
      76             : struct unmap_interface_args<false> {
      77             :   template <typename T>
      78             :   using f = typename T::mapped_type;
      79             : 
      80             :   template <size_t VolumeDim, typename T>
      81             :   static constexpr decltype(auto) apply(const ::Direction<VolumeDim>& direction,
      82             :                                         const T& arg) {
      83             :     return arg.at(direction);
      84             :   }
      85             : };
      86             : 
      87             : CREATE_IS_CALLABLE(apply)
      88             : CREATE_IS_CALLABLE_V(apply)
      89             : 
      90             : template <bool HasStaticApply, typename InterfaceReturnType,
      91             :           typename DirectionsTag, typename VolumeTagsList,
      92             :           typename... ArgumentTags>
      93             : struct DispatchInterfaceInvokable;
      94             : 
      95             : template <typename InterfaceReturnType, typename DirectionsTag,
      96             :           typename VolumeTagsList, typename... ArgumentTags>
      97             : struct DispatchInterfaceInvokable<true, InterfaceReturnType, DirectionsTag,
      98             :                                   VolumeTagsList, ArgumentTags...> {
      99             :   template <typename InterfaceInvokable, typename DbTagsList,
     100             :             typename... ExtraArgs>
     101             :   static constexpr auto apply(InterfaceInvokable&& /*interface_invokable*/,
     102             :                               const db::DataBox<DbTagsList>& box,
     103             :                               ExtraArgs&&... extra_args) {
     104             :     DirectionMap<DirectionsTag::volume_dim, InterfaceReturnType> result{};
     105             :     for (const auto& direction : get<DirectionsTag>(box)) {
     106             :       auto interface_value = InterfaceInvokable::apply(
     107             :           unmap_interface_args<
     108             :               tmpl::list_contains_v<VolumeTagsList, ArgumentTags>>::
     109             :               apply(direction,
     110             :                     get<tmpl::type_from<make_interface_tag<
     111             :                         ArgumentTags, DirectionsTag, VolumeTagsList>>>(box))...,
     112             :           extra_args...);
     113             :       result.insert({direction, std::move(interface_value)});
     114             :     }
     115             :     return result;
     116             :   }
     117             : };
     118             : 
     119             : template <typename DirectionsTag, typename VolumeTagsList,
     120             :           typename... ArgumentTags>
     121             : struct DispatchInterfaceInvokable<true, void, DirectionsTag, VolumeTagsList,
     122             :                                   ArgumentTags...> {
     123             :   template <typename InterfaceInvokable, typename DbTagsList,
     124             :             typename... ExtraArgs>
     125             :   static constexpr void apply(InterfaceInvokable&& /*interface_invokable*/,
     126             :                               const db::DataBox<DbTagsList>& box,
     127             :                               ExtraArgs&&... extra_args) {
     128             :     for (const auto& direction : get<DirectionsTag>(box)) {
     129             :       InterfaceInvokable::apply(
     130             :           unmap_interface_args<
     131             :               tmpl::list_contains_v<VolumeTagsList, ArgumentTags>>::
     132             :               apply(direction,
     133             :                     get<tmpl::type_from<make_interface_tag<
     134             :                         ArgumentTags, DirectionsTag, VolumeTagsList>>>(box))...,
     135             :           extra_args...);
     136             :     }
     137             :   }
     138             : };
     139             : 
     140             : template <typename InterfaceReturnType, typename DirectionsTag,
     141             :           typename VolumeTagsList, typename... ArgumentTags>
     142             : struct DispatchInterfaceInvokable<false, InterfaceReturnType, DirectionsTag,
     143             :                                   VolumeTagsList, ArgumentTags...> {
     144             :   template <typename InterfaceInvokable, typename DbTagsList,
     145             :             typename... ExtraArgs>
     146             :   static constexpr auto apply(InterfaceInvokable&& interface_invokable,
     147             :                               const db::DataBox<DbTagsList>& box,
     148             :                               ExtraArgs&&... extra_args) {
     149             :     DirectionMap<DirectionsTag::volume_dim, InterfaceReturnType> result{};
     150             :     for (const auto& direction : get<DirectionsTag>(box)) {
     151             :       auto interface_value = interface_invokable(
     152             :           unmap_interface_args<
     153             :               tmpl::list_contains_v<VolumeTagsList, ArgumentTags>>::
     154             :               apply(direction,
     155             :                     get<tmpl::type_from<make_interface_tag<
     156             :                         ArgumentTags, DirectionsTag, VolumeTagsList>>>(box))...,
     157             :           extra_args...);
     158             :       result.insert({direction, std::move(interface_value)});
     159             :     }
     160             :     return result;
     161             :   }
     162             : };
     163             : 
     164             : template <typename DirectionsTag, typename VolumeTagsList,
     165             :           typename... ArgumentTags>
     166             : struct DispatchInterfaceInvokable<false, void, DirectionsTag, VolumeTagsList,
     167             :                                   ArgumentTags...> {
     168             :   template <typename InterfaceInvokable, typename DbTagsList,
     169             :             typename... ExtraArgs>
     170             :   static constexpr void apply(InterfaceInvokable&& interface_invokable,
     171             :                               const db::DataBox<DbTagsList>& box,
     172             :                               ExtraArgs&&... extra_args) {
     173             :     for (const auto& direction : get<DirectionsTag>(box)) {
     174             :       interface_invokable(
     175             :           unmap_interface_args<
     176             :               tmpl::list_contains_v<VolumeTagsList, ArgumentTags>>::
     177             :               apply(direction,
     178             :                     get<tmpl::type_from<make_interface_tag<
     179             :                         ArgumentTags, DirectionsTag, VolumeTagsList>>>(box))...,
     180             :           extra_args...);
     181             :     }
     182             :   }
     183             : };
     184             : 
     185             : template <typename DirectionsTag, typename ArgumentTags, typename VolumeTags>
     186             : struct InterfaceApplyImpl;
     187             : 
     188             : template <typename DirectionsTag, typename VolumeTagsList,
     189             :           typename... ArgumentTags>
     190             : struct InterfaceApplyImpl<DirectionsTag, tmpl::list<ArgumentTags...>,
     191             :                           VolumeTagsList> {
     192             :   static constexpr size_t volume_dim = DirectionsTag::volume_dim;
     193             : 
     194             :   template <
     195             :       typename InterfaceInvokable, typename DbTagsList, typename... ExtraArgs,
     196             :       Requires<is_apply_callable_v<
     197             :           InterfaceInvokable, db::const_item_type<ArgumentTags, DbTagsList>...,
     198             :           ExtraArgs...>> = nullptr>
     199             :   static constexpr auto apply(InterfaceInvokable&& interface_invokable,
     200             :                               const db::DataBox<DbTagsList>& box,
     201             :                               ExtraArgs&&... extra_args) {
     202             :     using interface_return_type =
     203             :         std::decay_t<decltype(InterfaceInvokable::apply(
     204             :             std::declval<db::const_item_type<ArgumentTags, DbTagsList>>()...,
     205             :             std::declval<ExtraArgs&&>()...))>;
     206             :     return DispatchInterfaceInvokable<true, interface_return_type,
     207             :                                       DirectionsTag, VolumeTagsList,
     208             :                                       ArgumentTags...>::
     209             :         apply(std::forward<InterfaceInvokable>(interface_invokable), box,
     210             :               std::forward<ExtraArgs>(extra_args)...);
     211             :   }
     212             : 
     213             :   template <
     214             :       typename InterfaceInvokable, typename DbTagsList, typename... ExtraArgs,
     215             :       Requires<not is_apply_callable_v<
     216             :           InterfaceInvokable, db::const_item_type<ArgumentTags, DbTagsList>...,
     217             :           ExtraArgs...>> = nullptr>
     218             :   static constexpr auto apply(InterfaceInvokable&& interface_invokable,
     219             :                               const db::DataBox<DbTagsList>& box,
     220             :                               ExtraArgs&&... extra_args) {
     221             :     using interface_return_type = std::decay_t<decltype(interface_invokable(
     222             :         std::declval<db::const_item_type<ArgumentTags, DbTagsList>>()...,
     223             :         std::declval<ExtraArgs&&>()...))>;
     224             :     return DispatchInterfaceInvokable<false, interface_return_type,
     225             :                                       DirectionsTag, VolumeTagsList,
     226             :                                       ArgumentTags...>::
     227             :         apply(std::forward<InterfaceInvokable>(interface_invokable), box,
     228             :               std::forward<ExtraArgs>(extra_args)...);
     229             :   }
     230             : };
     231             : 
     232             : }  // namespace InterfaceHelpers_detail
     233             : 
     234             : /// @{
     235             : /*!
     236             :  * \brief Apply an invokable to the `box` on all interfaces given by the
     237             :  * `DirectionsTag`.
     238             :  *
     239             :  * This function has an overload that takes an `interface_invokable` as its
     240             :  * first argument, and one that takes an `InterfaceInvokable` class as its first
     241             :  * template parameter instead. For the latter, the `InterfaceInvokable` class
     242             :  * must have a static `apply` function. The `interface_invokable` or static
     243             :  * `apply` function, respectively, is expected to be invokable with the types
     244             :  * held by the `ArgumentTags`, followed by the `extra_args`. The `ArgumentTags`
     245             :  * will be prefixed as `::Tags::Interface<DirectionsTag, ArgumentTag>` and thus
     246             :  * taken from the interface, except for those specified in the `VolumeTags`.
     247             :  *
     248             :  * This function returns a `DirectionMap` that holds the value returned by
     249             :  * the `interface_invokable` in every direction of the `DirectionsTag`.
     250             :  *
     251             :  * Here is an example how to use this function:
     252             :  *
     253             :  * \snippet Test_InterfaceHelpers.cpp interface_apply_example
     254             :  *
     255             :  * Here is another example how to use this function with a stateless invokable
     256             :  * class:
     257             :  *
     258             :  * \snippet Test_InterfaceHelpers.cpp interface_apply_example_stateless
     259             :  *
     260             :  * This is the class that defines the invokable in the example above:
     261             :  *
     262             :  * \snippet Test_InterfaceHelpers.cpp interface_invokable_example
     263             :  */
     264             : template <typename DirectionsTag, typename ArgumentTags, typename VolumeTags,
     265             :           typename InterfaceInvokable, typename DbTagsList,
     266             :           typename... ExtraArgs>
     267           1 : SPECTRE_ALWAYS_INLINE constexpr auto interface_apply(
     268             :     InterfaceInvokable&& interface_invokable,
     269             :     const db::DataBox<DbTagsList>& box, ExtraArgs&&... extra_args) {
     270             :   return InterfaceHelpers_detail::
     271             :       InterfaceApplyImpl<DirectionsTag, ArgumentTags, VolumeTags>::apply(
     272             :           std::forward<InterfaceInvokable>(interface_invokable), box,
     273             :           std::forward<ExtraArgs>(extra_args)...);
     274             : }
     275             : 
     276             : // The `box` argument to this function overload is not constrained to
     277             : // `db::DataBox` to work around an issue with GCC <= 8.
     278             : //
     279             : // Details on the issue:
     280             : //
     281             : // GCC <= 8 tries to instantiate the `db::DataBox<DbTagsList>` template even
     282             : // when this function overload is _not_ SFINAE-selected. In that case the
     283             : // template parameter substitution for `DbTagsList` may contain base tags that
     284             : // causes errors with the `db::DataBox` template instantiation.
     285             : template <typename DirectionsTag, typename InterfaceInvokable,
     286             :           typename DataBoxType, typename... ExtraArgs,
     287             :           // Needed to disambiguate the overloads
     288             :           typename ArgumentTags = typename InterfaceInvokable::argument_tags>
     289           1 : SPECTRE_ALWAYS_INLINE constexpr auto interface_apply(
     290             :     const DataBoxType& box, ExtraArgs&&... extra_args) {
     291             :   return interface_apply<DirectionsTag, ArgumentTags,
     292             :                          get_volume_tags<InterfaceInvokable>>(
     293             :       InterfaceInvokable{}, box, std::forward<ExtraArgs>(extra_args)...);
     294             : }
     295             : /// @}

Generated by: LCOV version 1.14