poaflocParser Of Arguments For Lines Of Commands |
git clone git://git.dimitrijedobrota.com/poafloc.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
commit | 0774b9aeb57b54b263db4fa6d28e9134da86922e |
parent | 6bae612d291e8d715ea35b03873cb846928eca1d |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Wed, 4 Jun 2025 15:22:07 +0200 |
Modernize with based goodness
M | example/example.cpp | | | ++ --- |
M | include/poafloc/error.hpp | | | + |
M | include/poafloc/poafloc.hpp | | | ++++++++++++++++++++++++++++++++++++++++++++++++++++ ------------------------------ |
M | source/help.cpp | | | ++ -- |
M | source/option.cpp | | | ++++++++++++++++++++++++++++++++++ ------------------------------------------------ |
M | source/poafloc.cpp | | | +++++++ ----- |
M | test/source/parser.cpp | | | +++ - |
7 files changed, 118 insertions(+), 103 deletions(-)
diff --git a/ example/example.cpp b/ example/example.cpp
@@ -72,7 +72,7 @@
int main()
},
};
std::vector<std::string_view> cmd_args {
const std::vector<std::string_view> cmd_args {
"--value=150",
"-m1.34",
"--name",
@@ -86,11 +86,10 @@
int main()
arguments args;
program.help_long();
/*
std::cout << args << '\n';
program(args, cmd_args);
std::cout << args << '\n';
*/
return 0;
}
diff --git a/ include/poafloc/error.hpp b/ include/poafloc/error.hpp
@@ -4,6 +4,7 @@
#include <stdexcept>
#include <based/enum/enum.hpp>
#include <based/format.hpp>
#include <based/types/types.hpp>
#include <based/utility/forward.hpp>
diff --git a/ include/poafloc/poafloc.hpp b/ include/poafloc/poafloc.hpp
@@ -9,11 +9,13 @@
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
#include <based/concepts/is/same.hpp>
#include <based/container/array.hpp>
#include <based/container/vector.hpp>
#include <based/trait/integral_constant.hpp>
#include <based/trait/remove/cvref.hpp>
#include <based/types/literals.hpp>
#include <based/types/types.hpp>
#include <based/utility/forward.hpp>
#include <based/utility/move.hpp>
@@ -23,6 +25,8 @@
namespace poafloc
{
using namespace based::literals; // NOLINT(*namespace*)
namespace detail
{
@@ -41,10 +45,13 @@
public:
private:
using func_t = std::function<void(void*, std::string_view)>;
using size_type = based::u64;
type m_type;
func_t m_func;
std::vector<char> m_opts_short;
std::vector<std::string> m_opts_long;
based::vector<based::character, size_type> m_opts_short;
based::vector<std::string, size_type> m_opts_long;
std::string m_name;
std::string m_message;
@@ -238,9 +245,9 @@
struct is_positional<argument<Record, Type>> : based::true_type
template<class T>
concept IsPositional = is_positional<T>::value;
class positional_base : public std::vector<detail::option>
class positional_base : public based::vector<detail::option, based::u64>
{
using base = std::vector<option>;
using base = based::vector<option, based::u64>;
protected:
template<detail::IsPositional Arg, detail::IsPositional... Args>
@@ -250,7 +257,7 @@
protected:
based::forward<Args>(args)...,
})
{
for (std::size_t i = 0; i < base::size() - 1; i++) {
for (size_type i = 0_u; i + 1_u8 < base::size(); i++) {
if (base::operator[](i).get_type() == option::type::list) {
throw runtime_error("invalid positional constructor");
}
@@ -310,9 +317,9 @@
struct is_option<list<Record, Type>> : based::true_type
template<class T>
concept IsOption = is_option<T>::value;
class group_base : public std::vector<detail::option>
class group_base : public based::vector<detail::option, based::u64>
{
using base = std::vector<option>;
using base = based::vector<option, based::u64>;
std::string m_name;
@@ -359,57 +366,78 @@
namespace detail
class option_short
{
static constexpr const auto sentinel = std::size_t {0xFFFFFFFFFFFFFFFF};
using size_type = based::u8;
using value_type = based::u64;
using opt_type = std::optional<value_type>;
static constexpr auto size = static_cast<std::size_t>(2 * 26);
std::array<std::size_t, size> m_opts = {};
static constexpr auto size = size_type(2_u * 26_u);
static constexpr const auto sentinel = based::limits<value_type>::max;
[[nodiscard]] bool has(char chr) const;
using array_type = based::array<value_type, size_type, size>;
array_type m_opts = {};
[[nodiscard]] bool has(based::character chr) const;
public:
option_short() { m_opts.fill(sentinel); }
static constexpr bool is_valid(char chr);
[[nodiscard]] bool set(char chr, std::size_t idx);
[[nodiscard]] std::optional<std::size_t> get(char chr) const;
static constexpr bool is_valid(based::character chr);
[[nodiscard]] bool set(based::character chr, value_type value);
[[nodiscard]] opt_type get(based::character chr) const;
};
class trie_t
{
static constexpr const auto sentinel = std::size_t {0xFFFFFFFFFFFFFFFF};
using size_type = based::u8;
using value_type = based::u64;
using opt_type = std::optional<value_type>;
static constexpr auto size = size_type(26_u + 10_u);
static constexpr const auto sentinel = based::limits<value_type>::max;
using ptr_type = std::unique_ptr<trie_t>;
using array_type = based::array<ptr_type, size_type, size>;
array_type m_children = {};
static constexpr auto size = static_cast<std::size_t>(26ULL + 10ULL);
std::array<std::unique_ptr<trie_t>, size> m_children = {};
value_type m_value = sentinel;
based::u8 m_count = 0_u8;
std::size_t m_value = sentinel;
std::size_t m_count = 0;
bool m_terminal = false;
trie_t* m_parent = nullptr;
static constexpr auto map(char chr);
static constexpr auto map(based::character chr);
public:
static bool set(trie_t& trie, std::string_view key, std::size_t value);
static std::optional<std::size_t> get(
const trie_t& trie, std::string_view key
);
explicit trie_t(trie_t* parent = nullptr)
: m_parent(parent)
{
}
static bool set(trie_t& trie, std::string_view key, value_type value);
static opt_type get(const trie_t& trie, std::string_view key);
};
class option_long
{
using value_type = based::u64;
using opt_type = std::optional<value_type>;
trie_t m_trie;
public:
static constexpr bool is_valid(std::string_view opt);
[[nodiscard]] bool set(std::string_view opt, std::size_t idx);
[[nodiscard]] std::optional<std::size_t> get(std::string_view opt) const;
[[nodiscard]] bool set(std::string_view opt, value_type idx);
[[nodiscard]] opt_type get(std::string_view opt) const;
};
class parser_base
{
std::vector<option> m_options;
using size_type = based::u64;
based::vector<option, size_type> m_options;
using group_t = std::pair<std::size_t, std::string>;
std::vector<group_t> m_groups;
using group_type = std::pair<size_type, std::string>;
based::vector<group_type, size_type> m_groups;
positional_base m_pos;
option_short m_opt_short;
@@ -417,15 +445,15 @@
class parser_base
void process(const option& option);
[[nodiscard]] const option& get_option(char opt) const;
[[nodiscard]] const option& get_option(based::character opt) const;
[[nodiscard]] const option& get_option(std::string_view opt) const;
using next_t = std::span<std::string_view>;
using next_t = std::span<const std::string_view>;
next_t hdl_long_opt(void* record, std::string_view arg, next_t next) const;
next_t hdl_short_opts(void* record, std::string_view arg, next_t next) const;
next_t hdl_short_opt(
void* record, char opt, std::string_view rest, next_t next
void* record, based::character opt, std::string_view rest, next_t next
) const;
protected:
@@ -442,7 +470,7 @@
protected:
: m_pos(based::forward<decltype(positional)>(positional))
{
m_options.reserve(m_options.size() + (groups.size() + ...));
m_groups.reserve(sizeof...(groups));
m_groups.reserve(size_type::underlying_cast(sizeof...(groups)));
const auto process = [&](const auto& group)
{
@@ -455,7 +483,7 @@
protected:
}
void operator()(void* record, int argc, const char** argv);
void operator()(void* record, std::span<std::string_view> args);
void operator()(void* record, std::span<const std::string_view> args);
void help_long() const;
void help_short() const;
@@ -497,7 +525,7 @@
struct parser : detail::parser_base
parser_base::operator()(&record, argc, argv);
}
void operator()(Record& record, std::span<std::string_view> args)
void operator()(Record& record, std::span<const std::string_view> args)
{
parser_base::operator()(&record, args);
}
diff --git a/ source/help.cpp b/ source/help.cpp
@@ -18,7 +18,7 @@
void parser_base::help_long() const
}
std::cerr << '\n';
std::size_t idx = 0;
auto idx = size_type(0_u);
for (const auto& [end_idx, name] : m_groups) {
std::cerr << std::format("\n{}:\n", name);
while (idx < end_idx) {
@@ -27,7 +27,7 @@
void parser_base::help_long() const
line += " ";
for (const auto opt_short : option.opts_short()) {
line += std::format(" -{},", opt_short);
line += std::format(" -{},", opt_short.chr());
}
for (const auto& opt_long : option.opts_long()) {
switch (option.get_type()) {
diff --git a/ source/option.cpp b/ source/option.cpp
@@ -1,37 +1,37 @@
#include <algorithm>
#include <based/char/character.hpp>
#include <based/char/is/alpha.hpp>
#include <based/char/is/alpha_lower.hpp>
#include <based/char/is/digit.hpp>
#include <based/char/mapper.hpp>
#include <based/functional/predicate/not_null.hpp>
#include <based/trait/iterator.hpp>
#include "poafloc/error.hpp"
#include "poafloc/poafloc.hpp"
namespace
{
constexpr bool is_digit(char c)
{
return c >= '0' && c <= '9';
}
constexpr bool is_alpha_lower(char c)
{
return c >= 'a' && c <= 'z';
}
constexpr bool is_alpha_upper(char c)
struct short_map
{
return c >= 'A' && c <= 'Z';
}
constexpr auto convert(char chr)
{
return static_cast<size_t>(static_cast<unsigned char>(chr));
}
constexpr bool operator()(based::character chr) const
{
return based::is_alpha(chr);
}
};
constexpr auto map(char chr)
struct long_map
{
if (is_alpha_lower(chr)) {
return convert(chr) - convert('a');
constexpr bool operator()(based::character chr) const
{
return based::is_alpha_lower(chr) || based::is_digit(chr);
}
};
return convert(chr) - convert('A') + 26; // NOLINT(*magic*)
}
using short_mapper = based::mapper<short_map>;
using long_mapper = based::mapper<long_map>;
} // namespace
@@ -39,17 +39,17 @@
constexpr auto map(char chr)
namespace poafloc::detail
{
constexpr bool option_short::is_valid(char chr)
constexpr bool option_short::is_valid(based::character chr)
{
return is_alpha_lower(chr) || is_alpha_upper(chr);
return short_mapper::predicate(chr);
}
[[nodiscard]] bool option_short::has(char chr) const
bool option_short::has(based::character chr) const
{
return m_opts[map(chr)] != sentinel;
return m_opts[short_mapper::map(chr)] != sentinel;
}
[[nodiscard]] bool option_short::set(char chr, std::size_t idx)
bool option_short::set(based::character chr, value_type value)
{
if (!is_valid(chr)) {
throw error<error_code::invalid_option>(chr);
@@ -59,11 +59,11 @@
constexpr bool option_short::is_valid(char chr)
return false;
}
m_opts[map(chr)] = idx;
m_opts[short_mapper::map(chr)] = value;
return true;
}
[[nodiscard]] std::optional<std::size_t> option_short::get(char chr) const
option_short::opt_type option_short::get(based::character chr) const
{
if (!is_valid(chr)) {
throw error<error_code::invalid_option>(chr);
@@ -73,7 +73,7 @@
constexpr bool option_short::is_valid(char chr)
return {};
}
return m_opts[map(chr)];
return m_opts[short_mapper::map(chr)];
}
} // namespace poafloc::detail
@@ -82,16 +82,7 @@
constexpr bool option_short::is_valid(char chr)
namespace poafloc::detail
{
constexpr auto trie_t::map(char chr)
{
if (is_alpha_lower(chr)) {
return convert(chr) - convert('a');
}
return convert(chr) - convert('0') + 26; // NOLINT(*magic*)
}
bool trie_t::set(trie_t& trie, std::string_view key, std::size_t value)
bool trie_t::set(trie_t& trie, std::string_view key, value_type value)
{
trie_t* crnt = ≜
for (const auto c : key) {
@@ -100,9 +91,9 @@
bool trie_t::set(trie_t& trie, std::string_view key, std::size_t value)
crnt->m_value = value;
}
const auto idx = map(c);
const auto idx = long_mapper::map(c);
if (crnt->m_children[idx] == nullptr) {
crnt->m_children[idx] = std::make_unique<trie_t>();
crnt->m_children[idx] = std::make_unique<trie_t>(nullptr);
}
crnt = crnt->m_children[idx].get();
}
@@ -116,25 +107,24 @@
bool trie_t::set(trie_t& trie, std::string_view key, std::size_t value)
return true;
}
std::optional<std::size_t> trie_t::get(const trie_t& trie, std::string_view key)
trie_t::opt_type trie_t::get(const trie_t& trie, std::string_view key)
{
const trie_t* crnt = ≜
for (const auto c : key) {
const auto idx = map(c);
const auto idx = long_mapper::map(c);
if (crnt->m_children[idx] == nullptr) {
return {};
}
crnt = crnt->m_children[idx].get();
}
if (crnt->m_terminal || crnt->m_count == 1) {
if (crnt->m_terminal || crnt->m_count == 1_u8) {
return crnt->m_value;
}
return {};
}
} // namespace poafloc::detail
// option_long
@@ -143,17 +133,11 @@
namespace poafloc::detail
constexpr bool option_long::is_valid(std::string_view opt)
{
return is_alpha_lower(opt.front())
&& std::ranges::all_of(
opt,
[](const char chr)
{
return is_alpha_lower(chr) || is_digit(chr);
}
);
return based::is_alpha_lower(opt.front())
&& std::ranges::all_of(opt, long_mapper::predicate);
}
[[nodiscard]] bool option_long::set(std::string_view opt, std::size_t idx)
bool option_long::set(std::string_view opt, value_type idx)
{
if (!is_valid(opt)) {
throw error<error_code::invalid_option>(opt);
@@ -162,8 +146,7 @@
constexpr bool option_long::is_valid(std::string_view opt)
return trie_t::set(m_trie, opt, idx);
}
[[nodiscard]] std::optional<std::size_t> option_long::get(std::string_view opt
) const
option_long::opt_type option_long::get(std::string_view opt) const
{
if (!is_valid(opt)) {
throw error<error_code::invalid_option>(opt);
diff --git a/ source/poafloc.cpp b/ source/poafloc.cpp
@@ -12,7 +12,7 @@
constexpr bool is_option(std::string_view arg)
return arg.starts_with("-");
}
constexpr bool is_next_option(std::span<std::string_view> args)
constexpr bool is_next_option(std::span<const std::string_view> args)
{
return args.empty() || is_option(args.front());
}
@@ -76,7 +76,9 @@
void parser_base::operator()(void* record, int argc, const char** argv)
operator()(record, args);
}
void parser_base::operator()(void* record, std::span<std::string_view> args)
void parser_base::operator()(
void* record, std::span<const std::string_view> args
)
{
std::size_t arg_idx = 0;
bool is_term = false;
@@ -105,7 +107,7 @@
void parser_base::operator()(void* record, std::span<std::string_view> args)
arg_idx = std::size(args) - std::size(res);
}
std::size_t count = 0;
auto count = 0_u64;
while (arg_idx != std::size(args)) {
const auto arg = args[arg_idx++];
if (!is_term && arg == "--") {
@@ -133,7 +135,7 @@
void parser_base::operator()(void* record, std::span<std::string_view> args)
}
parser_base::next_t parser_base::hdl_short_opt(
void* record, char opt, std::string_view rest, next_t next
void* record, based::character opt, std::string_view rest, next_t next
) const
{
const auto option = get_option(opt);
@@ -240,7 +242,7 @@
parser_base::next_t parser_base::hdl_long_opt(
return next;
}
[[nodiscard]] const option& parser_base::get_option(char opt) const
[[nodiscard]] const option& parser_base::get_option(based::character opt) const
{
const auto idx = m_opt_short.get(opt);
if (!idx.has_value()) {
diff --git a/ test/source/parser.cpp b/ test/source/parser.cpp
@@ -548,7 +548,9 @@
TEST_CASE("list", "[poafloc/parser]")
SECTION("long terminal three")
{
std::vector<std::string_view> cmdline = {"--list", "one", "two", "three", "--"};
std::vector<std::string_view> cmdline = {
"--list", "one", "two", "three", "--"
};
REQUIRE_NOTHROW(program(args, cmdline));
REQUIRE(std::size(args.list) == 3);
REQUIRE(args.list[0] == "one");