CPP-AP 2.2.6
Command-line argument parser for C++20
Loading...
Searching...
No Matches
positional.hpp
Go to the documentation of this file.
1// Copyright (c) 2023-2025 Jakub MusiaƂ
2// This file is part of the CPP-AP project (https://github.com/SpectraL519/cpp-ap).
3// Licensed under the MIT License. See the LICENSE file in the project root for full license information.
4
6
7#pragma once
8
13
14#ifdef AP_TESTING
15
16namespace ap_testing {
17struct positional_argument_test_fixture;
18} // namespace ap_testing
19
20#endif
21
22namespace ap::argument {
23
28template <detail::c_argument_value_type T = std::string>
30public:
31 using value_type = T;
32
33 positional() = delete;
34
39 positional(const detail::argument_name& name) : argument_base(name) {}
40
41 ~positional() = default;
42
48 bool operator==(const positional& other) const noexcept {
49 return this->_name == other._name;
50 }
51
57 positional& help(std::string_view help_msg) noexcept {
58 this->_help_msg = help_msg;
59 return *this;
60 }
61
70 template <detail::c_range_of<value_type, detail::type_validator::convertible> CR>
71 positional& choices(const CR& choices) noexcept
72 requires(std::equality_comparable<value_type>)
73 {
74 for (const auto& choice : choices)
75 this->_choices.emplace_back(choice);
76 return *this;
77 }
78
85 positional& choices(std::initializer_list<value_type> choices) noexcept
86 requires(std::equality_comparable<value_type>)
87 {
88 return this->choices<>(choices);
89 }
90
98 template <action::detail::c_value_action_specifier AS, std::invocable<value_type&> F>
99 positional& action(F&& action) noexcept {
101 this->_value_actions.emplace_back(std::forward<callable_type>(action));
102 return *this;
103 }
104
106 friend class ::ap::argument_parser;
107
108#ifdef AP_TESTING
112 friend struct ::ap_testing::positional_argument_test_fixture;
113#endif
114
115private:
116 using value_action_type =
118
124 [[nodiscard]] detail::argument_descriptor desc(
125 const bool verbose, [[maybe_unused]] const char flag_char
126 ) const noexcept override {
127 detail::argument_descriptor desc(this->_name.str(), this->_help_msg);
128
129 if (not verbose)
130 return desc;
131
132 if constexpr (detail::c_writable<value_type>) {
133 if (not this->_choices.empty())
134 desc.add_range_param("choices", this->_choices);
135 }
136
137 return desc;
138 }
139
141 [[nodiscard]] bool is_required() const noexcept override {
142 return this->_required;
143 }
144
146 [[nodiscard]] bool bypass_required_enabled() const noexcept override {
147 return this->_bypass_required;
148 }
149
154 bool mark_used() override {
155 return false;
156 }
157
159 [[nodiscard]] bool is_used() const noexcept override {
160 return this->_value.has_value();
161 }
162
164 [[nodiscard]] std::size_t count() const noexcept override {
165 return static_cast<std::size_t>(this->_value.has_value());
166 }
167
174 bool set_value(const std::string& str_value) override {
175 if (this->_value.has_value())
176 throw parsing_failure::value_already_set(this->_name);
177
178 value_type value;
179 if (not (std::istringstream(str_value) >> value))
180 throw parsing_failure::invalid_value(this->_name, str_value);
181
182 if (not detail::is_valid_choice(value, this->_choices))
183 throw parsing_failure::invalid_choice(this->_name, str_value);
184
185 const auto apply_visitor = action::detail::apply_visitor<value_type>{value};
186 for (const auto& action : this->_value_actions)
187 std::visit(apply_visitor, action);
188
189 this->_value = value;
190 return false;
191 }
192
194 [[nodiscard]] bool has_value() const noexcept override {
195 return this->_value.has_value();
196 }
197
199 [[nodiscard]] bool has_parsed_values() const noexcept override {
200 return this->has_value();
201 }
202
204 [[nodiscard]] std::weak_ordering nvalues_ordering() const noexcept override {
205 return this->_value.has_value() ? std::weak_ordering::equivalent : std::weak_ordering::less;
206 }
207
212 [[nodiscard]] const std::any& value() const override {
213 if (not this->_value.has_value())
214 throw std::logic_error(
215 std::format("No value parsed for the `{}` positional argument.", this->_name.str())
216 );
217 return this->_value;
218 }
219
224 [[nodiscard]] const std::vector<std::any>& values() const override {
225 throw std::logic_error(
226 std::format("Positional argument `{}` has only 1 value.", this->_name.primary)
227 );
228 }
229
230 static constexpr bool _required = true;
231 static constexpr bool _bypass_required = false;
232 std::vector<value_type> _choices;
233 std::vector<value_action_type> _value_actions;
234
235 std::any _value;
236};
237
238} // namespace ap::argument
Defines the base argument class and common utility.
The positional argument class.
bool operator==(const positional &other) const noexcept
Equality operator for positional argument.
positional & action(F &&action) noexcept
Set the action for the positional argument.
positional & choices(const CR &choices) noexcept
Set the choices for the positional argument.
positional & help(std::string_view help_msg) noexcept
Set the help message for the positional argument.
T value_type
The argument's value type.
positional & choices(std::initializer_list< value_type > choices) noexcept
Set the choices for the positional argument.
positional(const detail::argument_name &name)
Constructor for positional argument with the name identifier.
Argument class interface.
const ap::detail::argument_name & name() const noexcept
A structure used to represent an argument's description.
void add_range_param(const std::string &name, const R &range, const std::string_view delimiter=default_delimiter)
Adds a range parameter descriptor with the given value.
The concept is satisfied when T overloads the std::ostream operator <<.
Definition concepts.hpp:29
Provides the general concept definitions.
Structure holding the argument's name.
std::string str(const std::optional< char > flag_char=std::nullopt) const noexcept
Get a string representation of the argument_name.
const std::string primary
The primary name of the argument.
Defines general action-related utility.
typename AS::template type< T > callable_type
Template argument action callable type alias.
Definition utility.hpp:36
std::variant< callable_type< action_type::observe, T >, callable_type< action_type::transform, T >, callable_type< action_type::modify, T > > value_action_variant_type
Template argument action callabla variant type alias.
Definition utility.hpp:43