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,83 @@ 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
43+ #ifndef _LIBCPP_CXX03_LANG
44+ // constexpr implementation for C++11 and later
4245
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 ))
46+ template <class _Tp >
47+ _LIBCPP_HIDE_FROM_ABI constexpr int __popcount (_Tp __t ) _NOEXCEPT {
48+ static_assert (is_unsigned<_Tp>::value, " __popcount only works with unsigned types" );
49+ if constexpr (sizeof (_Tp) <= sizeof (unsigned int )) {
4950 return std::__libcpp_popcount (static_cast <unsigned int >(__t ));
50- else if (sizeof (_Tp) <= sizeof (unsigned long ))
51+ } else if constexpr (sizeof (_Tp) <= sizeof (unsigned long )) {
5152 return std::__libcpp_popcount (static_cast <unsigned long >(__t ));
52- else if (sizeof (_Tp) <= sizeof (unsigned long long ))
53+ } else if constexpr (sizeof (_Tp) <= sizeof (unsigned long long )) {
5354 return std::__libcpp_popcount (static_cast <unsigned long long >(__t ));
54- else {
55+ } else {
56+ # if _LIBCPP_STD_VER == 11
57+ // A recursive constexpr implementation for C++11
58+ return __t != 0 ? std::__libcpp_popcount (static_cast <unsigned long long >(__t )) +
59+ std::__popcount<_Tp>(__t >> numeric_limits<unsigned long long >::digits)
60+ : 0 ;
61+ # else
5562 int __ret = 0 ;
5663 while (__t != 0 ) {
5764 __ret += std::__libcpp_popcount (static_cast <unsigned long long >(__t ));
58- __t >>= numeric_limits<unsigned long long >::digits;
65+ __t >>= std:: numeric_limits<unsigned long long >::digits;
5966 }
6067 return __ret;
6168 }
62- # endif // __has_builtin(__builtin_popcountg)
69+ # endif
6370}
6471
65- #endif // _LIBCPP_STD_VER >= 20
72+ #else
73+ // Implementation for C++03
74+
75+ template < class _Tp , __enable_if_t <is_unsigned<_Tp>::value && sizeof (_Tp) <= sizeof (unsigned int ), int > = 0 >
76+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount (_Tp __t ) {
77+ return std::__libcpp_popcount (static_cast <unsigned int >(__t ));
78+ }
79+
80+ template < class _Tp ,
81+ __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned int )) &&
82+ sizeof (_Tp) <= sizeof (unsigned long ),
83+ int > = 0 >
84+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount (_Tp __t ) {
85+ return std::__libcpp_popcount (static_cast <unsigned long >(__t ));
86+ }
87+
88+ template < class _Tp ,
89+ __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long )) &&
90+ sizeof (_Tp) <= sizeof (unsigned long long ),
91+ int > = 0 >
92+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount (_Tp __t ) {
93+ return std::__libcpp_popcount (static_cast <unsigned long long >(__t ));
94+ }
95+
96+ template < class _Tp , __enable_if_t <is_unsigned<_Tp>::value && (sizeof (_Tp) > sizeof (unsigned long long )), int > = 0 >
97+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __popcount (_Tp __t ) {
98+ int __ret = 0 ;
99+ while (__t != 0 ) {
100+ __ret += std::__libcpp_popcount (static_cast <unsigned long long >(__t ));
101+ __t >>= std::numeric_limits<unsigned long long >::digits;
102+ }
103+ return __ret;
104+ }
105+
106+ #endif // _LIBCPP_CXX03_LANG
107+
108+ #if _LIBCPP_STD_VER >= 20
109+
110+ template <__libcpp_unsigned_integer _Tp>
111+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr int popcount (_Tp __t ) noexcept {
112+ # if __has_builtin(__builtin_popcountg)
113+ return __builtin_popcountg (__t );
114+ # else
115+ return std::__popcount (__t );
116+ # endif
117+ }
118+
119+ #endif
66120
67121_LIBCPP_END_NAMESPACE_STD
68122
0 commit comments