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

Generated by: LCOV version 1.14