[PATCH 1/1] compat: modernize and simplify byte swapping functions
- From
- Rostislav Krasny <rostiprodev@gmail.com>
- Date
- Jan 2, 2026, 00:27 UTC
- Message-ID
- <20260102002735.31390-2-rostiprodev@gmail.com>
- In-Reply-To
- <20260102002735.31390-1-rostiprodev@gmail.com>
Replace manual bit operations with memcpy + network functions for better maintainability. Add missing 16-bit network byte order conversion.
Key improvements: - Simplify the get_be*() and put_be*() functions - Add bswap16() macro with automatic compiler optimization: * GCC/Clang: __builtin_bswap16() intrinsic * MSVC: _byteswap_ushort() intrinsic - Add default_bswap16() static inline function with manual fallback implementation - Rename default_swab32() to default_bswap32() for naming consistency - Add ntohs() and htons() macros for complete 16/32/64-bit network conversion - Add put_be16() function for API completeness alongside existing put_be*() and get_be*() functions - Performance improvements (GCC 15.2.1, Clang 21.1.7): * on x86-64 with -O0 4.2x faster (GCC), 3.7x faster (Clang) * on x86-64 with -O1 4x faster (GCC), identical (Clang) * on x86-64 with -O2 identical (GCC), 1.8x faster (Clang)
Signed-off-by: Rostislav Krasny <rostiprodev@gmail.com> --- compat/bswap.h | 74 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 30 deletions(-)
diff --git a/compat/bswap.h b/compat/bswap.h index 28635ebc69..f9954ef090 100644 --- a/compat/bswap.h +++ b/compat/bswap.h @@ -9,10 +9,15 @@ */ /* - * Default version that the compiler ought to optimize properly with + * Default versions that the compiler ought to optimize properly with * constant values. */ -static inline uint32_t default_swab32(uint32_t val) +static inline uint16_t default_bswap16(uint16_t val) +{ + return ((val & 0xff00) >> 8) | ((val & 0x00ff) << 8); +} + +static inline uint32_t default_bswap32(uint32_t val) { return (((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | @@ -40,6 +45,7 @@ static inline uint64_t default_bswap64(uint64_t val) # define __has_builtin(x) 0 #endif +#undef bswap16 #undef bswap32 #undef bswap64 @@ -47,6 +53,7 @@ static inline uint64_t default_bswap64(uint64_t val) #include <stdlib.h> +#define bswap16(x) _byteswap_ushort(x) #define bswap32(x) _byteswap_ulong(x) #define bswap64(x) _byteswap_uint64(x) @@ -54,8 +61,9 @@ static inline uint64_t default_bswap64(uint64_t val) #define GIT_BIG_ENDIAN 4321 #define GIT_BYTE_ORDER GIT_LITTLE_ENDIAN -#elif __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64) +#elif __has_builtin(__builtin_bswap16) && __has_builtin(__builtin_bswap32) && __has_builtin(__builtin_bswap64) +#define bswap16(x) __builtin_bswap16((x)) #define bswap32(x) __builtin_bswap32((x)) #define bswap64(x) __builtin_bswap64((x)) @@ -98,24 +106,36 @@ static inline uint64_t default_bswap64(uint64_t val) #endif +#undef ntohs +#undef htons #undef ntohl #undef htonl #undef ntohll #undef htonll #if GIT_BYTE_ORDER == GIT_BIG_ENDIAN +# define ntohs(x) (x) +# define htons(x) (x) # define ntohl(x) (x) # define htonl(x) (x) # define ntohll(x) (x) # define htonll(x) (x) #else +# if defined(bswap16) +# define ntohs(x) bswap16(x) +# define htons(x) bswap16(x) +# else +# define ntohs(x) default_bswap16(x) +# define htons(x) default_bswap16(x) +# endif + # if defined(bswap32) # define ntohl(x) bswap32(x) # define htonl(x) bswap32(x) # else -# define ntohl(x) default_swab32(x) -# define htonl(x) default_swab32(x) +# define ntohl(x) default_bswap32(x) +# define htonl(x) default_bswap32(x) # endif # if defined(bswap64) @@ -129,47 +149,41 @@ static inline uint64_t default_bswap64(uint64_t val) static inline uint16_t get_be16(const void *ptr) { - const unsigned char *p = ptr; - return (uint16_t)p[0] << 8 | - (uint16_t)p[1] << 0; + uint16_t n; + memcpy(&n, ptr, sizeof n); + return ntohs(n); } static inline uint32_t get_be32(const void *ptr) { - const unsigned char *p = ptr; - return (uint32_t)p[0] << 24 | - (uint32_t)p[1] << 16 | - (uint32_t)p[2] << 8 | - (uint32_t)p[3] << 0; + uint32_t n; + memcpy(&n, ptr, sizeof n); + return ntohl(n); } static inline uint64_t get_be64(const void *ptr) { - const unsigned char *p = ptr; - return (uint64_t)get_be32(&p[0]) << 32 | - (uint64_t)get_be32(&p[4]) << 0; + uint64_t n; + memcpy(&n, ptr, sizeof n); + return ntohll(n); +} + +static inline void put_be16(void *ptr, uint16_t value) +{ + uint16_t n = htons(value); + memcpy(ptr, &n, sizeof n); } static inline void put_be32(void *ptr, uint32_t value) { - unsigned char *p = ptr; - p[0] = (value >> 24) & 0xff; - p[1] = (value >> 16) & 0xff; - p[2] = (value >> 8) & 0xff; - p[3] = (value >> 0) & 0xff; + uint32_t n = htonl(value); + memcpy(ptr, &n, sizeof n); } static inline void put_be64(void *ptr, uint64_t value) { - unsigned char *p = ptr; - p[0] = (value >> 56) & 0xff; - p[1] = (value >> 48) & 0xff; - p[2] = (value >> 40) & 0xff; - p[3] = (value >> 32) & 0xff; - p[4] = (value >> 24) & 0xff; - p[5] = (value >> 16) & 0xff; - p[6] = (value >> 8) & 0xff; - p[7] = (value >> 0) & 0xff; + uint64_t n = htonll(value); + memcpy(ptr, &n, sizeof n); } #endif /* COMPAT_BSWAP_H */
-- 2.52.0