@@ -40,19 +40,25 @@ _LIBCPP_BEGIN_NAMESPACE_STD
4040 return __builtin_ctzll (__x);
4141}
4242
43- #if _LIBCPP_STD_VER >= 17
44- // Implementation using constexpr if for C++ standards >= 17
43+ #ifndef _LIBCPP_CXX03_LANG
44+ // constexpr implementation for C++11 and later
4545
46- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case)
46+ // Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case)
4747template <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 {
48+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI constexpr int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
4949 if constexpr (sizeof (_Tp) <= sizeof (unsigned int )) {
5050 return std::__libcpp_ctz (static_cast <unsigned int >(__t ));
5151 } else if constexpr (sizeof (_Tp) <= sizeof (unsigned long )) {
5252 return std::__libcpp_ctz (static_cast <unsigned long >(__t ));
5353 } else if constexpr (sizeof (_Tp) <= sizeof (unsigned long long )) {
5454 return std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
5555 } else {
56+ # if _LIBCPP_STD_VER == 11
57+ // A recursive constexpr implementation for C++11
58+ unsigned long long __ull = static_cast <unsigned long long >(__t );
59+ const unsigned int __ulldigits = numeric_limits<unsigned long long >::digits;
60+ return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz (__ull);
61+ # else
5662 int __ret = 0 ;
5763 const unsigned int __ulldigits = numeric_limits<unsigned long long >::digits;
5864 while (static_cast <unsigned long long >(__t ) == 0uLL) {
@@ -61,52 +67,35 @@ template <class _Tp, __enable_if_t<is_unsigned<_Tp>::value, int> = 0>
6167 }
6268 return __ret + std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
6369 }
64- }
70+ # endif // _LIBCPP_STD_VER == 11
71+ }
6572
6673#else
67- // Equivalent SFINAE-based implementation for older C++ standards < 17
74+ // Equivalent implementation using SFINAE-based overloading for C++03
6875
69- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case)
7076template < class _Tp , __enable_if_t <is_unsigned<_Tp>::value && sizeof (_Tp) <= sizeof (unsigned int ), int > = 0 >
71- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
77+ _LIBCPP_HIDE_FROM_ABI int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
7278 return std::__libcpp_ctz (static_cast <unsigned int >(__t ));
7379}
7480
75- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero)
7681template < class _Tp ,
7782 __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned int )) &&
7883 sizeof (_Tp) <= sizeof (unsigned long ),
7984 int > = 0 >
80- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
85+ _LIBCPP_HIDE_FROM_ABI int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
8186 return std::__libcpp_ctz (static_cast <unsigned long >(__t ));
8287}
8388
84- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero)
8589template < class _Tp ,
8690 __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long )) &&
8791 sizeof (_Tp) <= sizeof (unsigned long long ),
8892 int > = 0 >
89- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
93+ _LIBCPP_HIDE_FROM_ABI int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
9094 return std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
9195}
9296
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)
9797template < class _Tp , __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long long )), int > = 0 >
98- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
99- unsigned long long __ull = static_cast <unsigned long long >(__t );
100- const unsigned int __ulldigits = numeric_limits<unsigned long long >::digits;
101- return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz (__ull);
102- }
103-
104- # 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 {
98+ _LIBCPP_HIDE_FROM_ABI 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) {
@@ -116,35 +105,33 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp _
116105 return __ret + std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
117106}
118107
119- # endif // _LIBCPP_STD_VER == 11
120-
121- #endif // _LIBCPP_STD_VER >= 17
108+ #endif // _LIBCPP_CXX03_LANG
122109
123- template <class _Tp , __enable_if_t <is_unsigned<_Tp>::value, int > = 0 >
124- [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero (_Tp __t ) _NOEXCEPT {
110+ template <class _Tp , __enable_if_t <is_unsigned<_Tp>::value, int > = 0 >
111+ [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero (_Tp __t ) _NOEXCEPT {
125112#if __has_builtin(__builtin_ctzg)
126- return __builtin_ctzg (__t , numeric_limits<_Tp>::digits);
113+ return __builtin_ctzg (__t , numeric_limits<_Tp>::digits);
127114#else
128- return __t != 0 ? __countr_zero_impl (__t ) : numeric_limits<_Tp>::digits;
115+ return __t != 0 ? std:: __countr_zero_impl (__t ) : numeric_limits<_Tp>::digits;
129116#endif
130- }
117+ }
131118
132119#if _LIBCPP_STD_VER >= 20
133120
134- template <__libcpp_unsigned_integer _Tp>
135- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero (_Tp __t ) noexcept {
136- return std::__countr_zero (__t );
137- }
121+ template <__libcpp_unsigned_integer _Tp>
122+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_zero (_Tp __t ) noexcept {
123+ return std::__countr_zero (__t );
124+ }
138125
139- template <__libcpp_unsigned_integer _Tp>
140- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_one (_Tp __t ) noexcept {
141- return __t != numeric_limits<_Tp>::max () ? std::countr_zero (static_cast <_Tp>(~__t )) : numeric_limits<_Tp>::digits;
142- }
126+ template <__libcpp_unsigned_integer _Tp>
127+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int countr_one (_Tp __t ) noexcept {
128+ return __t != numeric_limits<_Tp>::max () ? std::countr_zero (static_cast <_Tp>(~__t )) : numeric_limits<_Tp>::digits;
129+ }
143130
144131#endif // _LIBCPP_STD_VER >= 20
145132
146- _LIBCPP_END_NAMESPACE_STD
133+ _LIBCPP_END_NAMESPACE_STD
147134
148- _LIBCPP_POP_MACROS
135+ _LIBCPP_POP_MACROS
149136
150137#endif // _LIBCPP___BIT_COUNTR_H
0 commit comments