From 26ac7e36c0710284d18d95eb0e58e21178396ffd Mon Sep 17 00:00:00 2001
From: Tavian Barnes <tavianator@tavianator.com>
Date: Wed, 29 May 2024 11:12:21 -0400
Subject: bit: Update to match C23

Based on the latest C23 draft (N3220):

- Argument types to generic bit functions should be unsigned
- Bit functions return unsigned int
- Byte-swapping functions (stdc_memreverse8*()) weren't added
- stdc_rotate_{left,right}() weren't added
- first_leading_*() counts from the *left*
---
 src/bit.h | 96 ++++++++++++++++++++++++++++++---------------------------------
 1 file changed, 45 insertions(+), 51 deletions(-)

(limited to 'src')

diff --git a/src/bit.h b/src/bit.h
index 17cfbcf..880ccd6 100644
--- a/src/bit.h
+++ b/src/bit.h
@@ -173,11 +173,7 @@
 #  define ENDIAN_NATIVE 0
 #endif
 
-#if __STDC_VERSION__ >= C23
-#  define bswap_u16 stdc_memreverse8u16
-#  define bswap_u32 stdc_memreverse8u32
-#  define bswap_u64 stdc_memreverse8u64
-#elif __GNUC__
+#if __GNUC__
 #  define bswap_u16 __builtin_bswap16
 #  define bswap_u32 __builtin_bswap32
 #  define bswap_u64 __builtin_bswap64
@@ -222,16 +218,10 @@ static inline uint8_t bswap_u8(uint8_t n) {
 // Select an overload based on an unsigned integer type
 #define UINT_SELECT(n, name) \
 	_Generic((n), \
-		char:               name##_uc, \
-		signed char:        name##_uc, \
 		unsigned char:      name##_uc, \
-		signed short:       name##_us, \
 		unsigned short:     name##_us, \
-		signed int:         name##_ui, \
 		unsigned int:       name##_ui, \
-		signed long:        name##_ul, \
 		unsigned long:      name##_ul, \
-		signed long long:   name##_ull, \
 		unsigned long long: name##_ull)
 
 // C23 polyfill: bit utilities
@@ -239,8 +229,6 @@ static inline uint8_t bswap_u8(uint8_t n) {
 #if __STDC_VERSION__ >= C23
 #  define count_ones stdc_count_ones
 #  define count_zeros stdc_count_zeros
-#  define rotate_left stdc_rotate_left
-#  define rotate_right stdc_rotate_right
 #  define leading_zeros stdc_leading_zeros
 #  define leading_ones stdc_leading_ones
 #  define trailing_zeros stdc_trailing_zeros
@@ -273,31 +261,31 @@ static inline uint8_t bswap_u8(uint8_t n) {
 #define BUILTIN_WIDTH(suffix) BUILTIN_WIDTH##suffix
 
 #define COUNT_ONES(type, suffix, width) \
-	static inline int count_ones##suffix(type n) { \
+	static inline unsigned int count_ones##suffix(type n) { \
 		return UINT_BUILTIN(popcount, suffix)(n); \
 	}
 
 #define LEADING_ZEROS(type, suffix, width) \
-	static inline int leading_zeros##suffix(type n) { \
+	static inline unsigned int leading_zeros##suffix(type n) { \
 	        return n \
 			? UINT_BUILTIN(clz, suffix)(n) - (BUILTIN_WIDTH(suffix) - width) \
 			: width; \
 	}
 
 #define TRAILING_ZEROS(type, suffix, width) \
-	static inline int trailing_zeros##suffix(type n) { \
+	static inline unsigned int trailing_zeros##suffix(type n) { \
 		return n ? UINT_BUILTIN(ctz, suffix)(n) : (int)width; \
 	}
 
 #define FIRST_TRAILING_ONE(type, suffix, width) \
-	static inline int first_trailing_one##suffix(type n) { \
+	static inline unsigned int first_trailing_one##suffix(type n) { \
 		return UINT_BUILTIN(ffs, suffix)(n); \
 	}
 
 #else // !__GNUC__
 
 #define COUNT_ONES(type, suffix, width) \
-	static inline int count_ones##suffix(type n) { \
+	static inline unsigned int count_ones##suffix(type n) { \
 		int ret; \
 		for (ret = 0; n; ++ret) { \
 			n &= n - 1; \
@@ -306,7 +294,7 @@ static inline uint8_t bswap_u8(uint8_t n) {
 	}
 
 #define LEADING_ZEROS(type, suffix, width) \
-	static inline int leading_zeros##suffix(type n) { \
+	static inline unsigned int leading_zeros##suffix(type n) { \
 		type bit = (type)1 << (width - 1); \
 		int ret; \
 		for (ret = 0; bit && !(n & bit); ++ret, bit >>= 1); \
@@ -314,7 +302,7 @@ static inline uint8_t bswap_u8(uint8_t n) {
 	}
 
 #define TRAILING_ZEROS(type, suffix, width) \
-	static inline int trailing_zeros##suffix(type n) { \
+	static inline unsigned int trailing_zeros##suffix(type n) { \
 		type bit = 1; \
 		int ret; \
 		for (ret = 0; bit && !(n & bit); ++ret, bit <<= 1); \
@@ -322,7 +310,7 @@ static inline uint8_t bswap_u8(uint8_t n) {
 	}
 
 #define FIRST_TRAILING_ONE(type, suffix, width) \
-	static inline int first_trailing_one##suffix(type n) { \
+	static inline unsigned int first_trailing_one##suffix(type n) { \
 		return n ? trailing_zeros##suffix(n) + 1 : 0; \
 	}
 
