feat update
All checks were successful
rpcrypto-build / build (Debug, himix200.toolchain.cmake) (push) Successful in 1m5s
rpcrypto-build / build (Debug, hisiv510.toolchain.cmake) (push) Successful in 1m4s
rpcrypto-build / build (Release, himix200.toolchain.cmake) (push) Successful in 1m13s
rpcrypto-build / build (Release, hisiv510.toolchain.cmake) (push) Successful in 1m26s
linux-hisiv500-gcc / linux-gcc-hisiv500 (push) Successful in 1m26s
linux-mips64-gcc / linux-gcc-mips64el (push) Successful in 1m38s
linux-x64-gcc / linux-gcc (push) Successful in 1m39s

This commit is contained in:
tqcq 2024-01-22 21:22:55 +08:00
parent cc74cbfda7
commit 6086d0778e

View File

@ -50,7 +50,6 @@
#include <utility>
#include <vector>
/**
* @brief
* There are only two hard things in Computer Science: cache invalidation and
@ -100,42 +99,35 @@
*/
namespace argagg {
/**
* @brief
* This exception is thrown when a long option is parsed and is given an
* argument using the "=" syntax but the option doesn't expect an argument.
*/
struct unexpected_argument_error
: public std::runtime_error {
struct unexpected_argument_error : public std::runtime_error {
using std::runtime_error::runtime_error;
};
/**
* @brief
* This exception is thrown when an option is parsed unexpectedly such as when
* an argument was expected for a previous option or if an option was found
* that has not been defined.
*/
struct unexpected_option_error
: public std::runtime_error {
struct unexpected_option_error : public std::runtime_error {
using std::runtime_error::runtime_error;
};
/**
* @brief
* This exception is thrown when an option requires an argument but is not
* provided one. This can happen if another flag was found after the option or
* if we simply reach the end of the command line arguments.
*/
struct option_lacks_argument_error
: public std::runtime_error {
struct option_lacks_argument_error : public std::runtime_error {
using std::runtime_error::runtime_error;
};
/**
* @brief
* This exception is thrown when an option's flag is invalid. This can be the
@ -143,12 +135,10 @@ struct option_lacks_argument_error
* alpha-numeric characters after the hypens. See is_valid_flag_definition()
* for more details.
*/
struct invalid_flag
: public std::runtime_error {
struct invalid_flag : public std::runtime_error {
using std::runtime_error::runtime_error;
};
/**
* @brief
* The set of template instantiations that convert C-strings to other types for
@ -165,8 +155,7 @@ namespace convert {
template<typename T>
T arg(const char *arg);
}
}// namespace convert
/**
* @brief
@ -222,10 +211,8 @@ struct option_result {
*/
template<typename T>
operator T() const;
};
/**
* @brief
* Represents multiple option parse results for a single option. If treated as
@ -299,10 +286,8 @@ struct option_results {
*/
template<typename T>
operator T() const;
};
/**
* @brief
* Represents all results of the parser including options and positional
@ -377,10 +362,8 @@ struct parser_results {
*/
template<typename T>
std::vector<T> all_as() const;
};
/**
* @brief
* An option definition which essentially represents what an option is.
@ -425,10 +408,8 @@ struct definition {
* Returns true if this option requires arguments.
*/
bool requires_arguments() const;
};
/**
* @brief
* Checks whether or not a command line argument should be processed as an
@ -436,27 +417,21 @@ struct definition {
* allow for short flag groups (e.g. "-abc") and equal-assigned long flag
* arguments (e.g. "--output=foo.txt").
*/
bool cmd_line_arg_is_option_flag(
const char* s);
bool cmd_line_arg_is_option_flag(const char *s);
/**
* @brief
* Checks whether a flag in an option definition is valid. I suggest reading
* through the function source to understand what dictates a valid.
*/
bool is_valid_flag_definition(
const char* s);
bool is_valid_flag_definition(const char *s);
/**
* @brief
* Tests whether or not a valid flag is short. Assumes the provided cstring is
* already a valid flag.
*/
bool flag_is_short(
const char* s);
bool flag_is_short(const char *s);
/**
* @brief
@ -489,35 +464,30 @@ struct parser_map {
* @brief
* Returns true if the provided short flag exists in the map object.
*/
bool known_short_flag(
const char flag) const;
bool known_short_flag(const char flag) const;
/**
* @brief
* If the short flag exists in the map object then it is returned by this
* method. If it doesn't then nullptr will be returned.
*/
const definition* get_definition_for_short_flag(
const char flag) const;
const definition *get_definition_for_short_flag(const char flag) const;
/**
* @brief
* Returns true if the provided long flag exists in the map object.
*/
bool known_long_flag(
const std::string& flag) const;
bool known_long_flag(const std::string &flag) const;
/**
* @brief
* If the long flag exists in the map object then it is returned by this
* method. If it doesn't then nullptr will be returned.
*/
const definition* get_definition_for_long_flag(
const std::string& flag) const;
const definition *
get_definition_for_long_flag(const std::string &flag) const;
};
/**
* @brief
* Validates a collection (specifically an std::vector) of @ref definition
@ -525,9 +495,7 @@ struct parser_map {
* definition objects is not valid then an exception is thrown. Upon successful
* validation a @ref parser_map object is returned.
*/
parser_map validate_definitions(
const std::vector<definition>& definitions);
parser_map validate_definitions(const std::vector<definition> &definitions);
/**
* @brief
@ -561,10 +529,8 @@ struct parser {
* which is typically frowned upon but is safe here.
*/
parser_results parse(int argc, char **argv) const;
};
/**
* @brief
* A convenience output stream that will accumulate what is streamed to it and
@ -611,10 +577,8 @@ struct fmt_ostream : public std::ostringstream {
* stored.
*/
~fmt_ostream();
};
/**
* @brief
* Processes the provided string using the fmt util and returns the resulting
@ -632,25 +596,21 @@ struct fmt_ostream : public std::ostringstream {
*/
std::string fmt_string(const std::string &s);
}// namespace argagg
/**
* @brief
* Writes the option help to the given stream.
*/
std::ostream &operator<<(std::ostream &os, const argagg::parser &x);
// ---- end of declarations, header-only implementations follow ----
namespace argagg {
template<typename T>
T option_result::as() const
T
option_result::as() const
{
if (this->arg) {
return convert::arg<T>(this->arg);
@ -659,9 +619,9 @@ T option_result::as() const
}
}
template<typename T>
T option_result::as(const T& t) const
T
option_result::as(const T &t) const
{
if (this->arg) {
try {
@ -679,44 +639,39 @@ T option_result::as(const T& t) const
}
}
template<typename T>
option_result::operator T() const
{
return this->as<T>();
}
template <> inline
option_result::operator bool () const
template<>
inline option_result::operator bool() const
{
return this->arg != nullptr;
}
inline
std::size_t option_results::count() const
inline std::size_t
option_results::count() const
{
return this->all.size();
}
inline
option_result& option_results::operator [] (std::size_t index)
inline option_result &
option_results::operator[](std::size_t index)
{
return this->all[index];
}
inline
const option_result& option_results::operator [] (std::size_t index) const
inline const option_result &
option_results::operator[](std::size_t index) const
{
return this->all[index];
}
template<typename T>
T option_results::as() const
T
option_results::as() const
{
if (this->all.size() == 0) {
throw std::out_of_range("no option arguments to convert");
@ -724,118 +679,97 @@ T option_results::as() const
return this->all.back().as<T>();
}
template<typename T>
T option_results::as(const T& t) const
T
option_results::as(const T &t) const
{
if (this->all.size() == 0) {
return t;
}
if (this->all.size() == 0) { return t; }
return this->all.back().as<T>(t);
}
template<typename T>
option_results::operator T() const
{
return this->as<T>();
}
template <> inline
option_results::operator bool () const
template<>
inline option_results::operator bool() const
{
return this->all.size() > 0;
}
inline
bool parser_results::has_option(const std::string& name) const
inline bool
parser_results::has_option(const std::string &name) const
{
const auto it = this->options.find(name);
return (it != this->options.end()) && it->second.all.size() > 0;
}
inline
option_results& parser_results::operator [] (const std::string& name)
inline option_results &
parser_results::operator[](const std::string &name)
{
return this->options.at(name);
}
inline
const option_results&
inline const option_results &
parser_results::operator[](const std::string &name) const
{
return this->options.at(name);
}
inline
std::size_t parser_results::count() const
inline std::size_t
parser_results::count() const
{
return this->pos.size();
}
inline
const char* parser_results::operator [] (std::size_t index) const
inline const char *
parser_results::operator[](std::size_t index) const
{
return this->pos[index];
}
template<typename T>
T parser_results::as(std::size_t i) const
T
parser_results::as(std::size_t i) const
{
return convert::arg<T>(this->pos[i]);
}
template<typename T>
std::vector<T> parser_results::all_as() const
std::vector<T>
parser_results::all_as() const
{
std::vector<T> v(this->pos.size());
std::transform(
this->pos.begin(), this->pos.end(), v.begin(),
[](const char* arg) {
return convert::arg<T>(arg);
});
std::transform(this->pos.begin(), this->pos.end(), v.begin(),
[](const char *arg) { return convert::arg<T>(arg); });
return v;
}
inline
bool definition::wants_no_arguments() const
inline bool
definition::wants_no_arguments() const
{
return this->num_args == 0;
}
inline
bool definition::requires_arguments() const
inline bool
definition::requires_arguments() const
{
return this->num_args > 0;
}
inline
bool cmd_line_arg_is_option_flag(
const char* s)
inline bool
cmd_line_arg_is_option_flag(const char *s)
{
auto len = std::strlen(s);
// The shortest possible flag has two characters: a hyphen and an
// alpha-numeric character.
if (len < 2) {
return false;
}
if (len < 2) { return false; }
// All flags must start with a hyphen.
if (s[0] != '-') {
return false;
}
if (s[0] != '-') { return false; }
// Shift the name forward by a character to account for the initial hyphen.
// This means if s was originally "-v" then name will be "v".
@ -847,9 +781,7 @@ bool cmd_line_arg_is_option_flag(
is_long = true;
// Just -- is not a valid flag.
if (len == 2) {
return false;
}
if (len == 2) { return false; }
// Shift the name forward to account for the extra hyphen. This means if s
// was originally "--output" then name will be "output".
@ -859,9 +791,7 @@ bool cmd_line_arg_is_option_flag(
// The first character of the flag name must be alpha-numeric. This is to
// prevent things like "---a" from being valid flags.
len = std::strlen(name);
if (!std::isalnum(name[0])) {
return false;
}
if (!std::isalnum(name[0])) { return false; }
// At this point in is_valid_flag_definition() we would check if the short
// flag has only one character. At command line specification you can group
@ -899,23 +829,17 @@ bool cmd_line_arg_is_option_flag(
return true;
}
inline
bool is_valid_flag_definition(
const char* s)
inline bool
is_valid_flag_definition(const char *s)
{
auto len = std::strlen(s);
// The shortest possible flag has two characters: a hyphen and an
// alpha-numeric character.
if (len < 2) {
return false;
}
if (len < 2) { return false; }
// All flags must start with a hyphen.
if (s[0] != '-') {
return false;
}
if (s[0] != '-') { return false; }
// Shift the name forward by a character to account for the initial hyphen.
// This means if s was originally "-v" then name will be "v".
@ -927,9 +851,7 @@ bool is_valid_flag_definition(
is_long = true;
// Just -- is not a valid flag.
if (len == 2) {
return false;
}
if (len == 2) { return false; }
// Shift the name forward to account for the extra hyphen. This means if s
// was originally "--output" then name will be "output".
@ -939,14 +861,10 @@ bool is_valid_flag_definition(
// The first character of the flag name must be alpha-numeric. This is to
// prevent things like "---a" from being valid flags.
len = std::strlen(name);
if (!std::isalnum(name[0])) {
return false;
}
if (!std::isalnum(name[0])) { return false; }
// If this is a short flag then it must only have one character.
if (!is_long && len > 1) {
return false;
}
if (!is_long && len > 1) { return false; }
// The rest of the characters must be alpha-numeric, but long flags are
// allowed to have hyphens too.
@ -955,55 +873,41 @@ bool is_valid_flag_definition(
});
}
inline
bool flag_is_short(
const char* s)
inline bool
flag_is_short(const char *s)
{
return s[0] == '-' && std::isalnum(s[1]);
}
inline
bool parser_map::known_short_flag(
const char flag) const
inline bool
parser_map::known_short_flag(const char flag) const
{
return this->short_map[flag] != nullptr;
}
inline
const definition* parser_map::get_definition_for_short_flag(
const char flag) const
inline const definition *
parser_map::get_definition_for_short_flag(const char flag) const
{
return this->short_map[flag];
}
inline
bool parser_map::known_long_flag(
const std::string& flag) const
inline bool
parser_map::known_long_flag(const std::string &flag) const
{
const auto existing_long_flag = this->long_map.find(flag);
return existing_long_flag != long_map.end();
}
inline
const definition* parser_map::get_definition_for_long_flag(
const std::string& flag) const
inline const definition *
parser_map::get_definition_for_long_flag(const std::string &flag) const
{
const auto existing_long_flag = this->long_map.find(flag);
if (existing_long_flag == long_map.end()) {
return nullptr;
}
if (existing_long_flag == long_map.end()) { return nullptr; }
return existing_long_flag->second;
}
inline
parser_map validate_definitions(
const std::vector<definition>& definitions)
inline parser_map
validate_definitions(const std::vector<definition> &definitions)
{
std::unordered_map<std::string, const definition *> long_map;
parser_map map{{{nullptr}}, std::move(long_map)};
@ -1020,15 +924,17 @@ parser_map validate_definitions(
if (!is_valid_flag_definition(flag.data())) {
std::ostringstream msg;
msg << "flag \"" << flag << "\" specified for option \"" << defn.name
<< "\" is invalid";
msg << "flag \"" << flag << "\" specified for option \""
<< defn.name << "\" is invalid";
throw invalid_flag(msg.str());
}
if (flag_is_short(flag.data())) {
const int short_flag_letter = flag[1];
const auto existing_short_flag = map.short_map[short_flag_letter];
bool short_flag_already_exists = (existing_short_flag != nullptr);
const auto existing_short_flag =
map.short_map[short_flag_letter];
bool short_flag_already_exists =
(existing_short_flag != nullptr);
if (short_flag_already_exists) {
std::ostringstream msg;
msg << "duplicate short flag \"" << flag
@ -1042,7 +948,8 @@ parser_map validate_definitions(
// If we're here then this is a valid, long-style flag.
if (map.known_long_flag(flag)) {
const auto existing_long_flag = map.get_definition_for_long_flag(flag);
const auto existing_long_flag =
map.get_definition_for_long_flag(flag);
std::ostringstream msg;
msg << "duplicate long flag \"" << flag
<< "\" found, specified by both option \"" << defn.name
@ -1056,9 +963,8 @@ parser_map validate_definitions(
return map;
}
inline
parser_results parser::parse(int argc, const char** argv) const
inline parser_results
parser::parse(int argc, const char **argv) const
{
// Inspect each definition to see if its valid. You may wonder "why don't
// you do this validation on construction?" I had thought about it but
@ -1084,8 +990,7 @@ parser_results parser::parse(int argc, const char** argv) const
// Add an empty option result for each definition.
for (const auto &defn : this->definitions) {
option_results opt_results{{}};
results.options.insert(
std::make_pair(defn.name, opt_results));
results.options.insert(std::make_pair(defn.name, opt_results));
}
// Don't start off ignoring flags. We only ignore flags after a -- shows up
@ -1111,11 +1016,9 @@ parser_results parser::parse(int argc, const char** argv) const
// Some behavior to note: if the previous option is expecting an argument
// then the next entry will be treated as a positional argument even if
// it looks like a flag.
bool treat_as_positional_argument = (
ignore_flags
|| num_option_args_to_consume > 0
|| !cmd_line_arg_is_option_flag(arg_i_cstr)
);
bool treat_as_positional_argument =
(ignore_flags || num_option_args_to_consume > 0
|| !cmd_line_arg_is_option_flag(arg_i_cstr));
if (treat_as_positional_argument) {
// If last option is expecting some specific positive number of
@ -1195,7 +1098,8 @@ parser_results parser::parse(int argc, const char** argv) const
opt_results.all.push_back(std::move(opt_result));
if (defn->requires_arguments()) {
bool there_is_an_equal_delimited_arg = (long_flag_arg != nullptr);
bool there_is_an_equal_delimited_arg =
(long_flag_arg != nullptr);
if (there_is_an_equal_delimited_arg) {
// long_flag_arg would be "=foo" in the "--output=foo" case so we
// increment by 1 to get rid of the equal sign.
@ -1223,8 +1127,9 @@ parser_results parser::parse(int argc, const char** argv) const
if (!std::isalnum(short_flag)) {
std::ostringstream msg;
msg << "found non-alphanumeric character '" << arg_i_cstr[sf_idx]
<< "' in flag group '" << arg_i_cstr << "'";
msg << "found non-alphanumeric character '"
<< arg_i_cstr[sf_idx] << "' in flag group '" << arg_i_cstr
<< "'";
throw std::domain_error(msg.str());
}
@ -1286,25 +1191,23 @@ parser_results parser::parse(int argc, const char** argv) const
return results;
}
inline
parser_results parser::parse(int argc, char** argv) const
inline parser_results
parser::parse(int argc, char **argv) const
{
return parse(argc, const_cast<const char **>(argv));
}
namespace convert {
/**
* @brief
* Templated function for conversion to T using the @ref std::strtol()
* function. This is used for anything long length or shorter (long, int,
* short, char).
*/
template <typename T> inline
T long_(const char* arg)
template<typename T>
inline T
long_(const char *arg)
{
char *endptr = nullptr;
errno = 0;
@ -1320,15 +1223,15 @@ namespace convert {
return ret;
}
/**
* @brief
* Templated function for conversion to T using the @ref std::strtoll()
* function. This is used for anything long long length or shorter (long
* long).
*/
template <typename T> inline
T long_long_(const char* arg)
template<typename T>
inline T
long_long_(const char *arg)
{
char *endptr = nullptr;
errno = 0;
@ -1344,10 +1247,9 @@ namespace convert {
return ret;
}
#define DEFINE_CONVERSION_FROM_LONG_(TYPE) \
template <> inline \
TYPE arg(const char* arg) \
template<> \
inline TYPE arg(const char *arg) \
{ \
return long_<TYPE>(arg); \
}
@ -1364,10 +1266,9 @@ namespace convert {
#undef DEFINE_CONVERSION_FROM_LONG_
#define DEFINE_CONVERSION_FROM_LONG_LONG_(TYPE) \
template <> inline \
TYPE arg(const char* arg) \
template<> \
inline TYPE arg(const char *arg) \
{ \
return long_long_<TYPE>(arg); \
}
@ -1377,16 +1278,16 @@ namespace convert {
#undef DEFINE_CONVERSION_FROM_LONG_LONG_
template <> inline
bool arg(const char* arg)
template<>
inline bool
arg(const char *arg)
{
return argagg::convert::arg<int>(arg) != 0;
}
template <> inline
float arg(const char* arg)
template<>
inline float
arg(const char *arg)
{
char *endptr = nullptr;
errno = 0;
@ -1402,9 +1303,9 @@ namespace convert {
return ret;
}
template <> inline
double arg(const char* arg)
template<>
inline double
arg(const char *arg)
{
char *endptr = nullptr;
errno = 0;
@ -1420,42 +1321,33 @@ namespace convert {
return ret;
}
template <> inline
const char* arg(const char* arg)
template<>
inline const char *
arg(const char *arg)
{
return arg;
}
template <> inline
std::string arg(const char* arg)
template<>
inline std::string
arg(const char *arg)
{
return std::string(arg);
}
}
}// namespace convert
inline fmt_ostream::fmt_ostream(std::ostream &output)
: std::ostringstream(),
output(output)
{}
inline
fmt_ostream::fmt_ostream(std::ostream& output)
: std::ostringstream(), output(output)
{
}
inline
fmt_ostream::~fmt_ostream()
{
output << fmt_string(this->str());
}
inline fmt_ostream::~fmt_ostream() { output << fmt_string(this->str()); }
#ifdef __unix__
inline
std::string fmt_string(const std::string& s)
inline std::string
fmt_string(const std::string &s)
{
constexpr int read_end = 0;
constexpr int write_end = 1;
@ -1465,12 +1357,8 @@ std::string fmt_string(const std::string& s)
int read_pipe[2];
int write_pipe[2];
if (pipe(read_pipe) == -1) {
return s;
}
if (pipe(write_pipe) == -1) {
return s;
}
if (pipe(read_pipe) == -1) { return s; }
if (pipe(write_pipe) == -1) { return s; }
auto parent_pid = fork();
bool is_fmt_proc = (parent_pid == 0);
@ -1489,20 +1377,16 @@ std::string fmt_string(const std::string& s)
close(read_pipe[write_end]);
auto fmt_write_fd = write_pipe[write_end];
auto write_result = write(fmt_write_fd, s.c_str(), s.length());
if (write_result != static_cast<ssize_t>(s.length())) {
return s;
}
if (write_result != static_cast<ssize_t>(s.length())) { return s; }
close(fmt_write_fd);
auto fmt_read_fd = read_pipe[read_end];
std::ostringstream os;
char buf[64];
while (true) {
auto read_count = read(
fmt_read_fd, reinterpret_cast<void*>(buf), sizeof(buf));
if (read_count <= 0) {
break;
}
auto read_count =
read(fmt_read_fd, reinterpret_cast<void *>(buf), sizeof(buf));
if (read_count <= 0) { break; }
os.write(buf, static_cast<std::streamsize>(read_count));
}
close(fmt_read_fd);
@ -1510,33 +1394,42 @@ std::string fmt_string(const std::string& s)
return os.str();
}
#else// #ifdef __unix__
inline
std::string fmt_string(const std::string& s)
inline std::string
fmt_string(const std::string &s)
{
return s;
}
#endif// #ifdef __unix__
}// namespace argagg
//
namespace ulib {
using parser = argagg::parser;
using parser_results = argagg::parser_results;
using option_results = argagg::option_results;
using option_result = argagg::option_result;
using definition = argagg::definition;
using fmt_ostream = argagg::fmt_ostream;
inline
std::ostream& operator << (std::ostream& os, const argagg::parser& x)
inline std::string
fmt_string(const std::string &s)
{
return argagg::fmt_string(s);
};
}// namespace ulib
inline std::ostream &
operator<<(std::ostream &os, const argagg::parser &x)
{
for (auto &definition : x.definitions) {
os << " ";
for (auto &flag : definition.flags) {
os << flag;
if (flag != definition.flags.back()) {
os << ", ";
}
if (flag != definition.flags.back()) { os << ", "; }
}
os << std::endl;
os << " " << definition.help << std::endl;
@ -1544,5 +1437,4 @@ std::ostream& operator << (std::ostream& os, const argagg::parser& x)
return os;
}
#endif// ARGAGG_ARGAGG_ARGAGG_HPP