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:
@@ -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