Copy small binary reads straight from the streambuf get area

The binary readers read every number and string with get_elements(), which
called the virtual std::streambuf::sgetn() each time. When the requested
bytes are in the get area, input_stream_adapter now copies them (and moves
the get pointer) inline, which is what sgetn() does for them anyway.

Instructions relative to the previous commit, from an ifstream (macOS, 5
parses): CBOR CITM 235M -> 226M, twitter 156M -> 151M, canada 495M -> 463M;
MessagePack CITM 232M -> 222M; UBJSON CITM 258M -> 241M, canada 638M ->
623M. Linux Ir (GCC / Clang): CBOR twitter 34.0M / 41.9M -> 32.2M / 40.0M,
CBOR CITM 51.4M / 58.2M -> 47.7M / 54.6M, MessagePack CITM 50.5M / 57.0M ->
46.8M / 53.4M, UBJSON CITM 56.6M / 64.1M -> 50.7M / 57.9M. Against develop
the three binary readers are 5-12 % cheaper in instructions with this series.

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Niels Lohmann committed 2026-10-22 09:28:36 +02:00
1 parent 419133b2af
commit 16de05b930
2 files changed
+24

No files matched your search

@@ -313,6 +313,18 @@ class input_stream_adapter
{
#if JSON_PRECISE_STREAM_POSITION
commit_lookahead();
#endif
#if !JSON_DISABLE_STREAM_BULK_SCAN
// the elements are in the get area: copy them, as sgetn() does, but
// without the virtual call
const char* const first = streambuf_access::get_ptr(sb);
const auto available = static_cast<std::size_t>(streambuf_access::get_end(sb) - first);
if (JSON_HEDLEY_LIKELY(count * sizeof(T) <= available && count * sizeof(T) <= static_cast<std::size_t>((std::numeric_limits<int>::max)())))
{
std::memcpy(dest, first, count * sizeof(T));
streambuf_access::bump(sb, static_cast<int>(count * sizeof(T)));
return count * sizeof(T);
}
#endif
auto res = static_cast<std::size_t>(sb->sgetn(reinterpret_cast<char*>(dest), static_cast<std::streamsize>(count * sizeof(T))));
if (JSON_HEDLEY_UNLIKELY(res < count * sizeof(T)))