mirror of
https://github.com/sametersoylu/argument-parser.git
synced 2026-04-13 03:41:18 +00:00
chore: clean up c++20/23 features to move to 17.
This commit is contained in:
@@ -1,10 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <argument_parser.hpp>
|
#include <argument_parser.hpp>
|
||||||
|
#include <array>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <exception>
|
|
||||||
#include <fake_parser.hpp>
|
#include <fake_parser.hpp>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <iostream>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
@@ -15,235 +14,230 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace argument_parser::v2 {
|
namespace argument_parser::v2 {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
static inline fake_parser fake_parser{};
|
static inline fake_parser fake_parser{};
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class add_argument_flags {
|
enum class add_argument_flags { ShortArgument, LongArgument, HelpText, Action, Required };
|
||||||
ShortArgument,
|
|
||||||
LongArgument,
|
|
||||||
HelpText,
|
|
||||||
Action,
|
|
||||||
Required
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace flags {
|
namespace flags {
|
||||||
constexpr static inline add_argument_flags ShortArgument = add_argument_flags::ShortArgument;
|
constexpr static inline add_argument_flags ShortArgument = add_argument_flags::ShortArgument;
|
||||||
constexpr static inline add_argument_flags LongArgument = add_argument_flags::LongArgument;
|
constexpr static inline add_argument_flags LongArgument = add_argument_flags::LongArgument;
|
||||||
constexpr static inline add_argument_flags HelpText = add_argument_flags::HelpText;
|
constexpr static inline add_argument_flags HelpText = add_argument_flags::HelpText;
|
||||||
constexpr static inline add_argument_flags Action = add_argument_flags::Action;
|
constexpr static inline add_argument_flags Action = add_argument_flags::Action;
|
||||||
constexpr static inline add_argument_flags Required = add_argument_flags::Required;
|
constexpr static inline add_argument_flags Required = add_argument_flags::Required;
|
||||||
}
|
} // namespace flags
|
||||||
|
|
||||||
class base_parser : private argument_parser::base_parser {
|
class base_parser : private argument_parser::base_parser {
|
||||||
public:
|
public:
|
||||||
template<typename T>
|
template <typename T> using typed_flag_value = std::variant<std::string, parametered_action<T>, bool>;
|
||||||
using typed_flag_value = std::variant<std::string, parametered_action<T>, bool>;
|
using non_typed_flag_value = std::variant<std::string, non_parametered_action, bool>;
|
||||||
using non_typed_flag_value = std::variant<std::string, non_parametered_action, bool>;
|
|
||||||
|
|
||||||
template<typename T>
|
template <typename T> using typed_argument_pair = std::pair<add_argument_flags, typed_flag_value<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>;
|
||||||
using non_typed_argument_pair = std::pair<add_argument_flags, non_typed_flag_value>;
|
|
||||||
|
|
||||||
template<typename T>
|
template <typename T>
|
||||||
void add_argument(std::unordered_map<add_argument_flags, typed_flag_value<T>> const& argument_pairs) {
|
void add_argument(std::unordered_map<add_argument_flags, typed_flag_value<T>> const &argument_pairs) {
|
||||||
std::unordered_map<extended_add_argument_flags, bool> found_params {{
|
std::unordered_map<extended_add_argument_flags, bool> found_params{
|
||||||
extended_add_argument_flags::IsTyped, true
|
{extended_add_argument_flags::IsTyped, true}};
|
||||||
}};
|
|
||||||
|
|
||||||
std::string short_arg, long_arg, help_text;
|
std::string short_arg, long_arg, help_text;
|
||||||
std::unique_ptr<action_base> action;
|
std::unique_ptr<action_base> action;
|
||||||
bool required = false;
|
bool required = false;
|
||||||
|
|
||||||
if (argument_pairs.contains(add_argument_flags::ShortArgument)) {
|
if (argument_pairs.contains(add_argument_flags::ShortArgument)) {
|
||||||
found_params[extended_add_argument_flags::ShortArgument] = true;
|
found_params[extended_add_argument_flags::ShortArgument] = true;
|
||||||
short_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::ShortArgument), "short");
|
short_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::ShortArgument), "short");
|
||||||
}
|
}
|
||||||
if (argument_pairs.contains(add_argument_flags::LongArgument)) {
|
if (argument_pairs.contains(add_argument_flags::LongArgument)) {
|
||||||
found_params[extended_add_argument_flags::LongArgument] = true;
|
found_params[extended_add_argument_flags::LongArgument] = true;
|
||||||
long_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::LongArgument), "long");
|
long_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::LongArgument), "long");
|
||||||
if (short_arg.empty()) short_arg = long_arg;
|
if (short_arg.empty())
|
||||||
} else {
|
short_arg = long_arg;
|
||||||
if (!short_arg.empty()) long_arg = short_arg;
|
} else {
|
||||||
}
|
if (!short_arg.empty())
|
||||||
|
long_arg = short_arg;
|
||||||
|
}
|
||||||
|
|
||||||
if (argument_pairs.contains(add_argument_flags::Action)) {
|
if (argument_pairs.contains(add_argument_flags::Action)) {
|
||||||
found_params[extended_add_argument_flags::Action] = true;
|
found_params[extended_add_argument_flags::Action] = true;
|
||||||
action = get_or_throw<parametered_action<T>>(argument_pairs.at(add_argument_flags::Action), "action").clone();
|
action = get_or_throw<parametered_action<T>>(argument_pairs.at(add_argument_flags::Action), "action")
|
||||||
}
|
.clone();
|
||||||
if (argument_pairs.contains(add_argument_flags::HelpText)) {
|
}
|
||||||
help_text = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::HelpText), "help");
|
if (argument_pairs.contains(add_argument_flags::HelpText)) {
|
||||||
} else {
|
help_text = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::HelpText), "help");
|
||||||
help_text = short_arg + ", " + long_arg;
|
} else {
|
||||||
}
|
help_text = short_arg + ", " + long_arg;
|
||||||
if (argument_pairs.contains(add_argument_flags::Required) && get_or_throw<bool>(argument_pairs.at(add_argument_flags::Required), "required")) {
|
}
|
||||||
required = true;
|
if (argument_pairs.contains(add_argument_flags::Required) &&
|
||||||
}
|
get_or_throw<bool>(argument_pairs.at(add_argument_flags::Required), "required")) {
|
||||||
|
required = true;
|
||||||
|
}
|
||||||
|
|
||||||
auto suggested_add = suggest_candidate(found_params);
|
auto suggested_add = suggest_candidate(found_params);
|
||||||
if (suggested_add == candidate_type::unknown) {
|
if (suggested_add == candidate_type::unknown) {
|
||||||
throw std::runtime_error("Could not match any add argument overload to given parameters. Are you missing some required parameter?");
|
throw std::runtime_error("Could not match any add argument overload to given parameters. Are you "
|
||||||
}
|
"missing some required parameter?");
|
||||||
switch (suggested_add) {
|
}
|
||||||
case candidate_type::typed_action:
|
switch (suggested_add) {
|
||||||
base::add_argument(short_arg, long_arg, help_text, *static_cast<parametered_action<T>*>(&(*action)), required);
|
case candidate_type::typed_action:
|
||||||
break;
|
base::add_argument(short_arg, long_arg, help_text, *static_cast<parametered_action<T> *>(&(*action)),
|
||||||
case candidate_type::store_other:
|
required);
|
||||||
base::add_argument(short_arg, long_arg, help_text, required);
|
break;
|
||||||
break;
|
case candidate_type::store_other:
|
||||||
default:
|
base::add_argument(short_arg, long_arg, help_text, required);
|
||||||
throw std::runtime_error("Could not match the arguments against any overload.");
|
break;
|
||||||
}
|
default:
|
||||||
}
|
throw std::runtime_error("Could not match the arguments against any overload.");
|
||||||
|
}
|
||||||
template<typename T>
|
}
|
||||||
void add_argument(std::initializer_list<typed_argument_pair<T>> const& pairs) {
|
|
||||||
std::unordered_map<add_argument_flags, typed_flag_value<T>> args;
|
|
||||||
|
|
||||||
for (auto& [k, v]: pairs) {
|
template <typename T> void add_argument(std::initializer_list<typed_argument_pair<T>> const &pairs) {
|
||||||
args[k] = v;
|
std::unordered_map<add_argument_flags, typed_flag_value<T>> args;
|
||||||
}
|
|
||||||
|
|
||||||
add_argument<T>(args);
|
for (auto &[k, v] : pairs) {
|
||||||
}
|
args[k] = v;
|
||||||
|
}
|
||||||
|
|
||||||
void add_argument(std::initializer_list<non_typed_argument_pair> const& pairs) {
|
add_argument<T>(args);
|
||||||
std::unordered_map<add_argument_flags, non_typed_flag_value> args;
|
}
|
||||||
|
|
||||||
for (auto& [k, v] : pairs) {
|
|
||||||
args[k] = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
add_argument(args);
|
void add_argument(std::initializer_list<non_typed_argument_pair> const &pairs) {
|
||||||
}
|
std::unordered_map<add_argument_flags, non_typed_flag_value> args;
|
||||||
|
|
||||||
void add_argument(std::unordered_map<add_argument_flags, non_typed_flag_value> const& argument_pairs) {
|
for (auto &[k, v] : pairs) {
|
||||||
std::unordered_map<extended_add_argument_flags, bool> found_params {{
|
args[k] = v;
|
||||||
extended_add_argument_flags::IsTyped, false
|
}
|
||||||
}};
|
|
||||||
|
|
||||||
std::string short_arg, long_arg, help_text;
|
add_argument(args);
|
||||||
std::unique_ptr<action_base> action;
|
}
|
||||||
bool required = false;
|
|
||||||
|
|
||||||
if (argument_pairs.contains(add_argument_flags::ShortArgument)) {
|
void add_argument(std::unordered_map<add_argument_flags, non_typed_flag_value> const &argument_pairs) {
|
||||||
found_params[extended_add_argument_flags::ShortArgument] = true;
|
std::unordered_map<extended_add_argument_flags, bool> found_params{
|
||||||
short_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::ShortArgument), "short");
|
{extended_add_argument_flags::IsTyped, false}};
|
||||||
}
|
|
||||||
if (argument_pairs.contains(add_argument_flags::LongArgument)) {
|
|
||||||
found_params[extended_add_argument_flags::LongArgument] = true;
|
|
||||||
long_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::LongArgument), "long");
|
|
||||||
if (short_arg.empty()) short_arg = long_arg;
|
|
||||||
} else {
|
|
||||||
if (!short_arg.empty()) long_arg = short_arg;
|
|
||||||
}
|
|
||||||
if (argument_pairs.contains(add_argument_flags::Action)) {
|
|
||||||
found_params[extended_add_argument_flags::Action] = true;
|
|
||||||
action = get_or_throw<non_parametered_action>(argument_pairs.at(add_argument_flags::Action), "action").clone();
|
|
||||||
|
|
||||||
}
|
|
||||||
if (argument_pairs.contains(add_argument_flags::HelpText)) {
|
|
||||||
help_text = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::HelpText), "help");
|
|
||||||
} else {
|
|
||||||
help_text = short_arg + ", " + long_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (argument_pairs.contains(add_argument_flags::Required) && get_or_throw<bool>(argument_pairs.at(add_argument_flags::Required), "required")) {
|
std::string short_arg, long_arg, help_text;
|
||||||
required = true;
|
std::unique_ptr<action_base> action;
|
||||||
}
|
bool required = false;
|
||||||
|
|
||||||
auto suggested_add = suggest_candidate(found_params);
|
if (argument_pairs.find(add_argument_flags::ShortArgument) != argument_pairs.end()) {
|
||||||
if (suggested_add == candidate_type::unknown) {
|
found_params[extended_add_argument_flags::ShortArgument] = true;
|
||||||
throw std::runtime_error("Could not match any add argument overload to given parameters. Are you missing some required parameter?");
|
short_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::ShortArgument), "short");
|
||||||
}
|
}
|
||||||
|
if (argument_pairs.find(add_argument_flags::LongArgument) != argument_pairs.end()) {
|
||||||
|
found_params[extended_add_argument_flags::LongArgument] = true;
|
||||||
|
long_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::LongArgument), "long");
|
||||||
|
if (short_arg.empty())
|
||||||
|
short_arg = long_arg;
|
||||||
|
} else {
|
||||||
|
if (!short_arg.empty())
|
||||||
|
long_arg = short_arg;
|
||||||
|
}
|
||||||
|
if (argument_pairs.find(add_argument_flags::Action) != argument_pairs.end()) {
|
||||||
|
found_params[extended_add_argument_flags::Action] = true;
|
||||||
|
action = get_or_throw<non_parametered_action>(argument_pairs.at(add_argument_flags::Action), "action")
|
||||||
|
.clone();
|
||||||
|
}
|
||||||
|
if (argument_pairs.find(add_argument_flags::HelpText) != argument_pairs.end()) {
|
||||||
|
help_text = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::HelpText), "help");
|
||||||
|
} else {
|
||||||
|
help_text = short_arg + ", " + long_arg;
|
||||||
|
}
|
||||||
|
|
||||||
switch (suggested_add) {
|
if (argument_pairs.find(add_argument_flags::Required) != argument_pairs.end() &&
|
||||||
case candidate_type::non_typed_action:
|
get_or_throw<bool>(argument_pairs.at(add_argument_flags::Required), "required")) {
|
||||||
base::add_argument(short_arg, long_arg, help_text, *static_cast<non_parametered_action*>(&(*action)), required);
|
required = true;
|
||||||
break;
|
}
|
||||||
case candidate_type::store_boolean:
|
|
||||||
base::add_argument(short_arg, long_arg, help_text, required);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::runtime_error("Could not match the arguments against any overload. The suggested candidate was: " + std::to_string((int(suggested_add))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
argument_parser::base_parser& to_v1() {
|
auto suggested_add = suggest_candidate(found_params);
|
||||||
return *this;
|
if (suggested_add == candidate_type::unknown) {
|
||||||
}
|
throw std::runtime_error("Could not match any add argument overload to given parameters. Are you "
|
||||||
|
"missing some required parameter?");
|
||||||
|
}
|
||||||
|
|
||||||
void handle_arguments(std::initializer_list<conventions::convention const* const> convention_types) {
|
switch (suggested_add) {
|
||||||
base::handle_arguments(convention_types);
|
case candidate_type::non_typed_action:
|
||||||
}
|
base::add_argument(short_arg, long_arg, help_text, *static_cast<non_parametered_action *>(&(*action)),
|
||||||
|
required);
|
||||||
|
break;
|
||||||
|
case candidate_type::store_boolean:
|
||||||
|
base::add_argument(short_arg, long_arg, help_text, required);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw std::runtime_error(
|
||||||
|
"Could not match the arguments against any overload. The suggested candidate was: " +
|
||||||
|
std::to_string((int(suggested_add))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
argument_parser::base_parser &to_v1() {
|
||||||
std::optional<T> get_optional(std::string const& arg) {
|
return *this;
|
||||||
return base::get_optional<T>(arg);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void on_complete(std::function<void(argument_parser::base_parser const&)> const& action) {
|
void handle_arguments(std::initializer_list<conventions::convention const *const> convention_types) {
|
||||||
base::on_complete(action);
|
base::handle_arguments(convention_types);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
template <typename T> std::optional<T> get_optional(std::string const &arg) {
|
||||||
void set_program_name(std::string p) {
|
return base::get_optional<T>(arg);
|
||||||
base::program_name = std::move(p);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string>& ref_parsed_args() {
|
void on_complete(std::function<void(argument_parser::base_parser const &)> const &action) {
|
||||||
return base::parsed_arguments;
|
base::on_complete(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
using base = argument_parser::base_parser;
|
void set_program_name(std::string p) {
|
||||||
enum class extended_add_argument_flags {
|
base::program_name = std::move(p);
|
||||||
ShortArgument,
|
}
|
||||||
LongArgument,
|
|
||||||
Action,
|
|
||||||
IsTyped
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class candidate_type {
|
std::vector<std::string> &ref_parsed_args() {
|
||||||
store_boolean,
|
return base::parsed_arguments;
|
||||||
store_other,
|
}
|
||||||
typed_action,
|
|
||||||
non_typed_action,
|
|
||||||
unknown
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, size_t S>
|
private:
|
||||||
bool satisfies_at_least_one(std::array<T, S> const& arr, std::unordered_map<T, bool> const& map) {
|
using base = argument_parser::base_parser;
|
||||||
for (const auto& req: arr) {
|
enum class extended_add_argument_flags { ShortArgument, LongArgument, Action, IsTyped };
|
||||||
if (map.contains(req)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
candidate_type suggest_candidate(std::unordered_map<extended_add_argument_flags, bool> const& available_vars) {
|
enum class candidate_type { store_boolean, store_other, typed_action, non_typed_action, unknown };
|
||||||
auto constexpr required_at_least_one = std::array<extended_add_argument_flags, 2> { extended_add_argument_flags::ShortArgument, extended_add_argument_flags::LongArgument };
|
|
||||||
if (!satisfies_at_least_one(required_at_least_one, available_vars)) return candidate_type::unknown;
|
|
||||||
|
|
||||||
if (available_vars.contains(extended_add_argument_flags::Action)) {
|
|
||||||
if (available_vars.at(extended_add_argument_flags::IsTyped))
|
|
||||||
return candidate_type::typed_action;
|
|
||||||
else return candidate_type::non_typed_action;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (available_vars.at(extended_add_argument_flags::IsTyped)) return candidate_type::store_other;
|
|
||||||
return candidate_type::store_boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename I>
|
template <typename T, size_t S>
|
||||||
T get_or_throw(typed_flag_value<I> const& v, std::string_view key) {
|
bool satisfies_at_least_one(std::array<T, S> const &arr, std::unordered_map<T, bool> const &map) {
|
||||||
if (auto p = std::get_if<T>(&v)) return *p;
|
for (const auto &req : arr) {
|
||||||
throw std::invalid_argument(std::string("variant type mismatch for key: ") + std::string(key));
|
if (map.find(req) != map.end())
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
candidate_type suggest_candidate(std::unordered_map<extended_add_argument_flags, bool> const &available_vars) {
|
||||||
T get_or_throw(non_typed_flag_value const& v, std::string_view key) {
|
auto constexpr required_at_least_one = std::array<extended_add_argument_flags, 2>{
|
||||||
if (auto p = std::get_if<T>(&v)) return *p;
|
extended_add_argument_flags::ShortArgument, extended_add_argument_flags::LongArgument};
|
||||||
throw std::invalid_argument(std::string("variant type mismatch for key: ") + std::string(key));
|
if (!satisfies_at_least_one(required_at_least_one, available_vars))
|
||||||
}
|
return candidate_type::unknown;
|
||||||
};
|
|
||||||
}
|
if (available_vars.find(extended_add_argument_flags::Action) != available_vars.end()) {
|
||||||
|
if (available_vars.at(extended_add_argument_flags::IsTyped))
|
||||||
|
return candidate_type::typed_action;
|
||||||
|
else
|
||||||
|
return candidate_type::non_typed_action;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (available_vars.at(extended_add_argument_flags::IsTyped))
|
||||||
|
return candidate_type::store_other;
|
||||||
|
return candidate_type::store_boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename I> T get_or_throw(typed_flag_value<I> const &v, std::string_view key) {
|
||||||
|
if (auto p = std::get_if<T>(&v))
|
||||||
|
return *p;
|
||||||
|
throw std::invalid_argument(std::string("variant type mismatch for key: ") + std::string(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> T get_or_throw(non_typed_flag_value const &v, std::string_view key) {
|
||||||
|
if (auto p = std::get_if<T>(&v))
|
||||||
|
return *p;
|
||||||
|
throw std::invalid_argument(std::string("variant type mismatch for key: ") + std::string(key));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace argument_parser::v2
|
||||||
Reference in New Issue
Block a user