feat(parser): add argument value storage and retrieval

- Implement stored_arguments map to store argument values
- Add get_optional method to retrieve stored values
- Add helper methods for creating parametered and non-parametered actions
- Refactor argument adding logic into smaller methods
- Update main.cpp to demonstrate new storage functionality
This commit is contained in:
2025-10-06 04:06:16 +04:00
parent 9750152dca
commit 8437a00c6b
2 changed files with 83 additions and 17 deletions

View File

@@ -1,4 +1,6 @@
#pragma once
#include <optional>
#include <type_traits>
#ifndef ARGUMENT_PARSER_HPP
#define ARGUMENT_PARSER_HPP
@@ -14,6 +16,7 @@
#include <string>
#include <unordered_map>
#include <vector>
#include <any>
namespace argument_parser {
class action_base {
@@ -129,6 +132,17 @@ namespace argument_parser {
std::string help_text;
};
namespace helpers {
template<typename T>
static parametered_action<T> make_parametered_action(std::function<void(const T&)> const& function) {
return parametered_action<T>(function);
}
static non_parametered_action make_non_parametered_action(std::function<void()> const& function) {
return non_parametered_action(function);
}
}
class base_parser {
public:
template <typename T>
@@ -140,6 +154,22 @@ namespace argument_parser {
base_add_argument(short_arg, long_arg, help_text, action, required);
}
void add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, bool required) {
base_add_argument<void>(short_arg, long_arg, help_text, required);
}
template<typename T>
void add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, bool required) {
base_add_argument<T>(short_arg, long_arg, help_text, required);
}
template<typename T>
std::optional<T> get_optional(std::string const& arg) {
auto id = find_argument_id(arg);
if (id.has_value()) return std::any_cast<T>(stored_arguments[id.value()]);
return std::nullopt;
}
std::string build_help_text(std::initializer_list<conventions::convention const* const> convention_types) {
std::stringstream ss;
ss << "Usage: " << program_name << " [OPTIONS]...\n";
@@ -164,6 +194,15 @@ namespace argument_parser {
}
throw std::runtime_error("Unknown argument: " + arg.second);
}
std::optional<int> find_argument_id(std::string const& arg) {
auto long_pos = long_arguments.find(arg);
auto short_post = short_arguments.find(arg);
if (long_pos != long_arguments.end()) return long_pos->second;
if (short_post != short_arguments.end()) return short_post->second;
return std::nullopt;
}
void handle_arguments(std::initializer_list<conventions::convention const* const> convention_types) {
for (auto it = parsed_arguments.begin(); it != parsed_arguments.end(); ++it) {
@@ -217,24 +256,50 @@ namespace argument_parser {
std::vector<std::string> parsed_arguments;
private:
template <typename ActionType>
void base_add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, ActionType const& action, bool required) {
void assert_argument_not_exist(std::string const& short_arg, std::string const& long_arg) {
if (short_arguments.count(short_arg) || long_arguments.count(long_arg)) {
throw std::runtime_error("The key already exists!");
}
}
int id = id_counter.fetch_add(1);
argument arg(id, short_arg + "|" + long_arg, action);
arg.set_required(required);
void set_argument_status(bool is_required, std::string const& help_text, argument& arg) {
arg.set_required(is_required);
arg.set_help_text(help_text);
}
void place_argument(int id, argument const& arg, std::string const& short_arg, std::string const& long_arg) {
argument_map[id] = arg;
short_arguments[short_arg] = id;
reverse_short_arguments[id] = short_arg;
long_arguments[long_arg] = id;
reverse_long_arguments[id] = long_arg;
}
template <typename ActionType>
void base_add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, ActionType const& action, bool required) {
assert_argument_not_exist(short_arg, long_arg);
int id = id_counter.fetch_add(1);
argument arg(id, short_arg + "|" + long_arg, action);
set_argument_status(required, help_text, arg);
place_argument(id, arg, short_arg, long_arg);
}
template<typename StoreType = void>
void base_add_argument(std::string const& short_arg, std::string const& long_arg, std::string const& help_text, bool required) {
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 }; });
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>([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);
place_argument(id, arg, short_arg, long_arg);
}
}
void check_for_required_arguments(std::initializer_list<conventions::convention const* const> convention_types) {
std::vector<std::pair<std::string, std::string>> required_args;
@@ -259,6 +324,7 @@ namespace argument_parser {
inline static std::atomic_int id_counter = 0;
std::unordered_map<int, std::any> stored_arguments;
std::unordered_map<int, argument> argument_map;
std::unordered_map<std::string, int> short_arguments;
std::unordered_map<int, std::string> reverse_short_arguments;
@@ -271,16 +337,7 @@ namespace argument_parser {
friend class fake_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);
}
static non_parametered_action make_non_parametered_action(std::function<void()> const& function) {
return non_parametered_action(function);
}
}
}
#endif // ARGUMENT_PARSER_HPP

View File

@@ -118,7 +118,16 @@ int main() {
parser.display_help(conventions);
}), false);
parser.add_argument<std::string>("t", "test_store", "Test store", false);
parser.handle_arguments(conventions);
auto store = parser.get_optional<std::string>("test_store");
if (store.has_value()) {
std::cout << "Stored value: " << store.value() << std::endl;
} else {
std::cout << "No stored value." << std::endl;
}
return 0;
}