diff options
author | Chris Robinson <[email protected]> | 2020-10-13 01:21:44 -0700 |
---|---|---|
committer | Chris Robinson <[email protected]> | 2020-10-13 01:21:44 -0700 |
commit | 303ca3af72aa7aecc25d94690f3886085c5c6e5b (patch) | |
tree | 05c0a6626b7884a76d181c8972d04f69800c2ece /common/alnumeric.h | |
parent | 45ff10fb4d847662ec7d1048f7e740c0ca55cf27 (diff) |
Use inline functions for popcnt and ctz instead of macros
Diffstat (limited to 'common/alnumeric.h')
-rw-r--r-- | common/alnumeric.h | 95 |
1 files changed, 47 insertions, 48 deletions
diff --git a/common/alnumeric.h b/common/alnumeric.h index af8e7b2e..d3d0edfd 100644 --- a/common/alnumeric.h +++ b/common/alnumeric.h @@ -90,34 +90,33 @@ inline size_t RoundUp(size_t value, size_t r) noexcept } -/* Define CTZ macros (count trailing zeros), and POPCNT macros (population - * count/count 1 bits), for 32- and 64-bit integers. The CTZ macros' results - * are *UNDEFINED* if the value is 0. +/* Define CountTrailingZeros (count trailing zero bits, starting from the lsb) + * and PopCount (population count/count 1 bits) methods, for 32- and 64-bit + * integers. The CountTrailingZeros results are *UNDEFINED* if the value is 0. */ -#ifdef __GNUC__ +template<typename T> +inline int PopCount(T val) = delete; +template<typename T> +inline int CountTrailingZeros(T val) = delete; -namespace detail_ { +#ifdef __GNUC__ -template<typename T> -constexpr inline auto popcnt64(T val) = delete; +/* Define variations for unsigned (long (long)) int, since we don't know what + * uint32/64_t are typedef'd to. + */ +template<> +inline int PopCount(unsigned long long val) { return __builtin_popcountll(val); } template<> -constexpr inline auto popcnt64(unsigned long long val) { return __builtin_popcountll(val); } +inline int PopCount(unsigned long val) { return __builtin_popcountl(val); } template<> -constexpr inline auto popcnt64(unsigned long val) { return __builtin_popcountl(val); } +inline int PopCount(unsigned int val) { return __builtin_popcount(val); } -template<typename T> -constexpr inline auto ctz64(T val) = delete; template<> -constexpr inline auto ctz64(unsigned long long val) { return __builtin_ctzll(val); } +inline int CountTrailingZeros(unsigned long long val) { return __builtin_ctzll(val); } template<> -constexpr inline auto ctz64(unsigned long val) { return __builtin_ctzl(val); } - -} // namespace detail_ - -#define POPCNT32 __builtin_popcount -#define CTZ32 __builtin_ctz -#define POPCNT64 detail_::popcnt64<uint64_t> -#define CTZ64 detail_::ctz64<uint64_t> +inline int CountTrailingZeros(unsigned long val) { return __builtin_ctzl(val); } +template<> +inline int CountTrailingZeros(unsigned int val) { return __builtin_ctz(val); } #else @@ -128,69 +127,69 @@ constexpr inline auto ctz64(unsigned long val) { return __builtin_ctzl(val); } * as the ntz2 variant. These likely aren't the most efficient methods, but * they're good enough if the GCC built-ins aren't available. */ -inline int fallback_popcnt32(uint32_t v) +template<> +inline int PopCount(uint32_t v) { v = v - ((v >> 1) & 0x55555555u); v = (v & 0x33333333u) + ((v >> 2) & 0x33333333u); v = (v + (v >> 4)) & 0x0f0f0f0fu; - return (int)((v * 0x01010101u) >> 24); + return static_cast<int>((v * 0x01010101u) >> 24); } -#define POPCNT32 fallback_popcnt32 -inline int fallback_popcnt64(uint64_t v) +template<> +inline int PopCount(uint64_t v) { v = v - ((v >> 1) & 0x5555555555555555_u64); v = (v & 0x3333333333333333_u64) + ((v >> 2) & 0x3333333333333333_u64); v = (v + (v >> 4)) & 0x0f0f0f0f0f0f0f0f_u64; - return (int)((v * 0x0101010101010101_u64) >> 56); + return static_cast<int>((v * 0x0101010101010101_u64) >> 56); } -#define POPCNT64 fallback_popcnt64 #if defined(_WIN64) -inline int msvc64_ctz32(uint32_t v) +template<> +inline int CountTrailingZeros(uint32_t v) { unsigned long idx = 32; _BitScanForward(&idx, v); - return (int)idx; + return static_cast<int>(idx); } -#define CTZ32 msvc64_ctz32 -inline int msvc64_ctz64(uint64_t v) +template<> +inline int CountTrailingZeros(uint64_t v) { unsigned long idx = 64; _BitScanForward64(&idx, v); - return (int)idx; + return static_cast<int>(idx); } -#define CTZ64 msvc64_ctz64 #elif defined(_WIN32) -inline int msvc_ctz32(uint32_t v) +template<> +inline int CountTrailingZeros(uint32_t v) { unsigned long idx = 32; _BitScanForward(&idx, v); - return (int)idx; + return static_cast<int>(idx); } -#define CTZ32 msvc_ctz32 -inline int msvc_ctz64(uint64_t v) +template<> +inline int CountTrailingZeros(uint64_t v) { unsigned long idx = 64; - if(!_BitScanForward(&idx, (uint32_t)(v&0xffffffff))) + if(!_BitScanForward(&idx, static_cast<uint32_t>(v&0xffffffff))) { - if(_BitScanForward(&idx, (uint32_t)(v>>32))) + if(_BitScanForward(&idx, static_cast<uint32_t>(v>>32))) idx += 32; } - return (int)idx; + return static_cast<int>(idx); } -#define CTZ64 msvc_ctz64 #else -inline int fallback_ctz32(uint32_t value) -{ return POPCNT32(~value & (value - 1)); } -#define CTZ32 fallback_ctz32 -inline int fallback_ctz64(uint64_t value) -{ return POPCNT64(~value & (value - 1)); } -#define CTZ64 fallback_ctz64 +template<> +inline int CountTrailingZeros(uint32_t value) +{ return PopCount(~value & (value - 1)); } +template<> +inline int CountTrailingZeros(uint64_t value) +{ return PopCount(~value & (value - 1)); } #endif #endif @@ -240,7 +239,7 @@ inline int float2int(float f) noexcept #elif (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP == 0) \ || ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) \ - && !defined(__SSE_MATH__)) + && !defined(__SSE_MATH__)) int sign, shift, mant; union { float f; @@ -276,7 +275,7 @@ inline int double2int(double d) noexcept #elif (defined(_MSC_VER) && defined(_M_IX86_FP) && _M_IX86_FP < 2) \ || ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) \ - && !defined(__SSE2_MATH__)) + && !defined(__SSE2_MATH__)) int sign, shift; int64_t mant; union { |