DataBox.hpp
Go to the documentation of this file.
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 <algorithm>
10 #include <cassert>
11 #include <functional>
12 #include <pup.h>
13 #include <string>
14 #include <type_traits>
15 #include <unordered_map>
16 
19 #include "ErrorHandling/Assert.hpp"
20 #include "ErrorHandling/Error.hpp"
22 #include "Utilities/BoostHelpers.hpp" // for pup variant
24 #include "Utilities/Gsl.hpp"
25 #include "Utilities/Requires.hpp"
26 #include "Utilities/TMPL.hpp"
27 #include "Utilities/TypeTraits.hpp"
28 
29 /*!
30  * \ingroup DataBoxGroup
31  * \brief Namespace for DataBox related things
32  */
33 namespace db {
34 
35 // Forward declarations
36 /// \cond
37 template <typename TagsList>
38 class DataBox;
39 /// \endcond
40 
41 // @{
42 /*!
43  * \ingroup TypeTraitsGroup DataBox
44  * \brief Determines if a type `T` is as db::DataBox
45  *
46  * \effects Inherits from std::true_type if `T` is a specialization of
47  * db::DataBox, otherwise inherits from std::false_type
48  * \example
49  */
50 // \snippet Test_DataBox.cpp
51 template <typename T>
53 /// \cond HIDDEN_SYMBOLS
54 template <typename... Tags>
55 struct is_databox<DataBox<tmpl::list<Tags...>>> : std::true_type {};
56 /// \endcond
57 // @}
58 
59 namespace DataBox_detail {
60 template <class Tag, class Type>
61 class DataBoxLeaf;
62 
63 template <class Tag, class Type>
64 class DataBoxLeaf {
65  using value_type = Deferred<Type>;
66  value_type value_;
67 
68  template <class T>
69  static constexpr bool can_bind_reference() noexcept {
70  using rem_ref_value_type = typename std::remove_reference<value_type>::type;
71  using rem_ref_T = typename std::remove_reference<T>::type;
72  using is_lvalue_type = std::integral_constant<
73  bool, cpp17::is_lvalue_reference_v<T> or
74  cpp17::is_same_v<std::reference_wrapper<rem_ref_value_type>,
75  rem_ref_T> or
78  rem_ref_T>>;
79  return not cpp17::is_reference_v<value_type> or
80  (cpp17::is_lvalue_reference_v<value_type> and
81  is_lvalue_type::value) or
82  (cpp17::is_rvalue_reference_v<value_type> and
83  not cpp17::is_lvalue_reference_v<T>);
84  }
85 
86  public:
87  constexpr DataBoxLeaf() noexcept(
88  cpp17::is_nothrow_default_constructible_v<value_type>)
89  : value_() {
90  static_assert(!cpp17::is_reference_v<value_type>,
91  "Cannot default construct a reference element in a "
92  "DataBox");
93  }
94 
95  // clang-tidy: forwarding references are hard
96  template <class T,
98  cpp17::is_constructible_v<value_type, T&&>> = nullptr>
99  constexpr explicit DataBoxLeaf(T&& t) noexcept( // NOLINT
100  cpp17::is_nothrow_constructible_v<value_type, T&&>)
101  : value_(std::forward<T>(t)) { // NOLINT
102  static_assert(can_bind_reference<T>(),
103  "Cannot construct an lvalue reference with an rvalue");
104  }
105 
106  constexpr DataBoxLeaf(DataBoxLeaf const& /*rhs*/) = default;
107  constexpr DataBoxLeaf(DataBoxLeaf&& /*rhs*/) = default;
108  constexpr DataBoxLeaf& operator=(DataBoxLeaf const& rhs) noexcept(
109  noexcept(value_ = rhs.value_)) {
110  if (this != &rhs) {
111  value_ = rhs.value_;
112  }
113  return *this;
114  }
115  constexpr DataBoxLeaf& operator=(DataBoxLeaf&& rhs) noexcept(
116  noexcept(value_ = std::move(rhs.value_))) {
117  if (this != &rhs) {
118  value_ = std::move(rhs.value_);
119  }
120  return *this;
121  }
122 
123  ~DataBoxLeaf() = default;
124 
125  constexpr value_type& get() noexcept { return value_; }
126  constexpr const value_type& get() const noexcept { return value_; }
127 
128  // clang-tidy: runtime-references
129  void pup(PUP::er& p) { p | value_; } // NOLINT
130 };
131 
132 template <typename Element>
133 struct extract_expand_simple_subitems {
134  using type =
135  tmpl::push_front<typename Subitems<NoSuchType, Element>::type, Element>;
136 };
137 
138 // Given a typelist of items List, returns a new typelist containing
139 // the items and all of their subitems.
140 template <typename List>
141 using expand_simple_subitems = tmpl::flatten<tmpl::transform<
142  List, extract_expand_simple_subitems<tmpl::_1>>>;
143 
144 namespace detail {
145 constexpr int select_expand_subitems_impl(const size_t pack_size) noexcept {
146  // selects the appropriate fast track based on the pack size. Fast tracks for
147  // 2 and 4 limit the DataBox to about 800 items. This could be increased by
148  // adding fast tracks for say 8 and 64.
149  return pack_size >= 4 ? 3 : pack_size >= 2 ? 2 : static_cast<int>(pack_size);
150 }
151 
152 // expand_subitems_from_list_impl is a left fold, but Brigand doesn't do folds
153 // through aliases, so it's cheaper this way
154 template <int FastTrackSelector, template <typename...> class F>
155 struct expand_subitems_impl;
156 
157 template <typename FulltagList, typename TagList, typename Element>
158 using expand_subitems_impl_helper = tmpl::append<
159  tmpl::push_back<TagList, Element>,
161 
162 template <template <typename...> class F>
163 struct expand_subitems_impl<0, F> {
164  template <typename FullTagList, typename TagList>
165  using f = TagList;
166 };
167 
168 template <template <typename...> class F>
169 struct expand_subitems_impl<1, F> {
170  // The compile time here could be improved by having Subitems have a nested
171  // type alias that generates the list currently retrieved by `::type` on to
172  // the next call of `expand_subitems_impl`
173  template <typename FullTagList, typename TagList, typename Element,
174  typename... Rest>
175  using f = typename expand_subitems_impl<
176  select_expand_subitems_impl(sizeof...(Rest)),
177  F>::template f<FullTagList, F<FullTagList, TagList, Element>, Rest...>;
178 };
179 
180 template <template <typename...> class F>
181 struct expand_subitems_impl<2, F> {
182  template <typename FullTagList, typename TagList, typename Element0,
183  typename Element1, typename... Rest>
184  using f = typename expand_subitems_impl<
185  select_expand_subitems_impl(sizeof...(Rest)), F>::
186  template f<FullTagList,
187  F<FullTagList, F<FullTagList, TagList, Element0>, Element1>,
188  Rest...>;
189 };
190 
191 template <template <typename...> class F>
192 struct expand_subitems_impl<3, F> {
193  template <typename FullTagList, typename TagList, typename Element0,
194  typename Element1, typename Element2, typename Element3,
195  typename... Rest>
196  using f = typename expand_subitems_impl<
197  select_expand_subitems_impl(sizeof...(Rest)), F>::
198  template f<
199  FullTagList,
200  F<FullTagList,
201  F<FullTagList,
202  F<FullTagList, F<FullTagList, TagList, Element0>, Element1>,
203  Element2>,
204  Element3>,
205  Rest...>;
206 };
207 
208 /*!
209  * Expands the `ComputeTagsList` into a parameter pack, and also makes the
210  * decision about expanding the simple tags. The `ComputeTagsList` is expanded
211  * into a parameter pack so that we can use type aliases to do the computation,
212  * rather than structs. This turns out to be better for compilation speed.
213  *
214  * Once the `ComputeTagsList` is turned into a parameter pack, the
215  * `expand_subitems_impl` struct's nested type alias is used for the recursive
216  * computation. This recursive nature limits us to about 800 items in the
217  * DataBox without the need for fast-tracking. If more are necessary, using
218  * fast-tracking will easily allow it.
219  */
220 template <class ComputeTagsList, bool ExpandSimpleTags>
221 struct expand_subitems;
222 
223 template <class... ComputeTags>
224 struct expand_subitems<tmpl::list<ComputeTags...>, true> {
225  template <typename SimpleTagsList>
226  using f = typename detail::expand_subitems_impl<select_expand_subitems_impl(
227  sizeof...(ComputeTags)),
228  expand_subitems_impl_helper>::
229  template f<tmpl::list<>, expand_simple_subitems<SimpleTagsList>,
230  ComputeTags...>;
231 };
232 
233 template <class... ComputeTags>
234 struct expand_subitems<tmpl::list<ComputeTags...>, false> {
235  template <typename SimpleTagsList>
236  using f = typename detail::expand_subitems_impl<
237  select_expand_subitems_impl(sizeof...(ComputeTags)),
238  expand_subitems_impl_helper>::template f<tmpl::list<>, SimpleTagsList,
239  ComputeTags...>;
240 };
241 
242 // The compile time here could be improved by having Subitems have a nested
243 // type alias that generates the list currently retrieved by `::type` on to
244 // the next call of `expand_subitems_from_list_impl`
245 template <typename FullTagList, typename BuildingTagList, typename Element>
246 using expand_subitems_from_list_impl_helper =
247  tmpl::append<tmpl::push_back<BuildingTagList, Element>,
248  typename Subitems<FullTagList, Element>::type>;
249 
250 template <typename ComputeTagsList>
251 struct expanded_list_from_full_list_impl;
252 
253 template <typename... ComputeTags>
254 struct expanded_list_from_full_list_impl<tmpl::list<ComputeTags...>> {
255  template <typename FullTagList>
256  using f =
257  typename expand_subitems_impl<select_expand_subitems_impl(
258  sizeof...(ComputeTags)),
259  expand_subitems_from_list_impl_helper>::
260  template f<FullTagList, tmpl::list<>, ComputeTags...>;
261 };
262 
263 template <>
264 struct expanded_list_from_full_list_impl<tmpl::list<>> {
265  template <typename FullTagList>
266  using f = tmpl::list<>;
267 };
268 } // namespace detail
269 
270 /*!
271  * \brief Returns a list of all the tags with the subitems expanded, but where
272  * the types for compute items are grabbed from the FullTagList instead of the
273  * tag list that is being built up.
274  *
275  * This is useful for generating a list with subitem-expanded compute items,
276  * without having it be prefixed with the full tags list or the simple tags
277  * list.
278  */
279 template <typename FullTagList, typename TagsList>
280 using expand_subitems_from_list =
281  typename detail::expanded_list_from_full_list_impl<TagsList>::template f<
282  FullTagList>;
283 
284 /*!
285  * Expand on the subitems in SimpleTagsList and ComputeTagsList. For a subitem
286  * `Varibles<Tag0, Tag1>` the order of the expanded tags is `Variables<Tag0,
287  * Tag1>, Tag0, Tag1`. The simple tag list is only expanded if
288  * `ExpandSimpleTags` is set to `true`, so if you already have an expanded
289  * simple tag list, you can avoid double expansion.
290  */
291 template <typename SimpleTagsList, typename ComputeTagsList,
292  bool ExpandSimpleTags>
293 using expand_subitems = typename detail::expand_subitems<
294  ComputeTagsList, ExpandSimpleTags>::template f<SimpleTagsList>;
295 
296 template <typename TagList, typename Tag>
297 using has_subitems = tmpl::not_<
299 
300 template <typename ComputeTag, typename ArgumentTag,
301  typename FoundComputeItemInBox>
302 struct report_missing_compute_item_argument {
303  static_assert(cpp17::is_same_v<ComputeTag, void>,
304  "A compute item's argument could not be found in the "
305  "DataBox or was found multiple times. See the first "
306  "template argument for the compute item and the second "
307  "for the missing argument.");
308 };
309 
310 template <typename ComputeTag, typename ArgumentTag>
311 struct report_missing_compute_item_argument<ComputeTag, ArgumentTag,
312  std::true_type> {
313  using type = void;
314 };
315 
316 template <typename TagList, typename ComputeTag>
317 struct create_dependency_graph {
318 #ifdef SPECTRE_DEBUG
319  using argument_check_assertion =
320  tmpl::transform<typename ComputeTag::argument_tags,
321  report_missing_compute_item_argument<
322  tmpl::pin<ComputeTag>, tmpl::_1,
323  DataBox_detail::has_unique_matching_tag<
324  tmpl::pin<TagList>, tmpl::_1>>>;
325 #endif // SPECTRE_DEBUG
326  // These edges record that a compute item's value depends on the
327  // values of it's arguments.
328  using compute_tag_argument_edges =
329  tmpl::transform<typename ComputeTag::argument_tags,
330  tmpl::bind<tmpl::edge,
331  tmpl::bind<DataBox_detail::first_matching_tag,
332  tmpl::pin<TagList>, tmpl::_1>,
333  tmpl::pin<ComputeTag>>>;
334  // These edges record that the values of the subitems of a compute
335  // item depend on the value of the compute item itself.
336  using subitem_reverse_edges =
337  tmpl::transform<typename Subitems<TagList, ComputeTag>::type,
338  tmpl::bind<tmpl::edge, tmpl::pin<ComputeTag>, tmpl::_1>>;
339 
340  using type = tmpl::append<compute_tag_argument_edges, subitem_reverse_edges>;
341 };
342 } // namespace DataBox_detail
343 
344 namespace DataBox_detail {
345 // Check if a tag has a name method
346 template <typename Tag, typename = std::nullptr_t>
347 struct tag_has_name {
348  static_assert(cpp17::is_same_v<Tag, const void* const*>,
349  "The tag does not have a static method 'name()' that returns a "
350  "std::string. See the first template parameter of "
351  "db::DataBox_detail::tag_has_name to see the problematic tag.");
352 };
353 template <typename Tag>
354 struct tag_has_name<
355  Tag, Requires<cpp17::is_same_v<decltype(Tag::name()), std::string>>> {};
356 
357 template <typename Tag, typename = std::nullptr_t>
358 struct check_simple_or_compute_tag {
359  static_assert(cpp17::is_same_v<Tag, const void* const*>,
360  "All tags added to a DataBox must derive off of db::SimpleTag "
361  "or db::ComputeTag, you cannot add a base tag itself. See the "
362  "first template parameter of "
363  "db::DataBox_detail::check_simple_or_compute_tag to see "
364  "the problematic tag.");
365 };
366 template <typename Tag>
367 struct check_simple_or_compute_tag<Tag, Requires<is_non_base_tag_v<Tag>>> {};
368 } // namespace DataBox_detail
369 
370 /*!
371  * \ingroup DataBoxGroup
372  * \brief A DataBox stores objects that can be retrieved by using Tags
373  * \warning
374  * The order of the tags in DataBoxes returned by db::create and
375  * db::create_from depends on implementation-defined behavior, and
376  * therefore should not be specified in source files. If explicitly
377  * naming a DataBox type is necessary they should be generated using
378  * db::compute_databox_type.
379  *
380  * \see db::create db::create_from
381  *
382  * @tparam Tags list of DataBoxTag's
383  */
384 template <typename... Tags>
385 class DataBox<tmpl::list<Tags...>>
386  : private DataBox_detail::DataBoxLeaf<
387  Tags, db::item_type<Tags, tmpl::list<Tags...>>>... {
388 #ifdef SPECTRE_DEBUG
389  static_assert(
390  tmpl2::flat_all_v<is_non_base_tag_v<Tags>...>,
391  "All structs used to Tag (compute) items in a DataBox must derive off of "
392  "db::SimpleTag. Another static_assert will tell you which tag is the "
393  "problematic one. Look for check_simple_or_compute_tag.");
394 #endif // ifdef SPECTRE_DEBUG
395 
396  public:
397  /*!
398  * \brief A typelist (`tmpl::list`) of Tags that the DataBox holds
399  */
400  using tags_list = tmpl::list<Tags...>;
401 
402  /// A list of all the compute item tags, excluding their subitems
403  using compute_item_tags =
404  tmpl::filter<tags_list, db::is_compute_item<tmpl::_1>>;
405 
406  /// A list of all the compute items, including subitems from the compute items
408  DataBox_detail::expand_subitems_from_list<tags_list, compute_item_tags>;
409 
410  /// A list of all the simple items, including subitems from the simple
411  /// items
412  using simple_item_tags =
413  tmpl::list_difference<tags_list, compute_with_subitems_tags>;
414 
415  /// A list of the simple items that have subitems, without expanding the
416  /// subitems out
417  using simple_subitems_tags = tmpl::filter<
419  tmpl::bind<DataBox_detail::has_subitems, tmpl::pin<tags_list>, tmpl::_1>>;
420 
421  /// A list of the expanded simple subitems, not including the main Subitem
422  /// tags themselves.
423  ///
424  /// Specifically, if there is a `Variables<Tag0, Tag1>`, then this list would
425  /// contain `Tag0, Tag1`.
426  using simple_only_expanded_subitems_tags = tmpl::flatten<tmpl::transform<
428 
429  /// \cond HIDDEN_SYMBOLS
430  /*!
431  * \note the default constructor is only used for serialization
432  */
433  DataBox() = default;
434  DataBox(DataBox&& rhs) noexcept(
436  cpp17::is_nothrow_move_constructible_v<DataBox_detail::DataBoxLeaf<
437  Tags, db::item_type<Tags, tmpl::list<Tags...>>>>...>) = default;
438  DataBox& operator=(DataBox&& rhs) noexcept(
440  cpp17::is_nothrow_move_assignable_v<DataBox_detail::DataBoxLeaf<
441  Tags, db::item_type<Tags, tmpl::list<Tags...>>>>...>) {
442  if (&rhs != this) {
443  ::expand_pack((get_deferred<Tags>() =
444  std::move(rhs.template get_deferred<Tags>()))...);
445  }
446  return *this;
447  }
448  DataBox(const DataBox& rhs) = delete;
449  DataBox& operator=(const DataBox& rhs) = delete;
450 #ifdef SPECTRE_DEBUG
451  // Destructor is used for triggering assertions
452  ~DataBox() noexcept {
453  EXPAND_PACK_LEFT_TO_RIGHT(DataBox_detail::tag_has_name<Tags>{});
455  DataBox_detail::check_simple_or_compute_tag<Tags>{});
456  }
457 #else // ifdef SPECTRE_DEBUG
458  ~DataBox() = default;
459 #endif // ifdef SPECTRE_DEBUG
460 
461  /// \endcond
462 
463  /// \cond HIDDEN_SYMBOLS
464  /// Retrieve the tag `Tag`, should be called by the free function db::get
465  template <typename Tag,
467  auto get() const noexcept -> const item_type<Tag, tags_list>&;
468 
469  /// Retrieve the tag `Tag`, should be called by the free function db::get
470  template <typename Tag,
472  auto get() const noexcept -> const DataBox<tags_list>&;
473  /// \endcond
474 
475  // clang-tidy: no non-const references
476  void pup(PUP::er& p) noexcept { // NOLINT
477  using non_subitems_tags =
478  tmpl::list_difference<simple_item_tags,
480 
481  // We do not send subitems for both simple items and compute items since
482  // they can be reconstructed very cheaply.
483  pup_impl(p, non_subitems_tags{}, compute_item_tags{});
484  }
485 
486  template <typename Box, typename... KeepTags, typename... AddTags,
487  typename... AddComputeTags, typename... Args>
488  constexpr DataBox(Box&& old_box, tmpl::list<KeepTags...> /*meta*/,
489  tmpl::list<AddTags...> /*meta*/,
490  tmpl::list<AddComputeTags...> /*meta*/,
491  Args&&... args) noexcept;
492 
493  template <typename... TagsInArgsOrder, typename... FullItems,
494  typename... ComputeTags, typename... FullComputeItems,
495  typename... Args>
496  constexpr DataBox(tmpl::list<TagsInArgsOrder...> /*meta*/,
497  tmpl::list<FullItems...> /*meta*/,
498  tmpl::list<ComputeTags...> /*meta*/,
499  tmpl::list<FullComputeItems...> /*meta*/,
500  Args&&... args) noexcept;
501  /// \endcond
502 
503  private:
504  template <typename... MutateTags, typename TagList, typename Invokable,
505  typename... Args>
506  // clang-tidy: redundant declaration
507  friend void mutate(gsl::not_null<DataBox<TagList>*> box, // NOLINT
508  Invokable&& invokable, Args&&... args) noexcept; // NOLINT
509 
510  template <typename... SimpleTags>
511  SPECTRE_ALWAYS_INLINE void copy_simple_items(
512  const DataBox& box, tmpl::list<SimpleTags...> /*meta*/) noexcept;
513 
514  // Creates a copy with no aliasing of items.
515  template <typename SimpleItemTags>
516  DataBox deep_copy() const noexcept;
517 
518  template <typename TagsList_>
519  // clang-tidy: redundant declaration
520  friend SPECTRE_ALWAYS_INLINE constexpr DataBox<TagsList_> // NOLINT
521  create_copy( // NOLINT
522  const DataBox<TagsList_>& box) noexcept;
523 
524  /*!
525  * \requires Type `T` is one of the Tags corresponding to an object stored in
526  * the DataBox
527  *
528  * \note This should not be used outside of implementation details
529  *
530  * @return The lazy object corresponding to the Tag `T`
531  */
532  template <typename T>
533  const Deferred<item_type<T, tags_list>>& get_deferred() const noexcept {
534  return static_cast<const DataBox_detail::DataBoxLeaf<
535  T, db::item_type<T, tags_list>>&>(*this)
536  .get();
537  }
538 
539  template <typename T>
540  Deferred<item_type<T, tags_list>>& get_deferred() noexcept {
541  return static_cast<
542  DataBox_detail::DataBoxLeaf<T, db::item_type<T, tags_list>>&>(
543  *this)
544  .get();
545  }
546 
547  // Adding compute items
548  template <typename ParentTag>
549  SPECTRE_ALWAYS_INLINE constexpr void add_sub_compute_item_tags_to_box(
550  tmpl::list<> /*meta*/, std::false_type /*meta*/) noexcept {}
551  template <typename ParentTag>
552  SPECTRE_ALWAYS_INLINE constexpr void add_sub_compute_item_tags_to_box(
553  tmpl::list<> /*meta*/, std::true_type /*meta*/) noexcept {}
554 
555  template <typename ParentTag, typename... Subtags>
556  SPECTRE_ALWAYS_INLINE constexpr void add_sub_compute_item_tags_to_box(
557  tmpl::list<Subtags...> /*meta*/,
558  std::false_type /*has_return_type_member*/) noexcept;
559  template <typename ParentTag, typename... Subtags>
560  SPECTRE_ALWAYS_INLINE constexpr void add_sub_compute_item_tags_to_box(
561  tmpl::list<Subtags...> /*meta*/,
562  std::true_type /*has_return_type_member*/) noexcept;
563 
564  template <typename ComputeItem, typename FullTagList,
565  typename... ComputeItemArgumentsTags>
566  constexpr void add_compute_item_to_box_impl(
567  tmpl::list<ComputeItemArgumentsTags...> /*meta*/) noexcept;
568 
569  template <typename Tag, typename FullTagList>
570  constexpr void add_compute_item_to_box() noexcept;
571  // End adding compute items
572 
573  // Adding simple items
574  template <typename ParentTag>
575  constexpr void add_subitem_tags_to_box(tmpl::list<> /*meta*/) noexcept {}
576 
577  template <typename ParentTag, typename... Subtags>
578  constexpr void add_subitem_tags_to_box(
579  tmpl::list<Subtags...> /*meta*/) noexcept;
580 
581  template <size_t ArgsIndex, typename Tag, typename... Ts>
582  constexpr cpp17::void_type add_item_to_box(
583  std::tuple<Ts...>& tupull) noexcept;
584  // End adding simple items
585 
586  template <typename FullTagList, typename... Ts, typename... AddItemTags,
587  typename... AddComputeTags, size_t... Is,
588  bool... DependenciesAddedBefore>
589  void add_items_to_box(std::tuple<Ts...>& tupull,
590  tmpl::list<AddItemTags...> /*meta*/,
592  tmpl::list<AddComputeTags...> /*meta*/) noexcept;
593 
594  // Merging DataBox's using create_from requires that all instantiations of
595  // DataBox be friends with each other.
596  template <typename OtherTags>
597  friend class DataBox;
598 
599  template <typename... OldTags, typename... TagsToCopy>
600  constexpr void merge_old_box(
601  const db::DataBox<tmpl::list<OldTags...>>& old_box,
602  tmpl::list<TagsToCopy...> /*meta*/) noexcept;
603 
604  template <typename... OldTags, typename... TagsToCopy>
605  constexpr void merge_old_box(db::DataBox<tmpl::list<OldTags...>>&& old_box,
606  tmpl::list<TagsToCopy...> /*meta*/) noexcept;
607 
608  // Serialization of DataBox
609  // make_deferred_helper is used to expand the parameter pack
610  // ComputeItemArgumentsTags
611  template <typename Tag, typename... ComputeItemArgumentsTags>
612  Deferred<db::item_type<Tag>> make_deferred_helper(
613  tmpl::list<ComputeItemArgumentsTags...> /*meta*/) noexcept;
614 
615  // clang-tidy: no non-const references
616  template <typename... NonSubitemsTags, typename... ComputeTags>
617  void pup_impl(PUP::er& p, tmpl::list<NonSubitemsTags...> /*meta*/, // NOLINT
618  tmpl::list<ComputeTags...> /*meta*/) noexcept;
619  // End serialization of DataBox
620 
621  // Mutating items in the DataBox
622  template <typename ParentTag>
623  constexpr void mutate_subitem_tags_in_box(tmpl::list<> /*meta*/) noexcept {}
624 
625  template <typename ParentTag, typename... Subtags>
626  constexpr void mutate_subitem_tags_in_box(
627  tmpl::list<Subtags...> /*meta*/) noexcept;
628 
629  template <typename ComputeItem,
631  constexpr void add_reset_compute_item_to_box(tmpl::list<> /*meta*/) noexcept {
632  }
633 
634  template <typename ComputeItem, typename... ComputeItemArgumentsTags,
636  constexpr void add_reset_compute_item_to_box(
637  tmpl::list<ComputeItemArgumentsTags...> /*meta*/) noexcept;
638 
639  template <typename... ComputeItemsToReset>
640  SPECTRE_ALWAYS_INLINE constexpr void reset_compute_items_after_mutate(
641  tmpl::list<ComputeItemsToReset...> /*meta*/) noexcept;
642 
643  SPECTRE_ALWAYS_INLINE constexpr void reset_compute_items_after_mutate(
644  tmpl::list<> /*meta*/) noexcept {}
645  // End mutating items in the DataBox
646 
647  using edge_list = tmpl::join<tmpl::transform<
649  DataBox_detail::create_dependency_graph<tmpl::pin<tags_list>, tmpl::_1>>>;
650 
651  bool mutate_locked_box_{false};
652 };
653 
654 // Adding compute items
655 namespace DataBox_detail {
656 template <bool IsMutating>
657 struct compute_item_function_pointer_type_impl;
658 
659 template <>
660 struct compute_item_function_pointer_type_impl<false> {
661  // get function pointer type for a non-mutating compute item
662  template <typename FullTagList, typename ComputeItem,
663  typename... ComputeItemArgumentsTags>
667 };
668 
669 template <>
670 struct compute_item_function_pointer_type_impl<true> {
671  // get function pointer type for a mutating compute item
672  template <typename FullTagList, typename ComputeItem,
673  typename... ComputeItemArgumentsTags>
674  using f =
675  void (*)(gsl::not_null<
679 };
680 
681 // Computes the function pointer type of the compute item
682 template <typename FullTagList, typename ComputeItem,
683  typename... ComputeItemArgumentsTags>
684 using compute_item_function_pointer_type =
685  typename compute_item_function_pointer_type_impl<has_return_type_member_v<
686  ComputeItem>>::template f<FullTagList, ComputeItem,
687  ComputeItemArgumentsTags...>;
688 
689 template <bool IsComputeTag>
690 struct get_argument_list_impl {
691  template <class Tag>
692  using f = tmpl::list<>;
693 };
694 
695 template <>
696 struct get_argument_list_impl<true> {
697  template <class Tag>
698  using f = typename Tag::argument_tags;
699 };
700 
701 /// Returns the argument_tags of a compute item. If the Tag is not a compute tag
702 /// then it returns tmpl::list<>
703 template <class Tag>
704 using get_argument_list = typename get_argument_list_impl<
705  ::db::is_compute_item_v<Tag>>::template f<Tag>;
706 } // namespace DataBox_detail
707 
708 template <typename... Tags>
709 template <typename ParentTag, typename... Subtags>
710 SPECTRE_ALWAYS_INLINE constexpr void
711 DataBox<tmpl::list<Tags...>>::add_sub_compute_item_tags_to_box(
712  tmpl::list<Subtags...> /*meta*/,
713  std::false_type /*has_return_type_member*/) noexcept {
714  const auto helper = [lazy_function = get_deferred<ParentTag>()](
715  auto tag) noexcept->decltype(auto) {
716  return Subitems<tmpl::list<Tags...>, ParentTag>::
717  template create_compute_item<decltype(tag)>(lazy_function.get());
718  };
720  (get_deferred<Subtags>() =
721  make_deferred_for_subitem<decltype(helper(Subtags{}))>(helper,
722  Subtags{})));
723 }
724 
725 template <typename... Tags>
726 template <typename ParentTag, typename... Subtags>
727 SPECTRE_ALWAYS_INLINE constexpr void
728 DataBox<tmpl::list<Tags...>>::add_sub_compute_item_tags_to_box(
729  tmpl::list<Subtags...> /*meta*/,
730  std::true_type /*has_return_type_member*/) noexcept {
731  const auto helper = [lazy_function = get_deferred<ParentTag>()](
732  const auto result, auto tag) noexcept {
733  Subitems<tmpl::list<Tags...>, ParentTag>::template create_compute_item<
734  decltype(tag)>(result, lazy_function.get());
735  };
737  (get_deferred<Subtags>() =
738  make_deferred_for_subitem<db::item_type<Subtags>>(helper,
739  Subtags{})));
740 }
741 
742 namespace DataBox_detail {
743 // This function exists so that the user can look at the template
744 // arguments to find out what triggered the static_assert.
745 template <typename ComputeItem, typename Argument, typename FullTagList>
746 constexpr cpp17::void_type check_compute_item_argument_exists() noexcept {
747  using compute_item_index = tmpl::index_of<FullTagList, ComputeItem>;
748  static_assert(
749  tmpl::less<tmpl::index_if<FullTagList,
750  std::is_same<tmpl::pin<Argument>, tmpl::_1>,
751  compute_item_index>,
752  compute_item_index>::value,
753  "The dependencies of a ComputeItem must be added before the "
754  "ComputeItem itself. This is done to ensure no cyclic "
755  "dependencies arise. See the first and second template "
756  "arguments of the instantiation of this function for the "
757  "compute item and missing dependency.");
758  return cpp17::void_type{};
759 }
760 } // namespace DataBox_detail
761 
762 template <typename... Tags>
763 template <typename ComputeItem, typename FullTagList,
764  typename... ComputeItemArgumentsTags>
765 SPECTRE_ALWAYS_INLINE constexpr void
766 DataBox<tmpl::list<Tags...>>::add_compute_item_to_box_impl(
767  tmpl::list<ComputeItemArgumentsTags...> /*meta*/) noexcept {
769  tmpl2::flat_all_v<is_tag_v<ComputeItemArgumentsTags>...>,
770  "Cannot have non-DataBoxTag arguments to a ComputeItem. Please make "
771  "sure all the specified argument_tags in the ComputeItem derive from "
772  "db::SimpleTag.");
774  not tmpl2::flat_any_v<
775  cpp17::is_same_v<ComputeItemArgumentsTags, ComputeItem>...>,
776  "A ComputeItem cannot take its own Tag as an argument.");
777  expand_pack(DataBox_detail::check_compute_item_argument_exists<
778  ComputeItem, ComputeItemArgumentsTags, FullTagList>()...);
779 
780  get_deferred<ComputeItem>() =
782  DataBox_detail::compute_item_function_pointer_type<
783  FullTagList, ComputeItem, ComputeItemArgumentsTags...>{
784  ComputeItem::function},
785  get_deferred<ComputeItemArgumentsTags>()...);
786 }
787 
788 template <typename... Tags>
789 template <typename Tag, typename FullTagList>
790 SPECTRE_ALWAYS_INLINE constexpr void
791 db::DataBox<tmpl::list<Tags...>>::add_compute_item_to_box() noexcept {
792  add_compute_item_to_box_impl<Tag, FullTagList>(
793  tmpl::transform<typename Tag::argument_tags,
794  tmpl::bind<DataBox_detail::first_matching_tag,
795  tmpl::pin<tmpl::list<Tags...>>, tmpl::_1>>{});
796  add_sub_compute_item_tags_to_box<Tag>(
797  typename Subitems<tmpl::list<Tags...>, Tag>::type{},
798  typename has_return_type_member<
799  Subitems<tmpl::list<Tags...>, Tag>>::type{});
800 }
801 // End adding compute items
802 
803 // Adding simple items
804 template <typename... Tags>
805 template <typename ParentTag, typename... Subtags>
806 SPECTRE_ALWAYS_INLINE constexpr void
807 db::DataBox<tmpl::list<Tags...>>::add_subitem_tags_to_box(
808  tmpl::list<Subtags...> /*meta*/) noexcept {
809  const auto helper = [this](auto tag_v) {
810  (void)this; // Compiler bug warns this is unused
811  using tag = decltype(tag_v);
812  get_deferred<tag>() = Deferred<db::item_type<tag>>(db::item_type<tag>{});
813  Subitems<tmpl::list<Tags...>, ParentTag>::template create_item<tag>(
814  make_not_null(&get_deferred<ParentTag>().mutate()),
815  make_not_null(&get_deferred<tag>().mutate()));
816  };
817 
818  EXPAND_PACK_LEFT_TO_RIGHT(helper(Subtags{}));
819 }
820 
821 template <typename... Tags>
822 template <size_t ArgsIndex, typename Tag, typename... Ts>
824 db::DataBox<tmpl::list<Tags...>>::add_item_to_box(
825  std::tuple<Ts...>& tupull) noexcept {
826  using ArgType = std::tuple_element_t<ArgsIndex, std::tuple<Ts...>>;
827  static_assert(not tt::is_a<Deferred, std::decay_t<ArgType>>::value,
828  "Cannot pass a Deferred into the DataBox as an Item. This "
829  "functionally can trivially be added, however it is "
830  "intentionally omitted because users of DataBox are not "
831  "supposed to deal with Deferred.");
832  get_deferred<Tag>() = Deferred<item_type<Tag>>(
833  std::forward<ArgType>(std::get<ArgsIndex>(tupull)));
834  add_subitem_tags_to_box<Tag>(
835  typename Subitems<tmpl::list<Tags...>, Tag>::type{});
836  return cpp17::void_type{}; // must return in constexpr function
837 }
838 // End adding simple items
839 
840 // Add items or compute items to the TaggedDeferredTuple `data`. If
841 // `AddItemTags...` is an empty pack then only compute items are added, while if
842 // `AddComputeTags...` is an empty pack only items are added. Items are
843 // always added before compute items.
844 template <typename... Tags>
845 template <typename FullTagList, typename... Ts, typename... AddItemTags,
846  typename... AddComputeTags, size_t... Is,
847  bool... DependenciesAddedBefore>
848 SPECTRE_ALWAYS_INLINE void DataBox<tmpl::list<Tags...>>::add_items_to_box(
849  std::tuple<Ts...>& tupull, tmpl::list<AddItemTags...> /*meta*/,
851  tmpl::list<AddComputeTags...> /*meta*/) noexcept {
852  expand_pack(add_item_to_box<Is, AddItemTags>(tupull)...);
854  add_compute_item_to_box<AddComputeTags, FullTagList>());
855 }
856 
857 namespace DataBox_detail {
858 // This function (and its unused template argument) exist so that
859 // users can see what tag has the wrong type when the static_assert
860 // fails.
861 template <typename Tag, typename TagType, typename SuppliedType>
862 constexpr int check_argument_type() noexcept {
863  static_assert(cpp17::is_same_v<TagType, SuppliedType>,
864  "The type of each Tag must be the same as the type being "
865  "passed into the function creating the new DataBox. See the "
866  "function template parameters for the tag, expected type, and "
867  "supplied type.");
868  return 0;
869 }
870 } // namespace DataBox_detail
871 
872 /// \cond
873 template <typename... Tags>
874 template <typename... TagsInArgsOrder, typename... FullItems,
875  typename... ComputeTags, typename... FullComputeItems,
876  typename... Args>
877 constexpr DataBox<tmpl::list<Tags...>>::DataBox(
878  tmpl::list<TagsInArgsOrder...> /*meta*/, tmpl::list<FullItems...> /*meta*/,
879  tmpl::list<ComputeTags...> /*meta*/,
880  tmpl::list<FullComputeItems...> /*meta*/, Args&&... args) noexcept {
882  sizeof...(Tags) == sizeof...(FullItems) + sizeof...(FullComputeItems),
883  "Must pass in as many (compute) items as there are Tags.");
884  DEBUG_STATIC_ASSERT(sizeof...(TagsInArgsOrder) == sizeof...(Args),
885  "Must pass in as many arguments as AddTags");
888  "Cannot store a DataBox inside a DataBox.");
889 #ifdef SPECTRE_DEBUG
890  // The check_argument_type call is very expensive compared to the majority of
891  // DataBox
892  expand_pack(
893  DataBox_detail::check_argument_type<TagsInArgsOrder,
894  typename TagsInArgsOrder::type,
895  std::decay_t<Args>>()...);
896 #endif // SPECTRE_DEBUG
897 
898  std::tuple<Args...> args_tuple(std::forward<Args>(args)...);
899  add_items_to_box<tmpl::list<FullItems..., FullComputeItems...>>(
900  args_tuple, tmpl::list<TagsInArgsOrder...>{},
901  std::make_index_sequence<sizeof...(TagsInArgsOrder)>{},
902  tmpl::list<ComputeTags...>{});
903 }
904 
905 ////////////////////////////////////////////////////////////////
906 // Construct DataBox from an existing one
907 template <typename... Tags>
908 template <typename... OldTags, typename... TagsToCopy>
909 constexpr void DataBox<tmpl::list<Tags...>>::merge_old_box(
910  const db::DataBox<tmpl::list<OldTags...>>& old_box,
911  tmpl::list<TagsToCopy...> /*meta*/) noexcept {
912  EXPAND_PACK_LEFT_TO_RIGHT(get_deferred<TagsToCopy>() =
913  old_box.template get_deferred<TagsToCopy>());
914 }
915 
916 template <typename... Tags>
917 template <typename... OldTags, typename... TagsToCopy>
918 constexpr void DataBox<tmpl::list<Tags...>>::merge_old_box(
919  db::DataBox<tmpl::list<OldTags...>>&& old_box,
920  tmpl::list<TagsToCopy...> /*meta*/) noexcept {
922  (void(get_deferred<TagsToCopy>() =
923  std::move(old_box.template get_deferred<TagsToCopy>())),
924  '0')...};
925 }
926 
927 template <typename... Tags>
928 template <typename Box, typename... KeepTags, typename... AddTags,
929  typename... AddComputeTags, typename... Args>
930 constexpr DataBox<tmpl::list<Tags...>>::DataBox(
931  Box&& old_box, tmpl::list<KeepTags...> /*meta*/,
932  tmpl::list<AddTags...> /*meta*/, tmpl::list<AddComputeTags...> /*meta*/,
933  Args&&... args) noexcept {
934  expand_pack(
935  DataBox_detail::check_argument_type<AddTags, typename AddTags::type,
936  std::decay_t<Args>>()...);
937 
938  merge_old_box(std::forward<Box>(old_box), tmpl::list<KeepTags...>{});
939 
940  // Add in new simple and compute tags
941  std::tuple<Args...> args_tuple(std::forward<Args>(args)...);
942  add_items_to_box<tmpl::list<Tags...>>(
943  args_tuple, tmpl::list<AddTags...>{},
944  std::make_index_sequence<sizeof...(AddTags)>{},
945  tmpl::list<AddComputeTags...>{});
946 }
947 
948 ////////////////////////////////////////////////////////////////
949 // Create a copy of the DataBox with no aliasing items.
950 template <typename... Tags>
951 template <typename... SimpleTags>
952 SPECTRE_ALWAYS_INLINE void DataBox<tmpl::list<Tags...>>::copy_simple_items(
953  const DataBox& box, tmpl::list<SimpleTags...> /*meta*/) noexcept {
954  EXPAND_PACK_LEFT_TO_RIGHT((get_deferred<SimpleTags>() =
955  box.get_deferred<SimpleTags>().deep_copy()));
956 }
957 
958 template <typename... Tags>
959 template <typename SimpleItemTags>
960 DataBox<tmpl::list<Tags...>> DataBox<tmpl::list<Tags...>>::deep_copy() const
961  noexcept {
962  DataBox new_box{};
963  new_box.copy_simple_items(*this, simple_item_tags{});
964 
965  std::tuple<> empty_tuple{};
966  new_box.add_items_to_box<tmpl::list<Tags...>>(empty_tuple, tmpl::list<>{},
969  return new_box;
970 }
971 /// \endcond
972 
973 ////////////////////////////////////////////////////////////////
974 // Serialization of DataBox
975 
976 // Function used to expand the parameter pack ComputeItemArgumentsTags
977 template <typename... Tags>
978 template <typename Tag, typename... ComputeItemArgumentsTags>
979 Deferred<db::item_type<Tag>> DataBox<tmpl::list<Tags...>>::make_deferred_helper(
980  tmpl::list<ComputeItemArgumentsTags...> /*meta*/) noexcept {
981  return make_deferred<db::item_type<Tag>>(
982  Tag::function, get_deferred<ComputeItemArgumentsTags>()...);
983 }
984 
985 template <typename... Tags>
986 template <typename... NonSubitemsTags, typename... ComputeTags>
987 void DataBox<tmpl::list<Tags...>>::pup_impl(
988  PUP::er& p, tmpl::list<NonSubitemsTags...> /*meta*/,
989  tmpl::list<ComputeTags...> /*meta*/) noexcept {
990  const auto pup_simple_item = [&p, this](auto current_tag) noexcept {
991  (void)this; // Compiler bug warning this capture is not used
992  using tag = decltype(current_tag);
993  if (p.isUnpacking()) {
994  db::item_type<tag> t{};
995  p | t;
996  get_deferred<tag>() = Deferred<db::item_type<tag>>(std::move(t));
997  add_subitem_tags_to_box<tag>(
998  typename Subitems<tmpl::list<Tags...>, tag>::type{});
999  } else {
1000  p | get_deferred<tag>().mutate();
1001  }
1002  };
1003  (void)pup_simple_item; // Silence GCC warning about unused variable
1004  EXPAND_PACK_LEFT_TO_RIGHT(pup_simple_item(NonSubitemsTags{}));
1005 
1006  const auto pup_compute_item = [&p, this](auto current_tag) noexcept {
1007  (void)this; // Compiler bug warns this isn't used
1008  using tag = decltype(current_tag);
1009  if (p.isUnpacking()) {
1010  get_deferred<tag>() =
1011  make_deferred_helper<tag>(typename tag::argument_tags{});
1012  }
1013  get_deferred<tag>().pack_unpack_lazy_function(p);
1014  if (p.isUnpacking()) {
1015  add_sub_compute_item_tags_to_box<tag>(
1016  typename Subitems<tmpl::list<Tags...>, tag>::type{},
1017  typename has_return_type_member<
1018  Subitems<tmpl::list<Tags...>, tag>>::type{});
1019  }
1020  };
1021  (void)pup_compute_item; // Silence GCC warning about unused variable
1022  EXPAND_PACK_LEFT_TO_RIGHT(pup_compute_item(ComputeTags{}));
1023 }
1024 
1025 ////////////////////////////////////////////////////////////////
1026 // Mutating items in the DataBox
1027 // Classes and functions necessary for db::mutate to work
1028 template <typename... Tags>
1029 template <typename ComputeItem, typename... ComputeItemArgumentsTags,
1031 SPECTRE_ALWAYS_INLINE constexpr void
1032 DataBox<tmpl::list<Tags...>>::add_reset_compute_item_to_box(
1033  tmpl::list<ComputeItemArgumentsTags...> /*meta*/) noexcept {
1034  get_deferred<ComputeItem>().reset();
1035  mutate_subitem_tags_in_box<ComputeItem>(
1036  typename Subitems<tmpl::list<Tags...>, ComputeItem>::type{});
1037 }
1038 
1039 template <typename... Tags>
1040 template <typename... ComputeItemsToReset>
1041 SPECTRE_ALWAYS_INLINE constexpr void
1042 db::DataBox<tmpl::list<Tags...>>::reset_compute_items_after_mutate(
1043  tmpl::list<ComputeItemsToReset...> /*meta*/) noexcept {
1044  EXPAND_PACK_LEFT_TO_RIGHT(add_reset_compute_item_to_box<ComputeItemsToReset>(
1045  DataBox_detail::get_argument_list<ComputeItemsToReset>{}));
1046 
1047  using next_compute_tags_to_reset =
1048  tmpl::transform<tmpl::append<tmpl::filter<
1049  typename DataBox<tmpl::list<Tags...>>::edge_list,
1051  tmpl::get_source<tmpl::_1>>>...>,
1052  tmpl::get_destination<tmpl::_1>>;
1053  reset_compute_items_after_mutate(next_compute_tags_to_reset{});
1054 }
1055 
1056 template <typename... Tags>
1057 template <typename ParentTag, typename... Subtags>
1058 SPECTRE_ALWAYS_INLINE constexpr void
1059 db::DataBox<tmpl::list<Tags...>>::mutate_subitem_tags_in_box(
1060  tmpl::list<Subtags...> /*meta*/) noexcept {
1061  const auto helper = [this](auto tag_v) {
1062  (void)this; // Compiler bug warns about unused this capture
1063  using tag = decltype(tag_v);
1064  if (is_compute_item_v<ParentTag>) {
1065  get_deferred<tag>().reset();
1066  } else {
1067  Subitems<tmpl::list<Tags...>, ParentTag>::template create_item<tag>(
1068  make_not_null(&get_deferred<ParentTag>().mutate()),
1069  make_not_null(&get_deferred<tag>().mutate()));
1070  }
1071  };
1072 
1073  EXPAND_PACK_LEFT_TO_RIGHT(helper(Subtags{}));
1074 }
1075 
1076 /*!
1077  * \ingroup DataBoxGroup
1078  * \brief Allows changing the state of one or more non-computed elements in
1079  * the DataBox
1080  *
1081  * `mutate()`'s first argument is the DataBox from which to retrieve the tags
1082  * `MutateTags`. The objects corresponding to the `MutateTags` are then passed
1083  * to `invokable`, which is a lambda or a function object taking as many
1084  * arguments as there are `MutateTags` and with the arguments being of types
1085  * `gsl::not_null<db::item_type<MutateTags>*>...`. Inside the `invokable` no
1086  * items can be retrieved from the DataBox `box`. This is to avoid confusing
1087  * subtleties with order of evaluation of compute items, as well as dangling
1088  * references. If an `invokable` needs read access to items in `box` they should
1089  * be passed as additional arguments to `mutate`. Capturing them by reference in
1090  * a lambda does not work because of a bug in GCC 6.3 and earlier. For a
1091  * function object the read-only items can also be stored as const references
1092  * inside the object by passing `db::get<TAG>(t)` to the constructor.
1093  *
1094  * \example
1095  * \snippet Test_DataBox.cpp databox_mutate_example
1096  */
1097 template <typename... MutateTags, typename TagList, typename Invokable,
1098  typename... Args>
1099 void mutate(const gsl::not_null<DataBox<TagList>*> box, Invokable&& invokable,
1100  Args&&... args) noexcept {
1101  static_assert(
1103  DataBox_detail::has_unique_matching_tag_v<TagList, MutateTags>...>,
1104  "One of the tags being mutated could not be found in the DataBox or "
1105  "is a base tag identifying more than one tag.");
1106  static_assert(
1107  not tmpl2::flat_any_v<db::is_compute_item_v<
1108  DataBox_detail::first_matching_tag<TagList, MutateTags>>...>,
1109  "Cannot mutate a compute item");
1110  if (UNLIKELY(box->mutate_locked_box_)) {
1111  ERROR(
1112  "Unable to mutate a DataBox that is already being mutated. This "
1113  "error occurs when mutating a DataBox from inside the invokable "
1114  "passed to the mutate function.");
1115  }
1116  box->mutate_locked_box_ = true;
1117  invokable(
1118  make_not_null(
1119  &box->template get_deferred<
1120  DataBox_detail::first_matching_tag<TagList, MutateTags>>()
1121  .mutate())...,
1122  std::forward<Args>(args)...);
1123  using mutate_tags_list =
1124  tmpl::list<DataBox_detail::first_matching_tag<TagList, MutateTags>...>;
1125  // For all the tags in the DataBox, check if one of their subtags is
1126  // being mutated and if so add the parent to the list of tags
1127  // being mutated. Then, remove any tags that would be passed
1128  // multiple times.
1129  using extra_mutated_tags = tmpl::list_difference<
1130  tmpl::filter<
1131  TagList,
1132  tmpl::bind<
1133  tmpl::found, Subitems<tmpl::pin<TagList>, tmpl::_1>,
1134  tmpl::pin<tmpl::bind<tmpl::list_contains,
1135  tmpl::pin<mutate_tags_list>, tmpl::_1>>>>,
1136  mutate_tags_list>;
1137  // Extract the subtags inside the MutateTags and reset compute items
1138  // depending on those too.
1139  using full_mutated_items = tmpl::append<
1140  DataBox_detail::expand_subitems_from_list<TagList, mutate_tags_list>,
1141  extra_mutated_tags>;
1142 
1143  using first_compute_items_to_reset =
1144  tmpl::transform<tmpl::filter<typename DataBox<TagList>::edge_list,
1145  tmpl::bind<tmpl::list_contains,
1146  tmpl::pin<full_mutated_items>,
1147  tmpl::get_source<tmpl::_1>>>,
1148  tmpl::get_destination<tmpl::_1>>;
1149 
1151  box->template mutate_subitem_tags_in_box<MutateTags>(
1152  typename Subitems<TagList, MutateTags>::type{}));
1153  box->template reset_compute_items_after_mutate(
1154  first_compute_items_to_reset{});
1155 
1156  box->mutate_locked_box_ = false;
1157 }
1158 
1159 ////////////////////////////////////////////////////////////////
1160 // Retrieving items from the DataBox
1161 
1162 /// \cond
1163 template <typename... Tags>
1164 template <typename Tag, Requires<not cpp17::is_same_v<Tag, ::Tags::DataBox>>>
1165 SPECTRE_ALWAYS_INLINE auto DataBox<tmpl::list<Tags...>>::get() const noexcept
1166  -> const item_type<Tag, tags_list>& {
1168  not DataBox_detail::has_no_matching_tag_v<tags_list, Tag>,
1169  "Found no tags in the DataBox that match the tag being retrieved.");
1171  DataBox_detail::has_unique_matching_tag_v<tags_list, Tag>,
1172  "Found more than one tag in the DataBox that matches the tag "
1173  "being retrieved. This happens because more than one tag with the same "
1174  "base (class) tag was added to the DataBox.");
1175  using derived_tag = DataBox_detail::first_matching_tag<tags_list, Tag>;
1176  if (UNLIKELY(mutate_locked_box_)) {
1177  ERROR("Unable to retrieve a (compute) item '"
1178  << derived_tag::name()
1179  << "' from the DataBox from within a "
1180  "call to mutate. You must pass these either through the capture "
1181  "list of the lambda or the constructor of a class, this "
1182  "restriction exists to avoid complexity.");
1183  }
1184  return get_deferred<derived_tag>().get();
1185 }
1186 
1187 template <typename... Tags>
1188 template <typename Tag, Requires<cpp17::is_same_v<Tag, ::Tags::DataBox>>>
1189 SPECTRE_ALWAYS_INLINE auto DataBox<tmpl::list<Tags...>>::get() const noexcept
1190  -> const DataBox<tags_list>& {
1191  if (UNLIKELY(mutate_locked_box_)) {
1192  ERROR(
1193  "Unable to retrieve a (compute) item 'DataBox' from the DataBox from "
1194  "within a call to mutate. You must pass these either through the "
1195  "capture list of the lambda or the constructor of a class, this "
1196  "restriction exists to avoid complexity.");
1197  }
1198  return *this;
1199 }
1200 /// \endcond
1201 
1202 /*!
1203  * \ingroup DataBoxGroup
1204  * \brief Retrieve the item with tag `Tag` from the DataBox
1205  * \requires Type `Tag` is one of the Tags corresponding to an object stored in
1206  * the DataBox
1207  *
1208  * \return The object corresponding to the tag `Tag`
1209  */
1210 template <typename Tag, typename TagList>
1211 SPECTRE_ALWAYS_INLINE const auto& get(const DataBox<TagList>& box) noexcept {
1212  return box.template get<Tag>();
1213 }
1214 
1215 /*!
1216  * \ingroup DataBoxGroup
1217  * \brief List of Tags to remove from the DataBox
1218  */
1219 template <typename... Tags>
1220 using RemoveTags = tmpl::flatten<tmpl::list<Tags...>>;
1221 
1222 /*!
1223  * \ingroup DataBoxGroup
1224  * \brief List of Tags to add to the DataBox
1225  */
1226 template <typename... Tags>
1227 using AddSimpleTags = tmpl::flatten<tmpl::list<Tags...>>;
1228 
1229 /*!
1230  * \ingroup DataBoxGroup
1231  * \brief List of Compute Item Tags to add to the DataBox
1232  */
1233 template <typename... Tags>
1234 using AddComputeTags = tmpl::flatten<tmpl::list<Tags...>>;
1235 
1236 /*!
1237  * \ingroup DataBoxGroup
1238  * \brief Create a new DataBox
1239  *
1240  * \details
1241  * Creates a new DataBox holding types Tags::type filled with the arguments
1242  * passed to the function. Compute items must be added so that the dependencies
1243  * of a compute item are added before the compute item. For example, say you
1244  * have compute items `A` and `B` where `B` depends on `A`, then you must
1245  * add them using `db::AddComputeTags<A, B>`.
1246  *
1247  * \example
1248  * \snippet Test_DataBox.cpp create_databox
1249  *
1250  * \see create_from
1251  *
1252  * \tparam AddSimpleTags the tags of the args being added
1253  * \tparam AddComputeTags list of \ref ComputeTag "compute item tags"
1254  * to add to the DataBox
1255  * \param args the data to be added to the DataBox
1256  */
1257 template <typename AddSimpleTags, typename AddComputeTags = tmpl::list<>,
1258  typename... Args>
1259 SPECTRE_ALWAYS_INLINE constexpr auto create(Args&&... args) {
1260  static_assert(tt::is_a_v<tmpl::list, AddComputeTags>,
1261  "AddComputeTags must be a tmpl::list");
1262  static_assert(tt::is_a_v<tmpl::list, AddSimpleTags>,
1263  "AddSimpleTags must be a tmpl::list");
1264  static_assert(
1265  not tmpl::any<AddSimpleTags, is_compute_item<tmpl::_1>>::value,
1266  "Cannot add any ComputeTags in the AddSimpleTags list, must use the "
1267  "AddComputeTags list.");
1268  static_assert(
1269  tmpl::all<AddComputeTags, is_compute_item<tmpl::_1>>::value,
1270  "Cannot add any SimpleTags in the AddComputeTags list, must use the "
1271  "AddSimpleTags list.");
1272 
1273  using tag_list =
1274  DataBox_detail::expand_subitems<AddSimpleTags, AddComputeTags, true>;
1275  using full_items =
1276  DataBox_detail::expand_subitems<AddSimpleTags, tmpl::list<>, true>;
1277  using full_compute_items =
1278  DataBox_detail::expand_subitems_from_list<tag_list, AddComputeTags>;
1279 
1281  AddSimpleTags{}, full_items{}, AddComputeTags{}, full_compute_items{},
1282  std::forward<Args>(args)...);
1283 }
1284 
1285 namespace DataBox_detail {
1286 template <typename RemoveTags, typename AddTags, typename AddComputeTags,
1287  typename Box, typename... Args>
1288 SPECTRE_ALWAYS_INLINE constexpr auto create_from(Box&& box,
1289  Args&&... args) noexcept {
1290  static_assert(tmpl::size<AddTags>::value == sizeof...(Args),
1291  "Must pass in as many arguments as AddTags to db::create_from");
1292 
1293  // 1. Full list of old tags, and the derived tags list of the RemoveTags
1294  using old_box_tags = typename std::decay_t<Box>::tags_list;
1295  static_assert(
1296  tmpl::all<RemoveTags, DataBox_detail::has_unique_matching_tag<
1297  tmpl::pin<old_box_tags>, tmpl::_1>>::value,
1298  "One of the tags being removed could not be found in the DataBox or "
1299  "is a base tag identifying more than one tag.");
1300  using remove_tags =
1301  tmpl::transform<RemoveTags,
1302  tmpl::bind<DataBox_detail::first_matching_tag,
1303  tmpl::pin<old_box_tags>, tmpl::_1>>;
1304 
1305  // 2. Expand simple remove tags and compute remove tags
1306  using compute_tags_to_remove =
1307  tmpl::filter<remove_tags, db::is_compute_item<tmpl::_1>>;
1308  using compute_tags_to_remove_with_subitems =
1309  DataBox_detail::expand_subitems_from_list<old_box_tags,
1310  compute_tags_to_remove>;
1311  using simple_tags_to_remove =
1312  tmpl::list_difference<remove_tags, compute_tags_to_remove>;
1313  using simple_tags_to_remove_with_subitems =
1314  DataBox_detail::expand_subitems<tmpl::list<>, simple_tags_to_remove,
1315  false>;
1316 
1317  // 3. Expand AddTags (these are just the simple tags)
1318  using simple_tags_to_add_with_subitems =
1319  DataBox_detail::expand_subitems<AddTags, tmpl::list<>, true>;
1320 
1321  // 4. Create new list of tags by removing all the remove tags, and adding all
1322  // the AddTags, including subitems
1323  using simple_tags_to_keep =
1324  tmpl::list_difference<typename std::decay_t<Box>::simple_item_tags,
1325  simple_tags_to_remove_with_subitems>;
1326  using new_simple_tags =
1327  tmpl::append<simple_tags_to_keep, simple_tags_to_add_with_subitems>;
1328 
1329  // 5. Create the list of compute items with the RemoveTags removed
1330  using compute_tags_to_keep = tmpl::list_difference<
1332  compute_tags_to_remove_with_subitems>;
1333 
1334  // 6. List of the old tags that are being kept
1335  using old_tags_to_keep =
1336  tmpl::append<simple_tags_to_keep, compute_tags_to_keep>;
1337 
1338  // 7. List of the new tags, we only need to expand the AddComputeTags now
1339  using new_tag_list = DataBox_detail::expand_subitems<
1340  tmpl::append<new_simple_tags, compute_tags_to_keep>, AddComputeTags,
1341  false>;
1342 
1344  tmpl::size<tmpl::list_difference<AddTags, RemoveTags>>::value ==
1345  tmpl::size<AddTags>::value,
1346  "Use db::mutate to mutate simple items, do not remove and add them with "
1347  "db::create_from.");
1348 
1349 #ifdef SPECTRE_DEBUG
1350  // Check that we're not removing a subitem itself, should remove the parent.
1351  using compute_subitems_tags =
1352  tmpl::filter<typename std::decay_t<Box>::compute_item_tags,
1353  tmpl::bind<DataBox_detail::has_subitems,
1354  tmpl::pin<old_box_tags>, tmpl::_1>>;
1355 
1356  using compute_only_expand_subitems_tags = tmpl::flatten<tmpl::transform<
1357  compute_subitems_tags, db::Subitems<tmpl::pin<old_box_tags>, tmpl::_1>>>;
1358  using all_only_subitems_tags = tmpl::append<
1360  compute_only_expand_subitems_tags>;
1361  using non_expand_subitems_remove_tags =
1362  tmpl::list_difference<RemoveTags, all_only_subitems_tags>;
1363  static_assert(tmpl::size<non_expand_subitems_remove_tags>::value ==
1364  tmpl::size<RemoveTags>::value,
1365  "You are not allowed to remove part of a Subitem from the "
1366  "DataBox using db::create_from.");
1367 #endif // ifdef SPECTRE_DEBUG
1368 
1369  return DataBox<new_tag_list>(std::forward<Box>(box), old_tags_to_keep{},
1370  AddTags{}, AddComputeTags{},
1371  std::forward<Args>(args)...);
1372 }
1373 } // namespace DataBox_detail
1374 
1375 /*!
1376  * \ingroup DataBoxGroup
1377  * \brief Create a new DataBox from an existing one adding or removing items
1378  * and compute items
1379  *
1380  * When passed an lvalue this function will return a const DataBox
1381  * whose members cannot be modified. When passed a (mutable) rvalue
1382  * this function will return a mutable DataBox.
1383  *
1384  * Note that in the const lvalue case the output DataBox shares all
1385  * items that were not removed with the input DataBox. This means if an item is
1386  * mutated in the input DataBox it is also mutated in the output DataBox.
1387  * Similarly, if a compute item is evaluated in either the returned DataBox or
1388  * the input DataBox it is evaluated in both (at the cost of only evaluating it
1389  * once).
1390  *
1391  * \example
1392  * Removing an item or compute item is done using:
1393  * \snippet Test_DataBox.cpp create_from_remove
1394  * Adding an item is done using:
1395  * \snippet Test_DataBox.cpp create_from_add_item
1396  * Adding a compute item is done using:
1397  * \snippet Test_DataBox.cpp create_from_add_compute_item
1398  *
1399  * \see create DataBox
1400  *
1401  * \tparam RemoveTags typelist of Tags to remove
1402  * \tparam AddTags typelist of Tags corresponding to the arguments to be
1403  * added
1404  * \tparam AddComputeTags list of \ref ComputeTag "compute item tags"
1405  * to add to the DataBox
1406  * \param box the DataBox the new box should be based off
1407  * \param args the values for the items to add to the DataBox
1408  * \return DataBox like `box` but altered by RemoveTags and AddTags
1409  *@{
1410  */
1411 template <typename RemoveTags, typename AddTags = tmpl::list<>,
1412  typename AddComputeTags = tmpl::list<>, typename TagsList,
1413  typename... Args>
1415  Args&&... args) noexcept {
1416  return DataBox_detail::create_from<RemoveTags, AddTags, AddComputeTags>(
1417  std::move(box), std::forward<Args>(args)...);
1418 }
1419 
1420 /// \cond HIDDEN_SYMBOLS
1421 // Clang warns that the const qualifier on the return type has no
1422 // effect. It does have an effect.
1423 #ifdef __clang__
1424 #pragma GCC diagnostic push
1425 #pragma GCC diagnostic ignored "-Wignored-qualifiers"
1426 #endif
1427 template <typename RemoveTags, typename AddTags = tmpl::list<>,
1428  typename AddComputeTags = tmpl::list<>, typename TagsList,
1429  typename... Args>
1430 SPECTRE_ALWAYS_INLINE constexpr const auto create_from(
1431  const db::DataBox<TagsList>& box, Args&&... args) noexcept {
1432  return DataBox_detail::create_from<RemoveTags, AddTags, AddComputeTags>(
1433  box, std::forward<Args>(args)...);
1434 }
1435 #ifdef __clang__
1436 #pragma GCC diagnostic pop
1437 #endif
1438 /// \endcond
1439 /**@}*/
1440 
1441 /*!
1442  * \ingroup DataBoxGroup
1443  * \brief Create a non-aliasing copy of the DataBox. That is, the new DataBox
1444  * will not share items with the old one.
1445  *
1446  * \warning Currently all compute items will be reset in the new DataBox because
1447  * copying of DataBoxes shouldn't be done in general. This does not lead to
1448  * incorrect behavior, but is less efficient.
1449  *
1450  * \see db::create_from
1451  */
1452 template <typename TagsList>
1454  const DataBox<TagsList>& box) noexcept {
1455  return box.template deep_copy<typename DataBox<TagsList>::simple_item_tags>();
1456 }
1457 
1458 namespace DataBox_detail {
1459 template <typename Type, typename... Tags, typename... TagsInBox>
1460 const Type& get_item_from_box(const DataBox<tmpl::list<TagsInBox...>>& box,
1461  const std::string& tag_name,
1462  tmpl::list<Tags...> /*meta*/) {
1464  sizeof...(Tags) != 0,
1465  "No items with the requested type were found in the DataBox");
1466  const Type* result = nullptr;
1467  const auto helper = [&box, &tag_name, &result ](auto current_tag) noexcept {
1468  using tag = decltype(current_tag);
1469  if (get_tag_name<tag>() == tag_name) {
1470  result = &::db::get<tag>(box);
1471  }
1472  };
1473  EXPAND_PACK_LEFT_TO_RIGHT(helper(Tags{}));
1474  if (result == nullptr) {
1475  std::string tags_in_box;
1476  const auto print_helper = [&tags_in_box](auto tag) noexcept {
1477  tags_in_box += " " + decltype(tag)::name() + "\n";
1478  };
1479  EXPAND_PACK_LEFT_TO_RIGHT(print_helper(Tags{}));
1480  ERROR("Could not find the tag named \""
1481  << tag_name << "\" in the DataBox. Available tags are:\n"
1482  << tags_in_box);
1483  }
1484  return *result;
1485 } // namespace db
1486 } // namespace DataBox_detail
1487 
1488 /*!
1489  * \ingroup DataBoxGroup
1490  * \brief Retrieve an item from the DataBox that has a tag with label `tag_name`
1491  * and type `Type`
1492  *
1493  * \details
1494  * The type that the tag represents must be of the type `Type`, and the tag must
1495  * have the label `tag_name`. The function iterates over all tags in the DataBox
1496  * `box` that have the type `Type` searching linearly for one whose `label`
1497  * matches `tag_name`.
1498  *
1499  * \example
1500  * \snippet Test_DataBox.cpp get_item_from_box
1501  *
1502  * \tparam Type the type of the tag with the `label` `tag_name`
1503  * \param box the DataBox through which to search
1504  * \param tag_name the `label` of the tag to retrieve
1505  */
1506 template <typename Type, typename TagList>
1507 constexpr const Type& get_item_from_box(const DataBox<TagList>& box,
1508  const std::string& tag_name) noexcept {
1509  using tags = tmpl::filter<
1510  TagList, std::is_same<tmpl::bind<item_type, tmpl::_1>, tmpl::pin<Type>>>;
1511  return DataBox_detail::get_item_from_box<Type>(box, tag_name, tags{});
1512 }
1513 
1514 namespace DataBox_detail {
1516 
1517 template <typename TagsList>
1518 struct Apply;
1519 
1520 template <typename... Tags>
1521 struct Apply<tmpl::list<Tags...>> {
1522  template <typename F, typename BoxTags, typename... Args,
1523  Requires<is_apply_callable_v<
1525  Args...>> = nullptr>
1526  static constexpr auto apply(F&& /*f*/, const DataBox<BoxTags>& box,
1527  Args&&... args) {
1528  return F::apply(::db::get<Tags>(box)..., std::forward<Args>(args)...);
1529  }
1530 
1531  template <typename F, typename BoxTags, typename... Args,
1532  Requires<not is_apply_callable_v<
1534  Args...>> = nullptr>
1535  static constexpr auto apply(F&& f, const DataBox<BoxTags>& box,
1536  Args&&... args) {
1537  static_assert(
1540  tmpl::conditional_t<cpp17::is_same_v<Tags, ::Tags::DataBox>,
1541  const DataBox<BoxTags>&, item_type<Tags>>...,
1542  Args...>,
1543  "Cannot call the function f with the list of tags and "
1544  "arguments specified. Check that the Tags::type and the "
1545  "types of the Args match the function f.");
1546  return std::forward<F>(f)(::db::get<Tags>(box)...,
1547  std::forward<Args>(args)...);
1548  }
1549 };
1550 } // namespace DataBox_detail
1551 
1552 /*!
1553  * \ingroup DataBoxGroup
1554  * \brief Apply the function `f` with argument Tags `TagsList` from
1555  * DataBox `box`
1556  *
1557  * \details
1558  * `f` must either be invokable with the arguments of type
1559  * `db::item_type<TagsList>..., Args...` where the first pack expansion
1560  * is over the elements in the type list `TagsList`, or have a static
1561  * `apply` function that is callable with the same types.
1562  *
1563  * \usage
1564  * Given a function `func` that takes arguments of types
1565  * `T1`, `T2`, `A1` and `A2`. Let the Tags for the quantities of types `T1` and
1566  * `T2` in the DataBox `box` be `Tag1` and `Tag2`, and objects `a1` of type
1567  * `A1` and `a2` of type `A2`, then
1568  * \code
1569  * auto result = db::apply<tmpl::list<Tag1, Tag2>>(func, box, a1, a2);
1570  * \endcode
1571  * \return `decltype(func(db::get<Tag1>(box), db::get<Tag2>(box), a1, a2))`
1572  *
1573  * \semantics
1574  * For tags `Tags...` in a DataBox `box`, and a function `func` that takes
1575  * `sizeof...(Tags)` arguments of types `db::item_type<Tags>...`, and
1576  * `sizeof...(Args)` arguments of types `Args...`,
1577  * \code
1578  * result = func(box, db::get<Tags>(box)..., args...);
1579  * \endcode
1580  *
1581  * \example
1582  * \snippet Test_DataBox.cpp apply_example
1583  * Using a struct with an `apply` method:
1584  * \snippet Test_DataBox.cpp apply_struct_example
1585  *
1586  * \see DataBox
1587  * \tparam TagsList typelist of Tags in the order that they are to be passed
1588  * to `f`
1589  * \param f the function to apply
1590  * \param box the DataBox out of which to retrieve the Tags and to pass to `f`
1591  * \param args the arguments to pass to the function that are not in the
1592  * DataBox, `box`
1593  */
1594 template <typename TagsList, typename F, typename BoxTags, typename... Args>
1595 inline constexpr auto apply(F&& f, const DataBox<BoxTags>& box,
1596  Args&&... args) {
1597  return DataBox_detail::Apply<TagsList>::apply(std::forward<F>(f), box,
1598  std::forward<Args>(args)...);
1599 }
1600 
1601 namespace DataBox_detail {
1602 template <typename... ReturnTags, typename... ArgumentTags, typename F,
1603  typename BoxTags, typename... Args,
1604  Requires<is_apply_callable_v<
1608  Args...>> = nullptr>
1609 inline constexpr auto mutate_apply(
1610  F /*f*/, const gsl::not_null<db::DataBox<BoxTags>*> box,
1611  tmpl::list<ReturnTags...> /*meta*/, tmpl::list<ArgumentTags...> /*meta*/,
1612  Args&&... args) noexcept {
1613  static_assert(
1614  not tmpl2::flat_any_v<
1615  cpp17::is_same_v<ArgumentTags, Tags::DataBox>...> and
1616  not tmpl2::flat_any_v<cpp17::is_same_v<ReturnTags, Tags::DataBox>...>,
1617  "Cannot pass a DataBox to mutate_apply since the db::get won't work "
1618  "inside mutate_apply.");
1619  ::db::mutate<ReturnTags...>(
1620  box,
1621  [](const gsl::not_null<db::item_type<ReturnTags>*>... mutated_items,
1622  const db::item_type<ArgumentTags, BoxTags>&... args_items,
1623  decltype(std::forward<Args>(args))... l_args)
1624  // clang-format off
1625  noexcept(noexcept(F::apply(
1626  std::declval<gsl::not_null<db::item_type<ReturnTags>*>>()...,
1627  std::declval<const db::item_type<ArgumentTags, BoxTags>&>()...,
1628  std::forward<Args>(args)...))) {
1629  // clang-format on
1630  return F::apply(mutated_items..., args_items...,
1631  std::forward<Args>(l_args)...);
1632  },
1633  db::get<ArgumentTags>(*box)..., std::forward<Args>(args)...);
1634 }
1635 
1636 template <typename... ReturnTags, typename... ArgumentTags, typename F,
1637  typename BoxTags, typename... Args,
1642  Args...>> = nullptr>
1643 inline constexpr auto mutate_apply(
1644  F f, const gsl::not_null<db::DataBox<BoxTags>*> box,
1645  tmpl::list<ReturnTags...> /*meta*/, tmpl::list<ArgumentTags...> /*meta*/,
1646  Args&&... args)
1647  // clang-format off
1648  noexcept(noexcept(f(
1649  std::declval<gsl::not_null<db::item_type<ReturnTags>*>>()...,
1650  std::declval<const db::item_type<ArgumentTags, BoxTags>&>()...,
1651  std::forward<Args>(args)...))) {
1652  // clang-format on
1653  static_assert(
1654  not tmpl2::flat_any_v<
1655  cpp17::is_same_v<ArgumentTags, Tags::DataBox>...> and
1656  not tmpl2::flat_any_v<cpp17::is_same_v<ReturnTags, Tags::DataBox>...>,
1657  "Cannot pass a DataBox to mutate_apply since the db::get won't work "
1658  "inside mutate_apply.");
1659  ::db::mutate<ReturnTags...>(
1660  box,
1661  [&f](const gsl::not_null<db::item_type<ReturnTags>*>... mutated_items,
1662  const db::item_type<ArgumentTags, BoxTags>&... args_items,
1663  decltype(std::forward<Args>(args))... l_args) noexcept {
1664  return f(mutated_items..., args_items...,
1665  std::forward<Args>(l_args)...);
1666  },
1667  db::get<ArgumentTags>(*box)..., std::forward<Args>(args)...);
1668 }
1669 
1670 template <typename Func, typename... Args>
1671 constexpr void error_mutate_apply_not_callable() noexcept {
1672  static_assert(cpp17::is_same_v<Func, void>,
1673  "The function is not callable with the expected arguments. "
1674  "See the first template parameter for the function type and "
1675  "the remaining arguments for the parameters that cannot be "
1676  "passed.");
1677 }
1678 
1679 template <
1680  typename... ReturnTags, typename... ArgumentTags, typename F,
1681  typename BoxTags, typename... Args,
1682  Requires<not(is_apply_callable_v<
1686  Args...> or
1691  Args...>)> = nullptr>
1692 inline constexpr auto mutate_apply(
1693  F /*f*/, const gsl::not_null<db::DataBox<BoxTags>*> /*box*/,
1694  tmpl::list<ReturnTags...> /*meta*/, tmpl::list<ArgumentTags...> /*meta*/,
1695  Args&&... /*args*/) noexcept {
1696  error_mutate_apply_not_callable<
1698  const db::item_type<ArgumentTags, BoxTags>&..., Args&&...>();
1699 }
1700 
1701 template <typename Tag, typename BoxTags>
1702 constexpr int check_mutate_apply_mutate_tag() noexcept {
1703  static_assert(tmpl::list_contains_v<BoxTags, Tag>,
1704  "A tag to mutate is not in the DataBox. See the first "
1705  "template argument for the missing tag, and the second for the "
1706  "available tags.");
1707  return 0;
1708 }
1709 
1710 template <typename BoxTags, typename... MutateTags>
1711 constexpr bool check_mutate_apply_mutate_tags(
1712  BoxTags /*meta*/, tmpl::list<MutateTags...> /*meta*/) noexcept {
1713  expand_pack(check_mutate_apply_mutate_tag<MutateTags, BoxTags>()...);
1714  return true;
1715 }
1716 
1717 template <typename Tag, typename BoxTags>
1718 constexpr int check_mutate_apply_apply_tag() noexcept {
1719  // This static assert is triggered for the mutate_apply on line
1720  // 86 of ComputeNonConservativeBoundaryFluxes, with the tag Interface<Dirs,
1721  // Normalized...>, which is the base tag of InterfaceComputeItem<Dirs,
1722  // Normalized...> and so can be retrieved from the DataBox, but still triggers
1723  // this assert.
1724 
1725  // static_assert(tmpl::list_contains_v<BoxTags, Tag>,
1726  // "A tag to apply with is not in the DataBox. See the first "
1727  // "template argument for the missing tag, and the second for
1728  // the " "available tags.");
1729  return 0;
1730 }
1731 
1732 template <typename BoxTags, typename... ApplyTags>
1733 constexpr bool check_mutate_apply_argument_tags(
1734  BoxTags /*meta*/, tmpl::list<ApplyTags...> /*meta*/) noexcept {
1735  expand_pack(check_mutate_apply_apply_tag<ApplyTags, BoxTags>()...);
1736  return true;
1737 }
1738 } // namespace DataBox_detail
1739 
1740 /*!
1741  * \ingroup DataBoxGroup
1742  * \brief Apply the function `f` mutating items `MutateTags` and taking as
1743  * additional arguments `ArgumentTags` and `args`.
1744  *
1745  * \details
1746  * `f` must either be invokable with the arguments of type
1747  * `gsl::not_null<db::item_type<MutateTags>*>...,
1748  * db::item_type<ArgumentTags>..., Args...`
1749  * where the first two pack expansions are over the elements in the type lists
1750  * `MutateTags` and `ArgumentTags`, or have a static `apply` function that is
1751  * callable with the same types.
1752  *
1753  * \example
1754  * An example of using `mutate_apply` with a lambda:
1755  * \snippet Test_DataBox.cpp mutate_apply_lambda_example
1756  *
1757  * An example of a class with a static `apply` function
1758  * \snippet Test_DataBox.cpp mutate_apply_struct_definition_example
1759  * and how to use `mutate_apply` with the above class
1760  * \snippet Test_DataBox.cpp mutate_apply_struct_example
1761  *
1762  * \see box
1763  * \tparam MutateTags typelist of Tags to mutate
1764  * \tparam ArgumentTags typelist of additional items to retrieve from the
1765  * DataBox
1766  * \param f the function to apply
1767  * \param box the DataBox out of which to retrieve the Tags and to pass to `f`
1768  * \param args the arguments to pass to the function that are not in the
1769  * DataBox, `box`
1770  */
1771 template <typename MutateTags, typename ArgumentTags, typename F,
1772  typename BoxTags, typename... Args>
1773 inline constexpr auto mutate_apply(
1774  F f, const gsl::not_null<DataBox<BoxTags>*> box,
1775  Args&&... args) noexcept(DataBox_detail::
1776  check_mutate_apply_mutate_tags(
1777  BoxTags{}, MutateTags{}) and
1778  DataBox_detail::check_mutate_apply_argument_tags(
1779  BoxTags{}, ArgumentTags{}) and
1781  f, box, MutateTags{}, ArgumentTags{},
1782  std::forward<Args>(args)...))) {
1783  // These checks are duplicated in the noexcept specification above
1784  // because the noexcept(DataBox_detail::mutate_apply(...)) can cause
1785  // a compilation error before the checks in the function body are
1786  // performed.
1787  DataBox_detail::check_mutate_apply_mutate_tags(BoxTags{}, MutateTags{});
1788  DataBox_detail::check_mutate_apply_argument_tags(BoxTags{}, ArgumentTags{});
1789  return DataBox_detail::mutate_apply(f, box, MutateTags{}, ArgumentTags{},
1790  std::forward<Args>(args)...);
1791 }
1792 
1793 /*!
1794  * \ingroup DataBoxGroup
1795  * \brief Get all the Tags that are compute items from the `TagList`
1796  */
1797 template <class TagList>
1798 using get_compute_items = tmpl::filter<TagList, db::is_compute_item<tmpl::_1>>;
1799 
1800 /*!
1801  * \ingroup DataBoxGroup
1802  * \brief Get all the Tags that are items from the `TagList`
1803  */
1804 template <class TagList>
1805 using get_items =
1806  tmpl::filter<TagList,
1807  tmpl::not_<tmpl::bind<db::is_compute_item, tmpl::_1>>>;
1808 
1809 namespace DataBox_detail {
1810 template <class ItemsList, class ComputeItemsList>
1811 struct compute_dbox_type;
1812 
1813 template <class... ItemsPack, class ComputeItemsList>
1814 struct compute_dbox_type<tmpl::list<ItemsPack...>, ComputeItemsList> {
1815  using type = decltype(db::create<tmpl::list<ItemsPack...>, ComputeItemsList>(
1816  std::declval<db::item_type<ItemsPack>>()...));
1817 };
1818 } // namespace DataBox_detail
1819 
1820 /*!
1821  * \ingroup DataBoxGroup
1822  * \brief Returns the type of the DataBox that would be constructed from the
1823  * `TagList` of tags.
1824  */
1825 template <class TagList>
1826 using compute_databox_type = typename DataBox_detail::compute_dbox_type<
1828 } // namespace db
Mark a return type as being "void". In C++17 void is a regular type under certain circumstances...
Definition: TypeTraits.hpp:47
#define ERROR(m)
prints an error message to the standard error stream and aborts the program.
Definition: Error.hpp:35
constexpr auto mutate_apply(F f, const gsl::not_null< DataBox< BoxTags > *> box, Args &&... args) noexcept(DataBox_detail::check_mutate_apply_mutate_tags(BoxTags{}, MutateTags{}) and DataBox_detail::check_mutate_apply_argument_tags(BoxTags{}, ArgumentTags{}) and noexcept(DataBox_detail::mutate_apply(f, box, MutateTags{}, ArgumentTags{}, std::forward< Args >(args)...)))
Apply the function f mutating items MutateTags and taking as additional arguments ArgumentTags and ar...
Definition: DataBox.hpp:1773
#define CREATE_IS_CALLABLE(METHOD_NAME)
Generate a type trait to check if a class has a member function that can be invoked with arguments of...
Definition: TypeTraits.hpp:870
void mutate(const gsl::not_null< DataBox< TagList > *> box, Invokable &&invokable, Args &&... args) noexcept
Allows changing the state of one or more non-computed elements in the DataBox.
Definition: DataBox.hpp:1099
#define EXPAND_PACK_LEFT_TO_RIGHT(...)
Expand a parameter pack evaluating the terms from left to right.
Definition: TMPL.hpp:561
tmpl::flatten< tmpl::transform< simple_subitems_tags, db::Subitems< tmpl::pin< tags_list >, tmpl::_1 > >> simple_only_expanded_subitems_tags
A list of the expanded simple subitems, not including the main Subitem tags themselves.
Definition: DataBox.hpp:427
constexpr DataBox< TagsList > create_copy(const DataBox< TagsList > &box) noexcept
Create a non-aliasing copy of the DataBox. That is, the new DataBox will not share items with the old...
Definition: DataBox.hpp:1453
constexpr bool flat_any_v
A non-short-circuiting logical OR between bools &#39;B"".
Definition: TMPL.hpp:528
tmpl::list_difference< tags_list, compute_with_subitems_tags > simple_item_tags
A list of all the simple items, including subitems from the simple items.
Definition: DataBox.hpp:413
constexpr bool flat_all_v
A non-short-circuiting logical AND between bools &#39;B"".
Definition: TMPL.hpp:504
#define UNLIKELY(x)
Definition: Gsl.hpp:72
tmpl::list< Tags... > tags_list
A typelist (tmpl::list) of Tags that the DataBox holds.
Definition: DataBox.hpp:400
Marks a DataBoxTag as being a compute item that executes a function.
Definition: DataBoxTag.hpp:155
constexpr auto create(Args &&... args)
Create a new DataBox.
Definition: DataBox.hpp:1259
Determines if a type T is as db::DataBox.
Definition: DataBox.hpp:52
tmpl::flatten< tmpl::list< Tags... > > RemoveTags
List of Tags to remove from the DataBox.
Definition: DataBox.hpp:1220
Defines the type alias Requires.
constexpr auto apply(F &&f, const DataBox< BoxTags > &box, Args &&... args)
Apply the function f with argument Tags TagsList from DataBox box
Definition: DataBox.hpp:1595
Deferred< Rt > make_deferred(Fp f, Args &&... args) noexcept
Create a deferred function call object.
Definition: Deferred.hpp:381
tmpl::filter< simple_item_tags, tmpl::bind< DataBox_detail::has_subitems, tmpl::pin< tags_list >, tmpl::_1 > > simple_subitems_tags
A list of the simple items that have subitems, without expanding the subitems out.
Definition: DataBox.hpp:419
constexpr bool is_callable_v
Definition: TypeTraits.hpp:844
Definition: Determinant.hpp:11
#define SPECTRE_ALWAYS_INLINE
Always inline a function. Only use this if you benchmarked the code.
Definition: ForceInline.hpp:20
constexpr auto create_from(db::DataBox< TagsList > &&box, Args &&... args) noexcept
Create a new DataBox from an existing one adding or removing items and compute items.
Definition: DataBox.hpp:1414
constexpr bool is_same_v
Variable template for is_same.
Definition: TypeTraits.hpp:221
Defines helper functions for working with boost.
DataBox_detail::expand_subitems_from_list< tags_list, compute_item_tags > compute_with_subitems_tags
A list of all the compute items, including subitems from the compute items.
Definition: DataBox.hpp:408
#define DEBUG_STATIC_ASSERT(...)
A static_assert that is only checked in Debug builds.
Definition: StaticAssert.hpp:16
tmpl::flatten< tmpl::list< Tags... > > AddSimpleTags
List of Tags to add to the DataBox.
Definition: DataBox.hpp:1227
A spectral element with knowledge of its neighbors.
Definition: Element.hpp:29
Definition: InterpolationTargetWedgeSectionTorus.hpp:24
constexpr const Type & get_item_from_box(const DataBox< TagList > &box, const std::string &tag_name) noexcept
Retrieve an item from the DataBox that has a tag with label tag_name and type Type ...
Definition: DataBox.hpp:1507
Struct that can be specialized to allow DataBox items to have subitems. Specializations must define: ...
Definition: DataBoxTag.hpp:648
tmpl::filter< tags_list, db::is_compute_item< tmpl::_1 > > compute_item_tags
A list of all the compute item tags, excluding their subitems.
Definition: DataBox.hpp:404
Defines macro to always inline a function.
tmpl::filter< TagList, db::is_compute_item< tmpl::_1 > > get_compute_items
Get all the Tags that are compute items from the TagList
Definition: DataBox.hpp:1798
Definition: DataBoxTag.hpp:29
Check if type T is a template specialization of U
Definition: TypeTraits.hpp:536
Namespace for DataBox related things.
Definition: DataBox.hpp:33
Defines macro ASSERT.
const auto & get(const DataBox< TagList > &box) noexcept
Retrieve the item with tag Tag from the DataBox.
Definition: DataBox.hpp:1211
Provides deferred or lazy evaluation of a function or function object, as well as efficient storage o...
Definition: Deferred.hpp:22
tmpl::filter< TagList, tmpl::not_< tmpl::bind< db::is_compute_item, tmpl::_1 > >> get_items
Get all the Tags that are items from the TagList
Definition: DataBox.hpp:1807
Wraps the template metaprogramming library used (brigand)
typename DataBox_detail::item_type_impl< TagList, Tag >::type item_type
Get the type that is returned by the Tag. If it is a base tag then a TagList must be passed as a seco...
Definition: DataBoxTag.hpp:410
Defines functions and classes from the GSL.
gsl::not_null< T * > make_not_null(T *ptr) noexcept
Construct a not_null from a pointer. Often this will be done as an implicit conversion, but it may be necessary to perform the conversion explicitly when type deduction is desired.
Definition: Gsl.hpp:863
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67
typename DataBox_detail::compute_dbox_type< get_items< TagList >, get_compute_items< TagList > >::type compute_databox_type
Returns the type of the DataBox that would be constructed from the TagList of tags.
Definition: DataBox.hpp:1827
Defines classes SimpleTag, PrefixTag, ComputeTag and several functions for retrieving tag info...
Defines macro ERROR.
Defines type traits, some of which are future STL type_traits header.
Defines class Deferred and make function.
Defines macro DEBUG_STATIC_ASSERT.
Definition: DataBoxTag.hpp:286
constexpr bool has_return_type_member_v
true if T has nested type alias named return_type
Definition: DataBoxTag.hpp:295
Require a pointer to not be a nullptr
Definition: ConservativeFromPrimitive.hpp:12
constexpr void expand_pack(Ts &&...) noexcept
Allows zero-cost unordered expansion of a parameter.
Definition: TMPL.hpp:545
tmpl::flatten< tmpl::list< Tags... > > AddComputeTags
List of Compute Item Tags to add to the DataBox.
Definition: DataBox.hpp:1234
Check if Tag derives off of db::ComputeTag.
Definition: DataBoxTag.hpp:217