Add m_core_ctz32 & m_core_ctz64 functions

(Count trailing zeros)
This commit is contained in:
Patrick Pelissier committed 2022-08-29 19:30:09 +02:00
1 parent e6fe36d3cd
commit 6b994c2928
2 files changed
+60 -2

No files matched your search

+48 -2
View File
@@ -2652,6 +2652,15 @@ static inline unsigned int m_core_clz64(uint64_t limb)
return (unsigned int) (M_UNLIKELY (limb == 0ULL) ? sizeof (uint64_t)*CHAR_BIT : (size_t) __builtin_clzll(limb) - (sizeof (unsigned long long) - sizeof (uint64_t)) * CHAR_BIT);
}
static inline unsigned int m_core_ctz32(uint32_t limb)
{
return (unsigned int) (M_UNLIKELY (limb == 0) ? sizeof(uint32_t)*CHAR_BIT : (size_t) __builtin_ctzl(limb));
}
static inline unsigned int m_core_ctz64(uint64_t limb)
{
return (unsigned int) (M_UNLIKELY (limb == 0ULL) ? sizeof (uint64_t)*CHAR_BIT : (size_t) __builtin_ctzll(limb));
}
#elif defined(_MSC_VER) && (defined(_M_AMD64) || defined(_M_ARM64))
// NOTE: _BitScanReverse64 is 64-bits only (not compatible 32 bits).
#include <intrin.h>
@@ -2674,6 +2683,25 @@ static inline unsigned int m_core_clz64(uint64_t limb)
}
}
static inline unsigned int m_core_ctz32(uint32_t limb)
{
unsigned long bit = 0;
if (_BitScanForward( &bit, limb ) != 0) {
return bit;
} else {
return 32;
}
}
static inline unsigned int m_core_ctz64(uint64_t limb)
{
unsigned long bit = 0;
if (_BitScanForward64( &bit, limb ) != 0) {
return bit;
} else {
return 64;
}
}
#else
// Emulation layer
#define M_CORE_CLZ_TAB "\010\07\06\06\05\05\05\05\04\04\04\04\04\04\04\04\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\03\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\02\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
@@ -2687,7 +2715,7 @@ static inline unsigned int m_core_clz32(uint32_t limb)
+ -2 for the highest 16 bits,
+ -1 for the highest 8 bits,
+ 0 otherwise */
shift = -(limb < 0x1000000UL);
shift = -(unsigned) (limb < 0x1000000UL);
shift -= (limb < 0x10000UL);
shift -= (limb < 0x100UL);
shift = shift*8 + 24;
@@ -2708,7 +2736,7 @@ static inline unsigned int m_core_clz64(uint64_t limb)
+ -2 for the highest 16 bits,
+ -1 for the highest 8 bits,
+ 0 otherwise */
shift = -(limb < 0x100000000000000UL);
shift = -(unsigned) (limb < 0x100000000000000UL);
shift -= (limb < 0x1000000000000UL);
shift -= (limb < 0x10000000000UL);
shift -= (limb < 0x100000000UL);
@@ -2719,6 +2747,24 @@ static inline unsigned int m_core_clz64(uint64_t limb)
shift = 56 - shift + (unsigned int) M_CORE_CLZ_TAB[limb >> shift ];
return shift;
}
/* See algorithm ctz5 that uses de Bruijn sequences to construct a minimal perfect hash function (32 bits) */
#define M_CORE_CTZ_TAB "\000\001\034\002\035\016\030\003\036\026\024\017\031\021\004\010\037\033\015\027\025\023\020\007\032\014\022\006\013\005\012\011"
static inline unsigned int m_core_ctz32(uint32_t limb)
{
if (limb == 0) { return 32; }
return (unsigned int) M_CORE_CTZ_TAB[ ( (uint32_t) (limb & -limb) * 0x077CB531) >> 27];
}
static inline unsigned int m_core_ctz64(uint64_t limb)
{
unsigned int shift = 0;
if ((limb & 0x0FFFFFFFFull) == 0) { shift = 32; limb >>= 32; }
if (limb == 0) { return 32+shift; }
return shift + (unsigned int) M_CORE_CTZ_TAB[ ( (uint32_t) (limb & -limb) * 0x077CB531) >> 27];
}
#endif
/* Implement a kind of FNV1A Hash.
+12
View File
@@ -749,6 +749,18 @@ static void test_builtin(void)
assert(m_core_clz64((uint64_t) ((1ULL<<i) | 1)) == 63U - i);
}
assert(m_core_ctz32(0) == 32);
for(unsigned i = 0; i < 31; i++) {
assert(m_core_ctz32((uint32_t) (1UL<<i)) == i);
assert(m_core_ctz32((uint32_t) ((1UL<<i) | 1UL<<31)) == i);
}
assert(m_core_ctz64(0) == 64);
for(unsigned i = 0; i < 63; i++) {
assert(m_core_ctz64((uint64_t) (1ULL<<i)) == i);
assert(m_core_ctz64((uint64_t) ((1ULL<<i) | 1ULL<<63)) == i);
}
assert ( m_core_roundpow2(0) == 0);
for(unsigned i = 0; i < 62; i++) {
assert ( m_core_roundpow2(1ULL<<i) == 1ULL<<i);