Binary readers: swap the bytes of floats with a single byteswap
byte_swap reversed float and double values byte by byte. GCC does not merge that loop into one bswap, and C++23's std::byteswap accepts only integers. Overloads for float and double now copy the bits into a uint32_t/uint64_t, call detail::byteswap, and copy them back. This applies to every binary reader that uses get_number. In the CBOR reader, the single- and double-precision float cases call a non-inlined helper. Without it, GCC stopped inlining the stream adapter's get_character() into parse_cbor_internal, which made reading from a std::istream about 0.5 % slower. Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
2 files changed
+294
-241
No files matched your search
@@ -22,6 +22,7 @@
|
||||
#include <bit> //byteswap
|
||||
#endif
|
||||
|
||||
#include <nlohmann/detail/bit_ops.hpp>
|
||||
#include <nlohmann/detail/exceptions.hpp>
|
||||
#include <nlohmann/detail/input/input_adapters.hpp>
|
||||
#include <nlohmann/detail/input/json_sax.hpp>
|
||||
@@ -1135,16 +1136,10 @@ class binary_reader
|
||||
return get_half_float(false);
|
||||
|
||||
case 0xFA: // Single-Precision Float (four-byte IEEE 754)
|
||||
{
|
||||
float number{};
|
||||
return get_number(number) && emit_float(number);
|
||||
}
|
||||
return get_cbor_float<float>();
|
||||
|
||||
case 0xFB: // Double-Precision Float (eight-byte IEEE 754)
|
||||
{
|
||||
double number{};
|
||||
return get_number(number) && emit_float(number);
|
||||
}
|
||||
return get_cbor_float<double>();
|
||||
|
||||
default: // anything else (0xFF is handled inside the other types)
|
||||
{
|
||||
@@ -1153,6 +1148,16 @@ class binary_reader
|
||||
}
|
||||
}
|
||||
|
||||
/// read a single- or double-precision float (kept out of
|
||||
/// parse_cbor_value, which is inlined into parse_cbor_internal)
|
||||
template<typename NumberType>
|
||||
JSON_HEDLEY_NEVER_INLINE
|
||||
bool get_cbor_float()
|
||||
{
|
||||
NumberType number{};
|
||||
return get_number(number) && emit_float(number);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief reports a nested indefinite-length CBOR string or byte array
|
||||
@param[in] type_name name of the rejected string type
|
||||
@@ -4220,6 +4225,27 @@ class binary_reader
|
||||
return current;
|
||||
}
|
||||
|
||||
/// reverse the byte order of a double with a single byteswap(): GCC does
|
||||
/// not merge the byte-wise swap of the generic version into one
|
||||
static void byte_swap(double& number) noexcept
|
||||
{
|
||||
static_assert(sizeof(double) == sizeof(std::uint64_t), "double must have 64 bits");
|
||||
std::uint64_t bits{};
|
||||
std::memcpy(&bits, &number, sizeof(bits));
|
||||
bits = byteswap(bits);
|
||||
std::memcpy(&number, &bits, sizeof(bits));
|
||||
}
|
||||
|
||||
/// reverse the byte order of a float with a single byteswap()
|
||||
static void byte_swap(float& number) noexcept
|
||||
{
|
||||
static_assert(sizeof(float) == sizeof(std::uint32_t), "float must have 32 bits");
|
||||
std::uint32_t bits{};
|
||||
std::memcpy(&bits, &number, sizeof(bits));
|
||||
bits = byteswap(bits);
|
||||
std::memcpy(&number, &bits, sizeof(bits));
|
||||
}
|
||||
|
||||
template<class NumberType>
|
||||
static void byte_swap(NumberType& number)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user