Skip to content

Commit f3103bd

Browse files
committed
Fix ambiguous call in ranges::count & std::count for vector<bool>::iterator
1 parent 5912de9 commit f3103bd

File tree

6 files changed

+225
-37
lines changed

6 files changed

+225
-37
lines changed

libcxx/include/__algorithm/count.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,21 @@ __count_bool(__bit_iterator<_Cp, _IsConst> __first, typename _Cp::size_type __n)
5555
if (__first.__ctz_ != 0) {
5656
__storage_type __clz_f = static_cast<__storage_type>(__bits_per_word - __first.__ctz_);
5757
__storage_type __dn = std::min(__clz_f, __n);
58-
__storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
59-
__r = std::__libcpp_popcount(std::__invert_if<!_ToCount>(*__first.__seg_) & __m);
58+
__storage_type __m = __middle_mask<__storage_type>(__first.__ctz_, __clz_f - __dn);
59+
// __r = std::__libcpp_popcount(std::__invert_if<!_ToCount>(*__first.__seg_) & __m);
60+
__r = std::popcount(__storage_type(std::__invert_if<!_ToCount>(*__first.__seg_) & __m));
6061
__n -= __dn;
6162
++__first.__seg_;
6263
}
6364
// do middle whole words
6465
for (; __n >= __bits_per_word; ++__first.__seg_, __n -= __bits_per_word)
65-
__r += std::__libcpp_popcount(std::__invert_if<!_ToCount>(*__first.__seg_));
66+
// __r += std::__libcpp_popcount(std::__invert_if<!_ToCount>(*__first.__seg_));
67+
__r += std::popcount(__storage_type(std::__invert_if<!_ToCount>(*__first.__seg_)));
6668
// do last partial word
6769
if (__n > 0) {
68-
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
69-
__r += std::__libcpp_popcount(std::__invert_if<!_ToCount>(*__first.__seg_) & __m);
70+
__storage_type __m = __trailing_mask<__storage_type>(__bits_per_word - __n);
71+
// __r += std::__libcpp_popcount(std::__invert_if<!_ToCount>(*__first.__seg_) & __m);
72+
__r += std::popcount(__storage_type(std::__invert_if<!_ToCount>(*__first.__seg_) & __m));
7073
}
7174
return __r;
7275
}

libcxx/include/__bit/popcount.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
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)
@@ -62,6 +64,50 @@ template <__libcpp_unsigned_integer _Tp>
6264
# endif // __has_builtin(__builtin_popcountg)
6365
}
6466

67+
#else
68+
69+
template <class _Tp, __enable_if_t<__has_builtin(__builtin_popcountg) && is_unsigned<_Tp>::value, int> = 0>
70+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int popcount(_Tp __t) _NOEXCEPT {
71+
return __builtin_popcountg(__t);
72+
}
73+
74+
template <
75+
class _Tp,
76+
__enable_if_t<!__has_builtin(__builtin_popcountg) && is_unsigned<_Tp>::value && sizeof(_Tp) <= sizeof(unsigned int),
77+
int> = 0>
78+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int popcount(_Tp __t) _NOEXCEPT {
79+
return std::__libcpp_popcount(static_cast<unsigned int>(__t));
80+
}
81+
82+
template < class _Tp,
83+
__enable_if_t<!__has_builtin(__builtin_popcountg) && is_unsigned<_Tp>::value &&
84+
(sizeof(_Tp) > sizeof(unsigned int)) && sizeof(_Tp) <= sizeof(unsigned long),
85+
int> = 0 >
86+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int popcount(_Tp __t) _NOEXCEPT {
87+
return std::__libcpp_popcount(static_cast<unsigned long>(__t));
88+
}
89+
90+
template < class _Tp,
91+
__enable_if_t<!__has_builtin(__builtin_popcountg) && is_unsigned<_Tp>::value &&
92+
(sizeof(_Tp) > sizeof(unsigned long)) && sizeof(_Tp) <= sizeof(unsigned long long),
93+
int> = 0 >
94+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR int popcount(_Tp __t) _NOEXCEPT {
95+
return std::__libcpp_popcount(static_cast<unsigned long long>(__t));
96+
}
97+
98+
template < class _Tp,
99+
__enable_if_t<!__has_builtin(__builtin_popcountg) && is_unsigned<_Tp>::value &&
100+
(sizeof(_Tp) > sizeof(unsigned long long)),
101+
int> = 0 >
102+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 int popcount(_Tp __t) _NOEXCEPT {
103+
int __ret = 0;
104+
while (__t != 0) {
105+
__ret += std::__libcpp_popcount(static_cast<unsigned long long>(__t));
106+
__t >>= numeric_limits<unsigned long long>::digits;
107+
}
108+
return __ret;
109+
}
110+
65111
#endif // _LIBCPP_STD_VER >= 20
66112

