mirror of
https://github.com/marzer/tomlplusplus.git
synced 2024-09-04 14:09:11 +00:00
parent
3f4a540ca6
commit
f6ce95907e
@ -213,6 +213,7 @@ UTF-8 decoding is performed using a state machine based on Bjoern Hoehrmann's '[
|
|||||||
- **[@bobfang1992](https://github.com/bobfang1992)** - Reported a bug and created a [wrapper in python](https://github.com/bobfang1992/pytomlpp)
|
- **[@bobfang1992](https://github.com/bobfang1992)** - Reported a bug and created a [wrapper in python](https://github.com/bobfang1992/pytomlpp)
|
||||||
- **[@GiulioRomualdi](https://github.com/GiulioRomualdi)** - Added cmake+meson support
|
- **[@GiulioRomualdi](https://github.com/GiulioRomualdi)** - Added cmake+meson support
|
||||||
- **[@levicki](https://github.com/levicki)** - Helped design some new features
|
- **[@levicki](https://github.com/levicki)** - Helped design some new features
|
||||||
|
- **[@moorereason](https://github.com/moorereason)** - Reported a whole bunch of bugs
|
||||||
- **[@mosra](https://github.com/mosra)** - Created the awesome [m.css] used to generate the API docs
|
- **[@mosra](https://github.com/mosra)** - Created the awesome [m.css] used to generate the API docs
|
||||||
- **[@ned14](https://github.com/ned14)** - Reported a bunch of bugs and helped design some new features
|
- **[@ned14](https://github.com/ned14)** - Reported a bunch of bugs and helped design some new features
|
||||||
- **[@okureta](https://github.com/okureta)** - Reported a bug
|
- **[@okureta](https://github.com/okureta)** - Reported a bug
|
||||||
|
@ -93,9 +93,11 @@ namespace
|
|||||||
R"(val = -+1)"sv,
|
R"(val = -+1)"sv,
|
||||||
R"(val = 1_0_)"sv,
|
R"(val = 1_0_)"sv,
|
||||||
R"(val = 1_0_ )"sv,
|
R"(val = 1_0_ )"sv,
|
||||||
R"(val = 999999999999999999999999999999999999 )"sv,
|
|
||||||
R"(val = 9223372036854775808 )"sv,
|
|
||||||
R"(val = 01 )"sv,
|
R"(val = 01 )"sv,
|
||||||
|
R"(val = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000 )"sv,
|
||||||
|
R"(val = 0o1000000000000000000000 )"sv,
|
||||||
|
R"(val = 9223372036854775808 )"sv,
|
||||||
|
R"(val = 0x8000000000000000 )"sv,
|
||||||
|
|
||||||
"########## floats"sv,
|
"########## floats"sv,
|
||||||
R"(val = 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0)"sv,
|
R"(val = 100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0)"sv,
|
||||||
|
@ -619,40 +619,44 @@ TOML_ANON_NAMESPACE_START
|
|||||||
template <>
|
template <>
|
||||||
struct parse_integer_traits<2>
|
struct parse_integer_traits<2>
|
||||||
{
|
{
|
||||||
static constexpr auto scope_qualifier = "binary integer"sv;
|
static constexpr auto scope_qualifier = "binary integer"sv;
|
||||||
static constexpr auto is_digit = impl::is_binary_digit;
|
static constexpr auto is_digit = impl::is_binary_digit;
|
||||||
static constexpr auto is_signed = false;
|
static constexpr auto is_signed = false;
|
||||||
static constexpr auto min_buffer_length = 63;
|
static constexpr auto max_digits = 63;
|
||||||
static constexpr auto prefix_codepoint = U'b';
|
static constexpr auto prefix_codepoint = U'b';
|
||||||
static constexpr auto prefix = "b"sv;
|
static constexpr auto prefix = "b"sv;
|
||||||
|
static constexpr auto full_prefix = "0b"sv;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct parse_integer_traits<8>
|
struct parse_integer_traits<8>
|
||||||
{
|
{
|
||||||
static constexpr auto scope_qualifier = "octal integer"sv;
|
static constexpr auto scope_qualifier = "octal integer"sv;
|
||||||
static constexpr auto is_digit = impl::is_octal_digit;
|
static constexpr auto is_digit = impl::is_octal_digit;
|
||||||
static constexpr auto is_signed = false;
|
static constexpr auto is_signed = false;
|
||||||
static constexpr auto min_buffer_length = 21; // strlen("777777777777777777777")
|
static constexpr auto max_digits = 21; // strlen("777777777777777777777")
|
||||||
static constexpr auto prefix_codepoint = U'o';
|
static constexpr auto prefix_codepoint = U'o';
|
||||||
static constexpr auto prefix = "o"sv;
|
static constexpr auto prefix = "o"sv;
|
||||||
|
static constexpr auto full_prefix = "0o"sv;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct parse_integer_traits<10>
|
struct parse_integer_traits<10>
|
||||||
{
|
{
|
||||||
static constexpr auto scope_qualifier = "decimal integer"sv;
|
static constexpr auto scope_qualifier = "decimal integer"sv;
|
||||||
static constexpr auto is_digit = impl::is_decimal_digit;
|
static constexpr auto is_digit = impl::is_decimal_digit;
|
||||||
static constexpr auto is_signed = true;
|
static constexpr auto is_signed = true;
|
||||||
static constexpr auto min_buffer_length = 19; // strlen("9223372036854775807")
|
static constexpr auto max_digits = 19; // strlen("9223372036854775807")
|
||||||
|
static constexpr auto full_prefix = ""sv;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct parse_integer_traits<16>
|
struct parse_integer_traits<16>
|
||||||
{
|
{
|
||||||
static constexpr auto scope_qualifier = "hexadecimal integer"sv;
|
static constexpr auto scope_qualifier = "hexadecimal integer"sv;
|
||||||
static constexpr auto is_digit = impl::is_hexadecimal_digit;
|
static constexpr auto is_digit = impl::is_hexadecimal_digit;
|
||||||
static constexpr auto is_signed = false;
|
static constexpr auto is_signed = false;
|
||||||
static constexpr auto min_buffer_length = 16; // strlen("7FFFFFFFFFFFFFFF")
|
static constexpr auto max_digits = 16; // strlen("7FFFFFFFFFFFFFFF")
|
||||||
static constexpr auto prefix_codepoint = U'x';
|
static constexpr auto prefix_codepoint = U'x';
|
||||||
static constexpr auto prefix = "x"sv;
|
static constexpr auto prefix = "x"sv;
|
||||||
|
static constexpr auto full_prefix = "0x"sv;
|
||||||
};
|
};
|
||||||
|
|
||||||
TOML_PURE_GETTER
|
TOML_PURE_GETTER
|
||||||
@ -1758,12 +1762,6 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
char first_integer_part = '\0';
|
char first_integer_part = '\0';
|
||||||
while (!is_eof() && !is_value_terminator(*cp))
|
while (!is_eof() && !is_value_terminator(*cp))
|
||||||
{
|
{
|
||||||
if TOML_UNLIKELY(length == sizeof(chars))
|
|
||||||
set_error_and_return_default("exceeds maximum length of "sv,
|
|
||||||
static_cast<uint64_t>(sizeof(chars)),
|
|
||||||
" characters"sv,
|
|
||||||
(seen_exponent ? ""sv : " (consider using exponent notation)"sv));
|
|
||||||
|
|
||||||
if (*cp == U'_')
|
if (*cp == U'_')
|
||||||
{
|
{
|
||||||
if (!prev || !is_decimal_digit(*prev))
|
if (!prev || !is_decimal_digit(*prev))
|
||||||
@ -1773,8 +1771,13 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
advance_and_return_if_error_or_eof({});
|
advance_and_return_if_error_or_eof({});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (prev && *prev == U'_' && !is_decimal_digit(*cp))
|
else if TOML_UNLIKELY(prev && *prev == U'_' && !is_decimal_digit(*cp))
|
||||||
set_error_and_return_default("underscores must be followed by digits"sv);
|
set_error_and_return_default("underscores must be followed by digits"sv);
|
||||||
|
else if TOML_UNLIKELY(length == sizeof(chars))
|
||||||
|
set_error_and_return_default("exceeds length limit of "sv,
|
||||||
|
static_cast<uint64_t>(sizeof(chars)),
|
||||||
|
" digits"sv,
|
||||||
|
(seen_exponent ? ""sv : " (consider using exponent notation)"sv));
|
||||||
else if (*cp == U'.')
|
else if (*cp == U'.')
|
||||||
{
|
{
|
||||||
// .1
|
// .1
|
||||||
@ -2109,10 +2112,8 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
|
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// consume value chars
|
// consume digits
|
||||||
static constexpr size_t underscore_padding = 32;
|
char digits[utf8_buffered_reader::max_history_length];
|
||||||
static constexpr size_t buffer_length = traits::min_buffer_length + underscore_padding;
|
|
||||||
char chars[buffer_length];
|
|
||||||
size_t length = {};
|
size_t length = {};
|
||||||
const utf8_codepoint* prev = {};
|
const utf8_codepoint* prev = {};
|
||||||
while (!is_eof() && !is_value_terminator(*cp))
|
while (!is_eof() && !is_value_terminator(*cp))
|
||||||
@ -2126,16 +2127,16 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
advance_and_return_if_error_or_eof({});
|
advance_and_return_if_error_or_eof({});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (prev && *prev == U'_' && !traits::is_digit(*cp))
|
else if TOML_UNLIKELY(prev && *prev == U'_' && !traits::is_digit(*cp))
|
||||||
set_error_and_return_default("underscores must be followed by digits"sv);
|
set_error_and_return_default("underscores must be followed by digits"sv);
|
||||||
else if (!traits::is_digit(*cp))
|
else if TOML_UNLIKELY(!traits::is_digit(*cp))
|
||||||
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
|
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
|
||||||
else if (length == sizeof(chars))
|
else if TOML_UNLIKELY(length == sizeof(digits))
|
||||||
set_error_and_return_default("exceeds maximum length of "sv,
|
set_error_and_return_default("exceeds length limit of "sv,
|
||||||
static_cast<uint64_t>(sizeof(chars)),
|
static_cast<uint64_t>(sizeof(digits)),
|
||||||
" characters"sv);
|
" digits"sv);
|
||||||
else
|
else
|
||||||
chars[length++] = static_cast<char>(cp->bytes[0]);
|
digits[length++] = static_cast<char>(cp->bytes[0]);
|
||||||
|
|
||||||
prev = cp;
|
prev = cp;
|
||||||
advance_and_return_if_error({});
|
advance_and_return_if_error({});
|
||||||
@ -2148,52 +2149,75 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
set_error_and_return_default("underscores must be followed by digits"sv);
|
set_error_and_return_default("underscores must be followed by digits"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for leading zeroes
|
|
||||||
if constexpr (base == 10)
|
|
||||||
{
|
|
||||||
if (chars[0] == '0')
|
|
||||||
set_error_and_return_default("leading zeroes are prohibited"sv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// single digits can be converted trivially
|
// single digits can be converted trivially
|
||||||
if (length == 1u)
|
if (length == 1u)
|
||||||
{
|
{
|
||||||
|
int64_t result;
|
||||||
|
|
||||||
if constexpr (base == 16)
|
if constexpr (base == 16)
|
||||||
return static_cast<int64_t>(hex_to_dec(chars[0]));
|
result = static_cast<int64_t>(hex_to_dec(digits[0]));
|
||||||
else if constexpr (base <= 10)
|
else
|
||||||
return static_cast<int64_t>(chars[0] - '0');
|
result = static_cast<int64_t>(digits[0] - '0');
|
||||||
|
|
||||||
|
if constexpr (traits::is_signed)
|
||||||
|
result *= sign;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise do the thing
|
// bin, oct and hex allow leading zeroes so trim them first
|
||||||
uint64_t result = {};
|
const char* end = digits + length;
|
||||||
|
const char* msd = digits;
|
||||||
|
if constexpr (base != 10)
|
||||||
{
|
{
|
||||||
const char* msd = chars;
|
|
||||||
const char* end = msd + length;
|
|
||||||
while (msd < end && *msd == '0')
|
while (msd < end && *msd == '0')
|
||||||
msd++;
|
msd++;
|
||||||
if (msd == end)
|
if (msd == end)
|
||||||
return 0ll;
|
return 0ll;
|
||||||
uint64_t power = 1;
|
}
|
||||||
while (--end >= msd)
|
|
||||||
{
|
// decimal integers do not allow leading zeroes
|
||||||
if constexpr (base == 16)
|
else
|
||||||
result += power * hex_to_dec(*end);
|
{
|
||||||
else
|
if TOML_UNLIKELY(digits[0] == '0')
|
||||||
result += power * static_cast<uint64_t>(*end - '0');
|
set_error_and_return_default("leading zeroes are prohibited"sv);
|
||||||
power *= base;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// range check
|
// range check
|
||||||
if (result > static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()) + (sign < 0 ? 1ull : 0ull))
|
if TOML_UNLIKELY(static_cast<size_t>(end - msd) > traits::max_digits)
|
||||||
set_error_and_return_default("'"sv,
|
set_error_and_return_default("'"sv,
|
||||||
std::string_view{ chars, length },
|
traits::full_prefix,
|
||||||
|
std::string_view{ digits, length },
|
||||||
"' is not representable in 64 bits"sv);
|
"' is not representable in 64 bits"sv);
|
||||||
|
|
||||||
if constexpr (traits::is_signed)
|
// do the thing
|
||||||
return static_cast<int64_t>(result) * sign;
|
{
|
||||||
else
|
uint64_t result = {};
|
||||||
return static_cast<int64_t>(result);
|
{
|
||||||
|
uint64_t power = 1;
|
||||||
|
while (--end >= msd)
|
||||||
|
{
|
||||||
|
if constexpr (base == 16)
|
||||||
|
result += power * hex_to_dec(*end);
|
||||||
|
else
|
||||||
|
result += power * static_cast<uint64_t>(*end - '0');
|
||||||
|
|
||||||
|
power *= base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// range check
|
||||||
|
if TOML_UNLIKELY(result > static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()) + (sign < 0 ? 1ull : 0ull))
|
||||||
|
set_error_and_return_default("'"sv,
|
||||||
|
traits::full_prefix,
|
||||||
|
std::string_view{ digits, length },
|
||||||
|
"' is not representable in 64 bits"sv);
|
||||||
|
|
||||||
|
if constexpr (traits::is_signed)
|
||||||
|
return static_cast<int64_t>(result) * sign;
|
||||||
|
else
|
||||||
|
return static_cast<int64_t>(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_NODISCARD
|
TOML_NODISCARD
|
||||||
|
@ -260,4 +260,46 @@ b = []
|
|||||||
{
|
{
|
||||||
parsing_should_fail(FILE_LINE_ARGS, "#\r"sv);
|
parsing_should_fail(FILE_LINE_ARGS, "#\r"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("github/issues/134") // https://github.com/marzer/tomlplusplus/issues/134
|
||||||
|
{
|
||||||
|
// binary
|
||||||
|
parsing_should_fail(
|
||||||
|
FILE_LINE_ARGS,
|
||||||
|
"val = 0b11111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111"sv); // uint64_t
|
||||||
|
// max
|
||||||
|
parsing_should_fail(
|
||||||
|
FILE_LINE_ARGS,
|
||||||
|
"val = 0b10000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000"sv); // int64_t
|
||||||
|
// max
|
||||||
|
// + 1
|
||||||
|
parse_expected_value(FILE_LINE_ARGS,
|
||||||
|
"0b01111111_11111111_11111111_11111111_11111111_11111111_11111111_11111111"sv,
|
||||||
|
INT64_MAX); // int64_t max
|
||||||
|
|
||||||
|
// octal
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = 0o1777777777777777777777"sv); // uint64_t max
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = 0o1000000000000000000000"sv); // int64_t max + 1
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, " 0o0777777777777777777777"sv, INT64_MAX);
|
||||||
|
|
||||||
|
// decimal
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = 100000000000000000000"sv);
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = 18446744073709551615"sv); // uint64_t max
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = 10000000000000000000"sv);
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = 9999999999999999999"sv);
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = 9223372036854775808"sv); // int64_t max + 1
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, " 9223372036854775807"sv, INT64_MAX);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, " 1000000000000000000"sv, 1000000000000000000LL);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, " -1000000000000000000"sv, -1000000000000000000LL);
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, " -9223372036854775808"sv, INT64_MIN);
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = -9223372036854775809"sv); // int64_t min - 1
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = -10000000000000000000"sv);
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = -18446744073709551615"sv); // -(uint64_t max)
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = -100000000000000000000"sv);
|
||||||
|
|
||||||
|
// hexadecimal
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = 0xFFFFFFFFFFFFFFFF"sv); // uint64_t max
|
||||||
|
parsing_should_fail(FILE_LINE_ARGS, " val = 0x8000000000000000"sv); // int64_t max + 1
|
||||||
|
parse_expected_value(FILE_LINE_ARGS, " 0x7FFFFFFFFFFFFFFF"sv, INT64_MAX);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
162
toml.hpp
162
toml.hpp
@ -11617,40 +11617,44 @@ TOML_ANON_NAMESPACE_START
|
|||||||
template <>
|
template <>
|
||||||
struct parse_integer_traits<2>
|
struct parse_integer_traits<2>
|
||||||
{
|
{
|
||||||
static constexpr auto scope_qualifier = "binary integer"sv;
|
static constexpr auto scope_qualifier = "binary integer"sv;
|
||||||
static constexpr auto is_digit = impl::is_binary_digit;
|
static constexpr auto is_digit = impl::is_binary_digit;
|
||||||
static constexpr auto is_signed = false;
|
static constexpr auto is_signed = false;
|
||||||
static constexpr auto min_buffer_length = 63;
|
static constexpr auto max_digits = 63;
|
||||||
static constexpr auto prefix_codepoint = U'b';
|
static constexpr auto prefix_codepoint = U'b';
|
||||||
static constexpr auto prefix = "b"sv;
|
static constexpr auto prefix = "b"sv;
|
||||||
|
static constexpr auto full_prefix = "0b"sv;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct parse_integer_traits<8>
|
struct parse_integer_traits<8>
|
||||||
{
|
{
|
||||||
static constexpr auto scope_qualifier = "octal integer"sv;
|
static constexpr auto scope_qualifier = "octal integer"sv;
|
||||||
static constexpr auto is_digit = impl::is_octal_digit;
|
static constexpr auto is_digit = impl::is_octal_digit;
|
||||||
static constexpr auto is_signed = false;
|
static constexpr auto is_signed = false;
|
||||||
static constexpr auto min_buffer_length = 21; // strlen("777777777777777777777")
|
static constexpr auto max_digits = 21; // strlen("777777777777777777777")
|
||||||
static constexpr auto prefix_codepoint = U'o';
|
static constexpr auto prefix_codepoint = U'o';
|
||||||
static constexpr auto prefix = "o"sv;
|
static constexpr auto prefix = "o"sv;
|
||||||
|
static constexpr auto full_prefix = "0o"sv;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct parse_integer_traits<10>
|
struct parse_integer_traits<10>
|
||||||
{
|
{
|
||||||
static constexpr auto scope_qualifier = "decimal integer"sv;
|
static constexpr auto scope_qualifier = "decimal integer"sv;
|
||||||
static constexpr auto is_digit = impl::is_decimal_digit;
|
static constexpr auto is_digit = impl::is_decimal_digit;
|
||||||
static constexpr auto is_signed = true;
|
static constexpr auto is_signed = true;
|
||||||
static constexpr auto min_buffer_length = 19; // strlen("9223372036854775807")
|
static constexpr auto max_digits = 19; // strlen("9223372036854775807")
|
||||||
|
static constexpr auto full_prefix = ""sv;
|
||||||
};
|
};
|
||||||
template <>
|
template <>
|
||||||
struct parse_integer_traits<16>
|
struct parse_integer_traits<16>
|
||||||
{
|
{
|
||||||
static constexpr auto scope_qualifier = "hexadecimal integer"sv;
|
static constexpr auto scope_qualifier = "hexadecimal integer"sv;
|
||||||
static constexpr auto is_digit = impl::is_hexadecimal_digit;
|
static constexpr auto is_digit = impl::is_hexadecimal_digit;
|
||||||
static constexpr auto is_signed = false;
|
static constexpr auto is_signed = false;
|
||||||
static constexpr auto min_buffer_length = 16; // strlen("7FFFFFFFFFFFFFFF")
|
static constexpr auto max_digits = 16; // strlen("7FFFFFFFFFFFFFFF")
|
||||||
static constexpr auto prefix_codepoint = U'x';
|
static constexpr auto prefix_codepoint = U'x';
|
||||||
static constexpr auto prefix = "x"sv;
|
static constexpr auto prefix = "x"sv;
|
||||||
|
static constexpr auto full_prefix = "0x"sv;
|
||||||
};
|
};
|
||||||
|
|
||||||
TOML_PURE_GETTER
|
TOML_PURE_GETTER
|
||||||
@ -12756,12 +12760,6 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
char first_integer_part = '\0';
|
char first_integer_part = '\0';
|
||||||
while (!is_eof() && !is_value_terminator(*cp))
|
while (!is_eof() && !is_value_terminator(*cp))
|
||||||
{
|
{
|
||||||
if TOML_UNLIKELY(length == sizeof(chars))
|
|
||||||
set_error_and_return_default("exceeds maximum length of "sv,
|
|
||||||
static_cast<uint64_t>(sizeof(chars)),
|
|
||||||
" characters"sv,
|
|
||||||
(seen_exponent ? ""sv : " (consider using exponent notation)"sv));
|
|
||||||
|
|
||||||
if (*cp == U'_')
|
if (*cp == U'_')
|
||||||
{
|
{
|
||||||
if (!prev || !is_decimal_digit(*prev))
|
if (!prev || !is_decimal_digit(*prev))
|
||||||
@ -12771,8 +12769,13 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
advance_and_return_if_error_or_eof({});
|
advance_and_return_if_error_or_eof({});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (prev && *prev == U'_' && !is_decimal_digit(*cp))
|
else if TOML_UNLIKELY(prev && *prev == U'_' && !is_decimal_digit(*cp))
|
||||||
set_error_and_return_default("underscores must be followed by digits"sv);
|
set_error_and_return_default("underscores must be followed by digits"sv);
|
||||||
|
else if TOML_UNLIKELY(length == sizeof(chars))
|
||||||
|
set_error_and_return_default("exceeds length limit of "sv,
|
||||||
|
static_cast<uint64_t>(sizeof(chars)),
|
||||||
|
" digits"sv,
|
||||||
|
(seen_exponent ? ""sv : " (consider using exponent notation)"sv));
|
||||||
else if (*cp == U'.')
|
else if (*cp == U'.')
|
||||||
{
|
{
|
||||||
// .1
|
// .1
|
||||||
@ -13107,10 +13110,8 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
|
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// consume value chars
|
// consume digits
|
||||||
static constexpr size_t underscore_padding = 32;
|
char digits[utf8_buffered_reader::max_history_length];
|
||||||
static constexpr size_t buffer_length = traits::min_buffer_length + underscore_padding;
|
|
||||||
char chars[buffer_length];
|
|
||||||
size_t length = {};
|
size_t length = {};
|
||||||
const utf8_codepoint* prev = {};
|
const utf8_codepoint* prev = {};
|
||||||
while (!is_eof() && !is_value_terminator(*cp))
|
while (!is_eof() && !is_value_terminator(*cp))
|
||||||
@ -13124,16 +13125,16 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
advance_and_return_if_error_or_eof({});
|
advance_and_return_if_error_or_eof({});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (prev && *prev == U'_' && !traits::is_digit(*cp))
|
else if TOML_UNLIKELY(prev && *prev == U'_' && !traits::is_digit(*cp))
|
||||||
set_error_and_return_default("underscores must be followed by digits"sv);
|
set_error_and_return_default("underscores must be followed by digits"sv);
|
||||||
else if (!traits::is_digit(*cp))
|
else if TOML_UNLIKELY(!traits::is_digit(*cp))
|
||||||
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
|
set_error_and_return_default("expected digit, saw '"sv, to_sv(*cp), "'"sv);
|
||||||
else if (length == sizeof(chars))
|
else if TOML_UNLIKELY(length == sizeof(digits))
|
||||||
set_error_and_return_default("exceeds maximum length of "sv,
|
set_error_and_return_default("exceeds length limit of "sv,
|
||||||
static_cast<uint64_t>(sizeof(chars)),
|
static_cast<uint64_t>(sizeof(digits)),
|
||||||
" characters"sv);
|
" digits"sv);
|
||||||
else
|
else
|
||||||
chars[length++] = static_cast<char>(cp->bytes[0]);
|
digits[length++] = static_cast<char>(cp->bytes[0]);
|
||||||
|
|
||||||
prev = cp;
|
prev = cp;
|
||||||
advance_and_return_if_error({});
|
advance_and_return_if_error({});
|
||||||
@ -13146,52 +13147,75 @@ TOML_IMPL_NAMESPACE_START
|
|||||||
set_error_and_return_default("underscores must be followed by digits"sv);
|
set_error_and_return_default("underscores must be followed by digits"sv);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for leading zeroes
|
|
||||||
if constexpr (base == 10)
|
|
||||||
{
|
|
||||||
if (chars[0] == '0')
|
|
||||||
set_error_and_return_default("leading zeroes are prohibited"sv);
|
|
||||||
}
|
|
||||||
|
|
||||||
// single digits can be converted trivially
|
// single digits can be converted trivially
|
||||||
if (length == 1u)
|
if (length == 1u)
|
||||||
{
|
{
|
||||||
|
int64_t result;
|
||||||
|
|
||||||
if constexpr (base == 16)
|
if constexpr (base == 16)
|
||||||
return static_cast<int64_t>(hex_to_dec(chars[0]));
|
result = static_cast<int64_t>(hex_to_dec(digits[0]));
|
||||||
else if constexpr (base <= 10)
|
else
|
||||||
return static_cast<int64_t>(chars[0] - '0');
|
result = static_cast<int64_t>(digits[0] - '0');
|
||||||
|
|
||||||
|
if constexpr (traits::is_signed)
|
||||||
|
result *= sign;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// otherwise do the thing
|
// bin, oct and hex allow leading zeroes so trim them first
|
||||||
uint64_t result = {};
|
const char* end = digits + length;
|
||||||
|
const char* msd = digits;
|
||||||
|
if constexpr (base != 10)
|
||||||
{
|
{
|
||||||
const char* msd = chars;
|
|
||||||
const char* end = msd + length;
|
|
||||||
while (msd < end && *msd == '0')
|
while (msd < end && *msd == '0')
|
||||||
msd++;
|
msd++;
|
||||||
if (msd == end)
|
if (msd == end)
|
||||||
return 0ll;
|
return 0ll;
|
||||||
uint64_t power = 1;
|
}
|
||||||
while (--end >= msd)
|
|
||||||
{
|
// decimal integers do not allow leading zeroes
|
||||||
if constexpr (base == 16)
|
else
|
||||||
result += power * hex_to_dec(*end);
|
{
|
||||||
else
|
if TOML_UNLIKELY(digits[0] == '0')
|
||||||
result += power * static_cast<uint64_t>(*end - '0');
|
set_error_and_return_default("leading zeroes are prohibited"sv);
|
||||||
power *= base;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// range check
|
// range check
|
||||||
if (result > static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()) + (sign < 0 ? 1ull : 0ull))
|
if TOML_UNLIKELY(static_cast<size_t>(end - msd) > traits::max_digits)
|
||||||
set_error_and_return_default("'"sv,
|
set_error_and_return_default("'"sv,
|
||||||
std::string_view{ chars, length },
|
traits::full_prefix,
|
||||||
|
std::string_view{ digits, length },
|
||||||
"' is not representable in 64 bits"sv);
|
"' is not representable in 64 bits"sv);
|
||||||
|
|
||||||
if constexpr (traits::is_signed)
|
// do the thing
|
||||||
return static_cast<int64_t>(result) * sign;
|
{
|
||||||
else
|
uint64_t result = {};
|
||||||
return static_cast<int64_t>(result);
|
{
|
||||||
|
uint64_t power = 1;
|
||||||
|
while (--end >= msd)
|
||||||
|
{
|
||||||
|
if constexpr (base == 16)
|
||||||
|
result += power * hex_to_dec(*end);
|
||||||
|
else
|
||||||
|
result += power * static_cast<uint64_t>(*end - '0');
|
||||||
|
|
||||||
|
power *= base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// range check
|
||||||
|
if TOML_UNLIKELY(result > static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()) + (sign < 0 ? 1ull : 0ull))
|
||||||
|
set_error_and_return_default("'"sv,
|
||||||
|
traits::full_prefix,
|
||||||
|
std::string_view{ digits, length },
|
||||||
|
"' is not representable in 64 bits"sv);
|
||||||
|
|
||||||
|
if constexpr (traits::is_signed)
|
||||||
|
return static_cast<int64_t>(result) * sign;
|
||||||
|
else
|
||||||
|
return static_cast<int64_t>(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TOML_NODISCARD
|
TOML_NODISCARD
|
||||||
|
Loading…
Reference in New Issue
Block a user