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