From 169bebdea7a0ef50fbb9232fa4844c2cfd51e256 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 22 Oct 2025 19:47:37 +0300 Subject: [PATCH 01/19] benchmark --- benchmarks/CMakeLists.txt | 1 + benchmarks/src/vector_bool_meow_of.cpp | 54 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 benchmarks/src/vector_bool_meow_of.cpp diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 9aa8a8c0450..5a054a4e42e 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -141,5 +141,6 @@ add_benchmark(unique src/unique.cpp) add_benchmark(vector_bool_copy src/vector_bool_copy.cpp) add_benchmark(vector_bool_copy_n src/vector_bool_copy_n.cpp) add_benchmark(vector_bool_count src/vector_bool_count.cpp) +add_benchmark(vector_bool_meow_of src/vector_bool_meow_of.cpp) add_benchmark(vector_bool_move src/vector_bool_move.cpp) add_benchmark(vector_bool_transform src/vector_bool_transform.cpp) diff --git a/benchmarks/src/vector_bool_meow_of.cpp b/benchmarks/src/vector_bool_meow_of.cpp new file mode 100644 index 00000000000..77a6839ec98 --- /dev/null +++ b/benchmarks/src/vector_bool_meow_of.cpp @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +// +#include +#include +#include +#include + +#include "skewed_allocator.hpp" + +using namespace std; + +enum class alg { any_, all_, none_ }; +enum class content { ones_then_zeros, zeros_then_ones }; + +template +void meow_of(benchmark::State& state) { + const auto size = static_cast(state.range(0)); + vector> source(size); + + if constexpr (Content == content::ones_then_zeros) { + fill(source.begin(), source.begin() + source.size() / 2, true); + } else { + fill(source.begin() + source.size() / 2, source.end(), true); + } + + for (auto _ : state) { + benchmark::DoNotOptimize(source); + bool result; + if constexpr (Alg == alg::any_) { + result = any_of(source.begin(), source.end(), Pred{}); + } else if constexpr (Alg == alg::all_) { + result = all_of(source.begin(), source.end(), Pred{}); + } else { + result = none_of(source.begin(), source.end(), Pred{}); + } + benchmark::DoNotOptimize(result); + } +} + +void common_args(auto bm) { + bm->RangeMultiplier(64)->Range(64, 64 << 10); +} + +using not_ = logical_not<>; + +BENCHMARK(meow_of)->Apply(common_args); +BENCHMARK(meow_of)->Apply(common_args); +BENCHMARK(meow_of)->Apply(common_args); +BENCHMARK(meow_of)->Apply(common_args); + +BENCHMARK_MAIN(); From ddd9e24ae80f02a39bd4dbf9a1cecc8122a94afc Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 22 Oct 2025 21:19:39 +0300 Subject: [PATCH 02/19] coverage --- .../test.cpp | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index 41e73cff35a..3a6917b3d62 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -190,6 +190,104 @@ CONSTEXPR20 bool test_transform() { return true; } +CONSTEXPR20 bool test__meow_of_helper(const size_t length_before, const size_t length, const size_t length_after) { + const size_t total_length = length_before + length + length_after; + + vector zeros(total_length); + vector ones(total_length); + vector mix(total_length); + fill(zeros.begin(), zeros.begin() + length_before, true); + fill(zeros.end() - length_after, zeros.end(), true); + fill(ones.begin() + length_before, ones.end() - length_after, true); + fill(mix.begin(), mix.begin() + length_before, true); + fill(mix.begin() + length_before + length / 2, mix.end() - length_after, true); + + const auto first_0 = zeros.begin() + length_before; + const auto last_0 = zeros.end() - length_after; + const auto first_1 = ones.cbegin() + length_before; + const auto last_1 = ones.cend() - length_after; + const auto first_m = mix.cbegin() + length_before; + const auto last_m = mix.cend() - length_after; + + if (length == 0) { +#if _HAS_CXX20 + assert(all_of(first_0, last_0, identity{}) == true); + assert(all_of(first_1, last_1, identity{}) == true); + assert(all_of(first_m, last_m, identity{}) == true); + + assert(any_of(first_0, last_0, identity{}) == false); + assert(any_of(first_1, last_1, identity{}) == false); + assert(any_of(first_m, last_m, identity{}) == false); + + assert(none_of(first_0, last_0, identity{}) == true); + assert(none_of(first_1, last_1, identity{}) == true); + assert(none_of(first_m, last_m, identity{}) == true); +#endif // _HAS_CXX20 + + assert(all_of(first_0, last_0, logical_not<>{}) == true); + assert(all_of(first_1, last_1, logical_not<>{}) == true); + assert(all_of(first_m, last_m, logical_not<>{}) == true); + + assert(any_of(first_0, last_0, logical_not<>{}) == false); + assert(any_of(first_1, last_1, logical_not<>{}) == false); + assert(any_of(first_m, last_m, logical_not<>{}) == false); + + assert(none_of(first_0, last_0, logical_not<>{}) == true); + assert(none_of(first_1, last_1, logical_not<>{}) == true); + assert(none_of(first_m, last_m, logical_not<>{}) == true); + } else { +#if _HAS_CXX20 + assert(all_of(first_0, last_0, identity{}) == false); + assert(all_of(first_1, last_1, identity{}) == true); + assert(all_of(first_m, last_m, identity{}) == false); + + assert(any_of(first_0, last_0, identity{}) == false); + assert(any_of(first_1, last_1, identity{}) == true); + assert(any_of(first_m, last_m, identity{}) == true); + + assert(none_of(first_0, last_0, identity{}) == true); + assert(none_of(first_1, last_1, identity{}) == false); + assert(none_of(first_m, last_m, identity{}) == false); +#endif // _HAS_CXX20 + + assert(all_of(first_0, last_0, logical_not<>{}) == true); + assert(all_of(first_1, last_1, logical_not<>{}) == false); + assert(all_of(first_m, last_m, logical_not<>{}) == false); + + assert(any_of(first_0, last_0, logical_not<>{}) == true); + assert(any_of(first_1, last_1, logical_not<>{}) == false); + assert(any_of(first_m, last_m, logical_not<>{}) == true); + + assert(none_of(first_0, last_0, logical_not<>{}) == false); + assert(none_of(first_1, last_1, logical_not<>{}) == true); + assert(none_of(first_m, last_m, logical_not<>{}) == false); + } + + return true; +} + +CONSTEXPR20 bool test_meow_of() { + // Empty range + test__meow_of_helper(0, 0, 3); + test__meow_of_helper(3, 0, 3); + + // One block, ends within block + test__meow_of_helper(0, 10, 3); + test__meow_of_helper(3, 10, 3); + + // One block, exactly + test__meow_of_helper(0, blockSize, 0); + + // Multiple blocks, spanning + test__meow_of_helper(3, blockSize - 2, 3); + test__meow_of_helper(3, blockSize + 2, 3); + + // Many blocks, exaclty + test__meow_of_helper(blockSize, 4 * blockSize, blockSize); + + return true; +} + CONSTEXPR20 void test_fill_helper(const size_t length) { // No offset { @@ -1531,6 +1629,7 @@ static_assert(test_fill()); static_assert(test_find()); static_assert(test_count()); static_assert(test_transform()); +static_assert(test_meow_of()); #if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-2574489 static_assert(test_copy_part_1()); @@ -1543,6 +1642,7 @@ int main() { test_find(); test_count(); test_transform(); + test_meow_of(); test_copy_part_1(); test_copy_part_2(); From 092ea877657cc1a3cf7d941cd333b20ae1313936 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 22 Oct 2025 21:20:19 +0300 Subject: [PATCH 03/19] optimization --- stl/inc/algorithm | 51 +++++++++++++++++++--------- stl/inc/vector | 85 +++++++++++++++++++++++++++++++++++++++++++++++ stl/inc/xutility | 7 ++++ 3 files changed, 128 insertions(+), 15 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index cb5511d5742..83e7367ee45 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -1506,18 +1506,30 @@ namespace ranges { } // namespace ranges #endif // _HAS_CXX20 +struct _All_of_vbool_traits; +struct _Any_of_vbool_traits; +struct _None_of_vbool_traits; + +template +_NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(_VbIt _First, _VbIt _Last, _Mapped_fn _Mapped_func); + _EXPORT_STD template _NODISCARD _CONSTEXPR20 bool all_of(_InIt _First, _InIt _Last, _Pr _Pred) { // test if all elements satisfy _Pred _STD _Adl_verify_range(_First, _Last); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); - for (; _UFirst != _ULast; ++_UFirst) { - if (!_Pred(*_UFirst)) { - return false; + + if constexpr (_Is_vb_iterator && !is_void_v<_Map_vb_functor_t<_Pr>>) { + return _Meow_of_vbool<_All_of_vbool_traits>(_UFirst, _ULast, _Map_vb_functor_t<_Pr>{}); + } else { + for (; _UFirst != _ULast; ++_UFirst) { + if (!_Pred(*_UFirst)) { + return false; + } } - } - return true; + return true; + } } #if _HAS_CXX17 @@ -1573,13 +1585,18 @@ _NODISCARD _CONSTEXPR20 bool any_of(const _InIt _First, const _InIt _Last, _Pr _ _STD _Adl_verify_range(_First, _Last); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); - for (; _UFirst != _ULast; ++_UFirst) { - if (_Pred(*_UFirst)) { - return true; + + if constexpr (_Is_vb_iterator && !is_void_v<_Map_vb_functor_t<_Pr>>) { + return _Meow_of_vbool<_Any_of_vbool_traits>(_UFirst, _ULast, _Map_vb_functor_t<_Pr>{}); + } else { + for (; _UFirst != _ULast; ++_UFirst) { + if (_Pred(*_UFirst)) { + return true; + } } - } - return false; + return false; + } } #if _HAS_CXX17 @@ -1635,13 +1652,17 @@ _NODISCARD _CONSTEXPR20 bool none_of(const _InIt _First, const _InIt _Last, _Pr _STD _Adl_verify_range(_First, _Last); auto _UFirst = _STD _Get_unwrapped(_First); const auto _ULast = _STD _Get_unwrapped(_Last); - for (; _UFirst != _ULast; ++_UFirst) { - if (_Pred(*_UFirst)) { - return false; + if constexpr (_Is_vb_iterator && !is_void_v<_Map_vb_functor_t<_Pr>>) { + return _Meow_of_vbool<_None_of_vbool_traits>(_UFirst, _ULast, _Map_vb_functor_t<_Pr>{}); + } else { + for (; _UFirst != _ULast; ++_UFirst) { + if (_Pred(*_UFirst)) { + return false; + } } - } - return true; + return true; + } } #if _HAS_CXX17 diff --git a/stl/inc/vector b/stl/inc/vector index dafac7c5933..48df6d2a024 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -4047,6 +4047,91 @@ _CONSTEXPR20 _OutIt _Transform_vbool_aligned( return _Dest; } +struct _All_of_vbool_traits { + static constexpr bool _Default_result = true; + + static _CONSTEXPR20 bool _Check(const _Vbase _Value) { + return _Value != ~_Vbase{0}; + } + + static _CONSTEXPR20 bool _Check(const _Vbase _Value, const _Vbase _Mask) { + return (_Value & _Mask) != _Mask; + } +}; + +struct _Any_of_vbool_traits_base { + static _CONSTEXPR20 bool _Check(const _Vbase _Value) { + return _Value != 0; + } + + static _CONSTEXPR20 bool _Check(const _Vbase _Value, const _Vbase _Mask) { + return (_Value & _Mask) != 0; + } +}; + +struct _Any_of_vbool_traits : _Any_of_vbool_traits_base { + static constexpr bool _Default_result = false; +}; + +struct _None_of_vbool_traits : _Any_of_vbool_traits_base { + static constexpr bool _Default_result = true; +}; + +template +_NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(const _VbIt _First, const _VbIt _Last, const _Mapped_fn _Mapped_func) { + constexpr bool _Early_result = !_Traits::_Default_result; + auto _First_ptr = _First._Myptr; + const auto _Last_ptr = _Last._Myptr; + + if (_First_ptr == _Last_ptr) { + const _Vbase _Mask = (_Vbase{1} << _Last._Myoff) - (_Vbase{1} << _First._Myoff); + if (_Mask == 0) { + return _Traits::_Default_result; + } else { + return _Traits::_Check(_Mapped_func(*_First_ptr), _Mask) ? _Early_result : _Traits::_Default_result; + } + } + + if (_First._Myoff != 0) { + const _Vbase _Mask = static_cast<_Vbase>(-1) << _First._Myoff; + if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { + return _Early_result; + } + + ++_First_ptr; + } + + for (; _First_ptr != _Last_ptr; ++_First_ptr) { + if (_Traits::_Check(_Mapped_func(*_First_ptr))) { + return _Early_result; + } + } + + if (_Last._Myoff != 0) { + const _Vbase _Mask = (_Vbase{1} << _Last._Myoff) - 1; + if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { + return _Early_result; + } + } + + return _Traits::_Default_result; +} + +template +_NODISCARD _CONSTEXPR20 bool _All_of_vbool(const _VbIt _First, const _VbIt _Last, const _Mapped_fn _Mapped_func) { + return _Meow_of_vbool<_All_of_vbool_traits>(_First, _Last, _Mapped_func); +} + +template +_NODISCARD _CONSTEXPR20 bool _Any_of_vbool(const _VbIt _First, const _VbIt _Last, const _Mapped_fn _Mapped_func) { + return _Meow_of_vbool<_Any_of_vbool_traits>(_First, _Last, _Mapped_func); +} + +template +_NODISCARD _CONSTEXPR20 bool _None_of_vbool(const _VbIt _First, const _VbIt _Last, const _Mapped_fn _Mapped_func) { + return _Meow_of_vbool<_None_of_vbool_traits>(_First, _Last, _Mapped_func); +} + #undef _ASAN_VECTOR_MODIFY #undef _ASAN_VECTOR_REMOVE #undef _ASAN_VECTOR_CREATE diff --git a/stl/inc/xutility b/stl/inc/xutility index 935ced63c13..2f81d957989 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -4873,6 +4873,13 @@ struct _Map_vb_functor { using type = void; }; +#if _HAS_CXX20 +template <> +struct _Map_vb_functor { + using type = identity; +}; +#endif // _HAS_CXX20 + template using _Map_vb_functor_t = typename _Map_vb_functor<_Fn>::type; From 2e3e7f46a6b561c633d01933cb98d80900af47a9 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Thu, 30 Oct 2025 08:26:00 +0200 Subject: [PATCH 04/19] fix UB --- .../test.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index 3a6917b3d62..c94c0b6ed19 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -190,7 +190,7 @@ CONSTEXPR20 bool test_transform() { return true; } -CONSTEXPR20 bool test__meow_of_helper(const size_t length_before, const size_t length, const size_t length_after) { +CONSTEXPR20 bool test_meow_of_helper(const size_t length_before, const size_t length, const size_t length_after) { const size_t total_length = length_before + length + length_after; vector zeros(total_length); @@ -268,22 +268,22 @@ CONSTEXPR20 bool test__meow_of_helper(const size_t length_before, const size_t l CONSTEXPR20 bool test_meow_of() { // Empty range - test__meow_of_helper(0, 0, 3); - test__meow_of_helper(3, 0, 3); + test_meow_of_helper(0, 0, 3); + test_meow_of_helper(3, 0, 3); // One block, ends within block - test__meow_of_helper(0, 10, 3); - test__meow_of_helper(3, 10, 3); + test_meow_of_helper(0, 10, 3); + test_meow_of_helper(3, 10, 3); // One block, exactly - test__meow_of_helper(0, blockSize, 0); + test_meow_of_helper(0, blockSize, 0); // Multiple blocks, spanning - test__meow_of_helper(3, blockSize - 2, 3); - test__meow_of_helper(3, blockSize + 2, 3); + test_meow_of_helper(3, blockSize - 2, 3); + test_meow_of_helper(3, blockSize + 2, 3); // Many blocks, exaclty - test__meow_of_helper(blockSize, 4 * blockSize, blockSize); + test_meow_of_helper(blockSize, 4 * blockSize, blockSize); return true; } From 5f3d8527e1e44f0b95e05d7621d6328c99284105 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sun, 2 Nov 2025 20:57:11 +0200 Subject: [PATCH 05/19] unused functions --- stl/inc/vector | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/stl/inc/vector b/stl/inc/vector index 48df6d2a024..48c270d8625 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -4117,21 +4117,6 @@ _NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(const _VbIt _First, const _VbIt _Las return _Traits::_Default_result; } -template -_NODISCARD _CONSTEXPR20 bool _All_of_vbool(const _VbIt _First, const _VbIt _Last, const _Mapped_fn _Mapped_func) { - return _Meow_of_vbool<_All_of_vbool_traits>(_First, _Last, _Mapped_func); -} - -template -_NODISCARD _CONSTEXPR20 bool _Any_of_vbool(const _VbIt _First, const _VbIt _Last, const _Mapped_fn _Mapped_func) { - return _Meow_of_vbool<_Any_of_vbool_traits>(_First, _Last, _Mapped_func); -} - -template -_NODISCARD _CONSTEXPR20 bool _None_of_vbool(const _VbIt _First, const _VbIt _Last, const _Mapped_fn _Mapped_func) { - return _Meow_of_vbool<_None_of_vbool_traits>(_First, _Last, _Mapped_func); -} - #undef _ASAN_VECTOR_MODIFY #undef _ASAN_VECTOR_REMOVE #undef _ASAN_VECTOR_CREATE From f31d22f168247f25c7c9bf788458b6284e33c995 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 21 Jan 2026 09:11:20 +0200 Subject: [PATCH 06/19] signed wraith --- .../test.cpp | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index 2031d14d8d9..268f414d710 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -194,18 +194,19 @@ CONSTEXPR20 bool test_meow_of_helper(const size_t length_before, const size_t le vector zeros(total_length); vector ones(total_length); vector mix(total_length); - fill(zeros.begin(), zeros.begin() + length_before, true); - fill(zeros.end() - length_after, zeros.end(), true); - fill(ones.begin() + length_before, ones.end() - length_after, true); - fill(mix.begin(), mix.begin() + length_before, true); - fill(mix.begin() + length_before + length / 2, mix.end() - length_after, true); - - const auto first_0 = zeros.begin() + length_before; - const auto last_0 = zeros.end() - length_after; - const auto first_1 = ones.cbegin() + length_before; - const auto last_1 = ones.cend() - length_after; - const auto first_m = mix.cbegin() + length_before; - const auto last_m = mix.cend() - length_after; + fill(zeros.begin(), zeros.begin() + static_cast(length_before), true); + fill(zeros.end() - static_cast(length_after), zeros.end(), true); + fill(ones.begin() + static_cast(length_before), ones.end() - static_cast(length_after), true); + fill(mix.begin(), mix.begin() + static_cast(length_before), true); + fill(mix.begin() + static_cast(length_before + length / 2), + mix.end() - static_cast(length_after), true); + + const auto first_0 = zeros.begin() + static_cast(length_before); + const auto last_0 = zeros.end() - static_cast(length_after); + const auto first_1 = ones.cbegin() + static_cast(length_before); + const auto last_1 = ones.cend() - static_cast(length_after); + const auto first_m = mix.cbegin() + static_cast(length_before); + const auto last_m = mix.cend() - static_cast(length_after); if (length == 0) { #if _HAS_CXX20 From 92faadc628ed30ced22906f2eb0f606c83d594b9 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 10:45:34 -0800 Subject: [PATCH 07/19] Style: Avoid conditional operator; an if-statement is more systematic here. --- stl/inc/vector | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/stl/inc/vector b/stl/inc/vector index a177e64b80f..82123700d1d 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -4091,7 +4091,12 @@ _NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(const _VbIt _First, const _VbIt _Las if (_Mask == 0) { return _Traits::_Default_result; } else { - return _Traits::_Check(_Mapped_func(*_First_ptr), _Mask) ? _Early_result : _Traits::_Default_result; + + if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { + return _Early_result; + } else { + return _Traits::_Default_result; + } } } From 0002ffc8d4b121949e558e4cd47b6146e52d3a9c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 10:53:41 -0800 Subject: [PATCH 08/19] Special cases aren't so special. --- stl/inc/vector | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/stl/inc/vector b/stl/inc/vector index 82123700d1d..34b6eadd968 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -4088,21 +4088,16 @@ _NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(const _VbIt _First, const _VbIt _Las if (_First_ptr == _Last_ptr) { const _Vbase _Mask = (_Vbase{1} << _Last._Myoff) - (_Vbase{1} << _First._Myoff); - if (_Mask == 0) { - return _Traits::_Default_result; + if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { // correctly handles `_Mask == 0` + return _Early_result; } else { - - if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { - return _Early_result; - } else { - return _Traits::_Default_result; - } + return _Traits::_Default_result; } } - if (_First._Myoff != 0) { + { const _Vbase _Mask = static_cast<_Vbase>(-1) << _First._Myoff; - if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { + if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { // correctly handles `_First._Myoff == 0` return _Early_result; } From 9de92318241005f607d7a13745635c28de71b2cf Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 10:56:39 -0800 Subject: [PATCH 09/19] Improve style further. --- stl/inc/vector | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/stl/inc/vector b/stl/inc/vector index 34b6eadd968..6ced1810ee5 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -4090,9 +4090,8 @@ _NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(const _VbIt _First, const _VbIt _Las const _Vbase _Mask = (_Vbase{1} << _Last._Myoff) - (_Vbase{1} << _First._Myoff); if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { // correctly handles `_Mask == 0` return _Early_result; - } else { - return _Traits::_Default_result; } + return _Traits::_Default_result; } { From 5b9aca00936865dbf9d1c3e06cce7a25066ebd02 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 11:04:42 -0800 Subject: [PATCH 10/19] Add comments about word handling. --- stl/inc/vector | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stl/inc/vector b/stl/inc/vector index 6ced1810ee5..91dd1372a2f 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -4086,7 +4086,7 @@ _NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(const _VbIt _First, const _VbIt _Las auto _First_ptr = _First._Myptr; const auto _Last_ptr = _Last._Myptr; - if (_First_ptr == _Last_ptr) { + if (_First_ptr == _Last_ptr) { // handle potentially-empty single word const _Vbase _Mask = (_Vbase{1} << _Last._Myoff) - (_Vbase{1} << _First._Myoff); if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { // correctly handles `_Mask == 0` return _Early_result; @@ -4094,7 +4094,7 @@ _NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(const _VbIt _First, const _VbIt _Las return _Traits::_Default_result; } - { + { // handle potentially-full first word const _Vbase _Mask = static_cast<_Vbase>(-1) << _First._Myoff; if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { // correctly handles `_First._Myoff == 0` return _Early_result; @@ -4103,13 +4103,13 @@ _NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(const _VbIt _First, const _VbIt _Las ++_First_ptr; } - for (; _First_ptr != _Last_ptr; ++_First_ptr) { + for (; _First_ptr != _Last_ptr; ++_First_ptr) { // handle full words if (_Traits::_Check(_Mapped_func(*_First_ptr))) { return _Early_result; } } - if (_Last._Myoff != 0) { + if (_Last._Myoff != 0) { // if we have a partial last word, handle it const _Vbase _Mask = (_Vbase{1} << _Last._Myoff) - 1; if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { return _Early_result; From fbafc44eb074af029397d20d572406c16ad0d62b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 11:08:08 -0800 Subject: [PATCH 11/19] Fix typo. --- tests/std/tests/GH_000625_vector_bool_optimization/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index 268f414d710..e4a5a367195 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -281,7 +281,7 @@ CONSTEXPR20 bool test_meow_of() { test_meow_of_helper(3, blockSize - 2, 3); test_meow_of_helper(3, blockSize + 2, 3); - // Many blocks, exaclty + // Many blocks, exactly test_meow_of_helper(blockSize, 4 * blockSize, blockSize); return true; From 5c6ecb1a755056753f045da78684921bf2fa0a2f Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 11:17:18 -0800 Subject: [PATCH 12/19] Move `first_0` etc. up and avoid `cbegin`. --- .../test.cpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index e4a5a367195..32f42f8bfde 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -194,19 +194,19 @@ CONSTEXPR20 bool test_meow_of_helper(const size_t length_before, const size_t le vector zeros(total_length); vector ones(total_length); vector mix(total_length); - fill(zeros.begin(), zeros.begin() + static_cast(length_before), true); - fill(zeros.end() - static_cast(length_after), zeros.end(), true); - fill(ones.begin() + static_cast(length_before), ones.end() - static_cast(length_after), true); - fill(mix.begin(), mix.begin() + static_cast(length_before), true); - fill(mix.begin() + static_cast(length_before + length / 2), - mix.end() - static_cast(length_after), true); const auto first_0 = zeros.begin() + static_cast(length_before); const auto last_0 = zeros.end() - static_cast(length_after); - const auto first_1 = ones.cbegin() + static_cast(length_before); - const auto last_1 = ones.cend() - static_cast(length_after); - const auto first_m = mix.cbegin() + static_cast(length_before); - const auto last_m = mix.cend() - static_cast(length_after); + const auto first_1 = ones.begin() + static_cast(length_before); + const auto last_1 = ones.end() - static_cast(length_after); + const auto first_m = mix.begin() + static_cast(length_before); + const auto last_m = mix.end() - static_cast(length_after); + + fill(zeros.begin(), first_0, true); + fill(last_0, zeros.end(), true); + fill(first_1, last_1, true); + fill(mix.begin(), first_m, true); + fill(mix.begin() + static_cast(length_before + length / 2), last_m, true); if (length == 0) { #if _HAS_CXX20 From 366dfc0fbf187bd1e9543587c5d7027a5c8130eb Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 11:21:53 -0800 Subject: [PATCH 13/19] Further clarify with more use of `first_m`. --- tests/std/tests/GH_000625_vector_bool_optimization/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index 32f42f8bfde..8e6ba590cbd 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -206,7 +206,7 @@ CONSTEXPR20 bool test_meow_of_helper(const size_t length_before, const size_t le fill(last_0, zeros.end(), true); fill(first_1, last_1, true); fill(mix.begin(), first_m, true); - fill(mix.begin() + static_cast(length_before + length / 2), last_m, true); + fill(first_m + static_cast(length / 2), last_m, true); if (length == 0) { #if _HAS_CXX20 From c53ef7700a74f040ef60a8d670afbf21beebcd3b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 11:35:50 -0800 Subject: [PATCH 14/19] Assert that mix is a mix. --- tests/std/tests/GH_000625_vector_bool_optimization/test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index 8e6ba590cbd..f4fe39c7017 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -235,6 +235,8 @@ CONSTEXPR20 bool test_meow_of_helper(const size_t length_before, const size_t le assert(none_of(first_1, last_1, logical_not<>{}) == true); assert(none_of(first_m, last_m, logical_not<>{}) == true); } else { + assert(length != 1); // [first_m, last_m) needs to contain both true and false + #if _HAS_CXX20 assert(all_of(first_0, last_0, identity{}) == false); assert(all_of(first_1, last_1, identity{}) == true); From 525ccd2a27c2ac46b679b209cc8a59012d84d0a9 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 11:41:37 -0800 Subject: [PATCH 15/19] Avoid shadowing `std::size`. --- benchmarks/src/vector_bool_meow_of.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/src/vector_bool_meow_of.cpp b/benchmarks/src/vector_bool_meow_of.cpp index 0e3a9fbcf3a..39d16bfa521 100644 --- a/benchmarks/src/vector_bool_meow_of.cpp +++ b/benchmarks/src/vector_bool_meow_of.cpp @@ -17,8 +17,8 @@ enum class content { ones_then_zeros, zeros_then_ones }; template void meow_of(benchmark::State& state) { - const auto size = static_cast(state.range(0)); - vector> source(size); + const auto n = static_cast(state.range(0)); + vector> source(n); if constexpr (Content == content::ones_then_zeros) { fill(source.begin(), source.begin() + source.size() / 2, true); From d0b66aed1a6632d291379476310da40225af9bc6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 11:45:36 -0800 Subject: [PATCH 16/19] Follow Standard order: all, any, none --- benchmarks/src/vector_bool_meow_of.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/benchmarks/src/vector_bool_meow_of.cpp b/benchmarks/src/vector_bool_meow_of.cpp index 39d16bfa521..dd5c87011a6 100644 --- a/benchmarks/src/vector_bool_meow_of.cpp +++ b/benchmarks/src/vector_bool_meow_of.cpp @@ -12,7 +12,7 @@ using namespace std; -enum class alg { any_, all_, none_ }; +enum class alg { all_, any_, none_ }; enum class content { ones_then_zeros, zeros_then_ones }; template @@ -29,10 +29,10 @@ void meow_of(benchmark::State& state) { for (auto _ : state) { benchmark::DoNotOptimize(source); bool result; - if constexpr (Alg == alg::any_) { - result = any_of(source.begin(), source.end(), Pred{}); - } else if constexpr (Alg == alg::all_) { + if constexpr (Alg == alg::all_) { result = all_of(source.begin(), source.end(), Pred{}); + } else if constexpr (Alg == alg::any_) { + result = any_of(source.begin(), source.end(), Pred{}); } else { result = none_of(source.begin(), source.end(), Pred{}); } @@ -46,9 +46,9 @@ void common_args(benchmark::Benchmark* bm) { using not_ = logical_not<>; +BENCHMARK(meow_of)->Apply(common_args); BENCHMARK(meow_of)->Apply(common_args); BENCHMARK(meow_of)->Apply(common_args); -BENCHMARK(meow_of)->Apply(common_args); BENCHMARK(meow_of)->Apply(common_args); BENCHMARK_MAIN(); From 986bbecda23303f76b37ee5bd298dececbb1e3cd Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 12:01:07 -0800 Subject: [PATCH 17/19] Undo my cleverness for first words. --- stl/inc/vector | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stl/inc/vector b/stl/inc/vector index 91dd1372a2f..ee0f54a1a40 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -4094,9 +4094,9 @@ _NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(const _VbIt _First, const _VbIt _Las return _Traits::_Default_result; } - { // handle potentially-full first word + if (_First._Myoff != 0) { // if we have a partial first word, handle it const _Vbase _Mask = static_cast<_Vbase>(-1) << _First._Myoff; - if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { // correctly handles `_First._Myoff == 0` + if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { return _Early_result; } From 37648a24e77ca68cfc799a090e978cef16fec730 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 12:20:33 -0800 Subject: [PATCH 18/19] I was bad. Don't read empty words. --- stl/inc/vector | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/stl/inc/vector b/stl/inc/vector index ee0f54a1a40..67c40f8e6c8 100644 --- a/stl/inc/vector +++ b/stl/inc/vector @@ -4086,9 +4086,13 @@ _NODISCARD _CONSTEXPR20 bool _Meow_of_vbool(const _VbIt _First, const _VbIt _Las auto _First_ptr = _First._Myptr; const auto _Last_ptr = _Last._Myptr; - if (_First_ptr == _Last_ptr) { // handle potentially-empty single word - const _Vbase _Mask = (_Vbase{1} << _Last._Myoff) - (_Vbase{1} << _First._Myoff); - if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { // correctly handles `_Mask == 0` + if (_First_ptr == _Last_ptr) { + if (_First._Myoff == _Last._Myoff) { // empty, can't read the word + return _Traits::_Default_result; + } + + const _Vbase _Mask = (_Vbase{1} << _Last._Myoff) - (_Vbase{1} << _First._Myoff); // handle partial single word + if (_Traits::_Check(_Mapped_func(*_First_ptr), _Mask)) { return _Early_result; } return _Traits::_Default_result; From 3ed3838fafb17e146a07cb27ab717eb6d37f4c57 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Fri, 6 Feb 2026 12:31:20 -0800 Subject: [PATCH 19/19] Test super empty ranges. --- .../GH_000625_vector_bool_optimization/test.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp index f4fe39c7017..3d3ca8a113b 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -268,6 +268,20 @@ CONSTEXPR20 bool test_meow_of_helper(const size_t length_before, const size_t le } CONSTEXPR20 bool test_meow_of() { + { // Super empty range + const vector::const_iterator it{}; // value-initialized, compares equal to itself + +#if _HAS_CXX20 + assert(all_of(it, it, identity{}) == true); + assert(any_of(it, it, identity{}) == false); + assert(none_of(it, it, identity{}) == true); +#endif // _HAS_CXX20 + + assert(all_of(it, it, logical_not<>{}) == true); + assert(any_of(it, it, logical_not<>{}) == false); + assert(none_of(it, it, logical_not<>{}) == true); + } + // Empty range test_meow_of_helper(0, 0, 3); test_meow_of_helper(3, 0, 3);