67113
_LIBCPP_END_NAMESPACE_STD

libcxx/include/__fwd/bit_reference.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#define _LIBCPP___FWD_BIT_REFERENCE_H
1111

1212
#include <__config>
13+
#include <__type_traits/enable_if.h>
14+
#include <__type_traits/is_unsigned.h>
1315

1416
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1517
# pragma GCC system_header
@@ -20,6 +22,22 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2022
template <class _Cp, bool _IsConst, typename _Cp::__storage_type = 0>
2123
class __bit_iterator;
2224

25+
template <class _StorageType, __enable_if_t<is_unsigned<_StorageType>::value, int> = 0>
26+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __leading_mask(unsigned __shift) {
27+
return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __shift);
28+
}
29+
30+
template <class _StorageType, __enable_if_t<is_unsigned<_StorageType>::value, int> = 0>
31+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __shift) {
32+
return static_cast<_StorageType>(static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __shift);
33+
}
34+
35+
template <class _StorageType, __enable_if_t<is_unsigned<_StorageType>::value, int> = 0>
36+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __lshift, unsigned __rshift) {
37+
return static_cast<_StorageType>(
38+
std::__leading_mask<_StorageType>(__lshift) & std::__trailing_mask<_StorageType>(__rshift));
39+
}
40+
2341
_LIBCPP_END_NAMESPACE_STD
2442

2543
#endif // _LIBCPP___FWD_BIT_REFERENCE_H

libcxx/test/std/algorithms/alg.nonmodifying/alg.count/count.pass.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <cstddef>
2222
#include <vector>
2323

24+
#include "sized_allocator.h"
2425
#include "test_macros.h"
2526
#include "test_iterators.h"
2627
#include "type_algorithms.h"
@@ -36,6 +37,29 @@ struct Test {
3637
}
3738
};
3839

40+
TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() {
41+
{
42+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
43+
std::vector<bool, Alloc> in(100, true, Alloc(1));
44+
assert(std::count(in.begin(), in.end(), true) == 100);
45+
}
46+
{
47+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
48+
std::vector<bool, Alloc> in(200, true, Alloc(1));
49+
assert(std::count(in.begin(), in.end(), true) == 200);
50+
}
51+
{
52+
using Alloc = sized_allocator<bool, std::uint32_t, std::int32_t>;
53+
std::vector<bool, Alloc> in(200, true, Alloc(1));
54+
assert(std::count(in.begin(), in.end(), true) == 200);
55+
}
56+
{
57+
using Alloc = sized_allocator<bool, std::uint64_t, std::int64_t>;
58+
std::vector<bool, Alloc> in(200, true, Alloc(1));
59+
assert(std::count(in.begin(), in.end(), true) == 200);
60+
}
61+
}
62+
3963
TEST_CONSTEXPR_CXX20 bool test() {
4064
types::for_each(types::cpp17_input_iterator_list<const int*>(), Test());
4165

@@ -51,6 +75,8 @@ TEST_CONSTEXPR_CXX20 bool test() {
5175
}
5276
}
5377

78+
test_bititer_with_custom_sized_types();
79+
5480
return true;
5581
}
5682

0 commit comments

Comments
 (0)