Line data Source code
1 0 : // Distributed under the MIT License.
2 : // See LICENSE.txt for details.
3 :
4 : #pragma once
5 :
6 : #include <optional>
7 : #include <ostream>
8 : #include <pup.h>
9 : #include <pup_stl.h>
10 : #include <string>
11 : #include <utility>
12 : #include <variant>
13 :
14 : #include "Options/Options.hpp"
15 : #include "Options/ParseError.hpp"
16 : #include "Utilities/GetOutput.hpp"
17 : #include "Utilities/PrettyType.hpp"
18 : #include "Utilities/StdHelpers.hpp"
19 :
20 : namespace Options {
21 : /// The label representing the absence of a value for `Options::Auto`
22 1 : namespace AutoLabel {
23 : /// 'Auto' label
24 1 : struct Auto {};
25 : /// 'None' label
26 1 : struct None {};
27 : /// 'All' label
28 1 : struct All {};
29 : } // namespace AutoLabel
30 :
31 : /// \ingroup OptionParsingGroup
32 : /// \brief A class indicating that a parsed value can be automatically
33 : /// computed instead of specified.
34 : ///
35 : /// When an `Auto<T>` is parsed from an input file, the value may be specified
36 : /// either as the `AutoLabel` (defaults to "Auto") or as a value of type `T`.
37 : /// When this class is passed to the constructor of the class taking it as an
38 : /// option, it can be implicitly converted to a `std::optional<U>`, for any
39 : /// type `U` implicitly creatable from a `T`.
40 : ///
41 : /// \snippet Test_Auto.cpp example_class
42 : /// \snippet Test_Auto.cpp example_create
43 : template <typename T, typename Label = AutoLabel::Auto>
44 1 : class Auto {
45 : public:
46 0 : using value_type = std::optional<T>;
47 :
48 0 : Auto() = default;
49 0 : explicit Auto(T value) : value_(std::move(value)) {}
50 :
51 : // NOLINTNEXTLINE(google-explicit-constructor)
52 : template <typename U>
53 : operator std::optional<U>() && {
54 : return std::move(value_);
55 : }
56 :
57 0 : void pup(PUP::er& p) { p | value_; }
58 :
59 : // NOLINTNEXTLINE(google-explicit-constructor)
60 0 : operator const value_type&() const { return value_; }
61 :
62 : private:
63 0 : value_type value_{};
64 : };
65 :
66 : template <typename T, typename Label>
67 0 : bool operator==(const Auto<T, Label>& a, const Auto<T, Label>& b) {
68 : return static_cast<const std::optional<T>&>(a) ==
69 : static_cast<const std::optional<T>&>(b);
70 : }
71 :
72 : template <typename T, typename Label>
73 0 : bool operator!=(const Auto<T, Label>& a, const Auto<T, Label>& b) {
74 : return not(a == b);
75 : }
76 :
77 : template <typename T, typename Label>
78 0 : std::ostream& operator<<(std::ostream& os, const Auto<T, Label>& x) {
79 : const std::optional<T>& value = x;
80 : if (value) {
81 : return os << get_output(*value);
82 : } else {
83 : return os << pretty_type::name<Label>();
84 : }
85 : }
86 :
87 : namespace Auto_detail {
88 : template <typename Label>
89 : struct AutoLabel {};
90 : } // namespace Auto_detail
91 :
92 : template <typename Label>
93 : struct create_from_yaml<Auto_detail::AutoLabel<Label>> {
94 : template <typename Metavariables>
95 : static Auto_detail::AutoLabel<Label> create(const Option& options) {
96 : const auto label_string = pretty_type::name<Label>();
97 : try {
98 : if (options.parse_as<std::string>() == label_string) {
99 : return {};
100 : }
101 : } catch (...) {
102 : // The node failed to parse as a string. It is not the Label.
103 : }
104 : // The error if the std::variant parse fails will print the value
105 : // from the input file (and the T parse probably will too), so we
106 : // don't need to print it again.
107 : PARSE_ERROR(options.context(),
108 : "Failed to parse as Auto label \"" << label_string << "\"");
109 : }
110 : };
111 :
112 : template <typename T, typename Label>
113 0 : struct create_from_yaml<Auto<T, Label>> {
114 : template <typename Metavariables>
115 0 : static Auto<T, Label> create(const Option& options) {
116 : auto parsed_variant =
117 : options.parse_as<std::variant<Auto_detail::AutoLabel<Label>, T>,
118 : Metavariables>();
119 : if (std::holds_alternative<T>(parsed_variant)) {
120 : return Auto<T, Label>{std::move(std::get<T>(parsed_variant))};
121 : } else {
122 : return Auto<T, Label>{};
123 : }
124 : }
125 : };
126 : } // namespace Options
|