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

Generated by: LCOV version 1.14