diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2023-05-16 10:48:50 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2023-05-16 11:29:48 -0400 |
commit | fe472f30e1b82f762993cbc5376ff9b25c605aa9 (patch) | |
tree | cd39f359cfc2f146d58ca06f196e6c76a9c90e30 | |
parent | 9ee1ca387d59a2d1281c310915a9853a57b11a1e (diff) | |
download | bfs-fe472f30e1b82f762993cbc5376ff9b25c605aa9.tar.xz |
int: Backport C23's endian utilities
-rw-r--r-- | src/int.h | 68 | ||||
-rw-r--r-- | tests/int.c | 10 |
2 files changed, 78 insertions, 0 deletions
@@ -11,6 +11,10 @@ #include <limits.h> #include <stdint.h> +#if __STDC_VERSION__ >= 202311L +# include <stdbit.h> +#endif + // C23 polyfill: _WIDTH macros // The U*_MAX macros are of the form 2**n - 1, and we want to extract the n. @@ -97,4 +101,68 @@ # define INTMAX_WIDTH UINTMAX_WIDTH #endif +// C23 polyfill: byte order + +#ifdef __STDC_ENDIAN_LITTLE__ +# define ENDIAN_LITTLE __STDC_ENDIAN_LITTLE__ +#elif defined(__ORDER_LITTLE_ENDIAN__) +# define ENDIAN_LITTLE __ORDER_LITTLE_ENDIAN__ +#else +# define ENDIAN_LITTLE 1234 +#endif + +#ifdef __STDC_ENDIAN_BIG__ +# define ENDIAN_BIG __STDC_ENDIAN_BIG__ +#elif defined(__ORDER_BIG_ENDIAN__) +# define ENDIAN_BIG __ORDER_BIG_ENDIAN__ +#else +# define ENDIAN_BIG 4321 +#endif + +#ifdef __STDC_ENDIAN_NATIVE__ +# define ENDIAN_NATIVE __STDC_ENDIAN_NATIVE__ +#elif defined(__ORDER_NATIVE_ENDIAN__) +# define ENDIAN_NATIVE __ORDER_NATIVE_ENDIAN__ +#else +# define ENDIAN_NATIVE 0 +#endif + +#if __STDC_VERSION__ >= 202311L +# define bswap16 stdc_memreverse8u16 +# define bswap32 stdc_memreverse8u32 +# define bswap64 stdc_memreverse8u64 +#elif __GNUC__ +# define bswap16 __builtin_bswap16 +# define bswap32 __builtin_bswap32 +# define bswap64 __builtin_bswap64 +#else + +static inline uint16_t bswap16(uint16_t n) { + return (n << 8) | (n >> 8); +} + +static inline uint32_t bswap32(uint32_t n) { + return ((uint32_t)bswap16(n) << 16) | bswap16(n >> 16); +} + +static inline uint64_t bswap64(uint64_t n) { + return ((uint64_t)bswap32(n) << 32) | bswap32(n >> 32); +} + +#endif + +static inline uint8_t bswap8(uint8_t n) { + return n; +} + +/** + * Reverse the byte order of an integer. + */ +#define bswap(n) \ + _Generic((n), \ + uint8_t: bswap8, \ + uint16_t: bswap16, \ + uint32_t: bswap32, \ + uint64_t: bswap64)(n) + #endif // BFS_INT_H diff --git a/tests/int.c b/tests/int.c index db59e90..0039862 100644 --- a/tests/int.c +++ b/tests/int.c @@ -1,10 +1,14 @@ // Copyright © Tavian Barnes <tavianator@tavianator.com> // SPDX-License-Identifier: 0BSD +#undef NDEBUG + #include "../src/int.h" #include "../src/diag.h" +#include <assert.h> #include <limits.h> #include <stdint.h> +#include <stdlib.h> bfs_static_assert(UMAX_WIDTH(0x1) == 1); bfs_static_assert(UMAX_WIDTH(0x3) == 2); @@ -51,4 +55,10 @@ bfs_static_assert(INTMAX_MIN == IWIDTH_MIN(INTMAX_WIDTH)); bfs_static_assert(INTMAX_MAX == IWIDTH_MAX(INTMAX_WIDTH)); int main(void) { + assert(bswap((uint8_t)0x12) == 0x12); + assert(bswap((uint16_t)0x1234) == 0x3412); + assert(bswap((uint32_t)0x12345678) == 0x78563412); + assert(bswap((uint64_t)0x1234567812345678) == 0x7856341278563412); + + return EXIT_SUCCESS; } |