summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2025-02-13 15:26:40 -0500
committerTavian Barnes <tavianator@tavianator.com>2025-02-13 15:26:40 -0500
commit690a06a5cef8ef506e52d274965e376d6ea865be (patch)
treec98d8e055fcb213b94a0d081178d38136ba505c1
parentd34d25c9546ce406afef2c561663db422045f05a (diff)
downloadbfs-690a06a5cef8ef506e52d274965e376d6ea865be.tar.xz
bit: Add the load8_[bl]euN() utilities
-rw-r--r--src/bit.h54
-rw-r--r--tests/bit.c11
2 files changed, 63 insertions, 2 deletions
diff --git a/src/bit.h b/src/bit.h
index 73a80dc..5d6fb9d 100644
--- a/src/bit.h
+++ b/src/bit.h
@@ -148,7 +148,7 @@
# define INTMAX_WIDTH UINTMAX_WIDTH
#endif
-// C23 polyfill: byte order
+// N3022 polyfill: byte order
#ifdef __STDC_ENDIAN_LITTLE__
# define ENDIAN_LITTLE __STDC_ENDIAN_LITTLE__
@@ -250,6 +250,58 @@ static inline uint8_t bswap_u8(uint8_t n) {
*/
#define bswap(n) UINT_SELECT(n, bswap)(n)
+#define LOAD8_LEU8(ptr, i, n) ((uint##n##_t)((const unsigned char *)ptr)[(i) / 8] << (i))
+#define LOAD8_BEU8(ptr, i, n) ((uint##n##_t)((const unsigned char *)ptr)[(i) / 8] << (n - (i) - 8))
+
+/** Load a little-endian 8-bit word. */
+static inline uint8_t load8_leu8(const void *ptr) {
+ return LOAD8_LEU8(ptr, 0, 8);
+}
+
+/** Load a big-endian 8-bit word. */
+static inline uint8_t load8_beu8(const void *ptr) {
+ return LOAD8_BEU8(ptr, 0, 8);
+}
+
+#define LOAD8_LEU16(ptr, i, n) (LOAD8_LEU8(ptr, i, n) | LOAD8_LEU8(ptr, i + 8, n))
+#define LOAD8_BEU16(ptr, i, n) (LOAD8_BEU8(ptr, i, n) | LOAD8_BEU8(ptr, i + 8, n))
+
+/** Load a little-endian 16-bit word. */
+static inline uint16_t load8_leu16(const void *ptr) {
+ return LOAD8_LEU16(ptr, 0, 16);
+}
+
+/** Load a big-endian 16-bit word. */
+static inline uint16_t load8_beu16(const void *ptr) {
+ return LOAD8_BEU16(ptr, 0, 16);
+}
+
+#define LOAD8_LEU32(ptr, i, n) (LOAD8_LEU16(ptr, i, n) | LOAD8_LEU16(ptr, i + 16, n))
+#define LOAD8_BEU32(ptr, i, n) (LOAD8_BEU16(ptr, i, n) | LOAD8_BEU16(ptr, i + 16, n))
+
+/** Load a little-endian 32-bit word. */
+static inline uint32_t load8_leu32(const void *ptr) {
+ return LOAD8_LEU32(ptr, 0, 32);
+}
+
+/** Load a big-endian 32-bit word. */
+static inline uint32_t load8_beu32(const void *ptr) {
+ return LOAD8_BEU32(ptr, 0, 32);
+}
+
+#define LOAD8_LEU64(ptr, i, n) (LOAD8_LEU32(ptr, i, n) | LOAD8_LEU32(ptr, i + 32, n))
+#define LOAD8_BEU64(ptr, i, n) (LOAD8_BEU32(ptr, i, n) | LOAD8_BEU32(ptr, i + 32, n))
+
+/** Load a little-endian 64-bit word. */
+static inline uint64_t load8_leu64(const void *ptr) {
+ return LOAD8_LEU64(ptr, 0, 64);
+}
+
+/** Load a big-endian 64-bit word. */
+static inline uint64_t load8_beu64(const void *ptr) {
+ return LOAD8_BEU64(ptr, 0, 64);
+}
+
// C23 polyfill: bit utilities
#if __STDC_VERSION_STDBIT_H__ >= C23
diff --git a/tests/bit.c b/tests/bit.c
index 5a3871d..09d470b 100644
--- a/tests/bit.c
+++ b/tests/bit.c
@@ -64,7 +64,7 @@ static_assert(INTMAX_MAX == IWIDTH_MAX(INTMAX_WIDTH));
bfs_check((a) == (b), "(0x%jX) %s != %s (0x%jX)", (uintmax_t)(a), #a, #b, (uintmax_t)(b))
void check_bit(void) {
- const char *str = "\x1\x2\x3\x4";
+ const char *str = "\x1\x2\x3\x4\x5\x6\x7\x8";
uint32_t word;
memcpy(&word, str, sizeof(word));
@@ -88,6 +88,15 @@ void check_bit(void) {
(void)bswap(0UL);
(void)bswap(0ULL);
+ check_eq(load8_beu8(str), 0x01);
+ check_eq(load8_leu8(str), 0x01);
+ check_eq(load8_beu16(str), 0x0102);
+ check_eq(load8_leu16(str), 0x0201);
+ check_eq(load8_beu32(str), 0x01020304);
+ check_eq(load8_leu32(str), 0x04030201);
+ check_eq(load8_beu64(str), 0x0102030405060708ULL);
+ check_eq(load8_leu64(str), 0x0807060504030201ULL);
+
check_eq(count_ones(0x0U), 0);
check_eq(count_ones(0x1U), 1);
check_eq(count_ones(0x2U), 1);