@@ -41,11 +41,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
4141}
4242
4343#if _LIBCPP_STD_VER >= 17
44- // Implementation using constexpr if for C++ standards >= 17
44+ // constexpr implementation for C++17 and later
4545
46- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case)
47- template <class _Tp , __enable_if_t <is_unsigned<_Tp>::value, int > = 0 >
48- [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
46+ // Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case)
47+ template <class _Tp >
48+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
49+ static_assert (is_unsigned<_Tp>::value, " __countr_zero_impl only works with unsigned types" );
4950 if constexpr (sizeof (_Tp) <= sizeof (unsigned int )) {
5051 return std::__libcpp_ctz (static_cast <unsigned int >(__t ));
5152 } else if constexpr (sizeof (_Tp) <= sizeof (unsigned long )) {
@@ -64,15 +65,13 @@ template <class _Tp, __enable_if_t<is_unsigned<_Tp>::value, int> = 0>
6465}
6566
6667#else
67- // Equivalent SFINAE-based implementation for older C++ standards < 17
68+ // constexpr implementation for C++11 and C++14
6869
69- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case)
7070template < class _Tp , __enable_if_t <is_unsigned<_Tp>::value && sizeof (_Tp) <= sizeof (unsigned int ), int > = 0 >
7171_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
7272 return std::__libcpp_ctz (static_cast <unsigned int >(__t ));
7373}
7474
75- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero)
7675template < class _Tp ,
7776 __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned int )) &&
7877 sizeof (_Tp) <= sizeof (unsigned long ),
@@ -81,7 +80,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEP
8180 return std::__libcpp_ctz (static_cast <unsigned long >(__t ));
8281}
8382
84- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero)
8583template < class _Tp ,
8684 __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long )) &&
8785 sizeof (_Tp) <= sizeof (unsigned long long ),
@@ -90,42 +88,33 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl(_Tp __t) _NOEXCEP
9088 return std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
9189}
9290
93- # if _LIBCPP_STD_VER == 11
94-
95- // Recursive constexpr implementation for C++11 due to limited constexpr support
96- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero)
9791template < class _Tp , __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long long )), int > = 0 >
9892_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
93+ # if _LIBCPP_STD_VER == 11
94+ // A recursive constexpr implementation for C++11
9995 unsigned long long __ull = static_cast <unsigned long long >(__t );
10096 const unsigned int __ulldigits = numeric_limits<unsigned long long >::digits;
10197 return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz (__ull);
102- }
103-
10498# else
105-
106- // Loop-based constexpr implementation for C++14 (and non-constexpr for C++03, 98)
107- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero)
108- template < class _Tp , __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long long )), int > = 0 >
109- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
11099 int __ret = 0 ;
111100 const unsigned int __ulldigits = numeric_limits<unsigned long long >::digits;
112101 while (static_cast <unsigned long long >(__t ) == 0uLL) {
113102 __ret += __ulldigits;
114103 __t >>= __ulldigits;
115104 }
116105 return __ret + std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
106+ # endif
117107}
118108
119- # endif // _LIBCPP_STD_VER == 11
120-
121109#endif // _LIBCPP_STD_VER >= 17
122110
123- template <class _Tp , __enable_if_t <is_unsigned<_Tp>::value, int > = 0 >
111+ template <class _Tp >
124112[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero (_Tp __t ) _NOEXCEPT {
113+ static_assert (is_unsigned<_Tp>::value, " __countr_zero only works with unsigned types" );
125114#if __has_builtin(__builtin_ctzg)
126115 return __builtin_ctzg (__t , numeric_limits<_Tp>::digits);
127116#else
128- return __t != 0 ? __countr_zero_impl (__t ) : numeric_limits<_Tp>::digits;
117+ return __t != 0 ? std:: __countr_zero_impl (__t ) : numeric_limits<_Tp>::digits;
129118#endif
130119}
131120
0 commit comments