WIP: Optimize binary conversion

This commit is contained in:
Martchus 2023-02-04 23:18:05 +01:00
parent 7d6fc9721a
commit 871e06c690
2 changed files with 111 additions and 36 deletions

View File

@ -4,6 +4,16 @@
#include "../global.h"
#include <cstdint>
#include <cstring>
#include <type_traits>
// use std::bit_cast and std::byteswap if available as only GCC is able to optimize the custom bitshift code in all cases
// note: Clang 15.0.0 is only able to optimize the bitshift code in getBytes() functions and MSVC 19.10 is not able to
// optimize it at all. Unfortunately bit_cast and byteswap are only available in C++20 and 23 respectively so the
// custom code needs to stay for compatibility.
#if __cplusplus >= 202002L
#include <bit>
#endif
// detect byte order according to __BYTE_ORDER__
#if defined(__BYTE_ORDER__)

View File

@ -2,10 +2,6 @@
#error "Do not include binaryconversionprivate.h directly."
#else
#include "../global.h"
#include <cstdint>
// disable warnings about sign conversions when using GCC or Clang
#ifdef __GNUC__
#pragma GCC diagnostic push
@ -18,10 +14,18 @@
CPP_UTILITIES_EXPORT constexpr std::int16_t toInt16(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_bit_cast) && defined(__cpp_lib_byteswap)
return std::byteswap(std::bit_cast<std::int16_t>(value));
#else
return static_cast<std::int16_t>((static_cast<std::int16_t>(value[0]) << 8 & 0xFF00) | (static_cast<std::int16_t>(value[1]) & 0x00FF));
#endif
#else
#if defined(__cpp_lib_bit_cast)
return std::bit_cast<std::int16_t>(value);
#else
return static_cast<std::int16_t>((static_cast<std::int16_t>(value[1]) << 8 & 0xFF00) | (static_cast<std::int16_t>(value[0]) & 0x00FF));
#endif
#endif
}
/*!
@ -30,10 +34,18 @@ CPP_UTILITIES_EXPORT constexpr std::int16_t toInt16(const char *value)
CPP_UTILITIES_EXPORT constexpr std::uint16_t toUInt16(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_bit_cast) && defined(__cpp_lib_byteswap)
return std::byteswap(std::bit_cast<std::uint16_t>(value));
#else
return static_cast<std::uint16_t>((static_cast<std::uint16_t>(value[0]) << 8 & 0xFF00) | (static_cast<std::uint16_t>(value[1]) & 0x00FF));
#endif
#else
#if defined(__cpp_lib_bit_cast)
return std::bit_cast<std::uint16_t>(value);
#else
return static_cast<std::uint16_t>((static_cast<std::uint16_t>(value[1]) << 8 & 0xFF00) | (static_cast<std::uint16_t>(value[0]) & 0x00FF));
#endif
#endif
}
/*!
@ -42,14 +54,22 @@ CPP_UTILITIES_EXPORT constexpr std::uint16_t toUInt16(const char *value)
CPP_UTILITIES_EXPORT constexpr std::int32_t toInt32(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_bit_cast) && defined(__cpp_lib_byteswap)
return std::byteswap(std::bit_cast<std::int32_t>(value));
#else
return static_cast<std::int32_t>((static_cast<std::int32_t>(value[0]) << 24 & 0xFF000000)
| (static_cast<std::int32_t>(value[1]) << 16 & 0x00FF0000) | (static_cast<std::int32_t>(value[2]) << 8 & 0x0000FF00)
| (static_cast<std::int32_t>(value[3]) & 0x000000FF));
#endif
#else
#if defined(__cpp_lib_bit_cast)
return std::bit_cast<std::int32_t>(value);
#else
return static_cast<std::int32_t>((static_cast<std::int32_t>(value[3]) << 24 & 0xFF000000)
| (static_cast<std::int32_t>(value[2]) << 16 & 0x00FF0000) | (static_cast<std::int32_t>(value[1]) << 8 & 0x0000FF00)
| (static_cast<std::int32_t>(value[0]) & 0x000000FF));
#endif
#endif
}
/*!
@ -72,11 +92,32 @@ CPP_UTILITIES_EXPORT constexpr std::uint32_t toUInt24(const char *value)
CPP_UTILITIES_EXPORT constexpr std::uint32_t toUInt32(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
return (static_cast<std::uint32_t>(value[0]) << 24 & 0xFF000000) | (static_cast<std::uint32_t>(value[1]) << 16 & 0x00FF0000)
| (static_cast<std::uint32_t>(value[2]) << 8 & 0x0000FF00) | (static_cast<std::uint32_t>(value[3]) & 0x000000FF);
#if __cplusplus >= 202002L
if (std::is_constant_evaluated()) {
#endif
return (static_cast<std::uint32_t>(value[0]) << 24 & 0xFF000000) | (static_cast<std::uint32_t>(value[1]) << 16 & 0x00FF0000)
| (static_cast<std::uint32_t>(value[2]) << 8 & 0x0000FF00) | (static_cast<std::uint32_t>(value[3]) & 0x000000FF);
#if __cplusplus >= 202002L
} else {
auto dst = std::uint32_t();
std::memcpy(&dst, value, sizeof(dst));
return dst;
}
#endif
#else
return (static_cast<std::uint32_t>(value[3]) << 24 & 0xFF000000) | (static_cast<std::uint32_t>(value[2]) << 16 & 0x00FF0000)
| (static_cast<std::uint32_t>(value[1]) << 8 & 0x0000FF00) | (static_cast<std::uint32_t>(value[0]) & 0x000000FF);
#if __cplusplus >= 202002L
if (std::is_constant_evaluated()) {
#endif
return (static_cast<std::uint32_t>(value[3]) << 24 & 0xFF000000) | (static_cast<std::uint32_t>(value[2]) << 16 & 0x00FF0000)
| (static_cast<std::uint32_t>(value[1]) << 8 & 0x0000FF00) | (static_cast<std::uint32_t>(value[0]) & 0x000000FF);
#if __cplusplus >= 202002L
} else {
auto dst = std::uint32_t();
std::memcpy(&dst, value, sizeof(dst));
return dst;
}
#endif
#endif
}
@ -86,16 +127,24 @@ CPP_UTILITIES_EXPORT constexpr std::uint32_t toUInt32(const char *value)
CPP_UTILITIES_EXPORT constexpr std::int64_t toInt64(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_bit_cast) && defined(__cpp_lib_byteswap)
return std::byteswap(std::bit_cast<std::int64_t>(value));
#else
return (static_cast<std::int64_t>(value[0]) << 56 & 0xFF00000000000000) | (static_cast<std::int64_t>(value[1]) << 48 & 0x00FF000000000000)
| (static_cast<std::int64_t>(value[2]) << 40 & 0x0000FF0000000000) | (static_cast<std::int64_t>(value[3]) << 32 & 0x000000FF00000000)
| (static_cast<std::int64_t>(value[4]) << 24 & 0x00000000FF000000) | (static_cast<std::int64_t>(value[5]) << 16 & 0x0000000000FF0000)
| (static_cast<std::int64_t>(value[6]) << 8 & 0x000000000000FF00) | (static_cast<std::int64_t>(value[7]) & 0x00000000000000FF);
#endif
#else
#if defined(__cpp_lib_bit_cast)
return std::bit_cast<std::int64_t>(value); // wrong, this would return pointer value
#else
return (static_cast<std::int64_t>(value[7]) << 56 & 0xFF00000000000000) | (static_cast<std::int64_t>(value[6]) << 48 & 0x00FF000000000000)
| (static_cast<std::int64_t>(value[5]) << 40 & 0x0000FF0000000000) | (static_cast<std::int64_t>(value[4]) << 32 & 0x000000FF00000000)
| (static_cast<std::int64_t>(value[3]) << 24 & 0x00000000FF000000) | (static_cast<std::int64_t>(value[2]) << 16 & 0x0000000000FF0000)
| (static_cast<std::int64_t>(value[1]) << 8 & 0x000000000000FF00) | (static_cast<std::int64_t>(value[0]) & 0x00000000000000FF);
#endif
#endif
}
/*!
@ -104,16 +153,24 @@ CPP_UTILITIES_EXPORT constexpr std::int64_t toInt64(const char *value)
CPP_UTILITIES_EXPORT constexpr std::uint64_t toUInt64(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_bit_cast) && defined(__cpp_lib_byteswap)
return std::byteswap(std::bit_cast<std::uint64_t>(value));
#else
return (static_cast<std::uint64_t>(value[0]) << 56 & 0xFF00000000000000) | (static_cast<std::uint64_t>(value[1]) << 48 & 0x00FF000000000000)
| (static_cast<std::uint64_t>(value[2]) << 40 & 0x0000FF0000000000) | (static_cast<std::uint64_t>(value[3]) << 32 & 0x000000FF00000000)
| (static_cast<std::uint64_t>(value[4]) << 24 & 0x00000000FF000000) | (static_cast<std::uint64_t>(value[5]) << 16 & 0x0000000000FF0000)
| (static_cast<std::uint64_t>(value[6]) << 8 & 0x000000000000FF00) | (static_cast<std::uint64_t>(value[7]) & 0x00000000000000FF);
#endif
#else
#if defined(__cpp_lib_bit_cast)
return std::bit_cast<std::uint64_t>(value);
#else
return (static_cast<std::uint64_t>(value[7]) << 56 & 0xFF00000000000000) | (static_cast<std::uint64_t>(value[6]) << 48 & 0x00FF000000000000)
| (static_cast<std::uint64_t>(value[5]) << 40 & 0x0000FF0000000000) | (static_cast<std::uint64_t>(value[4]) << 32 & 0x000000FF00000000)
| (static_cast<std::uint64_t>(value[3]) << 24 & 0x00000000FF000000) | (static_cast<std::uint64_t>(value[2]) << 16 & 0x0000000000FF0000)
| (static_cast<std::uint64_t>(value[1]) << 8 & 0x000000000000FF00) | (static_cast<std::uint64_t>(value[0]) & 0x00000000000000FF);
#endif
#endif
}
/*!
@ -142,11 +199,15 @@ CPP_UTILITIES_EXPORT inline double toFloat64(const char *value)
CPP_UTILITIES_EXPORT inline void getBytes(std::int16_t value, char *outputbuffer)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_byteswap)
value = std::byteswap(value);
std::memcpy(outputbuffer, &value, sizeof(value));
#else
outputbuffer[0] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[1] = static_cast<char>((value)&0xFF);
#endif
#else
outputbuffer[1] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[0] = static_cast<char>((value)&0xFF);
std::memcpy(outputbuffer, &value, sizeof(value));
#endif
}
@ -156,11 +217,15 @@ CPP_UTILITIES_EXPORT inline void getBytes(std::int16_t value, char *outputbuffer
CPP_UTILITIES_EXPORT inline void getBytes(std::uint16_t value, char *outputbuffer)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_byteswap)
value = std::byteswap(value);
std::memcpy(outputbuffer, &value, sizeof(value));
#else
outputbuffer[0] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[1] = static_cast<char>((value)&0xFF);
#endif
#else
outputbuffer[1] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[0] = static_cast<char>((value)&0xFF);
std::memcpy(outputbuffer, &value, sizeof(value));
#endif
}
@ -187,15 +252,17 @@ CPP_UTILITIES_EXPORT inline void getBytes24(std::uint32_t value, char *outputbuf
CPP_UTILITIES_EXPORT inline void getBytes(std::int32_t value, char *outputbuffer)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_byteswap)
value = std::byteswap(value);
std::memcpy(outputbuffer, &value, sizeof(value));
#else
outputbuffer[0] = static_cast<char>((value >> 24) & 0xFF);
outputbuffer[1] = static_cast<char>((value >> 16) & 0xFF);
outputbuffer[2] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[3] = static_cast<char>((value)&0xFF);
#endif
#else
outputbuffer[3] = static_cast<char>((value >> 24) & 0xFF);
outputbuffer[2] = static_cast<char>((value >> 16) & 0xFF);
outputbuffer[1] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[0] = static_cast<char>((value)&0xFF);
std::memcpy(outputbuffer, &value, sizeof(value));
#endif
}
@ -205,15 +272,17 @@ CPP_UTILITIES_EXPORT inline void getBytes(std::int32_t value, char *outputbuffer
CPP_UTILITIES_EXPORT inline void getBytes(std::uint32_t value, char *outputbuffer)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_byteswap)
value = std::byteswap(value);
std::memcpy(outputbuffer, &value, sizeof(value));
#else
outputbuffer[0] = static_cast<char>((value >> 24) & 0xFF);
outputbuffer[1] = static_cast<char>((value >> 16) & 0xFF);
outputbuffer[2] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[3] = static_cast<char>((value)&0xFF);
#endif
#else
outputbuffer[3] = static_cast<char>((value >> 24) & 0xFF);
outputbuffer[2] = static_cast<char>((value >> 16) & 0xFF);
outputbuffer[1] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[0] = static_cast<char>((value)&0xFF);
std::memcpy(outputbuffer, &value, sizeof(value));
#endif
}
@ -223,6 +292,10 @@ CPP_UTILITIES_EXPORT inline void getBytes(std::uint32_t value, char *outputbuffe
CPP_UTILITIES_EXPORT inline void getBytes(std::int64_t value, char *outputbuffer)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_byteswap)
value = std::byteswap(value);
std::memcpy(outputbuffer, &value, sizeof(value));
#else
outputbuffer[0] = static_cast<char>((value >> 56) & 0xFF);
outputbuffer[1] = static_cast<char>((value >> 48) & 0xFF);
outputbuffer[2] = static_cast<char>((value >> 40) & 0xFF);
@ -231,15 +304,9 @@ CPP_UTILITIES_EXPORT inline void getBytes(std::int64_t value, char *outputbuffer
outputbuffer[5] = static_cast<char>((value >> 16) & 0xFF);
outputbuffer[6] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[7] = static_cast<char>((value)&0xFF);
#endif
#else
outputbuffer[7] = static_cast<char>((value >> 56) & 0xFF);
outputbuffer[6] = static_cast<char>((value >> 48) & 0xFF);
outputbuffer[5] = static_cast<char>((value >> 40) & 0xFF);
outputbuffer[4] = static_cast<char>((value >> 32) & 0xFF);
outputbuffer[3] = static_cast<char>((value >> 24) & 0xFF);
outputbuffer[2] = static_cast<char>((value >> 16) & 0xFF);
outputbuffer[1] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[0] = static_cast<char>((value)&0xFF);
std::memcpy(outputbuffer, &value, sizeof(value));
#endif
}
@ -249,6 +316,10 @@ CPP_UTILITIES_EXPORT inline void getBytes(std::int64_t value, char *outputbuffer
CPP_UTILITIES_EXPORT inline void getBytes(std::uint64_t value, char *outputbuffer)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
#if defined(__cpp_lib_byteswap)
value = std::byteswap(value);
std::memcpy(outputbuffer, &value, sizeof(value));
#else
outputbuffer[0] = static_cast<char>((value >> 56) & 0xFF);
outputbuffer[1] = static_cast<char>((value >> 48) & 0xFF);
outputbuffer[2] = static_cast<char>((value >> 40) & 0xFF);
@ -257,15 +328,9 @@ CPP_UTILITIES_EXPORT inline void getBytes(std::uint64_t value, char *outputbuffe
outputbuffer[5] = static_cast<char>((value >> 16) & 0xFF);
outputbuffer[6] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[7] = static_cast<char>((value)&0xFF);
#endif
#else
outputbuffer[7] = static_cast<char>((value >> 56) & 0xFF);
outputbuffer[6] = static_cast<char>((value >> 48) & 0xFF);
outputbuffer[5] = static_cast<char>((value >> 40) & 0xFF);
outputbuffer[4] = static_cast<char>((value >> 32) & 0xFF);
outputbuffer[3] = static_cast<char>((value >> 24) & 0xFF);
outputbuffer[2] = static_cast<char>((value >> 16) & 0xFF);
outputbuffer[1] = static_cast<char>((value >> 8) & 0xFF);
outputbuffer[0] = static_cast<char>((value)&0xFF);
std::memcpy(outputbuffer, &value, sizeof(value));
#endif
}