Skip to content

Commit 6d09e07

Browse files
committed
[vector] Add specialization of count
1 parent 96083ae commit 6d09e07

File tree

3 files changed

+109
-8
lines changed

3 files changed

+109
-8
lines changed

stl/inc/vector

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3149,6 +3149,49 @@ _NODISCARD _CONSTEXPR20 _InIt _Find_vbool(_InIt _First, const _InIt _Last, const
31493149

31503150
return _Last;
31513151
}
3152+
3153+
template <class _InIt, class _Ty>
3154+
_NODISCARD _CONSTEXPR20 _Iter_diff_t<_InIt> _Count_vbool(_InIt _First, const _InIt _Last, const _Ty& _Val) {
3155+
_Iter_diff_t<_InIt> _Count = 0;
3156+
3157+
#ifdef __cpp_lib_bitops // TRANSITION, VSO-1020212
3158+
_Vbase* _UFirst = const_cast<_Vbase*>(_First._Myptr);
3159+
const _Vbase* const _ULast = _Last._Myptr;
3160+
3161+
// Fast path for less than _VBITS
3162+
if (_UFirst == _ULast) {
3163+
const auto _Mask = (_Vbase(-1) << _First._Myoff) & (_Vbase(-1) >> (_VBITS - _Last._Myoff));
3164+
const auto _SelectVal = _Val ? *_UFirst : static_cast<_Vbase>(~*_UFirst);
3165+
return __builtin_popcount(_SelectVal & _Mask);
3166+
}
3167+
3168+
if (_First._Myoff != 0) {
3169+
const auto _FirstMask = _Vbase(-1) << _First._Myoff;
3170+
const auto _SelectVal = _Val ? *_UFirst : static_cast<_Vbase>(~*_UFirst);
3171+
_Count += __builtin_popcount(_SelectVal & _FirstMask);
3172+
++_UFirst;
3173+
}
3174+
3175+
for (; _UFirst != _ULast; ++_UFirst) {
3176+
const auto _SelectVal = _Val ? *_UFirst : static_cast<_Vbase>(~*_UFirst);
3177+
_Count += __builtin_popcount(_SelectVal);
3178+
}
3179+
3180+
if (_Last._Myoff != 0) {
3181+
const auto _LastMask = _Vbase(-1) >> (_VBITS - _Last._Myoff);
3182+
const auto _SelectVal = _Val ? *_UFirst : static_cast<_Vbase>(~*_UFirst);
3183+
_Count += __builtin_popcount(_SelectVal & _LastMask);
3184+
}
3185+
#else // ^^^ __cpp_lib_bitops / !__cpp_lib_bitops vvv
3186+
for (; _First != _Last; ++_First) {
3187+
if (*_First == _Val) {
3188+
++_Count;
3189+
}
3190+
}
3191+
#endif // !__cpp_lib_bitops
3192+
3193+
return _Count;
3194+
}
31523195
#endif // _HAS_IF_CONSTEXPR
31533196
_STD_END
31543197

stl/inc/xutility

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5012,17 +5012,25 @@ template <class _InIt, class _Ty>
50125012
_NODISCARD _CONSTEXPR20 _Iter_diff_t<_InIt> count(const _InIt _First, const _InIt _Last, const _Ty& _Val) {
50135013
// count elements that match _Val
50145014
_Adl_verify_range(_First, _Last);
5015-
auto _UFirst = _Get_unwrapped(_First);
5016-
const auto _ULast = _Get_unwrapped(_Last);
5017-
_Iter_diff_t<_InIt> _Count = 0;
5015+
#if _HAS_IF_CONSTEXPR
5016+
if constexpr (_Is_vb_iterator<_InIt> && is_same_v<_Ty, bool>) {
5017+
return _Count_vbool(_First, _Last, _Val);
5018+
} else {
5019+
#endif // _HAS_IF_CONSTEXPR
5020+
auto _UFirst = _Get_unwrapped(_First);
5021+
const auto _ULast = _Get_unwrapped(_Last);
5022+
_Iter_diff_t<_InIt> _Count = 0;
50185023

5019-
for (; _UFirst != _ULast; ++_UFirst) {
5020-
if (*_UFirst == _Val) {
5021-
++_Count;
5024+
for (; _UFirst != _ULast; ++_UFirst) {
5025+
if (*_UFirst == _Val) {
5026+
++_Count;
5027+
}
50225028
}
5023-
}
50245029

5025-
return _Count;
5030+
return _Count;
5031+
#if _HAS_IF_CONSTEXPR
5032+
}
5033+
#endif // _HAS_IF_CONSTEXPR
50265034
}
50275035

50285036
#if _HAS_CXX17

tests/std/tests/GH_000625_vector_bool_optimization/test.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,9 +887,59 @@ bool test_find() {
887887
return true;
888888
}
889889

890+
bool test_count() {
891+
// Less than blockSize
892+
{
893+
const auto result_true = count(source.begin(), next(source.begin(), 8), true);
894+
assert(result_true == 5);
895+
896+
const auto result_false = count(source.begin(), next(source.begin(), 8), false);
897+
assert(result_false == 3);
898+
}
899+
900+
// Exactly blockSize
901+
{
902+
const auto result_true = count(source.begin(), next(source.begin(), blockSize), true);
903+
assert(result_true == 20);
904+
905+
const auto result_false = count(source.begin(), next(source.begin(), blockSize), false);
906+
assert(result_false == 12);
907+
}
908+
909+
// More than blockSize
910+
{
911+
const auto result_true = count(source.begin(), next(source.begin(), blockSize + 3), true);
912+
assert(result_true == 22);
913+
914+
const auto result_false = count(source.begin(), next(source.begin(), blockSize + 3), false);
915+
assert(result_false == 13);
916+
}
917+
918+
// Multiple blockSize ends at boundary
919+
{
920+
const auto result_true = count(source.begin(), next(source.begin(), 2 * blockSize), true);
921+
assert(result_true == 40);
922+
923+
const auto result_false = count(source.begin(), next(source.begin(), 2 * blockSize), false);
924+
assert(result_false == 24);
925+
}
926+
927+
// Multiple blockSize ends with offset
928+
{
929+
const auto result_true = count(source.begin(), next(source.begin(), 2 * blockSize + 5), true);
930+
assert(result_true == 43);
931+
932+
const auto result_false = count(source.begin(), next(source.begin(), 2 * blockSize + 5), false);
933+
assert(result_false == 26);
934+
}
935+
936+
return true;
937+
}
938+
890939
int main() {
891940
test_copy();
892941
test_fill();
893942
test_equal();
894943
test_find();
944+
test_count();
895945
}

0 commit comments

Comments
 (0)