SpECTRE Documentation Coverage Report
Current view: top level - Parallel - CharmRegistration.hpp Hit Total Coverage
Commit: 3c072f0ce967e2e56649d3fa12aa2a0e4fe2a42e Lines: 16 149 10.7 %
Date: 2024-04-23 20:50:18
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <cstddef>
       7             : #include <memory>
       8             : #include <string>
       9             : #include <unordered_map>
      10             : #include <unordered_set>
      11             : 
      12             : #include "Parallel/ParallelComponentHelpers.hpp"
      13             : #include "Parallel/ReductionDeclare.hpp"
      14             : #include "Parallel/TypeTraits.hpp"
      15             : #include "Utilities/Functional.hpp"
      16             : 
      17             : /// \cond
      18             : namespace db {
      19             : template <typename TagsList>
      20             : class DataBox;
      21             : }  // namespace db
      22             : template <size_t MaxSize, class Key, class ValueType, class Hash,
      23             :           class KeyEqual>
      24             : class FixedHashMap;
      25             : template <size_t Dim, class ValueType>
      26             : class DirectionalIdMap;
      27             : template <size_t Dim>
      28             : class DirectionalId;
      29             : namespace Parallel {
      30             : template <typename Metavariables>
      31             : class CProxy_GlobalCache;
      32             : template <typename Metavariables>
      33             : class CProxy_Main;
      34             : template <typename Metavariables>
      35             : class CkIndex_GlobalCache;
      36             : template <typename Metavariables>
      37             : class CkIndex_Main;
      38             : template <typename Metavariables>
      39             : class GlobalCache;
      40             : template <typename Metavariables>
      41             : class Main;
      42             : }  // namespace Parallel
      43             : /// \endcond
      44             : 
      45             : namespace Parallel {
      46           0 : namespace charmxx {
      47             : /*!
      48             :  * \ingroup CharmExtensionsGroup
      49             :  * \brief Class to mark a constructor as a constructor for the main chare.
      50             :  *
      51             :  * The main chare must have a constructor that takes a `const
      52             :  * Parallel::charmxx::MainChareRegistrationConstructor&` as its only argument.
      53             :  * This constructor is only used to trigger the `RegisterChare::registrar` code
      54             :  * needed for automatic registration.
      55             :  * \see RegisterChare
      56             :  */
      57           1 : struct MainChareRegistrationConstructor {};
      58             : 
      59             : /// \cond
      60             : struct RegistrationHelper;
      61             : extern std::unique_ptr<RegistrationHelper>* charm_register_list;
      62             : extern size_t charm_register_list_capacity;
      63             : extern size_t charm_register_list_size;
      64             : /// \endcond
      65             : 
      66           0 : std::string get_template_parameters_as_string_impl(
      67             :     const std::string& function_name);
      68             : 
      69             : /*!
      70             :  * \ingroup CharmExtensionsGroup
      71             :  * \brief Returns the template parameter as a `std::string`
      72             :  *
      73             :  * Uses the __PRETTY_FUNCTION__ compiler intrinsic to extract the template
      74             :  * parameter names in the same form that Charm++ uses to register entry methods.
      75             :  * This is used by the generated Singleton, Array, Group and Nodegroup headers,
      76             :  * as well as in CharmMain.tpp.
      77             :  */
      78             : template <class... Args>
      79           1 : std::string get_template_parameters_as_string() {
      80             :   std::string function_name(static_cast<char const*>(__PRETTY_FUNCTION__));
      81             :   return get_template_parameters_as_string_impl(function_name);
      82             : }
      83             : 
      84             : /*!
      85             :  * \ingroup CharmExtensionsGroup
      86             :  * \brief The base class used for automatic registration of entry methods.
      87             :  *
      88             :  * Entry methods are automatically registered by building a list of the entry
      89             :  * methods that need to be registered in the `charm_register_list`. All entry
      90             :  * methods in the list are later registered in the
      91             :  * `register_parallel_components` function, at which point the list is also
      92             :  * deleted.
      93             :  *
      94             :  * The reason for using an abstract base class mechanism is that we need to be
      95             :  * able to register entry method templates. The derived classes keep track of
      96             :  * the template parameters and override the `register_with_charm` function.
      97             :  * The result is that there must be one derived class template for each entry
      98             :  * method template, but since we only have a few entry method templates this is
      99             :  * not an issue.
     100             :  */
     101           1 : struct RegistrationHelper {
     102           0 :   RegistrationHelper() = default;
     103           0 :   RegistrationHelper(const RegistrationHelper&) = default;
     104           0 :   RegistrationHelper& operator=(const RegistrationHelper&) = default;
     105           0 :   RegistrationHelper(RegistrationHelper&&) = default;
     106           0 :   RegistrationHelper& operator=(RegistrationHelper&&) = default;
     107           0 :   virtual ~RegistrationHelper() = default;
     108             : 
     109           0 :   virtual void register_with_charm() const = 0;
     110           0 :   virtual std::string name() const = 0;
     111           0 :   virtual bool is_registering_chare() const { return false; };
     112             : };
     113             : 
     114             : /*!
     115             :  * \ingroup CharmExtensionsGroup
     116             :  * \brief Class used for automatic registration of Charm++ messages.
     117             :  *
     118             :  * Entry methods that use Charm++ messages are responsible for registering those
     119             :  * messages by calling the static `register_with_charm()` function of this
     120             :  * struct. Because an entry method can be templated on the message type, we
     121             :  * don't want to accidentally register the same message-type twice. This struct
     122             :  * will take care of that, rather than having the logic in the entry method
     123             :  * registration logic.
     124             :  */
     125             : template <typename MessageType>
     126           1 : struct RegisterCharmMessage {
     127           0 :   static void register_with_charm() {
     128             :     static bool done_registration = false;
     129             :     if (done_registration) {
     130             :       return;  // LCOV_EXCL_LINE
     131             :     }
     132             :     done_registration = true;
     133             : 
     134             :     // NOTE: Assumes custom pack/unpack but default allocate.
     135             :     static std::string name = MessageType::name();
     136             :     MessageType::base::__register(
     137             :         name.c_str(), sizeof(MessageType),
     138             :         reinterpret_cast<CkPackFnPtr>(MessageType::pack),
     139             :         reinterpret_cast<CkUnpackFnPtr>(MessageType::unpack));
     140             :   }
     141             : };
     142             : 
     143             : /*!
     144             :  * \ingroup CharmExtensionsGroup
     145             :  * \brief Derived class for registering parallel components.
     146             :  *
     147             :  * Calls the appropriate Charm++ function to register a parallel component.
     148             :  */
     149             : template <typename ParallelComponent>
     150           1 : struct RegisterParallelComponent : RegistrationHelper {
     151           0 :   using chare_type = typename ParallelComponent::chare_type;
     152           0 :   using charm_type = charm_types_with_parameters<
     153             :       ParallelComponent,
     154             :       typename get_array_index<chare_type>::template f<ParallelComponent>>;
     155           0 :   using ckindex = typename charm_type::ckindex;
     156           0 :   using algorithm = typename charm_type::algorithm;
     157             : 
     158           0 :   RegisterParallelComponent() = default;
     159           0 :   RegisterParallelComponent(const RegisterParallelComponent&) = default;
     160           0 :   RegisterParallelComponent& operator=(const RegisterParallelComponent&) =
     161             :       default;
     162           0 :   RegisterParallelComponent(RegisterParallelComponent&&) = default;
     163           0 :   RegisterParallelComponent& operator=(RegisterParallelComponent&&) = default;
     164           0 :   ~RegisterParallelComponent() override = default;
     165             : 
     166           0 :   void register_with_charm() const override {
     167             :     static bool done_registration{false};
     168             :     if (done_registration) {
     169             :       return;  // LCOV_EXCL_LINE
     170             :     }
     171             :     done_registration = true;
     172             :     static const std::string parallel_component_name = name();
     173             :     ckindex::__register(parallel_component_name.c_str(), sizeof(algorithm));
     174             :   }
     175             : 
     176           0 :   bool is_registering_chare() const override { return true; }
     177             : 
     178           0 :   std::string name() const override {
     179             :     return get_template_parameters_as_string<algorithm>();
     180             :   }
     181             : 
     182           0 :   static bool registrar;
     183             : };
     184             : 
     185             : /*!
     186             :  * \ingroup CharmExtensionsGroup
     187             :  * \brief Derived class for registering chares.
     188             :  *
     189             :  * Calls the appropriate Charm++ function to register a chare
     190             :  *
     191             :  * The chare that is being registered must have the following in the destructor:
     192             :  * \code
     193             :  * (void)Parallel::charmxx::RegisterChare<ChareName,
     194             :  *     CkIndex_ChareName>::registrar;
     195             :  * \endcode
     196             :  *
     197             :  * The main chare must also have a constructor that takes a `const
     198             :  * Parallel::charmxx::MainChareRegistrationConstructor&` as its only argument.
     199             :  * This constructor is only used to trigger the `RegisterChare::registrar` code
     200             :  * needed for automatic registration. The main chare is set up in
     201             :  * `Parallel::charmxx::register_main_module<Metavariables>`.
     202             :  */
     203             : template <typename Chare, typename CkIndex>
     204           1 : struct RegisterChare : RegistrationHelper {
     205           0 :   RegisterChare() = default;
     206           0 :   RegisterChare(const RegisterChare&) = default;
     207           0 :   RegisterChare& operator=(const RegisterChare&) = default;
     208           0 :   RegisterChare(RegisterChare&&) = default;
     209           0 :   RegisterChare& operator=(RegisterChare&&) = default;
     210           0 :   ~RegisterChare() override = default;
     211             : 
     212           0 :   void register_with_charm() const override {
     213             :     static bool done_registration{false};
     214             :     if (done_registration) {
     215             :       return;  // LCOV_EXCL_LINE
     216             :     }
     217             :     done_registration = true;
     218             :     static const std::string chare_name = name();
     219             :     CkIndex::__register(chare_name.c_str(), sizeof(Chare));
     220             :   }
     221             : 
     222           0 :   bool is_registering_chare() const override { return true; }
     223             : 
     224           0 :   std::string name() const override {
     225             :     return get_template_parameters_as_string<Chare>();
     226             :   }
     227             : 
     228           0 :   static bool registrar;
     229             : };
     230             : 
     231             : /*!
     232             :  * \ingroup CharmExtensionsGroup
     233             :  * \brief Derived class for registering simple actions.
     234             :  *
     235             :  * Calls the appropriate Charm++ function to register a simple action.
     236             :  */
     237             : template <typename ParallelComponent, typename Action, typename... Args>
     238           1 : struct RegisterSimpleAction : RegistrationHelper {
     239           0 :   using chare_type = typename ParallelComponent::chare_type;
     240           0 :   using charm_type = charm_types_with_parameters<
     241             :       ParallelComponent,
     242             :       typename get_array_index<chare_type>::template f<ParallelComponent>>;
     243           0 :   using cproxy = typename charm_type::cproxy;
     244           0 :   using ckindex = typename charm_type::ckindex;
     245           0 :   using algorithm = typename charm_type::algorithm;
     246             : 
     247           0 :   RegisterSimpleAction() = default;
     248           0 :   RegisterSimpleAction(const RegisterSimpleAction&) = default;
     249           0 :   RegisterSimpleAction& operator=(const RegisterSimpleAction&) = default;
     250           0 :   RegisterSimpleAction(RegisterSimpleAction&&) = default;
     251           0 :   RegisterSimpleAction& operator=(RegisterSimpleAction&&) = default;
     252           0 :   ~RegisterSimpleAction() override = default;
     253             : 
     254           0 :   void register_with_charm() const override {
     255             :     static bool done_registration{false};
     256             :     if (done_registration) {
     257             :       return;  // LCOV_EXCL_LINE
     258             :     }
     259             :     done_registration = true;
     260             :     ckindex::template idx_simple_action<Action>(
     261             :         static_cast<void (algorithm::*)(const std::tuple<Args...>&)>(nullptr));
     262             :   }
     263             : 
     264           0 :   std::string name() const override {
     265             :     return get_template_parameters_as_string<RegisterSimpleAction>();
     266             :   }
     267             : 
     268           0 :   static bool registrar;
     269             : };
     270             : 
     271             : /// \cond
     272             : template <typename ParallelComponent, typename Action>
     273             : struct RegisterSimpleAction<ParallelComponent, Action> : RegistrationHelper {
     274             :   using chare_type = typename ParallelComponent::chare_type;
     275             :   using charm_type = charm_types_with_parameters<
     276             :       ParallelComponent,
     277             :       typename get_array_index<chare_type>::template f<ParallelComponent>>;
     278             :   using cproxy = typename charm_type::cproxy;
     279             :   using ckindex = typename charm_type::ckindex;
     280             :   using algorithm = typename charm_type::algorithm;
     281             : 
     282             :   RegisterSimpleAction() = default;
     283             :   RegisterSimpleAction(const RegisterSimpleAction&) = default;
     284             :   RegisterSimpleAction& operator=(const RegisterSimpleAction&) = default;
     285             :   RegisterSimpleAction(RegisterSimpleAction&&) = default;
     286             :   RegisterSimpleAction& operator=(RegisterSimpleAction&&) = default;
     287             :   ~RegisterSimpleAction() override = default;
     288             : 
     289             :   void register_with_charm() const override {
     290             :     static bool done_registration{false};
     291             :     if (done_registration) {
     292             :       return;  // LCOV_EXCL_LINE
     293             :     }
     294             :     done_registration = true;
     295             :     ckindex::template idx_simple_action<Action>(
     296             :         static_cast<void (algorithm::*)()>(nullptr));
     297             :   }
     298             : 
     299             :   std::string name() const override {
     300             :     return get_template_parameters_as_string<RegisterSimpleAction>();
     301             :   }
     302             : 
     303             :   static bool registrar;
     304             : };
     305             : /// \endcond
     306             : 
     307             : /*!
     308             :  * \ingroup CharmExtensionsGroup
     309             :  * \brief Derived class for registering threaded actions.
     310             :  *
     311             :  * Calls the appropriate Charm++ function to register a threaded action.
     312             :  */
     313             : template <typename ParallelComponent, typename Action, typename... Args>
     314           1 : struct RegisterThreadedAction : RegistrationHelper {
     315           0 :   using chare_type = typename ParallelComponent::chare_type;
     316           0 :   using charm_type = charm_types_with_parameters<
     317             :       ParallelComponent,
     318             :       typename get_array_index<chare_type>::template f<ParallelComponent>>;
     319           0 :   using cproxy = typename charm_type::cproxy;
     320           0 :   using ckindex = typename charm_type::ckindex;
     321           0 :   using algorithm = typename charm_type::algorithm;
     322             : 
     323           0 :   RegisterThreadedAction() = default;
     324           0 :   RegisterThreadedAction(const RegisterThreadedAction&) = default;
     325           0 :   RegisterThreadedAction& operator=(const RegisterThreadedAction&) = default;
     326           0 :   RegisterThreadedAction(RegisterThreadedAction&&) = default;
     327           0 :   RegisterThreadedAction& operator=(RegisterThreadedAction&&) = default;
     328           0 :   ~RegisterThreadedAction() override = default;
     329             : 
     330           0 :   void register_with_charm() const override {
     331             :     static bool done_registration{false};
     332             :     if (done_registration) {
     333             :       return;  // LCOV_EXCL_LINE
     334             :     }
     335             :     done_registration = true;
     336             :     ckindex::template idx_threaded_action<Action>(
     337             :         static_cast<void (algorithm::*)(const std::tuple<Args...>&)>(nullptr));
     338             :   }
     339             : 
     340           0 :   std::string name() const override {
     341             :     return get_template_parameters_as_string<RegisterThreadedAction>();
     342             :   }
     343             : 
     344           0 :   static bool registrar;
     345             : };
     346             : 
     347             : /// \cond
     348             : template <typename ParallelComponent, typename Action>
     349             : struct RegisterThreadedAction<ParallelComponent, Action> : RegistrationHelper {
     350             :   using chare_type = typename ParallelComponent::chare_type;
     351             :   using charm_type = charm_types_with_parameters<
     352             :       ParallelComponent,
     353             :       typename get_array_index<chare_type>::template f<ParallelComponent>>;
     354             :   using cproxy = typename charm_type::cproxy;
     355             :   using ckindex = typename charm_type::ckindex;
     356             :   using algorithm = typename charm_type::algorithm;
     357             : 
     358             :   RegisterThreadedAction() = default;
     359             :   RegisterThreadedAction(const RegisterThreadedAction&) = default;
     360             :   RegisterThreadedAction& operator=(const RegisterThreadedAction&) = default;
     361             :   RegisterThreadedAction(RegisterThreadedAction&&) = default;
     362             :   RegisterThreadedAction& operator=(RegisterThreadedAction&&) = default;
     363             :   ~RegisterThreadedAction() override = default;
     364             : 
     365             :   void register_with_charm() const override {
     366             :     static bool done_registration{false};
     367             :     if (done_registration) {
     368             :       return;  // LCOV_EXCL_LINE
     369             :     }
     370             :     done_registration = true;
     371             :     ckindex::template idx_threaded_action<Action>(
     372             :         static_cast<void (algorithm::*)()>(nullptr));
     373             :   }
     374             : 
     375             :   std::string name() const override {
     376             :     return get_template_parameters_as_string<RegisterThreadedAction>();
     377             :   }
     378             : 
     379             :   static bool registrar;
     380             : };
     381             : /// \endcond
     382             : 
     383             : namespace detail {
     384             : template <class T>
     385             : struct get_value_type {
     386             :   using type = T;
     387             : };
     388             : 
     389             : template <class T>
     390             : struct get_value_type<std::vector<T>> {
     391             :   using type = T;
     392             : };
     393             : 
     394             : template <class Key, class Mapped, class Hash, class KeyEqual, class Allocator>
     395             : struct get_value_type<
     396             :     std::unordered_map<Key, Mapped, Hash, KeyEqual, Allocator>> {
     397             :   // When sending data it is typical to use `std::make_pair(a, b)` which results
     398             :   // in a non-const Key type, which is different from what
     399             :   // `unordered_map::value_type` is (e.g. `std::pair<const Key, Mapped>`). This
     400             :   // difference leads to issues with function registration with Charm++ because
     401             :   // when registering `receive_data` methods we register the `inbox_type`'s
     402             :   // `value_type` (`std::pair<const Key, Mapped>` in this case), not the type
     403             :   // passed to `receive_data`.
     404             :   using type = std::pair<Key, Mapped>;
     405             : };
     406             : 
     407             : template <size_t Size, class Key, class Mapped, class Hash, class KeyEqual>
     408             : struct get_value_type<FixedHashMap<Size, Key, Mapped, Hash, KeyEqual>> {
     409             :   // When sending data it is typical to use `std::make_pair(a, b)` which results
     410             :   // in a non-const Key type, which is different from what
     411             :   // `FixedHashMap::value_type` is (e.g. `std::pair<const Key, Mapped>`). This
     412             :   // difference leads to issues with function registration with Charm++ because
     413             :   // when registering `receive_data` methods we register the `inbox_type`'s
     414             :   // `value_type` (`std::pair<const Key, Mapped>` in this case), not the type
     415             :   // passed to `receive_data`.
     416             :   using type = std::pair<Key, Mapped>;
     417             : };
     418             : 
     419             : template <size_t Dim, class Mapped>
     420             : struct get_value_type<DirectionalIdMap<Dim, Mapped>> {
     421             :   // When sending data it is typical to use `std::make_pair(a, b)` which results
     422             :   // in a non-const Key type, which is different from what
     423             :   // `FixedHashMap::value_type` is (e.g. `std::pair<const Key, Mapped>`). This
     424             :   // difference leads to issues with function registration with Charm++ because
     425             :   // when registering `receive_data` methods we register the `inbox_type`'s
     426             :   // `value_type` (`std::pair<const Key, Mapped>` in this case), not the type
     427             :   // passed to `receive_data`.
     428             :   using type = std::pair<DirectionalId<Dim>, Mapped>;
     429             : };
     430             : 
     431             : template <class Key, class Hash, class KeyEqual, class Allocator>
     432             : struct get_value_type<std::unordered_multiset<Key, Hash, KeyEqual, Allocator>> {
     433             :   using type = Key;
     434             : };
     435             : 
     436             : template <class T>
     437             : using get_value_type_t = typename get_value_type<T>::type;
     438             : }  // namespace detail
     439             : 
     440             : /*!
     441             :  * \ingroup CharmExtensionsGroup
     442             :  * \brief Derived class for registering receive_data functions
     443             :  *
     444             :  * Calls the appropriate Charm++ function to register a receive_data function.
     445             :  * There is a bug in Charm++ that doesn't allow default values for entry method
     446             :  * arguments for groups and nodegroups, so we have to handle the (node)group
     447             :  * cases separately from the singleton and array cases.
     448             :  */
     449             : template <typename ParallelComponent, typename ReceiveTag, bool UsingMessages>
     450           1 : struct RegisterReceiveData : RegistrationHelper {
     451           0 :   using chare_type = typename ParallelComponent::chare_type;
     452           0 :   using charm_type = charm_types_with_parameters<
     453             :       ParallelComponent,
     454             :       typename get_array_index<chare_type>::template f<ParallelComponent>>;
     455           0 :   using cproxy = typename charm_type::cproxy;
     456           0 :   using ckindex = typename charm_type::ckindex;
     457           0 :   using algorithm = typename charm_type::algorithm;
     458             : 
     459           0 :   RegisterReceiveData() = default;
     460           0 :   RegisterReceiveData(const RegisterReceiveData&) = default;
     461           0 :   RegisterReceiveData& operator=(const RegisterReceiveData&) = default;
     462           0 :   RegisterReceiveData(RegisterReceiveData&&) = default;
     463           0 :   RegisterReceiveData& operator=(RegisterReceiveData&&) = default;
     464           0 :   ~RegisterReceiveData() override = default;
     465             : 
     466           0 :   void register_with_charm() const override {
     467             :     static bool done_registration{false};
     468             :     if (done_registration) {
     469             :       return;  // LCOV_EXCL_LINE
     470             :     }
     471             :     done_registration = true;
     472             :     if constexpr (UsingMessages) {
     473             :       using message_type = typename ReceiveTag::message_type;
     474             :       ckindex::template idx_receive_data<ReceiveTag>(
     475             :           static_cast<void (algorithm::*)(message_type*)>(nullptr));
     476             :       RegisterCharmMessage<message_type>::register_with_charm();
     477             :     } else {
     478             :       ckindex::template idx_receive_data<ReceiveTag>(
     479             :           static_cast<void (algorithm::*)(
     480             :               const typename ReceiveTag::temporal_id&,
     481             :               const detail::get_value_type_t<
     482             :                   typename ReceiveTag::type::mapped_type>&,
     483             :               bool)>(nullptr));
     484             :     }
     485             :   }
     486             : 
     487           0 :   std::string name() const override {
     488             :     return get_template_parameters_as_string<RegisterReceiveData>();
     489             :   }
     490             : 
     491           0 :   static bool registrar;
     492             : };
     493             : 
     494             : /*!
     495             :  * \ingroup CharmExtensionsGroup
     496             :  * \brief Derived class for registering reduction actions
     497             :  *
     498             :  * Calls the appropriate Charm++ functions to register a reduction action.
     499             :  */
     500             : template <typename ParallelComponent, typename Action, typename ReductionType>
     501           1 : struct RegisterReductionAction : RegistrationHelper {
     502           0 :   using chare_type = typename ParallelComponent::chare_type;
     503           0 :   using charm_type = charm_types_with_parameters<
     504             :       ParallelComponent,
     505             :       typename get_array_index<chare_type>::template f<ParallelComponent>>;
     506           0 :   using cproxy = typename charm_type::cproxy;
     507           0 :   using ckindex = typename charm_type::ckindex;
     508           0 :   using algorithm = typename charm_type::algorithm;
     509             : 
     510           0 :   RegisterReductionAction() = default;
     511           0 :   RegisterReductionAction(const RegisterReductionAction&) = default;
     512           0 :   RegisterReductionAction& operator=(const RegisterReductionAction&) = default;
     513           0 :   RegisterReductionAction(RegisterReductionAction&&) = default;
     514           0 :   RegisterReductionAction& operator=(RegisterReductionAction&&) = default;
     515           0 :   ~RegisterReductionAction() override = default;
     516             : 
     517           0 :   void register_with_charm() const override {
     518             :     static bool done_registration{false};
     519             :     if (done_registration) {
     520             :       return;  // LCOV_EXCL_LINE
     521             :     }
     522             :     done_registration = true;
     523             :     ckindex::template idx_reduction_action<Action, ReductionType>(
     524             :         static_cast<void (algorithm::*)(const ReductionType&)>(nullptr));
     525             :     ckindex::template redn_wrapper_reduction_action<Action, ReductionType>(
     526             :         nullptr);
     527             :   }
     528             : 
     529           0 :   std::string name() const override {
     530             :     return get_template_parameters_as_string<RegisterReductionAction>();
     531             :   }
     532             : 
     533           0 :   static bool registrar;
     534             : };
     535             : 
     536             : template <typename Metavariables, typename InvokeCombine, typename... Tags>
     537           0 : struct RegisterPhaseChangeReduction : RegistrationHelper {
     538           0 :   using cproxy = CProxy_Main<Metavariables>;
     539           0 :   using ckindex = CkIndex_Main<Metavariables>;
     540           0 :   using algorithm = Main<Metavariables>;
     541             : 
     542           0 :   RegisterPhaseChangeReduction() = default;
     543           0 :   RegisterPhaseChangeReduction(const RegisterPhaseChangeReduction&) = default;
     544           0 :   RegisterPhaseChangeReduction& operator=(const RegisterPhaseChangeReduction&) =
     545             :       default;
     546           0 :   RegisterPhaseChangeReduction(RegisterPhaseChangeReduction&&) = default;
     547           0 :   RegisterPhaseChangeReduction& operator=(RegisterPhaseChangeReduction&&) =
     548             :       default;
     549           0 :   ~RegisterPhaseChangeReduction() override = default;
     550             : 
     551           0 :   void register_with_charm() const override {
     552             :     static bool done_registration{false};
     553             :     if (done_registration) {
     554             :       return;  // LCOV_EXCL_LINE
     555             :     }
     556             :     done_registration = true;
     557             :     ckindex::template idx_phase_change_reduction<InvokeCombine, Tags...>(
     558             :         static_cast<void (algorithm::*)(
     559             :             const ReductionData<
     560             :                 ReductionDatum<tuples::TaggedTuple<Tags...>, InvokeCombine,
     561             :                                funcl::Identity, std::index_sequence<>>>&)>(
     562             :             nullptr));
     563             :     ckindex::template redn_wrapper_phase_change_reduction<InvokeCombine,
     564             :                                                           Tags...>(nullptr);
     565             :   }
     566             : 
     567           0 :   std::string name() const override {
     568             :     return get_template_parameters_as_string<RegisterPhaseChangeReduction>();
     569             :   }
     570             : 
     571           0 :   static bool registrar;
     572             : };
     573             : 
     574             : /*!
     575             :  * \ingroup CharmExtensionsGroup
     576             :  * \brief Derived class for registering GlobalCache::mutate
     577             :  *
     578             :  * Calls the appropriate Charm++ function to register the mutate function.
     579             :  */
     580             : template <typename Metavariables, typename GlobalCacheTag, typename Function,
     581             :           typename... Args>
     582           1 : struct RegisterGlobalCacheMutate : RegistrationHelper {
     583           0 :   using cproxy = CProxy_GlobalCache<Metavariables>;
     584           0 :   using ckindex = CkIndex_GlobalCache<Metavariables>;
     585           0 :   using algorithm = GlobalCache<Metavariables>;
     586             : 
     587           0 :   RegisterGlobalCacheMutate() = default;
     588           0 :   RegisterGlobalCacheMutate(const RegisterGlobalCacheMutate&) = default;
     589           0 :   RegisterGlobalCacheMutate& operator=(const RegisterGlobalCacheMutate&) =
     590             :       default;
     591           0 :   RegisterGlobalCacheMutate(RegisterGlobalCacheMutate&&) = default;
     592           0 :   RegisterGlobalCacheMutate& operator=(RegisterGlobalCacheMutate&&) = default;
     593           0 :   ~RegisterGlobalCacheMutate() override = default;
     594             : 
     595           0 :   void register_with_charm() const override {
     596             :     static bool done_registration{false};
     597             :     if (done_registration) {
     598             :       return;  // LCOV_EXCL_LINE
     599             :     }
     600             :     done_registration = true;
     601             :     ckindex::template idx_mutate<GlobalCacheTag, Function>(
     602             :         static_cast<void (algorithm::*)(const std::tuple<Args...>&)>(nullptr));
     603             :   }
     604             : 
     605           0 :   std::string name() const override {
     606             :     return get_template_parameters_as_string<RegisterGlobalCacheMutate>();
     607             :   }
     608             : 
     609           0 :   static bool registrar;
     610             : };
     611             : 
     612             : /*!
     613             :  * \ingroup CharmExtensionsGroup
     614             :  * \brief Derived class for registering the invoke_iterable_action entry method.
     615             :  * This is a `local` entry method that is only used for tracing the code with
     616             :  * Charm++'s Projections.
     617             :  *
     618             :  * Calls the appropriate Charm++ function to register the invoke_iterable_action
     619             :  * function.
     620             :  */
     621             : template <typename ParallelComponent, typename Action, typename PhaseIndex,
     622             :           typename DataBoxIndex>
     623           1 : struct RegisterInvokeIterableAction : RegistrationHelper {
     624           0 :   using chare_type = typename ParallelComponent::chare_type;
     625           0 :   using charm_type = charm_types_with_parameters<
     626             :       ParallelComponent,
     627             :       typename get_array_index<chare_type>::template f<ParallelComponent>>;
     628           0 :   using cproxy = typename charm_type::cproxy;
     629           0 :   using ckindex = typename charm_type::ckindex;
     630           0 :   using algorithm = typename charm_type::algorithm;
     631             : 
     632           0 :   RegisterInvokeIterableAction() = default;
     633           0 :   RegisterInvokeIterableAction(const RegisterInvokeIterableAction&) = default;
     634           0 :   RegisterInvokeIterableAction& operator=(const RegisterInvokeIterableAction&) =
     635             :       default;
     636           0 :   RegisterInvokeIterableAction(RegisterInvokeIterableAction&&) = default;
     637           0 :   RegisterInvokeIterableAction& operator=(RegisterInvokeIterableAction&&) =
     638             :       default;
     639           0 :   ~RegisterInvokeIterableAction() override = default;
     640             : 
     641           0 :   void register_with_charm() const override {
     642             :     static bool done_registration{false};
     643             :     if (done_registration) {
     644             :       return;  // LCOV_EXCL_LINE
     645             :     }
     646             :     done_registration = true;
     647             :     ckindex::template idx_invoke_iterable_action<Action, PhaseIndex,
     648             :                                                  DataBoxIndex>(
     649             :         static_cast<bool (algorithm::*)()>(nullptr));
     650             :   }
     651             : 
     652           0 :   std::string name() const override {
     653             :     return get_template_parameters_as_string<RegisterInvokeIterableAction>();
     654             :   }
     655             : 
     656           0 :   static bool registrar;
     657             : };
     658             : 
     659             : /*!
     660             :  * \ingroup CharmExtensionsGroup
     661             :  * \brief Function that adds a pointer to a specific derived class to the
     662             :  * `charm_register_list`
     663             :  *
     664             :  * Used to initialize the `registrar` bool of derived classes of
     665             :  * `RegistrationHelper`. When the function is invoked it appends the derived
     666             :  * class to the `charm_register_list`.
     667             :  *
     668             :  * \note The reason for not using a `std::vector` is that this did not behave
     669             :  * correctly when calling `push_back`. Specifically, the final vector was always
     670             :  * size 1, even though multiple elements were pushed back. The reason for that
     671             :  * behavior was never tracked down and so in the future it could be possible to
     672             :  * use a `std::vector`.
     673             :  */
     674             : template <typename Derived>
     675           1 : bool register_func_with_charm() {
     676             : #ifdef SPECTRE_CHARM_HAS_MAIN
     677             :   if (charm_register_list_size >= charm_register_list_capacity) {
     678             :     // clang-tidy: use gsl::owner (we don't use raw owning pointers unless
     679             :     // necessary)
     680             :     auto* const t =  // NOLINT
     681             :         new std::unique_ptr<RegistrationHelper>[charm_register_list_capacity +
     682             :                                                 10];
     683             :     for (size_t i = 0; i < charm_register_list_capacity; ++i) {
     684             :       // clang-tidy: do not use pointer arithmetic
     685             :       t[i] = std::move(charm_register_list[i]);  // NOLINT
     686             :     }
     687             :     // clang-tidy: use gsl::owner (we don't use raw owning pointers unless
     688             :     // necessary)
     689             :     delete[] charm_register_list;  // NOLINT
     690             :     charm_register_list = t;
     691             :     charm_register_list_capacity += 10;
     692             :   }
     693             :   charm_register_list_size++;
     694             :   // clang-tidy: do not use pointer arithmetic
     695             :   charm_register_list[charm_register_list_size - 1] =  // NOLINT
     696             :       std::make_unique<Derived>();
     697             : #endif  // SPECTRE_CHARM_HAS_MAIN
     698             :   return true;
     699             : }
     700             : }  // namespace charmxx
     701             : }  // namespace Parallel
     702             : 
     703             : // clang-tidy: redundant declaration
     704             : template <typename ParallelComponent>
     705             : bool Parallel::charmxx::RegisterParallelComponent<
     706             :     ParallelComponent>::registrar =  // NOLINT
     707             :     Parallel::charmxx::register_func_with_charm<
     708             :         RegisterParallelComponent<ParallelComponent>>();
     709             : 
     710             : // clang-tidy: redundant declaration
     711             : template <typename Chare, typename CkIndex>
     712             : bool Parallel::charmxx::RegisterChare<Chare, CkIndex>::registrar =  // NOLINT
     713             :     Parallel::charmxx::register_func_with_charm<
     714             :         RegisterChare<Chare, CkIndex>>();
     715             : 
     716             : // clang-tidy: redundant declaration
     717             : template <typename ParallelComponent, typename Action, typename... Args>
     718             : bool Parallel::charmxx::RegisterSimpleAction<ParallelComponent, Action,
     719             :                                              Args...>::registrar =  // NOLINT
     720             :     Parallel::charmxx::register_func_with_charm<
     721             :         RegisterSimpleAction<ParallelComponent, Action, Args...>>();
     722             : 
     723             : // clang-tidy: redundant declaration
     724             : template <typename ParallelComponent, typename Action>
     725             : bool Parallel::charmxx::RegisterSimpleAction<ParallelComponent,
     726             :                                              Action>::registrar =  // NOLINT
     727             :     Parallel::charmxx::register_func_with_charm<
     728             :         RegisterSimpleAction<ParallelComponent, Action>>();
     729             : 
     730             : // clang-tidy: redundant declaration
     731             : template <typename ParallelComponent, typename Action, typename... Args>
     732             : bool Parallel::charmxx::RegisterThreadedAction<ParallelComponent, Action,
     733             :                                                Args...>::registrar =  // NOLINT
     734             :     Parallel::charmxx::register_func_with_charm<
     735             :         RegisterThreadedAction<ParallelComponent, Action, Args...>>();
     736             : 
     737             : // clang-tidy: redundant declaration
     738             : template <typename ParallelComponent, typename Action>
     739             : bool Parallel::charmxx::RegisterThreadedAction<ParallelComponent,
     740             :                                                Action>::registrar =  // NOLINT
     741             :     Parallel::charmxx::register_func_with_charm<
     742             :         RegisterThreadedAction<ParallelComponent, Action>>();
     743             : 
     744             : // clang-tidy: redundant declaration
     745             : template <typename ParallelComponent, typename ReceiveTag, bool UsingMessages>
     746             : bool Parallel::charmxx::RegisterReceiveData<
     747             :     ParallelComponent, ReceiveTag, UsingMessages>::registrar =  // NOLINT
     748             :     Parallel::charmxx::register_func_with_charm<
     749             :         RegisterReceiveData<ParallelComponent, ReceiveTag, UsingMessages>>();
     750             : 
     751             : // clang-tidy: redundant declaration
     752             : template <typename ParallelComponent, typename Action, typename ReductionType>
     753             : bool Parallel::charmxx::RegisterReductionAction<
     754             :     ParallelComponent, Action, ReductionType>::registrar =  // NOLINT
     755             :     Parallel::charmxx::register_func_with_charm<
     756             :         RegisterReductionAction<ParallelComponent, Action, ReductionType>>();
     757             : 
     758             : // clang-tidy: redundant declaration
     759             : template <typename Metavariables, typename Invokable, typename... Tags>
     760             : bool Parallel::charmxx::RegisterPhaseChangeReduction<
     761             :     Metavariables, Invokable, Tags...>::registrar =  // NOLINT
     762             :     Parallel::charmxx::register_func_with_charm<
     763             :         RegisterPhaseChangeReduction<Metavariables, Invokable, Tags...>>();
     764             : 
     765             : // clang-tidy: redundant declaration
     766             : template <typename Metavariables, typename GlobalCacheTag, typename Function,
     767             :           typename... Args>
     768             : bool Parallel::charmxx::RegisterGlobalCacheMutate<
     769             :     Metavariables, GlobalCacheTag, Function,
     770             :     Args...>::registrar =  // NOLINT
     771             :     Parallel::charmxx::register_func_with_charm<RegisterGlobalCacheMutate<
     772             :         Metavariables, GlobalCacheTag, Function, Args...>>();
     773             : 
     774             : // clang-tidy: redundant declaration
     775             : template <typename ParallelComponent, typename Action, typename PhaseIndex,
     776             :           typename DataBoxIndex>
     777             : bool Parallel::charmxx::RegisterInvokeIterableAction<
     778             :     ParallelComponent, Action, PhaseIndex, DataBoxIndex>::registrar =  // NOLINT
     779             :     Parallel::charmxx::register_func_with_charm<RegisterInvokeIterableAction<
     780             :         ParallelComponent, Action, PhaseIndex, DataBoxIndex>>();
     781             : 
     782             : /// \cond
     783             : class CkReductionMsg;
     784             : /// \endcond
     785             : 
     786             : namespace Parallel {
     787             : namespace charmxx {
     788             : /*!
     789             :  * \ingroup CharmExtensionsGroup
     790             :  * \brief The type of a function pointer to a Charm++ custom reduction function.
     791             :  */
     792           1 : using ReducerFunctions = CkReductionMsg* (*)(int, CkReductionMsg**);
     793             : /// \cond
     794             : extern ReducerFunctions* charm_reducer_functions_list;
     795             : extern size_t charm_reducer_functions_capacity;
     796             : extern size_t charm_reducer_functions_size;
     797             : extern std::unordered_map<size_t, CkReduction::reducerType>
     798             :     charm_reducer_functions;
     799             : /// \endcond
     800             : 
     801             : /*!
     802             :  * \ingroup CharmExtensionsGroup
     803             :  * \brief Class used for registering custom reduction function
     804             :  *
     805             :  * The static member variable is initialized before main is entered. This means
     806             :  * we are able to inject code into the beginning of the execution of an
     807             :  * executable by "using" the variable (casting to void counts) the function that
     808             :  * initializes the variable is called. We "use" `registrar` inside the
     809             :  * `Parallel::contribute_to_reduction` function.
     810             :  */
     811             : template <ReducerFunctions>
     812           1 : struct RegisterReducerFunction {
     813           0 :   static bool registrar;
     814             : };
     815             : 
     816             : /*!
     817             :  * \ingroup CharmExtensionsGroup
     818             :  * \brief Function that stores a function pointer to the custom reduction
     819             :  * function to be registered later.
     820             :  *
     821             :  * Used to initialize the `registrar` bool of `RegisterReducerFunction`. When
     822             :  * invoked it adds the function `F` of type `ReducerFunctions` to the list
     823             :  * `charm_reducer_functions_list`.
     824             :  *
     825             :  * \note The reason for not using a `std::vector<ReducerFunctions>` is that this
     826             :  * did not behave correctly when calling `push_back`. Specifically, the final
     827             :  * vector was always size 1, even though multiple elements were pushed back. The
     828             :  * reason for that behavior was never tracked down and so in the future it could
     829             :  * be possible to use a `std::vector`.
     830             :  */
     831             : template <ReducerFunctions F>
     832           1 : bool register_reducer_function() {
     833             : #ifdef SPECTRE_CHARM_HAS_MAIN
     834             :   if (charm_reducer_functions_size >= charm_reducer_functions_capacity) {
     835             :     // clang-tidy: use gsl::owner (we don't use raw owning pointers unless
     836             :     // necessary)
     837             :     auto* const t =  // NOLINT
     838             :         new ReducerFunctions[charm_reducer_functions_capacity + 10];
     839             :     for (size_t i = 0; i < charm_reducer_functions_capacity; ++i) {
     840             :       // clang-tidy: do not use pointer arithmetic
     841             :       t[i] = std::move(charm_reducer_functions_list[i]);  // NOLINT
     842             :     }
     843             :     // clang-tidy: use gsl::owner (we don't use raw owning pointers unless
     844             :     // necessary)
     845             :     delete[] charm_reducer_functions_list;  // NOLINT
     846             :     charm_reducer_functions_list = t;
     847             :     charm_reducer_functions_capacity += 10;
     848             :   }
     849             :   charm_reducer_functions_size++;
     850             :   // clang-tidy: do not use pointer arithmetic
     851             :   charm_reducer_functions_list[charm_reducer_functions_size - 1] = F;  // NOLINT
     852             : #endif  // SPECTRE_CHARM_HAS_MAIN
     853             :   return true;
     854             : }
     855             : }  // namespace charmxx
     856             : }  // namespace Parallel
     857             : 
     858             : // clang-tidy: do not use pointer arithmetic
     859             : template <Parallel::charmxx::ReducerFunctions F>
     860             : bool Parallel::charmxx::RegisterReducerFunction<F>::registrar =  // NOLINT
     861             :     Parallel::charmxx::register_reducer_function<F>();

Generated by: LCOV version 1.14