Compare commits

..
Author SHA1 Message Date
Claude 27bb251d17 Return std::size_t from the hash helper in the ordered_json test
MSVC (Win32) rejected the implicit conversion of the unsigned long long
product to the 32-bit std::size_t (C4244 as an error). Also note when
JSON_NO_THREAD_LOCAL is set in the regression test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N5NasAgbDGG28MqXjQvLqp
Signed-off-by: Claude <noreply@anthropic.com>
2026-11-02 09:52:13 +00:00
10 changed files with 96 additions and 84 deletions

No files matched your search

@@ -545,9 +545,12 @@ class input_stream_adapter
std::char_traits<char>::int_type get_character_slow() std::char_traits<char>::int_type get_character_slow()
{ {
#if !JSON_DISABLE_STREAM_BULK_SCAN #if !JSON_DISABLE_STREAM_BULK_SCAN
// the get area is exhausted (get_character() handles the other case), // sbumpc() refills the get area if it is exhausted
// so sbumpc() refills it const bool refill = streambuf_access::get_ptr(sb) == streambuf_access::get_end(sb);
if (JSON_HEDLEY_UNLIKELY(refill))
{
save_token_segment(); save_token_segment();
}
#endif #endif
auto res = sb->sbumpc(); auto res = sb->sbumpc();
@@ -560,13 +563,17 @@ class input_stream_adapter
is->clear(is->rdstate() | std::ios::eofbit); is->clear(is->rdstate() | std::ios::eofbit);
} }
#if !JSON_DISABLE_STREAM_BULK_SCAN #if !JSON_DISABLE_STREAM_BULK_SCAN
else else if (JSON_HEDLEY_UNLIKELY(refill))
{ {
// the consumed character is at gptr() - 1, unless the streambuf // the consumed character is at gptr() - 1, unless the streambuf
// has no get area and returned it from uflow() // has no get area and returned it from uflow()
const char* const next = streambuf_access::get_ptr(sb); const char* const next = streambuf_access::get_ptr(sb);
after_refill(res, next != nullptr && next != streambuf_access::get_begin(sb)); after_refill(res, next != nullptr && next != streambuf_access::get_begin(sb));
} }
else
{
current_in_get_area = true; // LCOV_EXCL_LINE (called only when the get area is exhausted)
}
#endif #endif
return res; return res;
} }
+4 -3
View File
@@ -1737,7 +1737,7 @@ class json_sax_dom_callback_parser : public json_sax_dom_error_state
key_stack.push_back(val); key_stack.push_back(val);
// add discarded value at the given key and store the reference for later // add discarded value at the given key and store the reference for later
if (keep) if (keep && ref_stack.back())
{ {
auto& obj = *ref_stack.back()->m_data.m_value.object; auto& obj = *ref_stack.back()->m_data.m_value.object;
// a single lookup: insert the placeholder, or find the existing member // a single lookup: insert the placeholder, or find the existing member
@@ -1794,7 +1794,7 @@ class json_sax_dom_callback_parser : public json_sax_dom_error_state
const string_t object_key = pop_container(); const string_t object_key = pop_container();
if (!ref_stack.empty() && ref_stack.back()) if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
{ {
// remove discarded value // remove discarded value
remove_discarded_value(*ref_stack.back(), object_key); remove_discarded_value(*ref_stack.back(), object_key);
@@ -1960,7 +1960,8 @@ class json_sax_dom_callback_parser : public json_sax_dom_error_state
*/ */
string_t current_key() const string_t current_key() const
{ {
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_object()) if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_object()
&& !key_stack.empty())
{ {
return key_stack.back(); return key_stack.back();
} }
+8 -13
View File
@@ -300,16 +300,14 @@ class lexer : public lexer_base<BasicJsonType>
/// calls would (including the position and token bookkeeping of a /// calls would (including the position and token bookkeeping of a
/// streaming adapter, see bulk_consume) and leaves @a current holding the last of /// streaming adapter, see bulk_consume) and leaves @a current holding the last of
/// the 4 digits, just as the last such get() would; the codepoint is /// the 4 digits, just as the last such get() would; the codepoint is
/// written to @a out. Makes no state change and returns false for fewer /// written to @a out. Makes no state change and returns false for a
/// than 4 remaining bytes or any of the 4 bytes not being a hex digit, so /// pending unget, fewer than 4 remaining bytes, or any of the 4 bytes not
/// the caller falls back unchanged to the per-character loop, which then /// being a hex digit, so the caller falls back unchanged to the
/// reports the same diagnostic (stopping at the first invalid digit) as /// per-character loop, which then reports the same diagnostic (stopping
/// before this optimization. /// at the first invalid digit) as before this optimization.
bool get_codepoint_bulk(std::true_type /*bulk*/, int& out) bool get_codepoint_bulk(std::true_type /*bulk*/, int& out)
{ {
// no unget is pending inside a string (see get_after_string_run()) if (next_unget || ia.bulk_remaining() < 4)
JSON_ASSERT(!next_unget);
if (ia.bulk_remaining() < 4)
{ {
return false; return false;
} }
@@ -1411,7 +1409,7 @@ scan_number_done:
return token_type::value_unsigned; return token_type::value_unsigned;
} }
} }
else // value_integer (the callers handle value_float themselves) else if (number_type == token_type::value_integer)
{ {
if (parse_integer_signed(first, last, value_integer)) if (parse_integer_signed(first, last, value_integer))
{ {
@@ -1782,10 +1780,7 @@ scan_number_done:
/// the error at the right character /// the error at the right character
JSON_HEDLEY_ALWAYS_INLINE bool scan_literal_bulk(const char* rest, const std::size_t length, std::true_type /*bulk*/) JSON_HEDLEY_ALWAYS_INLINE bool scan_literal_bulk(const char* rest, const std::size_t length, std::true_type /*bulk*/)
{ {
// called right after scan_after_whitespace() read current (see if (next_unget || ia.bulk_remaining() < length
// get_after_string_run()), so no unget is pending
JSON_ASSERT(!next_unget);
if (ia.bulk_remaining() < length
|| std::memcmp(ia.bulk_data(), rest, length) != 0) || std::memcmp(ia.bulk_data(), rest, length) != 0)
{ {
return false; return false;
+3
View File
@@ -575,7 +575,10 @@ class parser
{ {
std::string error_msg = "syntax error "; std::string error_msg = "syntax error ";
if (!context.empty())
{
error_msg += concat("while parsing ", context, ' '); error_msg += concat("while parsing ", context, ' ');
}
error_msg += "- "; error_msg += "- ";
@@ -108,9 +108,6 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
// m_it is already value-initialized, so this is not needed for
// correctness; it is kept because GCC generates faster loops with it
// (iterating a parsed document is 0.5-2.7 % slower without it, #6005)
if (m_object->is_object()) if (m_object->is_object())
{ {
m_it.object_iterator = typename object_t::iterator(); m_it.object_iterator = typename object_t::iterator();
+12 -5
View File
@@ -1113,14 +1113,21 @@ class serializer
{ {
// the code point is at least 0x60 (smaller ones are handled // the code point is at least 0x60 (smaller ones are handled
// above) and is not printable ASCII (which the scanner // above) and is not printable ASCII (which the scanner
// copies). Under EnsureAscii it is DEL (0x7F): every // copies): it is DEL (0x7F) under EnsureAscii or a non-ASCII
// well-formed multi-byte character is escaped by // character
// write_u_escapes() above, so decode() only ever accepts a
// single byte here, and nothing of it was buffered
if (EnsureAscii) if (EnsureAscii)
{ {
JSON_ASSERT(codepoint == 0x7F); JSON_ASSERT(codepoint == 0x7F);
JSON_ASSERT(bytes == bytes_after_last_accept); if (error_handler == error_handler_t::keep)
{
// this character was buffered as raw bytes below
// in case it turned out to be part of an
// ill-formed sequence (which is kept as is); now
// that it decoded to a well-formed code point,
// undo that and \u-escape it like any other
// character instead
bytes = bytes_after_last_accept;
}
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint)); write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
} }
else else
+9 -14
View File
@@ -1576,7 +1576,7 @@ public:
auto src_it = src_object.cbegin(); auto src_it = src_object.cbegin();
for (auto& element : *dst.m_data.m_value.object) for (auto& element : *dst.m_data.m_value.object)
{ {
if (JSON_HEDLEY_LIKELY(copy_keys_equal(src_it->first, element.first))) if (JSON_HEDLEY_LIKELY(src_it != src_object.cend() && copy_keys_equal(src_it->first, element.first)))
{ {
copy_shallow(src_it->second, element.second, worklist); copy_shallow(src_it->second, element.second, worklist);
++src_it; ++src_it;
@@ -5353,7 +5353,8 @@ public:
/// @name lexicographical comparison operators /// @name lexicographical comparison operators
/// @{ /// @{
// the same-type cases for non-owning scalars, used by JSON_IMPLEMENT_SCALAR_FAST // the same-type cases for non-owning scalars, shared by JSON_IMPLEMENT_OPERATOR
// and JSON_IMPLEMENT_SCALAR_FAST
#define JSON_IMPLEMENT_SCALAR_CASES(op, null_result) \ #define JSON_IMPLEMENT_SCALAR_CASES(op, null_result) \
case value_t::null: \ case value_t::null: \
return (null_result); \ return (null_result); \
@@ -5375,7 +5376,7 @@ public:
// because any negative signed value is smaller than any unsigned value. // because any negative signed value is smaller than any unsigned value.
// Otherwise, the non-negative signed value is cast to unsigned before the // Otherwise, the non-negative signed value is cast to unsigned before the
// comparison to avoid wraparound. // comparison to avoid wraparound.
#define JSON_IMPLEMENT_OPERATOR(op, unordered_result, default_result, deep_result, may_descend) \ #define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result, deep_result, may_descend) \
const auto lhs_type = lhs.type(); \ const auto lhs_type = lhs.type(); \
const auto rhs_type = rhs.type(); \ const auto rhs_type = rhs.type(); \
\ \
@@ -5403,14 +5404,7 @@ public:
return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object); \ return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object); \
} \ } \
\ \
/* same-type scalars never get here: the inline fast path of the operator handles them */ \ JSON_IMPLEMENT_SCALAR_CASES(op, null_result) \
case value_t::null: \
case value_t::boolean: \
case value_t::number_integer: \
case value_t::number_unsigned: \
case value_t::number_float: \
JSON_ASSERT(false); /* NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) */ \
return (unordered_result); \
\ \
case value_t::string: \ case value_t::string: \
return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string); \ return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string); \
@@ -5451,7 +5445,7 @@ public:
? (number_integer_t(-1) op number_integer_t(1)) \ ? (number_integer_t(-1) op number_integer_t(1)) \
: (static_cast<number_unsigned_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_unsigned); \ : (static_cast<number_unsigned_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_unsigned); \
} \ } \
else if(lhs_type == value_t::discarded || rhs_type == value_t::discarded)\ else if(compares_unordered(lhs, rhs))\
{\ {\
return (unordered_result);\ return (unordered_result);\
}\ }\
@@ -5519,7 +5513,7 @@ public:
JSON_HEDLEY_DIAGNOSTIC_PUSH JSON_HEDLEY_DIAGNOSTIC_PUSH
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal") JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
#endif #endif
JSON_IMPLEMENT_OPERATOR( ==, false, false, JSON_IMPLEMENT_OPERATOR( ==, true, false, false,
compare_iteratively<false>(lhs, rhs, false) == compare_result::equal, true) compare_iteratively<false>(lhs, rhs, false) == compare_result::equal, true)
#ifdef __GNUC__ #ifdef __GNUC__
JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_DIAGNOSTIC_POP
@@ -5533,6 +5527,7 @@ public:
// default_result is used if we cannot compare values. In that case, // default_result is used if we cannot compare values. In that case,
// we compare types. // we compare types.
JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD* JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*
std::partial_ordering::equivalent,
std::partial_ordering::unordered, std::partial_ordering::unordered,
lhs_type <=> rhs_type, // *NOPAD* lhs_type <=> rhs_type, // *NOPAD*
to_partial_ordering(compare_iteratively<true>(lhs, rhs, false)), true) to_partial_ordering(compare_iteratively<true>(lhs, rhs, false)), true)
@@ -5544,7 +5539,7 @@ public:
// default_result is used if we cannot compare values. In that case, // default_result is used if we cannot compare values. In that case,
// we compare types. Note we have to call the operator explicitly, // we compare types. Note we have to call the operator explicitly,
// because MSVC has problems otherwise. // because MSVC has problems otherwise.
JSON_IMPLEMENT_OPERATOR( <, false, operator<(lhs_type, rhs_type), JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type),
compare_iteratively<true>(lhs, rhs, true) == compare_result::less, false) compare_iteratively<true>(lhs, rhs, true) == compare_result::less, false)
} }
#endif #endif
+46 -41
View File
@@ -9652,9 +9652,12 @@ class input_stream_adapter
std::char_traits<char>::int_type get_character_slow() std::char_traits<char>::int_type get_character_slow()
{ {
#if !JSON_DISABLE_STREAM_BULK_SCAN #if !JSON_DISABLE_STREAM_BULK_SCAN
// the get area is exhausted (get_character() handles the other case), // sbumpc() refills the get area if it is exhausted
// so sbumpc() refills it const bool refill = streambuf_access::get_ptr(sb) == streambuf_access::get_end(sb);
if (JSON_HEDLEY_UNLIKELY(refill))
{
save_token_segment(); save_token_segment();
}
#endif #endif
auto res = sb->sbumpc(); auto res = sb->sbumpc();
@@ -9667,13 +9670,17 @@ class input_stream_adapter
is->clear(is->rdstate() | std::ios::eofbit); is->clear(is->rdstate() | std::ios::eofbit);
} }
#if !JSON_DISABLE_STREAM_BULK_SCAN #if !JSON_DISABLE_STREAM_BULK_SCAN
else else if (JSON_HEDLEY_UNLIKELY(refill))
{ {
// the consumed character is at gptr() - 1, unless the streambuf // the consumed character is at gptr() - 1, unless the streambuf
// has no get area and returned it from uflow() // has no get area and returned it from uflow()
const char* const next = streambuf_access::get_ptr(sb); const char* const next = streambuf_access::get_ptr(sb);
after_refill(res, next != nullptr && next != streambuf_access::get_begin(sb)); after_refill(res, next != nullptr && next != streambuf_access::get_begin(sb));
} }
else
{
current_in_get_area = true; // LCOV_EXCL_LINE (called only when the get area is exhausted)
}
#endif #endif
return res; return res;
} }
@@ -13327,16 +13334,14 @@ class lexer : public lexer_base<BasicJsonType>
/// calls would (including the position and token bookkeeping of a /// calls would (including the position and token bookkeeping of a
/// streaming adapter, see bulk_consume) and leaves @a current holding the last of /// streaming adapter, see bulk_consume) and leaves @a current holding the last of
/// the 4 digits, just as the last such get() would; the codepoint is /// the 4 digits, just as the last such get() would; the codepoint is
/// written to @a out. Makes no state change and returns false for fewer /// written to @a out. Makes no state change and returns false for a
/// than 4 remaining bytes or any of the 4 bytes not being a hex digit, so /// pending unget, fewer than 4 remaining bytes, or any of the 4 bytes not
/// the caller falls back unchanged to the per-character loop, which then /// being a hex digit, so the caller falls back unchanged to the
/// reports the same diagnostic (stopping at the first invalid digit) as /// per-character loop, which then reports the same diagnostic (stopping
/// before this optimization. /// at the first invalid digit) as before this optimization.
bool get_codepoint_bulk(std::true_type /*bulk*/, int& out) bool get_codepoint_bulk(std::true_type /*bulk*/, int& out)
{ {
// no unget is pending inside a string (see get_after_string_run()) if (next_unget || ia.bulk_remaining() < 4)
JSON_ASSERT(!next_unget);
if (ia.bulk_remaining() < 4)
{ {
return false; return false;
} }
@@ -14438,7 +14443,7 @@ scan_number_done:
return token_type::value_unsigned; return token_type::value_unsigned;
} }
} }
else // value_integer (the callers handle value_float themselves) else if (number_type == token_type::value_integer)
{ {
if (parse_integer_signed(first, last, value_integer)) if (parse_integer_signed(first, last, value_integer))
{ {
@@ -14809,10 +14814,7 @@ scan_number_done:
/// the error at the right character /// the error at the right character
JSON_HEDLEY_ALWAYS_INLINE bool scan_literal_bulk(const char* rest, const std::size_t length, std::true_type /*bulk*/) JSON_HEDLEY_ALWAYS_INLINE bool scan_literal_bulk(const char* rest, const std::size_t length, std::true_type /*bulk*/)
{ {
// called right after scan_after_whitespace() read current (see if (next_unget || ia.bulk_remaining() < length
// get_after_string_run()), so no unget is pending
JSON_ASSERT(!next_unget);
if (ia.bulk_remaining() < length
|| std::memcmp(ia.bulk_data(), rest, length) != 0) || std::memcmp(ia.bulk_data(), rest, length) != 0)
{ {
return false; return false;
@@ -17369,7 +17371,7 @@ class json_sax_dom_callback_parser : public json_sax_dom_error_state
key_stack.push_back(val); key_stack.push_back(val);
// add discarded value at the given key and store the reference for later // add discarded value at the given key and store the reference for later
if (keep) if (keep && ref_stack.back())
{ {
auto& obj = *ref_stack.back()->m_data.m_value.object; auto& obj = *ref_stack.back()->m_data.m_value.object;
// a single lookup: insert the placeholder, or find the existing member // a single lookup: insert the placeholder, or find the existing member
@@ -17426,7 +17428,7 @@ class json_sax_dom_callback_parser : public json_sax_dom_error_state
const string_t object_key = pop_container(); const string_t object_key = pop_container();
if (!ref_stack.empty() && ref_stack.back()) if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_structured())
{ {
// remove discarded value // remove discarded value
remove_discarded_value(*ref_stack.back(), object_key); remove_discarded_value(*ref_stack.back(), object_key);
@@ -17592,7 +17594,8 @@ class json_sax_dom_callback_parser : public json_sax_dom_error_state
*/ */
string_t current_key() const string_t current_key() const
{ {
if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_object()) if (!ref_stack.empty() && ref_stack.back() && ref_stack.back()->is_object()
&& !key_stack.empty())
{ {
return key_stack.back(); return key_stack.back();
} }
@@ -23736,7 +23739,10 @@ class parser
{ {
std::string error_msg = "syntax error "; std::string error_msg = "syntax error ";
if (!context.empty())
{
error_msg += concat("while parsing ", context, ' '); error_msg += concat("while parsing ", context, ' ');
}
error_msg += "- "; error_msg += "- ";
@@ -24064,9 +24070,6 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
// m_it is already value-initialized, so this is not needed for
// correctness; it is kept because GCC generates faster loops with it
// (iterating a parsed document is 0.5-2.7 % slower without it, #6005)
if (m_object->is_object()) if (m_object->is_object())
{ {
m_it.object_iterator = typename object_t::iterator(); m_it.object_iterator = typename object_t::iterator();
@@ -36270,14 +36273,21 @@ class serializer
{ {
// the code point is at least 0x60 (smaller ones are handled // the code point is at least 0x60 (smaller ones are handled
// above) and is not printable ASCII (which the scanner // above) and is not printable ASCII (which the scanner
// copies). Under EnsureAscii it is DEL (0x7F): every // copies): it is DEL (0x7F) under EnsureAscii or a non-ASCII
// well-formed multi-byte character is escaped by // character
// write_u_escapes() above, so decode() only ever accepts a
// single byte here, and nothing of it was buffered
if (EnsureAscii) if (EnsureAscii)
{ {
JSON_ASSERT(codepoint == 0x7F); JSON_ASSERT(codepoint == 0x7F);
JSON_ASSERT(bytes == bytes_after_last_accept); if (error_handler == error_handler_t::keep)
{
// this character was buffered as raw bytes below
// in case it turned out to be part of an
// ill-formed sequence (which is kept as is); now
// that it decoded to a well-formed code point,
// undo that and \u-escape it like any other
// character instead
bytes = bytes_after_last_accept;
}
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint)); write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
} }
else else
@@ -39301,7 +39311,7 @@ public:
auto src_it = src_object.cbegin(); auto src_it = src_object.cbegin();
for (auto& element : *dst.m_data.m_value.object) for (auto& element : *dst.m_data.m_value.object)
{ {
if (JSON_HEDLEY_LIKELY(copy_keys_equal(src_it->first, element.first))) if (JSON_HEDLEY_LIKELY(src_it != src_object.cend() && copy_keys_equal(src_it->first, element.first)))
{ {
copy_shallow(src_it->second, element.second, worklist); copy_shallow(src_it->second, element.second, worklist);
++src_it; ++src_it;
@@ -43078,7 +43088,8 @@ public:
/// @name lexicographical comparison operators /// @name lexicographical comparison operators
/// @{ /// @{
// the same-type cases for non-owning scalars, used by JSON_IMPLEMENT_SCALAR_FAST // the same-type cases for non-owning scalars, shared by JSON_IMPLEMENT_OPERATOR
// and JSON_IMPLEMENT_SCALAR_FAST
#define JSON_IMPLEMENT_SCALAR_CASES(op, null_result) \ #define JSON_IMPLEMENT_SCALAR_CASES(op, null_result) \
case value_t::null: \ case value_t::null: \
return (null_result); \ return (null_result); \
@@ -43100,7 +43111,7 @@ public:
// because any negative signed value is smaller than any unsigned value. // because any negative signed value is smaller than any unsigned value.
// Otherwise, the non-negative signed value is cast to unsigned before the // Otherwise, the non-negative signed value is cast to unsigned before the
// comparison to avoid wraparound. // comparison to avoid wraparound.
#define JSON_IMPLEMENT_OPERATOR(op, unordered_result, default_result, deep_result, may_descend) \ #define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result, deep_result, may_descend) \
const auto lhs_type = lhs.type(); \ const auto lhs_type = lhs.type(); \
const auto rhs_type = rhs.type(); \ const auto rhs_type = rhs.type(); \
\ \
@@ -43128,14 +43139,7 @@ public:
return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object); \ return (*lhs.m_data.m_value.object) op (*rhs.m_data.m_value.object); \
} \ } \
\ \
/* same-type scalars never get here: the inline fast path of the operator handles them */ \ JSON_IMPLEMENT_SCALAR_CASES(op, null_result) \
case value_t::null: \
case value_t::boolean: \
case value_t::number_integer: \
case value_t::number_unsigned: \
case value_t::number_float: \
JSON_ASSERT(false); /* NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) */ \
return (unordered_result); \
\ \
case value_t::string: \ case value_t::string: \
return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string); \ return (*lhs.m_data.m_value.string) op (*rhs.m_data.m_value.string); \
@@ -43176,7 +43180,7 @@ public:
? (number_integer_t(-1) op number_integer_t(1)) \ ? (number_integer_t(-1) op number_integer_t(1)) \
: (static_cast<number_unsigned_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_unsigned); \ : (static_cast<number_unsigned_t>(lhs.m_data.m_value.number_integer) op rhs.m_data.m_value.number_unsigned); \
} \ } \
else if(lhs_type == value_t::discarded || rhs_type == value_t::discarded)\ else if(compares_unordered(lhs, rhs))\
{\ {\
return (unordered_result);\ return (unordered_result);\
}\ }\
@@ -43244,7 +43248,7 @@ public:
JSON_HEDLEY_DIAGNOSTIC_PUSH JSON_HEDLEY_DIAGNOSTIC_PUSH
JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal") JSON_HEDLEY_PRAGMA(GCC diagnostic ignored "-Wfloat-equal")
#endif #endif
JSON_IMPLEMENT_OPERATOR( ==, false, false, JSON_IMPLEMENT_OPERATOR( ==, true, false, false,
compare_iteratively<false>(lhs, rhs, false) == compare_result::equal, true) compare_iteratively<false>(lhs, rhs, false) == compare_result::equal, true)
#ifdef __GNUC__ #ifdef __GNUC__
JSON_HEDLEY_DIAGNOSTIC_POP JSON_HEDLEY_DIAGNOSTIC_POP
@@ -43258,6 +43262,7 @@ public:
// default_result is used if we cannot compare values. In that case, // default_result is used if we cannot compare values. In that case,
// we compare types. // we compare types.
JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD* JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*
std::partial_ordering::equivalent,
std::partial_ordering::unordered, std::partial_ordering::unordered,
lhs_type <=> rhs_type, // *NOPAD* lhs_type <=> rhs_type, // *NOPAD*
to_partial_ordering(compare_iteratively<true>(lhs, rhs, false)), true) to_partial_ordering(compare_iteratively<true>(lhs, rhs, false)), true)
@@ -43269,7 +43274,7 @@ public:
// default_result is used if we cannot compare values. In that case, // default_result is used if we cannot compare values. In that case,
// we compare types. Note we have to call the operator explicitly, // we compare types. Note we have to call the operator explicitly,
// because MSVC has problems otherwise. // because MSVC has problems otherwise.
JSON_IMPLEMENT_OPERATOR( <, false, operator<(lhs_type, rhs_type), JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type),
compare_iteratively<true>(lhs, rhs, true) == compare_result::less, false) compare_iteratively<true>(lhs, rhs, true) == compare_result::less, false)
} }
#endif #endif
+3 -2
View File
@@ -534,9 +534,10 @@ TEST_CASE("object_key_index")
// the hashes are not distinct on purpose: elements with the same // the hashes are not distinct on purpose: elements with the same
// hash are told apart by the caller // hash are told apart by the caller
const auto hash_of = [](std::size_t position) const auto hash_of = [](std::size_t position) -> std::size_t
{ {
return (position % 50) * 0x9E3779B97F4A7C15ull; // truncated to 32 bits where std::size_t is that small
return static_cast<std::size_t>((position % 50) * 0x9E3779B97F4A7C15ull);
}; };
std::vector<std::size_t> hashes; std::vector<std::size_t> hashes;
+1
View File
@@ -1555,6 +1555,7 @@ TEST_CASE("regression tests 1")
{ {
my_json j = make(); my_json j = make();
#ifdef JSON_NO_THREAD_LOCAL #ifdef JSON_NO_THREAD_LOCAL
// (set by the user, or by the library for clang with MinGW)
// the objects below the outermost one are not copied by their // the objects below the outermost one are not copied by their
// object_t here, but member by member, which keeps their // object_t here, but member by member, which keeps their
// timestamps correct: "c" is not mistaken for "b" and is inserted // timestamps correct: "c" is not mistaken for "b" and is inserted