SpECTRE Documentation Coverage Report
Current view: top level - Utilities/Serialization - RegisterDerivedClassesWithCharm.hpp Hit Total Coverage
Commit: 817e13c5144619b701c7cd870655d8dbf94ab8ce Lines: 5 5 100.0 %
Date: 2024-07-19 22:17:05
Legend: Lines: hit not hit

          Line data    Source code
       1           1 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : /// \file
       5             : /// Functions for serializing factory-created classes
       6             : 
       7             : #pragma once
       8             : 
       9             : #include <boost/algorithm/string.hpp>
      10             : #include <pup.h>
      11             : #include <typeinfo>
      12             : 
      13             : #include "Utilities/PrettyType.hpp"
      14             : #include "Utilities/Serialization/CharmPupable.hpp"
      15             : #include "Utilities/TMPL.hpp"
      16             : 
      17             : /*!
      18             :  * \brief String representation of a type that is somewhat stable
      19             :  *
      20             :  * This string representation is used to identify the type in serialized data,
      21             :  * including data written to disk. Therefore, the registration name must be
      22             :  * somewhat reliable across invocations of the same program, across different
      23             :  * compilers, and across different executables. C++ provides no standard tool
      24             :  * for this. In particular, the name returned by `typeid().name()` explicitly
      25             :  * provides no guarantees, though for GCC and Clang it returns the mangled name
      26             :  * which should be ABI-stable. See docs:
      27             :  * https://en.cppreference.com/w/cpp/types/type_info/name
      28             :  *
      29             :  * To obtain a somewhat reliable string representation we use
      30             :  * `pretty_type::get_name` (which actually demangles the `typeid().name()`). It
      31             :  * also doesn't make any guarantees, but at least it gives a human-readable
      32             :  * string representation close to the actual source code. We remove whitespaces
      33             :  * from the name because we found inconsistent whitespace on different machines,
      34             :  * likely because the compiler's internal demangling routine got updated:
      35             :  * https://github.com/sxs-collaboration/spectre/issues/4944
      36             :  *
      37             :  * To improve reliability further in the future we may call a dedicated function
      38             :  * on `T`, such as `static std::string registration_name()`, which is expected
      39             :  * to return a unique name (including any template parameters etc). However,
      40             :  * adding this requirement to all PUP::able classes requires quite a lot of code
      41             :  * on our part (but is ultimately the safest option).
      42             :  *
      43             :  * \warning Renaming classes or namespaces will change the registration name and
      44             :  * hence break compatibility with data written by older versions of the code, as
      45             :  * does changing the implementation of this function. This means we can't
      46             :  * deserialize coordinate maps written in H5 files for interpolation of volume
      47             :  * data.
      48             :  */
      49             : template <typename T>
      50           1 : std::string registration_name() {
      51             :   std::string result = pretty_type::get_name<T>();
      52             :   boost::algorithm::erase_all(result, " ");
      53             :   return result;
      54             : }
      55             : 
      56             : /// Register specified classes.  This function can either take classes
      57             : /// to register as template arguments or take a `tmpl::list` of
      58             : /// classes as a function argument.
      59             : template <typename... Registrants>
      60           1 : void register_classes_with_charm(
      61             :     const tmpl::list<Registrants...> /*meta*/ = {}) {
      62             :   const auto helper = [](auto class_v) {
      63             :     using class_to_register = typename decltype(class_v)::type;
      64             :     // We use PUPable_reg2 because this takes as a second argument the name of
      65             :     // the class (as a `const char*`), while PUPable_reg converts the argument
      66             :     // verbatim to a string using the `#` preprocessor operator.
      67             :     PUPable_reg2(class_to_register,
      68             :                  registration_name<class_to_register>().c_str());
      69             :   };
      70             :   (void)helper;
      71             :   EXPAND_PACK_LEFT_TO_RIGHT(helper(tmpl::type_<Registrants>{}));
      72             : }
      73             : 
      74             : /// Register derived classes of the `Base` class
      75             : template <typename Base>
      76           1 : void register_derived_classes_with_charm() {
      77             :   register_classes_with_charm(typename Base::creatable_classes{});
      78             : }
      79             : 
      80             : /// Register all classes in Metavariables::factory_classes
      81             : template <typename Metavariables>
      82           1 : void register_factory_classes_with_charm() {
      83             :   register_classes_with_charm(
      84             :       tmpl::filter<
      85             :           tmpl::flatten<tmpl::values_as_sequence<
      86             :               typename Metavariables::factory_creation::factory_classes>>,
      87             :           std::is_base_of<PUP::able, tmpl::_1>>{});
      88             : }

Generated by: LCOV version 1.14