xref: /freebsd/contrib/llvm-project/libcxx/include/__cxx03/__bit/countr.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
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 
12 #ifndef _LIBCPP___CXX03___BIT_COUNTR_H
13 #define _LIBCPP___CXX03___BIT_COUNTR_H
14 
15 #include <__cxx03/__bit/rotate.h>
16 #include <__cxx03/__config>
17 #include <__cxx03/limits>
18 
19 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
20 #  pragma GCC system_header
21 #endif
22 
23 _LIBCPP_PUSH_MACROS
24 #include <__cxx03/__undef_macros>
25 
26 _LIBCPP_BEGIN_NAMESPACE_STD
27 
__libcpp_ctz(unsigned __x)28 _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI int __libcpp_ctz(unsigned __x) _NOEXCEPT { return __builtin_ctz(__x); }
29 
__libcpp_ctz(unsigned long __x)30 _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI int __libcpp_ctz(unsigned long __x) _NOEXCEPT {
31   return __builtin_ctzl(__x);
32 }
33 
__libcpp_ctz(unsigned long long __x)34 _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI int __libcpp_ctz(unsigned long long __x) _NOEXCEPT {
35   return __builtin_ctzll(__x);
36 }
37 
38 template <class _Tp>
__countr_zero(_Tp __t)39 _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI int __countr_zero(_Tp __t) _NOEXCEPT {
40 #if __has_builtin(__builtin_ctzg)
41   return __builtin_ctzg(__t, numeric_limits<_Tp>::digits);
42 #else  // __has_builtin(__builtin_ctzg)
43   if (__t == 0)
44     return numeric_limits<_Tp>::digits;
45   if (sizeof(_Tp) <= sizeof(unsigned int))
46     return std::__libcpp_ctz(static_cast<unsigned int>(__t));
47   else if (sizeof(_Tp) <= sizeof(unsigned long))
48     return std::__libcpp_ctz(static_cast<unsigned long>(__t));
49   else if (sizeof(_Tp) <= sizeof(unsigned long long))
50     return std::__libcpp_ctz(static_cast<unsigned long long>(__t));
51   else {
52     int __ret                      = 0;
53     const unsigned int __ulldigits = numeric_limits<unsigned long long>::digits;
54     while (static_cast<unsigned long long>(__t) == 0uLL) {
55       __ret += __ulldigits;
56       __t >>= __ulldigits;
57     }
58     return __ret + std::__libcpp_ctz(static_cast<unsigned long long>(__t));
59   }
60 #endif // __has_builtin(__builtin_ctzg)
61 }
62 
63 _LIBCPP_END_NAMESPACE_STD
64 
65 _LIBCPP_POP_MACROS
66 
67 #endif // _LIBCPP___CXX03___BIT_COUNTR_H
68