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