mirror of
https://github.com/shadps4-emu/ext-fmt.git
synced 2024-11-23 17:59:52 +00:00
Simplify format string parsing
This commit is contained in:
parent
d907786f04
commit
b8f36207c9
@ -2017,41 +2017,14 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
begin = align_result.end;
|
begin = align_result.end;
|
||||||
if (begin == end) return {begin, begin};
|
if (begin == end) return {begin, begin};
|
||||||
|
|
||||||
auto width = detail::parse_dynamic_spec(begin, end, ctx);
|
begin = detail::parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
|
||||||
switch (width.spec.kind) {
|
|
||||||
case detail::dynamic_spec_kind::none:
|
|
||||||
break;
|
|
||||||
case detail::dynamic_spec_kind::value:
|
|
||||||
specs.width = width.spec.value;
|
|
||||||
break;
|
|
||||||
case detail::dynamic_spec_kind::index:
|
|
||||||
width_ref = arg_ref_type(width.spec.value);
|
|
||||||
break;
|
|
||||||
case detail::dynamic_spec_kind::name:
|
|
||||||
width_ref = arg_ref_type(width.spec.name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
begin = width.end;
|
|
||||||
if (begin == end) return {begin, begin};
|
if (begin == end) return {begin, begin};
|
||||||
|
|
||||||
auto checker = detail::chrono_format_checker();
|
auto checker = detail::chrono_format_checker();
|
||||||
if (*begin == '.') {
|
if (*begin == '.') {
|
||||||
checker.has_precision_integral = !std::is_floating_point<Rep>::value;
|
checker.has_precision_integral = !std::is_floating_point<Rep>::value;
|
||||||
auto prec = detail::parse_precision(begin, end, ctx);
|
begin =
|
||||||
switch (prec.spec.kind) {
|
detail::parse_precision(begin, end, precision, precision_ref, ctx);
|
||||||
case detail::dynamic_spec_kind::none:
|
|
||||||
break;
|
|
||||||
case detail::dynamic_spec_kind::value:
|
|
||||||
precision = prec.spec.value;
|
|
||||||
break;
|
|
||||||
case detail::dynamic_spec_kind::index:
|
|
||||||
precision_ref = arg_ref_type(prec.spec.value);
|
|
||||||
break;
|
|
||||||
case detail::dynamic_spec_kind::name:
|
|
||||||
precision_ref = arg_ref_type(prec.spec.name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
begin = prec.end;
|
|
||||||
}
|
}
|
||||||
if (begin != end && *begin == 'L') {
|
if (begin != end && *begin == 'L') {
|
||||||
++begin;
|
++begin;
|
||||||
|
@ -2179,7 +2179,7 @@ template <typename Char> struct arg_ref {
|
|||||||
|
|
||||||
arg_id_kind kind;
|
arg_id_kind kind;
|
||||||
union value {
|
union value {
|
||||||
FMT_CONSTEXPR value(int id = 0) : index{id} {}
|
FMT_CONSTEXPR value(int idx = 0) : index(idx) {}
|
||||||
FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {}
|
FMT_CONSTEXPR value(basic_string_view<Char> n) : name(n) {}
|
||||||
|
|
||||||
int index;
|
int index;
|
||||||
@ -2188,24 +2188,13 @@ template <typename Char> struct arg_ref {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Format specifiers with width and precision resolved at formatting rather
|
// Format specifiers with width and precision resolved at formatting rather
|
||||||
// than parsing time to allow re-using the same parsed specifiers with
|
// than parsing time to allow reusing the same parsed specifiers with
|
||||||
// different sets of arguments (precompilation of format strings).
|
// different sets of arguments (precompilation of format strings).
|
||||||
template <typename Char> struct dynamic_format_specs : format_specs<Char> {
|
template <typename Char> struct dynamic_format_specs : format_specs<Char> {
|
||||||
arg_ref<Char> width_ref;
|
arg_ref<Char> width_ref;
|
||||||
arg_ref<Char> precision_ref;
|
arg_ref<Char> precision_ref;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class dynamic_spec_kind { none, value, index, name };
|
|
||||||
|
|
||||||
// A format specifier that can be specified dynamically such as width.
|
|
||||||
template <typename Char> struct dynamic_spec {
|
|
||||||
dynamic_spec_kind kind;
|
|
||||||
union {
|
|
||||||
int value;
|
|
||||||
basic_string_view<Char> name;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char> constexpr bool is_ascii_letter(Char c) {
|
template <typename Char> constexpr bool is_ascii_letter(Char c) {
|
||||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||||
}
|
}
|
||||||
@ -2328,16 +2317,15 @@ template <typename Char> FMT_CONSTEXPR bool is_name_start(Char c) {
|
|||||||
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
|
return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename IDHandler>
|
template <typename Char, typename Handler>
|
||||||
FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
|
FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
|
||||||
IDHandler&& handler) -> const Char* {
|
Handler&& handler) -> const Char* {
|
||||||
FMT_ASSERT(begin != end, "");
|
|
||||||
Char c = *begin;
|
Char c = *begin;
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
constexpr int max = (std::numeric_limits<int>::max)();
|
||||||
if (c != '0')
|
if (c != '0')
|
||||||
index =
|
index = parse_nonnegative_int(begin, end, max);
|
||||||
parse_nonnegative_int(begin, end, (std::numeric_limits<int>::max)());
|
|
||||||
else
|
else
|
||||||
++begin;
|
++begin;
|
||||||
if (begin == end || (*begin != '}' && *begin != ':'))
|
if (begin == end || (*begin != '}' && *begin != ':'))
|
||||||
@ -2358,9 +2346,10 @@ FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end,
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename IDHandler>
|
template <typename Char, typename Handler>
|
||||||
FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end,
|
FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end,
|
||||||
IDHandler&& handler) -> const Char* {
|
Handler&& handler) -> const Char* {
|
||||||
|
FMT_ASSERT(begin != end, "");
|
||||||
Char c = *begin;
|
Char c = *begin;
|
||||||
if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler);
|
if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler);
|
||||||
handler.on_auto();
|
handler.on_auto();
|
||||||
@ -2369,65 +2358,58 @@ FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end,
|
|||||||
|
|
||||||
template <typename Char> struct dynamic_spec_id_handler {
|
template <typename Char> struct dynamic_spec_id_handler {
|
||||||
basic_format_parse_context<Char>& ctx;
|
basic_format_parse_context<Char>& ctx;
|
||||||
dynamic_spec<Char> spec;
|
arg_ref<Char>& ref;
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_auto() {
|
FMT_CONSTEXPR void on_auto() {
|
||||||
spec.kind = dynamic_spec_kind::index;
|
int id = ctx.next_arg_id();
|
||||||
spec.value = ctx.next_arg_id();
|
ref = arg_ref<Char>(id);
|
||||||
ctx.check_dynamic_spec(spec.value);
|
ctx.check_dynamic_spec(id);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR void on_index(int id) {
|
FMT_CONSTEXPR void on_index(int id) {
|
||||||
spec.kind = dynamic_spec_kind::index;
|
ref = arg_ref<Char>(id);
|
||||||
spec.value = id;
|
|
||||||
ctx.check_arg_id(id);
|
ctx.check_arg_id(id);
|
||||||
ctx.check_dynamic_spec(id);
|
ctx.check_dynamic_spec(id);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
|
FMT_CONSTEXPR void on_name(basic_string_view<Char> id) {
|
||||||
spec.kind = dynamic_spec_kind::name;
|
ref = arg_ref<Char>(id);
|
||||||
spec.name = id;
|
|
||||||
ctx.check_arg_id(id);
|
ctx.check_arg_id(id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char> struct parse_dynamic_spec_result {
|
|
||||||
const Char* end;
|
|
||||||
dynamic_spec<Char> spec;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Parses [integer | "{" [arg_id] "}"].
|
// Parses [integer | "{" [arg_id] "}"].
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end,
|
FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end,
|
||||||
|
int& value, arg_ref<Char>& ref,
|
||||||
basic_format_parse_context<Char>& ctx)
|
basic_format_parse_context<Char>& ctx)
|
||||||
-> parse_dynamic_spec_result<Char> {
|
-> const Char* {
|
||||||
FMT_ASSERT(begin != end, "");
|
FMT_ASSERT(begin != end, "");
|
||||||
if ('0' <= *begin && *begin <= '9') {
|
if ('0' <= *begin && *begin <= '9') {
|
||||||
int value = parse_nonnegative_int(begin, end, -1);
|
int val = parse_nonnegative_int(begin, end, -1);
|
||||||
if (value != -1) return {begin, {dynamic_spec_kind::value, {value}}};
|
if (val != -1)
|
||||||
throw_format_error("number is too big");
|
value = val;
|
||||||
|
else
|
||||||
|
throw_format_error("number is too big");
|
||||||
} else if (*begin == '{') {
|
} else if (*begin == '{') {
|
||||||
++begin;
|
++begin;
|
||||||
auto handler =
|
auto handler = dynamic_spec_id_handler<Char>{ctx, ref};
|
||||||
dynamic_spec_id_handler<Char>{ctx, {dynamic_spec_kind::none, {}}};
|
|
||||||
if (begin != end) begin = parse_arg_id(begin, end, handler);
|
if (begin != end) begin = parse_arg_id(begin, end, handler);
|
||||||
if (begin != end && *begin == '}') {
|
if (begin != end && *begin == '}') return ++begin;
|
||||||
++begin;
|
|
||||||
return {begin, handler.spec};
|
|
||||||
}
|
|
||||||
throw_format_error("invalid format string");
|
throw_format_error("invalid format string");
|
||||||
}
|
}
|
||||||
return {begin, {dynamic_spec_kind::none, {}}};
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
|
FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
|
||||||
|
int& value, arg_ref<Char>& ref,
|
||||||
basic_format_parse_context<Char>& ctx)
|
basic_format_parse_context<Char>& ctx)
|
||||||
-> parse_dynamic_spec_result<Char> {
|
-> const Char* {
|
||||||
++begin;
|
++begin;
|
||||||
if (begin == end || *begin == '}') {
|
if (begin == end || *begin == '}') {
|
||||||
throw_format_error("missing precision");
|
throw_format_error("missing precision");
|
||||||
return {begin, {dynamic_spec_kind::none, {}}};
|
return begin;
|
||||||
}
|
}
|
||||||
return parse_dynamic_spec(begin, end, ctx);
|
return parse_dynamic_spec(begin, end, value, ref, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
@ -2552,42 +2534,15 @@ FMT_CONSTEXPR FMT_INLINE auto parse_format_specs(
|
|||||||
if (++begin == end) return {begin, specs};
|
if (++begin == end) return {begin, specs};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto width = parse_dynamic_spec(begin, end, ctx);
|
begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx);
|
||||||
switch (width.spec.kind) {
|
|
||||||
case dynamic_spec_kind::none:
|
|
||||||
break;
|
|
||||||
case dynamic_spec_kind::value:
|
|
||||||
specs.width = width.spec.value;
|
|
||||||
break;
|
|
||||||
case dynamic_spec_kind::index:
|
|
||||||
specs.width_ref = arg_ref<Char>(width.spec.value);
|
|
||||||
break;
|
|
||||||
case dynamic_spec_kind::name:
|
|
||||||
specs.width_ref = arg_ref<Char>(width.spec.name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
begin = width.end;
|
|
||||||
if (begin == end) return {begin, specs};
|
if (begin == end) return {begin, specs};
|
||||||
|
|
||||||
// Parse precision.
|
// Parse precision.
|
||||||
if (*begin == '.') {
|
if (*begin == '.') {
|
||||||
auto precision = parse_precision(begin, end, ctx);
|
begin =
|
||||||
switch (precision.spec.kind) {
|
parse_precision(begin, end, specs.precision, specs.precision_ref, ctx);
|
||||||
case dynamic_spec_kind::none:
|
|
||||||
break;
|
|
||||||
case dynamic_spec_kind::value:
|
|
||||||
specs.precision = precision.spec.value;
|
|
||||||
break;
|
|
||||||
case dynamic_spec_kind::index:
|
|
||||||
specs.precision_ref = arg_ref<Char>(precision.spec.value);
|
|
||||||
break;
|
|
||||||
case dynamic_spec_kind::name:
|
|
||||||
specs.precision_ref = arg_ref<Char>(precision.spec.name);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (is_integral_type(arg_type) || arg_type == type::pointer_type)
|
if (is_integral_type(arg_type) || arg_type == type::pointer_type)
|
||||||
throw_format_error("precision not allowed for this argument type");
|
throw_format_error("precision not allowed for this argument type");
|
||||||
begin = precision.end;
|
|
||||||
if (begin == end) return {begin, specs};
|
if (begin == end) return {begin, specs};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2833,7 +2788,7 @@ constexpr int invalid_arg_index = -1;
|
|||||||
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
#if FMT_USE_NONTYPE_TEMPLATE_ARGS
|
||||||
template <int N, typename T, typename... Args, typename Char>
|
template <int N, typename T, typename... Args, typename Char>
|
||||||
constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
|
constexpr auto get_arg_index_by_name(basic_string_view<Char> name) -> int {
|
||||||
if constexpr (detail::is_statically_named_arg<T>()) {
|
if constexpr (is_statically_named_arg<T>()) {
|
||||||
if (name == T::name) return N;
|
if (name == T::name) return N;
|
||||||
}
|
}
|
||||||
if constexpr (sizeof...(Args) > 0)
|
if constexpr (sizeof...(Args) > 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user