From 629c1762f1f0b27c03b2fe8c4db8926c2c86fabe Mon Sep 17 00:00:00 2001 From: Liam Gray Date: Fri, 26 Sep 2025 14:43:07 +0100 Subject: [PATCH 1/2] Integer hashing functions that compile to optimal assembly --- rapidhash.h | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/rapidhash.h b/rapidhash.h index ad02871..5922b8c 100755 --- a/rapidhash.h +++ b/rapidhash.h @@ -565,3 +565,66 @@ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano(const void *key, size_t len) R return rapidhashNano_withSeed(key, len, 0); } +/* + * Helper method for converting to little-endian bytes on big-endian platforms. + */ +#ifndef RAPIDHASH_LITTLE_ENDIAN +RAPIDHASH_INLINE_CONSTEXPR uint16_t rapidhash_to_le_u16(const uint16_t v) RAPIDHASH_NOEXCEPT { return __builtin_bswap16(v); } +RAPIDHASH_INLINE_CONSTEXPR uint32_t rapidhash_to_le_u32(const uint32_t v) RAPIDHASH_NOEXCEPT { return __builtin_bswap32(v); } +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_to_le_u64(const uint64_t v) RAPIDHASH_NOEXCEPT { return __builtin_bswap64(v); } +#else +RAPIDHASH_INLINE_CONSTEXPR uint16_t rapidhash_to_le_u16(const uint16_t v) RAPIDHASH_NOEXCEPT { return v; } +RAPIDHASH_INLINE_CONSTEXPR uint32_t rapidhash_to_le_u32(const uint32_t v) RAPIDHASH_NOEXCEPT { return v; } +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_to_le_u64(const uint64_t v) RAPIDHASH_NOEXCEPT { return v; } +#endif + +/* + * rapidhash 8-bit integer hashing convenience function. + * + * @param key Integer to be hashed. + * @param seed 64-bit seed used to alter the hash result predictably. + * + * Signed integers can safely be cast to their unsigned equivalent for hashing. + */ +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint8(const uint8_t key, const uint64_t seed) RAPIDHASH_NOEXCEPT { + return rapidhashNano_withSeed(&key, 1, seed); +} + +/* + * rapidhash 16-bit integer hashing convenience function. + * + * @param key Integer to be hashed. + * @param seed 64-bit seed used to alter the hash result predictably. + * + * Signed integers can safely be cast to their unsigned equivalent for hashing. + */ +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint16(const uint16_t key, const uint64_t seed) RAPIDHASH_NOEXCEPT { + const uint16_t le = rapidhash_to_le_u16(key); + return rapidhashNano_withSeed(&le, 2, seed); +} + +/* + * rapidhash 32-bit integer hashing convenience function. + * + * @param key Integer to be hashed. + * @param seed 64-bit seed used to alter the hash result predictably. + * + * Signed integers can safely be cast to their unsigned equivalent for hashing. + */ +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint32(const uint32_t key, const uint64_t seed) RAPIDHASH_NOEXCEPT { + const uint32_t le = rapidhash_to_le_u32(key); + return rapidhashNano_withSeed(&le, 4, seed); +} + +/* + * rapidhash 64-bit integer hashing convenience function. + * + * @param key Integer to be hashed. + * @param seed 64-bit seed used to alter the hash result predictably. + * + * Signed integers can safely be cast to their unsigned equivalent for hashing. + */ +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint64(const uint64_t key, const uint64_t seed) RAPIDHASH_NOEXCEPT { + const uint64_t le = rapidhash_to_le_u64(key); + return rapidhashNano_withSeed(&le, 8, seed); +} From 9d742d7e4e8a75a2021b37ff1a5bf7b34bb57a68 Mon Sep 17 00:00:00 2001 From: Liam Gray Date: Fri, 26 Sep 2025 14:58:06 +0100 Subject: [PATCH 2/2] Make rapid_read use the rapid_to_le methods --- rapidhash.h | 93 ++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 48 deletions(-) diff --git a/rapidhash.h b/rapidhash.h index 5922b8c..083333f 100755 --- a/rapidhash.h +++ b/rapidhash.h @@ -204,30 +204,48 @@ * Returns 64-bit xor between high and low 64 bits of C. */ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapid_mix(uint64_t A, uint64_t B) RAPIDHASH_NOEXCEPT { rapid_mum(&A,&B); return A^B; } - - /* - * Read functions. - */ - #ifdef RAPIDHASH_LITTLE_ENDIAN - RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return v;} - RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return v;} - #elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) - RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return __builtin_bswap64(v);} - RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return __builtin_bswap32(v);} - #elif defined(_MSC_VER) - RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint64_t v; memcpy(&v, p, sizeof(uint64_t)); return _byteswap_uint64(v);} - RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { uint32_t v; memcpy(&v, p, sizeof(uint32_t)); return _byteswap_ulong(v);} - #else - RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { - uint64_t v; memcpy(&v, p, 8); - return (((v >> 56) & 0xff)| ((v >> 40) & 0xff00)| ((v >> 24) & 0xff0000)| ((v >> 8) & 0xff000000)| ((v << 8) & 0xff00000000)| ((v << 24) & 0xff0000000000)| ((v << 40) & 0xff000000000000)| ((v << 56) & 0xff00000000000000)); - } - RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { - uint32_t v; memcpy(&v, p, 4); - return (((v >> 24) & 0xff)| ((v >> 8) & 0xff00)| ((v << 8) & 0xff0000)| ((v << 24) & 0xff000000)); - } - #endif - + +/* + * Helper methods for converting integers to little-endian bytes on big-endian platforms. + */ +#ifdef RAPIDHASH_LITTLE_ENDIAN +RAPIDHASH_INLINE_CONSTEXPR uint16_t rapid_to_le_u16(const uint16_t v) RAPIDHASH_NOEXCEPT { return v; } +RAPIDHASH_INLINE_CONSTEXPR uint32_t rapid_to_le_u32(const uint32_t v) RAPIDHASH_NOEXCEPT { return v; } +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapid_to_le_u64(const uint64_t v) RAPIDHASH_NOEXCEPT { return v; } +#elif defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__) +RAPIDHASH_INLINE_CONSTEXPR uint16_t rapid_to_le_u16(const uint16_t v) RAPIDHASH_NOEXCEPT { return __builtin_bswap16(v); } +RAPIDHASH_INLINE_CONSTEXPR uint32_t rapid_to_le_u32(const uint32_t v) RAPIDHASH_NOEXCEPT { return __builtin_bswap32(v); } +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapid_to_le_u64(const uint64_t v) RAPIDHASH_NOEXCEPT { return __builtin_bswap64(v); } +#elif defined(_MSC_VER) +RAPIDHASH_INLINE_CONSTEXPR uint16_t rapid_to_le_u16(const uint16_t v) RAPIDHASH_NOEXCEPT { return _byteswap_ushort(v); } +RAPIDHASH_INLINE_CONSTEXPR uint32_t rapid_to_le_u32(const uint32_t v) RAPIDHASH_NOEXCEPT { return _byteswap_ulong(v); } +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapid_to_le_u64(const uint64_t v) RAPIDHASH_NOEXCEPT { return _byteswap_uint64(v); } +#else +RAPIDHASH_INLINE_CONSTEXPR uint16_t rapid_to_le_u16(const uint16_t v) RAPIDHASH_NOEXCEPT { + return ((v >> 8) & 0xff)| ((v << 8) & 0xff00); +} +RAPIDHASH_INLINE_CONSTEXPR uint32_t rapid_to_le_u32(const uint32_t v) RAPIDHASH_NOEXCEPT { + return (((v >> 24) & 0xff)| ((v >> 8) & 0xff00)| ((v << 8) & 0xff0000)| ((v << 24) & 0xff000000)); +} +RAPIDHASH_INLINE_CONSTEXPR uint64_t rapid_to_le_u64(const uint64_t v) RAPIDHASH_NOEXCEPT { + return (((v >> 56) & 0xff)| ((v >> 40) & 0xff00)| ((v >> 24) & 0xff0000)| ((v >> 8) & 0xff000000)| ((v << 8) & 0xff00000000)| ((v << 24) & 0xff0000000000)| ((v << 40) & 0xff000000000000)| ((v << 56) & 0xff00000000000000)); +} +#endif + +/* + * Read functions. + */ +RAPIDHASH_INLINE uint64_t rapid_read64(const uint8_t *p) RAPIDHASH_NOEXCEPT { + uint64_t v; + memcpy(&v, p, sizeof(uint64_t)); + return rapid_to_le_u64(v); +} +RAPIDHASH_INLINE uint64_t rapid_read32(const uint8_t *p) RAPIDHASH_NOEXCEPT { + uint32_t v; + memcpy(&v, p, sizeof(uint32_t)); + return rapid_to_le_u32(v); +} + /* * rapidhash main function. * @@ -565,26 +583,11 @@ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhashNano(const void *key, size_t len) R return rapidhashNano_withSeed(key, len, 0); } -/* - * Helper method for converting to little-endian bytes on big-endian platforms. - */ -#ifndef RAPIDHASH_LITTLE_ENDIAN -RAPIDHASH_INLINE_CONSTEXPR uint16_t rapidhash_to_le_u16(const uint16_t v) RAPIDHASH_NOEXCEPT { return __builtin_bswap16(v); } -RAPIDHASH_INLINE_CONSTEXPR uint32_t rapidhash_to_le_u32(const uint32_t v) RAPIDHASH_NOEXCEPT { return __builtin_bswap32(v); } -RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_to_le_u64(const uint64_t v) RAPIDHASH_NOEXCEPT { return __builtin_bswap64(v); } -#else -RAPIDHASH_INLINE_CONSTEXPR uint16_t rapidhash_to_le_u16(const uint16_t v) RAPIDHASH_NOEXCEPT { return v; } -RAPIDHASH_INLINE_CONSTEXPR uint32_t rapidhash_to_le_u32(const uint32_t v) RAPIDHASH_NOEXCEPT { return v; } -RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_to_le_u64(const uint64_t v) RAPIDHASH_NOEXCEPT { return v; } -#endif - /* * rapidhash 8-bit integer hashing convenience function. * * @param key Integer to be hashed. * @param seed 64-bit seed used to alter the hash result predictably. - * - * Signed integers can safely be cast to their unsigned equivalent for hashing. */ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint8(const uint8_t key, const uint64_t seed) RAPIDHASH_NOEXCEPT { return rapidhashNano_withSeed(&key, 1, seed); @@ -595,11 +598,9 @@ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint8(const uint8_t key, const uin * * @param key Integer to be hashed. * @param seed 64-bit seed used to alter the hash result predictably. - * - * Signed integers can safely be cast to their unsigned equivalent for hashing. */ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint16(const uint16_t key, const uint64_t seed) RAPIDHASH_NOEXCEPT { - const uint16_t le = rapidhash_to_le_u16(key); + const uint16_t le = rapid_to_le_u16(key); return rapidhashNano_withSeed(&le, 2, seed); } @@ -608,11 +609,9 @@ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint16(const uint16_t key, const u * * @param key Integer to be hashed. * @param seed 64-bit seed used to alter the hash result predictably. - * - * Signed integers can safely be cast to their unsigned equivalent for hashing. */ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint32(const uint32_t key, const uint64_t seed) RAPIDHASH_NOEXCEPT { - const uint32_t le = rapidhash_to_le_u32(key); + const uint32_t le = rapid_to_le_u32(key); return rapidhashNano_withSeed(&le, 4, seed); } @@ -621,10 +620,8 @@ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint32(const uint32_t key, const u * * @param key Integer to be hashed. * @param seed 64-bit seed used to alter the hash result predictably. - * - * Signed integers can safely be cast to their unsigned equivalent for hashing. */ RAPIDHASH_INLINE_CONSTEXPR uint64_t rapidhash_uint64(const uint64_t key, const uint64_t seed) RAPIDHASH_NOEXCEPT { - const uint64_t le = rapidhash_to_le_u64(key); + const uint64_t le = rapid_to_le_u64(key); return rapidhashNano_withSeed(&le, 8, seed); }