66//
77// ===----------------------------------------------------------------------===//
88
9- // TODO: __builtin_ctzg is available since Clang 19 and GCC 14. When support for older versions is dropped, we can
10- // refactor this code to exclusively use __builtin_ctzg.
11-
129#ifndef _LIBCPP___BIT_COUNTR_H
1310#define _LIBCPP___BIT_COUNTR_H
1411
1512#include < __assert>
16- #include < __bit/rotate.h>
1713#include < __concepts/arithmetic.h>
1814#include < __config>
1915#include < __type_traits/is_unsigned.h>
@@ -28,55 +24,10 @@ _LIBCPP_PUSH_MACROS
2824
2925_LIBCPP_BEGIN_NAMESPACE_STD
3026
31- [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz (unsigned __x) _NOEXCEPT {
32- return __builtin_ctz (__x);
33- }
34-
35- [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz (unsigned long __x) _NOEXCEPT {
36- return __builtin_ctzl (__x);
37- }
38-
39- [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_ctz (unsigned long long __x) _NOEXCEPT {
40- return __builtin_ctzll (__x);
41- }
42-
43- // A constexpr implementation for C++11 and later (using clang extensions for constexpr support)
44- // Precondition: __t != 0 (the caller __countr_zero handles __t == 0 as a special case)
45- template <class _Tp >
46- [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero_impl (_Tp __t ) _NOEXCEPT {
47- _LIBCPP_ASSERT_INTERNAL (__t != 0 , " __countr_zero_impl called with zero value" );
48- static_assert (is_unsigned<_Tp>::value, " __countr_zero_impl only works with unsigned types" );
49- if _LIBCPP_CONSTEXPR (sizeof (_Tp) <= sizeof (unsigned int )) {
50- return std::__libcpp_ctz (static_cast <unsigned int >(__t ));
51- } else if _LIBCPP_CONSTEXPR (sizeof (_Tp) <= sizeof (unsigned long )) {
52- return std::__libcpp_ctz (static_cast <unsigned long >(__t ));
53- } else if _LIBCPP_CONSTEXPR (sizeof (_Tp) <= sizeof (unsigned long long )) {
54- return std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
55- } else {
56- #if _LIBCPP_STD_VER == 11
57- unsigned long long __ull = static_cast <unsigned long long >(__t );
58- const unsigned int __ulldigits = numeric_limits<unsigned long long >::digits;
59- return __ull == 0ull ? __ulldigits + std::__countr_zero_impl<_Tp>(__t >> __ulldigits) : std::__libcpp_ctz (__ull);
60- #else
61- int __ret = 0 ;
62- const unsigned int __ulldigits = numeric_limits<unsigned long long >::digits;
63- while (static_cast <unsigned long long >(__t ) == 0uLL) {
64- __ret += __ulldigits;
65- __t >>= __ulldigits;
66- }
67- return __ret + std::__libcpp_ctz (static_cast <unsigned long long >(__t ));
68- #endif
69- }
70- }
71-
7227template <class _Tp >
7328[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __countr_zero (_Tp __t ) _NOEXCEPT {
7429 static_assert (is_unsigned<_Tp>::value, " __countr_zero only works with unsigned types" );
75- #if __has_builtin(__builtin_ctzg) // TODO (LLVM 21): This can be dropped once we only support Clang >= 19.
7630 return __builtin_ctzg (__t , numeric_limits<_Tp>::digits);
77- #else
78- return __t != 0 ? std::__countr_zero_impl (__t ) : numeric_limits<_Tp>::digits;
79- #endif
8031}
8132
8233#if _LIBCPP_STD_VER >= 20
0 commit comments