mirror of
https://git.lynn.is/Gwen/argparser.git
synced 2024-04-29 14:43:46 +02:00
128 lines
5.2 KiB
C++
128 lines
5.2 KiB
C++
#ifndef ARGPARSER_TUPLE_TYPE_H
|
|
#define ARGPARSER_TUPLE_TYPE_H
|
|
|
|
#include "errors.h"
|
|
#include "tuple-iteration.h"
|
|
#include "type.h"
|
|
#include <any>
|
|
#include <functional>
|
|
#include <string>
|
|
#include <tuple>
|
|
|
|
namespace argparser {
|
|
|
|
template<typename R, typename... Ts>
|
|
class base_tuple_type : public type_impl<R> {
|
|
public:
|
|
base_tuple_type(std::string name, std::tuple<type_handle_impl<Ts>...> types) : type_impl<R>(std::move(name)), types(types) {}
|
|
|
|
protected:
|
|
void parse_into_tuple(const char *begin, const char *end, const char *&parse_end, internal::parser_allow_undelimited allow_undelimited, std::tuple<Ts...> &result) {
|
|
auto cur_pos = begin;
|
|
size_t tuple_size = std::tuple_size_v<std::tuple<Ts...>>;
|
|
bool requires_delimiter = tuple_size > 1 && !internal::enum_flag_contains(allow_undelimited, internal::parser_allow_undelimited::Comma);
|
|
bool is_delimited;
|
|
|
|
if (std::string_view(begin, end).starts_with(this->name)) {
|
|
cur_pos += this->name.size();
|
|
requires_delimiter = true;
|
|
}
|
|
if (*cur_pos == '(') {
|
|
is_delimited = true;
|
|
cur_pos++;
|
|
} else if (requires_delimiter) {
|
|
throw errors::type_parsing_error(this->name, std::string(begin, end), cur_pos - begin, "expected '('");
|
|
} else {
|
|
is_delimited = false;
|
|
}
|
|
|
|
internal::parser_allow_undelimited sub_parse_allow_undelimited = internal::parser_allow_undelimited::Brackets;
|
|
if (tuple_size == 1) {
|
|
sub_parse_allow_undelimited = sub_parse_allow_undelimited | internal::parser_allow_undelimited::Comma;
|
|
}
|
|
if (!is_delimited) {
|
|
sub_parse_allow_undelimited = sub_parse_allow_undelimited & allow_undelimited;
|
|
}
|
|
|
|
internal::tuple_foreach(types, [&cur_pos, &end, &result, this, &begin, &sub_parse_allow_undelimited]<typename T>(type_handle_impl<T> &type, auto idx) {
|
|
const char *this_parse_end;
|
|
std::get<idx>(result) = type->parse(cur_pos, end, this_parse_end, sub_parse_allow_undelimited);
|
|
cur_pos = this_parse_end;
|
|
while (std::isspace(*cur_pos) && cur_pos < end)
|
|
cur_pos++;
|
|
if (idx < std::tuple_size_v<std::tuple<Ts...>> - 1) {
|
|
if (*cur_pos == ',') {
|
|
cur_pos += 1;
|
|
} else {
|
|
throw errors::type_parsing_error(this->name, std::string(begin, end), cur_pos - begin, "expected ','");
|
|
}
|
|
}
|
|
});
|
|
|
|
if (*cur_pos == ')') {
|
|
if (is_delimited) {
|
|
cur_pos++;
|
|
}
|
|
} else {
|
|
if (is_delimited) {
|
|
throw errors::type_parsing_error(this->name, std::string(begin, end), cur_pos - begin, "expected ')'");
|
|
}
|
|
}
|
|
parse_end = cur_pos;
|
|
}
|
|
|
|
private:
|
|
std::tuple<type_handle_impl<Ts>...>
|
|
types;
|
|
};
|
|
|
|
template<typename... Ts>
|
|
class tuple_type : public base_tuple_type<std::tuple<Ts...>, Ts...> {
|
|
public:
|
|
tuple_type(std::string name, std::tuple<type_handle_impl<Ts>...> types) : base_tuple_type<std::tuple<Ts...>, Ts...>(std::move(name), types) {}
|
|
|
|
std::tuple<Ts...> parse(const char *begin, const char *end, const char *&parse_end, internal::parser_allow_undelimited allow_undelimited) override {
|
|
std::tuple<Ts...> result{};
|
|
this->parse_into_tuple(begin, end, parse_end, allow_undelimited, result);
|
|
return result;
|
|
}
|
|
};
|
|
|
|
template<typename R, typename... Ts>
|
|
class custom_tuple_type : public base_tuple_type<R, Ts...> {
|
|
public:
|
|
custom_tuple_type(std::string name, std::tuple<type_handle_impl<Ts>...> types) : base_tuple_type<R, Ts...>(std::move(name), types) {}
|
|
|
|
R parse(const char *begin, const char *end, const char *&parse_end, internal::parser_allow_undelimited allow_undelimited) override {
|
|
std::tuple<Ts...> result{};
|
|
this->parse_into_tuple(begin, end, parse_end, allow_undelimited, result);
|
|
return std::apply(construct_return_type, result);
|
|
}
|
|
|
|
private:
|
|
static R construct_return_type(Ts... args) {
|
|
return R(args...);
|
|
}
|
|
};
|
|
|
|
template<typename R, typename... Ts>
|
|
class custom_tuple_type_with_constructor : public base_tuple_type<R, Ts...> {
|
|
public:
|
|
custom_tuple_type_with_constructor(std::string name, std::tuple<type_handle_impl<Ts>...> types, std::function<R(Ts...)> constructor)
|
|
: base_tuple_type<R, Ts...>(std::move(name), types), constructor(constructor) {}
|
|
|
|
R parse(const char *begin, const char *end, const char *&parse_end, internal::parser_allow_undelimited allow_undelimited) override {
|
|
std::tuple<Ts...> result{};
|
|
this->parse_into_tuple(begin, end, parse_end, allow_undelimited, result);
|
|
return std::apply(constructor, result);
|
|
}
|
|
|
|
private:
|
|
std::function<R(Ts...)> constructor;
|
|
};
|
|
|
|
}// namespace argparser
|
|
|
|
|
|
#endif//ARGPARSER_TUPLE_TYPE_H
|