15
15
#include < __bit/rotate.h>
16
16
#include < __concepts/arithmetic.h>
17
17
#include < __config>
18
+ #include < __type_traits/enable_if.h>
19
+ #include < __type_traits/is_unsigned.h>
18
20
#include < limits>
19
21
20
22
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -38,31 +40,87 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int __libcpp_popcount(unsigned lo
38
40
return __builtin_popcountll (__x);
39
41
}
40
42
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 )) {
49
48
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 )) {
51
50
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 )) {
53
52
return std::__libcpp_popcount (static_cast <unsigned long long >(__t ));
54
- else {
53
+ } else {
55
54
int __ret = 0 ;
56
55
while (__t != 0 ) {
57
56
__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;
59
58
}
60
59
return __ret;
61
60
}
62
- # endif // __has_builtin(__builtin_popcountg)
63
61
}
64
62
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
66
124
67
125
_LIBCPP_END_NAMESPACE_STD
68
126
0 commit comments