From 0676f3b1a8d5eee3d8cd3776f1910bb603ea8e43 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:29:41 +0100 Subject: [PATCH 01/13] Make all functions of ArgumentBase public --- include/argparse.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 26bbf08..eb57c16 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -916,7 +916,6 @@ namespace argparse return m_impl.get_nargs_option(); } - protected: auto get_default() const -> std::any const & { return m_impl.get_default(); From bee47a4f03aaf552cee14d1875821509a701ceeb Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:32:09 +0100 Subject: [PATCH 02/13] Add StoreAction class --- include/argparse.hpp | 101 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/include/argparse.hpp b/include/argparse.hpp index eb57c16..a806323 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1001,6 +1001,107 @@ namespace argparse ArgumentImpl m_impl; }; + class StoreAction + { + public: + StoreAction(ArgumentBase & base, std::any & value) + : m_base(base) + , m_value(value) + { + } + + auto perform(std::string const & value, std::ranges::view auto tokens) const -> void + { + if (m_base.has_nargs()) + { + if (m_base.has_nargs_number()) + { + parse_arguments_number(tokens); + } + else + { + parse_arguments_option(tokens); + } + } + else + { + if (value.empty()) + { + m_value = m_base.consume_token(tokens.front()); + } + else + { + m_value = m_base.process_token(value); + } + } + } + + auto check_errors(std::string const & value, std::ranges::view auto tokens) const -> void + { + if (!m_base.has_nargs() && value.empty() && tokens.empty()) + { + throw parsing_error(std::format("argument {}: expected one argument", m_base.get_joined_names())); + } + } + + auto assign_non_present_value() const -> void + { + m_value = m_base.get_default(); + } + + private: + auto parse_arguments_number(std::ranges::view auto tokens) const -> void + { + auto const nargs_number = m_base.get_nargs_number(); + auto const values = m_base.consume_tokens(tokens | std::views::take(nargs_number)); + if (values.size() < nargs_number) + { + throw parsing_error(std::format("argument {}: expected {} argument{}", m_base.get_joined_names(), std::to_string(nargs_number), nargs_number > 1 ? "s" : "")); + } + m_value = m_base.get_transformed(values); + } + + auto parse_arguments_option(std::ranges::view auto tokens) const -> void + { + switch (m_base.get_nargs_option()) + { + case zero_or_one: + { + if (!tokens.empty()) + { + m_value = m_base.consume_token(tokens.front()); + } + else + { + m_value = m_base.get_const(); + } + break; + } + case zero_or_more: + { + m_value = m_base.parse_arguments(tokens); + break; + } + case one_or_more: + { + if (auto const values = m_base.consume_tokens(tokens); !values.empty()) + { + m_value = m_base.get_transformed(values); + } + else + { + throw parsing_error(std::format("argument {}: expected at least one argument", m_base.get_joined_names())); + } + break; + } + } + } + + private: + ArgumentBase & m_base; + std::any & m_value; + }; + class PositionalArgument final : public ArgumentBase { private: From 7711dd8c33ffe81a00d879e107739fef04698c58 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:32:51 +0100 Subject: [PATCH 03/13] Add StoreConstAction class --- include/argparse.hpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/argparse.hpp b/include/argparse.hpp index a806323..ae58dea 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1102,6 +1102,38 @@ namespace argparse std::any & m_value; }; + class StoreConstAction + { + public: + StoreConstAction(ArgumentBase & base, std::any & value) + : m_base(base) + , m_value(value) + { + } + + auto perform(std::string const & /* value */, std::ranges::view auto /* tokens */) const -> void + { + m_value = m_base.get_const(); + } + + auto check_errors(std::string const & value, std::ranges::view auto /* tokens */) const -> void + { + if (!value.empty()) + { + throw parsing_error(std::format("argument {}: ignored explicit argument '{}'", m_base.get_joined_names(), value)); + } + } + + auto assign_non_present_value() const -> void + { + m_value = m_base.get_default(); + } + + private: + ArgumentBase & m_base; + std::any & m_value; + }; + class PositionalArgument final : public ArgumentBase { private: From d6574b24de026580fa19bd3b476d39076807b7cb Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:33:22 +0100 Subject: [PATCH 04/13] Add StoreTrueAction class --- include/argparse.hpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/argparse.hpp b/include/argparse.hpp index ae58dea..a6089c4 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1134,6 +1134,38 @@ namespace argparse std::any & m_value; }; + class StoreTrueAction + { + public: + StoreTrueAction(ArgumentBase & base, std::any & value) + : m_base(base) + , m_value(value) + { + } + + auto perform(std::string const & /* value */, std::ranges::view auto /* tokens */) const -> void + { + m_value = true; + } + + auto check_errors(std::string const & value, std::ranges::view auto /* tokens */) const -> void + { + if (!value.empty()) + { + throw parsing_error(std::format("argument {}: ignored explicit argument '{}'", m_base.get_joined_names(), value)); + } + } + + auto assign_non_present_value() const -> void + { + m_value = false; + } + + private: + ArgumentBase & m_base; + std::any & m_value; + }; + class PositionalArgument final : public ArgumentBase { private: From 7d677d6749294e2b893182c9606e328737ecccf4 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:33:58 +0100 Subject: [PATCH 05/13] Add StoreFalseAction class --- include/argparse.hpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/include/argparse.hpp b/include/argparse.hpp index a6089c4..b71f61f 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1166,6 +1166,38 @@ namespace argparse std::any & m_value; }; + class StoreFalseAction + { + public: + StoreFalseAction(ArgumentBase & base, std::any & value) + : m_base(base) + , m_value(value) + { + } + + auto perform(std::string const & /* value */, std::ranges::view auto /* tokens */) const -> void + { + m_value = false; + } + + auto check_errors(std::string const & value, std::ranges::view auto /* tokens */) const -> void + { + if (!value.empty()) + { + throw parsing_error(std::format("argument {}: ignored explicit argument '{}'", m_base.get_joined_names(), value)); + } + } + + auto assign_non_present_value() const -> void + { + m_value = true; + } + + private: + ArgumentBase & m_base; + std::any & m_value; + }; + class PositionalArgument final : public ArgumentBase { private: From 35fb927998256e4c9deeddcf3fb87296e5cd18ee Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:34:24 +0100 Subject: [PATCH 06/13] Add HelpAction class --- include/argparse.hpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/argparse.hpp b/include/argparse.hpp index b71f61f..f676b77 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1198,6 +1198,33 @@ namespace argparse std::any & m_value; }; + class HelpAction + { + public: + explicit HelpAction(std::any & value) + : m_value(value) + { + } + + auto perform(std::string const & /* value */, std::ranges::view auto /* tokens */) const -> void + { + m_value = true; + throw HelpRequested(); + } + + auto check_errors(std::string const & /* value */, std::ranges::view auto /* tokens */) const -> void + { + } + + auto assign_non_present_value() const -> void + { + m_value = false; + } + + private: + std::any & m_value; + }; + class PositionalArgument final : public ArgumentBase { private: From a024ec4a262441d9cb90d12fb9fe5caaac14d95a Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:34:49 +0100 Subject: [PATCH 07/13] Add VersionAction class --- include/argparse.hpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/argparse.hpp b/include/argparse.hpp index f676b77..c8baa6f 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1225,6 +1225,33 @@ namespace argparse std::any & m_value; }; + class VersionAction + { + public: + explicit VersionAction(std::any & value) + : m_value(value) + { + } + + auto perform(std::string const & /* value */, std::ranges::view auto /* tokens */) const -> void + { + m_value = true; + throw VersionRequested(); + } + + auto check_errors(std::string const & /* value */, std::ranges::view auto /* tokens */) const -> void + { + } + + auto assign_non_present_value() const -> void + { + m_value = false; + } + + private: + std::any & m_value; + }; + class PositionalArgument final : public ArgumentBase { private: From d5629c0de8e55cff9fc4b3bdc22338b9682d78be Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:35:15 +0100 Subject: [PATCH 08/13] Add CountAction class --- include/argparse.hpp | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/include/argparse.hpp b/include/argparse.hpp index c8baa6f..73567cb 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1252,6 +1252,46 @@ namespace argparse std::any & m_value; }; + class CountAction + { + public: + CountAction(ArgumentBase & base, std::any & value) + : m_base(base) + , m_value(value) + { + } + + auto perform(std::string const & /* value */, std::ranges::view auto /* tokens */) const -> void + { + if (!m_value.has_value()) + { + m_value = 1; + } + else + { + ++std::any_cast(m_value); + } + } + + auto check_errors(std::string const & value, std::ranges::view auto /* tokens */) const -> void + { + if (!value.empty()) + { + throw parsing_error(std::format("argument {}: ignored explicit argument '{}'", m_base.get_joined_names(), value)); + } + } + + auto assign_non_present_value() const -> void + { + m_value = m_base.get_default(); + } + + private: + ArgumentBase & m_base; + std::any & m_value; + std::any m_default; + }; + class PositionalArgument final : public ArgumentBase { private: From f9283975e9e439595cd4ec1c7c9aa7c2e2bb5421 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:35:41 +0100 Subject: [PATCH 09/13] Add AppendAction class --- include/argparse.hpp | 58 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/include/argparse.hpp b/include/argparse.hpp index 73567cb..944ba06 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1292,6 +1292,64 @@ namespace argparse std::any m_default; }; + class AppendAction + { + public: + AppendAction(ArgumentBase & base, std::any & value) + : m_base(base) + , m_value(value) + { + } + + auto perform(std::string const & value, std::ranges::view auto tokens) const -> void + { + if (value.empty()) + { + if (!m_value.has_value()) + { + auto const values = m_base.consume_tokens(tokens | std::views::take(1)); + m_value = m_base.get_transformed(values); + } + else + { + auto const val = m_base.consume_token(tokens.front()); + m_base.append_value(val, m_value); + } + } + else + { + if (!m_value.has_value()) + { + auto const values = m_base.consume_tokens(std::views::single(Token{value})); + m_value = m_base.get_transformed(values); + } + else + { + auto const val = m_base.process_token(value); + m_base.append_value(val, m_value); + } + } + } + + auto check_errors(std::string const & value, std::ranges::view auto tokens) const -> void + { + if (value.empty() && tokens.empty()) + { + throw parsing_error(std::format("argument {}: expected one argument", m_base.get_joined_names())); + } + } + + auto assign_non_present_value() const -> void + { + m_value = m_base.get_default(); + } + + private: + ArgumentBase & m_base; + std::any & m_value; + std::any m_default; + }; + class PositionalArgument final : public ArgumentBase { private: From 7a46c5d671a84b4aaf7eeab9a0a5941a5f0760f4 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:37:17 +0100 Subject: [PATCH 10/13] Add creating action --- include/argparse.hpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/argparse.hpp b/include/argparse.hpp index 944ba06..c18c2af 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1801,13 +1801,40 @@ namespace argparse }); } + auto create_action() -> std::variant + { + switch (get_action()) + { + case store: + return StoreAction(*this, m_value); + case store_true: + return StoreTrueAction(*this, m_value); + case store_false: + return StoreFalseAction(*this, m_value); + case store_const: + return StoreConstAction(*this, m_value); + case help: + return HelpAction(m_value); + case version: + return VersionAction(m_value); + case count: + return CountAction(*this, m_value); + case append: + return AppendAction(*this, m_value); + default: + return StoreAction(*this, m_value); + } + } + private: std::any m_value; bool m_present = false; + std::variant m_action; public: explicit OptionalArgument(Options options) : ArgumentBase(std::move(options)) + , m_action(create_action()) { } From 0a546ac64a35086032f619a9733546617014bdc5 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:37:57 +0100 Subject: [PATCH 11/13] Use action --- include/argparse.hpp | 128 +------------------------------------------ 1 file changed, 1 insertion(+), 127 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index c18c2af..6b201f8 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1504,133 +1504,7 @@ namespace argparse private: auto perform_action(std::string const & value, std::ranges::view auto tokens) -> void { - switch (get_action()) - { - case store: - if (has_nargs()) - { - if (has_nargs_number()) - { - parse_arguments_number(tokens); - } - else - { - parse_arguments_option(tokens); - } - } - else - { - if (value.empty()) - { - m_value = consume_token(tokens.front()); - } - else - { - m_value = process_token(value); - } - } - break; - case store_true: - m_value = true; - break; - case store_false: - m_value = false; - break; - case store_const: - m_value = get_const(); - break; - case count: - if (!m_value.has_value()) - { - m_value = 1; - } - else - { - ++std::any_cast(m_value); - } - break; - case append: - if (value.empty()) - { - if (!m_value.has_value()) - { - auto const values = consume_tokens(tokens | std::views::take(1)); - m_value = get_transformed(values); - } - else - { - auto const val = consume_token(tokens.front()); - append_value(val, m_value); - } - } - else - { - if (!m_value.has_value()) - { - auto const values = consume_tokens(std::views::single(Token{value})); - m_value = get_transformed(values); - } - else - { - auto const val = process_token(value); - append_value(val, m_value); - } - } - break; - case help: - m_value = true; - throw HelpRequested(); - case version: - m_value = true; - throw VersionRequested(); - } - } - - auto parse_arguments_number(std::ranges::view auto tokens) -> void - { - auto const nargs_number = get_nargs_number(); - auto const values = consume_tokens(tokens | std::views::take(nargs_number)); - if (values.size() < nargs_number) - { - throw parsing_error(std::format("argument {}: expected {} argument{}", get_joined_names(), std::to_string(nargs_number), nargs_number > 1 ? "s" : "")); - } - m_value = get_transformed(values); - } - - auto parse_arguments_option(std::ranges::view auto tokens) -> void - { - switch (get_nargs_option()) - { - case zero_or_one: - { - if (!tokens.empty()) - { - m_value = consume_token(tokens.front()); - } - else - { - m_value = get_const(); - } - break; - } - case zero_or_more: - { - m_value = parse_arguments(tokens); - break; - } - case one_or_more: - { - if (auto const values = consume_tokens(tokens); !values.empty()) - { - m_value = get_transformed(values); - } - else - { - throw parsing_error(std::format("argument {}: expected at least one argument", get_joined_names())); - } - break; - } - } + std::visit([&](auto const & action) { action.perform(value, tokens); }, m_action); } auto has_arg(auto it) const -> std::string_view From 7d7f9a736e43a47ffe0244aa7d014e860409cb65 Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:38:03 +0100 Subject: [PATCH 12/13] Use action --- include/argparse.hpp | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 6b201f8..0d720a1 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1601,33 +1601,7 @@ namespace argparse auto check_errors(std::string const & value, std::ranges::view auto tokens) const -> void { - switch (get_action()) - { - case store: - if (!has_nargs() && value.empty() && tokens.empty()) - { - throw parsing_error(std::format("argument {}: expected one argument", get_joined_names())); - } - break; - case store_true: - case store_false: - case store_const: - case count: - if (!value.empty()) - { - throw parsing_error(std::format("argument {}: ignored explicit argument '{}'", get_joined_names(), value)); - } - break; - case append: - if (value.empty() && tokens.empty()) - { - throw parsing_error(std::format("argument {}: expected one argument", get_joined_names())); - } - break; - case help: - case version: - break; - } + std::visit([&](auto const & action) { action.check_errors(value, tokens); }, m_action); } auto assign_non_present_value() -> void From cf9223181d9fbb13c33ac1b825dcd055b1f3811a Mon Sep 17 00:00:00 2001 From: Krzysiek Karbowiak Date: Sun, 9 Nov 2025 22:38:07 +0100 Subject: [PATCH 13/13] Use action --- include/argparse.hpp | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 0d720a1..30ac958 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -1606,23 +1606,7 @@ namespace argparse auto assign_non_present_value() -> void { - switch (get_action()) - { - case store_true: - case help: - case version: - m_value = false; - break; - case store_false: - m_value = true; - break; - case store: - case store_const: - case count: - case append: - m_value = get_default(); - break; - } + std::visit([&](auto const & action) { action.assign_non_present_value(); }, m_action); } static auto get_consumable(Tokens & tokens)