SpECTRE Documentation Coverage Report
Current view: top level - Options - Factory.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 100.0 % 1 1
Test Date: 2026-10-22 17:29:42
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              : /// Defines class template Factory.
       6              : 
       7              : #pragma once
       8              : 
       9              : #include <algorithm>
      10              : #include <iomanip>
      11              : #include <memory>
      12              : #include <sstream>
      13              : #include <string>
      14              : #include <utility>
      15              : #include <yaml-cpp/yaml.h>
      16              : 
      17              : #include "Options/Options.hpp"
      18              : #include "Options/ParseError.hpp"
      19              : #include "Options/Protocols/FactoryCreation.hpp"
      20              : #include "Utilities/ErrorHandling/Assert.hpp"
      21              : #include "Utilities/PrettyType.hpp"
      22              : #include "Utilities/ProtocolHelpers.hpp"
      23              : #include "Utilities/StdHelpers.hpp"
      24              : #include "Utilities/TMPL.hpp"
      25              : #include "Utilities/TypeTraits/CreateGetStaticMemberVariableOrDefault.hpp"
      26              : 
      27              : namespace Options {
      28              : namespace Factory_detail {
      29              : struct print_derived {
      30              :   // Not a stream because brigand requires the functor to be copyable.
      31              :   std::string value;
      32              :   template <typename T>
      33              :   void operator()(tmpl::type_<T> /*meta*/) {
      34              :     // These are zero-based
      35              :     const size_t name_col = 2;
      36              :     const size_t help_col = 22;
      37              :     const size_t end_col = 80;
      38              : 
      39              :     std::ostringstream ss;
      40              :     ss << std::left << std::setw(name_col) << ""
      41              :        << std::setw(help_col - name_col - 1) << pretty_type::name<T>();
      42              :     if (ss.str().size() >= help_col) {
      43              :       ss << "\n" << std::setw(help_col - 1) << "";
      44              :     }
      45              : 
      46              :     std::string help_snippet(T::help);
      47              :     if (help_snippet.size() > end_col - help_col) {
      48              :       help_snippet.resize(end_col - help_col - 3);
      49              :       help_snippet += "...";
      50              :     }
      51              :     std::replace(help_snippet.begin(), help_snippet.end(), '\n', ' ');
      52              :     ss << " " << help_snippet << "\n";
      53              : 
      54              :     value += ss.str();
      55              :   }
      56              : };
      57              : 
      58              : template <typename CreatableClasses>
      59              : std::string help_derived() {
      60              :   return "Known Ids:\n" +
      61              :          tmpl::for_each<CreatableClasses>(
      62              :              Factory_detail::print_derived{})
      63              :              .value;
      64              : }
      65              : 
      66              : // This is for handling legacy code that still uses creatable_classes.
      67              : // It should be inlined once everything is converted.
      68              : template <typename BaseClass, typename Metavariables, typename = std::void_t<>>
      69              : struct get_creatable_classes {
      70              :   using factory_creation = typename Metavariables::factory_creation;
      71              :   // This assertion is normally done in tests, but the executable
      72              :   // metavariables don't have tests, so we do it here.
      73              :   static_assert(tt::assert_conforms_to_v<factory_creation,
      74              :                                          Options::protocols::FactoryCreation>);
      75              :   using type = tmpl::at<typename factory_creation::factory_classes, BaseClass>;
      76              : };
      77              : 
      78              : template <typename BaseClass, typename Metavariables>
      79              : struct get_creatable_classes<
      80              :   BaseClass, Metavariables,
      81              :   std::void_t<typename BaseClass::creatable_classes>> {
      82              :   using type = typename BaseClass::creatable_classes;
      83              : };
      84              : 
      85              : CREATE_GET_STATIC_MEMBER_VARIABLE_OR_DEFAULT(factory_creatable)
      86              : 
      87              : template <typename T>
      88              : struct is_factory_creatable
      89              :     : std::bool_constant<get_factory_creatable_or_default_v<T, true>> {};
      90              : 
      91              : template <typename BaseClass, typename Metavariables>
      92              : std::unique_ptr<BaseClass> create(const Option& options) {
      93              :   using all_creatable_classes =
      94              :       typename get_creatable_classes<BaseClass, Metavariables>::type;
      95              :   static_assert(not std::is_same_v<all_creatable_classes, tmpl::no_such_type_>,
      96              :                 "List of creatable derived types for this class is missing "
      97              :                 "from Metavariables::factory_classes.");
      98              :   using creatable_classes =
      99              :       tmpl::filter<all_creatable_classes, is_factory_creatable<tmpl::_1>>;
     100              : 
     101              :   const auto& node = options.node();
     102              :   Option derived_opts(options.context());
     103              :   derived_opts.append_context("While operating factory for " +
     104              :                               pretty_type::name<BaseClass>());
     105              :   std::string id;
     106              :   if (node.IsScalar()) {
     107              :     id = node.as<std::string>();
     108              :   } else if (node.IsMap()) {
     109              :     if (node.size() != 1) {
     110              :       PARSE_ERROR(derived_opts.context(),
     111              :                   "Expected a class name (and possibly options), got multiple "
     112              :                   "key-value pairs:\n" << node);
     113              :     }
     114              :     id = node.begin()->first.as<std::string>();
     115              :     derived_opts.set_node(node.begin()->second);
     116              :   } else if (node.IsNull()) {
     117              :     PARSE_ERROR(derived_opts.context(),
     118              :                 "Expected a class name (and possibly options):\n"
     119              :                 << help_derived<creatable_classes>());
     120              :   } else {
     121              :     PARSE_ERROR(derived_opts.context(),
     122              :                 "Expected a class or a class with options, got:\n"
     123              :                 << node);
     124              :   }
     125              : 
     126              :   std::unique_ptr<BaseClass> result;
     127              :   tmpl::for_each<creatable_classes>(
     128              :       [&id, &derived_opts, &result](auto derived_v) {
     129              :         using Derived = tmpl::type_from<decltype(derived_v)>;
     130              :         if (pretty_type::name<Derived>() == id) {
     131              :           ASSERT(result == nullptr, "Duplicate factory id: " << id);
     132              :           result = std::make_unique<Derived>(
     133              :               derived_opts.parse_as<Derived, Metavariables>());
     134              :         }
     135              :       });
     136              :   if (result != nullptr) {
     137              :     return result;
     138              :   }
     139              :   PARSE_ERROR(derived_opts.context(),
     140              :               "Unknown Id '" << id << "'\n"
     141              :               << help_derived<creatable_classes>());
     142              : }
     143              : }  // namespace Factory_detail
     144              : 
     145              : template <typename T>
     146              : struct create_from_yaml<std::unique_ptr<T>> {
     147              :   template <typename Metavariables>
     148              :   static std::unique_ptr<T> create(const Option& options) {
     149              :     return Factory_detail::create<T, Metavariables>(options);
     150              :   }
     151              : };
     152              : }  // namespace Options
        

Generated by: LCOV version 2.0-1