@@ -40,73 +40,63 @@ _LIBCPP_BEGIN_NAMESPACE_STD
40
40
return __builtin_ctzll (__x);
41
41
}
42
42
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
45
45
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" );
49
50
if constexpr (sizeof (_Tp) <= sizeof (unsigned int )) {
50
51
return std::__libcpp_ctz (static_cast <unsigned int >(__t ));
51
52
} else if constexpr (sizeof (_Tp) <= sizeof (unsigned long )) {
52
53
return std::__libcpp_ctz (static_cast <unsigned long >(__t ));
53
54
} else if constexpr (sizeof (_Tp) <= sizeof (unsigned long long )) {
54
55
return std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
55
56
} else {
57
+ # if _LIBCPP_STD_VER == 11
58
+ // A recursive constexpr implementation for C++11
59
+ unsigned long long __ull = static_cast <unsigned long long >(__t );
60
+ const unsigned int __ulldigits = numeric_limits<unsigned long long >::digits;
61
+ return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz (__ull);
62
+ # else
56
63
int __ret = 0 ;
57
64
const unsigned int __ulldigits = numeric_limits<unsigned long long >::digits;
58
65
while (static_cast <unsigned long long >(__t ) == 0uLL) {
59
66
__ret += __ulldigits;
60
67
__t >>= __ulldigits;
61
68
}
62
69
return __ret + std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
70
+ # endif
63
71
}
64
72
}
65
73
66
74
#else
67
- // Equivalent SFINAE-based implementation for older C++ standards < 17
75
+ // implementation for C++03
68
76
69
- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero, which handles __t == 0 as a special case)
70
77
template < 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 {
78
+ _LIBCPP_HIDE_FROM_ABI int __countr_zero_impl (_Tp __t ) {
72
79
return std::__libcpp_ctz (static_cast <unsigned int >(__t ));
73
80
}
74
81
75
- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero)
76
82
template < class _Tp ,
77
83
__enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned int )) &&
78
84
sizeof (_Tp) <= sizeof (unsigned long ),
79
85
int > = 0 >
80
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
86
+ _LIBCPP_HIDE_FROM_ABI int __countr_zero_impl (_Tp __t ) {
81
87
return std::__libcpp_ctz (static_cast <unsigned long >(__t ));
82
88
}
83
89
84
- // Precondition: __t != 0 (This is guaranteed by the caller __countr_zero)
85
90
template < class _Tp ,
86
91
__enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long )) &&
87
92
sizeof (_Tp) <= sizeof (unsigned long long ),
88
93
int > = 0 >
89
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
94
+ _LIBCPP_HIDE_FROM_ABI int __countr_zero_impl (_Tp __t ) {
90
95
return std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
91
96
}
92
97
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)
97
- template < 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
98
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 {
99
+ _LIBCPP_HIDE_FROM_ABI int __countr_zero_impl (_Tp __t ) {
110
100
int __ret = 0 ;
111
101
const unsigned int __ulldigits = numeric_limits<unsigned long long >::digits;
112
102
while (static_cast <unsigned long long >(__t ) == 0uLL) {
@@ -116,16 +106,15 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __countr_zero_impl(_Tp _
116
106
return __ret + std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
117
107
}
118
108
119
- # endif // _LIBCPP_STD_VER == 11
120
-
121
- #endif // _LIBCPP_STD_VER >= 17
109
+ #endif // _LIBCPP_CXX03_LANG
122
110
123
- template <class _Tp , __enable_if_t <is_unsigned<_Tp>::value, int > = 0 >
111
+ template <class _Tp >
124
112
[[__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" );
125
114
#if __has_builtin(__builtin_ctzg)
126
115
return __builtin_ctzg (__t , numeric_limits<_Tp>::digits);
127
116
#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;
129
118
#endif
130
119
}
131
120
0 commit comments