chore: refactor class names.

feat: introduce parser settings for controlling the exit behavior.
This commit is contained in:
2026-05-13 13:04:57 +04:00
parent d1267c892f
commit 566b9128db
8 changed files with 90 additions and 58 deletions

View File

@@ -22,8 +22,8 @@ namespace argument_parser::builder {
reference,
accumulate,
count,
nonparametered_action,
parametered_action
action_no_param,
action_with_param
};
enum class extra_capability : unsigned { Store = static_cast<unsigned>(v2_flag::Reference) + 1, Flag };
@@ -321,9 +321,9 @@ namespace argument_parser::builder {
argument<builder_mask::remove(current_mask, builder_mask::value_mode_group), non_type>;
next_argument next{*this};
next.m_action = std::make_shared<argument_parser::non_parametered_action>(
next.m_action = std::make_shared<argument_parser::action_no_param>(
std::function<void()>(std::forward<Callable>(handler)));
next.m_value_mode = value_mode::nonparametered_action;
next.m_value_mode = value_mode::action_no_param;
return next;
}
@@ -338,9 +338,9 @@ namespace argument_parser::builder {
using next_argument = argument<builder_mask::remove(current_mask, builder_mask::value_mode_group), T>;
next_argument next{*this};
next.m_action = std::make_shared<argument_parser::parametered_action<T>>(
next.m_action = std::make_shared<argument_parser::action_with_param<T>>(
std::function<void(const T &)>(std::forward<Callable>(handler)));
next.m_value_mode = value_mode::parametered_action;
next.m_value_mode = value_mode::action_with_param;
return next;
}
@@ -352,8 +352,8 @@ namespace argument_parser::builder {
case value_mode::flag:
build_flag(parser);
return;
case value_mode::nonparametered_action:
build_nonparametered_action(parser);
case value_mode::action_no_param:
build_action_with_no_param(parser);
return;
case value_mode::store:
if constexpr (!std::is_same_v<store_type, non_type>) {
@@ -374,9 +374,9 @@ namespace argument_parser::builder {
return;
}
break;
case value_mode::parametered_action:
case value_mode::action_with_param:
if constexpr (!std::is_same_v<store_type, non_type>) {
build_parametered_action(parser);
build_action_with_param(parser);
return;
}
break;
@@ -535,9 +535,9 @@ namespace argument_parser::builder {
parser.template add_argument<store_type>(pairs);
}
auto build_parametered_action(argument_parser::v2::base_parser &parser) const -> void {
auto build_action_with_param(argument_parser::v2::base_parser &parser) const -> void {
auto const *typed_action =
dynamic_cast<argument_parser::parametered_action<store_type> const *>(m_action.get());
dynamic_cast<argument_parser::action_with_param<store_type> const *>(m_action.get());
if (typed_action == nullptr) {
throw std::logic_error("Stored action is not compatible with the requested parameter type.");
}
@@ -547,15 +547,14 @@ namespace argument_parser::builder {
parser.template add_argument<store_type>(pairs);
}
auto build_nonparametered_action(argument_parser::v2::base_parser &parser) const -> void {
auto const *nonparametered_action =
dynamic_cast<argument_parser::non_parametered_action const *>(m_action.get());
auto build_action_with_no_param(argument_parser::v2::base_parser &parser) const -> void {
auto const *nonparametered_action = dynamic_cast<argument_parser::action_no_param const *>(m_action.get());
if (nonparametered_action == nullptr) {
throw std::logic_error("Stored action is not a non-parametered action.");
}
if (is_positional()) {
auto wrapped_action = argument_parser::helpers::make_parametered_action<std::string>(
auto wrapped_action = argument_parser::helpers::make_action<std::string>(
[action = *nonparametered_action](std::string const &) { action.invoke(); });
auto pairs = make_typed_pairs<std::string>();
pairs[argument_parser::v2::flags::Action] = wrapped_action;

View File

@@ -66,7 +66,7 @@ namespace argument_parser {
copyable_atomic &operator=(copyable_atomic &&other) noexcept = default;
~copyable_atomic() = default;
copyable_atomic& operator=(T desired) noexcept {
copyable_atomic &operator=(T desired) noexcept {
store(desired);
return *this;
}
@@ -104,9 +104,9 @@ namespace argument_parser {
[[nodiscard]] virtual std::unique_ptr<action_base> clone() const = 0;
};
template <typename T> class parametered_action : public action_base {
template <typename T> class action_with_param : public action_base {
public:
explicit parametered_action(std::function<void(const T &)> const &handler) : handler(handler) {}
explicit action_with_param(std::function<void(const T &)> const &handler) : handler(handler) {}
using parameter_type = T;
void invoke(const T &arg) const {
handler(arg);
@@ -149,16 +149,16 @@ namespace argument_parser {
}
[[nodiscard]] std::unique_ptr<action_base> clone() const override {
return std::make_unique<parametered_action<T>>(handler);
return std::make_unique<action_with_param<T>>(handler);
}
private:
std::function<void(const T &)> handler;
};
class non_parametered_action : public action_base {
class action_no_param : public action_base {
public:
explicit non_parametered_action(std::function<void()> const &handler) : handler(handler) {}
explicit action_no_param(std::function<void()> const &handler) : handler(handler) {}
void invoke() const override {
handler();
@@ -177,7 +177,7 @@ namespace argument_parser {
}
[[nodiscard]] std::unique_ptr<action_base> clone() const override {
return std::make_unique<non_parametered_action>(handler);
return std::make_unique<action_no_param>(handler);
}
private:
@@ -230,16 +230,27 @@ namespace argument_parser {
};
namespace helpers {
template <typename T>
static parametered_action<T> make_parametered_action(std::function<void(const T &)> const &function) {
return parametered_action<T>(function);
template <typename T> static action_with_param<T> make_action(std::function<void(const T &)> const &function) {
return action_with_param<T>(function);
}
static non_parametered_action make_non_parametered_action(std::function<void()> const &function) {
return non_parametered_action(function);
static action_no_param make_action(std::function<void()> const &function) {
return action_no_param(function);
}
} // namespace helpers
struct parser_settings {
bool should_exit_on_error = true;
bool should_exit_on_missing_required = true;
bool should_exit_on_unknown_argument = true;
bool should_exit_on_help = true;
bool ignore_unknown_arguments = false;
bool ignore_errors = false;
};
constexpr static inline parser_settings no_exit{false, false, false, false};
/**
* @brief Base class for parsing arguments from the command line.
*
@@ -251,7 +262,7 @@ namespace argument_parser {
public:
template <typename T>
void add_argument(std::string const &short_arg, std::string const &long_arg, std::string const &help_text,
parametered_action<T> const &action, bool required) {
action_with_param<T> const &action, bool required) {
base_add_argument(short_arg, long_arg, help_text, action, required);
}
@@ -262,7 +273,7 @@ namespace argument_parser {
}
void add_argument(std::string const &short_arg, std::string const &long_arg, std::string const &help_text,
non_parametered_action const &action, bool required) {
action_no_param const &action, bool required) {
base_add_argument(short_arg, long_arg, help_text, action, required);
}
@@ -273,7 +284,7 @@ namespace argument_parser {
template <typename T>
void add_positional_argument(std::string const &name, std::string const &help_text,
parametered_action<T> const &action, bool required,
action_with_param<T> const &action, bool required,
std::optional<int> position = std::nullopt) {
base_add_positional_argument(name, help_text, action, required, position);
}
@@ -286,7 +297,7 @@ namespace argument_parser {
template <typename T>
void add_positional_accumulator(std::string const &name, std::string const &help_text,
parametered_action<T> const &action, bool required,
action_with_param<T> const &action, bool required,
std::optional<int> position = std::nullopt) {
base_add_positional_argument(name, help_text, action, required, position, true);
}
@@ -335,7 +346,12 @@ namespace argument_parser {
void on_complete(std::function<void(base_parser const &)> const &handler, bool to_start);
void set_settings(parser_settings const &settings) {
m_settings = settings;
}
private:
parser_settings m_settings;
struct found_argument {
std::string key;
argument arg;
@@ -343,15 +359,12 @@ namespace argument_parser {
};
bool test_conventions(std::initializer_list<conventions::convention const *const> convention_types,
std::vector<found_argument> &found_arguments,
std::optional<argument> &found_help, std::vector<std::string>::iterator &it,
std::stringstream &error_stream);
std::vector<found_argument> &found_arguments, std::optional<argument> &found_help,
std::vector<std::string>::iterator &it, std::stringstream &error_stream);
void extract_arguments(std::initializer_list<conventions::convention const *const> convention_types,
std::vector<found_argument> &found_arguments,
std::optional<argument> &found_help);
std::vector<found_argument> &found_arguments, std::optional<argument> &found_help);
void invoke_arguments(std::vector<found_argument> &found_arguments,
std::optional<argument> const &found_help);
void invoke_arguments(std::vector<found_argument> &found_arguments, std::optional<argument> const &found_help);
void enforce_creation_thread() const;
void assert_argument_not_exist(std::string const &short_arg, std::string const &long_arg) const;
@@ -379,13 +392,12 @@ namespace argument_parser {
assert_argument_not_exist(short_arg, long_arg);
int id = id_counter.fetch_add(1);
if constexpr (std::is_same_v<StoreType, void>) {
auto action =
helpers::make_non_parametered_action([id, this] { stored_arguments[id] = std::any{true}; });
auto action = helpers::make_action([id, this] { stored_arguments[id] = std::any{true}; });
argument arg(id, short_arg + "|" + long_arg, action);
set_argument_status(required, help_text, arg);
place_argument(id, arg, short_arg, long_arg);
} else {
auto action = helpers::make_parametered_action<StoreType>(
auto action = helpers::make_action<StoreType>(
[id, this](StoreType const &value) { stored_arguments[id] = std::any{value}; });
argument arg(id, short_arg + "|" + long_arg, action);
set_argument_status(required, help_text, arg);
@@ -412,7 +424,7 @@ namespace argument_parser {
std::optional<int> position = std::nullopt) {
assert_positional_not_exist(name);
int id = id_counter.fetch_add(1);
auto action = helpers::make_parametered_action<StoreType>(
auto action = helpers::make_action<StoreType>(
[id, this](StoreType const &value) { stored_arguments[id] = std::any{value}; });
argument arg(id, name, action);
set_argument_status(required, help_text, arg);

View File

@@ -0,0 +1,18 @@
#pragma once
#ifndef ARGUMENT_PARSER_EXCEPTIONS_HPP
#define ARGUMENT_PARSER_EXCEPTIONS_HPP
#include <stdexcept>
namespace argument_parser {
namespace parser {
class unknown_argument_exception : public std::runtime_error {
public:
unknown_argument_exception(const std::string &message) : std::runtime_error(message) {}
};
} // namespace parser
} // namespace argument_parser
#endif // ARGUMENT_PARSER_EXCEPTIONS_HPP

View File

@@ -57,15 +57,15 @@ namespace argument_parser::v2 {
class base_parser : argument_parser::base_parser {
public:
template <typename T> using typed_flag_value = std::variant<std::string, parametered_action<T>, bool, int, T *>;
using non_typed_flag_value = std::variant<std::string, non_parametered_action, bool, int>;
template <typename T> using typed_flag_value = std::variant<std::string, action_with_param<T>, bool, int, T *>;
using non_typed_flag_value = std::variant<std::string, action_no_param, bool, int>;
template <typename T> using typed_argument_pair = std::pair<add_argument_flags, typed_flag_value<T>>;
using non_typed_argument_pair = std::pair<add_argument_flags, non_typed_flag_value>;
template <typename T>
void add_argument(std::unordered_map<add_argument_flags, typed_flag_value<T>> const &argument_pairs) {
add_argument_impl<true, parametered_action<T>, T>(argument_pairs);
add_argument_impl<true, action_with_param<T>, T>(argument_pairs);
}
template <typename T> void add_argument(std::initializer_list<typed_argument_pair<T>> const &pairs) {
@@ -89,7 +89,7 @@ namespace argument_parser::v2 {
}
void add_argument(std::unordered_map<add_argument_flags, non_typed_flag_value> const &argument_pairs) {
add_argument_impl<false, non_parametered_action, void>(argument_pairs);
add_argument_impl<false, action_no_param, void>(argument_pairs);
}
argument_parser::base_parser &to_v1() {
@@ -122,7 +122,7 @@ namespace argument_parser::v2 {
void prepare_help_flag(bool should_exit = true) {
add_argument({{flags::ShortArgument, "h"},
{flags::LongArgument, "help"},
{flags::Action, helpers::make_non_parametered_action([this, should_exit] {
{flags::Action, helpers::make_action([this, should_exit] {
this->display_help(this->current_conventions());
if (should_exit) {
std::exit(0);
@@ -131,6 +131,10 @@ namespace argument_parser::v2 {
{flags::HelpText, "Prints this help text."}});
}
void set_settings(parser_settings const &settings) {
base::set_settings(settings);
}
private:
template <bool IsTyped, typename ActionType, typename T, typename ArgsMap>
void add_argument_impl(ArgsMap const &argument_pairs) {
@@ -224,7 +228,7 @@ namespace argument_parser::v2 {
base::add_argument<typename T::value_type>(
short_arg, long_arg, help_text,
*static_cast<parametered_action<typename T::value_type> *>(&(*action)), required);
*static_cast<action_with_param<typename T::value_type> *>(&(*action)), required);
return;
}
}
@@ -375,7 +379,7 @@ namespace argument_parser::v2 {
if constexpr (!std::is_same_v<T, void> && deducers::is_vector_v<T>) {
base::add_positional_accumulator<typename T::value_type>(
positional_name, help_text,
*static_cast<parametered_action<typename T::value_type> *>(&(*action)), required, position);
*static_cast<action_with_param<typename T::value_type> *>(&(*action)), required, position);
return;
}
}
@@ -452,16 +456,15 @@ namespace argument_parser::v2 {
}
template <typename T> std::unique_ptr<action_base> make_reference_action(T *target) {
return helpers::make_parametered_action<T>([target](T const &value) { *target = value; }).clone();
return helpers::make_action<T>([target](T const &value) { *target = value; }).clone();
}
template <typename Vector> std::unique_ptr<action_base> make_accumulate_ref_action(Vector *target) {
if constexpr (std::is_same_v<Vector, int>) {
return helpers::make_non_parametered_action([target]() { *target += 1; }).clone();
return helpers::make_action([target]() { *target += 1; }).clone();
} else {
using Value = typename Vector::value_type;
return helpers::make_parametered_action<Value>(
[target](Value const &value) { target->emplace_back(value); })
return helpers::make_action<Value>([target](Value const &value) { target->emplace_back(value); })
.clone();
}
}

View File

@@ -16,7 +16,7 @@ namespace argument_parser {
namespace v2 {
class linux_parser : public v2::base_parser {
public:
linux_parser(bool should_exit = true);
linux_parser(parser_settings const &settings = {});
using base_parser::display_help;
};
} // namespace v2

View File

@@ -15,7 +15,7 @@ namespace argument_parser {
namespace v2 {
class macos_parser : public v2::base_parser {
public:
explicit macos_parser(bool should_exit = true);
explicit macos_parser(parser_settings const &settings = {});
using base_parser::display_help;
};
} // namespace v2

View File

@@ -12,7 +12,7 @@ namespace argument_parser {
namespace v2 {
class windows_parser : public v2::base_parser {
public:
windows_parser(bool should_exit = true);
windows_parser(parser_settings const &settings = {});
using base_parser::display_help;
};
} // namespace v2