SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/DataBox - Access.hpp Hit Total Coverage
Commit: 1f2210958b4f38fdc0400907ee7c6d5af5111418 Lines: 10 20 50.0 %
Date: 2025-12-05 05:03: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 <string>
       7             : #include <tuple>
       8             : 
       9             : #include "DataStructures/DataBox/DataBoxTag.hpp"
      10             : #include "DataStructures/DataBox/IsApplyCallable.hpp"
      11             : #include "DataStructures/DataBox/TagName.hpp"
      12             : #include "Utilities/CleanupRoutine.hpp"
      13             : #include "Utilities/ErrorHandling/Error.hpp"
      14             : #include "Utilities/ForceInline.hpp"
      15             : #include "Utilities/Gsl.hpp"
      16             : #include "Utilities/PrettyType.hpp"
      17             : #include "Utilities/TMPL.hpp"
      18             : #include "Utilities/TypeTraits/IsCallable.hpp"
      19             : 
      20           1 : namespace db {
      21             : /*!
      22             :  * \brief A class for retrieving items from a DataBox without needing to know
      23             :  * all the tags in the box.
      24             :  *
      25             :  * Retrieval is handled using a virtual function call but still uses Tags
      26             :  * rather than strings to ensure automatic handling of casting to the expected
      27             :  * type.
      28             :  */
      29           1 : class Access {
      30             :  public:
      31           0 :   virtual ~Access() = default;
      32             : 
      33             :   /// Print the expanded type aliases of the derived `db::DataBox`
      34           1 :   virtual std::string print_tags() const = 0;
      35             : 
      36             :   /// Print the expanded type aliases of the derived `db::DataBox`
      37           1 :   virtual std::string print_types() const = 0;
      38             : 
      39             :  private:
      40             :   template <typename Tag>
      41           1 :   friend const auto& get(const Access& box);
      42             :   template <typename... MutateTags, typename Invokable, typename... Args>
      43           0 :   friend decltype(auto) mutate(Invokable&& invokable,
      44             :                                gsl::not_null<Access*> box, Args&&... args);
      45           0 :   virtual void* mutate_item_by_name(const std::string& tag_name) = 0;
      46           0 :   virtual const void* get_item_by_name(const std::string& tag_name) const = 0;
      47           0 :   virtual bool lock_box_for_mutate() = 0;
      48           0 :   virtual void unlock_box_after_mutate() = 0;
      49           0 :   virtual void mutate_mutable_subitems(const std::string& tag_name) = 0;
      50           0 :   virtual void reset_compute_items_after_mutate(
      51             :       const std::string& tag_name) = 0;
      52             : 
      53             :   template <typename Tag>
      54           0 :   auto mutate() -> gsl::not_null<typename Tag::type*> {
      55             :     static const std::string tag_name = pretty_type::get_name<Tag>();
      56             :     return {
      57             :         // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
      58             :         reinterpret_cast<typename Tag::type*>(mutate_item_by_name(tag_name))};
      59             :   }
      60             : };
      61             : 
      62             : /// \brief Retrieve a tag from a `db::Access`
      63             : template <typename Tag>
      64           1 : SPECTRE_ALWAYS_INLINE const auto& get(const Access& box) {
      65             :   static const std::string tag_name = pretty_type::get_name<Tag>();
      66             :   if constexpr (tt::is_a_v<std::unique_ptr, typename Tag::type>) {
      67             :     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
      68             :     return *reinterpret_cast<const typename Tag::type::element_type*>(
      69             :         box.get_item_by_name(tag_name));
      70             :   } else {
      71             :     // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
      72             :     return *reinterpret_cast<const typename Tag::type*>(
      73             :         box.get_item_by_name(tag_name));
      74             :   }
      75             : }
      76             : 
      77             : /// \brief Mutate a tag in a `db::Access`.
      78             : template <typename... MutateTags, typename Invokable, typename... Args>
      79           1 : decltype(auto) mutate(Invokable&& invokable, const gsl::not_null<Access*> box,
      80             :                       Args&&... args) {
      81             :   if (UNLIKELY(box->lock_box_for_mutate())) {
      82             :     ERROR(
      83             :         "Unable to mutate a DataBox that is already being mutated. This "
      84             :         "error occurs when mutating a DataBox from inside the invokable "
      85             :         "passed to the mutate function.");
      86             :   }
      87             : 
      88             :   const CleanupRoutine unlock_box = [&box]() {
      89             :     box->unlock_box_after_mutate();
      90             :   };
      91             : 
      92             :   // Check that the arguments are fetchable before setting up the
      93             :   // cleanup so we don't trigger an error during stack unwinding.
      94             :   const std::tuple mutate_pointers{box->template mutate<MutateTags>()...};
      95             : 
      96             :   const CleanupRoutine reset_post_mutate = [&box]() {
      97             :     (void)box;
      98             :     EXPAND_PACK_LEFT_TO_RIGHT([&box]() {
      99             :       static const std::string tag_name = pretty_type::get_name<MutateTags>();
     100             :       box->mutate_mutable_subitems(tag_name);
     101             :       box->reset_compute_items_after_mutate(tag_name);
     102             :     }());
     103             :   };
     104             :   return std::apply(
     105             :       invokable,
     106             :       std::tuple_cat(mutate_pointers,
     107             :                      std::forward_as_tuple(std::forward<Args>(args)...)));
     108             : }
     109             : 
     110             : namespace detail {
     111             : template <typename... ReturnTags, typename... ArgumentTags, typename F,
     112             :           typename... Args>
     113             : SPECTRE_ALWAYS_INLINE constexpr decltype(auto) mutate_apply(
     114             :     F&& f, const gsl::not_null<Access*> box, tmpl::list<ReturnTags...> /*meta*/,
     115             :     tmpl::list<ArgumentTags...> /*meta*/, Args&&... args) {
     116             :   static_assert(not(... or std::is_same_v<ArgumentTags, Tags::DataBox>),
     117             :                 "Cannot pass Tags::DataBox to mutate_apply when mutating "
     118             :                 "since the db::get won't work inside mutate_apply.");
     119             :   if constexpr (detail::is_apply_callable_v<
     120             :                     F, const gsl::not_null<typename ReturnTags::type*>...,
     121             :                     const_item_type<ArgumentTags, tmpl::list<>>..., Args...>) {
     122             :     return ::db::mutate<ReturnTags...>(
     123             :         [](const gsl::not_null<typename ReturnTags::type*>... mutated_items,
     124             :            const_item_type<ArgumentTags, tmpl::list<>>... args_items,
     125             :            decltype(std::forward<Args>(args))... l_args) {
     126             :           return std::decay_t<F>::apply(mutated_items..., args_items...,
     127             :                                         std::forward<Args>(l_args)...);
     128             :         },
     129             :         box, db::get<ArgumentTags>(*box)..., std::forward<Args>(args)...);
     130             :   } else if constexpr (::tt::is_callable_v<
     131             :                            F,
     132             :                            const gsl::not_null<typename ReturnTags::type*>...,
     133             :                            const_item_type<ArgumentTags, tmpl::list<>>...,
     134             :                            Args...>) {
     135             :     return ::db::mutate<ReturnTags...>(f, box, db::get<ArgumentTags>(*box)...,
     136             :                                        std::forward<Args>(args)...);
     137             :   } else {
     138             :     error_function_not_callable<F, gsl::not_null<typename ReturnTags::type*>...,
     139             :                                 const_item_type<ArgumentTags, tmpl::list<>>...,
     140             :                                 Args...>();
     141             :   }
     142             : }
     143             : }  // namespace detail
     144             : 
     145             : /// @{
     146             : /*!
     147             :  * \ingroup DataBoxGroup
     148             :  * \brief Apply the invokable `f` mutating items `MutateTags` and taking as
     149             :  * additional arguments `ArgumentTags` and `args`.
     150             :  *
     151             :  * \details
     152             :  * `f` must either be invokable with the arguments of type
     153             :  * `gsl::not_null<db::item_type<MutateTags>*>...,
     154             :  * db::const_item_type<ArgumentTags>..., Args...`
     155             :  * where the first two pack expansions are over the elements in the typelists
     156             :  * `MutateTags` and `ArgumentTags`, or have a static `apply` function that is
     157             :  * callable with the same types. If the type of `f` specifies `return_tags` and
     158             :  * `argument_tags` typelists, these are used for the `MutateTags` and
     159             :  * `ArgumentTags`, respectively.
     160             :  *
     161             :  * Any return values of the invokable `f` are forwarded as returns to the
     162             :  * `mutate_apply` call.
     163             :  *
     164             :  * \example
     165             :  * An example of using `mutate_apply` with a lambda:
     166             :  * \snippet Test_DataBox.cpp mutate_apply_lambda_example
     167             :  *
     168             :  * An example of a class with a static `apply` function
     169             :  * \snippet Test_DataBox.cpp mutate_apply_struct_definition_example
     170             :  * and how to use `mutate_apply` with the above class
     171             :  * \snippet Test_DataBox.cpp mutate_apply_struct_example_stateful
     172             :  * Note that the class exposes `return_tags` and `argument_tags` typelists, so
     173             :  * we don't specify the template parameters explicitly.
     174             :  * If the class `F` has no state, like in this example,
     175             :  * \snippet Test_DataBox.cpp mutate_apply_struct_definition_example
     176             :  * you can also use the stateless overload of `mutate_apply`:
     177             :  * \snippet Test_DataBox.cpp mutate_apply_struct_example_stateless
     178             :  *
     179             :  * \tparam MutateTags typelist of Tags to mutate
     180             :  * \tparam ArgumentTags typelist of additional items to retrieve from the
     181             :  * `Access`
     182             :  * \tparam F The invokable to apply
     183             :  */
     184             : template <typename MutateTags, typename ArgumentTags, typename F,
     185             :           typename... Args>
     186           1 : SPECTRE_ALWAYS_INLINE constexpr decltype(auto) mutate_apply(
     187             :     F&& f, const gsl::not_null<Access*> box, Args&&... args) {
     188             :   return detail::mutate_apply(std::forward<F>(f), box, MutateTags{},
     189             :                               ArgumentTags{}, std::forward<Args>(args)...);
     190             : }
     191             : 
     192             : template <typename F, typename... Args>
     193           1 : SPECTRE_ALWAYS_INLINE constexpr decltype(auto) mutate_apply(
     194             :     F&& f, const gsl::not_null<Access*> box, Args&&... args) {
     195             :   return mutate_apply<typename std::decay_t<F>::return_tags,
     196             :                       typename std::decay_t<F>::argument_tags>(
     197             :       std::forward<F>(f), box, std::forward<Args>(args)...);
     198             : }
     199             : 
     200             : template <typename F, typename... Args>
     201           1 : SPECTRE_ALWAYS_INLINE constexpr decltype(auto) mutate_apply(
     202             :     const gsl::not_null<Access*> box, Args&&... args) {
     203             :   return mutate_apply(F{}, box, std::forward<Args>(args)...);
     204             : }
     205             : /// @}
     206             : }  // namespace db

Generated by: LCOV version 1.14