mirror of
https://github.com/sametersoylu/argument-parser.git
synced 2026-05-28 20:08:10 +00:00
feat: accumulate to int.
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
#include <vector>
|
||||
#include <windows_argument_convention.hpp>
|
||||
|
||||
using argument = argument_parser::builder::argument<>;
|
||||
using argument_parser::builder::new_argument;
|
||||
|
||||
using argument_parser::parsing_traits::hint_type;
|
||||
|
||||
@@ -42,9 +42,9 @@ template <typename T> struct parser_trait<std::vector<T>> {
|
||||
using namespace argument_parser::v2::flags;
|
||||
|
||||
auto main() -> int {
|
||||
argument_parser::v2::parser parser(false);
|
||||
argument_parser::v2::parser parser(true);
|
||||
|
||||
argument::start()
|
||||
start()
|
||||
.positional("count")
|
||||
.position(1)
|
||||
.help_text("How many times to repeat the action.")
|
||||
@@ -52,13 +52,13 @@ auto main() -> int {
|
||||
.build(parser);
|
||||
|
||||
int captured_value = 0;
|
||||
argument::start()
|
||||
new_argument()
|
||||
.long_argument("threshold")
|
||||
.help_text("Store the parsed value through a reference.")
|
||||
.reference(captured_value)
|
||||
.build(parser);
|
||||
|
||||
argument::start()
|
||||
new_argument()
|
||||
.positional("captured")
|
||||
.position(0)
|
||||
.help_text("Store the parsed value through a reference.")
|
||||
@@ -71,7 +71,7 @@ auto main() -> int {
|
||||
// {Reference, &captured_value},
|
||||
// });
|
||||
|
||||
argument::start().short_argument("q").help_text("Store a boolean flag.").build(parser);
|
||||
new_argument().short_argument("q").help_text("Store a boolean flag.").build(parser);
|
||||
|
||||
// argument::start()
|
||||
// .long_argument("regex")
|
||||
@@ -79,14 +79,14 @@ auto main() -> int {
|
||||
// .store<std::optional<std::regex>>()
|
||||
// .build(parser);
|
||||
|
||||
argument::start()
|
||||
new_argument()
|
||||
.short_argument("e")
|
||||
.long_argument("echo")
|
||||
.help_text("Echo the parsed value.")
|
||||
.action(echo)
|
||||
.build(parser);
|
||||
|
||||
argument::start()
|
||||
new_argument()
|
||||
.long_argument("vecstr")
|
||||
.short_argument("vs")
|
||||
.action<std::vector<int>>([](std::vector<int> const &vecstr) {
|
||||
@@ -96,8 +96,14 @@ auto main() -> int {
|
||||
})
|
||||
.build(parser);
|
||||
|
||||
auto accumulated_pos = new_argument()
|
||||
.short_argument("v")
|
||||
.help_text("turns on verbose execution. up to three levels of verbosity.")
|
||||
.count()
|
||||
.build_and_get(parser);
|
||||
|
||||
auto accumulate_vec =
|
||||
argument::start().long_argument("vecstr1").short_argument("vs1").accumulate<int>().build_and_get(parser);
|
||||
new_argument().long_argument("vecstr1").short_argument("vs1").accumulate<int>().build_and_get(parser);
|
||||
|
||||
parser.add_argument<std::vector<int>>({
|
||||
{LongArgument, "accumulate"},
|
||||
@@ -152,5 +158,9 @@ auto main() -> int {
|
||||
}
|
||||
}
|
||||
|
||||
if (accumulated_pos) {
|
||||
std::cout << "accumulated_pos: " << *accumulated_pos << '\n';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include <parser_v2.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef ARGUMENT_PARSER_PARSER_V3_HPP
|
||||
#define ARGUMENT_PARSER_PARSER_V3_HPP
|
||||
#ifndef ARGUMENT_PARSER_PARSER_BUILDER_HPP
|
||||
#define ARGUMENT_PARSER_PARSER_BUILDER_HPP
|
||||
|
||||
namespace argument_parser::builder {
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace argument_parser::builder {
|
||||
flag,
|
||||
reference,
|
||||
accumulate,
|
||||
count,
|
||||
nonparametered_action,
|
||||
parametered_action
|
||||
};
|
||||
@@ -44,12 +45,17 @@ namespace argument_parser::builder {
|
||||
constexpr mask_type required = bit(v2_flag::Required);
|
||||
constexpr mask_type reference = bit(v2_flag::Reference);
|
||||
constexpr mask_type accumulate = bit(v2_flag::Accumulate);
|
||||
constexpr mask_type count = bit(
|
||||
static_cast<v2_flag>(static_cast<int>(v2_flag::Accumulate) + (static_cast<int>(extra_capability::Store) |
|
||||
static_cast<int>(extra_capability::Flag))));
|
||||
constexpr mask_type store = bit(extra_capability::Store);
|
||||
constexpr mask_type flag = bit(extra_capability::Flag);
|
||||
|
||||
constexpr mask_type value_mode_group = action | reference | accumulate | store | flag;
|
||||
constexpr mask_type value_mode_group = action | reference | accumulate | count | store | flag;
|
||||
constexpr mask_type initial = short_argument | long_argument | positional | help_text | action | required |
|
||||
reference | accumulate | store | flag;
|
||||
reference | accumulate | count | store | flag;
|
||||
|
||||
constexpr mask_type storable_mode_group = (count | store | flag | accumulate | reference) >> 1;
|
||||
|
||||
constexpr auto has(mask_type mask, mask_type capability) -> bool {
|
||||
return (mask & capability) == capability;
|
||||
@@ -70,6 +76,10 @@ namespace argument_parser::builder {
|
||||
constexpr auto is_buildable(mask_type mask) -> bool {
|
||||
return has_selected_identifier(mask);
|
||||
}
|
||||
|
||||
constexpr auto is_build_and_gettable(mask_type mask) -> bool {
|
||||
return has_selected_identifier(mask) && has(mask, storable_mode_group);
|
||||
}
|
||||
} // namespace builder_mask
|
||||
|
||||
template <typename store_type> class container {
|
||||
@@ -158,7 +168,7 @@ namespace argument_parser::builder {
|
||||
using next_argument =
|
||||
argument<builder_mask::replace(current_mask,
|
||||
builder_mask::short_argument | builder_mask::long_argument |
|
||||
builder_mask::positional | builder_mask::flag,
|
||||
builder_mask::positional | builder_mask::flag | builder_mask::count,
|
||||
builder_mask::position),
|
||||
store_type>;
|
||||
|
||||
@@ -214,11 +224,13 @@ namespace argument_parser::builder {
|
||||
|
||||
template <typename T = std::string, mask_type current_mask = mask,
|
||||
std::enable_if_t<builder_mask::has(current_mask, builder_mask::accumulate), int> = 0>
|
||||
auto accumulate() const
|
||||
-> argument<builder_mask::remove(current_mask, builder_mask::value_mode_group), std::vector<T>> {
|
||||
auto accumulate() const -> argument<builder_mask::replace(current_mask, builder_mask::value_mode_group,
|
||||
builder_mask::storable_mode_group),
|
||||
std::vector<T>> {
|
||||
using vector_type = std::vector<T>;
|
||||
using next_argument =
|
||||
argument<builder_mask::remove(current_mask, builder_mask::value_mode_group), vector_type>;
|
||||
using next_argument = argument<builder_mask::replace(current_mask, builder_mask::value_mode_group,
|
||||
builder_mask::storable_mode_group),
|
||||
vector_type>;
|
||||
|
||||
next_argument next{*this};
|
||||
next.m_value_mode = value_mode::accumulate;
|
||||
@@ -227,12 +239,14 @@ namespace argument_parser::builder {
|
||||
|
||||
template <mask_type current_mask = mask,
|
||||
std::enable_if_t<builder_mask::has(current_mask, builder_mask::accumulate), int> = 0, typename T>
|
||||
auto accumulate(T &value) const
|
||||
-> argument<builder_mask::remove(current_mask, builder_mask::value_mode_group), T> {
|
||||
auto accumulate(T &value) const -> argument<
|
||||
builder_mask::replace(current_mask, builder_mask::value_mode_group, builder_mask::storable_mode_group), T> {
|
||||
static_assert(argument_parser::v2::deducers::is_vector_v<T>,
|
||||
"accumulate(target) requires a std::vector target.");
|
||||
|
||||
using next_argument = argument<builder_mask::remove(current_mask, builder_mask::value_mode_group), T>;
|
||||
using next_argument = argument<builder_mask::replace(current_mask, builder_mask::value_mode_group,
|
||||
builder_mask::storable_mode_group),
|
||||
T>;
|
||||
|
||||
next_argument next{*this};
|
||||
next.m_reference = std::addressof(value);
|
||||
@@ -240,10 +254,44 @@ namespace argument_parser::builder {
|
||||
return next;
|
||||
}
|
||||
|
||||
template <mask_type current_mask = mask,
|
||||
std::enable_if_t<builder_mask::has(current_mask, builder_mask::count), int> = 0>
|
||||
auto count() const -> argument<builder_mask::replace(current_mask, builder_mask::value_mode_group,
|
||||
builder_mask::storable_mode_group),
|
||||
int> {
|
||||
using next_argument = argument<builder_mask::replace(current_mask, builder_mask::value_mode_group,
|
||||
builder_mask::storable_mode_group),
|
||||
int>;
|
||||
|
||||
next_argument next{*this};
|
||||
next.m_value_mode = value_mode::count;
|
||||
return next;
|
||||
}
|
||||
|
||||
template <mask_type current_mask = mask,
|
||||
std::enable_if_t<builder_mask::has(current_mask, builder_mask::count), int> = 0>
|
||||
auto count(int &value) const -> argument<builder_mask::replace(current_mask, builder_mask::value_mode_group,
|
||||
builder_mask::storable_mode_group),
|
||||
int> {
|
||||
|
||||
using next_argument = argument<builder_mask::replace(current_mask, builder_mask::value_mode_group,
|
||||
builder_mask::storable_mode_group),
|
||||
int>;
|
||||
|
||||
next_argument next{*this};
|
||||
next.m_reference = std::addressof(value);
|
||||
next.m_value_mode = value_mode::count;
|
||||
return next;
|
||||
}
|
||||
|
||||
template <mask_type current_mask = mask,
|
||||
std::enable_if_t<builder_mask::has(current_mask, builder_mask::flag), int> = 0>
|
||||
auto flag() const -> argument<builder_mask::remove(current_mask, builder_mask::value_mode_group), bool> {
|
||||
using next_argument = argument<builder_mask::remove(current_mask, builder_mask::value_mode_group), bool>;
|
||||
auto flag() const -> argument<builder_mask::replace(current_mask, builder_mask::value_mode_group,
|
||||
builder_mask::storable_mode_group),
|
||||
bool> {
|
||||
using next_argument = argument<builder_mask::replace(current_mask, builder_mask::value_mode_group,
|
||||
builder_mask::storable_mode_group),
|
||||
bool>;
|
||||
|
||||
next_argument next{*this};
|
||||
next.m_value_mode = value_mode::flag;
|
||||
@@ -252,9 +300,11 @@ namespace argument_parser::builder {
|
||||
|
||||
template <mask_type current_mask = mask,
|
||||
std::enable_if_t<builder_mask::has(current_mask, builder_mask::reference), int> = 0, typename T>
|
||||
auto reference(T &value) const
|
||||
-> argument<builder_mask::remove(current_mask, builder_mask::value_mode_group), T> {
|
||||
using next_argument = argument<builder_mask::remove(current_mask, builder_mask::value_mode_group), T>;
|
||||
auto reference(T &value) const -> argument<
|
||||
builder_mask::replace(current_mask, builder_mask::value_mode_group, builder_mask::storable_mode_group), T> {
|
||||
using next_argument = argument<builder_mask::replace(current_mask, builder_mask::value_mode_group,
|
||||
builder_mask::storable_mode_group),
|
||||
T>;
|
||||
|
||||
next_argument next{*this};
|
||||
next.m_reference = std::addressof(value);
|
||||
@@ -318,6 +368,7 @@ namespace argument_parser::builder {
|
||||
}
|
||||
break;
|
||||
case value_mode::accumulate:
|
||||
case value_mode::count:
|
||||
if constexpr (!std::is_same_v<store_type, non_type>) {
|
||||
build_accumulate(parser);
|
||||
return;
|
||||
@@ -341,7 +392,8 @@ namespace argument_parser::builder {
|
||||
throw std::logic_error("The builder reached build() without a supported terminal value mode.");
|
||||
}
|
||||
|
||||
template <mask_type current_mask = mask, std::enable_if_t<builder_mask::is_buildable(current_mask), int> = 0>
|
||||
template <mask_type current_mask = mask,
|
||||
std::enable_if_t<builder_mask::is_build_and_gettable(current_mask), int> = 0>
|
||||
auto build_and_get(argument_parser::v2::base_parser &parser) const -> container<store_type> {
|
||||
assert_has_identifier();
|
||||
switch (m_value_mode) {
|
||||
@@ -349,6 +401,7 @@ namespace argument_parser::builder {
|
||||
case value_mode::flag:
|
||||
case value_mode::unresolved:
|
||||
case value_mode::accumulate:
|
||||
case value_mode::count:
|
||||
build(parser);
|
||||
break;
|
||||
default:
|
||||
@@ -380,9 +433,7 @@ namespace argument_parser::builder {
|
||||
m_required(other.m_required), m_action(other.m_action), m_reference(copy_reference(other.m_reference)),
|
||||
m_value_mode(other.m_value_mode) {}
|
||||
|
||||
template <typename T>
|
||||
using typed_map =
|
||||
std::unordered_map<v2_flag, v2::base_parser::typed_flag_value<T>>;
|
||||
template <typename T> using typed_map = std::unordered_map<v2_flag, v2::base_parser::typed_flag_value<T>>;
|
||||
|
||||
using non_typed_map = std::unordered_map<v2_flag, v2::base_parser::non_typed_flag_value>;
|
||||
|
||||
@@ -538,6 +589,10 @@ namespace argument_parser::builder {
|
||||
template <mask_type other_mask, typename other_store_type> friend class argument;
|
||||
};
|
||||
|
||||
static inline auto new_argument() {
|
||||
return argument<>::start();
|
||||
}
|
||||
|
||||
namespace assertions {
|
||||
struct noop_handler {
|
||||
void operator()() const {}
|
||||
|
||||
@@ -195,8 +195,10 @@ namespace argument_parser::v2 {
|
||||
found_params[extended_add_argument_flags::Action] = true;
|
||||
accumulates = true;
|
||||
if constexpr (!std::is_same_v<T, void>) {
|
||||
if constexpr (!deducers::is_vector_v<T>) {
|
||||
throw std::logic_error("Expected vector (type does not have value_type member)");
|
||||
if constexpr (std::is_same_v<T, int>) {
|
||||
action = make_accumulate_action<T>(argument_pairs, ref_mode, short_arg, long_arg);
|
||||
} else if constexpr (!deducers::is_vector_v<T>) {
|
||||
throw std::logic_error("Expected vector or integer type");
|
||||
} else {
|
||||
if (action && !ref_mode) {
|
||||
throw std::logic_error("Cannot use both action and accumulate for the same argument");
|
||||
@@ -454,10 +456,14 @@ namespace argument_parser::v2 {
|
||||
}
|
||||
|
||||
template <typename Vector> std::unique_ptr<action_base> make_accumulate_ref_action(Vector *target) {
|
||||
using Value = typename Vector::value_type;
|
||||
return helpers::make_parametered_action<Value>(
|
||||
[target](Value const &value) { target->emplace_back(value); })
|
||||
.clone();
|
||||
if constexpr (std::is_same_v<Vector, int>) {
|
||||
return helpers::make_non_parametered_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); })
|
||||
.clone();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Vector>
|
||||
@@ -466,8 +472,14 @@ namespace argument_parser::v2 {
|
||||
on_complete(
|
||||
[this, short_arg = std::move(short_arg), long_arg = std::move(long_arg),
|
||||
accumulation_target](auto const &) {
|
||||
if (accumulation_target->empty()) {
|
||||
return;
|
||||
if constexpr (std::is_same_v<int, Vector>) {
|
||||
if (*accumulation_target == 0) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (accumulation_target->empty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const auto sid = this->find_argument_id(short_arg);
|
||||
@@ -484,8 +496,14 @@ namespace argument_parser::v2 {
|
||||
void store_accumulated_on_complete(std::string positional_name, std::shared_ptr<Vector> accumulation_target) {
|
||||
on_complete(
|
||||
[this, positional_name = std::move(positional_name), accumulation_target](auto const &) {
|
||||
if (accumulation_target->empty()) {
|
||||
return;
|
||||
if constexpr (std::is_same_v<int, Vector>) {
|
||||
if (*accumulation_target == 0) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (accumulation_target->empty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto id = this->find_argument_id(positional_name);
|
||||
|
||||
@@ -130,11 +130,17 @@ namespace argument_parser {
|
||||
auto name_it = reverse_positional_names.find(pos_id);
|
||||
if (name_it == reverse_positional_names.end())
|
||||
continue;
|
||||
if (auto const &arg = argument_map.at(pos_id); arg.is_required()) {
|
||||
|
||||
auto const &arg = argument_map.at(pos_id);
|
||||
if (arg.is_required()) {
|
||||
ss << " <" << name_it->second << ">";
|
||||
} else {
|
||||
ss << " [" << name_it->second << "]";
|
||||
}
|
||||
|
||||
if (arg.is_positional_accumulator()) {
|
||||
ss << "...";
|
||||
}
|
||||
}
|
||||
ss << "\n";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user