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