|
|
@ -82,11 +82,10 @@ constexpr string_view ConsumeFront(string_view str, size_t len = 1) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
constexpr string_view ConsumeAnyOf(string_view format, const char* chars) { |
|
|
|
constexpr string_view ConsumeAnyOf(string_view format, const char* chars) { |
|
|
|
if (ContainsChar(chars, GetChar(format, 0))) { |
|
|
|
while (ContainsChar(chars, GetChar(format, 0))) { |
|
|
|
return ConsumeAnyOf(ConsumeFront(format), chars); |
|
|
|
format = ConsumeFront(format); |
|
|
|
} else { |
|
|
|
|
|
|
|
return format; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return format; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
constexpr bool IsDigit(char c) { return c >= '0' && c <= '9'; } |
|
|
|
constexpr bool IsDigit(char c) { return c >= '0' && c <= '9'; } |
|
|
@ -108,13 +107,14 @@ struct Integer { |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
constexpr Integer ParseDigits(string_view format, int value = 0) { |
|
|
|
constexpr Integer ParseDigits(string_view format) { |
|
|
|
if (IsDigit(GetChar(format, 0))) { |
|
|
|
int value = 0; |
|
|
|
return ParseDigits(ConsumeFront(format), |
|
|
|
while (IsDigit(GetChar(format, 0))) { |
|
|
|
10 * value + GetChar(format, 0) - '0'); |
|
|
|
value = 10 * value + GetChar(format, 0) - '0'; |
|
|
|
} else { |
|
|
|
format = ConsumeFront(format); |
|
|
|
return Integer{format, value}; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return Integer{format, value}; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Parse digits for a positional argument.
|
|
|
|
// Parse digits for a positional argument.
|
|
|
@ -283,11 +283,9 @@ class FormatParser { |
|
|
|
// We use an inner function to increase the recursion limit.
|
|
|
|
// We use an inner function to increase the recursion limit.
|
|
|
|
// The inner function consumes up to `limit` characters on every run.
|
|
|
|
// The inner function consumes up to `limit` characters on every run.
|
|
|
|
// This increases the limit from 512 to ~512*limit.
|
|
|
|
// This increases the limit from 512 to ~512*limit.
|
|
|
|
static constexpr string_view ConsumeNonPercentInner(string_view format, |
|
|
|
static constexpr string_view ConsumeNonPercentInner(string_view format) { |
|
|
|
int limit = 20) { |
|
|
|
int limit = 20; |
|
|
|
if (FoundPercent(format) || !limit) { |
|
|
|
while (!FoundPercent(format) && limit != 0) { |
|
|
|
return format; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
size_t len = 0; |
|
|
|
size_t len = 0; |
|
|
|
|
|
|
|
|
|
|
|
if (GetChar(format, 0) == '%' && GetChar(format, 1) == '%') { |
|
|
|
if (GetChar(format, 0) == '%' && GetChar(format, 1) == '%') { |
|
|
@ -296,26 +294,29 @@ class FormatParser { |
|
|
|
len = 1; |
|
|
|
len = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return ConsumeNonPercentInner(ConsumeFront(format, len), limit - 1); |
|
|
|
format = ConsumeFront(format, len); |
|
|
|
|
|
|
|
--limit; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return format; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Consume characters until the next conversion spec %.
|
|
|
|
// Consume characters until the next conversion spec %.
|
|
|
|
// It skips %%.
|
|
|
|
// It skips %%.
|
|
|
|
static constexpr string_view ConsumeNonPercent(string_view format) { |
|
|
|
static constexpr string_view ConsumeNonPercent(string_view format) { |
|
|
|
if (FoundPercent(format)) { |
|
|
|
while (!FoundPercent(format)) { |
|
|
|
return format; |
|
|
|
format = ConsumeNonPercentInner(format); |
|
|
|
} else { |
|
|
|
|
|
|
|
return ConsumeNonPercent(ConsumeNonPercentInner(format)); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return format; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static constexpr bool IsPositional(string_view format) { |
|
|
|
static constexpr bool IsPositional(string_view format) { |
|
|
|
if (IsDigit(GetChar(format, 0))) { |
|
|
|
while (IsDigit(GetChar(format, 0))) { |
|
|
|
return IsPositional(ConsumeFront(format)); |
|
|
|
format = ConsumeFront(format); |
|
|
|
} else { |
|
|
|
|
|
|
|
return GetChar(format, 0) == '$'; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return GetChar(format, 0) == '$'; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
constexpr bool RunImpl(bool is_positional) const { |
|
|
|
constexpr bool RunImpl(bool is_positional) const { |
|
|
|