Line data Source code
1 1 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : /// \file
5 : /// Defines Parallel::Callback.
6 :
7 : #pragma once
8 :
9 : #include <memory>
10 : #include <pup.h>
11 : #include <tuple>
12 : #include <utility>
13 :
14 : #include "Parallel/Invoke.hpp"
15 : #include "Utilities/PrettyType.hpp"
16 : #include "Utilities/Serialization/CharmPupable.hpp"
17 : #include "Utilities/Serialization/RegisterDerivedClassesWithCharm.hpp"
18 : #include "Utilities/TypeTraits/HasEquivalence.hpp"
19 :
20 : namespace Parallel {
21 : namespace detail {
22 : // Not all tuple arguments are guaranteed to have operator==, so we check the
23 : // ones we can.
24 : template <typename... Args>
25 : bool tuple_equal(const std::tuple<Args...>& tuple_1,
26 : const std::tuple<Args...>& tuple_2) {
27 : bool result = true;
28 : tmpl::for_each<tmpl::make_sequence<tmpl::size_t<0>,
29 : tmpl::size<tmpl::list<Args...>>::value>>(
30 : [&](const auto index_v) {
31 : constexpr size_t index = tmpl::type_from<decltype(index_v)>::value;
32 :
33 : if (not result) {
34 : return;
35 : }
36 :
37 : if constexpr (tt::has_equivalence_v<decltype(std::get<index>(
38 : tuple_1))>) {
39 : result =
40 : result and std::get<index>(tuple_1) == std::get<index>(tuple_2);
41 : }
42 : });
43 :
44 : return result;
45 : }
46 : } // namespace detail
47 :
48 : /// An abstract base class, whose derived class holds a function that
49 : /// can be invoked at a later time. The function is intended to be
50 : /// invoked only once.
51 1 : class Callback : public PUP::able {
52 : public:
53 0 : WRAPPED_PUPable_abstract(Callback); // NOLINT
54 0 : Callback() = default;
55 0 : Callback(const Callback&) = default;
56 0 : Callback& operator=(const Callback&) = default;
57 0 : Callback(Callback&&) = default;
58 0 : Callback& operator=(Callback&&) = default;
59 0 : ~Callback() override = default;
60 0 : explicit Callback(CkMigrateMessage* msg) : PUP::able(msg) {}
61 0 : virtual void invoke() = 0;
62 0 : virtual void register_with_charm() = 0;
63 : /*!
64 : * \brief Returns if this callback is equal to the one passed in.
65 : */
66 1 : virtual bool is_equal_to(const Callback& rhs) const = 0;
67 0 : virtual std::string name() const = 0;
68 0 : virtual std::unique_ptr<Callback> get_clone() = 0;
69 : };
70 :
71 : /// Wraps a call to a simple action and its arguments.
72 : /// Can be invoked only once.
73 : template <typename SimpleAction, typename Proxy, typename... Args>
74 1 : class SimpleActionCallback : public Callback {
75 : public:
76 0 : WRAPPED_PUPable_decl_template(SimpleActionCallback); // NOLINT
77 0 : SimpleActionCallback() = default;
78 : // NOLINTNEXTLINE(google-explicit-constructor)
79 0 : SimpleActionCallback(Proxy proxy, std::decay_t<Args>... args)
80 : : proxy_(proxy), args_(std::move(args)...) {}
81 0 : explicit SimpleActionCallback(CkMigrateMessage* msg) : Callback(msg) {}
82 : using PUP::able::register_constructor;
83 0 : void invoke() override {
84 : std::apply(
85 : [this](auto&&... args) {
86 : Parallel::simple_action<SimpleAction>(proxy_, args...);
87 : },
88 : std::move(args_));
89 : }
90 0 : void pup(PUP::er& p) override {
91 : p | proxy_;
92 : p | args_;
93 : }
94 :
95 0 : void register_with_charm() override {
96 : static bool done_registration{false};
97 : if (done_registration) {
98 : return;
99 : }
100 : done_registration = true;
101 : register_classes_with_charm<SimpleActionCallback>();
102 : }
103 :
104 1 : bool is_equal_to(const Callback& rhs) const override {
105 : const auto* downcast_ptr = dynamic_cast<const SimpleActionCallback*>(&rhs);
106 : if (downcast_ptr == nullptr) {
107 : return false;
108 : }
109 : return detail::tuple_equal(args_, downcast_ptr->args_);
110 : }
111 :
112 0 : std::string name() const override {
113 : // Use pretty_type::get_name with the action since we want to differentiate
114 : // template paremeters. Only use pretty_type::name for proxy because it'll
115 : // likely be really long with the template parameters which is unnecessary
116 : return "SimpleActionCallback(" + pretty_type::get_name<SimpleAction>() +
117 : "," + pretty_type::name<Proxy>() + ")";
118 : }
119 :
120 0 : std::unique_ptr<Callback> get_clone() override {
121 : return std::make_unique<SimpleActionCallback<SimpleAction, Proxy, Args...>>(
122 : *this);
123 : }
124 :
125 : private:
126 0 : std::decay_t<Proxy> proxy_{};
127 0 : std::tuple<std::decay_t<Args>...> args_{};
128 : };
129 :
130 : /// Wraps a call to a simple action without arguments.
131 : template <typename SimpleAction, typename Proxy>
132 1 : class SimpleActionCallback<SimpleAction, Proxy> : public Callback {
133 : public:
134 0 : WRAPPED_PUPable_decl_template(SimpleActionCallback); // NOLINT
135 0 : SimpleActionCallback() = default;
136 : // NOLINTNEXTLINE(google-explicit-constructor)
137 0 : SimpleActionCallback(Proxy proxy) : proxy_(proxy) {}
138 0 : explicit SimpleActionCallback(CkMigrateMessage* msg) : Callback(msg) {}
139 : using PUP::able::register_constructor;
140 0 : void invoke() override { Parallel::simple_action<SimpleAction>(proxy_); }
141 :
142 0 : void pup(PUP::er& p) override { p | proxy_; }
143 :
144 0 : void register_with_charm() override {
145 : static bool done_registration{false};
146 : if (done_registration) {
147 : return;
148 : }
149 : done_registration = true;
150 : register_classes_with_charm<SimpleActionCallback>();
151 : }
152 :
153 1 : bool is_equal_to(const Callback& rhs) const override {
154 : const auto* downcast_ptr = dynamic_cast<const SimpleActionCallback*>(&rhs);
155 : return downcast_ptr != nullptr;
156 : }
157 :
158 0 : std::string name() const override {
159 : // Use pretty_type::get_name with the action since we want to differentiate
160 : // template paremeters. Only use pretty_type::name for proxy because it'll
161 : // likely be really long with the template parameters which is unnecessary
162 : return "SimpleActionCallback(" + pretty_type::get_name<SimpleAction>() +
163 : "," + pretty_type::name<Proxy>() + ")";
164 : }
165 :
166 0 : std::unique_ptr<Callback> get_clone() override {
167 : return std::make_unique<SimpleActionCallback<SimpleAction, Proxy>>(*this);
168 : }
169 :
170 : private:
171 0 : std::decay_t<Proxy> proxy_{};
172 : };
173 :
174 : /// Wraps a call to a threaded action and its arguments.
175 : /// Can be invoked only once.
176 : template <typename ThreadedAction, typename Proxy, typename... Args>
177 1 : class ThreadedActionCallback : public Callback {
178 : public:
179 0 : WRAPPED_PUPable_decl_template(ThreadedActionCallback); // NOLINT
180 0 : ThreadedActionCallback() = default;
181 : // NOLINTNEXTLINE(google-explicit-constructor)
182 0 : ThreadedActionCallback(Proxy proxy, std::decay_t<Args>... args)
183 : : proxy_(proxy), args_(std::move(args)...) {}
184 0 : explicit ThreadedActionCallback(CkMigrateMessage* msg) : Callback(msg) {}
185 : using PUP::able::register_constructor;
186 0 : void invoke() override {
187 : std::apply(
188 : [this](auto&&... args) {
189 : Parallel::threaded_action<ThreadedAction>(proxy_, args...);
190 : },
191 : std::move(args_));
192 : }
193 0 : void pup(PUP::er& p) override {
194 : p | proxy_;
195 : p | args_;
196 : }
197 :
198 0 : void register_with_charm() override {
199 : static bool done_registration{false};
200 : if (done_registration) {
201 : return;
202 : }
203 : done_registration = true;
204 : register_classes_with_charm<ThreadedActionCallback>();
205 : }
206 :
207 1 : bool is_equal_to(const Callback& rhs) const override {
208 : const auto* downcast_ptr =
209 : dynamic_cast<const ThreadedActionCallback*>(&rhs);
210 : if (downcast_ptr == nullptr) {
211 : return false;
212 : }
213 : return detail::tuple_equal(args_, downcast_ptr->args_);
214 : }
215 :
216 0 : std::string name() const override {
217 : // Use pretty_type::get_name with the action since we want to differentiate
218 : // template paremeters. Only use pretty_type::name for proxy because it'll
219 : // likely be really long with the template parameters which is unnecessary
220 : return "ThreadedActionCallback(" + pretty_type::get_name<ThreadedAction>() +
221 : "," + pretty_type::name<Proxy>() + ")";
222 : }
223 :
224 0 : std::unique_ptr<Callback> get_clone() override {
225 : return std::make_unique<
226 : ThreadedActionCallback<ThreadedAction, Proxy, Args...>>(*this);
227 : }
228 :
229 : private:
230 0 : std::decay_t<Proxy> proxy_{};
231 0 : std::tuple<std::decay_t<Args>...> args_{};
232 : };
233 :
234 : /// Wraps a call to a threaded action without arguments.
235 : template <typename ThreadedAction, typename Proxy>
236 1 : class ThreadedActionCallback<ThreadedAction, Proxy> : public Callback {
237 : public:
238 0 : WRAPPED_PUPable_decl_template(ThreadedActionCallback); // NOLINT
239 0 : ThreadedActionCallback() = default;
240 : // NOLINTNEXTLINE(google-explicit-constructor)
241 0 : ThreadedActionCallback(Proxy proxy) : proxy_(proxy) {}
242 0 : explicit ThreadedActionCallback(CkMigrateMessage* msg) : Callback(msg) {}
243 : using PUP::able::register_constructor;
244 0 : void invoke() override { Parallel::threaded_action<ThreadedAction>(proxy_); }
245 :
246 0 : void pup(PUP::er& p) override { p | proxy_; }
247 :
248 0 : void register_with_charm() override {
249 : static bool done_registration{false};
250 : if (done_registration) {
251 : return;
252 : }
253 : done_registration = true;
254 : register_classes_with_charm<ThreadedActionCallback>();
255 : }
256 :
257 1 : bool is_equal_to(const Callback& rhs) const override {
258 : const auto* downcast_ptr =
259 : dynamic_cast<const ThreadedActionCallback*>(&rhs);
260 : return downcast_ptr != nullptr;
261 : }
262 :
263 0 : std::string name() const override {
264 : // Use pretty_type::get_name with the action since we want to differentiate
265 : // template paremeters. Only use pretty_type::name for proxy because it'll
266 : // likely be really long with the template parameters which is unnecessary
267 : return "ThreadedActionCallback(" + pretty_type::get_name<ThreadedAction>() +
268 : "," + pretty_type::name<Proxy>() + ")";
269 : }
270 :
271 0 : std::unique_ptr<Callback> get_clone() override {
272 : return std::make_unique<ThreadedActionCallback<ThreadedAction, Proxy>>(
273 : *this);
274 : }
275 :
276 : private:
277 0 : std::decay_t<Proxy> proxy_{};
278 : };
279 :
280 : /// Wraps a call to perform_algorithm.
281 : template <typename Proxy>
282 1 : class PerformAlgorithmCallback : public Callback {
283 : public:
284 0 : WRAPPED_PUPable_decl_template(PerformAlgorithmCallback); // NOLINT
285 0 : PerformAlgorithmCallback() = default;
286 : // NOLINTNEXTLINE(google-explicit-constructor)
287 0 : PerformAlgorithmCallback(Proxy proxy) : proxy_(proxy) {}
288 0 : explicit PerformAlgorithmCallback(CkMigrateMessage* msg) : Callback(msg) {}
289 : using PUP::able::register_constructor;
290 0 : void invoke() override { proxy_.perform_algorithm(); }
291 0 : void pup(PUP::er& p) override { p | proxy_; }
292 :
293 0 : void register_with_charm() override {
294 : static bool done_registration{false};
295 : if (done_registration) {
296 : return;
297 : }
298 : done_registration = true;
299 : register_classes_with_charm<PerformAlgorithmCallback>();
300 : }
301 :
302 1 : bool is_equal_to(const Callback& rhs) const override {
303 : const auto* downcast_ptr =
304 : dynamic_cast<const PerformAlgorithmCallback*>(&rhs);
305 : return downcast_ptr != nullptr;
306 : }
307 :
308 0 : std::string name() const override {
309 : // Only use pretty_type::name for proxy because it'll likely be really long
310 : // with the template parameters which is unnecessary
311 : return "PerformAlgorithmCallback(" + pretty_type::name<Proxy>() + ")";
312 : }
313 :
314 0 : std::unique_ptr<Callback> get_clone() override {
315 : return std::make_unique<PerformAlgorithmCallback<Proxy>>(*this);
316 : }
317 :
318 : private:
319 0 : std::decay_t<Proxy> proxy_{};
320 : };
321 :
322 : /// \cond
323 : template <typename Proxy>
324 : // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
325 : PUP::able::PUP_ID PerformAlgorithmCallback<Proxy>::my_PUP_ID = 0;
326 : template <typename SimpleAction, typename Proxy, typename... Args>
327 : PUP::able::PUP_ID
328 : // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
329 : SimpleActionCallback<SimpleAction, Proxy, Args...>::my_PUP_ID =
330 : 0; // NOLINT
331 : template <typename SimpleAction, typename Proxy>
332 : // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
333 : PUP::able::PUP_ID SimpleActionCallback<SimpleAction, Proxy>::my_PUP_ID =
334 : 0; // NOLINT
335 : template <typename ThreadedAction, typename Proxy, typename... Args>
336 : PUP::able::PUP_ID
337 : // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
338 : ThreadedActionCallback<ThreadedAction, Proxy, Args...>::my_PUP_ID =
339 : 0; // NOLINT
340 : template <typename ThreadedAction, typename Proxy>
341 : // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
342 : PUP::able::PUP_ID ThreadedActionCallback<ThreadedAction, Proxy>::my_PUP_ID =
343 : 0; // NOLINT
344 : /// \endcond
345 :
346 : } // namespace Parallel
|