#ifndef ARGPARSER_TUPLE_TYPE_H #define ARGPARSER_TUPLE_TYPE_H #include "errors.h" #include "tuple-iteration.h" #include "type.h" #include #include #include #include namespace argparser { template class base_tuple_type : public type_impl { public: base_tuple_type(std::string name, std::tuple...> types) : type_impl(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 &result) { auto cur_pos = begin; size_t tuple_size = std::tuple_size_v>; 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](type_handle_impl &type, auto idx) { const char *this_parse_end; std::get(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> - 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...> types; }; template class tuple_type : public base_tuple_type, Ts...> { public: tuple_type(std::string name, std::tuple...> types) : base_tuple_type, Ts...>(std::move(name), types) {} std::tuple parse(const char *begin, const char *end, const char *&parse_end, internal::parser_allow_undelimited allow_undelimited) override { std::tuple result{}; this->parse_into_tuple(begin, end, parse_end, allow_undelimited, result); return result; } }; template class custom_tuple_type : public base_tuple_type { public: custom_tuple_type(std::string name, std::tuple...> types) : base_tuple_type(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 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 class custom_tuple_type_with_constructor : public base_tuple_type { public: custom_tuple_type_with_constructor(std::string name, std::tuple...> types, std::function constructor) : base_tuple_type(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 result{}; this->parse_into_tuple(begin, end, parse_end, allow_undelimited, result); return std::apply(constructor, result); } private: std::function constructor; }; }// namespace argparser #endif//ARGPARSER_TUPLE_TYPE_H