SimpleActionVisitation.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <boost/variant/variant.hpp>
7 
8 #include "DataStructures/DataBox/DataBox.hpp" // IWYU pragma: keep
10 #include "Parallel/AlgorithmMetafunctions.hpp"
11 #include "Utilities/Gsl.hpp"
12 #include "Utilities/Overloader.hpp"
13 #include "Utilities/PrettyType.hpp"
14 #include "Utilities/Requires.hpp"
15 #include "Utilities/TMPL.hpp"
16 #include "Utilities/TypeTraits.hpp"
17 
18 namespace Parallel {
19 namespace Algorithm_detail {
20 template <typename Invokable, typename InitialDataBox, typename ThisVariant,
21  typename... Variants, typename... Args,
22  Requires<is_apply_callable_v<
23  Invokable, std::add_lvalue_reference_t<ThisVariant>, Args&&...>> =
24  nullptr>
25 void simple_action_visitor_helper(boost::variant<Variants...>& box,
26  const gsl::not_null<int*> iter,
27  const gsl::not_null<bool*> already_visited,
28  Args&&... args) {
29  if (box.which() == *iter and not*already_visited) {
30  try {
32  [&box](std::true_type /*returns_void*/, auto&&... my_args) {
33  Invokable::apply(boost::get<ThisVariant>(box),
34  std::forward<Args>(my_args)...);
35  },
36  [&box](std::false_type /*returns_void*/, auto&&... my_args) {
37  box = std::get<0>(Invokable::apply(boost::get<ThisVariant>(box),
38  std::forward<Args>(my_args)...));
39  using return_box_type = decltype(std::get<0>(Invokable::apply(
40  boost::get<ThisVariant>(box), std::forward<Args>(my_args)...)));
41  static_assert(
43  InitialDataBox> and
44  cpp17::is_same_v<db::DataBox<tmpl::list<>>, ThisVariant>,
45  "A simple action must return either void or take an empty "
46  "DataBox and return the initial_databox set in the parallel "
47  "component.");
48  })(
49  typename std::is_same<void, decltype(Invokable::apply(
50  std::declval<ThisVariant&>(),
51  std::declval<Args>()...))>::type{},
52  std::forward<Args>(args)...);
53 
54  } catch (std::exception& e) {
55  ERROR("Fatal error: Failed to call single Action '"
56  << pretty_type::get_name<Invokable>() << "' on iteration '" << iter
57  << "' with DataBox type '" << pretty_type::get_name<ThisVariant>()
58  << "'\nThe exception is: '" << e.what() << "'\n");
59  }
60  *already_visited = true;
61  }
62  (*iter)++;
63 }
64 
65 template <typename Invokable, typename InitialDataBox, typename ThisVariant,
66  typename... Variants, typename... Args,
67  Requires<not is_apply_callable_v<
68  Invokable, std::add_lvalue_reference_t<ThisVariant>, Args&&...>> =
69  nullptr>
70 void simple_action_visitor_helper(boost::variant<Variants...>& box,
71  const gsl::not_null<int*> iter,
72  const gsl::not_null<bool*> already_visited,
73  Args&&... /*args*/) {
74  if (box.which() == *iter and not*already_visited) {
75  ERROR("\nCannot call apply function of '"
76  << pretty_type::get_name<Invokable>() << "' with DataBox type '"
77  << pretty_type::get_name<ThisVariant>() << "' and arguments '"
78  << pretty_type::get_name<tmpl::list<Args...>>() << "'.\n"
79  << "If the argument types to the apply function match, then it is "
80  "possible that the apply function has non-deducible template "
81  "parameters. This could occur from removing an apply function "
82  "argument and forgetting to remove its associated template "
83  "parameters.\n");
84  }
85  (*iter)++;
86 }
87 
88 /*!
89  * \brief Calls an `Invokable`'s `apply` static member function with the current
90  * type in the `boost::variant`.
91  *
92  * The primary use case for this is to allow executing a single Action at any
93  * point in the Algorithm. The current best-known use case for this is setting
94  * up initial data. However, the implementation is generic enough to handle a
95  * call at any time that is valid. Here valid is defined as the `apply` function
96  * only accesses members of the DataBox that are guaranteed to be present when
97  * it is invoked, and returns a DataBox of a type that does not break the
98  * Algorithm.
99  */
100 template <typename Invokable, typename InitialDataBox, typename... Variants,
101  typename... Args>
102 void simple_action_visitor(boost::variant<Variants...>& box, Args&&... args) {
103  // iter is the current element of the variant in the "for loop"
104  int iter = 0;
105  // already_visited ensures that only one visitor is invoked
106  bool already_visited = false;
107  static_cast<void>(std::initializer_list<char>{
108  (simple_action_visitor_helper<Invokable, InitialDataBox, Variants>(
109  box, &iter, &already_visited, std::forward<Args>(args)...),
110  '0')...});
111 }
112 } // namespace Algorithm_detail
113 } // namespace Parallel
#define ERROR(m)
prints an error message to the standard error stream and aborts the program.
Definition: Error.hpp:35
Overloader< Fs... > make_overloader(Fs... fs)
Create Overloader<Fs...>, see Overloader for details.
Definition: Overloader.hpp:109
Contains functions that forward to Charm++ parallel functions.
Definition: Abort.hpp:13
std::string get_name()
Returns a string with the prettiest typename known for the type T.
Definition: PrettyType.hpp:674
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
Defines classes and functions used for manipulating DataBox&#39;s.
constexpr bool is_same_v
Variable template for is_same.
Definition: TypeTraits.hpp:221
Definition: InterpolationTargetWedgeSectionTorus.hpp:24
Contains a pretty_type library to write types in a "pretty" format.
Wraps the template metaprogramming library used (brigand)
Defines functions and classes from the GSL.
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
Defines macro ERROR.
Defines type traits, some of which are future STL type_traits header.
Require a pointer to not be a nullptr
Definition: ConservativeFromPrimitive.hpp:12