From 2414d904a837aa2d0b795f086081df2d53b57d98 Mon Sep 17 00:00:00 2001 From: Mark Gillard Date: Mon, 3 Apr 2023 19:34:39 +0300 Subject: [PATCH] fixed `value_flags` not preserved during insertion (#108) also: - fixed `toml::value::flags()` not being cleared when `std::move`-ing a value - fixed #195 --- CHANGELOG.md | 10 +++ README.md | 4 - include/toml++/impl/forward_declarations.h | 8 +- include/toml++/impl/make_node.h | 2 +- include/toml++/impl/parse_result.h | 2 +- include/toml++/impl/parser.h | 2 +- include/toml++/impl/parser.inl | 8 +- include/toml++/impl/table.h | 4 +- include/toml++/impl/unicode.h | 2 +- include/toml++/impl/value.h | 20 ++++- tests/manipulating_arrays.cpp | 89 ++++++++++++++++++++++ tests/manipulating_tables.cpp | 67 ++++++++++++++++ tests/user_feedback.cpp | 2 +- toml.hpp | 47 +++++++----- 14 files changed, 228 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 849e47e..17e2874 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,16 @@ template: --> +## Unreleased + +#### Fixes + +- fixed `value_flags` not being preserved correctly when inserting into tables and arrays (#108) (@LebJe) +- fixed `toml::value::flags()` not being cleared when `std::move`-ing a value +- fixed error in README (#195) (@andrewkcorcoran) + +

+ ## v3.3.0 [Released](https://github.com/marzer/tomlplusplus/releases/tag/v3.3.0) 2023-01-29 diff --git a/README.md b/README.md index 117af5f..4fa63f7 100644 --- a/README.md +++ b/README.md @@ -177,12 +177,8 @@ FetchContent_MakeAvailable(tomlplusplus) ```plaintext git submodule add --depth 1 https://github.com/marzer/tomlplusplus.git tomlplusplus -git config -f .gitmodules submodule.tomlplusplus.shallow true ``` -> ⚠️ The toml++ repository has some submodules of its own, but **they are only used for testing**! -> You should **not** use the `--recursive` option for regular library consumption. - ### Other environments and package managers The C++ tooling ecosystem is a fractal nightmare of unbridled chaos so naturally I'm not up-to-speed with all of the diff --git a/include/toml++/impl/forward_declarations.h b/include/toml++/impl/forward_declarations.h index 49f6ac5..7ffc99d 100644 --- a/include/toml++/impl/forward_declarations.h +++ b/include/toml++/impl/forward_declarations.h @@ -119,7 +119,7 @@ TOML_IMPL_NAMESPACE_START class parser; TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS - // clang-format off + // clang-format off inline constexpr std::string_view control_char_escapes[] = { @@ -366,7 +366,7 @@ TOML_NAMESPACE_START // abi namespace T value; }; template - inserter(T &&) -> inserter; + inserter(T&&) -> inserter; template inserter(T&) -> inserter; @@ -620,8 +620,8 @@ TOML_IMPL_NAMESPACE_START && digits <= 53 // DBL_MANT_DIG && digits10 <= 15; // DBL_DIG - static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG - && digits10 >= 15; // DBL_DIG + static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG + && digits10 >= 15; // DBL_DIG static constexpr bool can_partially_represent_native = digits > 0 && digits10 > 0; }; diff --git a/include/toml++/impl/make_node.h b/include/toml++/impl/make_node.h index 4b754b7..50d882d 100644 --- a/include/toml++/impl/make_node.h +++ b/include/toml++/impl/make_node.h @@ -36,7 +36,7 @@ TOML_IMPL_NAMESPACE_START // copy/move ctor if constexpr (std::is_same_v, value_type>) { - out = new value_type{ static_cast(val) }; + out = new value_type{ static_cast(val), flags }; } // creating from raw value diff --git a/include/toml++/impl/parse_result.h b/include/toml++/impl/parse_result.h index ceaa6e1..3292e8d 100644 --- a/include/toml++/impl/parse_result.h +++ b/include/toml++/impl/parse_result.h @@ -474,7 +474,7 @@ TOML_NAMESPACE_START return err_ ? node_view{} : table()[key]; } -#endif // TOML_ENABLE_WINDOWS_COMPAT +#endif // TOML_ENABLE_WINDOWS_COMPAT /// @} diff --git a/include/toml++/impl/parser.h b/include/toml++/impl/parser.h index 740166f..78b030b 100644 --- a/include/toml++/impl/parser.h +++ b/include/toml++/impl/parser.h @@ -379,7 +379,7 @@ TOML_NAMESPACE_START return parse(std::u8string_view{ str, len }); } -#endif // TOML_HAS_CHAR8 +#endif // TOML_HAS_CHAR8 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS } diff --git a/include/toml++/impl/parser.inl b/include/toml++/impl/parser.inl index 27de2b0..ef9cfde 100644 --- a/include/toml++/impl/parser.inl +++ b/include/toml++/impl/parser.inl @@ -473,11 +473,11 @@ TOML_ANON_NAMESPACE_START template utf8_reader(std::basic_string_view, std::string_view) -> utf8_reader>; template - utf8_reader(std::basic_string_view, std::string &&) -> utf8_reader>; + utf8_reader(std::basic_string_view, std::string&&) -> utf8_reader>; template utf8_reader(std::basic_istream&, std::string_view) -> utf8_reader>; template - utf8_reader(std::basic_istream&, std::string &&) -> utf8_reader>; + utf8_reader(std::basic_istream&, std::string&&) -> utf8_reader>; #if TOML_EXCEPTIONS #define utf8_buffered_reader_error_check(...) static_assert(true) @@ -2122,7 +2122,7 @@ TOML_IMPL_NAMESPACE_START return (fragments[0].value + fragments[1].value) * pow(2.0, fragments[2].value * exponent_sign) * sign; -#else // !TOML_LANG_UNRELEASED +#else // !TOML_LANG_UNRELEASED set_error_and_return_default("hexadecimal floating-point values are not supported " "in TOML 1.0.0 and earlier"sv); @@ -3906,7 +3906,7 @@ TOML_NAMESPACE_START return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) }); } -#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT +#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS } diff --git a/include/toml++/impl/table.h b/include/toml++/impl/table.h index c11faee..1ce1792 100644 --- a/include/toml++/impl/table.h +++ b/include/toml++/impl/table.h @@ -1216,7 +1216,7 @@ TOML_NAMESPACE_START return contains(impl::narrow(key)); } -#endif // TOML_ENABLE_WINDOWS_COMPAT +#endif // TOML_ENABLE_WINDOWS_COMPAT /// @} @@ -1900,7 +1900,7 @@ TOML_NAMESPACE_START return node_view{ get(key) }; } -#endif // TOML_ENABLE_WINDOWS_COMPAT +#endif // TOML_ENABLE_WINDOWS_COMPAT /// @} diff --git a/include/toml++/impl/unicode.h b/include/toml++/impl/unicode.h index acb30d8..3f2b753 100644 --- a/include/toml++/impl/unicode.h +++ b/include/toml++/impl/unicode.h @@ -168,7 +168,7 @@ TOML_IMPL_NAMESPACE_START const auto type = state_table[byte]; codepoint = static_cast(has_code_point() ? (uint_least32_t{ 255u } >> type) & byte - : (byte & uint_least32_t{ 63u }) + : (byte& uint_least32_t{ 63u }) | (static_cast(codepoint) << 6)); state = state_table[state + uint_least32_t{ 256u } + type]; diff --git a/include/toml++/impl/value.h b/include/toml++/impl/value.h index ae12e97..8e3963c 100644 --- a/include/toml++/impl/value.h +++ b/include/toml++/impl/value.h @@ -7,6 +7,7 @@ #include "date_time.h" #include "node.h" #include "print_to_stream.h" +#include "std_utility.h" #include "header_start.h" TOML_DISABLE_ARITHMETIC_WARNINGS; @@ -192,6 +193,16 @@ TOML_IMPL_NAMESPACE_START } return { static_cast(val) }; } + + template + struct is_val_ctor_with_flags : std::false_type + {}; + + template + struct is_val_ctor_with_flags : std::bool_constant< // + (is_node && is_value) // + &&(std::is_same_v, value_flags>)> + {}; } TOML_IMPL_NAMESPACE_END; /// \endcond @@ -253,7 +264,7 @@ TOML_NAMESPACE_START /// /// \tparam Args Constructor argument types. /// \param args Arguments to forward to the internal value's constructor. - template + TOML_HIDDEN_CONSTRAINT(!impl::is_val_ctor_with_flags::value, typename... Args) TOML_NODISCARD_CTOR explicit value(Args&&... args) noexcept(noexcept(value_type( impl::native_value_maker...>::make(static_cast(args)...)))) @@ -293,7 +304,7 @@ TOML_NAMESPACE_START value(value&& other) noexcept // : node(std::move(other)), val_{ std::move(other.val_) }, - flags_{ other.flags_ } + flags_{ std::exchange(other.flags_, value_flags{}) } { #if TOML_LIFETIME_HOOKS TOML_VALUE_CREATED; @@ -310,6 +321,7 @@ TOML_NAMESPACE_START #if TOML_LIFETIME_HOOKS TOML_VALUE_CREATED; #endif + other.flags_ = {}; } /// \brief Copy-assignment operator. @@ -328,7 +340,7 @@ TOML_NAMESPACE_START { node::operator=(std::move(rhs)); val_ = std::move(rhs.val_); - flags_ = rhs.flags_; + flags_ = std::exchange(rhs.flags_, value_flags{}); } return *this; } @@ -968,6 +980,8 @@ TOML_NAMESPACE_START template value(T) -> value>>; + template + value(T, value_flags) -> value>>; template TOML_NODISCARD diff --git a/tests/manipulating_arrays.cpp b/tests/manipulating_arrays.cpp index b6ab0de..e08e6c0 100644 --- a/tests/manipulating_arrays.cpp +++ b/tests/manipulating_arrays.cpp @@ -453,6 +453,23 @@ TEST_CASE("arrays - insertion and erasure") CHECK(*arr.back().as_string() == "test4"sv); #endif // TOML_ENABLE_WINDOWS_COMPAT + + // push_back with value_flags + { + arr.clear(); + + auto hex = toml::value{ 1 }; + hex.flags(value_flags::format_as_hexadecimal); + CHECK(hex.flags() == value_flags::format_as_hexadecimal); + + arr.push_back(hex); + CHECK(hex.flags() == value_flags::format_as_hexadecimal); + CHECK(arr.back().as_integer()->flags() == value_flags::format_as_hexadecimal); + + arr.push_back(std::move(hex)); + CHECK(hex.flags() == value_flags{}); + CHECK(arr.back().as_integer()->flags() == value_flags::format_as_hexadecimal); + } } TEST_CASE("arrays - flattening") @@ -534,3 +551,75 @@ TEST_CASE("arrays - resizing and truncation") CHECK(arr.size() == 6u); CHECK(arr == array{ 1, 2, 42, 42, 42, 42 }); } + +TEST_CASE("arrays - for_each") +{ + const auto arr = array{ 1, 2.0, 3, "four", false }; + + SECTION("type checking") + { + int count = 0; + int ints = 0; + int floats = 0; + int numbers = 0; + int strings = 0; + int bools = 0; + arr.for_each( + [&](const auto& v) noexcept + { + count++; + if constexpr (toml::is_integer) + ints++; + if constexpr (toml::is_floating_point) + floats++; + if constexpr (toml::is_number) + numbers++; + if constexpr (toml::is_string) + strings++; + if constexpr (toml::is_boolean) + bools++; + }); + CHECK(count == 5); + CHECK(ints == 2); + CHECK(floats == 1); + CHECK(numbers == (ints + floats)); + CHECK(strings == 1); + CHECK(bools == 1); + } + + SECTION("early-exit (elem, index)") + { + int count = 0; + arr.for_each( + [&](const auto& elem, size_t /*idx*/) noexcept -> bool + { + count++; + return !toml::is_string; + }); + CHECK(count == 4); + } + + SECTION("early-exit (elem)") + { + int count = 0; + arr.for_each( + [&](const auto& elem) noexcept -> bool + { + count++; + return !toml::is_string; + }); + CHECK(count == 4); + } + + SECTION("early-exit (index, elem)") + { + int count = 0; + arr.for_each( + [&](size_t /*idx*/, const auto& elem) noexcept -> bool + { + count++; + return !toml::is_string; + }); + CHECK(count == 4); + } +} diff --git a/tests/manipulating_tables.cpp b/tests/manipulating_tables.cpp index 43bb6f4..82561b7 100644 --- a/tests/manipulating_tables.cpp +++ b/tests/manipulating_tables.cpp @@ -403,6 +403,23 @@ TEST_CASE("tables - insertion and erasure") CHECK(tbl.size() == 0u); #endif // TOML_ENABLE_WINDOWS_COMPAT + + // insert with value_flags + { + tbl.clear(); + + auto hex = toml::value{ 1 }; + hex.flags(value_flags::format_as_hexadecimal); + CHECK(hex.flags() == value_flags::format_as_hexadecimal); + + tbl.insert("hex", hex); + CHECK(hex.flags() == value_flags::format_as_hexadecimal); + CHECK(tbl["hex"].as_integer()->flags() == value_flags::format_as_hexadecimal); + + tbl.insert("hex2", std::move(hex)); + CHECK(hex.flags() == value_flags{}); + CHECK(tbl["hex2"].as_integer()->flags() == value_flags::format_as_hexadecimal); + } } TEST_CASE("tables - toml_formatter") @@ -599,3 +616,53 @@ key8 = [ == expected_without_indentation); } } + +TEST_CASE("tables - for_each") +{ + const auto tbl = table{ { "a", 1 }, { "b", 2.0 }, { "c", 3 }, { "d", "four" }, { "e", false } }; + + SECTION("type checking") + { + int count = 0; + int ints = 0; + int floats = 0; + int numbers = 0; + int strings = 0; + int bools = 0; + tbl.for_each( + [&](const auto& v) noexcept + { + count++; + if constexpr (toml::is_integer) + ints++; + if constexpr (toml::is_floating_point) + floats++; + if constexpr (toml::is_number) + numbers++; + if constexpr (toml::is_string) + strings++; + if constexpr (toml::is_boolean) + bools++; + }); + CHECK(count == 5); + CHECK(ints == 2); + CHECK(floats == 1); + CHECK(numbers == (ints + floats)); + CHECK(strings == 1); + CHECK(bools == 1); + } + + SECTION("early-exit (key, val)") + { + int count = 0; + tbl.for_each([&](const key& /*k*/, const auto& /*v*/) noexcept -> bool { return ++count < 3; }); + CHECK(count == 3); + } + + SECTION("early-exit (val)") + { + int count = 0; + tbl.for_each([&](const auto& /*v*/) noexcept -> bool { return ++count < 3; }); + CHECK(count == 3); + } +} diff --git a/tests/user_feedback.cpp b/tests/user_feedback.cpp index b754280..b8fdbd4 100644 --- a/tests/user_feedback.cpp +++ b/tests/user_feedback.cpp @@ -129,7 +129,7 @@ TEST_CASE("user feedback") }); } - SECTION("tomlplusplus/issues/69") // https://github.com/marzer/tomlplusplus/issues/69 + SECTION("tomlplusplus/issues/69") // https://github.com/marzer/tomlplusplus/issues/69 { using namespace toml::literals; // should compile without namespace ambiguity auto table = "[table]\nkey=\"value\""_toml; diff --git a/toml.hpp b/toml.hpp index e5a6715..b0af20e 100644 --- a/toml.hpp +++ b/toml.hpp @@ -1320,7 +1320,7 @@ TOML_IMPL_NAMESPACE_START class parser; TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS - // clang-format off + // clang-format off inline constexpr std::string_view control_char_escapes[] = { @@ -1466,7 +1466,7 @@ TOML_NAMESPACE_START // abi namespace T value; }; template - inserter(T &&) -> inserter; + inserter(T&&) -> inserter; template inserter(T&) -> inserter; @@ -1714,8 +1714,8 @@ TOML_IMPL_NAMESPACE_START && digits <= 53 // DBL_MANT_DIG && digits10 <= 15; // DBL_DIG - static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG - && digits10 >= 15; // DBL_DIG + static constexpr bool can_represent_native = digits >= 53 // DBL_MANT_DIG + && digits10 >= 15; // DBL_DIG static constexpr bool can_partially_represent_native = digits > 0 && digits10 > 0; }; @@ -4721,6 +4721,16 @@ TOML_IMPL_NAMESPACE_START } return { static_cast(val) }; } + + template + struct is_val_ctor_with_flags : std::false_type + {}; + + template + struct is_val_ctor_with_flags : std::bool_constant< // + (is_node && is_value) // + &&(std::is_same_v, value_flags>)> + {}; } TOML_IMPL_NAMESPACE_END; @@ -4759,7 +4769,7 @@ TOML_NAMESPACE_START std::string_view, std::conditional_t, value_type, const value_type&>>); - template + TOML_HIDDEN_CONSTRAINT(!impl::is_val_ctor_with_flags::value, typename... Args) TOML_NODISCARD_CTOR explicit value(Args&&... args) noexcept(noexcept(value_type( impl::native_value_maker...>::make(static_cast(args)...)))) @@ -4796,7 +4806,7 @@ TOML_NAMESPACE_START value(value&& other) noexcept // : node(std::move(other)), val_{ std::move(other.val_) }, - flags_{ other.flags_ } + flags_{ std::exchange(other.flags_, value_flags{}) } { #if TOML_LIFETIME_HOOKS TOML_VALUE_CREATED; @@ -4812,6 +4822,7 @@ TOML_NAMESPACE_START #if TOML_LIFETIME_HOOKS TOML_VALUE_CREATED; #endif + other.flags_ = {}; } value& operator=(const value& rhs) noexcept @@ -4828,7 +4839,7 @@ TOML_NAMESPACE_START { node::operator=(std::move(rhs)); val_ = std::move(rhs.val_); - flags_ = rhs.flags_; + flags_ = std::exchange(rhs.flags_, value_flags{}); } return *this; } @@ -5316,6 +5327,8 @@ TOML_NAMESPACE_START template value(T) -> value>>; + template + value(T, value_flags) -> value>>; template TOML_NODISCARD @@ -5649,7 +5662,7 @@ TOML_IMPL_NAMESPACE_START // copy/move ctor if constexpr (std::is_same_v, value_type>) { - out = new value_type{ static_cast(val) }; + out = new value_type{ static_cast(val), flags }; } // creating from raw value @@ -7967,7 +7980,7 @@ TOML_NAMESPACE_START return contains(impl::narrow(key)); } -#endif // TOML_ENABLE_WINDOWS_COMPAT +#endif // TOML_ENABLE_WINDOWS_COMPAT private: @@ -8266,7 +8279,7 @@ TOML_NAMESPACE_START return node_view{ get(key) }; } -#endif // TOML_ENABLE_WINDOWS_COMPAT +#endif // TOML_ENABLE_WINDOWS_COMPAT private: @@ -8674,7 +8687,7 @@ TOML_IMPL_NAMESPACE_START const auto type = state_table[byte]; codepoint = static_cast(has_code_point() ? (uint_least32_t{ 255u } >> type) & byte - : (byte & uint_least32_t{ 63u }) + : (byte& uint_least32_t{ 63u }) | (static_cast(codepoint) << 6)); state = state_table[state + uint_least32_t{ 256u } + type]; @@ -9160,7 +9173,7 @@ TOML_NAMESPACE_START return err_ ? node_view{} : table()[key]; } -#endif // TOML_ENABLE_WINDOWS_COMPAT +#endif // TOML_ENABLE_WINDOWS_COMPAT #if TOML_ENABLE_FORMATTERS @@ -9288,7 +9301,7 @@ TOML_NAMESPACE_START return parse(std::u8string_view{ str, len }); } -#endif // TOML_HAS_CHAR8 +#endif // TOML_HAS_CHAR8 TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS } @@ -12595,11 +12608,11 @@ TOML_ANON_NAMESPACE_START template utf8_reader(std::basic_string_view, std::string_view) -> utf8_reader>; template - utf8_reader(std::basic_string_view, std::string &&) -> utf8_reader>; + utf8_reader(std::basic_string_view, std::string&&) -> utf8_reader>; template utf8_reader(std::basic_istream&, std::string_view) -> utf8_reader>; template - utf8_reader(std::basic_istream&, std::string &&) -> utf8_reader>; + utf8_reader(std::basic_istream&, std::string&&) -> utf8_reader>; #if TOML_EXCEPTIONS #define utf8_buffered_reader_error_check(...) static_assert(true) @@ -14240,7 +14253,7 @@ TOML_IMPL_NAMESPACE_START return (fragments[0].value + fragments[1].value) * pow(2.0, fragments[2].value * exponent_sign) * sign; -#else // !TOML_LANG_UNRELEASED +#else // !TOML_LANG_UNRELEASED set_error_and_return_default("hexadecimal floating-point values are not supported " "in TOML 1.0.0 and earlier"sv); @@ -16018,7 +16031,7 @@ TOML_NAMESPACE_START return TOML_ANON_NAMESPACE::do_parse(TOML_ANON_NAMESPACE::utf8_reader{ doc, impl::narrow(source_path) }); } -#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT +#endif // TOML_HAS_CHAR8 && TOML_ENABLE_WINDOWS_COMPAT TOML_ABI_NAMESPACE_END; // TOML_EXCEPTIONS }