@@ -333,19 +321,9 @@ UINT_OVERLOADS(LEADING_ZEROS)
 UINT_OVERLOADS(TRAILING_ZEROS)
 UINT_OVERLOADS(FIRST_TRAILING_ONE)
 
-#define ROTATE_LEFT(type, suffix, width) \
-	static inline type rotate_left##suffix(type n, int c) { \
-		return (n << c) | (n >> ((width - c) % width)); \
-	}
-
-#define ROTATE_RIGHT(type, suffix, width) \
-	static inline type rotate_right##suffix(type n, int c) { \
-		return (n >> c) | (n << ((width - c) % width)); \
-	}
-
 #define FIRST_LEADING_ONE(type, suffix, width) \
-	static inline int first_leading_one##suffix(type n) { \
-		return width - leading_zeros##suffix(n); \
+	static inline unsigned int first_leading_one##suffix(type n) { \
+		return n ? leading_zeros##suffix(n) + 1 : 0; \
 	}
 
 #define HAS_SINGLE_BIT(type, suffix, width) \
@@ -354,17 +332,30 @@ UINT_OVERLOADS(FIRST_TRAILING_ONE)
 		return n - 1 < (n ^ (n - 1)); \
 	}
 
-UINT_OVERLOADS(ROTATE_LEFT)
-UINT_OVERLOADS(ROTATE_RIGHT)
+#define BIT_WIDTH(type, suffix, width) \
+	static inline unsigned int bit_width##suffix(type n) { \
+		return width - leading_zeros##suffix(n); \
+	}
+
+#define BIT_FLOOR(type, suffix, width) \
+	static inline type bit_floor##suffix(type n) { \
+		return n ? (type)1 << (bit_width##suffix(n) - 1) : 0; \
+	}
+
+#define BIT_CEIL(type, suffix, width) \
+	static inline type bit_ceil##suffix(type n) { \
+		return (type)1 << bit_width##suffix(n - !!n); \
+	}
+
 UINT_OVERLOADS(FIRST_LEADING_ONE)
 UINT_OVERLOADS(HAS_SINGLE_BIT)
+UINT_OVERLOADS(BIT_WIDTH)
+UINT_OVERLOADS(BIT_FLOOR)
+UINT_OVERLOADS(BIT_CEIL)
 
 #define count_ones(n) UINT_SELECT(n, count_ones)(n)
 #define count_zeros(n) UINT_SELECT(n, count_ones)(~(n))
 
-#define rotate_left(n, c) UINT_SELECT(n, rotate_left)(n, c)
-#define rotate_right(n, c) UINT_SELECT(n, rotate_right)(n, c)
-
 #define leading_zeros(n) UINT_SELECT(n, leading_zeros)(n)
 #define leading_ones(n) UINT_SELECT(n, leading_zeros)(~(n))
 
@@ -379,23 +370,26 @@ UINT_OVERLOADS(HAS_SINGLE_BIT)
 
 #define has_single_bit(n) UINT_SELECT(n, has_single_bit)(n)
 
-#define BIT_FLOOR(type, suffix, width) \
-	static inline type bit_floor##suffix(type n) { \
-		return n ? (type)1 << (first_leading_one##suffix(n) - 1) : 0; \
-	}
+#define bit_width(n) UINT_SELECT(n, bit_width)(n)
+#define bit_floor(n) UINT_SELECT(n, bit_floor)(n)
+#define bit_ceil(n) UINT_SELECT(n, bit_ceil)(n)
 
-#define BIT_CEIL(type, suffix, width) \
-	static inline type bit_ceil##suffix(type n) { \
-		return (type)1 << first_leading_one##suffix(n - !!n); \
+#endif // __STDC_VERSION__ < C23
+
+#define ROTATE_LEFT(type, suffix, width) \
+	static inline type rotate_left##suffix(type n, int c) { \
+		return (n << c) | (n >> ((width - c) % width)); \
 	}
 
-UINT_OVERLOADS(BIT_FLOOR)
-UINT_OVERLOADS(BIT_CEIL)
+#define ROTATE_RIGHT(type, suffix, width) \
+	static inline type rotate_right##suffix(type n, int c) { \
+		return (n >> c) | (n << ((width - c) % width)); \
+	}
 
-#define bit_width(n) first_leading_one(n)
-#define bit_floor(n) UINT_SELECT(n, bit_floor)(n)
-#define bit_ceil(n) UINT_SELECT(n, bit_ceil)(n)
+UINT_OVERLOADS(ROTATE_LEFT)
+UINT_OVERLOADS(ROTATE_RIGHT)
 
-#endif // __STDC_VERSION__ < C23
+#define rotate_left(n, c) UINT_SELECT(n, rotate_left)(n, c)
+#define rotate_right(n, c) UINT_SELECT(n, rotate_right)(n, c)
 
 #endif // BFS_BIT_H
-- 
cgit v1.2.3