SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/DataBox - Access.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 50.0 % 20 10
Test Date: 2026-10-22 17:29:42
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 2.0-1