1515#include < __bit/rotate.h>
1616#include < __concepts/arithmetic.h>
1717#include < __config>
18+ #include < __type_traits/enable_if.h>
19+ #include < __type_traits/is_unsigned.h>
1820#include < limits>
1921
2022#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -38,31 +40,87 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned lo
3840 return __builtin_popcountll (__x);
3941}
4042
41- #if _LIBCPP_STD_VER >= 20
42-
43- template <__libcpp_unsigned_integer _Tp>
44- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount (_Tp __t ) noexcept {
45- # if __has_builtin(__builtin_popcountg)
46- return __builtin_popcountg (__t );
47- # else // __has_builtin(__builtin_popcountg)
48- if (sizeof (_Tp) <= sizeof (unsigned int ))
43+ #if _LIBCPP_STD_VER >= 17
44+ // Implementation using constexpr if for C++ standards >= 17
45+ template <class _Tp , __enable_if_t <is_unsigned<_Tp>::value, int > = 0 >
46+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 int __popcount (_Tp __t ) _NOEXCEPT {
47+ if constexpr (sizeof (_Tp) <= sizeof (unsigned int )) {
4948 return std::__libcpp_popcount (static_cast <unsigned int >(__t ));
50- else if (sizeof (_Tp) <= sizeof (unsigned long ))
49+ } else if constexpr (sizeof (_Tp) <= sizeof (unsigned long )) {
5150 return std::__libcpp_popcount (static_cast <unsigned long >(__t ));
52- else if (sizeof (_Tp) <= sizeof (unsigned long long ))
51+ } else if constexpr (sizeof (_Tp) <= sizeof (unsigned long long )) {
5352 return std::__libcpp_popcount (static_cast <unsigned long long >(__t ));
54- else {
53+ } else {
5554 int __ret = 0 ;
5655 while (__t != 0 ) {
5756 __ret += std::__libcpp_popcount (static_cast <unsigned long long >(__t ));
58- __t >>= numeric_limits<unsigned long long >::digits;
57+ __t >>= std:: numeric_limits<unsigned long long >::digits;
5958 }
6059 return __ret;
6160 }
62- # endif // __has_builtin(__builtin_popcountg)
6361}
6462
65- #endif // _LIBCPP_STD_VER >= 20
63+ #else
64+ // Equivalent SFINAE-based implementation for older C++ standards < 17
65+
66+ template < class _Tp , __enable_if_t <is_unsigned<_Tp>::value && sizeof (_Tp) <= sizeof (unsigned int ), int > = 0 >
67+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount (_Tp __t ) _NOEXCEPT {
68+ return std::__libcpp_popcount (static_cast <unsigned int >(__t ));
69+ }
70+
71+ template < class _Tp ,
72+ __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned int )) &&
73+ sizeof (_Tp) <= sizeof (unsigned long ),
74+ int > = 0 >
75+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount (_Tp __t ) _NOEXCEPT {
76+ return std::__libcpp_popcount (static_cast <unsigned long >(__t ));
77+ }
78+
79+ template < class _Tp ,
80+ __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long )) &&
81+ sizeof (_Tp) <= sizeof (unsigned long long ),
82+ int > = 0 >
83+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount (_Tp __t ) _NOEXCEPT {
84+ return std::__libcpp_popcount (static_cast <unsigned long long >(__t ));
85+ }
86+
87+ # if _LIBCPP_STD_VER == 11
88+ // Recursive constexpr implementation for C++11 due to limited constexpr support
89+ template < class _Tp , __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long long )), int > = 0 >
90+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount (_Tp __t ) _NOEXCEPT {
91+ return __t != 0 ? std::__libcpp_popcount (static_cast <unsigned long long >(__t )) +
92+ std::__popcount<_Tp>(__t >> numeric_limits<unsigned long long >::digits)
93+ : 0 ;
94+ }
95+
96+ # else
97+ // Loop-based constexpr implementation for C++14 (and non-constexpr for C++03, 98)
98+ template < class _Tp , __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long long )), int > = 0 >
99+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int __popcount (_Tp __t ) _NOEXCEPT {
100+ int __ret = 0 ;
101+ while (__t != 0 ) {
102+ __ret += std::__libcpp_popcount (static_cast <unsigned long long >(__t ));
103+ __t >>= numeric_limits<unsigned long long >::digits;
104+ }
105+ return __ret;
106+ }
107+
108+ # endif // _LIBCPP_STD_VER == 11
109+
110+ #endif // _LIBCPP_STD_VER >= 17
111+
112+ #if _LIBCPP_STD_VER >= 20
113+
114+ template <__libcpp_unsigned_integer _Tp>
115+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount (_Tp __t ) noexcept {
116+ # if __has_builtin(__builtin_popcountg)
117+ return __builtin_popcountg (__t );
118+ # else
119+ return __popcount (__t );
120+ # endif
121+ }
122+
123+ #endif
66124
67125_LIBCPP_END_NAMESPACE_STD
68126
0 commit comments