Factory.hpp
Go to the documentation of this file.
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"
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 
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 
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
sstream
std::string
utility
PARSE_ERROR
#define PARSE_ERROR(context, m)
Definition: Options.hpp:71
Options.hpp
algorithm
db::create
constexpr auto create(Args &&... args)
Create a new DataBox.
Definition: DataBox.hpp:853
Options
Utilities for parsing input files.
Definition: MinmodType.hpp:8
Assert.hpp
memory
std::ostringstream
ASSERT
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
iomanip
StdHelpers.hpp
std::unique_ptr
TMPL.hpp
string