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 
16 #include "ErrorHandling/Assert.hpp"
17 #include "Options/Options.hpp"
18 #include "Utilities/PrettyType.hpp"
19 #include "Utilities/Requires.hpp"
20 #include "Utilities/StdHelpers.hpp"
21 #include "Utilities/TMPL.hpp"
22 
23 namespace Factory_detail {
24 template <typename BaseClass, typename CreateList,
26 std::unique_ptr<BaseClass> create_derived(
27  const std::string& /*id*/, const Option& /*opts*/) noexcept {
29 }
30 
31 template <typename BaseClass, typename CreateList,
32  Requires<(tmpl::size<CreateList>::value != 0)> = nullptr>
33 std::unique_ptr<BaseClass> create_derived(const std::string& id,
34  const Option& opts) {
35  using derived = tmpl::front<CreateList>;
36 
37  if (pretty_type::short_name<derived>() != id) {
38  return create_derived<BaseClass, tmpl::pop_front<CreateList>>(id, opts);
39  }
40 
41  ASSERT((not create_derived<BaseClass, tmpl::pop_front<CreateList>>(id, opts)),
42  "Duplicate factory id: " << id);
43 
44  return std::make_unique<derived>(opts.parse_as<derived>());
45 }
46 
47 struct print_derived {
48  // Not a stream because brigand requires the functor to be copyable.
49  std::string value;
50  template <typename T>
51  void operator()(tmpl::type_<T> /*meta*/) noexcept {
52  // These are zero-based
53  const size_t name_col = 2;
54  const size_t help_col = 22;
55  const size_t end_col = 80;
56 
58  ss << std::left
59  << std::setw(name_col) << ""
60  << std::setw(help_col - name_col - 1) << pretty_type::short_name<T>();
61  if (ss.str().size() >= help_col) {
62  ss << "\n" << std::setw(help_col - 1) << "";
63  }
64 
65  std::string help_snippet(T::help);
66  if (help_snippet.size() > end_col - help_col) {
67  help_snippet.resize(end_col - help_col - 3);
68  help_snippet += "...";
69  }
70  std::replace(help_snippet.begin(), help_snippet.end(), '\n', ' ');
71  ss << " " << help_snippet << "\n";
72 
73  value += ss.str();
74  }
75 };
76 
77 template <typename BaseClass>
78 std::string help_derived() noexcept {
79  return "Known Ids:\n" +
80  tmpl::for_each<typename BaseClass::creatable_classes>(
81  Factory_detail::print_derived{})
82  .value;
83 }
84 
85 template <typename BaseClass>
87  const auto& node = options.node();
88  Option derived_opts(options.context());
89  derived_opts.append_context("While operating factory for " +
90  pretty_type::short_name<BaseClass>());
91  std::string id;
92  if (node.IsScalar()) {
93  id = node.as<std::string>();
94  } else if (node.IsMap()) {
95  if (node.size() != 1) {
96  PARSE_ERROR(derived_opts.context(),
97  "Expected a single class to create, got "
98  << node.size() << ":\n" << node);
99  }
100  id = node.begin()->first.as<std::string>();
101  derived_opts.set_node(node.begin()->second);
102  } else if (node.IsNull()) {
103  PARSE_ERROR(derived_opts.context(),
104  "Expected a class to create:\n" << help_derived<BaseClass>());
105  } else {
106  PARSE_ERROR(derived_opts.context(),
107  "Expected a class or a class with options, got:\n"
108  << node);
109  }
110  auto derived =
111  create_derived<BaseClass, typename BaseClass::creatable_classes>(
112  id, derived_opts);
113  if (derived != nullptr) {
114  return derived;
115  }
116  PARSE_ERROR(derived_opts.context(),
117  "Unknown Id '" << id << "'\n" << help_derived<BaseClass>());
118 }
119 } // namespace Factory_detail
120 
121 template <typename T>
122 struct create_from_yaml<std::unique_ptr<T>> {
123  static std::unique_ptr<T> create(const Option& options) {
124  return Factory_detail::create<T>(options);
125  }
126 };
Defines helper functions for the standard library.
The type that options are passed around as. Contains YAML node data and an OptionContext.
Definition: Options.hpp:103
T parse_as() const
Convert to an object of type T.
Definition: ParseOptions.hpp:69
Used by the parser to create an object. The default action is to parse options using T::options...
Definition: Options.hpp:143
Defines classes and functions for making classes creatable from input files.
constexpr auto create(Args &&... args)
Create a new DataBox.
Definition: DataBox.hpp:1259
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
Definition: Factory.hpp:23
Defines the type alias Requires.
#define PARSE_ERROR(context, m)
Like ERROR("\n" << (context) << m), but instead throws an exception that will be caught in a higher l...
Definition: Options.hpp:66
void append_context(const std::string &context) noexcept
Append a line to the contained context.
Definition: ParseOptions.hpp:57
const YAML::Node & node() const noexcept
Definition: ParseOptions.hpp:51
Defines macro ASSERT.
Contains a pretty_type library to write types in a "pretty" format.
Wraps the template metaprogramming library used (brigand)
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t ...
Definition: Requires.hpp:67