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