9#if !TOML_IMPLEMENTATION
10#error This is an implementation-only header.
27#if TOML_INT_CHARCONV || TOML_FLOAT_CHARCONV
30#if !TOML_INT_CHARCONV || !TOML_FLOAT_CHARCONV
45 class utf8_byte_stream;
50 template <
typename Char>
51 class utf8_byte_stream<
std::basic_string_view<Char>> {
52 static_assert(
sizeof(Char) == 1);
56 size_t position_ = {};
68 constexpr bool error() const noexcept {
return false; }
71 constexpr bool eof() const noexcept {
return position_ >= source_.length(); }
74 explicit constexpr operator bool() const noexcept {
return !eof(); }
77 constexpr bool peek_eof() const noexcept {
return eof(); }
81 size_t operator()(
void* dest,
size_t num) noexcept {
84 num = impl::min(position_ + num, source_.length()) - position_;
85 std::memcpy(dest, source_.data() + position_, num);
92 class utf8_byte_stream<
std::istream> {
103 const auto initial_pos = source_->tellg();
105 source_->read(bom, 3);
106 if (source_->bad() ||
111 source_->seekg(initial_pos, std::istream::beg);
115 bool error() const noexcept {
return !!(source_->rdstate() & std::istream::badbit); }
118 bool eof() const noexcept {
return !!(source_->rdstate() & std::istream::eofbit); }
121 explicit operator bool() const noexcept {
122 return !(source_->rdstate() & (std::istream::badbit | std::istream::eofbit));
127 return eof() || source_->peek() == std::istream::traits_type::eof();
135 source_->read(
static_cast<char*
>(dest),
static_cast<std::streamsize
>(num));
136 return static_cast<size_t>(source_->gcount());
147 constexpr operator const char32_t&()
const noexcept {
return value; }
152 static_assert(std::is_trivial_v<utf8_codepoint>);
153 static_assert(std::is_standard_layout_v<utf8_codepoint>);
168 virtual optional<parse_error>&&
error() noexcept = 0;
176#define utf8_reader_error(...) throw parse_error(__VA_ARGS__)
177#define utf8_reader_return_after_error(...) static_assert(true)
178#define utf8_reader_error_check(...) static_assert(true)
180#define utf8_reader_error(...) err_.emplace(__VA_ARGS__)
181#define utf8_reader_return_after_error(...) return __VA_ARGS__
182#define utf8_reader_error_check(...) \
184 if TOML_UNLIKELY (err_) return __VA_ARGS__; \
189#if defined(__APPLE__) || defined(__MINGW32__) || defined(__MINGW64__)
190#define TOML_OVERALIGNED
192#define TOML_OVERALIGNED alignas(32)
195 template <
typename T>
198 static constexpr size_t block_capacity = 32;
206 } currently_decoding_;
224 size_t raw_bytes_read;
227 if constexpr (
noexcept(stream_(raw_bytes, block_capacity)) || !
TOML_EXCEPTIONS) {
228 raw_bytes_read = stream_(raw_bytes, block_capacity);
233 raw_bytes_read = stream_(raw_bytes, block_capacity);
234 }
catch (
const std::exception& exc) {
235 throw parse_error{exc.what(), next_pos_, source_path_};
237 throw parse_error{
"An unspecified error occurred", next_pos_, source_path_};
248 if (decoder_.needs_more_input())
250 next_pos_, source_path_);
253 next_pos_, source_path_);
259 std::memset(&codepoints_, 0,
sizeof(codepoints_));
262 const auto calc_positions = [&]()
noexcept {
263 for (
size_t i = 0; i < codepoints_.count; i++) {
264 auto& cp = codepoints_.buffer[i];
265 cp.position = next_pos_;
269 next_pos_.
column = source_index{1};
277 const auto ascii_fast_path =
278 !decoder_.needs_more_input() && impl::is_ascii(raw_bytes, raw_bytes_read);
281 if (ascii_fast_path) {
283 currently_decoding_.count = {};
285 codepoints_.count = raw_bytes_read;
286 for (
size_t i = 0; i < codepoints_.count; i++) {
287 auto& cp = codepoints_.buffer[i];
288 cp.value =
static_cast<char32_t>(raw_bytes[i]);
289 cp.bytes[0] = raw_bytes[i];
298 return codepoints_.count ? codepoints_.buffer[codepoints_.count - 1u].position
302 for (
size_t i = 0; i < raw_bytes_read; i++) {
303 decoder_(
static_cast<uint8_t
>(raw_bytes[i]));
306 utf8_reader_error(
"Encountered invalid utf-8 sequence", error_pos(), source_path_);
310 currently_decoding_.bytes[currently_decoding_.count++] = raw_bytes[i];
312 if (decoder_.has_code_point()) {
313 auto& cp = codepoints_.buffer[codepoints_.count++];
315 cp.value = decoder_.codepoint;
316 cp.count = currently_decoding_.count;
317 std::memcpy(cp.bytes, currently_decoding_.bytes, currently_decoding_.count);
318 currently_decoding_.count = {};
321 utf8_reader_error(
"Encountered overlong utf-8 sequence", error_pos(), source_path_);
325 if TOML_UNLIKELY (decoder_.needs_more_input() && stream_.eof()) {
328 error_pos(), source_path_);
339 utf8_reader_error(
"An I/O error occurred while reading from the underlying stream",
340 next_pos_, source_path_);
348 template <
typename U,
typename String = std::
string_view>
350 std::is_nothrow_constructible_v<utf8_byte_stream<T>, U&&>)
351 : stream_{static_cast<U&&>(source)} {
352 currently_decoding_.count = {};
354 codepoints_.current = {};
355 codepoints_.count = {};
357 if (!source_path.empty())
358 source_path_ = std::make_shared<const std::string>(
static_cast<String&&
>(source_path));
368 if (codepoints_.current == codepoints_.count) {
369 if TOML_UNLIKELY (!stream_ || !read_next_block())
return nullptr;
377 return &codepoints_.buffer[codepoints_.current++];
382 return stream_.peek_eof();
388 optional<parse_error>&&
error() noexcept final {
return std::move(err_); }
393 template <
typename Char>
396 template <
typename Char>
399 template <
typename Char>
401 template <
typename Char>
405#define utf8_buffered_reader_error_check(...) static_assert(true)
407#define utf8_buffered_reader_error_check(...) \
409 if TOML_UNLIKELY (reader_.error()) return __VA_ARGS__; \
416 static constexpr size_t max_history_length = 128;
419 static constexpr size_t history_buffer_size =
420 max_history_length - 1;
427 size_t negative_offset_ = {};
441 if (negative_offset_) {
445 if (!negative_offset_)
return head_;
449 return history_.buffer +
450 ((history_.first + history_.count - negative_offset_) % history_buffer_size);
458 history_.buffer[history_.count++] = *head_;
460 history_.buffer[(history_.first++ + history_buffer_size) % history_buffer_size] =
477 negative_offset_ += count;
479 return negative_offset_
481 ((history_.first + history_.count - negative_offset_) % history_buffer_size)
491 optional<parse_error>&&
error() noexcept {
return reader_.
error(); }
503#define TOML_RETURNS_BY_THROWING [[noreturn]]
505#define TOML_RETURNS_BY_THROWING
509 template <
typename... T>
511 T... vals)
noexcept {
512 static_assert((std::is_same_v<char32_t, T> && ...));
513 return ((codepoint == vals) || ...);
517 struct parse_integer_traits;
519 struct parse_integer_traits<2> {
520 static constexpr auto scope_qualifier =
"binary integer"sv;
521 static constexpr auto is_digit = impl::is_binary_digit;
522 static constexpr auto is_signed =
false;
523 static constexpr auto max_digits = 63;
524 static constexpr auto prefix_codepoint = U
'b';
525 static constexpr auto prefix =
"b"sv;
526 static constexpr auto full_prefix =
"0b"sv;
529 struct parse_integer_traits<8> {
530 static constexpr auto scope_qualifier =
"octal integer"sv;
531 static constexpr auto is_digit = impl::is_octal_digit;
532 static constexpr auto is_signed =
false;
533 static constexpr auto max_digits = 21;
534 static constexpr auto prefix_codepoint = U
'o';
535 static constexpr auto prefix =
"o"sv;
536 static constexpr auto full_prefix =
"0o"sv;
539 struct parse_integer_traits<10> {
540 static constexpr auto scope_qualifier =
"decimal integer"sv;
541 static constexpr auto is_digit = impl::is_decimal_digit;
542 static constexpr auto is_signed =
true;
543 static constexpr auto max_digits = 19;
544 static constexpr auto full_prefix =
""sv;
547 struct parse_integer_traits<16> {
548 static constexpr auto scope_qualifier =
"hexadecimal integer"sv;
549 static constexpr auto is_digit = impl::is_hexadecimal_digit;
550 static constexpr auto is_signed =
false;
551 static constexpr auto max_digits = 16;
552 static constexpr auto prefix_codepoint = U
'x';
553 static constexpr auto prefix =
"x"sv;
554 static constexpr auto full_prefix =
"0x"sv;
559 std::string_view
to_sv(node_type val)
noexcept {
560 return impl::node_type_friendly_names[impl::unwrap_enum(val)];
565 std::string_view
to_sv(
const std::string& str)
noexcept {
566 return std::string_view{str};
571 std::string_view
to_sv(
bool val)
noexcept {
572 using namespace std::string_view_literals;
574 return val ?
"true"sv :
"false"sv;
580 if (cp.value <= U
'\x1F')
581 return impl::control_char_escapes[cp.value];
582 else if (cp.value == U
'\x7F')
585 return std::string_view{cp.bytes, cp.count};
591 if (cp)
return to_sv(*cp);
599 template <
typename T>
602 const T& arg) noexcept {
605 using arg_type = impl::remove_cvref<T>;
608 if constexpr (std::is_same_v<arg_type, std::string_view>) {
609 const auto max_chars =
static_cast<size_t>(buf_end - write_pos);
610 const auto len = max_chars < arg.length() ? max_chars : arg.length();
611 std::memcpy(write_pos, arg.data(), len);
616 else if constexpr (std::is_same_v<arg_type, double>) {
617#if TOML_FLOAT_CHARCONV
618 const auto result = std::to_chars(write_pos, buf_end, arg);
619 write_pos = result.ptr;
621 std::ostringstream ss;
622 ss.imbue(std::locale::classic());
623 ss.precision(std::numeric_limits<arg_type>::max_digits10);
630 else if constexpr (impl::is_one_of<arg_type, int64_t, uint64_t>) {
632 const auto result = std::to_chars(write_pos, buf_end, arg);
633 write_pos = result.ptr;
635 std::ostringstream ss;
636 ss.imbue(std::locale::classic());
637 using cast_type = std::conditional_t<std::is_signed_v<arg_type>, int64_t, uint64_t>;
638 ss << static_cast<cast_type>(arg);
644 else if constexpr (std::is_same_v<arg_type, escaped_codepoint>) {
645 if (arg.cp.value <= U
'\x7F')
648 auto val =
static_cast<uint_least32_t
>(arg.cp.value);
649 const auto digits = val > 0xFFFFu ? 8u : 4u;
650 constexpr auto mask = uint_least32_t{0xFu};
651 char buf[10] = {
'\\', digits > 4 ?
'U' :
'u'};
652 for (
auto i = 2u + digits; i-- > 2u;) {
653 const auto hexdig = val & mask;
654 buf[i] =
static_cast<char>(hexdig >= 0xAu ? (
'A' + (hexdig - 0xAu)) : (
'0' + hexdig));
657 concatenate(write_pos, buf_end, std::string_view{buf, digits + 2u});
662 else if constexpr (std::is_floating_point_v<arg_type>)
663 concatenate(write_pos, buf_end,
static_cast<double>(arg));
666 else if constexpr (std::is_arithmetic_v<arg_type> && std::is_integral_v<arg_type>) {
667 using cast_type = std::conditional_t<std::is_unsigned_v<arg_type>, uint64_t, int64_t>;
668 concatenate(write_pos, buf_end,
static_cast<cast_type
>(arg));
672 static_assert(impl::always_false<T>,
673 "concatenate() inputs are limited to std::string_views, integers, floats, and "
674 "escaped_codepoint");
691 template <
typename T>
701 throw parse_error{
buf, pos, source_path};
703 return parse_error{std::string(
buf,
static_cast<size_t>(
write_pos -
buf)), pos, source_path};
715 explicit parse_scope(std::string_view& current_scope, std::string_view new_scope) noexcept
724#define push_parse_scope_2(scope, line) parse_scope ps_##line(current_scope, scope)
725#define push_parse_scope_1(scope, line) push_parse_scope_2(scope, line)
726#define push_parse_scope(scope) push_parse_scope_1(scope, __LINE__)
732 std::vector<source_position>
ends;
754 std::string_view
back() const noexcept {
return (*
this)[
segments.size() - 1u]; }
809#define assert_not_eof() TOML_ASSERT_ASSUME(cp != nullptr)
810#define return_if_eof(...) \
812 if TOML_UNLIKELY (is_eof()) return __VA_ARGS__; \
816#define is_error() false
817#define return_after_error(...) TOML_UNREACHABLE
818#define assert_not_error() static_assert(true)
819#define return_if_error(...) static_assert(true)
820#define return_if_error_or_eof(...) return_if_eof(__VA_ARGS__)
822#define is_error() !!err
823#define return_after_error(...) return __VA_ARGS__
824#define assert_not_error() TOML_ASSERT(!is_error())
825#define return_if_error(...) \
827 if TOML_UNLIKELY (is_error()) return __VA_ARGS__; \
829#define return_if_error_or_eof(...) \
831 if TOML_UNLIKELY (is_eof() || is_error()) return __VA_ARGS__; \
835#if defined(TOML_BREAK_AT_PARSE_ERRORS) && TOML_BREAK_AT_PARSE_ERRORS
836#if defined(__has_builtin)
837#if __has_builtin(__builtin_debugtrap)
838#define parse_error_break() __builtin_debugtrap()
839#elif __has_builtin(__debugbreak)
840#define parse_error_break() __debugbreak()
843#ifndef parse_error_break
844#if TOML_MSVC || TOML_ICC
845#define parse_error_break() __debugbreak()
847#define parse_error_break() TOML_ASSERT(false)
851#define parse_error_break() static_assert(true)
854#define set_error_and_return(ret, ...) \
856 if (!is_error()) set_error(__VA_ARGS__); \
857 return_after_error(ret); \
860#define set_error_and_return_default(...) set_error_and_return({}, __VA_ARGS__)
862#define set_error_and_return_if_eof(...) \
864 if TOML_UNLIKELY (is_eof()) set_error_and_return(__VA_ARGS__, "encountered end-of-file"sv); \
867#define advance_and_return_if_error(...) \
871 return_if_error(__VA_ARGS__); \
874#define advance_and_return_if_error_or_eof(...) \
878 return_if_error(__VA_ARGS__); \
879 set_error_and_return_if_eof(__VA_ARGS__); \
906 mutable optional<parse_error>
err;
915 template <
typename... T>
917 const T&... reason)
const {
918 static_assert(
sizeof...(T) > 0);
922 (builder.append(reason), ...);
933 template <
typename... T>
982 else if (pop_bytes == 1u)
994 bool consumed =
false;
995 while (!
is_eof() && is_horizontal_whitespace(*
cp)) {
1011 R
"(vertical tabs '\v' and form-feeds '\f' are not legal line breaks in TOML)"sv);
1022 }
else if (*
cp != U
'\n')
1033 if (is_ascii_vertical_whitespace(*
cp))
1046 if (*
cp != U
'#')
return false;
1056#if TOML_LANG_AT_LEAST(1, 0, 0)
1061 "control characters other than TAB (U+0009) are explicitly prohibited in comments"sv);
1066 "unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited in comments"sv);
1080 for (
auto c : seq) {
1082 if (*
cp != c)
return false;
1088 template <
typename T>
1094 for (
size_t i = 0; i < len; i++) {
1096 if (!is_decimal_digit(*
cp))
return false;
1098 digits[i] =
static_cast<T
>(*
cp - U
'0');
1104 template <
typename T>
1111 for (; i < max_len; i++) {
1112 if (
is_eof() || !is_decimal_digit(*
cp))
break;
1114 buffer[i] =
static_cast<T
>(*
cp - U
'0');
1140 bool escaped =
false;
1141 bool skipping_whitespace =
false;
1147 if (multi_line && is_whitespace(*
cp)) {
1152 "line-ending backslashes must be the last non-whitespace character on the line"sv);
1154 skipping_whitespace =
true;
1159 bool skip_escaped_codepoint =
true;
1185#if TOML_LANG_UNRELEASED
1192 "escape sequence '\\e' is not supported in TOML 1.0.0 and earlier"sv);
1195#if TOML_LANG_UNRELEASED
1201 "escape sequence '\\x' is not supported in TOML 1.0.0 and earlier"sv);
1210 skip_escaped_codepoint =
false;
1215 uint32_t sequence_value{};
1216 while (place_value) {
1222 sequence_value += place_value * hex_to_dec(*
cp);
1229 "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
1233 if (sequence_value < 0x80) {
1234 str +=
static_cast<char>(sequence_value);
1235 }
else if (sequence_value < 0x800u) {
1236 str +=
static_cast<char>((sequence_value >> 6) | 0xC0u);
1237 str +=
static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
1238 }
else if (sequence_value < 0x10000u) {
1239 str +=
static_cast<char>((sequence_value >> 12) | 0xE0u);
1240 str +=
static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
1241 str +=
static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
1242 }
else if (sequence_value < 0x110000u) {
1243 str +=
static_cast<char>((sequence_value >> 18) | 0xF0u);
1244 str +=
static_cast<char>(((sequence_value >> 12) & 0x3Fu) | 0x80u);
1245 str +=
static_cast<char>(((sequence_value >> 6) & 0x3Fu) | 0x80u);
1246 str +=
static_cast<char>((sequence_value & 0x3Fu) | 0x80u);
1262 size_t lookaheads = {};
1263 size_t consecutive_delimiters = 1;
1268 consecutive_delimiters++;
1271 }
while (lookaheads < 4u);
1273 switch (consecutive_delimiters) {
1277 skipping_whitespace =
false;
1282 str.append(
"\"\""sv);
1283 skipping_whitespace =
false;
1297 str.append(
"\"\""sv);
1311 else if (*
cp == U
'\\') {
1313 skipping_whitespace =
false;
1319 if (multi_line && is_ascii_vertical_whitespace(*
cp)) {
1322 if (!skipping_whitespace) str +=
'\n';
1329 "unescaped control characters other than TAB (U+0009) are explicitly prohibited"sv);
1331#if TOML_LANG_AT_LEAST(1, 0, 0)
1336 "unescaped unicode surrogates (U+D800 to U+DFFF) are explicitly prohibited"sv);
1340 if (!skipping_whitespace || !is_horizontal_whitespace(*
cp)) {
1341 skipping_whitespace =
false;
1380 size_t lookaheads = {};
1381 size_t consecutive_delimiters = 1;
1386 consecutive_delimiters++;
1389 }
while (lookaheads < 4u);
1391 switch (consecutive_delimiters) {
1427 if (multi_line && is_ascii_vertical_whitespace(*
cp)) {
1437 "control characters other than TAB (U+0009) are explicitly prohibited"sv);
1439#if TOML_LANG_AT_LEAST(1, 0, 0)
1444 "unicode surrogates (U+D800 - U+DFFF) are explicitly prohibited"sv);
1465 const auto second =
cp->
value;
1467 const auto third =
cp ?
cp->
value : U
'\0';
1472 if (second == first)
return {};
1479 else if (first == second && first == third) {
1503 if (!is_bare_key_character(*
cp))
break;
1521 auto result = is_match(*
cp, U
't', U
'T');
1527 if (
cp && !is_value_terminator(*
cp))
1542 const bool negative = *
cp == U
'-';
1545 const bool inf = is_match(*
cp, U
'i', U
'I');
1551 if (
cp && !is_value_terminator(*
cp))
1554 return inf ? (negative ? -std::numeric_limits<double>::infinity()
1555 : std::numeric_limits<double>::infinity())
1556 : std::numeric_limits<double>::quiet_NaN();
1568 const int sign = *
cp == U
'-' ? -1 : 1;
1575 bool seen_decimal =
false, seen_exponent =
false;
1576 char first_integer_part =
'\0';
1577 while (!
is_eof() && !is_value_terminator(*
cp)) {
1579 if (!prev || !is_decimal_digit(*prev))
1585 }
else if TOML_UNLIKELY (prev && *prev == U
'_' && !is_decimal_digit(*
cp))
1589 "exceeds length limit of "sv,
sizeof(chars),
" digits"sv,
1590 (seen_exponent ?
""sv :
" (consider using exponent notation)"sv));
1591 else if (*
cp == U
'.') {
1595 if (!first_integer_part)
1599 else if (seen_exponent)
1605 else if (seen_decimal)
1608 seen_decimal =
true;
1609 }
else if (is_match(*
cp, U
'e', U
'E')) {
1610 if (prev && !is_decimal_digit(*prev))
1614 else if (seen_exponent)
1617 seen_decimal =
true;
1618 seen_exponent =
true;
1619 }
else if (is_match(*
cp, U
'+', U
'-')) {
1626 else if (!is_match(*prev, U
'e', U
'E'))
1628 }
else if (is_decimal_digit(*
cp)) {
1629 if (!seen_decimal) {
1630 if (!first_integer_part)
1631 first_integer_part =
static_cast<char>(
cp->
bytes[0]);
1632 else if (first_integer_part ==
'0')
1638 chars[length++] =
static_cast<char>(
cp->
bytes[0]);
1645 if (*prev == U
'_') {
1648 }
else if (is_match(*prev, U
'e', U
'E', U
'+', U
'-', U
'.')) {
1656#if TOML_FLOAT_CHARCONV
1658 auto fc_result = std::from_chars(chars, chars + length, result);
1659 switch (fc_result.ec) {
1662 return result * sign;
1664 case std::errc::invalid_argument:
1666 "' could not be interpreted as a value"sv);
1669 case std::errc::result_out_of_range:
1671 "' is not representable in 64 bits"sv);
1676 "an unspecified error occurred while trying to interpret '"sv,
1677 std::string_view{chars, length},
"' as a value"sv);
1682 std::stringstream ss;
1683 ss.imbue(std::locale::classic());
1684 ss.write(chars,
static_cast<std::streamsize
>(length));
1686 return result * sign;
1689 "' could not be interpreted as a value"sv);
1702#if TOML_LANG_UNRELEASED
1705 const int sign = *
cp == U
'-' ? -1 : 1;
1713 if (!is_match(*
cp, U
'x', U
'X'))
1725 fragment fragments[] = {
1730 fragment* current_fragment = fragments;
1732 int exponent_sign = 1;
1733 while (!
is_eof() && !is_value_terminator(*
cp)) {
1735 if (!prev || !is_hexadecimal_digit(*prev))
1741 }
else if (prev && *prev == U
'_' && !is_hexadecimal_digit(*
cp))
1743 else if (*
cp == U
'.') {
1745 if (current_fragment == fragments + 2)
1749 else if (current_fragment == fragments + 1)
1754 }
else if (is_match(*
cp, U
'p', U
'P')) {
1756 if (current_fragment == fragments + 2)
1761 else if (fragments[0].length == 0u && fragments[1].length == 0u)
1765 current_fragment = fragments + 2;
1766 }
else if (is_match(*
cp, U
'+', U
'-')) {
1768 if (current_fragment != fragments + 2)
1773 else if (!is_match(*prev, U
'p', U
'P'))
1777 exponent_sign = *
cp == U
'-' ? -1 : 1;
1778 }
else if (current_fragment < fragments + 2 && !is_hexadecimal_digit(*
cp))
1781 else if (current_fragment == fragments + 2 && !is_decimal_digit(*
cp))
1784 else if (current_fragment->length ==
sizeof(fragment::chars))
1786 sizeof(fragment::chars),
" characters"sv);
1788 current_fragment->chars[current_fragment->length++] =
static_cast<char>(
cp->
bytes[0]);
1795 if (current_fragment != fragments + 2 || current_fragment->length == 0u) {
1798 }
else if (prev && *prev == U
'_') {
1804 for (
int fragment_idx = 0; fragment_idx < 3; fragment_idx++) {
1805 auto& f = fragments[fragment_idx];
1806 const uint32_t base = fragment_idx == 2 ? 10u : 16u;
1809 const char* c = f.chars;
1811 while (f.length && *c ==
'0') {
1816 if (!f.length)
continue;
1820 for (
size_t i = 0; i < f.length - 1u; i++) place *= base;
1824 val += place * hex_to_dec(*c);
1826 val += place *
static_cast<uint32_t
>(*c -
'0');
1827 if (fragment_idx == 1) sig++;
1831 f.value =
static_cast<double>(val);
1834 if (fragment_idx == 1) {
1835 while (sig--) f.value /= base;
1839 return (fragments[0].value + fragments[1].value) *
1840 pow(2.0, fragments[2].value * exponent_sign) * sign;
1845 "hexadecimal floating-point values are not supported "
1846 "in TOML 1.0.0 and earlier"sv);
1851 template <u
int64_t base>
1855 using traits = parse_integer_traits<base>;
1858 [[maybe_unused]] int64_t sign = 1;
1859 if constexpr (traits::is_signed) {
1860 sign = *
cp == U
'-' ? -1 : 1;
1864 if constexpr (base == 10) {
1865 if (!traits::is_digit(*
cp))
1874 if (*
cp != traits::prefix_codepoint)
1879 if (!traits::is_digit(*
cp))
1887 while (!
is_eof() && !is_value_terminator(*
cp)) {
1889 if (!prev || !traits::is_digit(*prev))
1895 }
else if TOML_UNLIKELY (prev && *prev == U
'_' && !traits::is_digit(*
cp))
1902 digits[length++] =
static_cast<char>(
cp->
bytes[0]);
1909 if (prev && *prev == U
'_') {
1918 if constexpr (base == 16)
1919 result =
static_cast<int64_t
>(hex_to_dec(digits[0]));
1921 result =
static_cast<int64_t
>(digits[0] -
'0');
1923 if constexpr (traits::is_signed) result *= sign;
1929 const char* end = digits + length;
1930 const char* msd = digits;
1931 if constexpr (base != 10) {
1932 while (msd < end && *msd ==
'0') msd++;
1933 if (msd == end)
return 0ll;
1943 if TOML_UNLIKELY (
static_cast<size_t>(end - msd) > traits::max_digits)
1945 "' is not representable in 64 bits"sv);
1949 uint64_t result = {};
1952 while (--end >= msd) {
1953 if constexpr (base == 16)
1954 result += power * hex_to_dec(*end);
1956 result += power *
static_cast<uint64_t
>(*end -
'0');
1963 static constexpr auto i64_max =
1964 static_cast<uint64_t
>((std::numeric_limits<int64_t>::max)());
1967 "' is not representable in 64 bits"sv);
1969 if constexpr (traits::is_signed) {
1972 return (std::numeric_limits<int64_t>::min)();
1974 return static_cast<int64_t
>(result) * sign;
1976 return static_cast<int64_t
>(result);
1992 const auto year = digits[3] + digits[2] * 10u + digits[1] * 100u + digits[0] * 1000u;
1993 const auto is_leap_year = (year % 4u == 0u) && ((year % 100u != 0u) || (year % 400u == 0u));
2003 const auto month = digits[1] + digits[0] * 10u;
2004 if (month == 0u || month > 12u)
2006 const auto max_days_in_month =
2007 month == 2u ? (is_leap_year ? 29u : 28u)
2008 : (month == 4u || month == 6u || month == 9u || month == 11u ? 30u : 31u);
2018 const auto day = digits[1] + digits[0] * 10u;
2019 if (day == 0u || day > max_days_in_month)
2021 " (inclusive), saw "sv, day);
2023 if (!part_of_datetime && !
is_eof() && !is_value_terminator(*
cp))
2026 return {year, month, day};
2037 static constexpr size_t max_digits = 64;
2039 uint32_t digits[max_digits];
2044 const auto hour = digits[1] + digits[0] * 10u;
2056 const auto minute = digits[1] + digits[0] * 10u;
2060 auto time = toml::time{hour, minute};
2065 if (
is_eof() || is_value_terminator(*
cp) ||
2066 (part_of_datetime && is_match(*
cp, U
'+', U
'-', U
'Z', U
'z')))
2076 const auto second = digits[1] + digits[0] * 10u;
2083 if (
is_eof() || is_value_terminator(*
cp) ||
2084 (part_of_datetime && is_match(*
cp, U
'+', U
'-', U
'Z', U
'z')))
2095 if (digit_count == max_digits && is_decimal_digit(*
cp))
2098 else if (!part_of_datetime && !is_value_terminator(*
cp))
2101 uint32_t value = 0u;
2102 uint32_t place = 1u;
2103 for (
auto i = impl::min<size_t>(digit_count, 9u); i-- > 0u;) {
2104 value += digits[i] * place;
2107 for (
auto i = digit_count; i < 9u; i++)
2126 if (!is_match(*
cp, U
' ', U
'T', U
't'))
2135 if (
is_eof() || is_value_terminator(*
cp))
return {date,
time};
2142 else if (is_match(*
cp, U
'+', U
'-')) {
2146 int sign = *
cp == U
'-' ? -1 : 1;
2153 const auto hour = digits[1] + digits[0] * 10;
2165 const auto minute = digits[1] + digits[0] * 10;
2169 offset.minutes =
static_cast<decltype(offset.minutes)
>((hour * 60 + minute) * sign);
2172 if (!
is_eof() && !is_value_terminator(*
cp))
2175 return {date,
time, offset};
2211 const auto cp_upper =
static_cast<uint_least32_t
>(
cp->
value) & ~0x20u;
2214 if (cp_upper == 70u || cp_upper == 84u)
2218 else if (cp_upper == 73u || cp_upper == 78u)
2238 " (TOML_MAX_NESTED_VALUES)"sv);
2247 else if (*
cp == U
'_')
2279 has_minus = 1 << 10,
2281 begins_sign = 1 << 12,
2282 begins_digit = 1 << 13,
2283 begins_zero = 1 << 14,
2285 signs_msk = has_plus | has_minus,
2286 bdigit_msk = has_digits | begins_digit,
2287 bzero_msk = bdigit_msk | begins_zero,
2289 value_traits traits = has_nothing;
2290 const auto has_any = [&](
auto t)
noexcept {
return (traits & t) != has_nothing; };
2291 const auto has_none = [&](
auto t)
noexcept {
return (traits & t) == has_nothing; };
2292 const auto add_trait = [&](
auto t)
noexcept {
2293 traits =
static_cast<value_traits
>(traits | t);
2298 if (is_decimal_digit(*
cp)) {
2299 add_trait(begins_digit);
2300 if (*
cp == U
'0') add_trait(begins_zero);
2301 }
else if (is_match(*
cp, U
'+', U
'-'))
2302 add_trait(begins_sign);
2308 size_t char_count = {}, advance_count = {};
2309 bool eof_while_scanning =
false;
2315 if (
const auto c = **
cp; c != U
'_') {
2316 chars[char_count++] = c;
2318 if (is_decimal_digit(c))
2319 add_trait(has_digits);
2320 else if (is_ascii_letter(c)) {
2322 switch (
static_cast<char32_t>(c | 32u)) {
2324 if (char_count == 2u && has_any(begins_zero)) add_trait(has_b);
2328 if (char_count > 1u &&
2329 has_none(has_b | has_o | has_p | has_t | has_x | has_z | has_colon) &&
2330 (has_none(has_plus | has_minus) || has_any(begins_sign)))
2335 if (char_count == 2u && has_any(begins_zero)) add_trait(has_o);
2339 if (has_any(has_x)) add_trait(has_p);
2343 if ((char_count == 2u && has_any(begins_zero)) ||
2344 (char_count == 3u && has_any(begins_sign) && chars[1] == U
'0'))
2355 }
else if (c <= U
':') {
2359 add_trait(has_plus);
2362 add_trait(has_minus);
2368 add_trait(has_colon);
2376 eof_while_scanning =
is_eof();
2378 !is_value_terminator(*
cp));
2384 if (char_count == 10u
2385 && (traits | begins_zero) == (bzero_msk | has_minus)
2390 const auto pre_advance_count = advance_count;
2391 const auto pre_scan_traits = traits;
2392 chars[char_count++] = *
cp;
2395 const auto backpedal = [&]()
noexcept {
2396 go_back(advance_count - pre_advance_count);
2397 advance_count = pre_advance_count;
2398 traits = pre_scan_traits;
2405 if (
is_eof() || !is_decimal_digit(*
cp))
2408 chars[char_count++] = *
cp;
2416 if (char_count == 12u) backpedal();
2425 if (char_count == 1u) {
2426 if (has_any(begins_digit)) {
2427 val.reset(
new value{
static_cast<int64_t
>(chars[0] - U
'0')});
2435 :
"could not determine value type"sv);
2447 else if (has_any(has_x | has_o | has_b)) {
2450 if (has_any(has_x)) {
2451 i = parse_integer<16>();
2452 flags = value_flags::format_as_hexadecimal;
2453 }
else if (has_any(has_o)) {
2454 i = parse_integer<8>();
2455 flags = value_flags::format_as_octal;
2458 i = parse_integer<2>();
2459 flags = value_flags::format_as_binary;
2463 val.reset(
new value{i});
2464 val->ref_cast<int64_t>().flags(flags);
2465 }
else if (has_any(has_e) || (has_any(begins_digit) && chars[1] == U
'.'))
2467 else if (has_any(begins_sign)) {
2469 if (char_count == 2u && has_any(has_digits)) {
2471 new value{
static_cast<int64_t
>(chars[1] - U
'0') * (chars[0] == U
'-' ? -1LL : 1LL)});
2478 if (is_decimal_digit(chars[1]) && chars[2] == U
'.') val.reset(
new value{
parse_float()});
2481 else if (is_match(chars[1], U
'i', U
'n', U
'I', U
'N'))
2492 switch (unwrap_enum(traits)) {
2495 case bzero_msk | has_b:
2496 val.reset(
new value{parse_integer<2>()});
2497 val->ref_cast<int64_t>().flags(value_flags::format_as_binary);
2502 case bzero_msk | has_o:
2503 val.reset(
new value{parse_integer<8>()});
2504 val->ref_cast<int64_t>().flags(value_flags::format_as_octal);
2516 case begins_sign | has_digits | has_minus:
2518 case begins_sign | has_digits | has_plus: {
2524 static constexpr size_t max_numeric_value_length =
2526 if TOML_UNLIKELY (!eof_while_scanning && advance_count > max_numeric_value_length)
2528 "numeric value too long to identify type - cannot exceed "sv,
2529 max_numeric_value_length,
" characters"sv);
2531 val.reset(
new value{parse_integer<10>()});
2537 case bzero_msk | has_x:
2538 val.reset(
new value{parse_integer<16>()});
2539 val->ref_cast<int64_t>().flags(value_flags::format_as_hexadecimal);
2550 case bzero_msk | has_e:
2552 case bzero_msk | has_e | has_minus:
2554 case bzero_msk | has_e | has_plus:
2556 case bzero_msk | has_dot:
2558 case bzero_msk | has_dot | has_e:
2560 case bzero_msk | has_dot | has_e | has_minus:
2562 case bzero_msk | has_dot | has_e | has_plus:
2571 case bdigit_msk | has_e:
2573 case bdigit_msk | has_e | has_minus:
2575 case bdigit_msk | has_e | has_plus:
2577 case bdigit_msk | has_dot:
2579 case bdigit_msk | has_dot | has_e:
2581 case bdigit_msk | has_dot | has_e | has_minus:
2583 case bdigit_msk | has_dot | has_e | has_plus:
2591 case begins_sign | has_digits | has_e | has_plus:
2593 case begins_sign | has_digits | has_dot | has_plus:
2595 case begins_sign | has_digits | has_dot | has_e | has_plus:
2597 case begins_sign | has_digits | has_dot | has_e | signs_msk:
2605 case begins_sign | has_digits | has_e | has_minus:
2607 case begins_sign | has_digits | has_e | signs_msk:
2609 case begins_sign | has_digits | has_dot | has_minus:
2611 case begins_sign | has_digits | has_dot | has_e | has_minus:
2619 case bzero_msk | has_x | has_p:
2621 case bzero_msk | has_x | has_p | has_minus:
2623 case bzero_msk | has_x | has_p | has_plus:
2631 case begins_sign | has_digits | has_x | has_p | has_minus:
2633 case begins_sign | has_digits | has_x | has_p | has_plus:
2635 case begins_sign | has_digits | has_x | has_p | signs_msk:
2640 case bzero_msk | has_x | has_dot | has_p:
2642 case bzero_msk | has_x | has_dot | has_p | has_minus:
2644 case bzero_msk | has_x | has_dot | has_p | has_plus:
2652 case begins_sign | has_digits | has_x | has_dot | has_p | has_minus:
2654 case begins_sign | has_digits | has_x | has_dot | has_p | has_plus:
2656 case begins_sign | has_digits | has_x | has_dot | has_p | signs_msk:
2664 case bzero_msk | has_colon:
2666 case bzero_msk | has_colon | has_dot:
2668 case bdigit_msk | has_colon:
2670 case bdigit_msk | has_colon | has_dot:
2676 case bzero_msk | has_minus:
2678 case bdigit_msk | has_minus:
2695 case bzero_msk | has_minus | has_colon | has_t:
2697 case bzero_msk | signs_msk | has_colon | has_t:
2699 case bdigit_msk | has_minus | has_colon | has_t:
2701 case bdigit_msk | signs_msk | has_colon | has_t:
2709 case bzero_msk | has_minus | has_colon | has_dot | has_t:
2711 case bzero_msk | signs_msk | has_colon | has_dot | has_t:
2713 case bdigit_msk | has_minus | has_colon | has_dot | has_t:
2715 case bdigit_msk | signs_msk | has_colon | has_dot | has_t:
2723 case bzero_msk | has_minus | has_colon | has_z | has_t:
2725 case bzero_msk | has_minus | has_colon | has_dot | has_z | has_t:
2727 case bdigit_msk | has_minus | has_colon | has_z | has_t:
2729 case bdigit_msk | has_minus | has_colon | has_dot | has_z | has_t:
2736 set_error_at(begin_pos,
"could not determine value type"sv);
2752 recording_whitespace =
false;
2755 std::string_view key_segment;
2756 const auto key_begin = current_position();
2759 if (is_bare_key_character(*cp)) key_segment = parse_bare_key_segment();
2762 else if (is_string_delimiter(*cp)) {
2763 const auto begin_pos = cp->
position;
2765 recording_whitespace =
true;
2767 recording_whitespace =
false;
2771 set_error_at(begin_pos,
"multi-line strings are prohibited in "sv,
2772 key_buffer.
empty() ?
""sv :
"dotted "sv,
"keys"sv);
2775 key_segment = str.
value;
2781 "expected bare key starting character or string delimiter, saw '"sv,
to_sv(*cp),
2784 const auto key_end = current_position();
2787 consume_leading_whitespace();
2790 key_buffer.
push_back(key_segment, key_begin, key_end);
2793 if (
is_eof() || *cp != U
'.')
break;
2797 consume_leading_whitespace();
2809 return key{key_buffer[segment_index],
2811 root.source().path}};
2824 bool is_arr =
false;
2832 const bool had_leading_whitespace = consume_leading_whitespace();
2837 if (had_leading_whitespace)
2839 "[[array-of-table]] brackets must be contiguous (i.e. [ [ this ] ] is prohibited)"sv);
2845 consume_leading_whitespace();
2860 consume_leading_whitespace();
2871 header_end_pos = current_position(1);
2874 consume_leading_whitespace();
2875 if (!
is_eof() && !consume_comment() && !consume_line_break())
2882 table* parent = &root;
2883 for (
size_t i = 0, e = key_buffer.
size() - 1u; i < e; i++) {
2884 const std::string_view segment = key_buffer[i];
2888 if (pit != parent->
end() && pit->first == segment) {
2889 node& p = pit->second;
2891 if (
auto tbl = p.as_table()) {
2893 if (tbl->is_inline() &&
2894 !impl::find(open_inline_tables.begin(), open_inline_tables.end(), tbl))
2896 "' into existing inline table"sv);
2899 }
else if (
auto arr = p.as_array();
2900 arr && impl::find(table_arrays.begin(), table_arrays.end(), arr)) {
2905 parent = &arr->back().ref_cast<
table>();
2907 if (!is_arr && p.type() == node_type::table)
2909 to_sv(recording_buffer),
"'"sv);
2912 to_sv(recording_buffer),
"' as "sv,
2913 is_arr ?
"array-of-tables"sv :
"table"sv);
2919 pit = parent->emplace_hint<
table>(pit, make_key(i));
2921 p.source_ = {header_begin_pos, header_end_pos, reader.
source_path()};
2923 implicit_tables.push_back(&p);
2928 const auto last_segment = key_buffer.
back();
2935 if (it != parent->
end() && it->first == last_segment) {
2936 node& matching_node = it->second;
2937 if (
auto arr = matching_node.as_array();
2938 is_arr && arr && impl::find(table_arrays.begin(), table_arrays.end(), arr)) {
2940 tbl.source_ = {header_begin_pos, header_end_pos, reader.
source_path()};
2944 else if (
auto tbl = matching_node.as_table(); !is_arr && tbl && !implicit_tables.empty()) {
2945 if (
auto found = impl::find(implicit_tables.begin(), implicit_tables.end(), tbl); found) {
2947 if (!tbl->empty()) {
2948 for (
auto& [_, child] : *tbl) {
2949 if (!child.is_table() && !child.is_array_of_tables()) {
2957 implicit_tables.
erase(implicit_tables.cbegin() + (found - implicit_tables.data()));
2958 tbl->source_.begin = header_begin_pos;
2959 tbl->source_.end = header_end_pos;
2966 if (!is_arr && matching_node.type() == node_type::table) {
2967 set_error_at(header_begin_pos,
"cannot redefine existing table '"sv,
2968 to_sv(recording_buffer),
"'"sv);
2971 set_error_at(header_begin_pos,
"cannot redefine existing "sv,
to_sv(matching_node.type()),
2972 " '"sv,
to_sv(recording_buffer),
"' as "sv,
2973 is_arr ?
"array-of-tables"sv :
"table"sv);
2980 auto last_key = make_key(key_buffer.
size() - 1u);
2985 it = parent->emplace_hint<
array>(it, std::move(last_key));
2986 array& tbl_arr = it->second.ref_cast<
array>();
2988 tbl_arr.source_ = {header_begin_pos, header_end_pos, reader.
source_path()};
2991 tbl.source_ = {header_begin_pos, header_end_pos, reader.
source_path()};
2997 it = parent->emplace_hint<
table>(it, std::move(last_key));
2999 tbl.source_ = {header_begin_pos, header_end_pos, reader.
source_path()};
3020 consume_leading_whitespace();
3028 consume_leading_whitespace();
3033 if (is_value_terminator(*cp))
3038 if (key_buffer.
size() > 1u) {
3039 for (
size_t i = 0; i < key_buffer.
size() - 1u; i++) {
3040 const std::string_view segment = key_buffer[i];
3044 if (pit != tbl->
end() && pit->first == segment) {
3049 !(impl::find(dotted_key_tables.begin(), dotted_key_tables.end(), p) ||
3050 impl::find(implicit_tables.begin(), implicit_tables.end(), p))) {
3051 set_error_at(key_buffer.
starts[i],
"cannot redefine existing "sv,
3052 to_sv(pit->second.type()),
" as dotted key-value pair"sv);
3061 pit = tbl->emplace_hint<
table>(pit, make_key(i));
3063 p.source_ = pit->first.source();
3065 dotted_key_tables.push_back(&p);
3072 const std::string_view last_segment = key_buffer.
back();
3074 if (it != tbl->
end() && it->first == last_segment) {
3075 set_error(
"cannot redefine existing "sv,
to_sv(it->second.type()),
" '"sv,
3076 to_sv(recording_buffer),
"'"sv);
3082 auto last_key = make_key(key_buffer.
size() - 1u);
3085 node_ptr val = parse_value();
3088 tbl->emplace_hint<node_ptr>(it, std::move(last_key), std::move(val));
3097 table* current_table = &root;
3103 if (consume_leading_whitespace() || consume_line_break() || consume_comment())
continue;
3108 if (*cp == U
'[') current_table = parse_table_header();
3113 else if (is_bare_key_character(*cp) || is_string_delimiter(*cp)) {
3116 parse_key_value_pair_and_insert(current_table);
3121 consume_leading_whitespace();
3123 if (!
is_eof() && !consume_comment() && !consume_line_break())
3124 set_error(
"expected a comment or whitespace, saw '"sv,
to_sv(cp),
"'"sv);
3128 set_error(
"expected keys, tables, whitespace or comments, saw '"sv,
to_sv(cp),
"'"sv);
3131 auto eof_pos = current_position(1);
3132 root.source_.
end = eof_pos;
3133 if (current_table && current_table != &root &&
3134 current_table->source_.
end <= current_table->source_.
begin)
3135 current_table->source_.
end = eof_pos;
3139 const auto type = nde.type();
3140 if (type > node_type::array)
return;
3142 if (type == node_type::table) {
3143 auto& tbl = nde.ref_cast<
table>();
3144 if (tbl.is_inline())
3148 auto end = nde.source_.
end;
3149 for (
auto&& [k, v] : tbl) {
3151 update_region_ends(v);
3152 if (end < v.source_.end) end = v.source_.end;
3156 auto& arr = nde.ref_cast<
array>();
3157 auto end = nde.source_.
end;
3158 for (
auto&& v : arr) {
3159 update_region_ends(v);
3160 if (end < v.source_.
end) end = v.source_.
end;
3162 nde.source_.end = end;
3169 root.source_ = {prev_pos, prev_pos, reader.
source_path()};
3175 if (reader.
error()) {
3176 err = std::move(reader.
error());
3181 if (cp) parse_document();
3184 update_region_ends(root);
3191 return {std::move(root)};
3214 node_ptr arr_ptr{
new array{}};
3217 parse_type prev = parse_type::none;
3225 if (prev == parse_type::val) {
3226 prev = parse_type::comma;
3234 else if (*
cp == U
']') {
3241 if (prev == parse_type::val) {
3245 prev = parse_type::val;
3269 node_ptr tbl_ptr{
new table{}};
3275 parse_type prev = parse_type::none;
3289 if (prev == parse_type::kvp) {
3290 prev = parse_type::comma;
3297 else if (*
cp == U
'}') {
3301 if (prev == parse_type::comma) {
3303 "expected key-value pair, saw closing '}' (dangling comma)"sv);
3312 else if (is_string_delimiter(*
cp) || is_bare_key_character(*
cp)) {
3313 if (prev == parse_type::kvp)
3316 prev = parse_type::kvp;
3334#undef TOML_RETURNS_BY_THROWING
3335#undef advance_and_return_if_error
3336#undef advance_and_return_if_error_or_eof
3337#undef assert_not_eof
3338#undef assert_not_error
3341#undef parse_error_break
3342#undef push_parse_scope
3343#undef push_parse_scope_1
3344#undef push_parse_scope_2
3345#undef return_after_error
3347#undef return_if_error
3348#undef return_if_error_or_eof
3349#undef set_error_and_return
3350#undef set_error_and_return_default
3351#undef set_error_and_return_if_eof
3352#undef utf8_buffered_reader_error_check
3353#undef utf8_reader_error
3354#undef utf8_reader_error_check
3355#undef utf8_reader_return_after_error
3365 return impl::parser{std::move(reader)};
3370 parse_result do_parse_file(std::string_view file_path) {
3372#define TOML_PARSE_FILE_ERROR(msg, path) \
3373 throw parse_error { \
3374 msg, source_position{}, std::make_shared<const std::string>(std::move(path)) \
3377#define TOML_PARSE_FILE_ERROR(msg, path) \
3378 return parse_result { \
3380 msg, source_position{}, std::make_shared<const std::string>(std::move(path)) \
3385 std::string file_path_str(file_path);
3390 file.rdbuf()->pubsetbuf(file_buffer,
sizeof(file_buffer));
3392 file.open(impl::widen(file_path_str).c_str(),
3393 std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
3395 file.open(file_path_str, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
3397 if (!file.is_open())
3401 const auto file_size = file.tellg();
3403 file.seekg(0, std::ifstream::beg);
3406 constexpr auto large_file_threshold = 1024 * 1024 * 2;
3407 if (file_size <= large_file_threshold) {
3408 std::vector<char> file_data;
3409 file_data.resize(
static_cast<size_t>(file_size));
3410 file.read(file_data.data(),
static_cast<std::streamsize
>(file_size));
3411 return parse(std::string_view{file_data.data(), file_data.size()}, std::move(file_path_str));
3416 return parse(file, std::move(file_path_str));
3418#undef TOML_PARSE_FILE_ERROR
3428 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
3433 return TOML_ANON_NAMESPACE::do_parse(
3434 TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
3439 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
3444 return TOML_ANON_NAMESPACE::do_parse(
3445 TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
3450 return TOML_ANON_NAMESPACE::do_parse_file(file_path);
3457 return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{doc, source_path});
3462 return TOML_ANON_NAMESPACE::do_parse(
3463 TOML_ANON_NAMESPACE::utf8_reader{doc, std::move(source_path)});
3468 std::string file_path_str;
3469 file_path_str.resize(file_path.length());
3470 memcpy(file_path_str.data(), file_path.data(), file_path.length());
3471 return TOML_ANON_NAMESPACE::do_parse_file(file_path_str);
3476#if TOML_ENABLE_WINDOWS_COMPAT
3480 return TOML_ANON_NAMESPACE::do_parse(
3481 TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
3486 return TOML_ANON_NAMESPACE::do_parse(
3487 TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
3492 return TOML_ANON_NAMESPACE::do_parse_file(impl::narrow(file_path));
3497#if TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT
3501 return TOML_ANON_NAMESPACE::do_parse(
3502 TOML_ANON_NAMESPACE::utf8_reader{doc, impl::narrow(source_path)});
3511#undef TOML_OVERALIGNED
A TOML array.
Definition array.hpp:285
TOML_EXPORTED_MEMBER_FUNCTION void reserve(size_t new_capacity)
Reserves internal storage capacity up to a pre-determined number of elements.
TOML_NODISCARD iterator end() noexcept
Returns an iterator to one-past-the-last element.
Definition array.hpp:831
TOML_NODISCARD size_t capacity() const noexcept
Returns the current max number of elements that may be held in the array's internal storage.
Definition array.hpp:1150
decltype(auto) emplace_back(Args &&... args)
Emplaces a new element at the end of the array.
Definition array.hpp:1659
void push_back(ElemType &&val, value_flags flags=preserve_source_value_flags)
Appends a new element to the end of the array.
Definition array.hpp:1633
The result of a parsing operation.
Definition parse_result.hpp:53
Definition parser.inl:887
std::vector< table * > implicit_tables
Definition parser.inl:895
TOML_NODISCARD key make_key(size_t segment_index) const
Definition parser.inl:2806
optional< parse_error > err
Definition parser.inl:906
TOML_NODISCARD node_ptr parse_value_known_prefixes()
Definition parser.inl:2185
TOML_NODISCARD TOML_NEVER_INLINE date parse_date(bool part_of_datetime=false)
Definition parser.inl:1982
utf8_buffered_reader reader
Definition parser.inl:891
table root
Definition parser.inl:892
parser(utf8_reader_interface &&reader_)
Definition parser.inl:3167
TOML_NODISCARD TOML_NEVER_INLINE bool parse_boolean()
Definition parser.inl:1514
TOML_NODISCARD TOML_NEVER_INLINE date_time parse_date_time()
Definition parser.inl:2115
TOML_RETURNS_BY_THROWING void set_error(const T &... reason) const
Definition parser.inl:934
size_t nested_values
Definition parser.inl:904
TOML_NODISCARD node_ptr parse_value()
Definition parser.inl:2229
TOML_NODISCARD node_ptr parse_inline_table()
Definition parser.inl:3260
parse_key_buffer key_buffer
Definition parser.inl:899
std::string_view current_scope
Definition parser.inl:903
std::string string_buffer
Definition parser.inl:900
bool consume_leading_whitespace()
Definition parser.inl:991
bool consume_rest_of_line()
Definition parser.inl:1029
std::string recording_buffer
Definition parser.inl:901
void advance()
Definition parser.inl:946
TOML_NODISCARD node_ptr parse_array()
Definition parser.inl:3205
TOML_NODISCARD TOML_NEVER_INLINE double parse_float()
Definition parser.inl:1561
TOML_NODISCARD TOML_NEVER_INLINE int64_t parse_integer()
Definition parser.inl:1852
TOML_NODISCARD size_t consume_variable_length_digit_sequence(T *buffer, size_t max_len)
Definition parser.inl:1105
void go_back(size_t count=1) noexcept
Definition parser.inl:938
TOML_NODISCARD bool consume_digit_sequence(T *digits, size_t len)
Definition parser.inl:1089
TOML_NODISCARD bool consume_expected_sequence(std::u32string_view seq)
Definition parser.inl:1076
bool recording_whitespace
Definition parser.inl:902
source_position prev_pos
Definition parser.inl:893
TOML_NEVER_INLINE bool parse_key_value_pair_and_insert(table *tbl)
Definition parser.inl:3006
void parse_document()
Definition parser.inl:3092
TOML_NODISCARD TOML_NEVER_INLINE std::string_view parse_basic_string(bool multi_line)
Definition parser.inl:1122
std::vector< array * > table_arrays
Definition parser.inl:898
bool recording
Definition parser.inl:902
std::vector< table * > open_inline_tables
Definition parser.inl:897
TOML_NODISCARD source_position current_position(source_index fallback_offset=0) const noexcept
Definition parser.inl:910
TOML_NODISCARD TOML_NEVER_INLINE time parse_time(bool part_of_datetime=false)
Definition parser.inl:2031
TOML_NODISCARD TOML_NEVER_INLINE table * parse_table_header()
Definition parser.inl:2816
static constexpr size_t max_nested_values
Definition parser.inl:889
const utf8_codepoint * cp
Definition parser.inl:894
TOML_NODISCARD TOML_NEVER_INLINE double parse_inf_or_nan()
Definition parser.inl:1535
static void update_region_ends(node &nde) noexcept
Definition parser.inl:3138
TOML_NEVER_INLINE bool parse_key()
Definition parser.inl:2745
void stop_recording(size_t pop_bytes=0) noexcept
Definition parser.inl:975
TOML_NODISCARD TOML_NEVER_INLINE std::string_view parse_literal_string(bool multi_line)
Definition parser.inl:1356
TOML_RETURNS_BY_THROWING TOML_NEVER_INLINE void set_error_at(source_position pos, const T &... reason) const
Definition parser.inl:916
TOML_NODISCARD TOML_NEVER_INLINE parsed_string parse_string()
Definition parser.inl:1456
bool consume_comment()
Definition parser.inl:1043
TOML_NODISCARD TOML_NEVER_INLINE std::string_view parse_bare_key_segment()
Definition parser.inl:1495
TOML_NODISCARD TOML_NEVER_INLINE double parse_hex_float()
Definition parser.inl:1696
bool consume_line_break()
Definition parser.inl:1006
void start_recording(bool include_current=true) noexcept
Definition parser.inl:966
std::vector< table * > dotted_key_tables
Definition parser.inl:896
A TOML table.
Definition table.hpp:220
TOML_CONST_INLINE_GETTER table * as_table() noexcept final
Returns a pointer to the table.
Definition table.hpp:414
TOML_PURE_INLINE_GETTER iterator begin() noexcept
Returns an iterator to the first key-value pair.
Definition table.hpp:797
TOML_PURE_INLINE_GETTER iterator end() noexcept
Returns an iterator to one-past-the-last key-value pair.
Definition table.hpp:818
TOML_PURE_INLINE_GETTER bool is_inline() const noexcept
Returns true if this table is an inline table.
Definition table.hpp:548
TOML_PURE_GETTER iterator lower_bound(std::string_view key) noexcept
Returns an iterator to the first key-value pair with key that is not less than the given key.
Definition table.hpp:1143
iterator erase(iterator pos) noexcept
Removes the specified key-value pair from the table.
Definition table.hpp:1295
Definition parser.inl:414
utf8_reader_interface & reader_
Definition parser.inl:421
TOML_PURE_INLINE_GETTER const source_path_ptr & source_path() const noexcept
Definition parser.inl:435
TOML_NODISCARD const utf8_codepoint * read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition parser.inl:438
size_t count
Definition parser.inl:424
TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition parser.inl:486
TOML_NODISCARD const utf8_codepoint * step_back(size_t count) noexcept
Definition parser.inl:471
TOML_NODISCARD optional< parse_error > && error() noexcept
Definition parser.inl:491
static constexpr size_t max_history_length
Definition parser.inl:416
TOML_NODISCARD_CTOR utf8_buffered_reader(utf8_reader_interface &reader) noexcept
Definition parser.inl:431
TOML_PURE_INLINE_GETTER constexpr bool peek_eof() const noexcept
Definition parser.inl:77
TOML_NODISCARD_CTOR constexpr utf8_byte_stream(std::basic_string_view< Char > sv) noexcept
Definition parser.inl:60
TOML_CONST_INLINE_GETTER constexpr bool error() const noexcept
Definition parser.inl:68
TOML_PURE_INLINE_GETTER constexpr bool eof() const noexcept
Definition parser.inl:71
std::basic_string_view< Char > source_
Definition parser.inl:55
TOML_PURE_INLINE_GETTER bool eof() const noexcept
Definition parser.inl:118
TOML_NODISCARD_CTOR utf8_byte_stream(std::istream &stream) noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition parser.inl:98
TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition parser.inl:126
TOML_PURE_INLINE_GETTER bool error() const noexcept
Definition parser.inl:115
std::istream * source_
Definition parser.inl:94
Definition parser.inl:196
TOML_NODISCARD_CTOR utf8_reader(U &&source, String &&source_path={}) noexcept(std::is_nothrow_constructible_v< utf8_byte_stream< T >, U && >)
Definition parser.inl:349
utf8_byte_stream< T > stream_
Definition parser.inl:199
source_path_ptr source_path_
Definition parser.inl:214
optional< parse_error > err_
Definition parser.inl:217
impl::utf8_decoder decoder_
Definition parser.inl:202
TOML_NODISCARD optional< parse_error > && error() noexcept final
Definition parser.inl:388
TOML_PURE_INLINE_GETTER const source_path_ptr & source_path() const noexcept final
Definition parser.inl:362
bool read_next_block() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)
Definition parser.inl:220
TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
Definition parser.inl:381
TOML_NODISCARD const utf8_codepoint * read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS) final
Definition parser.inl:365
enum TOML_OPEN_FLAGS_ENUM value_flags
Metadata associated with TOML values.
Definition forward_declarations.hpp:272
#define TOML_CALLCONV
Calling convention to apply to exported free/static functions. \detail Not defined by default (let th...
Definition preprocessor.hpp:1134
#define TOML_ASSERT(expr)
Sets the assert function used by the library. \detail Defaults to the standard C assert().
Definition preprocessor.hpp:1185
#define TOML_EXCEPTIONS
Sets whether the library uses exceptions to report parsing failures. \detail Defaults to 1 or 0 accor...
Definition preprocessor.hpp:1126
#define TOML_ASSERT_ASSUME(expr)
Definition preprocessor.hpp:1190
#define TOML_MAX_NESTED_VALUES
Definition preprocessor.hpp:1154
#define TOML_RETURNS_BY_THROWING
Definition parser.inl:505
TOML_NAMESPACE_START
Definition parser.inl:3423
TOML_EXTERNAL_LINKAGE parse_result TOML_CALLCONV parse(std::string_view doc, std::string_view source_path)
Parses a TOML document from a string view.
Definition parser.inl:3427
#define set_error_and_return_if_eof(...)
Definition parser.inl:862
TOML_ANON_NAMESPACE_START
Definition parser.inl:43
#define set_error_and_return_default(...)
Definition parser.inl:860
TOML_EXTERNAL_LINKAGE parse_result TOML_CALLCONV parse_file(std::string_view file_path)
Parses a TOML document from a file.
Definition parser.inl:3449
TOML_ENABLE_WARNINGS
Definition parser.inl:36
#define return_if_error_or_eof(...)
Definition parser.inl:829
#define is_error()
Definition parser.inl:822
TOML_IMPL_NAMESPACE_END
Definition parser.inl:3332
TOML_DISABLE_WARNINGS
Definition parser.inl:24
#define TOML_OVERALIGNED
Definition parser.inl:192
#define utf8_reader_error(...)
Definition parser.inl:180
TOML_PURE_GETTER TOML_INTERNAL_LINKAGE std::string_view to_sv(node_type val) noexcept
Definition parser.inl:559
#define TOML_PARSE_FILE_ERROR(msg, path)
#define return_if_error(...)
Definition parser.inl:825
#define return_after_error(...)
Definition parser.inl:823
#define push_parse_scope(scope)
Definition parser.inl:726
#define utf8_reader_error_check(...)
Definition parser.inl:182
#define assert_not_error()
Definition parser.inl:824
TOML_ABI_NAMESPACE_END
Definition parser.inl:3330
#define advance_and_return_if_error_or_eof(...)
Definition parser.inl:874
#define parse_error_break()
Definition parser.inl:851
#define utf8_buffered_reader_error_check(...)
Definition parser.inl:407
#define is_eof()
Definition parser.inl:808
#define advance_and_return_if_error(...)
Definition parser.inl:867
#define assert_not_eof()
Definition parser.inl:809
TOML_INTERNAL_LINKAGE constexpr auto utf8_byte_order_mark
Definition parser.inl:48
TOML_ANON_NAMESPACE_END
Definition parser.inl:496
TOML_INTERNAL_LINKAGE void concatenate(char *&write_pos, char *const buf_end, const T &arg) noexcept
Definition parser.inl:601
TOML_IMPL_NAMESPACE_START
Definition parser.inl:884
#define utf8_reader_return_after_error(...)
Definition parser.inl:181
TOML_NAMESPACE_END
Definition parser.inl:3509
#define TOML_UNUSED(...)
Definition preprocessor.hpp:603
#define TOML_NODISCARD_CTOR
Definition preprocessor.hpp:446
#define TOML_UNLIKELY(...)
Definition preprocessor.hpp:538
#define TOML_ABI_NAMESPACE_BOOL(cond, T, F)
Definition preprocessor.hpp:1323
#define TOML_EMPTY_BASES
Definition preprocessor.hpp:424
#define TOML_NEVER_INLINE
Definition preprocessor.hpp:419
#define TOML_INTERNAL_LINKAGE
Definition preprocessor.hpp:1340
#define TOML_CLOSED_ENUM
Definition preprocessor.hpp:557
#define TOML_UNLIKELY_CASE
Definition preprocessor.hpp:541
#define TOML_EXTERNAL_LINKAGE
Definition preprocessor.hpp:1339
#define TOML_UNREACHABLE
Definition preprocessor.hpp:515
#define TOML_NODISCARD
Definition preprocessor.hpp:439
#define TOML_CONST_GETTER
Definition preprocessor.hpp:485
#define TOML_LANG_UNRELEASED
Definition preprocessor.hpp:1308
#define TOML_COMPILER_HAS_EXCEPTIONS
Definition preprocessor.hpp:334
#define TOML_PURE_GETTER
Definition preprocessor.hpp:474
#define TOML_LIKELY_CASE
Definition preprocessor.hpp:528
#define TOML_CLOSED_FLAGS_ENUM
Definition preprocessor.hpp:562
#define TOML_ATTR(...)
Definition preprocessor.hpp:316
#define TOML_PURE_INLINE_GETTER
Definition preprocessor.hpp:479
#define TOML_CONST_INLINE_GETTER
Definition preprocessor.hpp:490
#define TOML_ABSTRACT_INTERFACE
Definition preprocessor.hpp:423
std::shared_ptr< const std::string > source_path_ptr
A pointer to a shared string resource containing a source path.
Definition source_region.hpp:19
A date-time.
Definition date_time.hpp:327
Definition parser.inl:763
~depth_counter_scope() noexcept
Definition parser.inl:772
size_t & depth_
Definition parser.inl:764
TOML_DELETE_DEFAULTS(depth_counter_scope)
TOML_NODISCARD_CTOR depth_counter_scope(size_t &depth) noexcept
Definition parser.inl:767
Definition parser.inl:678
void append(const T &arg) noexcept
Definition parser.inl:692
char buf[buf_size]
Definition parser.inl:680
static constexpr std::size_t buf_size
Definition parser.inl:679
TOML_NODISCARD_CTOR error_builder(std::string_view scope) noexcept
Definition parser.inl:685
TOML_DELETE_DEFAULTS(error_builder)
TOML_RETURNS_BY_THROWING auto finish(const source_position &pos, const source_path_ptr &source_path) const
Definition parser.inl:697
char *const max_write_pos
Definition parser.inl:682
char * write_pos
Definition parser.inl:681
Definition parser.inl:595
const utf8_codepoint & cp
Definition parser.inl:596
Definition parser.inl:728
TOML_PURE_INLINE_GETTER size_t size() const noexcept
Definition parser.inl:760
std::vector< std::pair< size_t, size_t > > segments
Definition parser.inl:730
std::vector< source_position > starts
Definition parser.inl:731
std::vector< source_position > ends
Definition parser.inl:732
TOML_PURE_INLINE_GETTER std::string_view back() const noexcept
Definition parser.inl:754
void clear() noexcept
Definition parser.inl:734
void push_back(std::string_view segment, source_position b, source_position e)
Definition parser.inl:741
TOML_PURE_INLINE_GETTER bool empty() const noexcept
Definition parser.inl:757
std::string buffer
Definition parser.inl:729
TOML_PURE_INLINE_GETTER std::string_view operator[](size_t i) const noexcept
Definition parser.inl:749
Definition parser.inl:710
TOML_DELETE_DEFAULTS(parse_scope)
std::string_view parent_
Definition parser.inl:712
~parse_scope() noexcept
Definition parser.inl:720
TOML_NODISCARD_CTOR parse_scope(std::string_view ¤t_scope, std::string_view new_scope) noexcept
Definition parser.inl:715
std::string_view & storage_
Definition parser.inl:711
Definition parser.inl:777
std::string_view value
Definition parser.inl:778
bool was_multi_line
Definition parser.inl:779
A source document line-and-column pair.
Definition source_region.hpp:43
source_index line
The line number.
Definition source_region.hpp:46
source_index column
The column number.
Definition source_region.hpp:50
A source document region.
Definition source_region.hpp:167
Definition parser.inl:782
std::vector< table * > & tables
Definition parser.inl:783
~table_vector_scope() noexcept
Definition parser.inl:791
TOML_DELETE_DEFAULTS(table_vector_scope)
TOML_NODISCARD_CTOR table_vector_scope(std::vector< table * > &tables_, table &tbl)
Definition parser.inl:786
A timezone offset.
Definition date_time.hpp:221
A local time-of-day.
Definition date_time.hpp:113
uint32_t nanosecond
The fractional nanoseconds component, from 0 - 999999999.
Definition date_time.hpp:124
uint8_t second
The second component, from 0 - 59.
Definition date_time.hpp:121
Definition parser.inl:140
TOML_PURE_INLINE_GETTER constexpr const char32_t & operator*() const noexcept
Definition parser.inl:150
source_position position
Definition parser.inl:144
char32_t value
Definition parser.inl:141
size_t count
Definition parser.inl:143
char bytes[4]
Definition parser.inl:142
Definition parser.inl:208
size_t current
Definition parser.inl:210
size_t count
Definition parser.inl:211
Definition parser.inl:203
size_t count
Definition parser.inl:205
Definition parser.inl:155
virtual TOML_NODISCARD optional< parse_error > && error() noexcept=0
virtual TOML_NODISCARD const source_path_ptr & source_path() const noexcept=0
virtual ~utf8_reader_interface() noexcept=default
virtual TOML_NODISCARD bool peek_eof() const noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)=0
virtual TOML_NODISCARD const utf8_codepoint * read_next() noexcept(!TOML_COMPILER_HAS_EXCEPTIONS)=0