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

Generated by: LCOV version 1.14