SpECTRE Documentation Coverage Report
Current view: top level - Options - Factory.hpp Hit Total Coverage
Commit: ebec864322c50bab8dca0a90baf8d01875114261 Lines: 1 1 100.0 %
Date: 2020-11-25 20:28:50
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 "ErrorHandling/Assert.hpp"
      18             : #include "Options/Options.hpp"
      19             : #include "Utilities/StdHelpers.hpp"
      20             : #include "Utilities/TMPL.hpp"
      21             : 
      22             : namespace Options {
      23             : namespace Factory_detail {
      24             : struct print_derived {
      25             :   // Not a stream because brigand requires the functor to be copyable.
      26             :   std::string value;
      27             :   template <typename T>
      28             :   void operator()(tmpl::type_<T> /*meta*/) noexcept {
      29             :     // These are zero-based
      30             :     const size_t name_col = 2;
      31             :     const size_t help_col = 22;
      32             :     const size_t end_col = 80;
      33             : 
      34             :     std::ostringstream ss;
      35             :     ss << std::left
      36             :        << std::setw(name_col) << ""
      37             :        << std::setw(help_col - name_col - 1) << name<T>();
      38             :     if (ss.str().size() >= help_col) {
      39             :       ss << "\n" << std::setw(help_col - 1) << "";
      40             :     }
      41             : 
      42             :     std::string help_snippet(T::help);
      43             :     if (help_snippet.size() > end_col - help_col) {
      44             :       help_snippet.resize(end_col - help_col - 3);
      45             :       help_snippet += "...";
      46             :     }
      47             :     std::replace(help_snippet.begin(), help_snippet.end(), '\n', ' ');
      48             :     ss << " " << help_snippet << "\n";
      49             : 
      50             :     value += ss.str();
      51             :   }
      52             : };
      53             : 
      54             : template <typename BaseClass>
      55             : std::string help_derived() noexcept {
      56             :   return "Known Ids:\n" +
      57             :          tmpl::for_each<typename BaseClass::creatable_classes>(
      58             :              Factory_detail::print_derived{})
      59             :              .value;
      60             : }
      61             : 
      62             : template <typename BaseClass, typename Metavariables>
      63             : std::unique_ptr<BaseClass> create(const Option& options) {
      64             :   const auto& node = options.node();
      65             :   Option derived_opts(options.context());
      66             :   derived_opts.append_context("While operating factory for " +
      67             :                               name<BaseClass>());
      68             :   std::string id;
      69             :   if (node.IsScalar()) {
      70             :     id = node.as<std::string>();
      71             :   } else if (node.IsMap()) {
      72             :     if (node.size() != 1) {
      73             :       PARSE_ERROR(derived_opts.context(),
      74             :                   "Expected a single class to create, got "
      75             :                   << node.size() << ":\n" << node);
      76             :     }
      77             :     id = node.begin()->first.as<std::string>();
      78             :     derived_opts.set_node(node.begin()->second);
      79             :   } else if (node.IsNull()) {
      80             :     PARSE_ERROR(derived_opts.context(),
      81             :                 "Expected a class to create:\n" << help_derived<BaseClass>());
      82             :   } else {
      83             :     PARSE_ERROR(derived_opts.context(),
      84             :                 "Expected a class or a class with options, got:\n"
      85             :                 << node);
      86             :   }
      87             : 
      88             :   std::unique_ptr<BaseClass> result;
      89             :   tmpl::for_each<typename BaseClass::creatable_classes>(
      90             :       [&id, &derived_opts, &result](auto derived_v) {
      91             :         using Derived = tmpl::type_from<decltype(derived_v)>;
      92             :         if (name<Derived>() == id) {
      93             :           ASSERT(result == nullptr, "Duplicate factory id: " << id);
      94             :           result = std::make_unique<Derived>(
      95             :               derived_opts.parse_as<Derived, Metavariables>());
      96             :         }
      97             :       });
      98             :   if (result != nullptr) {
      99             :     return result;
     100             :   }
     101             :   PARSE_ERROR(derived_opts.context(),
     102             :               "Unknown Id '" << id << "'\n" << help_derived<BaseClass>());
     103             : }
     104             : }  // namespace Factory_detail
     105             : 
     106             : template <typename T>
     107             : struct create_from_yaml<std::unique_ptr<T>> {
     108             :   template <typename Metavariables>
     109             :   static std::unique_ptr<T> create(const Option& options) {
     110             :     return Factory_detail::create<T, Metavariables>(options);
     111             :   }
     112             : };
     113             : }  // namespace Options

Generated by: LCOV version 1.14