diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 93f707097..81a3ebd42 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -4887,6 +4887,14 @@ class binary_reader const char* context, ContainerType& result) { + // a string that is in the block of input as a whole is appended from + // it, without the zero-filling resize() below + constexpr bool from_block = bulk_scan && std::is_same::value; + if (append_from_block(len, result, std::integral_constant {})) + { + return true; + } + // upper bound on the number of bytes read (and allocated) per chunk constexpr std::size_t chunk_size = 4096; @@ -4923,6 +4931,36 @@ class binary_reader return true; } + /// append the @a len bytes at the current position to @a result, if the + /// input holds them in one block; false (with nothing read) otherwise + template + bool append_from_block(const NumberType len, string_t& result, std::true_type /*block*/) + { + if (len <= 0) + { + return false; + } + // (len > 0, so the unsigned type holds it; casting a signed char + // straight to std::size_t would trip bugprone-signed-char-misuse) + const auto ulen = static_cast::type>(len); + const std::size_t remaining = ia.bulk_remaining(); + if (static_cast(ulen) > static_cast(remaining)) + { + return false; // (the loop reports the premature end) + } + const auto n = static_cast(ulen); + result.append(reinterpret_cast(ia.bulk_data()), n); + ia.bulk_skip(n); + chars_read += n; + return true; + } + + template + static bool append_from_block(const NumberType /*len*/, ContainerType& /*result*/, std::false_type /*block*/) noexcept + { + return false; + } + /*! @param[in] context further context information (for diagnostics) @return whether the last read character is not EOF diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index eedb9c561..6e2ead1b4 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -22903,6 +22903,14 @@ class binary_reader const char* context, ContainerType& result) { + // a string that is in the block of input as a whole is appended from + // it, without the zero-filling resize() below + constexpr bool from_block = bulk_scan && std::is_same::value; + if (append_from_block(len, result, std::integral_constant {})) + { + return true; + } + // upper bound on the number of bytes read (and allocated) per chunk constexpr std::size_t chunk_size = 4096; @@ -22939,6 +22947,36 @@ class binary_reader return true; } + /// append the @a len bytes at the current position to @a result, if the + /// input holds them in one block; false (with nothing read) otherwise + template + bool append_from_block(const NumberType len, string_t& result, std::true_type /*block*/) + { + if (len <= 0) + { + return false; + } + // (len > 0, so the unsigned type holds it; casting a signed char + // straight to std::size_t would trip bugprone-signed-char-misuse) + const auto ulen = static_cast::type>(len); + const std::size_t remaining = ia.bulk_remaining(); + if (static_cast(ulen) > static_cast(remaining)) + { + return false; // (the loop reports the premature end) + } + const auto n = static_cast(ulen); + result.append(reinterpret_cast(ia.bulk_data()), n); + ia.bulk_skip(n); + chars_read += n; + return true; + } + + template + static bool append_from_block(const NumberType /*len*/, ContainerType& /*result*/, std::false_type /*block*/) noexcept + { + return false; + } + /*! @param[in] context further context information (for diagnostics) @return whether the last read character is not EOF