fixed value_flags not preserved during insertion (#108)

also:
- fixed `toml::value::flags()` not being cleared when `std::move`-ing a value
- fixed #195
This commit is contained in:
Mark Gillard 2023-04-03 19:34:39 +03:00
parent 7eb2ffcc09
commit 2414d904a8
14 changed files with 228 additions and 39 deletions

View File

@ -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)
<br><br>
## v3.3.0
[Released](https://github.com/marzer/tomlplusplus/releases/tag/v3.3.0) 2023-01-29

View File

@ -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
```
> ⚠&#xFE0F; 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

View File

@ -366,7 +366,7 @@ TOML_NAMESPACE_START // abi namespace
T value;
};
template <typename T>
inserter(T &&) -> inserter<T&&>;
inserter(T&&) -> inserter<T&&>;
template <typename T>
inserter(T&) -> inserter<T&>;

View File

@ -36,7 +36,7 @@ TOML_IMPL_NAMESPACE_START
// copy/move ctor
if constexpr (std::is_same_v<remove_cvref<T>, value_type>)
{
out = new value_type{ static_cast<T&&>(val) };
out = new value_type{ static_cast<T&&>(val), flags };
}
// creating from raw value

View File

@ -473,11 +473,11 @@ TOML_ANON_NAMESPACE_START
template <typename Char>
utf8_reader(std::basic_string_view<Char>, std::string_view) -> utf8_reader<std::basic_string_view<Char>>;
template <typename Char>
utf8_reader(std::basic_string_view<Char>, std::string &&) -> utf8_reader<std::basic_string_view<Char>>;
utf8_reader(std::basic_string_view<Char>, std::string&&) -> utf8_reader<std::basic_string_view<Char>>;
template <typename Char>
utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
template <typename Char>
utf8_reader(std::basic_istream<Char>&, std::string &&) -> utf8_reader<std::basic_istream<Char>>;
utf8_reader(std::basic_istream<Char>&, std::string&&) -> utf8_reader<std::basic_istream<Char>>;
#if TOML_EXCEPTIONS
#define utf8_buffered_reader_error_check(...) static_assert(true)

View File

@ -168,7 +168,7 @@ TOML_IMPL_NAMESPACE_START
const auto type = state_table[byte];
codepoint = static_cast<char32_t>(has_code_point() ? (uint_least32_t{ 255u } >> type) & byte
: (byte & uint_least32_t{ 63u })
: (byte& uint_least32_t{ 63u })
| (static_cast<uint_least32_t>(codepoint) << 6));
state = state_table[state + uint_least32_t{ 256u } + type];

View File

@ -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<T>(val) };
}
template <typename...>
struct is_val_ctor_with_flags : std::false_type
{};
template <typename T, typename U>
struct is_val_ctor_with_flags<T, U> : std::bool_constant< //
(is_node<T> && is_value<T>) //
&&(std::is_same_v<remove_cvref<U>, 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 <typename... Args>
TOML_HIDDEN_CONSTRAINT(!impl::is_val_ctor_with_flags<Args...>::value, typename... Args)
TOML_NODISCARD_CTOR
explicit value(Args&&... args) noexcept(noexcept(value_type(
impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(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 <typename T>
value(T) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
template <typename T>
value(T, value_flags) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
template <typename T>
TOML_NODISCARD

View File

@ -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<decltype(v)>)
ints++;
if constexpr (toml::is_floating_point<decltype(v)>)
floats++;
if constexpr (toml::is_number<decltype(v)>)
numbers++;
if constexpr (toml::is_string<decltype(v)>)
strings++;
if constexpr (toml::is_boolean<decltype(v)>)
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<decltype(elem)>;
});
CHECK(count == 4);
}
SECTION("early-exit (elem)")
{
int count = 0;
arr.for_each(
[&](const auto& elem) noexcept -> bool
{
count++;
return !toml::is_string<decltype(elem)>;
});
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<decltype(elem)>;
});
CHECK(count == 4);
}
}

View File

@ -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<decltype(v)>)
ints++;
if constexpr (toml::is_floating_point<decltype(v)>)
floats++;
if constexpr (toml::is_number<decltype(v)>)
numbers++;
if constexpr (toml::is_string<decltype(v)>)
strings++;
if constexpr (toml::is_boolean<decltype(v)>)
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);
}
}

View File

@ -1466,7 +1466,7 @@ TOML_NAMESPACE_START // abi namespace
T value;
};
template <typename T>
inserter(T &&) -> inserter<T&&>;
inserter(T&&) -> inserter<T&&>;
template <typename T>
inserter(T&) -> inserter<T&>;
@ -4721,6 +4721,16 @@ TOML_IMPL_NAMESPACE_START
}
return { static_cast<T>(val) };
}
template <typename...>
struct is_val_ctor_with_flags : std::false_type
{};
template <typename T, typename U>
struct is_val_ctor_with_flags<T, U> : std::bool_constant< //
(is_node<T> && is_value<T>) //
&&(std::is_same_v<remove_cvref<U>, value_flags>)>
{};
}
TOML_IMPL_NAMESPACE_END;
@ -4759,7 +4769,7 @@ TOML_NAMESPACE_START
std::string_view,
std::conditional_t<impl::is_one_of<value_type, double, int64_t, bool>, value_type, const value_type&>>);
template <typename... Args>
TOML_HIDDEN_CONSTRAINT(!impl::is_val_ctor_with_flags<Args...>::value, typename... Args)
TOML_NODISCARD_CTOR
explicit value(Args&&... args) noexcept(noexcept(value_type(
impl::native_value_maker<value_type, std::decay_t<Args>...>::make(static_cast<Args&&>(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 <typename T>
value(T) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
template <typename T>
value(T, value_flags) -> value<impl::native_type_of<impl::remove_cvref<T>>>;
template <typename T>
TOML_NODISCARD
@ -5649,7 +5662,7 @@ TOML_IMPL_NAMESPACE_START
// copy/move ctor
if constexpr (std::is_same_v<remove_cvref<T>, value_type>)
{
out = new value_type{ static_cast<T&&>(val) };
out = new value_type{ static_cast<T&&>(val), flags };
}
// creating from raw value
@ -8674,7 +8687,7 @@ TOML_IMPL_NAMESPACE_START
const auto type = state_table[byte];
codepoint = static_cast<char32_t>(has_code_point() ? (uint_least32_t{ 255u } >> type) & byte
: (byte & uint_least32_t{ 63u })
: (byte& uint_least32_t{ 63u })
| (static_cast<uint_least32_t>(codepoint) << 6));
state = state_table[state + uint_least32_t{ 256u } + type];
@ -12595,11 +12608,11 @@ TOML_ANON_NAMESPACE_START
template <typename Char>
utf8_reader(std::basic_string_view<Char>, std::string_view) -> utf8_reader<std::basic_string_view<Char>>;
template <typename Char>
utf8_reader(std::basic_string_view<Char>, std::string &&) -> utf8_reader<std::basic_string_view<Char>>;
utf8_reader(std::basic_string_view<Char>, std::string&&) -> utf8_reader<std::basic_string_view<Char>>;
template <typename Char>
utf8_reader(std::basic_istream<Char>&, std::string_view) -> utf8_reader<std::basic_istream<Char>>;
template <typename Char>
utf8_reader(std::basic_istream<Char>&, std::string &&) -> utf8_reader<std::basic_istream<Char>>;
utf8_reader(std::basic_istream<Char>&, std::string&&) -> utf8_reader<std::basic_istream<Char>>;
#if TOML_EXCEPTIONS
#define utf8_buffered_reader_error_check(...) static_assert(true)