diff --git a/CHANGELOG.md b/CHANGELOG.md index a316deb..117df81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,8 @@ template: #### Fixes: #### Additions: #### Changes: -#### Removals and Deprecations: +#### Removals: +#### Build system: --> @@ -20,12 +21,12 @@ This release will be a major version bump, so it's ABI breaks all around. Any AP code changes at callsites or in build systems are indicated with ⚠️. #### Fixes: +- ⚠️ fixed incorrect `noexcept` specifications on many functions - fixed `json_formatter` not formatting inf and nan incorrectly - fixed `table` init-list constructor requiring double-brackets - fixed `TOML_API` + extern templates causing linker errors in some circumstances - fixed an illegal table redefinition edge case (#112) (@python36) - fixed documentation issues -- fixed incorrect `noexcept` specifications on many functions ⚠️ - fixed incorrect source position in redefinition error messages - fixed missing `#include ` - fixed missing `#include ` @@ -34,9 +35,15 @@ code changes at callsites or in build systems are indicated with ⚠️. #### Additions: - added `array::at()` and `table::at()` -- added `array::replace()` (#109) (#LebJe) -- added `default_init_flags` param to `array::resize()` -- added `formatter_flags::quote_infinities_and_nans` +- added `array::replace()` (#109) (@LebJe) +- added `array::resize()` param `default_init_flags` +- added `format_flags::allow_binary_integers` +- added `format_flags::allow_hexadecimal_integers` +- added `format_flags::allow_octal_integers` +- added `format_flags::allow_real_tabs_in_strings` +- added `format_flags::indent_array_elements` +- added `format_flags::indent_sub_tables` +- added `format_flags::quote_infinities_and_nans` - added `operator->` to `value` for class types - added `parse_benchmark` example - added `TOML_ENABLE_FORMATTERS` option @@ -48,32 +55,34 @@ code changes at callsites or in build systems are indicated with ⚠️. - added value flags to array + table insert methods (#44) (@levicki) #### Changes: -- `format_flags` is now backed by `uint64_t` (was previously `uint8_t`) ⚠️ -- `source_index` is now an alias for `uint32_t` unconditionally (was previously dependent on `TOML_LARGE_FILES`) ⚠️ -- `value_flags` is now backed by `uint16_t` (was previously `uint8_t`) ⚠️ +- ⚠️ `format_flags` is now backed by `uint64_t` (was previously `uint8_t`) +- ⚠️ `source_index` is now an alias for `uint32_t` unconditionally (was previously dependent on `TOML_LARGE_FILES`) +- ⚠️ `value_flags` is now backed by `uint16_t` (was previously `uint8_t`) +- ⚠️ made all overloaded operators 'hidden friends' where possible +- ⚠️ renamed `default_formatter` to `toml_formatter` (`default_formatter` is now an alias) +- ⚠️ renamed `TOML_PARSER` option to `TOML_ENABLE_PARSER` (`TOML_PARSER` will continue to work but is deprecated) +- ⚠️ renamed `TOML_UNRELEASED_FEATURES` to `TOML_ENABLE_UNRELEASED_FEATURES` (`TOML_UNRELEASED_FEATURES` will continue to work but is deprecated) +- ⚠️ renamed `TOML_WINDOWS_COMPAT` to `TOML_ENABLE_WINDOWS_COMPAT` (`TOML_WINDOWS_COMPAT` will continue to work but is deprecated) - applied clang-format to all the things 🎉️ -- improved performance of parser's internal UTF-8 stream decoder -- made all overloaded operators 'hidden friends' where possible ⚠️ +- improved performance of parser - made date/time constructors accept any integral types - moved all implementation headers to `/impl` -- renamed `default_formatter` to `toml_formatter` (`default_formatter` is now an alias) - renamed all implementation headers to `.h` and 'source' headers to `.inl` - updated conformance tests -#### Removals and Deprecations: -- removed `TOML_LARGE_FILES` (it is now default - explicitly setting `TOML_LARGE_FILES` to `0` will invoke an `#error`) ⚠️ +#### Removals: +- ⚠️ removed `format_flags::allow_value_format_flags` +- ⚠️ removed `TOML_LARGE_FILES` (it is now default - explicitly setting `TOML_LARGE_FILES` to `0` will invoke an `#error`) - removed unnecessary template machinery (esp. where ostreams were involved) - removed unnecessary uses of `final` -- renamed `TOML_PARSER` option to `TOML_ENABLE_PARSER` (`TOML_PARSER` will continue to work but is deprecated) ⚠️ -- renamed `TOML_UNRELEASED_FEATURES` to `TOML_ENABLE_UNRELEASED_FEATURES` (`TOML_UNRELEASED_FEATURES` will continue to work but is deprecated) ⚠️ -- renamed `TOML_WINDOWS_COMPAT` to `TOML_ENABLE_WINDOWS_COMPAT` (`TOML_WINDOWS_COMPAT` will continue to work but is deprecated) ⚠️ #### Build system: +- ⚠️ increased minimum required meson version to `0.54.0` - disabled 'install' path when being used as a meson subproject (#114) (@Tachi107) +- fixed builds failing with meson 0.6.0 (#117) (@Tachi107) - general meson improvements and fixes (#115) (@Tachi107) - used `override_dependency` where supported (#116) (@Tachi107) -- fixed builds failing with meson 0.6.0 (#117) (@Tachi107) -- increased minimum required meson version to `0.54.0` ⚠️ + ## [v2.5.0](https://github.com/osgenic/stim/releases/tag/v2.5.0) - 2021-07-11 @@ -120,7 +129,7 @@ code changes at callsites or in build systems are indicated with ⚠️. - added proper cmake support (#85) (@ClausKlein) - added cmake FetchContent information to documentation (#101) (@proydakov) -#### Removals and Deprecations: +#### Removals: - removed explicit `#include ` requirement for `parse_file()` @@ -199,7 +208,7 @@ code changes at callsites or in build systems are indicated with ⚠️. ## [v2.0.0](https://github.com/osgenic/stim/releases/tag/v2.0.0) - 2020-07-20 This release contains a fairly significant number of 'quality of life' improvements, yay! But also necessitates an ABI -break (hence the version number bump). Changes that might block a migration are annotated with '⚠️'. +break (hence the version number bump). Changes that might block a migration are annotated with ⚠️. #### Fixes: - fixed infinity and NaN-related code breaking when using `-ffast-math` and friends @@ -228,14 +237,14 @@ break (hence the version number bump). Changes that might block a migration are - added explicit instantiations of more template types when `!TOML_ALL_INLINE` #### Changes: +- ⚠️ deprecated `parse_result::get()` in favour of `parse_result::table()` +- ⚠️ deprecated `node_view::get()` in favour of `node_view::node()` +- ⚠️ simplified internal ABI namespaces - improved the quality of many static_assert error messages -- simplified internal ABI namespaces ⚠️ -#### Removals and Deprecations: -- deprecated `node_view::get()` in favour of `node_view::node()` ⚠️ -- deprecated `parse_result::get()` in favour of `parse_result::table()` ⚠️ -- removed `TOML_CHAR_8_STRINGS` since it no longer makes sense ⚠️ -- renamed `date_time::time_offset` to just 'offset' ⚠️ +#### Removals: +- ⚠️ renamed `date_time::time_offset` to just 'offset' +- ⚠️ removed `TOML_CHAR_8_STRINGS` since it no longer makes sense @@ -446,7 +455,7 @@ break (hence the version number bump). Changes that might block a migration are - added `TOML_ALL_INLINE` and `TOML_IMPLEMENTATION` options - added preliminary support for ICC -#### Removals and Deprecations: +#### Removals: - removed `` dependency diff --git a/README.md b/README.md index 4c32338..0cae33c 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ - Proper UTF-8 handling (incl. BOM) - Works with or without exceptions - Doesn't require RTTI - - First-class support for serializing to JSON and YAML - - Tested on Clang (6+), GCC (7+) and MSVC (VS2019) + - Support for serializing to JSON and YAML + - Tested on Clang (6+), GCC (7+) and MSVC (VS2019, VS2022) - Tested on x64, x86 and ARM
diff --git a/examples/error_printer.vcxproj b/examples/error_printer.vcxproj index 0036138..05efe84 100644 --- a/examples/error_printer.vcxproj +++ b/examples/error_printer.vcxproj @@ -19,13 +19,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte @@ -58,4 +58,4 @@ - \ No newline at end of file + diff --git a/examples/parse_benchmark.vcxproj b/examples/parse_benchmark.vcxproj index ea3c25a..442375a 100644 --- a/examples/parse_benchmark.vcxproj +++ b/examples/parse_benchmark.vcxproj @@ -19,13 +19,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte @@ -59,4 +59,4 @@ - \ No newline at end of file + diff --git a/examples/simple_parser.vcxproj b/examples/simple_parser.vcxproj index 29ea77f..7217863 100644 --- a/examples/simple_parser.vcxproj +++ b/examples/simple_parser.vcxproj @@ -19,13 +19,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte @@ -59,4 +59,4 @@ - \ No newline at end of file + diff --git a/examples/toml_generator.vcxproj b/examples/toml_generator.vcxproj index 84afd8f..2e30d9b 100644 --- a/examples/toml_generator.vcxproj +++ b/examples/toml_generator.vcxproj @@ -20,13 +20,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte @@ -59,4 +59,4 @@ - \ No newline at end of file + diff --git a/examples/toml_to_json_transcoder.vcxproj b/examples/toml_to_json_transcoder.vcxproj index daff5d7..a9e5465 100644 --- a/examples/toml_to_json_transcoder.vcxproj +++ b/examples/toml_to_json_transcoder.vcxproj @@ -20,13 +20,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte @@ -59,4 +59,4 @@ - \ No newline at end of file + diff --git a/include/toml++/impl/parser.inl b/include/toml++/impl/parser.inl index bf0ef92..c4c9225 100644 --- a/include/toml++/impl/parser.inl +++ b/include/toml++/impl/parser.inl @@ -932,16 +932,47 @@ TOML_ANON_NAMESPACE_START } }; - struct parsed_key + struct parsed_key_buffer { - source_position position; - std::vector segments; - }; + std::string buffer; + std::vector> segments; + source_region source; - struct parsed_key_value_pair - { - parsed_key key; - node_ptr value; + void reset(source_position pos) noexcept + { + buffer.clear(); + segments.clear(); + source.begin = pos; + } + + void push_back(std::string_view segment) + { + segments.push_back({ buffer.length(), segment.length() }); + buffer.append(segment); + } + + void finish(source_position pos) noexcept + { + source.end = pos; + } + + TOML_PURE_INLINE_GETTER + std::string_view operator[](size_t i) noexcept + { + return std::string_view{ buffer.c_str() + segments[i].first, segments[i].second }; + } + + TOML_PURE_INLINE_GETTER + std::string_view back() noexcept + { + return (*this)[segments.size() - 1u]; + } + + TOML_PURE_INLINE_GETTER + size_t size() noexcept + { + return segments.size(); + } }; struct parse_depth_counter @@ -967,7 +998,7 @@ TOML_ANON_NAMESPACE_START struct parsed_string { - std::string value; + std::string_view value; bool was_multi_line; }; } @@ -1052,7 +1083,7 @@ TOML_ANON_NAMESPACE_END; #define set_error_and_return_if_eof(...) \ do \ { \ - if (is_eof()) \ + if TOML_UNLIKELY(is_eof()) \ set_error_and_return(__VA_ARGS__, "encountered end-of-file"sv); \ } \ while (false) @@ -1094,6 +1125,8 @@ TOML_IMPL_NAMESPACE_START std::vector implicit_tables; std::vector dotted_key_tables; std::vector table_arrays; + parsed_key_buffer key_buffer; + std::string string_buffer; std::string recording_buffer; // for diagnostics bool recording = false, recording_whitespace = true; std::string_view current_scope; @@ -1343,7 +1376,7 @@ TOML_IMPL_NAMESPACE_START } TOML_NODISCARD - std::string parse_basic_string(bool multi_line) + std::string_view parse_basic_string(bool multi_line) { return_if_error({}); assert_not_eof(); @@ -1361,7 +1394,8 @@ TOML_IMPL_NAMESPACE_START set_error_and_return_if_eof({}); } - std::string str; + auto& str = string_buffer; + str.clear(); bool escaped = false; bool skipping_whitespace = false; do @@ -1567,7 +1601,7 @@ TOML_IMPL_NAMESPACE_START } TOML_NODISCARD - std::string parse_literal_string(bool multi_line) + std::string_view parse_literal_string(bool multi_line) { return_if_error({}); assert_not_eof(); @@ -1585,7 +1619,8 @@ TOML_IMPL_NAMESPACE_START set_error_and_return_if_eof({}); } - std::string str; + auto& str = string_buffer; + str.clear(); do { return_if_error({}); @@ -1714,14 +1749,14 @@ TOML_IMPL_NAMESPACE_START TOML_NODISCARD TOML_NEVER_INLINE - std::string parse_bare_key_segment() + std::string_view parse_bare_key_segment() { return_if_error({}); assert_not_eof(); assert_or_assume(is_bare_key_character(*cp)); - std::string segment; - segment.reserve(10u); + auto& segment = string_buffer; + segment.clear(); while (!is_eof()) { @@ -2485,7 +2520,7 @@ TOML_IMPL_NAMESPACE_START // strings case U'"': [[fallthrough]]; case U'\'': - return new value{ std::move(parse_string().value) }; + return new value{ parse_string().value }; // bools case U't': [[fallthrough]]; @@ -2980,18 +3015,16 @@ TOML_IMPL_NAMESPACE_START return val.release(); } - TOML_NODISCARD - parsed_key parse_key() + bool parse_key() { return_if_error({}); assert_not_eof(); assert_or_assume(is_bare_key_character(*cp) || is_string_delimiter(*cp)); push_parse_scope("key"sv); - parsed_key key; - key.position = current_position(); + key_buffer.reset(current_position()); recording_whitespace = false; - std::string pending_key_segment; + std::string_view pending_key_segment; while (!is_error()) { @@ -3018,12 +3051,12 @@ TOML_IMPL_NAMESPACE_START { set_error_at(begin_pos, "multi-line strings are prohibited in "sv, - key.segments.empty() ? ""sv : "dotted "sv, + key_buffer.segments.empty() ? ""sv : "dotted "sv, "keys"sv); return_after_error({}); } else - pending_key_segment = std::move(str.value); + pending_key_segment = str.value; } // ??? @@ -3035,58 +3068,22 @@ TOML_IMPL_NAMESPACE_START // whitespace following the key segment consume_leading_whitespace(); + // store segment + key_buffer.push_back(pending_key_segment); + // eof or no more key to come if (is_eof() || *cp != U'.') - { - key.segments.push_back(std::move(pending_key_segment)); break; - } - // was a dotted key - reserve capacity for a few segments - if (!key.segments.capacity()) - key.segments.reserve(3u); - key.segments.push_back(std::move(pending_key_segment)); - - // go around again to consume the next segment + // was a dotted key - go around again advance_and_return_if_error_or_eof({}); consume_leading_whitespace(); set_error_and_return_if_eof({}); } return_if_error({}); - return key; - } - TOML_NODISCARD - parsed_key_value_pair parse_key_value_pair() - { - return_if_error({}); - assert_not_eof(); - assert_or_assume(is_string_delimiter(*cp) || is_bare_key_character(*cp)); - push_parse_scope("key-value pair"sv); - - // get the key - start_recording(); - auto key = parse_key(); - stop_recording(1u); - - // skip past any whitespace that followed the key - consume_leading_whitespace(); - set_error_and_return_if_eof({}); - - // '=' - if (*cp != U'=') - set_error_and_return_default("expected '=', saw '"sv, to_sv(*cp), "'"sv); - advance_and_return_if_error_or_eof({}); - - // skip past any whitespace that followed the '=' - consume_leading_whitespace(); - return_if_error({}); - set_error_and_return_if_eof({}); - - // get the value - if (is_value_terminator(*cp)) - set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv); - return { std::move(key), node_ptr{ parse_value() } }; + key_buffer.finish(current_position()); + return true; } TOML_NODISCARD @@ -3099,7 +3096,6 @@ TOML_IMPL_NAMESPACE_START const source_position header_begin_pos = cp->position; source_position header_end_pos; - parsed_key key; bool is_arr = false; // parse header @@ -3132,7 +3128,7 @@ TOML_IMPL_NAMESPACE_START // get the actual key start_recording(); - key = parse_key(); + parse_key(); stop_recording(1u); return_if_error({}); @@ -3158,16 +3154,17 @@ TOML_IMPL_NAMESPACE_START if (!is_eof() && !consume_comment() && !consume_line_break()) set_error_and_return_default("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv); } - TOML_ASSERT(!key.segments.empty()); + TOML_ASSERT(!key_buffer.segments.empty()); // check if each parent is a table/table array, or can be created implicitly as a table. auto parent = &root; - for (size_t i = 0; i < key.segments.size() - 1u; i++) + for (size_t i = 0, e = key_buffer.size() - 1u; i < e; i++) { - auto child = parent->get(key.segments[i]); + const auto segment = key_buffer[i]; + auto child = parent->get(segment); if (!child) { - child = parent->map_.emplace(key.segments[i], new table{}).first->second.get(); + child = parent->map_.emplace(segment, new table{}).first->second.get(); implicit_tables.push_back(&child->ref_cast()); child->source_ = { header_begin_pos, header_end_pos, reader.source_path() }; parent = &child->ref_cast
(); @@ -3204,14 +3201,15 @@ TOML_IMPL_NAMESPACE_START // check the last parent table for a node matching the last key. // if there was no matching node, then sweet; // we can freely instantiate a new table/table array. - auto matching_node = parent->get(key.segments.back()); + const auto last_segment = key_buffer.back(); + auto matching_node = parent->get(last_segment); if (!matching_node) { // if it's an array we need to make the array and it's first table element, // set the starting regions, and return the table element if (is_arr) { - array& tbl_arr = parent->emplace(key.segments.back()).first->second.ref_cast(); + array& tbl_arr = parent->emplace(last_segment).first->second.ref_cast(); table_arrays.push_back(&tbl_arr); tbl_arr.source_ = { header_begin_pos, header_end_pos, reader.source_path() }; @@ -3223,7 +3221,7 @@ TOML_IMPL_NAMESPACE_START // otherwise we're just making a table else { - table& tbl = parent->emplace
(key.segments.back()).first->second.ref_cast
(); + table& tbl = parent->emplace
(last_segment).first->second.ref_cast
(); tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() }; return &tbl; } @@ -3279,29 +3277,51 @@ TOML_IMPL_NAMESPACE_START } } - void parse_key_value_pair_and_insert(table* tab) + bool parse_key_value_pair_and_insert(table* tbl) { - return_if_error(); + return_if_error({}); assert_not_eof(); + assert_or_assume(is_string_delimiter(*cp) || is_bare_key_character(*cp)); push_parse_scope("key-value pair"sv); - auto kvp = parse_key_value_pair(); - return_if_error(); + // read the key into the key buffer + start_recording(); + parse_key(); + stop_recording(1u); + return_if_error({}); + TOML_ASSERT(key_buffer.size() >= 1u); - TOML_ASSERT(kvp.key.segments.size() >= 1u); + // skip past any whitespace that followed the key + consume_leading_whitespace(); + set_error_and_return_if_eof({}); + + // '=' + if (*cp != U'=') + set_error_and_return_default("expected '=', saw '"sv, to_sv(*cp), "'"sv); + advance_and_return_if_error_or_eof({}); + + // skip past any whitespace that followed the '=' + consume_leading_whitespace(); + return_if_error({}); + set_error_and_return_if_eof({}); + + // check that the next character could actually be a value + if (is_value_terminator(*cp)) + set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv); // if it's a dotted kvp we need to spawn the sub-tables if necessary, // and set the target table to the second-to-last one in the chain - if (kvp.key.segments.size() > 1u) + if (key_buffer.size() > 1u) { - for (size_t i = 0; i < kvp.key.segments.size() - 1u; i++) + for (size_t i = 0; i < key_buffer.size() - 1u; i++) { - auto child = tab->get(kvp.key.segments[i]); + const auto segment = key_buffer[i]; + auto child = tbl->get(segment); if (!child) { - child = tab->map_.emplace(std::move(kvp.key.segments[i]), new table{}).first->second.get(); + child = tbl->map_.emplace(std::string{ segment }, new table{}).first->second.get(); dotted_key_tables.push_back(&child->ref_cast
()); - child->source_ = kvp.value->source_; + child->source_ = key_buffer.source; } else if (!child->is_table() || !(impl::find(dotted_key_tables.begin(), @@ -3310,37 +3330,38 @@ TOML_IMPL_NAMESPACE_START || impl::find(implicit_tables.begin(), implicit_tables.end(), &child->ref_cast
()))) - set_error_at(kvp.key.position, + { + set_error_at(key_buffer.source.begin, "cannot redefine existing "sv, to_sv(child->type()), " as dotted key-value pair"sv); - else - child->source_.end = kvp.value->source_.end; + return_after_error({}); + } - return_if_error(); - tab = &child->ref_cast
(); + tbl = &child->ref_cast
(); } } - if (auto conflicting_node = tab->get(kvp.key.segments.back())) + // ensure this isn't a redefinition + if (auto conflicting_node = tbl->get(key_buffer.back())) { - if (conflicting_node->type() == kvp.value->type()) - set_error("cannot redefine existing "sv, - to_sv(conflicting_node->type()), - " '"sv, - to_sv(recording_buffer), - "'"sv); - else - set_error("cannot redefine existing "sv, - to_sv(conflicting_node->type()), - " '"sv, - to_sv(recording_buffer), - "' as "sv, - to_sv(kvp.value->type())); + set_error("cannot redefine existing "sv, + to_sv(conflicting_node->type()), + " '"sv, + to_sv(recording_buffer), + "'"sv); + return_after_error({}); } - return_if_error(); - tab->map_.emplace(std::move(kvp.key.segments.back()), std::unique_ptr{ kvp.value.release() }); + // cache the last segment since it might get overwritten by nested tables etc. + auto last_segment = std::string{ key_buffer.back() }; + + // now we can actually parse the value + auto val = node_ptr{ parse_value() }; + return_if_error({}); + + tbl->map_.emplace(std::move(last_segment), std::unique_ptr{ val.release() }); + return true; } void parse_document() @@ -3432,7 +3453,8 @@ TOML_IMPL_NAMESPACE_START parser(utf8_reader_interface&& reader_) // : reader{ reader_ } { - root.source_ = { prev_pos, prev_pos, reader.source_path() }; + root.source_ = { prev_pos, prev_pos, reader.source_path() }; + key_buffer.source.path = reader.source_path(); if (!reader.peek_eof()) { diff --git a/tests/vs/test_debug_x64.vcxproj b/tests/vs/test_debug_x64.vcxproj index 037d419..7c28e52 100644 --- a/tests/vs/test_debug_x64.vcxproj +++ b/tests/vs/test_debug_x64.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x64_cpplatest.vcxproj b/tests/vs/test_debug_x64_cpplatest.vcxproj index cbd576c..69d407b 100644 --- a/tests/vs/test_debug_x64_cpplatest.vcxproj +++ b/tests/vs/test_debug_x64_cpplatest.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x64_cpplatest_noexcept.vcxproj b/tests/vs/test_debug_x64_cpplatest_noexcept.vcxproj index bdb9616..55d2ae4 100644 --- a/tests/vs/test_debug_x64_cpplatest_noexcept.vcxproj +++ b/tests/vs/test_debug_x64_cpplatest_noexcept.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x64_cpplatest_noexcept_unrel.vcxproj b/tests/vs/test_debug_x64_cpplatest_noexcept_unrel.vcxproj index 034a631..6c65bce 100644 --- a/tests/vs/test_debug_x64_cpplatest_noexcept_unrel.vcxproj +++ b/tests/vs/test_debug_x64_cpplatest_noexcept_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x64_cpplatest_unrel.vcxproj b/tests/vs/test_debug_x64_cpplatest_unrel.vcxproj index 4365e13..773efe9 100644 --- a/tests/vs/test_debug_x64_cpplatest_unrel.vcxproj +++ b/tests/vs/test_debug_x64_cpplatest_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x64_noexcept.vcxproj b/tests/vs/test_debug_x64_noexcept.vcxproj index 0a78c4d..316ae5c 100644 --- a/tests/vs/test_debug_x64_noexcept.vcxproj +++ b/tests/vs/test_debug_x64_noexcept.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x64_noexcept_unrel.vcxproj b/tests/vs/test_debug_x64_noexcept_unrel.vcxproj index 23ec38c..903a8bd 100644 --- a/tests/vs/test_debug_x64_noexcept_unrel.vcxproj +++ b/tests/vs/test_debug_x64_noexcept_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x64_unrel.vcxproj b/tests/vs/test_debug_x64_unrel.vcxproj index b351b7f..0401e89 100644 --- a/tests/vs/test_debug_x64_unrel.vcxproj +++ b/tests/vs/test_debug_x64_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x86.vcxproj b/tests/vs/test_debug_x86.vcxproj index a4681a0..47f910d 100644 --- a/tests/vs/test_debug_x86.vcxproj +++ b/tests/vs/test_debug_x86.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x86_cpplatest.vcxproj b/tests/vs/test_debug_x86_cpplatest.vcxproj index f588da2..b7632a0 100644 --- a/tests/vs/test_debug_x86_cpplatest.vcxproj +++ b/tests/vs/test_debug_x86_cpplatest.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x86_cpplatest_noexcept.vcxproj b/tests/vs/test_debug_x86_cpplatest_noexcept.vcxproj index aa8c1fa..894b7bb 100644 --- a/tests/vs/test_debug_x86_cpplatest_noexcept.vcxproj +++ b/tests/vs/test_debug_x86_cpplatest_noexcept.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x86_cpplatest_noexcept_unrel.vcxproj b/tests/vs/test_debug_x86_cpplatest_noexcept_unrel.vcxproj index daf4074..cab19d8 100644 --- a/tests/vs/test_debug_x86_cpplatest_noexcept_unrel.vcxproj +++ b/tests/vs/test_debug_x86_cpplatest_noexcept_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x86_cpplatest_unrel.vcxproj b/tests/vs/test_debug_x86_cpplatest_unrel.vcxproj index 4a50cc1..52432d4 100644 --- a/tests/vs/test_debug_x86_cpplatest_unrel.vcxproj +++ b/tests/vs/test_debug_x86_cpplatest_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x86_noexcept.vcxproj b/tests/vs/test_debug_x86_noexcept.vcxproj index a13d98a..77d8bce 100644 --- a/tests/vs/test_debug_x86_noexcept.vcxproj +++ b/tests/vs/test_debug_x86_noexcept.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x86_noexcept_unrel.vcxproj b/tests/vs/test_debug_x86_noexcept_unrel.vcxproj index 1907333..4b947e7 100644 --- a/tests/vs/test_debug_x86_noexcept_unrel.vcxproj +++ b/tests/vs/test_debug_x86_noexcept_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_debug_x86_unrel.vcxproj b/tests/vs/test_debug_x86_unrel.vcxproj index 202db4e..17f3523 100644 --- a/tests/vs/test_debug_x86_unrel.vcxproj +++ b/tests/vs/test_debug_x86_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x64.vcxproj b/tests/vs/test_release_x64.vcxproj index f0e811a..5519ce1 100644 --- a/tests/vs/test_release_x64.vcxproj +++ b/tests/vs/test_release_x64.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x64_cpplatest.vcxproj b/tests/vs/test_release_x64_cpplatest.vcxproj index 29cb1bb..6f1a45d 100644 --- a/tests/vs/test_release_x64_cpplatest.vcxproj +++ b/tests/vs/test_release_x64_cpplatest.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x64_cpplatest_noexcept.vcxproj b/tests/vs/test_release_x64_cpplatest_noexcept.vcxproj index 45bb60b..8822474 100644 --- a/tests/vs/test_release_x64_cpplatest_noexcept.vcxproj +++ b/tests/vs/test_release_x64_cpplatest_noexcept.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x64_cpplatest_noexcept_unrel.vcxproj b/tests/vs/test_release_x64_cpplatest_noexcept_unrel.vcxproj index c62047c..c28f5d0 100644 --- a/tests/vs/test_release_x64_cpplatest_noexcept_unrel.vcxproj +++ b/tests/vs/test_release_x64_cpplatest_noexcept_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x64_cpplatest_unrel.vcxproj b/tests/vs/test_release_x64_cpplatest_unrel.vcxproj index d58c218..0122a67 100644 --- a/tests/vs/test_release_x64_cpplatest_unrel.vcxproj +++ b/tests/vs/test_release_x64_cpplatest_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x64_noexcept.vcxproj b/tests/vs/test_release_x64_noexcept.vcxproj index 7ba95c4..763859b 100644 --- a/tests/vs/test_release_x64_noexcept.vcxproj +++ b/tests/vs/test_release_x64_noexcept.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x64_noexcept_unrel.vcxproj b/tests/vs/test_release_x64_noexcept_unrel.vcxproj index 1bd6c86..b23555b 100644 --- a/tests/vs/test_release_x64_noexcept_unrel.vcxproj +++ b/tests/vs/test_release_x64_noexcept_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x64_unrel.vcxproj b/tests/vs/test_release_x64_unrel.vcxproj index 2cd1ba6..7c6f729 100644 --- a/tests/vs/test_release_x64_unrel.vcxproj +++ b/tests/vs/test_release_x64_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x86.vcxproj b/tests/vs/test_release_x86.vcxproj index 3c3cd35..893a4fe 100644 --- a/tests/vs/test_release_x86.vcxproj +++ b/tests/vs/test_release_x86.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x86_cpplatest.vcxproj b/tests/vs/test_release_x86_cpplatest.vcxproj index 6d4fd09..97d21e6 100644 --- a/tests/vs/test_release_x86_cpplatest.vcxproj +++ b/tests/vs/test_release_x86_cpplatest.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x86_cpplatest_noexcept.vcxproj b/tests/vs/test_release_x86_cpplatest_noexcept.vcxproj index 6cdb661..abe41cd 100644 --- a/tests/vs/test_release_x86_cpplatest_noexcept.vcxproj +++ b/tests/vs/test_release_x86_cpplatest_noexcept.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x86_cpplatest_noexcept_unrel.vcxproj b/tests/vs/test_release_x86_cpplatest_noexcept_unrel.vcxproj index a9d0e16..fdb5da9 100644 --- a/tests/vs/test_release_x86_cpplatest_noexcept_unrel.vcxproj +++ b/tests/vs/test_release_x86_cpplatest_noexcept_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x86_cpplatest_unrel.vcxproj b/tests/vs/test_release_x86_cpplatest_unrel.vcxproj index c72558f..3ea5734 100644 --- a/tests/vs/test_release_x86_cpplatest_unrel.vcxproj +++ b/tests/vs/test_release_x86_cpplatest_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x86_noexcept.vcxproj b/tests/vs/test_release_x86_noexcept.vcxproj index 0e56695..cf2fdc0 100644 --- a/tests/vs/test_release_x86_noexcept.vcxproj +++ b/tests/vs/test_release_x86_noexcept.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x86_noexcept_unrel.vcxproj b/tests/vs/test_release_x86_noexcept_unrel.vcxproj index 8c13e52..12eb804 100644 --- a/tests/vs/test_release_x86_noexcept_unrel.vcxproj +++ b/tests/vs/test_release_x86_noexcept_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/tests/vs/test_release_x86_unrel.vcxproj b/tests/vs/test_release_x86_unrel.vcxproj index ba59549..5c2f2fb 100644 --- a/tests/vs/test_release_x86_unrel.vcxproj +++ b/tests/vs/test_release_x86_unrel.vcxproj @@ -16,13 +16,13 @@ Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte diff --git a/toml++.vcxproj b/toml++.vcxproj index 5baf9cd..ddf8a7f 100644 --- a/toml++.vcxproj +++ b/toml++.vcxproj @@ -19,13 +19,13 @@ StaticLibrary true - v142 + v143 MultiByte StaticLibrary false - v142 + v143 true MultiByte @@ -125,4 +125,4 @@ - \ No newline at end of file + diff --git a/toml.hpp b/toml.hpp index 48a8d89..67a7230 100644 --- a/toml.hpp +++ b/toml.hpp @@ -10587,16 +10587,47 @@ TOML_ANON_NAMESPACE_START } }; - struct parsed_key + struct parsed_key_buffer { - source_position position; - std::vector segments; - }; + std::string buffer; + std::vector> segments; + source_region source; - struct parsed_key_value_pair - { - parsed_key key; - node_ptr value; + void reset(source_position pos) noexcept + { + buffer.clear(); + segments.clear(); + source.begin = pos; + } + + void push_back(std::string_view segment) + { + segments.push_back({ buffer.length(), segment.length() }); + buffer.append(segment); + } + + void finish(source_position pos) noexcept + { + source.end = pos; + } + + TOML_PURE_INLINE_GETTER + std::string_view operator[](size_t i) noexcept + { + return std::string_view{ buffer.c_str() + segments[i].first, segments[i].second }; + } + + TOML_PURE_INLINE_GETTER + std::string_view back() noexcept + { + return (*this)[segments.size() - 1u]; + } + + TOML_PURE_INLINE_GETTER + size_t size() noexcept + { + return segments.size(); + } }; struct parse_depth_counter @@ -10622,7 +10653,7 @@ TOML_ANON_NAMESPACE_START struct parsed_string { - std::string value; + std::string_view value; bool was_multi_line; }; } @@ -10707,7 +10738,7 @@ TOML_ANON_NAMESPACE_END; #define set_error_and_return_if_eof(...) \ do \ { \ - if (is_eof()) \ + if TOML_UNLIKELY(is_eof()) \ set_error_and_return(__VA_ARGS__, "encountered end-of-file"sv); \ } \ while (false) @@ -10749,6 +10780,8 @@ TOML_IMPL_NAMESPACE_START std::vector implicit_tables; std::vector dotted_key_tables; std::vector table_arrays; + parsed_key_buffer key_buffer; + std::string string_buffer; std::string recording_buffer; // for diagnostics bool recording = false, recording_whitespace = true; std::string_view current_scope; @@ -10998,7 +11031,7 @@ TOML_IMPL_NAMESPACE_START } TOML_NODISCARD - std::string parse_basic_string(bool multi_line) + std::string_view parse_basic_string(bool multi_line) { return_if_error({}); assert_not_eof(); @@ -11016,7 +11049,8 @@ TOML_IMPL_NAMESPACE_START set_error_and_return_if_eof({}); } - std::string str; + auto& str = string_buffer; + str.clear(); bool escaped = false; bool skipping_whitespace = false; do @@ -11222,7 +11256,7 @@ TOML_IMPL_NAMESPACE_START } TOML_NODISCARD - std::string parse_literal_string(bool multi_line) + std::string_view parse_literal_string(bool multi_line) { return_if_error({}); assert_not_eof(); @@ -11240,7 +11274,8 @@ TOML_IMPL_NAMESPACE_START set_error_and_return_if_eof({}); } - std::string str; + auto& str = string_buffer; + str.clear(); do { return_if_error({}); @@ -11369,14 +11404,14 @@ TOML_IMPL_NAMESPACE_START TOML_NODISCARD TOML_NEVER_INLINE - std::string parse_bare_key_segment() + std::string_view parse_bare_key_segment() { return_if_error({}); assert_not_eof(); assert_or_assume(is_bare_key_character(*cp)); - std::string segment; - segment.reserve(10u); + auto& segment = string_buffer; + segment.clear(); while (!is_eof()) { @@ -12140,7 +12175,7 @@ TOML_IMPL_NAMESPACE_START // strings case U'"': [[fallthrough]]; case U'\'': - return new value{ std::move(parse_string().value) }; + return new value{ parse_string().value }; // bools case U't': [[fallthrough]]; @@ -12634,18 +12669,16 @@ TOML_IMPL_NAMESPACE_START return val.release(); } - TOML_NODISCARD - parsed_key parse_key() + bool parse_key() { return_if_error({}); assert_not_eof(); assert_or_assume(is_bare_key_character(*cp) || is_string_delimiter(*cp)); push_parse_scope("key"sv); - parsed_key key; - key.position = current_position(); + key_buffer.reset(current_position()); recording_whitespace = false; - std::string pending_key_segment; + std::string_view pending_key_segment; while (!is_error()) { @@ -12672,12 +12705,12 @@ TOML_IMPL_NAMESPACE_START { set_error_at(begin_pos, "multi-line strings are prohibited in "sv, - key.segments.empty() ? ""sv : "dotted "sv, + key_buffer.segments.empty() ? ""sv : "dotted "sv, "keys"sv); return_after_error({}); } else - pending_key_segment = std::move(str.value); + pending_key_segment = str.value; } // ??? @@ -12689,58 +12722,22 @@ TOML_IMPL_NAMESPACE_START // whitespace following the key segment consume_leading_whitespace(); + // store segment + key_buffer.push_back(pending_key_segment); + // eof or no more key to come if (is_eof() || *cp != U'.') - { - key.segments.push_back(std::move(pending_key_segment)); break; - } - // was a dotted key - reserve capacity for a few segments - if (!key.segments.capacity()) - key.segments.reserve(3u); - key.segments.push_back(std::move(pending_key_segment)); - - // go around again to consume the next segment + // was a dotted key - go around again advance_and_return_if_error_or_eof({}); consume_leading_whitespace(); set_error_and_return_if_eof({}); } return_if_error({}); - return key; - } - TOML_NODISCARD - parsed_key_value_pair parse_key_value_pair() - { - return_if_error({}); - assert_not_eof(); - assert_or_assume(is_string_delimiter(*cp) || is_bare_key_character(*cp)); - push_parse_scope("key-value pair"sv); - - // get the key - start_recording(); - auto key = parse_key(); - stop_recording(1u); - - // skip past any whitespace that followed the key - consume_leading_whitespace(); - set_error_and_return_if_eof({}); - - // '=' - if (*cp != U'=') - set_error_and_return_default("expected '=', saw '"sv, to_sv(*cp), "'"sv); - advance_and_return_if_error_or_eof({}); - - // skip past any whitespace that followed the '=' - consume_leading_whitespace(); - return_if_error({}); - set_error_and_return_if_eof({}); - - // get the value - if (is_value_terminator(*cp)) - set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv); - return { std::move(key), node_ptr{ parse_value() } }; + key_buffer.finish(current_position()); + return true; } TOML_NODISCARD @@ -12753,7 +12750,6 @@ TOML_IMPL_NAMESPACE_START const source_position header_begin_pos = cp->position; source_position header_end_pos; - parsed_key key; bool is_arr = false; // parse header @@ -12786,7 +12782,7 @@ TOML_IMPL_NAMESPACE_START // get the actual key start_recording(); - key = parse_key(); + parse_key(); stop_recording(1u); return_if_error({}); @@ -12812,16 +12808,17 @@ TOML_IMPL_NAMESPACE_START if (!is_eof() && !consume_comment() && !consume_line_break()) set_error_and_return_default("expected a comment or whitespace, saw '"sv, to_sv(cp), "'"sv); } - TOML_ASSERT(!key.segments.empty()); + TOML_ASSERT(!key_buffer.segments.empty()); // check if each parent is a table/table array, or can be created implicitly as a table. auto parent = &root; - for (size_t i = 0; i < key.segments.size() - 1u; i++) + for (size_t i = 0, e = key_buffer.size() - 1u; i < e; i++) { - auto child = parent->get(key.segments[i]); + const auto segment = key_buffer[i]; + auto child = parent->get(segment); if (!child) { - child = parent->map_.emplace(key.segments[i], new table{}).first->second.get(); + child = parent->map_.emplace(segment, new table{}).first->second.get(); implicit_tables.push_back(&child->ref_cast
()); child->source_ = { header_begin_pos, header_end_pos, reader.source_path() }; parent = &child->ref_cast
(); @@ -12858,14 +12855,15 @@ TOML_IMPL_NAMESPACE_START // check the last parent table for a node matching the last key. // if there was no matching node, then sweet; // we can freely instantiate a new table/table array. - auto matching_node = parent->get(key.segments.back()); + const auto last_segment = key_buffer.back(); + auto matching_node = parent->get(last_segment); if (!matching_node) { // if it's an array we need to make the array and it's first table element, // set the starting regions, and return the table element if (is_arr) { - array& tbl_arr = parent->emplace(key.segments.back()).first->second.ref_cast(); + array& tbl_arr = parent->emplace(last_segment).first->second.ref_cast(); table_arrays.push_back(&tbl_arr); tbl_arr.source_ = { header_begin_pos, header_end_pos, reader.source_path() }; @@ -12877,7 +12875,7 @@ TOML_IMPL_NAMESPACE_START // otherwise we're just making a table else { - table& tbl = parent->emplace
(key.segments.back()).first->second.ref_cast
(); + table& tbl = parent->emplace
(last_segment).first->second.ref_cast
(); tbl.source_ = { header_begin_pos, header_end_pos, reader.source_path() }; return &tbl; } @@ -12933,29 +12931,51 @@ TOML_IMPL_NAMESPACE_START } } - void parse_key_value_pair_and_insert(table* tab) + bool parse_key_value_pair_and_insert(table* tbl) { - return_if_error(); + return_if_error({}); assert_not_eof(); + assert_or_assume(is_string_delimiter(*cp) || is_bare_key_character(*cp)); push_parse_scope("key-value pair"sv); - auto kvp = parse_key_value_pair(); - return_if_error(); + // read the key into the key buffer + start_recording(); + parse_key(); + stop_recording(1u); + return_if_error({}); + TOML_ASSERT(key_buffer.size() >= 1u); - TOML_ASSERT(kvp.key.segments.size() >= 1u); + // skip past any whitespace that followed the key + consume_leading_whitespace(); + set_error_and_return_if_eof({}); + + // '=' + if (*cp != U'=') + set_error_and_return_default("expected '=', saw '"sv, to_sv(*cp), "'"sv); + advance_and_return_if_error_or_eof({}); + + // skip past any whitespace that followed the '=' + consume_leading_whitespace(); + return_if_error({}); + set_error_and_return_if_eof({}); + + // check that the next character could actually be a value + if (is_value_terminator(*cp)) + set_error_and_return_default("expected value, saw '"sv, to_sv(*cp), "'"sv); // if it's a dotted kvp we need to spawn the sub-tables if necessary, // and set the target table to the second-to-last one in the chain - if (kvp.key.segments.size() > 1u) + if (key_buffer.size() > 1u) { - for (size_t i = 0; i < kvp.key.segments.size() - 1u; i++) + for (size_t i = 0; i < key_buffer.size() - 1u; i++) { - auto child = tab->get(kvp.key.segments[i]); + const auto segment = key_buffer[i]; + auto child = tbl->get(segment); if (!child) { - child = tab->map_.emplace(std::move(kvp.key.segments[i]), new table{}).first->second.get(); + child = tbl->map_.emplace(std::string{ segment }, new table{}).first->second.get(); dotted_key_tables.push_back(&child->ref_cast
()); - child->source_ = kvp.value->source_; + child->source_ = key_buffer.source; } else if (!child->is_table() || !(impl::find(dotted_key_tables.begin(), @@ -12964,37 +12984,38 @@ TOML_IMPL_NAMESPACE_START || impl::find(implicit_tables.begin(), implicit_tables.end(), &child->ref_cast
()))) - set_error_at(kvp.key.position, + { + set_error_at(key_buffer.source.begin, "cannot redefine existing "sv, to_sv(child->type()), " as dotted key-value pair"sv); - else - child->source_.end = kvp.value->source_.end; + return_after_error({}); + } - return_if_error(); - tab = &child->ref_cast
(); + tbl = &child->ref_cast
(); } } - if (auto conflicting_node = tab->get(kvp.key.segments.back())) + // ensure this isn't a redefinition + if (auto conflicting_node = tbl->get(key_buffer.back())) { - if (conflicting_node->type() == kvp.value->type()) - set_error("cannot redefine existing "sv, - to_sv(conflicting_node->type()), - " '"sv, - to_sv(recording_buffer), - "'"sv); - else - set_error("cannot redefine existing "sv, - to_sv(conflicting_node->type()), - " '"sv, - to_sv(recording_buffer), - "' as "sv, - to_sv(kvp.value->type())); + set_error("cannot redefine existing "sv, + to_sv(conflicting_node->type()), + " '"sv, + to_sv(recording_buffer), + "'"sv); + return_after_error({}); } - return_if_error(); - tab->map_.emplace(std::move(kvp.key.segments.back()), std::unique_ptr{ kvp.value.release() }); + // cache the last segment since it might get overwritten by nested tables etc. + auto last_segment = std::string{ key_buffer.back() }; + + // now we can actually parse the value + auto val = node_ptr{ parse_value() }; + return_if_error({}); + + tbl->map_.emplace(std::move(last_segment), std::unique_ptr{ val.release() }); + return true; } void parse_document() @@ -13086,7 +13107,8 @@ TOML_IMPL_NAMESPACE_START parser(utf8_reader_interface&& reader_) // : reader{ reader_ } { - root.source_ = { prev_pos, prev_pos, reader.source_path() }; + root.source_ = { prev_pos, prev_pos, reader.source_path() }; + key_buffer.source.path = reader.source_path(); if (!reader.peek_eof()) { diff --git a/tools/generate_windows_test_targets.py b/tools/generate_windows_test_targets.py index 13b7c67..516446c 100644 --- a/tools/generate_windows_test_targets.py +++ b/tools/generate_windows_test_targets.py @@ -59,13 +59,13 @@ def main(): Application true - v142 + v143 MultiByte Application false - v142 + v143 true MultiByte