Skip to content

Commit

Permalink
extracted arg_token
Browse files Browse the repository at this point in the history
  • Loading branch information
SpectraL519 committed Feb 1, 2025
1 parent d7b2dcb commit 57269d4
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 55 deletions.
62 changes: 14 additions & 48 deletions include/ap/argument_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ SOFTWARE.
#include "argument/positional.hpp"
#include "detail/argument_interface.hpp"
#include "detail/argument_name.hpp"
#include "detail/argument_token.hpp"
#include "detail/concepts.hpp"
#include "error/exceptions.hpp"
#include "nargs/range.hpp"
Expand Down Expand Up @@ -131,7 +132,7 @@ class argument_parser {
argument::positional<T>& add_positional_argument(std::string_view primary_name) {
// TODO: check forbidden characters

const ap::detail::argument_name arg_name = {primary_name};
const detail::argument_name arg_name = {primary_name};
if (this->_is_arg_name_used(arg_name))
throw error::argument_name_used(arg_name);

Expand All @@ -152,7 +153,7 @@ class argument_parser {
) {
// TODO: check forbidden characters

const ap::detail::argument_name arg_name = {primary_name, secondary_name};
const detail::argument_name arg_name = {primary_name, secondary_name};
if (this->_is_arg_name_used(arg_name))
throw error::argument_name_used(arg_name);

Expand All @@ -170,7 +171,7 @@ class argument_parser {
argument::optional<T>& add_optional_argument(std::string_view primary_name) {
// TODO: check forbidden characters

const ap::detail::argument_name arg_name = {primary_name};
const detail::argument_name arg_name = {primary_name};
if (this->_is_arg_name_used(arg_name))
throw error::argument_name_used(arg_name);

Expand All @@ -191,7 +192,7 @@ class argument_parser {
) {
// TODO: check forbidden characters

const ap::detail::argument_name arg_name = {primary_name, secondary_name};
const detail::argument_name arg_name = {primary_name, secondary_name};
if (this->_is_arg_name_used(arg_name))
throw error::argument_name_used(arg_name);

Expand Down Expand Up @@ -347,49 +348,15 @@ class argument_parser {
#endif

private:
using arg_ptr_t = std::unique_ptr<ap::detail::argument_interface>;
using arg_ptr_t = std::unique_ptr<detail::argument_interface>;
using arg_ptr_list_t = std::vector<arg_ptr_t>;
using arg_opt_t = std::optional<std::reference_wrapper<ap::detail::argument_interface>>;
using arg_opt_t = std::optional<std::reference_wrapper<detail::argument_interface>>;

// TODO: extract to a separate file
// TODO: add a tokenizer struct
// which will be responsible for converting a span/range of strings
// to tokens using a specified flag prefix character
/// @brief Structure representing a single command-line argument token.
struct arg_token {
enum class token_type : bool { flag, value };

arg_token() = default;

arg_token(const arg_token&) = default;
arg_token(arg_token&&) = default;

arg_token& operator=(const arg_token&) = default;
arg_token& operator=(arg_token&&) = default;

/**
* @brief Constructor of a command-line argument.
* @param type Type type of the token (flag or value).
* @param value The value of the argument.
*/
arg_token(const token_type type, const std::string& value) : type(type), value(value) {}

~arg_token() = default;

/**
* @brief Equality operator for comparing arg_token instances.
* @param other An arg_token instance to compare with.
* @return Boolean statement of equality comparison.
*/
bool operator==(const arg_token& other) const noexcept {
return this->type == other.type and this->value == other.value;
}

token_type type;
std::string value;
};

using arg_token_list_t = std::vector<arg_token>;
using arg_token_list_t = std::vector<detail::argument_token>;
using arg_token_list_iterator_t = typename arg_token_list_t::const_iterator;

// TODO: extract to detail
Expand Down Expand Up @@ -469,8 +436,7 @@ class argument_parser {
* @param arg_name The name of the argument.
* @return Argument predicate based on the provided name.
*/
[[nodiscard]] auto _name_match_predicate(const ap::detail::argument_name& arg_name
) const noexcept {
[[nodiscard]] auto _name_match_predicate(const detail::argument_name& arg_name) const noexcept {
return [&arg_name](const arg_ptr_t& arg) { return arg->name().match(arg_name); };
}

Expand All @@ -479,7 +445,7 @@ class argument_parser {
* @param arg_name The name of the argument.
* @return True if the argument name is already used, false otherwise.
*/
[[nodiscard]] bool _is_arg_name_used(const ap::detail::argument_name& arg_name) const noexcept {
[[nodiscard]] bool _is_arg_name_used(const detail::argument_name& arg_name) const noexcept {
const auto predicate = this->_name_match_predicate(arg_name);

if (std::ranges::find_if(this->_positional_args, predicate) != this->_positional_args.end())
Expand Down Expand Up @@ -508,10 +474,10 @@ class argument_parser {
std::string value = argv[i];
if (this->_is_flag(value)) {
this->_strip_flag_prefix(value);
args.emplace_back(arg_token::token_type::flag, std::move(value));
args.emplace_back(detail::argument_token::t_flag, std::move(value));
}
else {
args.emplace_back(arg_token::token_type::value, std::move(value));
args.emplace_back(detail::argument_token::t_value, std::move(value));
}
}

Expand Down Expand Up @@ -566,7 +532,7 @@ class argument_parser {
if (token_it == arg_tokens.end())
return;

if (token_it->type == arg_token::token_type::flag)
if (token_it->type == detail::argument_token::t_flag)
return;

pos_arg->set_value(token_it->value);
Expand All @@ -585,7 +551,7 @@ class argument_parser {
std::optional<std::reference_wrapper<arg_ptr_t>> curr_opt_arg;

while (token_it != arg_tokens.end()) {
if (token_it->type == arg_token::token_type::flag) {
if (token_it->type == detail::argument_token::t_flag) {
auto opt_arg_it = std::ranges::find_if(
this->_optional_args, this->_name_match_predicate(token_it->value)
);
Expand Down
43 changes: 43 additions & 0 deletions include/ap/detail/argument_token.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#pragma once

#include <string>

namespace ap::detail {

/// @brief Structure representing a single command-line argument token.
struct argument_token {
/// @brief The token type discriminator.
enum class token_type : bool { t_flag, t_value };
using enum token_type;

argument_token() = default;

argument_token(const argument_token&) = default;
argument_token(argument_token&&) = default;

argument_token& operator=(const argument_token&) = default;
argument_token& operator=(argument_token&&) = default;

/**
* @brief Constructor of a command-line argument.
* @param type Type type of the token (flag or value).
* @param value The value of the argument.
*/
argument_token(const token_type type, const std::string& value) : type(type), value(value) {}

~argument_token() = default;

/**
* @brief Equality operator for comparing argument_token instances.
* @param other An argument_token instance to compare with.
* @return Boolean statement of equality comparison.
*/
bool operator==(const argument_token& other) const noexcept {
return this->type == other.type and this->value == other.value;
}

token_type type;
std::string value;
};

} // namespace ap::detail
8 changes: 4 additions & 4 deletions tests/include/argument_parser_test_fixture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
#include <cstring>

using ap::detail::argument_name;
using ap::detail::argument_token;

namespace ap_testing {

struct argument_parser_test_fixture {
argument_parser_test_fixture() = default;
~argument_parser_test_fixture() = default;

using arg_token = ap::argument_parser::arg_token;
using arg_token_list_t = ap::argument_parser::arg_token_list_t;
using arg_opt_t = ap::argument_parser::arg_opt_t;

Expand Down Expand Up @@ -106,12 +106,12 @@ struct argument_parser_test_fixture {
arg_tokens.reserve(get_args_length(num_args, args_split));

for (std::size_t i = 0; i < args_split; ++i) { // positional args
arg_tokens.push_back(arg_token{arg_token::token_type::value, prepare_arg_value(i)});
arg_tokens.push_back(argument_token{argument_token::t_value, prepare_arg_value(i)});
}
for (std::size_t i = args_split; i < num_args; ++i) { // optional args
arg_tokens.push_back(arg_token{arg_token::token_type::flag, prepare_arg_name(i).primary}
arg_tokens.push_back(argument_token{argument_token::t_flag, prepare_arg_name(i).primary}
);
arg_tokens.push_back(arg_token{arg_token::token_type::value, prepare_arg_value(i)});
arg_tokens.push_back(argument_token{argument_token::t_value, prepare_arg_value(i)});
}

return arg_tokens;
Expand Down
6 changes: 3 additions & 3 deletions tests/source/test_argument_parser_parse_args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,16 @@ TEST_CASE_FIXTURE(
REQUIRE_EQ(arg_tokens.size(), get_args_length(non_default_num_args, non_default_args_split));

for (std::size_t i = 0; i < non_default_args_split; ++i) { // positional args
REQUIRE_EQ(arg_tokens.at(i).type, arg_token::token_type::value);
REQUIRE_EQ(arg_tokens.at(i).type, argument_token::t_value);
CHECK_EQ(arg_tokens.at(i).value, prepare_arg_value(i));
}

std::size_t opt_arg_idx = non_default_args_split;
for (std::size_t i = non_default_args_split; i < arg_tokens.size(); i += 2) { // optional args
REQUIRE_EQ(arg_tokens.at(i).type, arg_token::token_type::flag);
REQUIRE_EQ(arg_tokens.at(i).type, argument_token::t_flag);
CHECK(prepare_arg_name(opt_arg_idx).match(arg_tokens.at(i).value));

REQUIRE_EQ(arg_tokens.at(i + 1).type, arg_token::token_type::value);
REQUIRE_EQ(arg_tokens.at(i + 1).type, argument_token::t_value);
CHECK_EQ(arg_tokens.at(i + 1).value, prepare_arg_value(opt_arg_idx));

++opt_arg_idx;
Expand Down

0 comments on commit 57269d4

Please sign in to comment.