SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/DataBox - DataBox.hpp Hit Total Coverage
Commit: 2068747df712b64688243d3254666212942d85f2 Lines: 43 85 50.6 %
Date: 2026-05-22 23:35:16
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             : /// Defines classes and functions used for manipulating DataBox's
       6             : 
       7             : #pragma once
       8             : 
       9             : #include <cstddef>
      10             : #include <exception>
      11             : #include <functional>
      12             : #include <initializer_list>
      13             : #include <map>
      14             : #include <ostream>
      15             : #include <pup.h>
      16             : #include <sstream>
      17             : #include <string>
      18             : #include <tuple>
      19             : #include <unordered_map>
      20             : #include <utility>
      21             : 
      22             : #include "DataStructures/DataBox/Access.hpp"
      23             : #include "DataStructures/DataBox/DataBoxTag.hpp"
      24             : #include "DataStructures/DataBox/IsApplyCallable.hpp"
      25             : #include "DataStructures/DataBox/Item.hpp"
      26             : #include "DataStructures/DataBox/MetavariablesTag.hpp"
      27             : #include "DataStructures/DataBox/SubitemTag.hpp"
      28             : #include "DataStructures/DataBox/Subitems.hpp"
      29             : #include "DataStructures/DataBox/TagName.hpp"
      30             : #include "DataStructures/DataBox/TagTraits.hpp"
      31             : #include "DataStructures/TaggedTuple.hpp"
      32             : #include "Utilities/CleanupRoutine.hpp"
      33             : #include "Utilities/ErrorHandling/Assert.hpp"
      34             : #include "Utilities/ErrorHandling/Error.hpp"
      35             : #include "Utilities/ErrorHandling/StaticAssert.hpp"
      36             : #include "Utilities/ForceInline.hpp"
      37             : #include "Utilities/Gsl.hpp"
      38             : #include "Utilities/NoSuchType.hpp"
      39             : #include "Utilities/PrintHelpers.hpp"
      40             : #include "Utilities/Serialization/Serialize.hpp"
      41             : #include "Utilities/StdHelpers.hpp"
      42             : #include "Utilities/TMPL.hpp"
      43             : #include "Utilities/TypeTraits.hpp"
      44             : #include "Utilities/TypeTraits/CreateIsCallable.hpp"
      45             : #include "Utilities/TypeTraits/IsA.hpp"
      46             : #include "Utilities/TypeTraits/IsCallable.hpp"
      47             : 
      48             : /*!
      49             :  * \ingroup DataBoxGroup
      50             :  * \brief Namespace for DataBox related things
      51             :  */
      52             : namespace db {
      53             : // Forward declarations
      54             : /// \cond
      55             : template <typename TagsList>
      56             : class DataBox;
      57             : /// \endcond
      58             : 
      59             : /// @{
      60             : /// \ingroup DataBoxGroup
      61             : /// Equal to `true` if `Tag` can be retrieved from a `DataBox` of type
      62             : /// `DataBoxType`.
      63             : template <typename Tag, typename DataBoxType>
      64           1 : using tag_is_retrievable =
      65             :     tmpl::or_<std::is_same<Tag, ::Tags::DataBox>,
      66             :               tmpl::any<typename DataBoxType::tags_list,
      67             :                         std::is_base_of<tmpl::pin<Tag>, tmpl::_1>>>;
      68             : 
      69             : template <typename Tag, typename DataBoxType>
      70           1 : constexpr bool tag_is_retrievable_v =
      71             :     tag_is_retrievable<Tag, DataBoxType>::value;
      72             : /// @}
      73             : 
      74             : namespace detail {
      75             : template <typename TagsList, typename Tag>
      76             : struct creation_tag_impl {
      77             :   DEBUG_STATIC_ASSERT(
      78             :       not has_no_matching_tag_v<TagsList, Tag>,
      79             :       "Found no tags in the DataBox that match the tag being retrieved.");
      80             :   DEBUG_STATIC_ASSERT(
      81             :       has_unique_matching_tag_v<TagsList, Tag>,
      82             :       "Found more than one tag in the DataBox that matches the tag "
      83             :       "being retrieved. This happens because more than one tag with the same "
      84             :       "base (class) tag was added to the DataBox.");
      85             :   using normalized_tag = first_matching_tag<TagsList, Tag>;
      86             :   // A list with 0 or 1 elements.  This uses `Tag` rather than
      87             :   // `normalized_tag` because subitems of compute tags normalize to
      88             :   // `Tags::Subitem<...>`, which is not what is in the `Subitems`
      89             :   // list.
      90             :   using parent_of_subitem = tmpl::filter<
      91             :       TagsList, tmpl::lazy::list_contains<Subitems<tmpl::_1>, tmpl::pin<Tag>>>;
      92             :   using type = tmpl::front<tmpl::push_back<parent_of_subitem, normalized_tag>>;
      93             : };
      94             : }  // namespace detail
      95             : 
      96             : /*!
      97             :  * \ingroup DataBoxGroup
      98             :  * \brief The tag added to \p Box referred to by \p Tag.  This
      99             :  * resolves base tags and converts subitems to full items.
     100             :  */
     101             : template <typename Tag, typename Box>
     102           1 : using creation_tag =
     103             :     typename detail::creation_tag_impl<typename Box::tags_list, Tag>::type;
     104             : 
     105             : namespace detail {
     106             : template <typename Tag>
     107             : using has_subitems =
     108             :     tmpl::not_<std::is_same<typename Subitems<Tag>::type, tmpl::list<>>>;
     109             : 
     110             : template <typename Tag>
     111             : constexpr bool has_subitems_v = has_subitems<Tag>::value;
     112             : 
     113             : template <typename Tag, typename ParentTag>
     114             : struct make_subitem_tag {
     115             :   using type = ::Tags::Subitem<Tag, ParentTag>;
     116             : };
     117             : 
     118             : template <typename Tag>
     119             : struct append_subitem_tags {
     120             :   using type = tmpl::push_front<typename db::Subitems<Tag>::type, Tag>;
     121             : };
     122             : 
     123             : template <typename ParentTag>
     124             :   requires(has_subitems_v<ParentTag> and is_immutable_item_tag_v<ParentTag>)
     125             : struct append_subitem_tags<ParentTag> {
     126             :   using type = tmpl::push_front<
     127             :       tmpl::transform<typename Subitems<ParentTag>::type,
     128             :                       make_subitem_tag<tmpl::_1, tmpl::pin<ParentTag>>>,
     129             :       ParentTag>;
     130             : };
     131             : 
     132             : template <typename Tag>
     133             :   requires(not has_subitems_v<Tag>)
     134             : struct append_subitem_tags<Tag> {
     135             :   using type = tmpl::list<Tag>;
     136             : };
     137             : 
     138             : template <typename TagsList>
     139             : using expand_subitems =
     140             :     tmpl::flatten<tmpl::transform<TagsList, append_subitem_tags<tmpl::_1>>>;
     141             : 
     142             : template <typename ComputeTag, typename ArgumentTag,
     143             :           typename FoundArgumentTagInBox>
     144             : struct report_missing_compute_item_argument {
     145             :   static_assert(std::is_same_v<ComputeTag, void>,
     146             :                 "A compute item's argument could not be found in the DataBox "
     147             :                 "or was found multiple times.  See the first template argument "
     148             :                 "of report_missing_compute_item_argument for the compute item "
     149             :                 "and the second for the missing (or duplicated) argument.");
     150             : };
     151             : 
     152             : template <typename ComputeTag, typename ArgumentTag>
     153             : struct report_missing_compute_item_argument<ComputeTag, ArgumentTag,
     154             :                                             std::true_type> {
     155             :   using type = void;
     156             : };
     157             : 
     158             : template <typename TagsList, typename ComputeTag>
     159             : struct create_compute_tag_argument_edges {
     160             : #ifdef SPECTRE_DEBUG
     161             :   using argument_check_assertion = tmpl::transform<
     162             :       typename ComputeTag::argument_tags,
     163             :       report_missing_compute_item_argument<
     164             :           tmpl::pin<ComputeTag>, tmpl::_1,
     165             :           has_unique_matching_tag<tmpl::pin<TagsList>, tmpl::_1>>>;
     166             : #endif  // SPECTRE_DEBUG
     167             :   // These edges record that a compute item's value depends on the
     168             :   // values of it's arguments.
     169             :   using type = tmpl::transform<
     170             :       typename ComputeTag::argument_tags,
     171             :       tmpl::bind<tmpl::edge,
     172             :                  tmpl::bind<first_matching_tag, tmpl::pin<TagsList>, tmpl::_1>,
     173             :                  tmpl::pin<ComputeTag>>>;
     174             : };
     175             : 
     176             : template <typename TagsList, typename ImmutableItemTagsList>
     177             : struct create_dependency_graph {
     178             :   using immutable_item_argument_edges =
     179             :       tmpl::join<tmpl::transform<ImmutableItemTagsList,
     180             :                                  detail::create_compute_tag_argument_edges<
     181             :                                      tmpl::pin<TagsList>, tmpl::_1>>>;
     182             :   using type = immutable_item_argument_edges;
     183             : };
     184             : }  // namespace detail
     185             : 
     186             : /*!
     187             :  * \ingroup DataBoxGroup
     188             :  * \brief A DataBox stores objects that can be retrieved by using Tags
     189             :  * \warning
     190             :  * The order of the tags in DataBoxes returned by db::create depends on
     191             :  * implementation-defined behavior, and therefore should not be specified in
     192             :  * source files. If explicitly naming a DataBox type is necessary they should be
     193             :  * generated using db::compute_databox_type.
     194             :  *
     195             :  * \see db::create
     196             :  *
     197             :  * @tparam Tags list of DataBoxTag's
     198             :  */
     199             : template <typename... Tags>
     200           1 : class DataBox<tmpl::list<Tags...>> : public Access,
     201             :                                      private detail::Item<Tags>... {
     202             :  public:
     203             :   /*!
     204             :    * \brief A typelist (`tmpl::list`) of Tags that the DataBox holds
     205             :    */
     206           1 :   using tags_list = tmpl::list<Tags...>;
     207             : 
     208             :   /// A list of all the immutable item tags, including their subitems.
     209             :   /// Immutable items are compute tags and reference tags.
     210           1 :   using immutable_item_tags =
     211             :       tmpl::filter<tags_list, db::is_immutable_item_tag<tmpl::_1>>;
     212             : 
     213             :   /// A list of all the immutable item tags used to create the DataBox
     214             :   ///
     215             :   /// \note This does not include subitems of immutable items
     216           1 :   using immutable_item_creation_tags =
     217             :       tmpl::remove_if<immutable_item_tags, tt::is_a<::Tags::Subitem, tmpl::_1>>;
     218             : 
     219             :   /// A list of all the mutable item tags, including their subitems
     220           1 :   using mutable_item_tags =
     221             :       tmpl::filter<tags_list, db::is_mutable_item_tag<tmpl::_1>>;
     222             : 
     223             :   /// A list of the expanded simple subitems, not including the main Subitem
     224             :   /// tags themselves.
     225             :   ///
     226             :   /// Specifically, if there is a `Variables<Tag0, Tag1>`, then this list would
     227             :   /// contain `Tag0, Tag1`.
     228           1 :   using mutable_subitem_tags = tmpl::flatten<
     229             :       tmpl::transform<mutable_item_tags, db::Subitems<tmpl::_1>>>;
     230             : 
     231             :   /// A list of all the mutable item tags used to create the DataBox
     232             :   ///
     233             :   /// \note This does not include subitems of mutable items
     234           1 :   using mutable_item_creation_tags =
     235             :       tmpl::list_difference<mutable_item_tags, mutable_subitem_tags>;
     236             : 
     237             :   /// A list of all the mutable tags that have subitems
     238           1 :   using mutable_item_parent_tags =
     239             :       tmpl::filter<mutable_item_creation_tags,
     240             :                    tmpl::bind<detail::has_subitems, tmpl::_1>>;
     241             : 
     242             :   /// A list of all the compute item tags
     243           1 :   using compute_item_tags =
     244             :       tmpl::filter<immutable_item_tags, db::is_compute_tag<tmpl::_1>>;
     245             : 
     246             :   /// A list of all the compute tags that have subitems
     247           1 :   using compute_item_parent_tags =
     248             :       tmpl::filter<compute_item_tags,
     249             :                    tmpl::bind<detail::has_subitems, tmpl::_1>>;
     250             : 
     251             :   /// A list of all the reference tags
     252           1 :   using reference_item_tags =
     253             :       tmpl::filter<immutable_item_tags, db::is_reference_tag<tmpl::_1>>;
     254             : 
     255             :   /// A list of all the reference tags that have subitems
     256           1 :   using reference_item_parent_tags =
     257             :       tmpl::filter<reference_item_tags,
     258             :                    tmpl::bind<detail::has_subitems, tmpl::_1>>;
     259             : 
     260             :   /// If it exists, the Parallel::Tags::MetavariablesImpl tag, otherwise
     261             :   /// NoSuchType
     262             :   ///
     263             :   /// This allows the type-erased Parallel::Tags::Metavariables
     264             :   /// to be used to fetch the metavariables
     265           1 :   using metavars_tag =
     266             :       typename detail::metavars_tag_impl<mutable_item_tags>::type;
     267             : 
     268             :   /// \cond
     269             :   /*!
     270             :    * \note the default constructor is only used for serialization
     271             :    */
     272             :   DataBox() = default;
     273             : 
     274             :   constexpr DataBox(DataBox&& rhs) : detail::Item<Tags>(std::move(rhs))... {
     275             :     reset_all_subitems();
     276             :   }
     277             :   constexpr DataBox& operator=(DataBox&& rhs) {
     278             :     if (&rhs != this) {
     279             :       ::expand_pack(
     280             :           (get_item<Tags>() = std::move(rhs.template get_item<Tags>()))...);
     281             :       reset_all_subitems();
     282             :     }
     283             :     return *this;
     284             :   }
     285             :   DataBox(const DataBox& rhs) = delete;
     286             :   DataBox& operator=(const DataBox& rhs) = delete;
     287             :   ~DataBox() override = default;
     288             : 
     289             :   /// \endcond
     290             : 
     291             :   /// Print the expanded type aliases
     292           1 :   std::string print_tags() const override;
     293             : 
     294             :   /// Print the expanded type aliases
     295           1 :   std::string print_types() const override;
     296             : 
     297             :   /// Print the items
     298             :   template <bool PrintImmutableItems = true>
     299           1 :   std::string print_items() const;
     300             : 
     301             :   /// The size in bytes of each item (excluding reference items)
     302           1 :   std::map<std::string, size_t> size_of_items() const;
     303             : 
     304             :   /// Retrieve the tag `Tag`, should be called by the free function db::get
     305             :   template <typename Tag>
     306           1 :   const auto& get() const;
     307             : 
     308             :   /// \brief Copy the items with tags `TagsOfItemsToCopy` from the DataBox
     309             :   /// into a TaggedTuple, should be called by the free function db::copy_items
     310             :   template <typename... TagsOfItemsToCopy>
     311           1 :   tuples::TaggedTuple<TagsOfItemsToCopy...> copy_items() const;
     312             : 
     313             :   /// Retrieve a mutable reference to the tag `Tag`, should be called
     314             :   /// by the free function db::get_mutable_reference
     315             :   template <typename Tag>
     316           1 :   auto& get_mutable_reference();
     317             : 
     318             :   /// Check whether a tags depends on another tag.  Should be called
     319             :   /// through the metafunction db::tag_depends_on.
     320             :   template <typename Consumer, typename Provider>
     321           1 :   constexpr static bool tag_depends_on();
     322             : 
     323             :   // NOLINTNEXTLINE(google-runtime-references)
     324           0 :   void pup(PUP::er& p) {
     325             :     // Only the mutable creation items are serialized.  Compute items are
     326             :     // initialized to unevaluated, and mutable subitems are reinitialized
     327             :     // cheaply.
     328             :     pup_impl(p, mutable_item_creation_tags{});
     329             :   }
     330             : 
     331             :   template <typename... AddMutableItemTags, typename AddImmutableItemTagsList,
     332             :             typename... Args>
     333           0 :   constexpr DataBox(tmpl::list<AddMutableItemTags...> /*meta*/,
     334             :                     AddImmutableItemTagsList /*meta*/, Args&&... args);
     335             : 
     336             :  private:
     337             :   template <typename CopiedItemsTagList, typename DbTagList>
     338             :   // clang-tidy: redundant declaration
     339           1 :   friend auto copy_items(const DataBox<DbTagList>& box);
     340             : 
     341             :   template <typename... MutateTags, typename TagList, typename Invokable,
     342             :             typename... Args>
     343             :   // clang-tidy: redundant declaration
     344           0 :   friend decltype(auto) mutate(Invokable&& invokable,
     345             :                                gsl::not_null<DataBox<TagList>*> box,  // NOLINT
     346             :                                Args&&... args);                       // NOLINT
     347             : 
     348             :   // evaluates the compute item corresponding to ComputeTag passing along
     349             :   // items fetched via ArgumentTags
     350             :   template <typename ComputeTag, typename... ArgumentTags>
     351           0 :   void evaluate_compute_item(tmpl::list<ArgumentTags...> /*meta*/) const;
     352             : 
     353             :   // retrieves the reference of the ReferenceTag passing along items fetched via
     354             :   // ArgumentTags
     355             :   template <typename ReferenceTag, typename... ArgumentTags>
     356           0 :   const auto& get_reference_item(tmpl::list<ArgumentTags...> /*meta*/) const;
     357             : 
     358             :   // get a constant reference to the item corresponding to Tag
     359             :   template <typename Tag>
     360           0 :   const auto& get_item() const {
     361             :     return static_cast<const detail::Item<Tag>&>(*this);
     362             :   }
     363             : 
     364             :   // get a mutable reference to the item corresponding to Tag
     365             :   template <typename Tag>
     366           0 :   auto& get_item() {
     367             :     return static_cast<detail::Item<Tag>&>(*this);
     368             :   }
     369             : 
     370             :   ////////////////////////////////////////////////////////////////
     371             :   // Data structure for runtime retrieval and mutation of tags.
     372           0 :   struct TagGraphs {
     373             :     std::unordered_map<std::string, const void* (DataBox::*)() const>
     374           0 :         tag_retrieval_functions{};
     375           0 :     std::unordered_map<std::string, std::vector<std::string>> tag_aliases{};
     376             :     std::unordered_map<std::string, std::vector<std::string>>
     377           0 :         tags_and_dependents{};
     378             :     std::unordered_map<std::string, bool (DataBox::*)()>
     379           0 :         tags_and_reset_functions{};
     380             :     std::unordered_map<std::string, std::vector<std::string>>
     381           0 :         parent_to_subitem_tags{};
     382           0 :     std::unordered_map<std::string, std::string> subitem_to_parent_tag{};
     383             :     std::unordered_map<std::string, void* (DataBox::*)()>
     384           0 :         tag_mutate_functions{};
     385             :     std::unordered_map<std::string, void (DataBox::*)()>
     386           0 :         mutate_mutable_subitems_functions{};
     387             :     std::unordered_map<std::string, void (DataBox::*)()>
     388           0 :         reset_compute_items_after_mutate_functions{};
     389             :   };
     390             : 
     391             :   /// \cond
     392             :   static const TagGraphs tag_graphs_;
     393             :   /// \endcond
     394           0 :   static TagGraphs compute_tag_graphs();
     395           0 :   void reset_compute_items(const std::string& item_name);
     396             :   template <typename MutatedTag>
     397           0 :   void reset_compute_items_after_mutate();
     398           0 :   void mutate_mutable_subitems(const std::string& tag_name) override;
     399           0 :   void reset_compute_items_after_mutate(const std::string& tag_name) override;
     400             :   template <typename Tag>
     401           0 :   const void* get_item_as_void_pointer() const;
     402             :   template <typename Tag>
     403           0 :   void* get_item_as_void_pointer_for_mutate();
     404           0 :   const void* get_item_by_name(const std::string& tag_name) const override;
     405           0 :   void* mutate_item_by_name(const std::string& tag_name) override;
     406           0 :   bool lock_box_for_mutate() override;
     407           0 :   void unlock_box_after_mutate() override;
     408             :   // End of runtime retrieval code
     409             :   ////////////////////////////////////////////////////////////////
     410             : 
     411             :   // copy item correspond to Tag
     412             :   template <typename Tag>
     413           0 :   auto copy_item() const;
     414             : 
     415             :   // copy items corresponding to CopiedItemsTags
     416             :   // from the DataBox to a TaggedTuple
     417             :   template <typename... CopiedItemsTags>
     418           0 :   tuples::TaggedTuple<CopiedItemsTags...> copy_items(
     419             :       tmpl::list<CopiedItemsTags...> /*meta*/) const;
     420             : 
     421             :   template <typename ParentTag>
     422           0 :   constexpr void add_mutable_subitems_to_box(tmpl::list<> /*meta*/) {}
     423             : 
     424             :   // add mutable items for the subitems of the item corresponding to ParentTag
     425             :   template <typename ParentTag, typename... SubitemTags>
     426           0 :   constexpr void add_mutable_subitems_to_box(
     427             :       tmpl::list<SubitemTags...> /*meta*/);
     428             : 
     429             :   // sets the mutable item corresponding to Tag with the ArgsIndex object in
     430             :   // items
     431             :   template <size_t ArgsIndex, typename Tag, typename... Ts>
     432           0 :   constexpr char add_mutable_item_to_box(std::tuple<Ts...>& items);
     433             : 
     434             :   // set the mutable items corresponding to AddMutableItemTags to the
     435             :   // appropriate objects from items, and checks the dependencies of the
     436             :   // immutable items corresponding to AddImmutableItemTags
     437             :   template <typename... Ts, typename... AddMutableItemTags,
     438             :             typename... AddImmutableItemTags, size_t... Is>
     439           0 :   void add_items_to_box(std::tuple<Ts...>& items,
     440             :                         tmpl::list<AddMutableItemTags...> /*meta*/,
     441             :                         std::index_sequence<Is...> /*meta*/,
     442             :                         tmpl::list<AddImmutableItemTags...> /*meta*/);
     443             : 
     444             :   // clang-tidy: no non-const references
     445             :   template <typename... MutableItemCreationTags>
     446           0 :   void pup_impl(PUP::er& p,  // NOLINT
     447             :                 tmpl::list<MutableItemCreationTags...> /*meta*/);
     448             : 
     449             :   // Mutating items in the DataBox
     450             :   template <typename ParentTag>
     451           0 :   constexpr void mutate_mutable_subitems(tmpl::list<> /*meta*/) {}
     452             : 
     453             :   template <typename ParentTag, typename... Subtags>
     454           0 :   constexpr void mutate_mutable_subitems(tmpl::list<Subtags...> /*meta*/);
     455             : 
     456             :   template <typename ParentTag>
     457           0 :   void mutate_mutable_subitems() {
     458             :     return mutate_mutable_subitems<ParentTag>(
     459             :         typename Subitems<ParentTag>::type{});
     460             :   }
     461             : 
     462           0 :   constexpr void reset_all_subitems();
     463             : 
     464             :   /// Returns `true` if the compute tag was evaluated before reset, `false` if
     465             :   /// it was not.
     466             :   template <typename ImmutableItemTag>
     467           1 :   bool reset_compute_item();
     468             :   // End mutating items in the DataBox
     469             : 
     470           0 :   using edge_list =
     471             :       typename detail::create_dependency_graph<tags_list,
     472             :                                                immutable_item_tags>::type;
     473             : 
     474           0 :   bool mutate_locked_box_{false};
     475             : };
     476             : 
     477             : /// \cond
     478             : template <typename... Tags>
     479             : const typename DataBox<tmpl::list<Tags...>>::TagGraphs
     480             :     DataBox<tmpl::list<Tags...>>::tag_graphs_ =
     481             :         DataBox<tmpl::list<Tags...>>::compute_tag_graphs();
     482             : 
     483             : template <typename... Tags>
     484             : std::string DataBox<tmpl::list<Tags...>>::print_tags() const {
     485             :   std::ostringstream os;
     486             :   os << "Simple tags("
     487             :      << tmpl::size<mutable_item_creation_tags>::value << ")  = [\n";
     488             :   tmpl::for_each<mutable_item_creation_tags>(
     489             :       [&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     490             :         os << "    " << pretty_type::get_name<Tag>() << ",\n";
     491             :       });
     492             :   os << "];\n";
     493             :   os << "Simple tags subitems(" << tmpl::size<mutable_subitem_tags>::value
     494             :      << ") = [\n";
     495             :   tmpl::for_each<mutable_subitem_tags>(
     496             :       [&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     497             :         os << "    " << pretty_type::get_name<Tag>() << ",\n";
     498             :       });
     499             :   os << "];\n";
     500             :   os << "Compute tags(" << tmpl::size<compute_item_tags>::value
     501             :      << ") = [\n";
     502             :   tmpl::for_each<compute_item_tags>(
     503             :       [&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     504             :         os << "    " << pretty_type::get_name<Tag>() << ",\n";
     505             :       });
     506             :   os << "];\n";
     507             :   os << "Reference tags(" << tmpl::size<reference_item_tags>::value
     508             :      << ") = [\n";
     509             :   tmpl::for_each<reference_item_tags>(
     510             :       [&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     511             :         os << "    " << pretty_type::get_name<Tag>() << ",\n";
     512             :       });
     513             :   os << "];\n";
     514             :   return os.str();
     515             : }
     516             : 
     517             : template <typename... Tags>
     518             : std::string DataBox<tmpl::list<Tags...>>::print_types() const {
     519             :   std::ostringstream os;
     520             :   os << "DataBox type aliases:\n";
     521             :   os << "using tags_list = [";
     522             :   tmpl::for_each<tags_list>([&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     523             :     os << "  " << pretty_type::get_name<Tag>() << ",\n";
     524             :   });
     525             :   os << "];\n";
     526             :   os << "using immutable_item_tags = [";
     527             :   tmpl::for_each<immutable_item_tags>(
     528             :       [&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     529             :         os << "  " << pretty_type::get_name<Tag>() << ",\n";
     530             :       });
     531             :   os << "];\n";
     532             :   os << "using immutable_item_creation_tags = [";
     533             :   tmpl::for_each<immutable_item_creation_tags>(
     534             :       [&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     535             :         os << "  " << pretty_type::get_name<Tag>() << ",\n";
     536             :       });
     537             :   os << "];\n";
     538             :   os << "using mutable_item_tags = [";
     539             :   tmpl::for_each<mutable_item_tags>(
     540             :       [&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     541             :         os << "  " << pretty_type::get_name<Tag>() << ",\n";
     542             :       });
     543             :   os << "];\n";
     544             :   os << "using mutable_subitem_tags = [";
     545             :   tmpl::for_each<mutable_subitem_tags>(
     546             :       [&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     547             :         os << "  " << pretty_type::get_name<Tag>() << ",\n";
     548             :       });
     549             :   os << "];\n";
     550             :   os << "using compute_item_tags = [";
     551             :   tmpl::for_each<compute_item_tags>(
     552             :       [&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     553             :         os << "  " << pretty_type::get_name<Tag>() << ",\n";
     554             :       });
     555             :   os << "];\n";
     556             :   os << "using reference_item_tags = [";
     557             :   tmpl::for_each<reference_item_tags>(
     558             :       [&os]<class Tag>(const tmpl::type_<Tag> /*meta*/) {
     559             :         os << "  " << pretty_type::get_name<Tag>() << ",\n";
     560             :       });
     561             :   os << "];\n";
     562             :   os << "using edge_list = " << pretty_type::get_name<edge_list>() << ";\n";
     563             :   return os.str();
     564             : }
     565             : 
     566             : template <typename... Tags>
     567             : template <bool PrintImmutableItems>
     568             : std::string DataBox<tmpl::list<Tags...>>::print_items() const {
     569             :   std::ostringstream os;
     570             :   os << "Items:\n";
     571             :   const auto print_item = [this, &os](auto tag_v) {
     572             :     (void)this;
     573             :     using tag = tmpl::type_from<decltype(tag_v)>;
     574             :     using type = typename tag::type;
     575             :     os << "----------\n";
     576             :     os << "Name:  " << pretty_type::get_name<tag>() << "\n";
     577             :     os << "Type:  " << pretty_type::get_name<type>() << "\n";
     578             :     os << "Value: ";
     579             :     print_value(os, this->get<tag>());
     580             :     os << "\n";
     581             :   };
     582             :   tmpl::for_each<mutable_item_creation_tags>(print_item);
     583             :   if constexpr (PrintImmutableItems) {
     584             :     tmpl::for_each<immutable_item_creation_tags>(print_item);
     585             :   }
     586             :   return os.str();
     587             : }
     588             : 
     589             : template <typename... Tags>
     590             : std::map<std::string, size_t> DataBox<tmpl::list<Tags...>>::size_of_items()
     591             :     const {
     592             :   std::map<std::string, size_t> result{};
     593             :   const auto add_item_size = [this, &result](auto tag_v) {
     594             :     (void)this;
     595             :     using tag = tmpl::type_from<decltype(tag_v)>;
     596             :     if constexpr (not db::is_reference_tag_v<tag>) {
     597             :       // For item of ItemType::Compute, this will not evaluate its function
     598             :       // (i.e. if the item has never been evaluated its size will be that of a
     599             :       // default initialized object)
     600             :       const auto& item = get_item<tag>().get();
     601             :       if constexpr (tt::is_a_v<std::unique_ptr, typename tag::type>) {
     602             :         if (item == nullptr) {
     603             :           result[pretty_type::get_name<tag>()] = 0;
     604             :         } else {
     605             :           result[pretty_type::get_name<tag>()] = size_of_object_in_bytes(*item);
     606             :         }
     607             :       } else {
     608             :         result[pretty_type::get_name<tag>()] = size_of_object_in_bytes(item);
     609             :       }
     610             :     }
     611             :   };
     612             :   tmpl::for_each<mutable_item_creation_tags>(add_item_size);
     613             :   tmpl::for_each<immutable_item_creation_tags>(add_item_size);
     614             :   return result;
     615             : }
     616             : 
     617             : namespace detail {
     618             : // This function exists so that the user can look at the template
     619             : // arguments to find out what triggered the static_assert.
     620             : template <typename ImmutableItemTag, typename ArgumentTag, typename TagsList>
     621             : constexpr char check_immutable_item_tag_dependency() {
     622             :   using immutable_item_tag_index = tmpl::index_of<TagsList, ImmutableItemTag>;
     623             :   static_assert(
     624             :       std::is_same_v<ArgumentTag, Parallel::Tags::Metavariables> or
     625             :           tmpl::less<
     626             :               tmpl::index_if<TagsList,
     627             :                              std::is_same<tmpl::pin<ArgumentTag>, tmpl::_1>,
     628             :                              immutable_item_tag_index>,
     629             :               immutable_item_tag_index>::value,
     630             :       "The argument_tags of an immutable item tag must be added before itself. "
     631             :       "This is done to ensure no cyclic dependencies arise.  See the first and "
     632             :       "second template arguments of check_immutable_item_tag_dependency for "
     633             :       "the immutable item tag and its missing (or incorrectly added) argument "
     634             :       "tag.  The third template argument is the TagsList of the DataBox (in "
     635             :       "which the argument tag should precede the immutable item tag)");
     636             :   return '0';
     637             : }
     638             : 
     639             : template <typename ImmutableItemTag, typename TagsList,
     640             :           typename... ArgumentsTags>
     641             : SPECTRE_ALWAYS_INLINE constexpr void check_immutable_item_tag_dependencies_impl(
     642             :     tmpl::list<ArgumentsTags...> /*meta*/) {
     643             :   DEBUG_STATIC_ASSERT(
     644             :       tmpl2::flat_all_v<is_tag_v<ArgumentsTags>...>,
     645             :       "Cannot have non-DataBoxTag arguments to a ComputeItem or ReferenceItem. "
     646             :       "Please make sure all the specified argument_tags derive from "
     647             :       "db::SimpleTag or are the special tag Parallel::Tags::Metavariables.");
     648             :   DEBUG_STATIC_ASSERT(
     649             :       not tmpl2::flat_any_v<std::is_same_v<ArgumentsTags, ImmutableItemTag>...>,
     650             :       "A ComputeItem cannot take its own Tag as an argument.");
     651             :   expand_pack(detail::check_immutable_item_tag_dependency<
     652             :               ImmutableItemTag, ArgumentsTags, TagsList>()...);
     653             : }
     654             : 
     655             : template <typename ImmutableItemTag, typename TagsList>
     656             : SPECTRE_ALWAYS_INLINE constexpr void check_immutable_item_tag_dependencies() {
     657             :   check_immutable_item_tag_dependencies_impl<ImmutableItemTag, TagsList>(
     658             :       tmpl::transform<typename ImmutableItemTag::argument_tags,
     659             :                       tmpl::bind<detail::first_matching_tag,
     660             :                                  tmpl::pin<TagsList>, tmpl::_1>>{});
     661             : }
     662             : }  // namespace detail
     663             : 
     664             : template <typename... Tags>
     665             : template <typename ParentTag, typename... SubitemTags>
     666             : SPECTRE_ALWAYS_INLINE constexpr void
     667             : db::DataBox<tmpl::list<Tags...>>::add_mutable_subitems_to_box(
     668             :     tmpl::list<SubitemTags...> /*meta*/) {
     669             :   const auto add_mutable_subitem_to_box = [this](auto tag_v) {
     670             :     (void)this;  // Compiler bug warns this is unused
     671             :     using subitem_tag = decltype(tag_v);
     672             :     get_item<subitem_tag>() =
     673             :         detail::Item<subitem_tag>(typename subitem_tag::type{});
     674             :     Subitems<ParentTag>::template create_item<subitem_tag>(
     675             :         make_not_null(&get_item<ParentTag>().mutate()),
     676             :         make_not_null(&get_item<subitem_tag>().mutate()));
     677             :   };
     678             : 
     679             :   EXPAND_PACK_LEFT_TO_RIGHT(add_mutable_subitem_to_box(SubitemTags{}));
     680             : }
     681             : 
     682             : template <typename... Tags>
     683             : template <size_t ArgsIndex, typename MutableItemTag, typename... Ts>
     684             : SPECTRE_ALWAYS_INLINE constexpr char
     685             : db::DataBox<tmpl::list<Tags...>>::add_mutable_item_to_box(
     686             :     std::tuple<Ts...>& items) {
     687             :   if constexpr (sizeof...(Ts) > 0) {
     688             :     using ArgType = std::tuple_element_t<ArgsIndex, std::tuple<Ts...>>;
     689             :     get_item<MutableItemTag>() = detail::Item<MutableItemTag>(
     690             :         std::forward<ArgType>(std::get<ArgsIndex>(items)));
     691             :   }
     692             :   add_mutable_subitems_to_box<MutableItemTag>(
     693             :       typename Subitems<MutableItemTag>::type{});
     694             :   return '0';  // must return in constexpr function
     695             : }
     696             : 
     697             : // Add items or compute items to the TaggedDeferredTuple `data`. If
     698             : // `AddItemTags...` is an empty pack then only compute items are added, while if
     699             : // `AddComputeTags...` is an empty pack only items are added. Items are
     700             : // always added before compute items.
     701             : template <typename... Tags>
     702             : template <typename... Ts, typename... AddMutableItemTags,
     703             :           typename... AddImmutableItemTags, size_t... Is>
     704             : SPECTRE_ALWAYS_INLINE void DataBox<tmpl::list<Tags...>>::add_items_to_box(
     705             :     std::tuple<Ts...>& items, tmpl::list<AddMutableItemTags...> /*meta*/,
     706             :     std::index_sequence<Is...> /*meta*/,
     707             :     tmpl::list<AddImmutableItemTags...> /*meta*/) {
     708             :   expand_pack(add_mutable_item_to_box<Is, AddMutableItemTags>(items)...);
     709             :   EXPAND_PACK_LEFT_TO_RIGHT(
     710             :       detail::check_immutable_item_tag_dependencies<AddImmutableItemTags,
     711             :                                                     tags_list>());
     712             : }
     713             : 
     714             : namespace detail {
     715             : // This function (and its unused template argument) exist so that
     716             : // users can see what tag has the wrong type when the static_assert
     717             : // fails.
     718             : template <typename Tag, typename TagType, typename SuppliedType>
     719             : constexpr int check_initialization_argument_type() {
     720             :   static_assert(std::is_same_v<TagType, SuppliedType>,
     721             :                 "The type of each Tag must be the same as the type being "
     722             :                 "passed into the function creating the new DataBox.  See the "
     723             :                 "template parameters of check_initialization_argument_type for "
     724             :                 "the tag, expected type, and supplied type.");
     725             :   return 0;
     726             : }
     727             : }  // namespace detail
     728             : 
     729             : template <typename... Tags>
     730             : template <typename... AddMutableItemTags, typename AddImmutableItemTagsList,
     731             :           typename... Args>
     732             : constexpr DataBox<tmpl::list<Tags...>>::DataBox(
     733             :     tmpl::list<AddMutableItemTags...> /*meta*/,
     734             :     AddImmutableItemTagsList /*meta*/, Args&&... args) {
     735             :   DEBUG_STATIC_ASSERT(
     736             :       sizeof...(Args) == 0 or sizeof...(Args) == sizeof...(AddMutableItemTags),
     737             :       "Must pass in as many arguments as AddTags, or none to "
     738             :       "default-construct them.");
     739             : #ifdef SPECTRE_DEBUG
     740             :   if constexpr (sizeof...(Args) > 0) {
     741             :     // The check_argument_type call is very expensive compared to the majority
     742             :     // of DataBox
     743             :     expand_pack(detail::check_initialization_argument_type<
     744             :                 AddMutableItemTags, typename AddMutableItemTags::type,
     745             :                 std::decay_t<Args>>()...);
     746             :   }
     747             : #endif  // SPECTRE_DEBUG
     748             : 
     749             :   std::tuple<Args&&...> args_tuple(std::forward<Args>(args)...);
     750             :   add_items_to_box(args_tuple, tmpl::list<AddMutableItemTags...>{},
     751             :                    std::make_index_sequence<sizeof...(AddMutableItemTags)>{},
     752             :                    AddImmutableItemTagsList{});
     753             : }
     754             : 
     755             : ////////////////////////////////////////////////////////////////
     756             : // Serialization of DataBox
     757             : 
     758             : template <typename... Tags>
     759             : template <typename... MutableItemCreationTags>
     760             : void DataBox<tmpl::list<Tags...>>::pup_impl(
     761             :     PUP::er& p, tmpl::list<MutableItemCreationTags...> /*meta*/) {
     762             :   const auto pup_simple_item = [&p, this](auto current_tag) {
     763             :     (void)this;  // Compiler bug warning this capture is not used
     764             :     using tag = decltype(current_tag);
     765             :     get_item<tag>().pup(p);
     766             :     if (p.isUnpacking()) {
     767             :       add_mutable_subitems_to_box<tag>(typename Subitems<tag>::type{});
     768             :     }
     769             :   };
     770             :   (void)pup_simple_item;  // Silence GCC warning about unused variable
     771             :   EXPAND_PACK_LEFT_TO_RIGHT(pup_simple_item(MutableItemCreationTags{}));
     772             : }
     773             : 
     774             : ////////////////////////////////////////////////////////////////
     775             : // Runtime tag retrieval
     776             : namespace detail {
     777             : template <typename MappedPtr>
     778             : void set_or_null_if_ambiguous(
     779             :     const gsl::not_null<std::unordered_map<std::string, MappedPtr>*> map,
     780             :     const std::string& key, const MappedPtr value) {
     781             :   const auto [entry, added] = map->emplace(key, value);
     782             :   if (not added and entry->second != value) {
     783             :     entry->second = nullptr;
     784             :   }
     785             : }
     786             : 
     787             : template <typename Tag, typename... Others>
     788             : struct tag_and_bases {
     789             :   using type = tmpl::list<Tag, Others...>;
     790             : };
     791             : 
     792             : template <typename Tag, typename... Others>
     793             :   requires requires { typename Tag::base; }
     794             : struct tag_and_bases<Tag, Others...>
     795             :     : tag_and_bases<typename Tag::base, Tag, Others...> {};
     796             : }  // namespace detail
     797             : 
     798             : template <typename... Tags>
     799             : auto DataBox<tmpl::list<Tags...>>::compute_tag_graphs() -> TagGraphs {
     800             :   TagGraphs result{};
     801             :   // Compute graphs for retrieving tags
     802             :   const auto process_tag = [&result]<typename ConcreteTag>(
     803             :                                tmpl::type_<ConcreteTag> /*meta*/) {
     804             :     const std::string concrete_tag_name = pretty_type::get_name<ConcreteTag>();
     805             :     tmpl::for_each<typename detail::tag_and_bases<ConcreteTag>::type>(
     806             :         [&]<typename Tag>(tmpl::type_<Tag> /*meta*/) {
     807             :           const std::string tag_name = pretty_type::get_name<Tag>();
     808             :           detail::set_or_null_if_ambiguous(
     809             :               make_not_null(&result.tag_retrieval_functions), tag_name,
     810             :               &DataBox::template get_item_as_void_pointer<ConcreteTag>);
     811             :           result.tag_aliases[concrete_tag_name].push_back(tag_name);
     812             :         });
     813             :   };
     814             :   (void)process_tag;
     815             :   EXPAND_PACK_LEFT_TO_RIGHT(process_tag(tmpl::type_<Tags>{}));
     816             : 
     817             :   // Compute graphs for resetting compute tags
     818             :   //
     819             :   //
     820             :   // Subitems are a bit tricky. We need:
     821             :   // - If a parent tag is mutated, need to track through all subitems
     822             :   // - If a subitem is mutated, need to track through parent tag and all
     823             :   //   subitems
     824             :   tmpl::for_each<
     825             :       tmpl::append<mutable_item_parent_tags, reference_item_parent_tags,
     826             :                    compute_item_parent_tags>>([&result](auto tag_v) {
     827             :     using parent_tag = tmpl::type_from<decltype(tag_v)>;
     828             :     using subitems = typename Subitems<parent_tag>::type;
     829             :     const std::string parent_tag_name = pretty_type::get_name<parent_tag>();
     830             :     const std::vector<std::string> subitem_tag_names =
     831             :         pretty_type::vector_of_get_names(subitems{});
     832             :     for (const std::string& subitem_name : subitem_tag_names) {
     833             :       result.parent_to_subitem_tags[parent_tag_name].push_back(subitem_name);
     834             :       ASSERT(result.subitem_to_parent_tag.find(subitem_name) ==
     835             :                  result.subitem_to_parent_tag.end(),
     836             :              "Trying to insert subitem tag "
     837             :                  << subitem_name
     838             :                  << " for a second time. This is an "
     839             :                     "internal inconsistency bug.\n");
     840             :       result.subitem_to_parent_tag[subitem_name] = parent_tag_name;
     841             :     }
     842             :   });
     843             : 
     844             :   tmpl::for_each<tmpl::append<reference_item_tags, compute_item_tags>>(
     845             :       [&result](auto tag_v) {
     846             :         using compute_tag = tmpl::type_from<decltype(tag_v)>;
     847             :         const std::string tag_name = pretty_type::get_name<compute_tag>();
     848             :         const std::vector<std::string> argument_tags =
     849             :             pretty_type::vector_of_get_names(
     850             :                 typename compute_tag::argument_tags{});
     851             :         for (const std::string& argument_tag : argument_tags) {
     852             :           result.tags_and_dependents[argument_tag].push_back(tag_name);
     853             :         }
     854             :         result.tags_and_reset_functions[tag_name] =
     855             :             &DataBox::template reset_compute_item<compute_tag>;
     856             :       });
     857             : 
     858             :   // Set mutation function
     859             :   tmpl::for_each<mutable_item_tags>([&result]<typename MutableTag>(
     860             :                                         tmpl::type_<MutableTag> /*meta*/) {
     861             :     tmpl::for_each<typename detail::tag_and_bases<MutableTag>::type>(
     862             :         [&result]<typename Tag>(tmpl::type_<Tag> /*meta*/) {
     863             :           const std::string tag_name = pretty_type::get_name<Tag>();
     864             :           detail::set_or_null_if_ambiguous(
     865             :               make_not_null(&result.tag_mutate_functions), tag_name,
     866             :               &DataBox::template get_item_as_void_pointer_for_mutate<
     867             :                   MutableTag>);
     868             :           detail::set_or_null_if_ambiguous(
     869             :               make_not_null(&result.mutate_mutable_subitems_functions),
     870             :               tag_name,
     871             :               static_cast<void (DataBox::*)()>(
     872             :                   &DataBox::template mutate_mutable_subitems<MutableTag>));
     873             :           detail::set_or_null_if_ambiguous(
     874             :               make_not_null(&result.reset_compute_items_after_mutate_functions),
     875             :               tag_name,
     876             :               &DataBox::template reset_compute_items_after_mutate<MutableTag>);
     877             :         });
     878             :   });
     879             :   return result;
     880             : }
     881             : 
     882             : template <typename... Tags>
     883             : void DataBox<tmpl::list<Tags...>>::reset_compute_items(
     884             :     const std::string& item_name) {
     885             :   // If the compute tag was evaluated before reset, then we reset dependent
     886             :   // compute tags.
     887             :   const auto aliases = tag_graphs_.tag_aliases.find(item_name);
     888             :   ASSERT(aliases != tag_graphs_.tag_aliases.end(),
     889             :          "Internal error: Item " << item_name << " has no names");
     890             :   for (const std::string& alias : aliases->second) {
     891             :     const auto dependents = tag_graphs_.tags_and_dependents.find(alias);
     892             :     if (dependents != tag_graphs_.tags_and_dependents.end()) {
     893             :       for (const std::string& dependent_item_name : dependents->second) {
     894             :         ASSERT(tag_graphs_.tags_and_reset_functions.find(dependent_item_name) !=
     895             :                    tag_graphs_.tags_and_reset_functions.end(),
     896             :                "Item " << dependent_item_name
     897             :                        << " does not have a reset function.");
     898             :         if ((this->*(tag_graphs_.tags_and_reset_functions)
     899             :                         .at(dependent_item_name))()) {
     900             :           // If the compute tag was evaluated, then we need to check the items
     901             :           // that depend on it.
     902             :           reset_compute_items(dependent_item_name);
     903             :         }
     904             :       }
     905             :     }
     906             :   }
     907             : }
     908             : 
     909             : template <typename... Tags>
     910             : template <typename MutatedTag>
     911             : void DataBox<tmpl::list<Tags...>>::reset_compute_items_after_mutate() {
     912             :   DEBUG_STATIC_ASSERT(
     913             :       tmpl::list_contains_v<mutable_item_tags, MutatedTag>,
     914             :       "internal inconsistency bug: reset_compute_items_after_mutate on "
     915             :       "invalid tag");
     916             : 
     917             :   // If a subitem is edited, reset the parent instead.  (The item
     918             :   // itself will be reset as a subitem of the parent below.)
     919             :   static const std::string tag_to_reset = []() {
     920             :     if constexpr (tmpl::list_contains_v<mutable_subitem_tags, MutatedTag>) {
     921             :       const std::string mutated_tag = pretty_type::get_name<MutatedTag>();
     922             :       ASSERT(tag_graphs_.subitem_to_parent_tag.find(mutated_tag) !=
     923             :                  tag_graphs_.subitem_to_parent_tag.end(),
     924             :              "Expected to find a parent tag of "
     925             :                  << mutated_tag
     926             :                  << " but did not. This is an internal inconsistency bug.");
     927             :       return tag_graphs_.subitem_to_parent_tag.at(mutated_tag);
     928             :     } else {
     929             :       return pretty_type::get_name<MutatedTag>();
     930             :     }
     931             :   }();
     932             : 
     933             :   reset_compute_items(tag_to_reset);
     934             : 
     935             :   // If the tag has subitems, reset those too.
     936             :   if (const auto parent_tag_it =
     937             :           tag_graphs_.parent_to_subitem_tags.find(tag_to_reset);
     938             :       parent_tag_it != tag_graphs_.parent_to_subitem_tags.end()) {
     939             :     for (const auto& subitem_tag : parent_tag_it->second) {
     940             :       reset_compute_items(subitem_tag);
     941             :     }
     942             :   }
     943             : }
     944             : 
     945             : template <typename... Tags>
     946             : void DataBox<tmpl::list<Tags...>>::mutate_mutable_subitems(
     947             :     const std::string& tag_name) {
     948             :   ASSERT(tag_graphs_.mutate_mutable_subitems_functions.find(tag_name) !=
     949             :              tag_graphs_.mutate_mutable_subitems_functions.end(),
     950             :          "Can't find tag " << tag_name
     951             :                            << " when mutating. Either the tag is not mutable "
     952             :                               "or this is an internal inconsistency bug.\n");
     953             :   (this->*tag_graphs_.mutate_mutable_subitems_functions.at(tag_name))();
     954             : }
     955             : 
     956             : template <typename... Tags>
     957             : void DataBox<tmpl::list<Tags...>>::reset_compute_items_after_mutate(
     958             :     const std::string& tag_name) {
     959             :   ASSERT(
     960             :       tag_graphs_.reset_compute_items_after_mutate_functions.find(tag_name) !=
     961             :           tag_graphs_.reset_compute_items_after_mutate_functions.end(),
     962             :       "Can't find tag " << tag_name
     963             :                         << " when mutating. Either the tag is not mutable "
     964             :                            "or this is an internal inconsistency bug.\n");
     965             :   (this->*tag_graphs_.reset_compute_items_after_mutate_functions.at(
     966             :               tag_name))();
     967             : }
     968             : 
     969             : template <typename... Tags>
     970             : template <typename Tag>
     971             : const void* DataBox<tmpl::list<Tags...>>::get_item_as_void_pointer() const {
     972             :   // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     973             :   return reinterpret_cast<const void*>(&this->template get<Tag>());
     974             : }
     975             : 
     976             : template <typename... Tags>
     977             : template <typename Tag>
     978             : void* DataBox<tmpl::list<Tags...>>::get_item_as_void_pointer_for_mutate() {
     979             :   // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
     980             :   return reinterpret_cast<void*>(
     981             :       &this->template get_item<
     982             :           detail::first_matching_tag<tmpl::list<Tags...>, Tag>>());
     983             : }
     984             : 
     985             : template <typename... Tags>
     986             : const void* DataBox<tmpl::list<Tags...>>::get_item_by_name(
     987             :     const std::string& tag_name) const {
     988             :   ASSERT(tag_graphs_.tag_retrieval_functions.find(tag_name) !=
     989             :              tag_graphs_.tag_retrieval_functions.end(),
     990             :          "Tag with name " << tag_name
     991             :                           << " is not found in the DataBox. Known tags are:\n"
     992             :                           << keys_of(tag_graphs_.tag_retrieval_functions));
     993             :   ASSERT(tag_graphs_.tag_retrieval_functions.at(tag_name) != nullptr,
     994             :          "Tag with name " << tag_name
     995             :                           << " is in the DataBox more than once and so "
     996             :                              "cannot be retrieved by name.");
     997             : 
     998             :   return (this->*tag_graphs_.tag_retrieval_functions.at(tag_name))();
     999             : }
    1000             : 
    1001             : template <typename... Tags>
    1002             : void* DataBox<tmpl::list<Tags...>>::mutate_item_by_name(
    1003             :     const std::string& tag_name) {
    1004             :   ASSERT(tag_graphs_.tag_mutate_functions.find(tag_name) !=
    1005             :              tag_graphs_.tag_mutate_functions.end(),
    1006             :          "Cannot mutate tag: " << tag_name << ".  Known tags are:\n"
    1007             :                                << keys_of(tag_graphs_.tag_mutate_functions));
    1008             :   return (this->*tag_graphs_.tag_mutate_functions.at(tag_name))();
    1009             : }
    1010             : 
    1011             : template <typename... Tags>
    1012             : bool DataBox<tmpl::list<Tags...>>::lock_box_for_mutate() {
    1013             :   const bool temp = mutate_locked_box_;
    1014             :   mutate_locked_box_ = true;
    1015             :   return temp;
    1016             : }
    1017             : 
    1018             : template <typename... Tags>
    1019             : void DataBox<tmpl::list<Tags...>>::unlock_box_after_mutate() {
    1020             :   mutate_locked_box_ = false;
    1021             : }
    1022             : 
    1023             : ////////////////////////////////////////////////////////////////
    1024             : // Mutating items in the DataBox
    1025             : // Classes and functions necessary for db::mutate to work
    1026             : 
    1027             : template <typename... Tags>
    1028             : template <typename ImmutableItemTag>
    1029             : SPECTRE_ALWAYS_INLINE bool DataBox<tmpl::list<Tags...>>::reset_compute_item() {
    1030             :   // reference items do not need to be reset, but it still needs to be handled
    1031             :   // here. Partly just so we get an error if we are calling this function
    1032             :   // incorrectly and because we need to call this function during resets
    1033             :   // to get dependency tracking correct when compute tags depend on reference
    1034             :   // tags.
    1035             :   if constexpr (db::is_compute_tag_v<ImmutableItemTag>) {
    1036             :     const bool was_evaluated = get_item<ImmutableItemTag>().evaluated();
    1037             :     get_item<ImmutableItemTag>().reset();
    1038             :     return was_evaluated;
    1039             :   } else if constexpr (db::is_reference_tag_v<ImmutableItemTag>) {
    1040             :     return true;
    1041             :   }
    1042             :   ERROR(
    1043             :       "Trying to reset a tag that is neither a compute or reference tag. This "
    1044             :       "is an implementation bug. A decision needs to be made as to whether the "
    1045             :       "tag was previously evaluated or not. If it was not, then anything that "
    1046             :       "depends on this tag will not be reset.");
    1047             :   return false;
    1048             : }
    1049             : 
    1050             : template <typename... Tags>
    1051             : template <typename ParentTag, typename... Subtags>
    1052             : SPECTRE_ALWAYS_INLINE constexpr void
    1053             : db::DataBox<tmpl::list<Tags...>>::mutate_mutable_subitems(
    1054             :     tmpl::list<Subtags...> /*meta*/) {
    1055             :   const auto helper = [this](auto tag_v) {
    1056             :     (void)this;  // Compiler bug warns about unused this capture
    1057             :     using tag = decltype(tag_v);
    1058             :     Subitems<ParentTag>::template create_item<tag>(
    1059             :         make_not_null(&get_item<ParentTag>().mutate()),
    1060             :         make_not_null(&get_item<tag>().mutate()));
    1061             :   };
    1062             : 
    1063             :   EXPAND_PACK_LEFT_TO_RIGHT(helper(Subtags{}));
    1064             : }
    1065             : 
    1066             : template <typename... Tags>
    1067             : SPECTRE_ALWAYS_INLINE constexpr void
    1068             : db::DataBox<tmpl::list<Tags...>>::reset_all_subitems() {
    1069             :   tmpl::for_each<mutable_item_tags>([this](auto tag) {
    1070             :     using Tag = tmpl::type_from<decltype(tag)>;
    1071             :     this->mutate_mutable_subitems<Tag>(typename Subitems<Tag>::type{});
    1072             :   });
    1073             : }
    1074             : /// \endcond
    1075             : 
    1076             : /*!
    1077             :  * \ingroup DataBoxGroup
    1078             :  * \brief Allows changing the state of one or more non-computed elements in
    1079             :  * the DataBox
    1080             :  *
    1081             :  * `mutate()`'s second argument is the DataBox from which to retrieve the tags
    1082             :  * `MutateTags`. The objects corresponding to the `MutateTags` are then passed
    1083             :  * to `invokable`, which is a lambda or a function object taking as many
    1084             :  * arguments as there are `MutateTags` and with the arguments being of types
    1085             :  * `gsl::not_null<db::item_type<MutateTags>*>...`. Inside the `invokable` no
    1086             :  * items can be retrieved from the DataBox `box`. This is to avoid confusing
    1087             :  * subtleties with order of evaluation of compute items, as well as dangling
    1088             :  * references. If an `invokable` needs read access to items in `box` they should
    1089             :  * be passed as additional arguments to `mutate`. Capturing them by reference in
    1090             :  * a lambda does not work because of a bug in GCC 6.3 and earlier. For a
    1091             :  * function object the read-only items can also be stored as const references
    1092             :  * inside the object by passing `db::get<TAG>(t)` to the constructor.
    1093             :  *
    1094             :  * \example
    1095             :  * \snippet Test_DataBox.cpp databox_mutate_example
    1096             :  *
    1097             :  * The `invokable` may have function return values, and any returns are
    1098             :  * forwarded as returns to the `db::mutate` call.
    1099             :  *
    1100             :  * For convenience in generic programming, if `::Tags::DataBox` is
    1101             :  * passed as the sole `MutateTags` parameter, this function will
    1102             :  * simply call its first argument with its remaining arguments.
    1103             :  * Except for this case, `::Tags::DataBox` is not usable with this
    1104             :  * function.
    1105             :  *
    1106             :  * \warning Using `db::mutate` returns to obtain non-const references or
    1107             :  * pointers to box items is potentially very dangerous. The \ref DataBoxGroup
    1108             :  * "DataBox" cannot track any subsequent changes to quantities that have been
    1109             :  * "unsafely" extracted in this manner, so we consider it undefined behavior to
    1110             :  * return pointers or references to \ref DataBoxGroup "DataBox" contents.
    1111             :  */
    1112             : template <typename... MutateTags, typename TagList, typename Invokable,
    1113             :           typename... Args>
    1114           1 : decltype(auto) mutate(Invokable&& invokable,
    1115             :                       const gsl::not_null<DataBox<TagList>*> box,
    1116             :                       Args&&... args) {
    1117             :   if constexpr ((... or std::is_same_v<MutateTags, Tags::DataBox>)) {
    1118             :     // This branch doesn't directly access the box, so no locking or
    1119             :     // resetting is necessary.
    1120             :     static_assert(
    1121             :         std::is_same_v<tmpl::list<MutateTags...>, tmpl::list<Tags::DataBox>>,
    1122             :         "Cannot mutate other tags when obtaining the mutable DataBox.");
    1123             :     return invokable(box, std::forward<Args>(args)...);
    1124             :   } else {
    1125             :     static_assert(
    1126             :         tmpl2::flat_all_v<
    1127             :             detail::has_unique_matching_tag_v<TagList, MutateTags>...>,
    1128             :         "One of the tags being mutated could not be found in the DataBox or "
    1129             :         "is a base tag identifying more than one tag.");
    1130             :     static_assert(tmpl2::flat_all_v<tmpl::list_contains_v<
    1131             :                       typename DataBox<TagList>::mutable_item_tags,
    1132             :                       detail::first_matching_tag<TagList, MutateTags>>...>,
    1133             :                   "Can only mutate mutable items");
    1134             :     if (UNLIKELY(box->mutate_locked_box_)) {
    1135             :       ERROR(
    1136             :           "Unable to mutate a DataBox that is already being mutated. This "
    1137             :           "error occurs when mutating a DataBox from inside the invokable "
    1138             :           "passed to the mutate function.");
    1139             :     }
    1140             : 
    1141             :     const CleanupRoutine unlock_box = [&box]() {
    1142             :       box->mutate_locked_box_ = false;
    1143             :       EXPAND_PACK_LEFT_TO_RIGHT(
    1144             :           box->template mutate_mutable_subitems<
    1145             :               detail::first_matching_tag<TagList, MutateTags>>());
    1146             :       EXPAND_PACK_LEFT_TO_RIGHT(
    1147             :           box->template reset_compute_items_after_mutate<
    1148             :               detail::first_matching_tag<TagList, MutateTags>>());
    1149             :     };
    1150             :     box->mutate_locked_box_ = true;
    1151             :     return invokable(
    1152             :         make_not_null(&box->template get_item<
    1153             :                               detail::first_matching_tag<TagList, MutateTags>>()
    1154             :                            .mutate())...,
    1155             :         std::forward<Args>(args)...);
    1156             :   }
    1157             : }
    1158             : 
    1159             : ////////////////////////////////////////////////////////////////
    1160             : // Retrieving items from the DataBox
    1161             : 
    1162             : /// \cond
    1163             : template <typename... Tags>
    1164             : template <typename ComputeTag, typename... ArgumentTags>
    1165             : void DataBox<tmpl::list<Tags...>>::evaluate_compute_item(
    1166             :     tmpl::list<ArgumentTags...> /*meta*/) const {
    1167             :   get_item<ComputeTag>().evaluate(get<ArgumentTags>()...);
    1168             : }
    1169             : 
    1170             : template <typename... Tags>
    1171             : template <typename ReferenceTag, typename... ArgumentTags>
    1172             : const auto& DataBox<tmpl::list<Tags...>>::get_reference_item(
    1173             :     tmpl::list<ArgumentTags...> /*meta*/) const {
    1174             :   return ReferenceTag::get(get<ArgumentTags>()...);
    1175             : }
    1176             : 
    1177             : template <typename... Tags>
    1178             : template <typename Tag>
    1179             : const auto& DataBox<tmpl::list<Tags...>>::get() const {
    1180             :   if constexpr (std::is_same_v<Tag, ::Tags::DataBox>) {
    1181             :     if (UNLIKELY(mutate_locked_box_)) {
    1182             :       ERROR(
    1183             :           "Unable to retrieve a (compute) item 'DataBox' from the DataBox from "
    1184             :           "within a call to mutate. You must pass these either through the "
    1185             :           "capture list of the lambda or the constructor of a class, this "
    1186             :           "restriction exists to avoid complexity.");
    1187             :     }
    1188             :     return *this;
    1189             :   } else if constexpr (std::is_same_v<Tag, Parallel::Tags::Metavariables>) {
    1190             :     static_assert(not std::is_same_v<metavars_tag, NoSuchType>);
    1191             :     return get_item<metavars_tag>().get();
    1192             :   } else {
    1193             :     DEBUG_STATIC_ASSERT(
    1194             :         not detail::has_no_matching_tag_v<tags_list, Tag>,
    1195             :         "Found no tags in the DataBox that match the tag being retrieved.");
    1196             :     DEBUG_STATIC_ASSERT(
    1197             :         detail::has_unique_matching_tag_v<tags_list, Tag>,
    1198             :         "Found more than one tag in the DataBox that matches the tag "
    1199             :         "being retrieved. This happens because more than one tag with the same "
    1200             :         "base (class) tag was added to the DataBox.");
    1201             :     using item_tag = detail::first_matching_tag<tags_list, Tag>;
    1202             :     if (UNLIKELY(mutate_locked_box_)) {
    1203             :       ERROR("Unable to retrieve a (compute) item '"
    1204             :             << db::tag_name<item_tag>()
    1205             :             << "' from the DataBox from within a "
    1206             :                "call to mutate. You must pass these either through the capture "
    1207             :                "list of the lambda or the constructor of a class, this "
    1208             :                "restriction exists to avoid complexity.");
    1209             :     }
    1210             :     if constexpr (detail::Item<item_tag>::item_type ==
    1211             :                   detail::ItemType::Reference) {
    1212             :       return get_reference_item<item_tag>(typename item_tag::argument_tags{});
    1213             :     } else {
    1214             :       if constexpr (detail::Item<item_tag>::item_type ==
    1215             :                     detail::ItemType::Compute) {
    1216             :         if (not get_item<item_tag>().evaluated()) {
    1217             :           evaluate_compute_item<item_tag>(typename item_tag::argument_tags{});
    1218             :         }
    1219             :       }
    1220             :       if constexpr (tt::is_a_v<std::unique_ptr, typename item_tag::type>) {
    1221             :         return *(get_item<item_tag>().get());
    1222             :       } else {
    1223             :         return get_item<item_tag>().get();
    1224             :       }
    1225             :     }
    1226             :   }
    1227             : }
    1228             : /// \endcond
    1229             : 
    1230             : /*!
    1231             :  * \ingroup DataBoxGroup
    1232             :  * \brief Retrieve the item with tag `Tag` from the DataBox
    1233             :  * \requires Type `Tag` is one of the Tags corresponding to an object stored in
    1234             :  * the DataBox
    1235             :  *
    1236             :  * \return The object corresponding to the tag `Tag`
    1237             :  */
    1238             : template <typename Tag, typename TagList>
    1239           1 : SPECTRE_ALWAYS_INLINE const auto& get(const DataBox<TagList>& box) {
    1240             :   return box.template get<Tag>();
    1241             : }
    1242             : 
    1243             : ////////////////////////////////////////////////////////////////
    1244             : // Copy mutable creation items from the DataBox
    1245             : 
    1246             : /// \cond
    1247             : template <typename... Tags>
    1248             : template <typename Tag>
    1249             : SPECTRE_ALWAYS_INLINE auto DataBox<tmpl::list<Tags...>>::copy_item() const {
    1250             :   using item_tag = detail::first_matching_tag<tags_list, Tag>;
    1251             :   using item_type = typename item_tag::type;
    1252             :   static_assert(tmpl::list_contains_v<mutable_item_creation_tags, item_tag>,
    1253             :                 "Can only copy mutable creation items");
    1254             :   return serialize_and_deserialize<item_type>(get_item<item_tag>().get());
    1255             : }
    1256             : 
    1257             : template <typename... DbTags>
    1258             : template <typename... CopiedItemsTags>
    1259             : tuples::TaggedTuple<CopiedItemsTags...>
    1260             : DataBox<tmpl::list<DbTags...>>::copy_items(
    1261             :     tmpl::list<CopiedItemsTags...> /*meta*/) const {
    1262             :   return tuples::TaggedTuple<CopiedItemsTags...>{
    1263             :       copy_item<CopiedItemsTags>()...};
    1264             : }
    1265             : /// \endcond
    1266             : 
    1267             : /*!
    1268             :  * \ingroup DataBoxGroup
    1269             :  * \brief Copy the items from the DataBox into a TaggedTuple
    1270             :  *
    1271             :  * \return The objects corresponding to CopiedItemsTagList
    1272             :  *
    1273             :  * \note The tags in CopiedItemsTagList must be a subset of
    1274             :  * the mutable_item_creation_tags of the DataBox
    1275             :  */
    1276             : template <typename CopiedItemsTagList, typename DbTagList>
    1277           1 : SPECTRE_ALWAYS_INLINE auto copy_items(const DataBox<DbTagList>& box) {
    1278             :   return box.copy_items(CopiedItemsTagList{});
    1279             : }
    1280             : 
    1281             : ////////////////////////////////////////////////////////////////
    1282             : // Get mutable reference from the DataBox
    1283             : /// \cond
    1284             : template <typename... Tags>
    1285             : template <typename Tag>
    1286             : auto& DataBox<tmpl::list<Tags...>>::get_mutable_reference() {
    1287             :   DEBUG_STATIC_ASSERT(
    1288             :       not detail::has_no_matching_tag_v<tmpl::list<Tags...>, Tag>,
    1289             :       "Found no tags in the DataBox that match the tag being retrieved.");
    1290             :   DEBUG_STATIC_ASSERT(
    1291             :       detail::has_unique_matching_tag_v<tmpl::list<Tags...>, Tag>,
    1292             :       "Found more than one tag in the DataBox that matches the tag "
    1293             :       "being retrieved. This happens because more than one tag with the same "
    1294             :       "base (class) tag was added to the DataBox.");
    1295             : 
    1296             :   using item_tag = detail::first_matching_tag<tmpl::list<Tags...>, Tag>;
    1297             : 
    1298             :   DEBUG_STATIC_ASSERT(tmpl::list_contains_v<mutable_item_tags, item_tag>,
    1299             :                       "Can only mutate mutable items");
    1300             : 
    1301             :   DEBUG_STATIC_ASSERT(
    1302             :       not (... or
    1303             :            tmpl::list_contains_v<typename Subitems<Tags>::type, item_tag>),
    1304             :       "Cannot extract references to subitems");
    1305             :   DEBUG_STATIC_ASSERT(not detail::has_subitems_v<item_tag>,
    1306             :                       "Cannot extract references to items with subitems.");
    1307             : 
    1308             :   DEBUG_STATIC_ASSERT(
    1309             :       tmpl::none<edge_list, std::is_same<tmpl::pin<item_tag>,
    1310             :                                          tmpl::get_source<tmpl::_1>>>::value,
    1311             :       "Cannot extract references to items used by compute items.");
    1312             : 
    1313             :   return get_item<item_tag>().mutate();
    1314             : }
    1315             : 
    1316             : template <typename... Tags>
    1317             : template <typename Consumer, typename Provider>
    1318             : constexpr bool DataBox<tmpl::list<Tags...>>::tag_depends_on() {
    1319             :   // We need to check for things depending on the passed tag, any
    1320             :   // subitems, and the parent item if we were passed a subitem.  These
    1321             :   // dependencies are handled internally by the mutation functions and
    1322             :   // not encoded in the graph.
    1323             :   using provider_aliases =
    1324             :       tmpl::push_front<typename Subitems<Provider>::type,
    1325             :                        creation_tag<Provider, DataBox<tmpl::list<Tags...>>>>;
    1326             : 
    1327             :   // We have to replace subitems with their parents here because
    1328             :   // subitems of compute tags sometimes get graph edges from their
    1329             :   // parents and sometimes do not, depending on if they have
    1330             :   // dependencies.
    1331             :   using consumer_tag_to_check =
    1332             :       creation_tag<Consumer, DataBox<tmpl::list<Tags...>>>;
    1333             : 
    1334             :   // We cannot recursively call the function we are in, because we
    1335             :   // need to avoid the normalization done above.  Otherwise we could
    1336             :   // end up in a loop when destination of an edge normalizes to its
    1337             :   // source.
    1338             : 
    1339             :   // Lambdas cannot capture themselves, but they can take themselves
    1340             :   // as an argument.
    1341             :   auto check_dependents = [](auto&& recurse,
    1342             :                              auto node_depending_on_provider_v) {
    1343             :     using node_depending_on_provider = decltype(node_depending_on_provider_v);
    1344             :     if (std::is_same_v<node_depending_on_provider, consumer_tag_to_check>) {
    1345             :       return true;
    1346             :     }
    1347             : 
    1348             :     using next_nodes_to_check = tmpl::transform<
    1349             :         tmpl::filter<
    1350             :             edge_list,
    1351             :             tmpl::has_source<tmpl::_1, tmpl::pin<node_depending_on_provider>>>,
    1352             :         tmpl::get_destination<tmpl::_1>>;
    1353             : 
    1354             :     return tmpl::as_pack<next_nodes_to_check>([&](auto... nodes) {
    1355             :       return (... or recurse(recurse, tmpl::type_from<decltype(nodes)>{}));
    1356             :     });
    1357             :   };
    1358             : 
    1359             :   return tmpl::as_pack<provider_aliases>([&](auto... aliases) {
    1360             :     return (... or check_dependents(check_dependents,
    1361             :                                     tmpl::type_from<decltype(aliases)>{}));
    1362             :   });
    1363             : }
    1364             : /// \endcond
    1365             : 
    1366             : /*!
    1367             :  * \ingroup DataBoxGroup
    1368             :  * \brief Retrieve a mutable reference to the item with tag `Tag` from the
    1369             :  * DataBox.
    1370             :  *
    1371             :  * The tag retrieved cannot be used by any compute tags, cannot have
    1372             :  * subitems, and cannot itself be a subitem.  These requirements
    1373             :  * prevent changes to the retrieved item from affecting any other tags
    1374             :  * in the DataBox, so it can safely be modified without causing
    1375             :  * internal inconsistencies.
    1376             :  */
    1377             : template <typename Tag, typename TagList>
    1378           1 : SPECTRE_ALWAYS_INLINE auto& get_mutable_reference(
    1379             :     const gsl::not_null<DataBox<TagList>*> box) {
    1380             :   return box->template get_mutable_reference<Tag>();
    1381             : }
    1382             : 
    1383             : /// @{
    1384             : /*!
    1385             :  * \ingroup DataBoxGroup
    1386             :  * \brief Check whether the tag \p Consumer depends on the tag \p
    1387             :  * Provider in a given \p Box.
    1388             :  *
    1389             :  * This is equivalent to the question of whether changing \p Provider
    1390             :  * (through `db::mutate`, updating one of its dependencies, etc.)
    1391             :  * could change the value of `db::get<Consumer>`.  Tags depend on
    1392             :  * themselves, and an item and its subitems all depend on one another.
    1393             :  */
    1394             : template <typename Consumer, typename Provider, typename Box>
    1395           1 : using tag_depends_on =
    1396             :     std::bool_constant<Box::template tag_depends_on<Consumer, Provider>()>;
    1397             : 
    1398             : template <typename Consumer, typename Provider, typename Box>
    1399           1 : constexpr bool tag_depends_on_v =
    1400             :     tag_depends_on<Consumer, Provider, Box>::value;
    1401             : /// @}
    1402             : 
    1403             : /*!
    1404             :  * \ingroup DataBoxGroup
    1405             :  * \brief List of Tags to add to the DataBox
    1406             :  */
    1407             : template <typename... Tags>
    1408           1 : using AddSimpleTags = tmpl::flatten<tmpl::list<Tags...>>;
    1409             : 
    1410             : /*!
    1411             :  * \ingroup DataBoxGroup
    1412             :  * \brief List of Compute Item Tags to add to the DataBox
    1413             :  */
    1414             : template <typename... Tags>
    1415           1 : using AddComputeTags = tmpl::flatten<tmpl::list<Tags...>>;
    1416             : 
    1417             : namespace detail {
    1418             : template <class TagList>
    1419             : struct compute_dbox_type {
    1420             :   using immutable_item_tags = detail::expand_subitems<
    1421             :       tmpl::filter<TagList, db::is_immutable_item_tag<tmpl::_1>>>;
    1422             :   using mutable_item_tags = detail::expand_subitems<
    1423             :       tmpl::filter<TagList, db::is_mutable_item_tag<tmpl::_1>>>;
    1424             :   using type = DataBox<tmpl::append<mutable_item_tags, immutable_item_tags>>;
    1425             : };
    1426             : }  // namespace detail
    1427             : 
    1428             : /*!
    1429             :  * \ingroup DataBoxGroup
    1430             :  * \brief Returns the type of the DataBox that would be constructed from the
    1431             :  * `TagList` of tags.
    1432             :  */
    1433             : template <typename TagList>
    1434           1 : using compute_databox_type = typename detail::compute_dbox_type<TagList>::type;
    1435             : 
    1436             : /*!
    1437             :  * \ingroup DataBoxGroup
    1438             :  * \brief Create a new DataBox
    1439             :  *
    1440             :  * \details
    1441             :  * Creates a new DataBox holding types Tags::type filled with the arguments
    1442             :  * passed to the function. Compute and reference items must be added so that
    1443             :  * their dependencies are added before themselves. For example, say you have
    1444             :  * compute items `A` and `B` where `B` depends on `A`, then you must add them
    1445             :  * using `db::AddImmutableItemTags<A, B>`.
    1446             :  *
    1447             :  * \example
    1448             :  * \snippet Test_DataBox.cpp create_databox
    1449             :  *
    1450             :  * \see create_from
    1451             :  *
    1452             :  * \tparam AddMutableItemTags the tags of the mutable items that are being added
    1453             :  * \tparam AddImmutableItemTags list of \ref ComputeTag "compute item tags" and
    1454             :  *         \ref ReferenceTag "refernce item tags" to add to the DataBox
    1455             :  * \param args the initial values for the mutable items to add to the DataBox
    1456             :  */
    1457             : template <typename AddMutableItemTags,
    1458             :           typename AddImmutableItemTags = tmpl::list<>, typename... Args>
    1459           1 : SPECTRE_ALWAYS_INLINE constexpr auto create(Args&&... args) {
    1460             :   static_assert(tt::is_a_v<tmpl::list, AddImmutableItemTags>,
    1461             :                 "AddImmutableItemTags must be a tmpl::list");
    1462             :   static_assert(tt::is_a_v<tmpl::list, AddMutableItemTags>,
    1463             :                 "AddMutableItemTags must be a tmpl::list");
    1464             :   static_assert(
    1465             :       tmpl::all<AddMutableItemTags, is_creation_tag<tmpl::_1>>::value and
    1466             :           tmpl::all<AddImmutableItemTags, is_creation_tag<tmpl::_1>>::value,
    1467             :       "Can only add tags derived from db::SimpleTag.");
    1468             :   static_assert(
    1469             :       tmpl::all<AddMutableItemTags, is_mutable_item_tag<tmpl::_1>>::value,
    1470             :       "Cannot add any ComputeTags or ReferenceTags in the AddMutableTags list, "
    1471             :       "must use the AddImmutableItemTags list.");
    1472             :   static_assert(
    1473             :       tmpl::all<AddImmutableItemTags, is_immutable_item_tag<tmpl::_1>>::value,
    1474             :       "Cannot add any SimpleTags in the AddImmutableItemTags list, must use "
    1475             :       "the "
    1476             :       "AddMutableItemTags list.");
    1477             : 
    1478             :   using mutable_item_tags = detail::expand_subitems<AddMutableItemTags>;
    1479             :   using immutable_item_tags = detail::expand_subitems<AddImmutableItemTags>;
    1480             : 
    1481             :   return db::DataBox<tmpl::append<mutable_item_tags, immutable_item_tags>>(
    1482             :       AddMutableItemTags{}, AddImmutableItemTags{},
    1483             :       std::forward<Args>(args)...);
    1484             : }
    1485             : 
    1486             : namespace detail {
    1487             : template <typename DataBoxTags, typename... TagsToRetrieve>
    1488             : constexpr bool check_tags_are_in_databox(
    1489             :     DataBoxTags /*meta*/, tmpl::list<TagsToRetrieve...> /*meta*/) {
    1490             :   static_assert(
    1491             :       (tag_is_retrievable_v<TagsToRetrieve, DataBox<DataBoxTags>> and ...),
    1492             :       "A desired tag is not in the DataBox.  See the first template "
    1493             :       "argument of tag_is_retrievable_v for the missing tag, and the "
    1494             :       "second for the available tags.");
    1495             :   return true;
    1496             : }
    1497             : 
    1498             : template <typename... ArgumentTags, typename F, typename BoxTags,
    1499             :           typename... Args>
    1500             : static constexpr auto apply(F&& f, const DataBox<BoxTags>& box,
    1501             :                             tmpl::list<ArgumentTags...> /*meta*/,
    1502             :                             Args&&... args) {
    1503             :   if constexpr (is_apply_callable_v<
    1504             :                     F,
    1505             :                     tmpl::conditional_t<
    1506             :                         std::is_same_v<ArgumentTags, ::Tags::DataBox>,
    1507             :                         const DataBox<BoxTags>&,
    1508             :                         const_item_type<ArgumentTags, BoxTags>>...,
    1509             :                     Args...>) {
    1510             :     return F::apply(::db::get<ArgumentTags>(box)...,
    1511             :                     std::forward<Args>(args)...);
    1512             :   } else if constexpr (::tt::is_callable_v<
    1513             :                            std::remove_pointer_t<F>,
    1514             :                            tmpl::conditional_t<
    1515             :                                std::is_same_v<ArgumentTags, ::Tags::DataBox>,
    1516             :                                const DataBox<BoxTags>&,
    1517             :                                const_item_type<ArgumentTags, BoxTags>>...,
    1518             :                            Args...>) {
    1519             :     return std::forward<F>(f)(::db::get<ArgumentTags>(box)...,
    1520             :                               std::forward<Args>(args)...);
    1521             :   } else {
    1522             :     error_function_not_callable<
    1523             :         std::remove_pointer_t<F>,
    1524             :         tmpl::conditional_t<std::is_same_v<ArgumentTags, ::Tags::DataBox>,
    1525             :                             const DataBox<BoxTags>&,
    1526             :                             const_item_type<ArgumentTags, BoxTags>>...,
    1527             :         Args...>();
    1528             :   }
    1529             : }
    1530             : }  // namespace detail
    1531             : 
    1532             : /// @{
    1533             : /*!
    1534             :  * \ingroup DataBoxGroup
    1535             :  * \brief Apply the invokable `f` with argument Tags `TagsList` from
    1536             :  * DataBox `box`
    1537             :  *
    1538             :  * \details
    1539             :  * `f` must either be invokable with the arguments of type
    1540             :  * `db::const_item_type<TagsList>..., Args...` where the first pack expansion
    1541             :  * is over the elements in the type list `ArgumentTags`, or have a static
    1542             :  * `apply` function that is callable with the same types.
    1543             :  * If the class that implements the static `apply` functions also provides an
    1544             :  * `argument_tags` typelist, then it is used and no explicit `ArgumentTags`
    1545             :  * template parameter should be specified.
    1546             :  *
    1547             :  * \usage
    1548             :  * Given a function `func` that takes arguments of types
    1549             :  * `T1`, `T2`, `A1` and `A2`. Let the Tags for the quantities of types `T1` and
    1550             :  * `T2` in the DataBox `box` be `Tag1` and `Tag2`, and objects `a1` of type
    1551             :  * `A1` and `a2` of type `A2`, then
    1552             :  * \code
    1553             :  * auto result = db::apply<tmpl::list<Tag1, Tag2>>(func, box, a1, a2);
    1554             :  * \endcode
    1555             :  * \return `decltype(func(db::get<Tag1>(box), db::get<Tag2>(box), a1, a2))`
    1556             :  *
    1557             :  * \semantics
    1558             :  * For tags `Tags...` in a DataBox `box`, and a function `func` that takes
    1559             :  * `sizeof...(Tags)` arguments of types `db::const_item_type<Tags>...`,  and
    1560             :  * `sizeof...(Args)` arguments of types `Args...`,
    1561             :  * \code
    1562             :  * result = func(box, db::get<Tags>(box)..., args...);
    1563             :  * \endcode
    1564             :  *
    1565             :  * \example
    1566             :  * \snippet Test_DataBox.cpp apply_example
    1567             :  * Using a struct with an `apply` method:
    1568             :  * \snippet Test_DataBox.cpp apply_struct_example
    1569             :  * If the class `F` has no state, you can also use the stateless overload of
    1570             :  * `apply`: \snippet Test_DataBox.cpp apply_stateless_struct_example
    1571             :  *
    1572             :  * \see DataBox
    1573             :  * \tparam ArgumentTags typelist of Tags in the order that they are to be passed
    1574             :  * to `f`
    1575             :  * \tparam F The invokable to apply
    1576             :  */
    1577             : template <typename ArgumentTags, typename F, typename BoxTags, typename... Args>
    1578           1 : SPECTRE_ALWAYS_INLINE constexpr auto apply(F&& f, const DataBox<BoxTags>& box,
    1579             :                                            Args&&... args) {
    1580             :   detail::check_tags_are_in_databox(
    1581             :       BoxTags{}, tmpl::remove<ArgumentTags, ::Tags::DataBox>{});
    1582             :   return detail::apply(std::forward<F>(f), box, ArgumentTags{},
    1583             :                        std::forward<Args>(args)...);
    1584             : }
    1585             : 
    1586             : template <typename F, typename BoxTags, typename... Args>
    1587           1 : SPECTRE_ALWAYS_INLINE constexpr auto apply(F&& f, const DataBox<BoxTags>& box,
    1588             :                                            Args&&... args) {
    1589             :   return apply<typename std::decay_t<F>::argument_tags>(
    1590             :       std::forward<F>(f), box, std::forward<Args>(args)...);
    1591             : }
    1592             : 
    1593             : template <typename F, typename BoxTags, typename... Args>
    1594           1 : SPECTRE_ALWAYS_INLINE constexpr auto apply(const DataBox<BoxTags>& box,
    1595             :                                            Args&&... args) {
    1596             :   return apply(F{}, box, std::forward<Args>(args)...);
    1597             : }
    1598             : /// @}
    1599             : 
    1600             : namespace detail {
    1601             : template <typename Tag, typename BoxTags>
    1602             : using tag_return_type =
    1603             :     tmpl::conditional_t<std::is_same_v<Tag, ::Tags::DataBox>,
    1604             :                         db::DataBox<BoxTags>, typename Tag::type>;
    1605             : 
    1606             : template <typename... ReturnTags, typename... ArgumentTags, typename F,
    1607             :           typename BoxTags, typename... Args>
    1608             : SPECTRE_ALWAYS_INLINE constexpr decltype(auto) mutate_apply(
    1609             :     F&& f, const gsl::not_null<db::DataBox<BoxTags>*> box,
    1610             :     tmpl::list<ReturnTags...> /*meta*/, tmpl::list<ArgumentTags...> /*meta*/,
    1611             :     Args&&... args) {
    1612             :   if constexpr (sizeof...(ReturnTags) == 0) {
    1613             :     return apply<tmpl::list<ArgumentTags...>>(std::forward<F>(f), *box,
    1614             :                                               std::forward<Args>(args)...);
    1615             :   } else {
    1616             :     detail::check_tags_are_in_databox(BoxTags{}, tmpl::list<ReturnTags...>{});
    1617             :     detail::check_tags_are_in_databox(BoxTags{}, tmpl::list<ArgumentTags...>{});
    1618             :     static_assert(not(... or std::is_same_v<ArgumentTags, Tags::DataBox>),
    1619             :                   "Cannot pass Tags::DataBox to mutate_apply when mutating "
    1620             :                   "since the db::get won't work inside mutate_apply.");
    1621             :     if constexpr (is_apply_callable_v<
    1622             :                       F,
    1623             :                       const gsl::not_null<
    1624             :                           tag_return_type<ReturnTags, BoxTags>*>...,
    1625             :                       const_item_type<ArgumentTags, BoxTags>..., Args...>) {
    1626             :       return ::db::mutate<ReturnTags...>(
    1627             :           [](const gsl::not_null<
    1628             :                  tag_return_type<ReturnTags, BoxTags>*>... mutated_items,
    1629             :              const_item_type<ArgumentTags, BoxTags>... args_items,
    1630             :              decltype(std::forward<Args>(args))... l_args) {
    1631             :             return std::decay_t<F>::apply(mutated_items..., args_items...,
    1632             :                                           std::forward<Args>(l_args)...);
    1633             :           },
    1634             :           box, db::get<ArgumentTags>(*box)..., std::forward<Args>(args)...);
    1635             :     } else if constexpr (
    1636             :         ::tt::is_callable_v<
    1637             :             F, const gsl::not_null<tag_return_type<ReturnTags, BoxTags>*>...,
    1638             :             const_item_type<ArgumentTags, BoxTags>..., Args...>) {
    1639             :       return ::db::mutate<ReturnTags...>(f, box, db::get<ArgumentTags>(*box)...,
    1640             :                                          std::forward<Args>(args)...);
    1641             :     } else {
    1642             :       error_function_not_callable<
    1643             :           F, gsl::not_null<tag_return_type<ReturnTags, BoxTags>*>...,
    1644             :           const_item_type<ArgumentTags, BoxTags>..., Args...>();
    1645             :     }
    1646             :   }
    1647             : }
    1648             : }  // namespace detail
    1649             : 
    1650             : /// @{
    1651             : /*!
    1652             :  * \ingroup DataBoxGroup
    1653             :  * \brief Apply the invokable `f` mutating items `MutateTags` and taking as
    1654             :  * additional arguments `ArgumentTags` and `args`.
    1655             :  *
    1656             :  * \details
    1657             :  * `f` must either be invokable with the arguments of type
    1658             :  * `gsl::not_null<db::item_type<MutateTags>*>...,
    1659             :  * db::const_item_type<ArgumentTags>..., Args...`
    1660             :  * where the first two pack expansions are over the elements in the typelists
    1661             :  * `MutateTags` and `ArgumentTags`, or have a static `apply` function that is
    1662             :  * callable with the same types. If the type of `f` specifies `return_tags` and
    1663             :  * `argument_tags` typelists, these are used for the `MutateTags` and
    1664             :  * `ArgumentTags`, respectively.
    1665             :  *
    1666             :  * Any return values of the invokable `f` are forwarded as returns to the
    1667             :  * `mutate_apply` call.
    1668             :  *
    1669             :  * \note If `MutateTags` is empty this will forward to `db::apply`, so
    1670             :  * `::Tags::DataBox` will be available.  Otherwise it will call
    1671             :  * `db::mutate`.  See those functions for more details on retrieving
    1672             :  * the entire box.
    1673             :  *
    1674             :  * \example
    1675             :  * An example of using `mutate_apply` with a lambda:
    1676             :  * \snippet Test_DataBox.cpp mutate_apply_lambda_example
    1677             :  *
    1678             :  * An example of a class with a static `apply` function
    1679             :  * \snippet Test_DataBox.cpp mutate_apply_struct_definition_example
    1680             :  * and how to use `mutate_apply` with the above class
    1681             :  * \snippet Test_DataBox.cpp mutate_apply_struct_example_stateful
    1682             :  * Note that the class exposes `return_tags` and `argument_tags` typelists, so
    1683             :  * we don't specify the template parameters explicitly.
    1684             :  * If the class `F` has no state, like in this example,
    1685             :  * \snippet Test_DataBox.cpp mutate_apply_struct_definition_example
    1686             :  * you can also use the stateless overload of `mutate_apply`:
    1687             :  * \snippet Test_DataBox.cpp mutate_apply_struct_example_stateless
    1688             :  *
    1689             :  * \tparam MutateTags typelist of Tags to mutate
    1690             :  * \tparam ArgumentTags typelist of additional items to retrieve from the
    1691             :  * DataBox
    1692             :  * \tparam F The invokable to apply
    1693             :  */
    1694             : template <typename MutateTags, typename ArgumentTags, typename F,
    1695             :           typename BoxTags, typename... Args>
    1696           1 : SPECTRE_ALWAYS_INLINE constexpr decltype(auto) mutate_apply(
    1697             :     F&& f, const gsl::not_null<DataBox<BoxTags>*> box, Args&&... args) {
    1698             :   return detail::mutate_apply(std::forward<F>(f), box, MutateTags{},
    1699             :                               ArgumentTags{}, std::forward<Args>(args)...);
    1700             : }
    1701             : 
    1702             : template <typename F, typename BoxTags, typename... Args>
    1703           1 : SPECTRE_ALWAYS_INLINE constexpr decltype(auto) mutate_apply(
    1704             :     F&& f, const gsl::not_null<DataBox<BoxTags>*> box, Args&&... args) {
    1705             :   return mutate_apply<typename std::decay_t<F>::return_tags,
    1706             :                       typename std::decay_t<F>::argument_tags>(
    1707             :       std::forward<F>(f), box, std::forward<Args>(args)...);
    1708             : }
    1709             : 
    1710             : template <typename F, typename BoxTags, typename... Args>
    1711           1 : SPECTRE_ALWAYS_INLINE constexpr decltype(auto) mutate_apply(
    1712             :     const gsl::not_null<DataBox<BoxTags>*> box, Args&&... args) {
    1713             :   return mutate_apply(F{}, box, std::forward<Args>(args)...);
    1714             : }
    1715             : /// @}
    1716             : }  // namespace db
    1717             : 
    1718             : template <typename TagsList>
    1719           0 : std::ostream& operator<<(std::ostream& os, const db::DataBox<TagsList>& box) {
    1720             :   os << box.print_types() << "\n";
    1721             :   os << box.print_items() << "\n";
    1722             :   return os;
    1723             : }

Generated by: LCOV version 1.14