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
7 changed files with 58 additions and 44 deletions

No files matched your search

@@ -545,9 +545,12 @@ class input_stream_adapter
std::char_traits<char>::int_type get_character_slow()
{
#if !JSON_DISABLE_STREAM_BULK_SCAN
// the get area is exhausted (get_character() handles the other case),
// so sbumpc() refills it
save_token_segment();
// sbumpc() refills the get area if it is exhausted
const bool refill = streambuf_access::get_ptr(sb) == streambuf_access::get_end(sb);
if (JSON_HEDLEY_UNLIKELY(refill))
{
save_token_segment();
}
#endif
auto res = sb->sbumpc();
@@ -560,13 +563,17 @@ class input_stream_adapter
is->clear(is->rdstate() | std::ios::eofbit);
}
#if !JSON_DISABLE_STREAM_BULK_SCAN
else
else if (JSON_HEDLEY_UNLIKELY(refill))
{
// the consumed character is at gptr() - 1, unless the streambuf
// has no get area and returned it from uflow()
const char* const next = streambuf_access::get_ptr(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
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);
// 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;
// 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();
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(*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
{
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();
}
+8 -13
View File
@@ -300,16 +300,14 @@ class lexer : public lexer_base<BasicJsonType>
/// calls would (including the position and token bookkeeping of a
/// 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
/// written to @a out. Makes no state change and returns false for fewer
/// than 4 remaining bytes or any of the 4 bytes not being a hex digit, so
/// the caller falls back unchanged to the per-character loop, which then
/// reports the same diagnostic (stopping at the first invalid digit) as
/// before this optimization.
/// written to @a out. Makes no state change and returns false for a
/// pending unget, fewer than 4 remaining bytes, or any of the 4 bytes not
/// being a hex digit, so the caller falls back unchanged to the
/// per-character loop, which then reports the same diagnostic (stopping
/// at the first invalid digit) as before this optimization.
bool get_codepoint_bulk(std::true_type /*bulk*/, int& out)
{
// no unget is pending inside a string (see get_after_string_run())
JSON_ASSERT(!next_unget);
if (ia.bulk_remaining() < 4)
if (next_unget || ia.bulk_remaining() < 4)
{
return false;
}
@@ -1411,7 +1409,7 @@ scan_number_done:
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))
{
@@ -1782,10 +1780,7 @@ scan_number_done:
/// 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*/)
{
// called right after scan_after_whitespace() read current (see
// get_after_string_run()), so no unget is pending
JSON_ASSERT(!next_unget);
if (ia.bulk_remaining() < length
if (next_unget || ia.bulk_remaining() < length
|| std::memcmp(ia.bulk_data(), rest, length) != 0)
{
return false;
+4 -1
View File
@@ -575,7 +575,10 @@ class parser
{
std::string error_msg = "syntax error ";
error_msg += concat("while parsing ", context, ' ');
if (!context.empty())
{
error_msg += concat("while parsing ", context, ' ');
}
error_msg += "- ";
+27 -21
View File
@@ -9652,9 +9652,12 @@ class input_stream_adapter
std::char_traits<char>::int_type get_character_slow()
{
#if !JSON_DISABLE_STREAM_BULK_SCAN
// the get area is exhausted (get_character() handles the other case),
// so sbumpc() refills it
save_token_segment();
// sbumpc() refills the get area if it is exhausted
const bool refill = streambuf_access::get_ptr(sb) == streambuf_access::get_end(sb);
if (JSON_HEDLEY_UNLIKELY(refill))
{
save_token_segment();
}
#endif
auto res = sb->sbumpc();
@@ -9667,13 +9670,17 @@ class input_stream_adapter
is->clear(is->rdstate() | std::ios::eofbit);
}
#if !JSON_DISABLE_STREAM_BULK_SCAN
else
else if (JSON_HEDLEY_UNLIKELY(refill))
{
// the consumed character is at gptr() - 1, unless the streambuf
// has no get area and returned it from uflow()
const char* const next = streambuf_access::get_ptr(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
return res;
}
@@ -13327,16 +13334,14 @@ class lexer : public lexer_base<BasicJsonType>
/// calls would (including the position and token bookkeeping of a
/// 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
/// written to @a out. Makes no state change and returns false for fewer
/// than 4 remaining bytes or any of the 4 bytes not being a hex digit, so
/// the caller falls back unchanged to the per-character loop, which then
/// reports the same diagnostic (stopping at the first invalid digit) as
/// before this optimization.
/// written to @a out. Makes no state change and returns false for a
/// pending unget, fewer than 4 remaining bytes, or any of the 4 bytes not
/// being a hex digit, so the caller falls back unchanged to the
/// per-character loop, which then reports the same diagnostic (stopping
/// at the first invalid digit) as before this optimization.
bool get_codepoint_bulk(std::true_type /*bulk*/, int& out)
{
// no unget is pending inside a string (see get_after_string_run())
JSON_ASSERT(!next_unget);
if (ia.bulk_remaining() < 4)
if (next_unget || ia.bulk_remaining() < 4)
{
return false;
}
@@ -14438,7 +14443,7 @@ scan_number_done:
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))
{
@@ -14809,10 +14814,7 @@ scan_number_done:
/// 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*/)
{
// called right after scan_after_whitespace() read current (see
// get_after_string_run()), so no unget is pending
JSON_ASSERT(!next_unget);
if (ia.bulk_remaining() < length
if (next_unget || ia.bulk_remaining() < length
|| std::memcmp(ia.bulk_data(), rest, length) != 0)
{
return false;
@@ -17369,7 +17371,7 @@ class json_sax_dom_callback_parser : public json_sax_dom_error_state
key_stack.push_back(val);
// 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;
// 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();
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(*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
{
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();
}
@@ -23736,7 +23739,10 @@ class parser
{
std::string error_msg = "syntax error ";
error_msg += concat("while parsing ", context, ' ');
if (!context.empty())
{
error_msg += concat("while parsing ", context, ' ');
}
error_msg += "- ";
+3 -2
View File
@@ -534,9 +534,10 @@ TEST_CASE("object_key_index")
// the hashes are not distinct on purpose: elements with the same
// 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;
+1
View File
@@ -1555,6 +1555,7 @@ TEST_CASE("regression tests 1")
{
my_json j = make();
#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
// object_t here, but member by member, which keeps their
// timestamps correct: "c" is not mistaken for "b" and is inserted