MathExtras: Parametrize count(Trailing|Leading)Zeros on the type size.

Otherwise we will always select the generic version for e.g. unsigned
long if uint64_t is typedef'd to 'unsigned long long'. Also remove
enable_if hacks in favor of static_assert.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@228921 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Benjamin Kramer
2015-02-12 13:47:29 +00:00
parent b0d513e1eb
commit 9df4111876

View File

@ -35,19 +35,9 @@ enum ZeroBehavior {
ZB_Width ZB_Width
}; };
/// \brief Count number of 0's from the least significant bit to the most namespace detail {
/// stopping at the first 1. template <typename T, std::size_t SizeOfT> struct TrailingZerosCounter {
/// static std::size_t count(T Val, ZeroBehavior) {
/// Only unsigned integral types are allowed.
///
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments.
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed, std::size_t>::type
countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
(void)ZB;
if (!Val) if (!Val)
return std::numeric_limits<T>::digits; return std::numeric_limits<T>::digits;
if (Val & 0x1) if (Val & 0x1)
@ -66,17 +56,12 @@ countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
Mask >>= Shift; Mask >>= Shift;
} }
return ZeroBits; return ZeroBits;
} }
};
// Disable signed.
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed, std::size_t>::type
countTrailingZeros(T, ZeroBehavior = ZB_Width) LLVM_DELETED_FUNCTION;
#if __GNUC__ >= 4 || _MSC_VER #if __GNUC__ >= 4 || _MSC_VER
template <> template <typename T> struct TrailingZerosCounter<T, 4> {
inline std::size_t countTrailingZeros<uint32_t>(uint32_t Val, ZeroBehavior ZB) { static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0) if (ZB != ZB_Undefined && Val == 0)
return 32; return 32;
@ -87,11 +72,12 @@ inline std::size_t countTrailingZeros<uint32_t>(uint32_t Val, ZeroBehavior ZB) {
_BitScanForward(&Index, Val); _BitScanForward(&Index, Val);
return Index; return Index;
#endif #endif
} }
};
#if !defined(_MSC_VER) || defined(_M_X64) #if !defined(_MSC_VER) || defined(_M_X64)
template <> template <typename T> struct TrailingZerosCounter<T, 8> {
inline std::size_t countTrailingZeros<uint64_t>(uint64_t Val, ZeroBehavior ZB) { static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0) if (ZB != ZB_Undefined && Val == 0)
return 64; return 64;
@ -102,11 +88,13 @@ inline std::size_t countTrailingZeros<uint64_t>(uint64_t Val, ZeroBehavior ZB) {
_BitScanForward64(&Index, Val); _BitScanForward64(&Index, Val);
return Index; return Index;
#endif #endif
} }
};
#endif #endif
#endif #endif
} // namespace detail
/// \brief Count number of 0's from the most significant bit to the least /// \brief Count number of 0's from the least significant bit to the most
/// stopping at the first 1. /// stopping at the first 1.
/// ///
/// Only unsigned integral types are allowed. /// Only unsigned integral types are allowed.
@ -114,11 +102,16 @@ inline std::size_t countTrailingZeros<uint64_t>(uint64_t Val, ZeroBehavior ZB) {
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are /// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments. /// valid arguments.
template <typename T> template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer && std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
!std::numeric_limits<T>::is_signed, std::size_t>::type static_assert(std::numeric_limits<T>::is_integer &&
countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) { !std::numeric_limits<T>::is_signed,
(void)ZB; "Only unsigned integral types are allowed.");
return detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
}
namespace detail {
template <typename T, std::size_t SizeOfT> struct LeadingZerosCounter {
static std::size_t count(T Val, ZeroBehavior) {
if (!Val) if (!Val)
return std::numeric_limits<T>::digits; return std::numeric_limits<T>::digits;
@ -132,17 +125,12 @@ countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
ZeroBits |= Shift; ZeroBits |= Shift;
} }
return ZeroBits; return ZeroBits;
} }
};
// Disable signed.
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed, std::size_t>::type
countLeadingZeros(T, ZeroBehavior = ZB_Width) LLVM_DELETED_FUNCTION;
#if __GNUC__ >= 4 || _MSC_VER #if __GNUC__ >= 4 || _MSC_VER
template <> template <typename T> struct LeadingZerosCounter<T, 4> {
inline std::size_t countLeadingZeros<uint32_t>(uint32_t Val, ZeroBehavior ZB) { static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0) if (ZB != ZB_Undefined && Val == 0)
return 32; return 32;
@ -153,11 +141,12 @@ inline std::size_t countLeadingZeros<uint32_t>(uint32_t Val, ZeroBehavior ZB) {
_BitScanReverse(&Index, Val); _BitScanReverse(&Index, Val);
return Index ^ 31; return Index ^ 31;
#endif #endif
} }
};
#if !defined(_MSC_VER) || defined(_M_X64) #if !defined(_MSC_VER) || defined(_M_X64)
template <> template <typename T> struct LeadingZerosCounter<T, 8> {
inline std::size_t countLeadingZeros<uint64_t>(uint64_t Val, ZeroBehavior ZB) { static std::size_t count(T Val, ZeroBehavior ZB) {
if (ZB != ZB_Undefined && Val == 0) if (ZB != ZB_Undefined && Val == 0)
return 64; return 64;
@ -168,9 +157,26 @@ inline std::size_t countLeadingZeros<uint64_t>(uint64_t Val, ZeroBehavior ZB) {
_BitScanReverse64(&Index, Val); _BitScanReverse64(&Index, Val);
return Index ^ 63; return Index ^ 63;
#endif #endif
}
};
#endif
#endif
} // namespace detail
/// \brief Count number of 0's from the most significant bit to the least
/// stopping at the first 1.
///
/// Only unsigned integral types are allowed.
///
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
/// valid arguments.
template <typename T>
std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
"Only unsigned integral types are allowed.");
return detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
} }
#endif
#endif
/// \brief Get the index of the first set bit starting from the least /// \brief Get the index of the first set bit starting from the least
/// significant bit. /// significant bit.
@ -179,22 +185,13 @@ inline std::size_t countLeadingZeros<uint64_t>(uint64_t Val, ZeroBehavior ZB) {
/// ///
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are /// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
/// valid arguments. /// valid arguments.
template <typename T> template <typename T> T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
typename std::enable_if<std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed, T>::type
findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
if (ZB == ZB_Max && Val == 0) if (ZB == ZB_Max && Val == 0)
return std::numeric_limits<T>::max(); return std::numeric_limits<T>::max();
return countTrailingZeros(Val, ZB_Undefined); return countTrailingZeros(Val, ZB_Undefined);
} }
// Disable signed.
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed, T>::type
findFirstSet(T, ZeroBehavior = ZB_Max) LLVM_DELETED_FUNCTION;
/// \brief Get the index of the last set bit starting from the least /// \brief Get the index of the last set bit starting from the least
/// significant bit. /// significant bit.
/// ///
@ -202,10 +199,7 @@ findFirstSet(T, ZeroBehavior = ZB_Max) LLVM_DELETED_FUNCTION;
/// ///
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are /// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
/// valid arguments. /// valid arguments.
template <typename T> template <typename T> T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
typename std::enable_if<std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed, T>::type
findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
if (ZB == ZB_Max && Val == 0) if (ZB == ZB_Max && Val == 0)
return std::numeric_limits<T>::max(); return std::numeric_limits<T>::max();
@ -215,12 +209,6 @@ findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
(std::numeric_limits<T>::digits - 1); (std::numeric_limits<T>::digits - 1);
} }
// Disable signed.
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed, T>::type
findLastSet(T, ZeroBehavior = ZB_Max) LLVM_DELETED_FUNCTION;
/// \brief Macro compressed bit reversal table for 256 bits. /// \brief Macro compressed bit reversal table for 256 bits.
/// ///
/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable /// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable