mirror of
https://github.com/marzer/tomlplusplus.git
synced 2024-09-15 15:13:21 +00:00
parent
f6450f6ff9
commit
82616e734c
@ -1037,14 +1037,8 @@ TOML_IMPL_NAMESPACE_START
|
||||
if (cp && !is_value_terminator(*cp))
|
||||
set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
|
||||
|
||||
// control for implementations that don't properly implement std::numeric_limits<double>::quiet_NaN()
|
||||
// and/or std::numeric_limits<double>::infinity() (e.g. due to -ffast-math and friends)
|
||||
constexpr uint64_t neg_inf = 0b1111111111110000000000000000000000000000000000000000000000000000ull;
|
||||
constexpr uint64_t pos_inf = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
|
||||
constexpr uint64_t qnan = 0b1111111111111000000000000000000000000000000000000000000000000001ull;
|
||||
double rval;
|
||||
std::memcpy(&rval, inf ? (negative ? &neg_inf : &pos_inf) : &qnan, sizeof(double));
|
||||
return rval;
|
||||
return inf ? (negative ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity())
|
||||
: std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
|
@ -398,39 +398,14 @@ TOML_NAMESPACE_START
|
||||
{
|
||||
if constexpr (std::is_same_v<value_type, double>)
|
||||
{
|
||||
using namespace impl;
|
||||
static constexpr auto pack = [](auto l, auto r) constexpr noexcept
|
||||
{
|
||||
return (static_cast<uint64_t>(unwrap_enum(l)) << 32)
|
||||
| static_cast<uint64_t>(unwrap_enum(r));
|
||||
};
|
||||
|
||||
switch (pack(impl::fpclassify(lhs.val_), impl::fpclassify(rhs)))
|
||||
{
|
||||
case pack(fp_class::pos_inf, fp_class::neg_inf): [[fallthrough]];
|
||||
case pack(fp_class::pos_inf, fp_class::nan): [[fallthrough]];
|
||||
case pack(fp_class::neg_inf, fp_class::pos_inf): [[fallthrough]];
|
||||
case pack(fp_class::neg_inf, fp_class::nan): [[fallthrough]];
|
||||
case pack(fp_class::nan, fp_class::pos_inf): [[fallthrough]];
|
||||
case pack(fp_class::nan, fp_class::neg_inf):
|
||||
return false;
|
||||
|
||||
case pack(fp_class::pos_inf, fp_class::pos_inf): [[fallthrough]];
|
||||
case pack(fp_class::neg_inf, fp_class::neg_inf): [[fallthrough]];
|
||||
case pack(fp_class::nan, fp_class::nan):
|
||||
return true;
|
||||
|
||||
case pack(fp_class::ok, fp_class::ok):
|
||||
return lhs.val_ == rhs;
|
||||
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
|
||||
TOML_UNREACHABLE;
|
||||
const auto lhs_class = impl::fpclassify(lhs.val_);
|
||||
const auto rhs_class = impl::fpclassify(rhs);
|
||||
if (lhs_class == impl::fp_class::nan && rhs_class == impl::fp_class::nan)
|
||||
return true;
|
||||
if ((lhs_class == impl::fp_class::nan) != (rhs_class == impl::fp_class::nan))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return lhs.val_ == rhs;
|
||||
|
||||
return lhs.val_ == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, )
|
||||
|
||||
|
@ -35,9 +35,9 @@ def python_value_to_tomlpp(val):
|
||||
return 'true' if val else 'false'
|
||||
elif isinstance(val, float):
|
||||
if math.isinf(val):
|
||||
return 'make_infinity({})'.format('' if val >= 0.0 else '-1')
|
||||
return f'{"-" if val < 0.0 else ""}std::numeric_limits<double>::infinity()'
|
||||
elif math.isnan(val):
|
||||
return 'make_nan()'
|
||||
return 'std::numeric_limits<double>::quiet_NaN()'
|
||||
else:
|
||||
return str(val)
|
||||
elif isinstance(val, int):
|
||||
|
@ -744,7 +744,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_10, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ R"(sf1)"sv, make_infinity() },
|
||||
{ R"(sf1)"sv, std::numeric_limits<double>::infinity() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
@ -752,7 +752,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_11, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ R"(sf2)"sv, make_infinity() },
|
||||
{ R"(sf2)"sv, std::numeric_limits<double>::infinity() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
@ -760,7 +760,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_12, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ R"(sf2)"sv, make_infinity(-1) },
|
||||
{ R"(sf2)"sv, -std::numeric_limits<double>::infinity() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
@ -768,7 +768,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_13, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ R"(sf4)"sv, make_nan() },
|
||||
{ R"(sf4)"sv, std::numeric_limits<double>::quiet_NaN() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
@ -776,7 +776,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_14, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ R"(sf5)"sv, make_nan() },
|
||||
{ R"(sf5)"sv, std::numeric_limits<double>::quiet_NaN() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
@ -784,7 +784,7 @@ TEST_CASE("conformance - iarna/valid")
|
||||
parsing_should_succeed(FILE_LINE_ARGS, spec_float_15, [](toml::table&& tbl)
|
||||
{
|
||||
auto expected = toml::table{{
|
||||
{ R"(sf6)"sv, make_nan() },
|
||||
{ R"(sf6)"sv, std::numeric_limits<double>::quiet_NaN() },
|
||||
}};
|
||||
REQUIRE(tbl == expected);
|
||||
});
|
||||
|
@ -45,26 +45,17 @@ TOML_POP_WARNINGS
|
||||
while (false)
|
||||
#endif
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
inline double make_infinity(int sign = 1) noexcept
|
||||
{
|
||||
constexpr uint64_t pos_inf = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
|
||||
constexpr uint64_t neg_inf = 0b1111111111110000000000000000000000000000000000000000000000000000ull;
|
||||
double val;
|
||||
std::memcpy(&val, sign >= 0 ? &pos_inf : &neg_inf, sizeof(double));
|
||||
return val;
|
||||
}
|
||||
#define CHECK_SYMMETRIC_RELOP(lhs, op, rhs, result) \
|
||||
CHECK(((lhs) op (rhs)) == (result)); \
|
||||
CHECK(((rhs) op (lhs)) == (result))
|
||||
|
||||
[[nodiscard]]
|
||||
TOML_ATTR(const)
|
||||
inline double make_nan() noexcept
|
||||
{
|
||||
constexpr uint64_t qnan = 0b1111111111111000000000000000000000000000000000000000000000000001ull;
|
||||
double val;
|
||||
std::memcpy(&val, &qnan, sizeof(double));
|
||||
return val;
|
||||
}
|
||||
#define CHECK_SYMMETRIC_EQUAL(lhs, rhs) \
|
||||
CHECK_SYMMETRIC_RELOP(lhs, ==, rhs, true); \
|
||||
CHECK_SYMMETRIC_RELOP(lhs, !=, rhs, false)
|
||||
|
||||
#define CHECK_SYMMETRIC_INEQUAL(lhs, rhs) \
|
||||
CHECK_SYMMETRIC_RELOP(lhs, ==, rhs, false); \
|
||||
CHECK_SYMMETRIC_RELOP(lhs, !=, rhs, true)
|
||||
|
||||
// function_view - adapted from here: https://vittorioromeo.info/index/blog/passing_functions_to_functions.html
|
||||
template <typename Func>
|
||||
@ -230,21 +221,61 @@ inline bool parse_expected_value(
|
||||
REQUIRE(tbl == table{ { { "val"sv, expected } } });
|
||||
REQUIRE(!(tbl != table{ { { "val"sv, expected } } }));
|
||||
|
||||
// check the value relops
|
||||
REQUIRE(*nv.as<value_type>() == expected);
|
||||
REQUIRE(expected == *nv.as<value_type>());
|
||||
REQUIRE(!(*nv.as<value_type>() != expected));
|
||||
REQUIRE(!(expected != *nv.as<value_type>()));
|
||||
|
||||
// check the node_view relops
|
||||
REQUIRE(nv == expected);
|
||||
REQUIRE(expected == nv);
|
||||
REQUIRE(!(nv != expected));
|
||||
REQUIRE(!(expected != nv));
|
||||
// check value/node relops
|
||||
CHECK_SYMMETRIC_EQUAL(*nv.as<value_type>(), *nv.as<value_type>());
|
||||
CHECK_SYMMETRIC_EQUAL(*nv.as<value_type>(), expected);
|
||||
CHECK_SYMMETRIC_EQUAL(nv, expected);
|
||||
|
||||
// make sure source info is correct
|
||||
REQUIRE(nv.node()->source().begin == begin);
|
||||
REQUIRE(nv.node()->source().end == end);
|
||||
CHECK_SYMMETRIC_EQUAL(nv.node()->source().begin, begin);
|
||||
CHECK_SYMMETRIC_EQUAL(nv.node()->source().end, end);
|
||||
|
||||
// check float identities etc
|
||||
if constexpr (std::is_same_v<value_type, double>)
|
||||
{
|
||||
auto& float_node = *nv.as<value_type>();
|
||||
const auto fpcls = impl::fpclassify(*float_node);
|
||||
if (fpcls == impl::fp_class::nan)
|
||||
{
|
||||
CHECK_SYMMETRIC_EQUAL(float_node, std::numeric_limits<double>::quiet_NaN());
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, std::numeric_limits<double>::infinity());
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, -std::numeric_limits<double>::infinity());
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, 1.0);
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, 0.0);
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, -1.0);
|
||||
}
|
||||
else if (fpcls == impl::fp_class::neg_inf || fpcls == impl::fp_class::pos_inf)
|
||||
{
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, std::numeric_limits<double>::quiet_NaN());
|
||||
if (fpcls == impl::fp_class::neg_inf)
|
||||
{
|
||||
CHECK_SYMMETRIC_EQUAL(float_node, -std::numeric_limits<double>::infinity());
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, std::numeric_limits<double>::infinity());
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_SYMMETRIC_EQUAL(float_node, std::numeric_limits<double>::infinity());
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, -std::numeric_limits<double>::infinity());
|
||||
}
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, 1.0);
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, 0.0);
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, -1.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, std::numeric_limits<double>::quiet_NaN());
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, std::numeric_limits<double>::infinity());
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, -std::numeric_limits<double>::infinity());
|
||||
CHECK_SYMMETRIC_EQUAL(float_node, *float_node);
|
||||
if (std::abs(*float_node) <= 1e10)
|
||||
{
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, *float_node + 100.0);
|
||||
CHECK_SYMMETRIC_INEQUAL(float_node, *float_node - 100.0);
|
||||
}
|
||||
CHECK(float_node < std::numeric_limits<double>::infinity());
|
||||
CHECK(float_node > -std::numeric_limits<double>::infinity());
|
||||
}
|
||||
}
|
||||
|
||||
// steal the val for round-trip tests
|
||||
if (!stolen_value)
|
||||
|
49
toml.hpp
49
toml.hpp
@ -2838,39 +2838,14 @@ TOML_NAMESPACE_START
|
||||
{
|
||||
if constexpr (std::is_same_v<value_type, double>)
|
||||
{
|
||||
using namespace impl;
|
||||
static constexpr auto pack = [](auto l, auto r) constexpr noexcept
|
||||
{
|
||||
return (static_cast<uint64_t>(unwrap_enum(l)) << 32)
|
||||
| static_cast<uint64_t>(unwrap_enum(r));
|
||||
};
|
||||
|
||||
switch (pack(impl::fpclassify(lhs.val_), impl::fpclassify(rhs)))
|
||||
{
|
||||
case pack(fp_class::pos_inf, fp_class::neg_inf): [[fallthrough]];
|
||||
case pack(fp_class::pos_inf, fp_class::nan): [[fallthrough]];
|
||||
case pack(fp_class::neg_inf, fp_class::pos_inf): [[fallthrough]];
|
||||
case pack(fp_class::neg_inf, fp_class::nan): [[fallthrough]];
|
||||
case pack(fp_class::nan, fp_class::pos_inf): [[fallthrough]];
|
||||
case pack(fp_class::nan, fp_class::neg_inf):
|
||||
return false;
|
||||
|
||||
case pack(fp_class::pos_inf, fp_class::pos_inf): [[fallthrough]];
|
||||
case pack(fp_class::neg_inf, fp_class::neg_inf): [[fallthrough]];
|
||||
case pack(fp_class::nan, fp_class::nan):
|
||||
return true;
|
||||
|
||||
case pack(fp_class::ok, fp_class::ok):
|
||||
return lhs.val_ == rhs;
|
||||
|
||||
TOML_NO_DEFAULT_CASE;
|
||||
}
|
||||
|
||||
TOML_UNREACHABLE;
|
||||
const auto lhs_class = impl::fpclassify(lhs.val_);
|
||||
const auto rhs_class = impl::fpclassify(rhs);
|
||||
if (lhs_class == impl::fp_class::nan && rhs_class == impl::fp_class::nan)
|
||||
return true;
|
||||
if ((lhs_class == impl::fp_class::nan) != (rhs_class == impl::fp_class::nan))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return lhs.val_ == rhs;
|
||||
|
||||
return lhs.val_ == rhs;
|
||||
}
|
||||
TOML_ASYMMETRICAL_EQUALITY_OPS(const value&, value_arg, )
|
||||
[[nodiscard]] friend bool operator < (const value& lhs, value_arg rhs) noexcept { return lhs.val_ < rhs; }
|
||||
@ -9619,14 +9594,8 @@ TOML_IMPL_NAMESPACE_START
|
||||
if (cp && !is_value_terminator(*cp))
|
||||
set_error_and_return_default("expected value-terminator, saw '"sv, to_sv(*cp), "'"sv);
|
||||
|
||||
// control for implementations that don't properly implement std::numeric_limits<double>::quiet_NaN()
|
||||
// and/or std::numeric_limits<double>::infinity() (e.g. due to -ffast-math and friends)
|
||||
constexpr uint64_t neg_inf = 0b1111111111110000000000000000000000000000000000000000000000000000ull;
|
||||
constexpr uint64_t pos_inf = 0b0111111111110000000000000000000000000000000000000000000000000000ull;
|
||||
constexpr uint64_t qnan = 0b1111111111111000000000000000000000000000000000000000000000000001ull;
|
||||
double rval;
|
||||
std::memcpy(&rval, inf ? (negative ? &neg_inf : &pos_inf) : &qnan, sizeof(double));
|
||||
return rval;
|
||||
return inf ? (negative ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity())
|
||||
: std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
TOML_PUSH_WARNINGS
|
||||
|
Loading…
Reference in New Issue
Block a user