From d9e1912278db8d27959789199e46587b5c746f6c Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 22 Oct 2025 17:53:55 +0300 Subject: [PATCH 1/5] concise void --- stl/inc/algorithm | 4 ++-- stl/inc/functional | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index cb5511d5742..4a4f07d0c23 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -4118,7 +4118,7 @@ _CONSTEXPR20 _OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Des const auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_n(_Dest, _STD _Idl_distance<_InIt>(_UFirst, _ULast)); - if constexpr (_Is_vb_iterator<_InIt> && _Is_vb_iterator<_OutIt, true> && !is_same_v<_Map_vb_functor_t<_Fn>, void>) { + if constexpr (_Is_vb_iterator<_InIt> && _Is_vb_iterator<_OutIt, true> && !is_void_v<_Map_vb_functor_t<_Fn>>) { if (_UFirst._Myoff == 0 && _UDest._Myoff == 0) { _UDest = _Transform_vbool_aligned(_UFirst, _ULast, _UDest, _Map_vb_functor_t<_Fn>{}); _STD _Seek_wrapped(_Dest, _UDest); @@ -4151,7 +4151,7 @@ _CONSTEXPR20 _OutIt transform( auto _UDest = _STD _Get_unwrapped_n(_Dest, _Count); if constexpr (_Is_vb_iterator<_InIt1> && _Is_vb_iterator<_InIt2> && _Is_vb_iterator<_OutIt, true> - && !is_same_v<_Map_vb_functor_t<_Fn>, void>) { + && !is_void_v<_Map_vb_functor_t<_Fn>>) { if (_UFirst1._Myoff == 0 && _UFirst2._Myoff == 0 && _UDest._Myoff == 0) { _UDest = _Transform_vbool_aligned(_UFirst1, _ULast1, _UFirst2, _UDest, _Map_vb_functor_t<_Fn>{}); _STD _Seek_wrapped(_Dest, _UDest); diff --git a/stl/inc/functional b/stl/inc/functional index 48feddd89c4..99b1542d831 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -269,7 +269,7 @@ struct _Bit_xnor { }; template -constexpr bool _Is_vbool_functor_arg = is_same_v<_Ty, void> || is_integral_v<_Ty>; +constexpr bool _Is_vbool_functor_arg = is_void_v<_Ty> || is_integral_v<_Ty>; template struct _Map_vb_functor> { From cc0f528d5dc0cfa943d30b0951649f3d9e709685 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 22 Oct 2025 17:54:18 +0300 Subject: [PATCH 2/5] benchmark --- benchmarks/src/vector_bool_transform.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/benchmarks/src/vector_bool_transform.cpp b/benchmarks/src/vector_bool_transform.cpp index 4f54882c18c..585db6ead47 100644 --- a/benchmarks/src/vector_bool_transform.cpp +++ b/benchmarks/src/vector_bool_transform.cpp @@ -48,6 +48,7 @@ void common_args(auto bm) { BENCHMARK(transform_two_inputs_aligned>)->Apply(common_args); BENCHMARK(transform_two_inputs_aligned>)->Apply(common_args); +BENCHMARK(transform_two_inputs_aligned>)->Apply(common_args); BENCHMARK(transform_one_input_aligned>)->Apply(common_args); BENCHMARK_MAIN(); From b325d6f043cff02c982f2006ab56902052a56092 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 22 Oct 2025 18:00:41 +0300 Subject: [PATCH 3/5] optimization --- stl/inc/functional | 60 +++++++++++++++++++ .../test.cpp | 45 ++++++++++++++ 2 files changed, 105 insertions(+) diff --git a/stl/inc/functional b/stl/inc/functional index 99b1542d831..6530b97c91a 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -268,6 +268,46 @@ struct _Bit_xnor { using is_transparent = int; }; +struct _Bit_imply { + template + _NODISCARD constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const // + -> decltype(~_STD forward<_Ty1>(_Left) | _STD forward<_Ty2>(_Right)) { + return ~_STD forward<_Ty1>(_Left) | _STD forward<_Ty2>(_Right); + } + + using is_transparent = int; +}; + +struct _Bit_cimply { + template + _NODISCARD constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const // + -> decltype(_STD forward<_Ty1>(_Left) | ~_STD forward<_Ty2>(_Right)) { + return _STD forward<_Ty1>(_Left) | ~_STD forward<_Ty2>(_Right); + } + + using is_transparent = int; +}; + +struct _Bit_nimply { + template + _NODISCARD constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const // + -> decltype(_STD forward<_Ty1>(_Left) & ~_STD forward<_Ty2>(_Right)) { + return _STD forward<_Ty1>(_Left) & ~_STD forward<_Ty2>(_Right); + } + + using is_transparent = int; +}; + +struct _Bit_cnimply { + template + _NODISCARD constexpr auto operator()(_Ty1&& _Left, _Ty2&& _Right) const // + -> decltype(~_STD forward<_Ty1>(_Left) & _STD forward<_Ty2>(_Right)) { + return ~_STD forward<_Ty1>(_Left) & _STD forward<_Ty2>(_Right); + } + + using is_transparent = int; +}; + template constexpr bool _Is_vbool_functor_arg = is_void_v<_Ty> || is_integral_v<_Ty>; @@ -306,6 +346,26 @@ struct _Map_vb_functor> { using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_xnor, void>; }; +template +struct _Map_vb_functor> { + using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_imply, void>; +}; + +template +struct _Map_vb_functor> { + using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_cimply, void>; +}; + +template +struct _Map_vb_functor> { + using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_cnimply, void>; +}; + +template +struct _Map_vb_functor> { + using type = conditional_t<_Is_vbool_functor_arg<_Ty>, _Bit_nimply, void>; +}; + template struct _Map_vb_functor> { using type = conditional_t<_Is_vbool_functor_arg<_Ty>, bit_not<>, void>; 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..6e14badc9d5 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -76,12 +76,20 @@ CONSTEXPR20 void test_transform_helper(const size_t length) { bool or_expected_raw[size(source_raw)]; bool xor_expected_raw[size(source_raw)]; bool xnor_expected_raw[size(source_raw)]; + bool l_expected_raw[size(source_raw)]; + bool le_expected_raw[size(source_raw)]; + bool g_expected_raw[size(source_raw)]; + bool ge_expected_raw[size(source_raw)]; bool not_expected_raw[size(source_raw)]; transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(and_expected_raw), logical_and<>{}); transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(or_expected_raw), logical_or<>{}); transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(xor_expected_raw), not_equal_to<>{}); transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(xnor_expected_raw), equal_to<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(l_expected_raw), less<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(le_expected_raw), less_equal<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(g_expected_raw), greater<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(ge_expected_raw), greater_equal<>{}); transform(begin(source_raw), end(source_raw), begin(not_expected_raw), logical_not<>{}); const vector source1(source_raw, source_raw + length); @@ -91,18 +99,30 @@ CONSTEXPR20 void test_transform_helper(const size_t length) { vector or_expected(or_expected_raw, or_expected_raw + length); vector xor_expected(xor_expected_raw, xor_expected_raw + length); vector xnor_expected(xnor_expected_raw, xnor_expected_raw + length); + vector less_expected(l_expected_raw, l_expected_raw + length); + vector less_equal_expected(le_expected_raw, le_expected_raw + length); + vector greater_expected(g_expected_raw, g_expected_raw + length); + vector greater_equal_expected(ge_expected_raw, ge_expected_raw + length); vector not_expected(not_expected_raw, not_expected_raw + length); and_expected.resize(length + 3, false); or_expected.resize(length + 3, false); xor_expected.resize(length + 3, false); xnor_expected.resize(length + 3, false); + less_expected.resize(length + 3, false); + less_equal_expected.resize(length + 3, false); + greater_expected.resize(length + 3, false); + greater_equal_expected.resize(length + 3, false); not_expected.resize(length + 3, false); vector and_actual(length + 3); vector or_actual(length + 3); vector xor_actual(length + 3); vector xnor_actual(length + 3); + vector less_actual(length + 3); + vector less_equal_actual(length + 3); + vector greater_actual(length + 3); + vector greater_equal_actual(length + 3); vector not_actual(length + 3); // Also test combinations of vector::iterator and vector::const_iterator for the inputs. @@ -157,6 +177,31 @@ CONSTEXPR20 void test_transform_helper(const size_t length) { // bit_xnor doesn't exist in the Standard } + { + const auto less_ret = transform(cfirst1, clast1, cfirst2, less_actual.begin(), less<>{}); + assert(less_actual == less_expected); + assert(less_ret == less_actual.begin() + length); + } + + { + const auto less_equal_ret = transform(cfirst1, clast1, cfirst2, less_equal_actual.begin(), less_equal<>{}); + assert(less_equal_actual == less_equal_expected); + assert(less_equal_ret == less_equal_actual.begin() + length); + } + + { + const auto greater_ret = transform(cfirst1, clast1, cfirst2, greater_actual.begin(), greater<>{}); + assert(greater_actual == greater_expected); + assert(greater_ret == greater_actual.begin() + length); + } + + { + const auto greater_equal_ret = + transform(cfirst1, clast1, cfirst2, greater_equal_actual.begin(), greater_equal<>{}); + assert(greater_equal_actual == greater_equal_expected); + assert(greater_equal_ret == greater_equal_actual.begin() + length); + } + { auto not_ret = transform(first1, last1, not_actual.begin(), logical_not<>{}); assert(not_actual == not_expected); From 69b17bb57d1dae003e090c33764cf7178fc672c0 Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Sat, 25 Oct 2025 09:18:15 +0300 Subject: [PATCH 4/5] Consistently check unwrapped iterators Should not matter in practice I think, but for consistency --- stl/inc/algorithm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 4a4f07d0c23..3d32a2704c4 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -4118,7 +4118,8 @@ _CONSTEXPR20 _OutIt transform(const _InIt _First, const _InIt _Last, _OutIt _Des const auto _ULast = _STD _Get_unwrapped(_Last); auto _UDest = _STD _Get_unwrapped_n(_Dest, _STD _Idl_distance<_InIt>(_UFirst, _ULast)); - if constexpr (_Is_vb_iterator<_InIt> && _Is_vb_iterator<_OutIt, true> && !is_void_v<_Map_vb_functor_t<_Fn>>) { + if constexpr (_Is_vb_iterator && _Is_vb_iterator + && !is_void_v<_Map_vb_functor_t<_Fn>>) { if (_UFirst._Myoff == 0 && _UDest._Myoff == 0) { _UDest = _Transform_vbool_aligned(_UFirst, _ULast, _UDest, _Map_vb_functor_t<_Fn>{}); _STD _Seek_wrapped(_Dest, _UDest); @@ -4150,8 +4151,8 @@ _CONSTEXPR20 _OutIt transform( auto _UFirst2 = _STD _Get_unwrapped_n(_First2, _Count); auto _UDest = _STD _Get_unwrapped_n(_Dest, _Count); - if constexpr (_Is_vb_iterator<_InIt1> && _Is_vb_iterator<_InIt2> && _Is_vb_iterator<_OutIt, true> - && !is_void_v<_Map_vb_functor_t<_Fn>>) { + if constexpr (_Is_vb_iterator && _Is_vb_iterator + && _Is_vb_iterator && !is_void_v<_Map_vb_functor_t<_Fn>>) { if (_UFirst1._Myoff == 0 && _UFirst2._Myoff == 0 && _UDest._Myoff == 0) { _UDest = _Transform_vbool_aligned(_UFirst1, _ULast1, _UFirst2, _UDest, _Map_vb_functor_t<_Fn>{}); _STD _Seek_wrapped(_Dest, _UDest); From 83f0be45b5d21af74d792b35ecbae0d52ba3a4cb Mon Sep 17 00:00:00 2001 From: Alex Guteniev Date: Wed, 21 Jan 2026 08:41:58 +0200 Subject: [PATCH 5/5] Fix formatting --- .../test.cpp | 3218 ++++++++--------- 1 file changed, 1609 insertions(+), 1609 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 e3e948c22ae..706a3015552 100644 --- a/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp +++ b/tests/std/tests/GH_000625_vector_bool_optimization/test.cpp @@ -1,1613 +1,1613 @@ -// Copyright (c) Microsoft Corporation. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if _HAS_CXX20 -#define CONSTEXPR20 constexpr -#else -#define CONSTEXPR20 inline -#endif - -using namespace std; - -constexpr int blockSize = 32; -static_assert(blockSize == _VBITS, "Invalid block size"); - -// This test data is not random, but irregular enough to ensure confidence in the tests -constexpr bool source_raw[] = { // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false}; - -CONSTEXPR20 void test_transform_helper(const size_t length) { - // Only no offset case - - // This test data is not random, but irregular enough to ensure confidence in the tests - constexpr bool source2_raw[] = {// - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true, // - true, true, false, false, false, false, true, true}; - -#if _HAS_CXX17 - static_assert(size(source_raw) == size(source2_raw)); -#endif // _HAS_CXX17 - - bool and_expected_raw[size(source_raw)]; - bool or_expected_raw[size(source_raw)]; - bool xor_expected_raw[size(source_raw)]; - bool xnor_expected_raw[size(source_raw)]; - bool l_expected_raw[size(source_raw)]; - bool le_expected_raw[size(source_raw)]; - bool g_expected_raw[size(source_raw)]; - bool ge_expected_raw[size(source_raw)]; - bool not_expected_raw[size(source_raw)]; - - transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(and_expected_raw), logical_and<>{}); - transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(or_expected_raw), logical_or<>{}); - transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(xor_expected_raw), not_equal_to<>{}); - transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(xnor_expected_raw), equal_to<>{}); - transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(l_expected_raw), less<>{}); - transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(le_expected_raw), less_equal<>{}); - transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(g_expected_raw), greater<>{}); - transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(ge_expected_raw), greater_equal<>{}); - transform(begin(source_raw), end(source_raw), begin(not_expected_raw), logical_not<>{}); - - const vector source1(source_raw, source_raw + static_cast(length)); - const vector source2(source2_raw, source2_raw + static_cast(length)); - - vector and_expected(and_expected_raw, and_expected_raw + static_cast(length)); - vector or_expected(or_expected_raw, or_expected_raw + static_cast(length)); - vector xor_expected(xor_expected_raw, xor_expected_raw + static_cast(length)); - vector xnor_expected(xnor_expected_raw, xnor_expected_raw + static_cast(length)); - vector less_expected(l_expected_raw, l_expected_raw + static_cast(length)); - vector less_equal_expected(le_expected_raw, le_expected_raw + static_cast(length)); - vector greater_expected(g_expected_raw, g_expected_raw + static_cast(length)); - vector greater_equal_expected(ge_expected_raw, ge_expected_raw + static_cast(length)); - vector not_expected(not_expected_raw, not_expected_raw + static_cast(length)); - - and_expected.resize(length + 3, false); - or_expected.resize(length + 3, false); - xor_expected.resize(length + 3, false); - xnor_expected.resize(length + 3, false); - less_expected.resize(length + 3, false); - less_equal_expected.resize(length + 3, false); - greater_expected.resize(length + 3, false); - greater_equal_expected.resize(length + 3, false); - not_expected.resize(length + 3, false); - - vector and_actual(length + 3); - vector or_actual(length + 3); - vector xor_actual(length + 3); - vector xnor_actual(length + 3); - vector less_actual(length + 3); - vector less_equal_actual(length + 3); - vector greater_actual(length + 3); - vector greater_equal_actual(length + 3); - vector not_actual(length + 3); - - // Also test combinations of vector::iterator and vector::const_iterator for the inputs. - const auto first1 = source1.begin(); - const auto cfirst1 = source1.cbegin(); - const auto first2 = source2.begin(); - const auto cfirst2 = source2.cbegin(); - const auto last1 = first1 + static_cast(length); - const auto clast1 = cfirst1 + static_cast(length); - - { - auto and_ret = transform(first1, last1, first2, and_actual.begin(), logical_and<>{}); - assert(and_actual == and_expected); - assert(and_ret == and_actual.begin() + static_cast(length)); - - and_actual.assign(and_actual.size(), false); - - and_ret = transform(first1, last1, first2, and_actual.begin(), bit_and<>{}); - assert(and_actual == and_expected); - assert(and_ret == and_actual.begin() + static_cast(length)); - } - - { - auto or_ret = transform(first1, last1, cfirst2, or_actual.begin(), logical_or<>{}); - assert(or_actual == or_expected); - assert(or_ret == or_actual.begin() + static_cast(length)); - - or_actual.assign(or_actual.size(), false); - - or_ret = transform(first1, last1, cfirst2, or_actual.begin(), bit_or<>{}); - assert(or_actual == or_expected); - assert(or_ret == or_actual.begin() + static_cast(length)); - } - - { - auto xor_ret = transform(cfirst1, clast1, first2, xor_actual.begin(), not_equal_to<>{}); - assert(xor_actual == xor_expected); - assert(xor_ret == xor_actual.begin() + static_cast(length)); - - xor_actual.assign(xor_actual.size(), false); - - xor_ret = transform(cfirst1, clast1, first2, xor_actual.begin(), bit_xor<>{}); - assert(xor_actual == xor_expected); - assert(xor_ret == xor_actual.begin() + static_cast(length)); - } - - { - const auto xnor_ret = transform(cfirst1, clast1, cfirst2, xnor_actual.begin(), equal_to<>{}); - assert(xnor_actual == xnor_expected); - assert(xnor_ret == xnor_actual.begin() + static_cast(length)); - - // bit_xnor doesn't exist in the Standard - } - - { - const auto less_ret = transform(cfirst1, clast1, cfirst2, less_actual.begin(), less<>{}); +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if _HAS_CXX20 +#define CONSTEXPR20 constexpr +#else +#define CONSTEXPR20 inline +#endif + +using namespace std; + +constexpr int blockSize = 32; +static_assert(blockSize == _VBITS, "Invalid block size"); + +// This test data is not random, but irregular enough to ensure confidence in the tests +constexpr bool source_raw[] = { // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false}; + +CONSTEXPR20 void test_transform_helper(const size_t length) { + // Only no offset case + + // This test data is not random, but irregular enough to ensure confidence in the tests + constexpr bool source2_raw[] = {// + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true, // + true, true, false, false, false, false, true, true}; + +#if _HAS_CXX17 + static_assert(size(source_raw) == size(source2_raw)); +#endif // _HAS_CXX17 + + bool and_expected_raw[size(source_raw)]; + bool or_expected_raw[size(source_raw)]; + bool xor_expected_raw[size(source_raw)]; + bool xnor_expected_raw[size(source_raw)]; + bool l_expected_raw[size(source_raw)]; + bool le_expected_raw[size(source_raw)]; + bool g_expected_raw[size(source_raw)]; + bool ge_expected_raw[size(source_raw)]; + bool not_expected_raw[size(source_raw)]; + + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(and_expected_raw), logical_and<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(or_expected_raw), logical_or<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(xor_expected_raw), not_equal_to<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(xnor_expected_raw), equal_to<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(l_expected_raw), less<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(le_expected_raw), less_equal<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(g_expected_raw), greater<>{}); + transform(begin(source_raw), end(source_raw), begin(source2_raw), begin(ge_expected_raw), greater_equal<>{}); + transform(begin(source_raw), end(source_raw), begin(not_expected_raw), logical_not<>{}); + + const vector source1(source_raw, source_raw + static_cast(length)); + const vector source2(source2_raw, source2_raw + static_cast(length)); + + vector and_expected(and_expected_raw, and_expected_raw + static_cast(length)); + vector or_expected(or_expected_raw, or_expected_raw + static_cast(length)); + vector xor_expected(xor_expected_raw, xor_expected_raw + static_cast(length)); + vector xnor_expected(xnor_expected_raw, xnor_expected_raw + static_cast(length)); + vector less_expected(l_expected_raw, l_expected_raw + static_cast(length)); + vector less_equal_expected(le_expected_raw, le_expected_raw + static_cast(length)); + vector greater_expected(g_expected_raw, g_expected_raw + static_cast(length)); + vector greater_equal_expected(ge_expected_raw, ge_expected_raw + static_cast(length)); + vector not_expected(not_expected_raw, not_expected_raw + static_cast(length)); + + and_expected.resize(length + 3, false); + or_expected.resize(length + 3, false); + xor_expected.resize(length + 3, false); + xnor_expected.resize(length + 3, false); + less_expected.resize(length + 3, false); + less_equal_expected.resize(length + 3, false); + greater_expected.resize(length + 3, false); + greater_equal_expected.resize(length + 3, false); + not_expected.resize(length + 3, false); + + vector and_actual(length + 3); + vector or_actual(length + 3); + vector xor_actual(length + 3); + vector xnor_actual(length + 3); + vector less_actual(length + 3); + vector less_equal_actual(length + 3); + vector greater_actual(length + 3); + vector greater_equal_actual(length + 3); + vector not_actual(length + 3); + + // Also test combinations of vector::iterator and vector::const_iterator for the inputs. + const auto first1 = source1.begin(); + const auto cfirst1 = source1.cbegin(); + const auto first2 = source2.begin(); + const auto cfirst2 = source2.cbegin(); + const auto last1 = first1 + static_cast(length); + const auto clast1 = cfirst1 + static_cast(length); + + { + auto and_ret = transform(first1, last1, first2, and_actual.begin(), logical_and<>{}); + assert(and_actual == and_expected); + assert(and_ret == and_actual.begin() + static_cast(length)); + + and_actual.assign(and_actual.size(), false); + + and_ret = transform(first1, last1, first2, and_actual.begin(), bit_and<>{}); + assert(and_actual == and_expected); + assert(and_ret == and_actual.begin() + static_cast(length)); + } + + { + auto or_ret = transform(first1, last1, cfirst2, or_actual.begin(), logical_or<>{}); + assert(or_actual == or_expected); + assert(or_ret == or_actual.begin() + static_cast(length)); + + or_actual.assign(or_actual.size(), false); + + or_ret = transform(first1, last1, cfirst2, or_actual.begin(), bit_or<>{}); + assert(or_actual == or_expected); + assert(or_ret == or_actual.begin() + static_cast(length)); + } + + { + auto xor_ret = transform(cfirst1, clast1, first2, xor_actual.begin(), not_equal_to<>{}); + assert(xor_actual == xor_expected); + assert(xor_ret == xor_actual.begin() + static_cast(length)); + + xor_actual.assign(xor_actual.size(), false); + + xor_ret = transform(cfirst1, clast1, first2, xor_actual.begin(), bit_xor<>{}); + assert(xor_actual == xor_expected); + assert(xor_ret == xor_actual.begin() + static_cast(length)); + } + + { + const auto xnor_ret = transform(cfirst1, clast1, cfirst2, xnor_actual.begin(), equal_to<>{}); + assert(xnor_actual == xnor_expected); + assert(xnor_ret == xnor_actual.begin() + static_cast(length)); + + // bit_xnor doesn't exist in the Standard + } + + { + const auto less_ret = transform(cfirst1, clast1, cfirst2, less_actual.begin(), less<>{}); assert(less_actual == less_expected); - assert(less_ret == less_actual.begin() + static_cast(length)); - } - - { - const auto less_equal_ret = transform(cfirst1, clast1, cfirst2, less_equal_actual.begin(), less_equal<>{}); + assert(less_ret == less_actual.begin() + static_cast(length)); + } + + { + const auto less_equal_ret = transform(cfirst1, clast1, cfirst2, less_equal_actual.begin(), less_equal<>{}); assert(less_equal_actual == less_equal_expected); - assert(less_equal_ret == less_equal_actual.begin() + static_cast(length)); - } - - { - const auto greater_ret = transform(cfirst1, clast1, cfirst2, greater_actual.begin(), greater<>{}); + assert(less_equal_ret == less_equal_actual.begin() + static_cast(length)); + } + + { + const auto greater_ret = transform(cfirst1, clast1, cfirst2, greater_actual.begin(), greater<>{}); assert(greater_actual == greater_expected); - assert(greater_ret == greater_actual.begin() + static_cast(length)); - } - - { - const auto greater_equal_ret = - transform(cfirst1, clast1, cfirst2, greater_equal_actual.begin(), greater_equal<>{}); + assert(greater_ret == greater_actual.begin() + static_cast(length)); + } + + { + const auto greater_equal_ret = + transform(cfirst1, clast1, cfirst2, greater_equal_actual.begin(), greater_equal<>{}); assert(greater_equal_actual == greater_equal_expected); - assert(greater_equal_ret == greater_equal_actual.begin() + static_cast(length)); - } - - { - auto not_ret = transform(first1, last1, not_actual.begin(), logical_not<>{}); - assert(not_actual == not_expected); - assert(not_ret == not_actual.begin() + static_cast(length)); - - not_actual.assign(not_actual.size(), false); - - // bit_not emits MSVC and Clang warnings, so it isn't optimized. - // Continue using logical_not to test vector::const_iterator: - not_ret = transform(cfirst1, clast1, not_actual.begin(), logical_not<>{}); - assert(not_actual == not_expected); - assert(not_ret == not_actual.begin() + static_cast(length)); - } -} - -CONSTEXPR20 bool test_transform() { - // Empty range - test_transform_helper(0); - - // One block, ends within block - test_transform_helper(15); - - // One block, ends at block boundary - test_transform_helper(blockSize); - - // Multiple blocks, within block - test_transform_helper(3 * blockSize + 5); - - // Multiple blocks, ends at block boundary - test_transform_helper(4 * blockSize); - return true; -} - -CONSTEXPR20 void test_fill_helper(const size_t length) { - // No offset - { - vector result_true(length, true); - result_true.resize(length + 3, false); - vector dest_true(length + 3, false); - fill(dest_true.begin(), prev(dest_true.end(), 3), true); - assert(dest_true == result_true); - - vector result_false(length, false); - result_false.resize(length + 3, true); - vector dest_false(length + 3, true); - fill(dest_false.begin(), prev(dest_false.end(), 3), false); - assert(dest_false == result_false); - - vector result_true_n(length, true); - result_true_n.resize(length + 3, false); - vector dest_true_n(length + 3, false); - const auto res_fill_n = fill_n(dest_true_n.begin(), length, true); - assert(dest_true_n == result_true_n); - assert(res_fill_n == prev(dest_true_n.end(), 3)); - - vector result_false_n(length, false); - result_false_n.resize(length + 3, true); - vector dest_false_n(length + 3, true); - fill_n(dest_false_n.begin(), length, false); - assert(dest_false_n == result_false_n); - } - - // With offset - { - vector result_true(length, true); - result_true.resize(length + 3, false); - result_true.insert(result_true.begin(), false); - vector dest_true(length + 4, false); - fill(next(dest_true.begin()), prev(dest_true.end(), 3), true); - assert(dest_true == result_true); - - vector result_false(length, false); - result_false.resize(length + 3, true); - result_false.insert(result_false.begin(), true); - vector dest_false(length + 4, true); - fill(next(dest_false.begin()), prev(dest_false.end(), 3), false); - assert(dest_false == result_false); - - vector result_true_n(length, true); - result_true_n.resize(length + 3, false); - result_true_n.insert(result_true_n.begin(), false); - vector dest_true_n(length + 4, false); - const auto res_fill_n = fill_n(next(dest_true_n.begin()), length, true); - assert(dest_true_n == result_true_n); - assert(res_fill_n == prev(dest_true_n.end(), 3)); - - vector result_false_n(length, false); - result_false_n.resize(length + 3, true); - result_false_n.insert(result_false_n.begin(), true); - vector dest_false_n(length + 4, true); - fill_n(next(dest_false_n.begin()), length, false); - assert(dest_false_n == result_false_n); - } -} - -CONSTEXPR20 bool test_fill() { - // Empty - test_fill_helper(0); - - // One block, ends within block - test_fill_helper(15); - - // One block, ends at block boundary - test_fill_helper(blockSize); - - // Multiple blocks, no memset, within block - test_fill_helper(blockSize + 11); - - // Multiple blocks, no memset, ends at block boundary - test_fill_helper(2 * blockSize); - - // Multiple blocks, with memset, within block - test_fill_helper(3 * blockSize + 5); - - // Multiple blocks, with memset, ends at block boundary - test_fill_helper(4 * blockSize); - return true; -} - -CONSTEXPR20 void test_find_helper(const size_t length) { - // No offset - { - vector input_true(length + 3, false); - input_true.resize(length + 6, true); - input_true[length + 1].flip(); - const auto result_true = find(input_true.cbegin(), prev(input_true.cend(), 3), true); - assert(result_true == next(input_true.cbegin(), static_cast(length + 1))); - - vector input_false(length + 3, true); - input_false.resize(length + 6, false); - input_false[length + 1].flip(); - const auto result_false = find(input_false.cbegin(), prev(input_false.cend(), 3), false); - assert(result_false == next(input_false.cbegin(), static_cast(length + 1))); - } - - // With offset - { - vector input_true(length + 3, false); - input_true.resize(length + 6, true); - input_true[length + 1].flip(); - input_true[0].flip(); - const auto result_true = find(next(input_true.cbegin()), prev(input_true.cend(), 3), true); - assert(result_true == next(input_true.cbegin(), static_cast(length + 1))); - - vector input_false(length + 3, true); - input_false.resize(length + 6, false); - input_false[length + 1].flip(); - input_false[0].flip(); - const auto result_false = find(next(input_false.cbegin()), prev(input_false.cend(), 3), false); - assert(result_false == next(input_false.cbegin(), static_cast(length + 1))); - } -} - -CONSTEXPR20 bool test_find() { - // Empty range - test_find_helper(0); - - // One block, ends within block - test_find_helper(15); - - // One block, ends at block boundary - test_find_helper(blockSize); - - // Multiple blocks, within block - test_find_helper(3 * blockSize + 5); - - // Multiple blocks, ends at block boundary - test_find_helper(4 * blockSize); - return true; -} - -CONSTEXPR20 void test_count_helper(const ptrdiff_t length) { - const vector source(begin(source_raw), end(source_raw)); - const int counts_true[] = {0, 1, 1, 2, 2, 3, 4, 5}; - const int counts_false[] = {0, 0, 1, 1, 2, 2, 2, 2}; - const div_t expected = {static_cast(length) / 8, static_cast(length) % 8}; - // No offset - { - const auto result_true = static_cast(count(source.cbegin(), next(source.cbegin(), length), true)); - assert(result_true == expected.quot * 5 + counts_true[expected.rem]); - - const auto result_false = static_cast(count(source.cbegin(), next(source.cbegin(), length), false)); - assert(result_false == expected.quot * 3 + counts_false[expected.rem]); - } - - // With offset - { - const auto result_true = - static_cast(count(next(source.cbegin(), 2), next(source.cbegin(), length + 2), true)); - assert(result_true == expected.quot * 5 + counts_true[expected.rem]); - - const auto result_false = - static_cast(count(next(source.cbegin(), 2), next(source.cbegin(), length + 2), false)); - assert(result_false == expected.quot * 3 + counts_false[expected.rem]); - } -} - -CONSTEXPR20 bool test_count() { - // Empty range - test_count_helper(0); - - // One block, ends within block - test_count_helper(15); - - // One block, ends at block boundary - test_count_helper(blockSize); - - // Multiple blocks, within block - test_count_helper(3 * blockSize + 8); - - // Multiple blocks, ends at block boundary - test_count_helper(4 * blockSize); - return true; -} - -// Also test the behavior of a huge vector whose size is greater than SIZE_MAX, -// which is practical on 32-bit platforms. -template -struct huge_allocator { - huge_allocator() = default; - template - constexpr huge_allocator(const huge_allocator&) noexcept {} - - using value_type = T; - using size_type = uint64_t; - using difference_type = int64_t; - - T* allocate(uint64_t n) { - return allocator{}.allocate(static_cast(n)); - } - - void deallocate(T* p, uint64_t n) { - allocator{}.deallocate(p, static_cast(n)); - } -}; - -void test_huge_vector_bool() { - constexpr uint64_t small_bit_length = 0x7000'4321ULL; - constexpr uint64_t large_bit_length = 0x1'2000'4321ULL; // overflows uint32_t - constexpr auto large_bit_diff = static_cast(large_bit_length); - - vector> v(small_bit_length); - v.resize(large_bit_length); - assert(v.end() - v.begin() == large_bit_diff); - - v.back() = true; - assert(find(v.begin(), v.end(), true) - v.begin() == large_bit_diff - 1); - - v[small_bit_length] = true; - v[large_bit_length - small_bit_length] = true; - assert(count(v.begin(), v.end(), false) == large_bit_diff - 3); -} - -CONSTEXPR20 void test_copy_no_offset(const size_t length) { - vector result; - switch (length) { - case 3: - result = {true, false, true}; - break; - case 8: - result = {true, false, true, false, true, true, true, false}; - break; - case 22: - result = {// - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true}; - break; - case 31: - result = {// - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true}; - break; - case 32: - result = {// - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false}; - break; - case 67: - result = {// - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true}; - break; - default: - assert(false); - } - - const vector source(begin(source_raw), end(source_raw)); - - { - vector dest(length, false); - const auto res_copy = copy(source.begin(), source.begin() + static_cast(length), dest.begin()); - assert(dest == result); - assert(res_copy == dest.end()); - } - - { - vector dest_n(length, false); - const auto res_copy_n = copy_n(source.begin(), static_cast(length), dest_n.begin()); - assert(dest_n == result); - assert(res_copy_n == dest_n.end()); - } - - { - vector dest_backward(length, false); - const auto res_copy_backward = - copy_backward(source.begin(), source.begin() + static_cast(length), dest_backward.end()); - assert(dest_backward == result); - assert(res_copy_backward == dest_backward.begin()); - } - - { - vector dest_move(length, false); - const auto res_move = move(source.begin(), source.begin() + static_cast(length), dest_move.begin()); - assert(dest_move == result); - assert(res_move == dest_move.end()); - } - - { - vector dest_move_backward(length, false); - const auto res_move_backward = - move_backward(source.begin(), source.begin() + static_cast(length), dest_move_backward.end()); - assert(dest_move_backward == result); - assert(res_move_backward == dest_move_backward.begin()); - } -} - -CONSTEXPR20 void test_copy_offset_source(const size_t length) { - vector result; - switch (length) { - case 3: - result = {/***/ false, true, false}; - break; - case 8: - result = {// - /***/ false, true, false, true, true, true, false, // - true}; - break; - case 22: - result = {// - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true}; - break; - case 31: - result = {// - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false}; - break; - case 32: - result = {// - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true}; - break; - case 67: - result = {// - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false}; - break; - default: - assert(false); - } - - const vector source(begin(source_raw), end(source_raw)); - - { - vector dest(length, false); - const auto res_copy = - copy(next(source.begin()), source.begin() + static_cast(length) + 1, dest.begin()); - assert(dest == result); - assert(res_copy == dest.end()); - } - - { - vector dest_n(length, false); - const auto res_copy_n = copy_n(next(source.begin()), static_cast(length), dest_n.begin()); - assert(dest_n == result); - assert(res_copy_n == dest_n.end()); - } - - { - vector dest_backward(length, false); - const auto res_copy_backward = copy_backward( - next(source.begin()), source.begin() + static_cast(length) + 1, dest_backward.end()); - assert(dest_backward == result); - assert(res_copy_backward == dest_backward.begin()); - } - - { - vector dest_move(length, false); - const auto res_move = - move(next(source.begin()), source.begin() + static_cast(length) + 1, dest_move.begin()); - assert(dest_move == result); - assert(res_move == dest_move.end()); - } - - { - vector dest_move_backward(length, false); - const auto res_move_backward = move_backward( - next(source.begin()), source.begin() + static_cast(length) + 1, dest_move_backward.end()); - assert(dest_move_backward == result); - assert(res_move_backward == dest_move_backward.begin()); - } -} - -CONSTEXPR20 void test_copy_offset_dest(const size_t length) { - vector result; - switch (length) { - case 3: - result = {// - false, // - true, false, true}; - break; - case 8: - result = {// - false, // - true, false, true, false, true, true, true, false}; - break; - case 22: - result = {// - false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true}; - break; - case 31: - result = {// - false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true}; - break; - case 32: - result = {// - false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false}; - break; - case 67: - result = {// - false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true}; - break; - default: - assert(false); - } - - const vector source(begin(source_raw), end(source_raw)); - - { - vector dest(length + 1, false); - const auto res_copy = copy(source.begin(), source.begin() + static_cast(length), next(dest.begin())); - assert(dest == result); - assert(res_copy == dest.end()); - } - - { - vector dest_n(length + 1, false); - const auto res_copy_n = copy_n(source.begin(), static_cast(length), next(dest_n.begin())); - assert(dest_n == result); - assert(res_copy_n == dest_n.end()); - } - - { - vector dest_backward(length + 1, false); - const auto res_copy_backward = - copy_backward(source.begin(), source.begin() + static_cast(length), dest_backward.end()); - assert(dest_backward == result); - assert(res_copy_backward == next(dest_backward.begin())); - } - - { - vector dest_move(length + 1, false); - const auto res_move = - move(source.begin(), source.begin() + static_cast(length), next(dest_move.begin())); - assert(dest_move == result); - assert(res_move == dest_move.end()); - } - - { - vector dest_move_backward(length + 1, false); - const auto res_move_backward = - move_backward(source.begin(), source.begin() + static_cast(length), dest_move_backward.end()); - assert(dest_move_backward == result); - assert(res_move_backward == next(dest_move_backward.begin())); - } -} - -CONSTEXPR20 void test_copy_offset_match(const size_t length) { - vector result; - switch (length) { - case 3: - result = {// - false, // - /***/ false, true}; - break; - case 8: - result = {// - false, // - /***/ false, true, false, true, true, true, false}; - break; - case 22: - result = {// - false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true}; - break; - case 31: - result = {// - false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true}; - break; - case 32: - result = {// - false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false}; - break; - case 67: - result = {// - false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true}; - break; - default: - assert(false); - } - - const vector source(begin(source_raw), end(source_raw)); - - { - vector dest(length, false); - const auto res_copy = - copy(next(source.begin()), source.begin() + static_cast(length), next(dest.begin())); - assert(dest == result); - assert(res_copy == dest.end()); - } - - { - vector dest_n(length, false); - const auto res_copy_n = copy_n(next(source.begin()), static_cast(length) - 1, next(dest_n.begin())); - assert(dest_n == result); - assert(res_copy_n == dest_n.end()); - } - - { - vector dest_backward(length, false); - const auto res_copy_backward = - copy_backward(next(source.begin()), source.begin() + static_cast(length), dest_backward.end()); - assert(dest_backward == result); - assert(res_copy_backward == next(dest_backward.begin())); - } - - { - vector dest_move(length, false); - const auto res_move = - move(next(source.begin()), source.begin() + static_cast(length), next(dest_move.begin())); - assert(dest_move == result); - assert(res_move == dest_move.end()); - } - - { - vector dest_move_backward(length, false); - const auto res_move_backward = move_backward( - next(source.begin()), source.begin() + static_cast(length), dest_move_backward.end()); - assert(dest_move_backward == result); - assert(res_move_backward == next(dest_move_backward.begin())); - } -} - -CONSTEXPR20 void test_copy_offset_mismatch_leftshift(const size_t length) { - vector result; - switch (length) { - case 3: - result = {// - false, false, // - /***/ false, true}; - break; - case 8: - result = {// - false, false, // - /***/ false, true, false, true, true, true, false}; - break; - case 22: - result = {// - false, false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true}; - break; - case 31: - result = {// - false, false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true}; - break; - case 32: - result = {// - false, false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false}; - break; - case 67: - result = {// - false, false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true}; - break; - default: - assert(false); - } - - const vector source(begin(source_raw), end(source_raw)); - - { - vector dest(length + 1, false); - const auto res_copy = - copy(next(source.begin()), source.begin() + static_cast(length), next(dest.begin(), 2)); - assert(dest == result); - assert(res_copy == dest.end()); - } - - { - vector dest_n(length + 1, false); - const auto res_copy_n = - copy_n(next(source.begin()), static_cast(length) - 1, next(dest_n.begin(), 2)); - assert(dest_n == result); - assert(res_copy_n == dest_n.end()); - } - - { - vector dest_backward(length + 1, false); - const auto res_copy_backward = - copy_backward(next(source.begin()), source.begin() + static_cast(length), dest_backward.end()); - assert(dest_backward == result); - assert(res_copy_backward == next(dest_backward.begin(), 2)); - } - - { - vector dest_move(length + 1, false); - const auto res_move = - move(next(source.begin()), source.begin() + static_cast(length), next(dest_move.begin(), 2)); - assert(dest_move == result); - assert(res_move == dest_move.end()); - } - - { - vector dest_move_backward(length + 1, false); - const auto res_move_backward = move_backward( - next(source.begin()), source.begin() + static_cast(length), dest_move_backward.end()); - assert(dest_move_backward == result); - assert(res_move_backward == next(dest_move_backward.begin(), 2)); - } -} - -CONSTEXPR20 void test_copy_offset_mismatch_rightshift(const size_t length) { - vector result; - switch (length) { - case 3: - result = {// - false, // - /**********/ true, false}; - break; - case 8: - result = {// - false, // - /**********/ true, false, true, true, true, false, // - true}; - break; - case 22: - result = {// - false, // - /**********/ true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true}; - break; - case 31: - result = {// - false, // - /**********/ true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false}; - break; - case 32: - result = {// - false, // - /**********/ true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true}; - break; - case 67: - result = {// - false, // - /**********/ true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false}; - break; - default: - assert(false); - } - - const vector source(begin(source_raw), end(source_raw)); - - { - vector dest(length, false); - const auto res_copy = - copy(next(source.begin(), 2), source.begin() + static_cast(length) + 1, next(dest.begin())); - assert(dest == result); - assert(res_copy == dest.end()); - } - - { - vector dest_n(length, false); - const auto res_copy_n = - copy_n(next(source.begin(), 2), static_cast(length) - 1, next(dest_n.begin())); - assert(dest_n == result); - assert(res_copy_n == dest_n.end()); - } - - { - vector dest_backward(length, false); - const auto res_copy_backward = copy_backward( - next(source.begin(), 2), source.begin() + static_cast(length) + 1, dest_backward.end()); - assert(dest_backward == result); - assert(res_copy_backward == next(dest_backward.begin())); - } - - { - vector dest_move(length, false); - const auto res_move = - move(next(source.begin(), 2), source.begin() + static_cast(length) + 1, next(dest_move.begin())); - assert(dest_move == result); - assert(res_move == dest_move.end()); - } - - { - vector dest_move_backward(length, false); - const auto res_move_backward = move_backward( - next(source.begin(), 2), source.begin() + static_cast(length) + 1, dest_move_backward.end()); - assert(dest_move_backward == result); - assert(res_move_backward == next(dest_move_backward.begin())); - } -} - -CONSTEXPR20 void test_copy_offset_aligned(const size_t length) { - vector result; - switch (length) { - case 3: - result = {// - false, // - /***/ false, true}; - break; - case 8: - result = {// - false, // - /***/ false, true, false, true, true, true, false}; - break; - case 22: - result = {// - false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true}; - break; - case 31: - result = {// - false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true}; - break; - case 32: - result = {// - false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false}; - break; - case 67: - result = {// - false, // - /***/ false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true, false, true, true, true, false, // - true, false, true}; - break; - default: - assert(false); - } - - const vector source(begin(source_raw), end(source_raw)); - - { - vector dest(length, false); - const auto res_copy = - copy(next(source.begin(), 9), source.begin() + static_cast(length) + 8, next(dest.begin())); - assert(dest == result); - assert(res_copy == dest.end()); - } - - { - vector dest_n(length, false); - const auto res_copy_n = - copy_n(next(source.begin(), 9), static_cast(length) - 1, next(dest_n.begin())); - assert(dest_n == result); - assert(res_copy_n == dest_n.end()); - } - - { - vector dest_backward(length, false); - const auto res_copy_backward = copy_backward( - next(source.begin(), 9), source.begin() + static_cast(length) + 8, dest_backward.end()); - assert(dest_backward == result); - assert(res_copy_backward == next(dest_backward.begin())); - } - - { - vector dest_move(length, false); - const auto res_move = - move(next(source.begin(), 9), source.begin() + static_cast(length) + 8, next(dest_move.begin())); - assert(dest_move == result); - assert(res_move == dest_move.end()); - } - - { - vector dest_move_backward(length, false); - const auto res_move_backward = move_backward( - next(source.begin(), 9), source.begin() + static_cast(length) + 8, dest_move_backward.end()); - assert(dest_move_backward == result); - assert(res_move_backward == next(dest_move_backward.begin())); - } -} - -CONSTEXPR20 void test_copy_sub_char() { - const vector source(begin(source_raw), end(source_raw)); - - { // sub char copy unaligned - const vector result = {false, false, true, false, true, false, false, false}; - - { - vector dest(8, false); - const auto res_copy = copy(source.begin(), next(source.begin(), 3), next(dest.begin(), 2)); - assert(dest == result); - assert(res_copy == next(dest.begin(), 5)); - } - - { - vector dest_n(8, false); - const auto res_copy_n = copy_n(source.begin(), 3, next(dest_n.begin(), 2)); - assert(dest_n == result); - assert(res_copy_n == next(dest_n.begin(), 5)); - } - - { - vector dest_backward(8, false); - const auto res_copy_backward = - copy_backward(source.begin(), next(source.begin(), 3), next(dest_backward.begin(), 5)); - assert(dest_backward == result); - assert(res_copy_backward == next(dest_backward.begin(), 2)); - } - - { - vector dest_move(8, false); - const auto res_move = move(source.begin(), next(source.begin(), 3), next(dest_move.begin(), 2)); - assert(dest_move == result); - assert(res_move == next(dest_move.begin(), 5)); - } - - { - vector dest_move_backward(8, false); - const auto res_move_backward = - move_backward(source.begin(), next(source.begin(), 3), next(dest_move_backward.begin(), 5)); - assert(dest_move_backward == result); - assert(res_move_backward == next(dest_move_backward.begin(), 2)); - } - } - - { // sub char copy until char alignment source - const vector result = {false, false, true, true, false, false, false, false}; - - { - vector dest(8, false); - const auto res_copy = copy(next(source.begin(), 5), next(source.begin(), 8), next(dest.begin(), 2)); - assert(dest == result); - assert(res_copy == next(dest.begin(), 5)); - } - - { - vector dest_n(8, false); - const auto res_copy_n = copy_n(next(source.begin(), 5), 3, next(dest_n.begin(), 2)); - assert(dest_n == result); - assert(res_copy_n == next(dest_n.begin(), 5)); - } - - { - vector dest_backward(8, false); - const auto res_copy_backward = - copy_backward(next(source.begin(), 5), next(source.begin(), 8), next(dest_backward.begin(), 5)); - assert(dest_backward == result); - assert(res_copy_backward == next(dest_backward.begin(), 2)); - } - - { - vector dest_move(8, false); - const auto res_move = move(next(source.begin(), 5), next(source.begin(), 8), next(dest_move.begin(), 2)); - assert(dest_move == result); - assert(res_move == next(dest_move.begin(), 5)); - } - - { - vector dest_move_backward(8, false); - const auto res_move_backward = - move_backward(next(source.begin(), 5), next(source.begin(), 8), next(dest_move_backward.begin(), 5)); - assert(dest_move_backward == result); - assert(res_move_backward == next(dest_move_backward.begin(), 2)); - } - } - - { // sub char copy until char alignment dest - const vector result = {false, false, false, false, false, true, false, true, false, false, false, false, - false, false, false, false}; - - { - vector dest(16, false); - const auto res_copy = copy(source.begin(), next(source.begin(), 3), next(dest.begin(), 5)); - assert(dest == result); - assert(res_copy == next(dest.begin(), 8)); - } - - { - vector dest_n(16, false); - const auto res_copy_n = copy_n(source.begin(), 3, next(dest_n.begin(), 5)); - assert(dest_n == result); - assert(res_copy_n == next(dest_n.begin(), 8)); - } - - { - vector dest_backward(16, false); - const auto res_copy_backward = - copy_backward(source.begin(), next(source.begin(), 3), next(dest_backward.begin(), 8)); - assert(dest_backward == result); - assert(res_copy_backward == next(dest_backward.begin(), 5)); - } - - { - vector dest_move(16, false); - const auto res_move = move(source.begin(), next(source.begin(), 3), next(dest_move.begin(), 5)); - assert(dest_move == result); - assert(res_move == next(dest_move.begin(), 8)); - } - - { - vector dest_move_backward(16, false); - const auto res_move_backward = - move_backward(source.begin(), next(source.begin(), 3), next(dest_move_backward.begin(), 8)); - assert(dest_move_backward == result); - assert(res_move_backward == next(dest_move_backward.begin(), 5)); - } - } - - { // sub char copy over char alignment source - const vector result = {false, false, false, true, false, false, false, false}; - - { - vector dest(8, false); - const auto res_copy = copy(next(source.begin(), 7), next(source.begin(), 10), next(dest.begin(), 2)); - assert(dest == result); - assert(res_copy == next(dest.begin(), 5)); - } - - { - vector dest_n(8, false); - const auto res_copy_n = copy_n(next(source.begin(), 7), 3, next(dest_n.begin(), 2)); - assert(dest_n == result); - assert(res_copy_n == next(dest_n.begin(), 5)); - } - - { - vector dest_backward(8, false); - const auto res_copy_backward = - copy_backward(next(source.begin(), 7), next(source.begin(), 10), next(dest_backward.begin(), 5)); - assert(dest_backward == result); - assert(res_copy_backward == next(dest_backward.begin(), 2)); - } - - { - vector dest_move(8, false); - const auto res_move = move(next(source.begin(), 7), next(source.begin(), 10), next(dest_move.begin(), 2)); - assert(dest_move == result); - assert(res_move == next(dest_move.begin(), 5)); - } - - { - vector dest_move_backward(8, false); - const auto res_move_backward = - move_backward(next(source.begin(), 7), next(source.begin(), 10), next(dest_move_backward.begin(), 5)); - assert(dest_move_backward == result); - assert(res_move_backward == next(dest_move_backward.begin(), 2)); - } - } - - { // sub char copy over char alignment dest - const vector result = {false, false, false, false, false, false, false, true, false, true, false, false, - false, false, false, false}; - - { - vector dest(16, false); - const auto res_copy = copy(source.begin(), next(source.begin(), 3), next(dest.begin(), 7)); - assert(dest == result); - assert(res_copy == next(dest.begin(), 10)); - } - - { - vector dest_n(16, false); - const auto res_copy_n = copy_n(source.begin(), 3, next(dest_n.begin(), 7)); - assert(dest_n == result); - assert(res_copy_n == next(dest_n.begin(), 10)); - } - - { - vector dest_backward(16, false); - const auto res_copy_backward = - copy_backward(source.begin(), next(source.begin(), 3), next(dest_backward.begin(), 10)); - assert(dest_backward == result); - assert(res_copy_backward == next(dest_backward.begin(), 7)); - } - - { - vector dest_move(16, false); - const auto res_move = move(source.begin(), next(source.begin(), 3), next(dest_move.begin(), 7)); - assert(dest_move == result); - assert(res_move == next(dest_move.begin(), 10)); - } - - { - vector dest_move_backward(16, false); - const auto res_move_backward = - move_backward(source.begin(), next(source.begin(), 3), next(dest_move_backward.begin(), 10)); - assert(dest_move_backward == result); - assert(res_move_backward == next(dest_move_backward.begin(), 7)); - } - } -} - -CONSTEXPR20 void test_copy_regression() { - // This specific case was found by the randomized coverage below. - const vector src = {0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, - 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, - 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0}; - - vector dst = {0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, - 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, - 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1}; - - const int src_prefix = 24; - const int dst_prefix = 7; - const int copy_len = 48; - - copy(src.begin() + src_prefix, src.begin() + src_prefix + copy_len, dst.begin() + dst_prefix); - - const vector correct = {0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, - 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, - 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1}; - - assert(dst == correct); -} - -// Test copy() in multiple parts to stay within constexpr step limits. -CONSTEXPR20 bool test_copy_part_1() { - test_copy_no_offset(3); - test_copy_no_offset(8); - test_copy_no_offset(22); - test_copy_no_offset(31); - test_copy_no_offset(32); - test_copy_no_offset(67); - - test_copy_offset_source(3); - test_copy_offset_source(8); - test_copy_offset_source(22); - test_copy_offset_source(31); - test_copy_offset_source(32); - test_copy_offset_source(67); - - test_copy_offset_dest(3); - test_copy_offset_dest(8); - test_copy_offset_dest(22); - test_copy_offset_dest(31); - test_copy_offset_dest(32); - test_copy_offset_dest(67); - - test_copy_offset_match(3); - test_copy_offset_match(8); - test_copy_offset_match(22); - test_copy_offset_match(31); - test_copy_offset_match(32); - test_copy_offset_match(67); - - return true; -} - -CONSTEXPR20 bool test_copy_part_2() { - test_copy_offset_mismatch_leftshift(3); - test_copy_offset_mismatch_leftshift(8); - test_copy_offset_mismatch_leftshift(22); - test_copy_offset_mismatch_leftshift(31); - test_copy_offset_mismatch_leftshift(32); - test_copy_offset_mismatch_leftshift(67); - - test_copy_offset_mismatch_rightshift(3); - test_copy_offset_mismatch_rightshift(8); - test_copy_offset_mismatch_rightshift(22); - test_copy_offset_mismatch_rightshift(31); - test_copy_offset_mismatch_rightshift(32); - test_copy_offset_mismatch_rightshift(67); - - test_copy_offset_aligned(3); - test_copy_offset_aligned(8); - test_copy_offset_aligned(22); - test_copy_offset_aligned(31); - test_copy_offset_aligned(32); - test_copy_offset_aligned(67); - - test_copy_sub_char(); - - test_copy_regression(); - - return true; -} - -void initialize_randomness(mt19937_64& gen) { - constexpr size_t n = mt19937_64::state_size; - constexpr size_t w = mt19937_64::word_size; - static_assert(w % 32 == 0, "w should be evenly divisible by 32"); - constexpr size_t k = w / 32; - - vector vec(n * k); - - random_device rd; - generate(vec.begin(), vec.end(), ref(rd)); - - printf("This is a randomized test.\n"); - printf("DO NOT IGNORE/RERUN ANY FAILURES.\n"); - printf("You must report them to the STL maintainers.\n\n"); - - seed_seq seq(vec.cbegin(), vec.cend()); - gen.seed(seq); -} - -template -void print_vec(const char* const name, const vector& v) { - printf("%s: ", name); - for (const auto& e : v) { - printf("%d", static_cast(e)); - } - printf("\n"); -} - -void randomized_test_copy(mt19937_64& gen) { - uniform_int_distribution affix_dist{0, 2 * blockSize - 1}; // from nothing to a partial then whole block - uniform_int_distribution copy_len_dist{1, 3 * blockSize}; // from 1 bit to leading/middle/trailing blocks - auto bool_dist = [&gen] { return static_cast(gen() & 1); }; - - constexpr int repetitions = 10'000; // tune the number of tests to balance coverage vs. execution time - - for (int k = 0; k < repetitions; ++k) { - const int src_prefix = affix_dist(gen); - const int dst_prefix = affix_dist(gen); - const int copy_len = copy_len_dist(gen); - const int src_suffix = affix_dist(gen); - const int dst_suffix = affix_dist(gen); - - // src vector: - // dst vector: - - vector vb_src(static_cast(src_prefix + copy_len + src_suffix)); - vector vb_dst(static_cast(dst_prefix + copy_len + dst_suffix)); - - generate(vb_src.begin(), vb_src.end(), bool_dist); - generate(vb_dst.begin(), vb_dst.end(), bool_dist); - - const vector v8_src(vb_src.cbegin(), vb_src.cend()); - vector v8_dst(vb_dst.cbegin(), vb_dst.cend()); - - const vector orig_v8_dst = v8_dst; - - copy(vb_src.cbegin() + src_prefix, vb_src.cbegin() + src_prefix + copy_len, vb_dst.begin() + dst_prefix); - copy(v8_src.cbegin() + src_prefix, v8_src.cbegin() + src_prefix + copy_len, v8_dst.begin() + dst_prefix); - - if (!equal(vb_dst.cbegin(), vb_dst.cend(), v8_dst.cbegin(), v8_dst.cend(), equal_to{})) { - printf("src_prefix: %d\n", src_prefix); - printf("dst_prefix: %d\n", dst_prefix); - printf(" copy_len: %d\n", copy_len); - printf("src_suffix: %d\n", src_suffix); - printf("dst_suffix: %d\n", dst_suffix); - - print_vec(" Src", v8_src); - print_vec("Original", orig_v8_dst); - print_vec(" Got", vb_dst); - print_vec("Expected", v8_dst); - - assert(false); - } - } - - // Overlapping is permitted when the dst range starts before the src range. - for (int k = 0; k < repetitions; ++k) { - const int prefix = affix_dist(gen); - const int copy_len = copy_len_dist(gen); - const int overhang = uniform_int_distribution{1, copy_len + 30}(gen); - const int suffix = affix_dist(gen); - - // An overhang of 1 results in the maximum possible overlap. - // An overhang of copy_len results in non-overlapping but adjacent ranges. - // An overhang of copy_len + 30 is the maximum value where the dst and src ranges could share a block. - - // Vector diagram: - // - // ^ - // - - vector vb(static_cast(prefix + overhang + copy_len + suffix)); - - generate(vb.begin(), vb.end(), bool_dist); - - vector v8(vb.cbegin(), vb.cend()); - - const vector orig_v8 = v8; - - copy(vb.cbegin() + prefix + overhang, vb.cbegin() + prefix + overhang + copy_len, vb.begin() + prefix); - copy(v8.cbegin() + prefix + overhang, v8.cbegin() + prefix + overhang + copy_len, v8.begin() + prefix); - - if (!equal(vb.cbegin(), vb.cend(), v8.cbegin(), v8.cend(), equal_to{})) { - printf(" prefix: %d\n", prefix); - printf("copy_len: %d\n", copy_len); - printf("overhang: %d\n", overhang); - printf(" suffix: %d\n", suffix); - - print_vec("Original", orig_v8); - print_vec("Got", vb); - print_vec("Expected", v8); - - assert(false); - } - } - - uniform_int_distribution gap_dist{0, 30}; // 0 gap is adjacent; 30 is the max gap between 2 bits in a block - - // One more interesting case: when the src range is before the dst range, - // and they're non-overlapping but close enough that they could share a block. - for (int k = 0; k < repetitions; ++k) { - const int prefix = affix_dist(gen); - const int copy_len = copy_len_dist(gen); - const int gap = gap_dist(gen); - const int suffix = affix_dist(gen); - - // Vector diagram: - // - - vector vb(static_cast(prefix + copy_len + gap + copy_len + suffix)); - - generate(vb.begin(), vb.end(), bool_dist); - - vector v8(vb.cbegin(), vb.cend()); - - const vector orig_v8 = v8; - - copy(vb.cbegin() + prefix, vb.cbegin() + prefix + copy_len, vb.begin() + prefix + copy_len + gap); - copy(v8.cbegin() + prefix, v8.cbegin() + prefix + copy_len, v8.begin() + prefix + copy_len + gap); - - if (!equal(vb.cbegin(), vb.cend(), v8.cbegin(), v8.cend(), equal_to{})) { - printf(" prefix: %d\n", prefix); - printf("copy_len: %d\n", copy_len); - printf(" gap: %d\n", gap); - printf(" suffix: %d\n", suffix); - - print_vec("Original", orig_v8); - print_vec("Got", vb); - print_vec("Expected", v8); - - assert(false); - } - } -} - -#if _HAS_CXX20 -template -constexpr bool test_gh_5345() { - // GH-5345 : _Copy_vbool() mishandles vectors of size 32 and 64, revealed by constexpr Clang - vector src(N, true); - - for (size_t i = 2; i != N; ++i) { - for (size_t j = i * 2; j < N; j += i) { - src[j] = false; - } - } - - vector dst(N, false); - copy(src.begin() + Offset, src.end(), dst.begin() + Offset); - return equal(src.begin() + Offset, src.end(), dst.begin() + Offset, dst.end()); -} - -static_assert(test_gh_5345<17>()); -static_assert(test_gh_5345<17, 1>()); -static_assert(test_gh_5345<32>()); -static_assert(test_gh_5345<32, 5>()); -static_assert(test_gh_5345<43>()); -static_assert(test_gh_5345<43, 10>()); -static_assert(test_gh_5345<64>()); -static_assert(test_gh_5345<64, 16>()); -static_assert(test_gh_5345<120>()); -static_assert(test_gh_5345<120, 31>()); - -static_assert(test_fill()); -static_assert(test_find()); -static_assert(test_count()); -static_assert(test_transform()); - -#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-2574489 -static_assert(test_copy_part_1()); -static_assert(test_copy_part_2()); -#endif // ^^^ no workaround ^^^ -#endif // _HAS_CXX20 - -int main() { - test_fill(); - test_find(); - test_count(); - test_transform(); - test_copy_part_1(); - test_copy_part_2(); - - test_huge_vector_bool(); - - mt19937_64 gen; - initialize_randomness(gen); - randomized_test_copy(gen); -} + assert(greater_equal_ret == greater_equal_actual.begin() + static_cast(length)); + } + + { + auto not_ret = transform(first1, last1, not_actual.begin(), logical_not<>{}); + assert(not_actual == not_expected); + assert(not_ret == not_actual.begin() + static_cast(length)); + + not_actual.assign(not_actual.size(), false); + + // bit_not emits MSVC and Clang warnings, so it isn't optimized. + // Continue using logical_not to test vector::const_iterator: + not_ret = transform(cfirst1, clast1, not_actual.begin(), logical_not<>{}); + assert(not_actual == not_expected); + assert(not_ret == not_actual.begin() + static_cast(length)); + } +} + +CONSTEXPR20 bool test_transform() { + // Empty range + test_transform_helper(0); + + // One block, ends within block + test_transform_helper(15); + + // One block, ends at block boundary + test_transform_helper(blockSize); + + // Multiple blocks, within block + test_transform_helper(3 * blockSize + 5); + + // Multiple blocks, ends at block boundary + test_transform_helper(4 * blockSize); + return true; +} + +CONSTEXPR20 void test_fill_helper(const size_t length) { + // No offset + { + vector result_true(length, true); + result_true.resize(length + 3, false); + vector dest_true(length + 3, false); + fill(dest_true.begin(), prev(dest_true.end(), 3), true); + assert(dest_true == result_true); + + vector result_false(length, false); + result_false.resize(length + 3, true); + vector dest_false(length + 3, true); + fill(dest_false.begin(), prev(dest_false.end(), 3), false); + assert(dest_false == result_false); + + vector result_true_n(length, true); + result_true_n.resize(length + 3, false); + vector dest_true_n(length + 3, false); + const auto res_fill_n = fill_n(dest_true_n.begin(), length, true); + assert(dest_true_n == result_true_n); + assert(res_fill_n == prev(dest_true_n.end(), 3)); + + vector result_false_n(length, false); + result_false_n.resize(length + 3, true); + vector dest_false_n(length + 3, true); + fill_n(dest_false_n.begin(), length, false); + assert(dest_false_n == result_false_n); + } + + // With offset + { + vector result_true(length, true); + result_true.resize(length + 3, false); + result_true.insert(result_true.begin(), false); + vector dest_true(length + 4, false); + fill(next(dest_true.begin()), prev(dest_true.end(), 3), true); + assert(dest_true == result_true); + + vector result_false(length, false); + result_false.resize(length + 3, true); + result_false.insert(result_false.begin(), true); + vector dest_false(length + 4, true); + fill(next(dest_false.begin()), prev(dest_false.end(), 3), false); + assert(dest_false == result_false); + + vector result_true_n(length, true); + result_true_n.resize(length + 3, false); + result_true_n.insert(result_true_n.begin(), false); + vector dest_true_n(length + 4, false); + const auto res_fill_n = fill_n(next(dest_true_n.begin()), length, true); + assert(dest_true_n == result_true_n); + assert(res_fill_n == prev(dest_true_n.end(), 3)); + + vector result_false_n(length, false); + result_false_n.resize(length + 3, true); + result_false_n.insert(result_false_n.begin(), true); + vector dest_false_n(length + 4, true); + fill_n(next(dest_false_n.begin()), length, false); + assert(dest_false_n == result_false_n); + } +} + +CONSTEXPR20 bool test_fill() { + // Empty + test_fill_helper(0); + + // One block, ends within block + test_fill_helper(15); + + // One block, ends at block boundary + test_fill_helper(blockSize); + + // Multiple blocks, no memset, within block + test_fill_helper(blockSize + 11); + + // Multiple blocks, no memset, ends at block boundary + test_fill_helper(2 * blockSize); + + // Multiple blocks, with memset, within block + test_fill_helper(3 * blockSize + 5); + + // Multiple blocks, with memset, ends at block boundary + test_fill_helper(4 * blockSize); + return true; +} + +CONSTEXPR20 void test_find_helper(const size_t length) { + // No offset + { + vector input_true(length + 3, false); + input_true.resize(length + 6, true); + input_true[length + 1].flip(); + const auto result_true = find(input_true.cbegin(), prev(input_true.cend(), 3), true); + assert(result_true == next(input_true.cbegin(), static_cast(length + 1))); + + vector input_false(length + 3, true); + input_false.resize(length + 6, false); + input_false[length + 1].flip(); + const auto result_false = find(input_false.cbegin(), prev(input_false.cend(), 3), false); + assert(result_false == next(input_false.cbegin(), static_cast(length + 1))); + } + + // With offset + { + vector input_true(length + 3, false); + input_true.resize(length + 6, true); + input_true[length + 1].flip(); + input_true[0].flip(); + const auto result_true = find(next(input_true.cbegin()), prev(input_true.cend(), 3), true); + assert(result_true == next(input_true.cbegin(), static_cast(length + 1))); + + vector input_false(length + 3, true); + input_false.resize(length + 6, false); + input_false[length + 1].flip(); + input_false[0].flip(); + const auto result_false = find(next(input_false.cbegin()), prev(input_false.cend(), 3), false); + assert(result_false == next(input_false.cbegin(), static_cast(length + 1))); + } +} + +CONSTEXPR20 bool test_find() { + // Empty range + test_find_helper(0); + + // One block, ends within block + test_find_helper(15); + + // One block, ends at block boundary + test_find_helper(blockSize); + + // Multiple blocks, within block + test_find_helper(3 * blockSize + 5); + + // Multiple blocks, ends at block boundary + test_find_helper(4 * blockSize); + return true; +} + +CONSTEXPR20 void test_count_helper(const ptrdiff_t length) { + const vector source(begin(source_raw), end(source_raw)); + const int counts_true[] = {0, 1, 1, 2, 2, 3, 4, 5}; + const int counts_false[] = {0, 0, 1, 1, 2, 2, 2, 2}; + const div_t expected = {static_cast(length) / 8, static_cast(length) % 8}; + // No offset + { + const auto result_true = static_cast(count(source.cbegin(), next(source.cbegin(), length), true)); + assert(result_true == expected.quot * 5 + counts_true[expected.rem]); + + const auto result_false = static_cast(count(source.cbegin(), next(source.cbegin(), length), false)); + assert(result_false == expected.quot * 3 + counts_false[expected.rem]); + } + + // With offset + { + const auto result_true = + static_cast(count(next(source.cbegin(), 2), next(source.cbegin(), length + 2), true)); + assert(result_true == expected.quot * 5 + counts_true[expected.rem]); + + const auto result_false = + static_cast(count(next(source.cbegin(), 2), next(source.cbegin(), length + 2), false)); + assert(result_false == expected.quot * 3 + counts_false[expected.rem]); + } +} + +CONSTEXPR20 bool test_count() { + // Empty range + test_count_helper(0); + + // One block, ends within block + test_count_helper(15); + + // One block, ends at block boundary + test_count_helper(blockSize); + + // Multiple blocks, within block + test_count_helper(3 * blockSize + 8); + + // Multiple blocks, ends at block boundary + test_count_helper(4 * blockSize); + return true; +} + +// Also test the behavior of a huge vector whose size is greater than SIZE_MAX, +// which is practical on 32-bit platforms. +template +struct huge_allocator { + huge_allocator() = default; + template + constexpr huge_allocator(const huge_allocator&) noexcept {} + + using value_type = T; + using size_type = uint64_t; + using difference_type = int64_t; + + T* allocate(uint64_t n) { + return allocator{}.allocate(static_cast(n)); + } + + void deallocate(T* p, uint64_t n) { + allocator{}.deallocate(p, static_cast(n)); + } +}; + +void test_huge_vector_bool() { + constexpr uint64_t small_bit_length = 0x7000'4321ULL; + constexpr uint64_t large_bit_length = 0x1'2000'4321ULL; // overflows uint32_t + constexpr auto large_bit_diff = static_cast(large_bit_length); + + vector> v(small_bit_length); + v.resize(large_bit_length); + assert(v.end() - v.begin() == large_bit_diff); + + v.back() = true; + assert(find(v.begin(), v.end(), true) - v.begin() == large_bit_diff - 1); + + v[small_bit_length] = true; + v[large_bit_length - small_bit_length] = true; + assert(count(v.begin(), v.end(), false) == large_bit_diff - 3); +} + +CONSTEXPR20 void test_copy_no_offset(const size_t length) { + vector result; + switch (length) { + case 3: + result = {true, false, true}; + break; + case 8: + result = {true, false, true, false, true, true, true, false}; + break; + case 22: + result = {// + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true}; + break; + case 31: + result = {// + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true}; + break; + case 32: + result = {// + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false}; + break; + case 67: + result = {// + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true}; + break; + default: + assert(false); + } + + const vector source(begin(source_raw), end(source_raw)); + + { + vector dest(length, false); + const auto res_copy = copy(source.begin(), source.begin() + static_cast(length), dest.begin()); + assert(dest == result); + assert(res_copy == dest.end()); + } + + { + vector dest_n(length, false); + const auto res_copy_n = copy_n(source.begin(), static_cast(length), dest_n.begin()); + assert(dest_n == result); + assert(res_copy_n == dest_n.end()); + } + + { + vector dest_backward(length, false); + const auto res_copy_backward = + copy_backward(source.begin(), source.begin() + static_cast(length), dest_backward.end()); + assert(dest_backward == result); + assert(res_copy_backward == dest_backward.begin()); + } + + { + vector dest_move(length, false); + const auto res_move = move(source.begin(), source.begin() + static_cast(length), dest_move.begin()); + assert(dest_move == result); + assert(res_move == dest_move.end()); + } + + { + vector dest_move_backward(length, false); + const auto res_move_backward = + move_backward(source.begin(), source.begin() + static_cast(length), dest_move_backward.end()); + assert(dest_move_backward == result); + assert(res_move_backward == dest_move_backward.begin()); + } +} + +CONSTEXPR20 void test_copy_offset_source(const size_t length) { + vector result; + switch (length) { + case 3: + result = {/***/ false, true, false}; + break; + case 8: + result = {// + /***/ false, true, false, true, true, true, false, // + true}; + break; + case 22: + result = {// + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true}; + break; + case 31: + result = {// + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false}; + break; + case 32: + result = {// + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true}; + break; + case 67: + result = {// + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false}; + break; + default: + assert(false); + } + + const vector source(begin(source_raw), end(source_raw)); + + { + vector dest(length, false); + const auto res_copy = + copy(next(source.begin()), source.begin() + static_cast(length) + 1, dest.begin()); + assert(dest == result); + assert(res_copy == dest.end()); + } + + { + vector dest_n(length, false); + const auto res_copy_n = copy_n(next(source.begin()), static_cast(length), dest_n.begin()); + assert(dest_n == result); + assert(res_copy_n == dest_n.end()); + } + + { + vector dest_backward(length, false); + const auto res_copy_backward = copy_backward( + next(source.begin()), source.begin() + static_cast(length) + 1, dest_backward.end()); + assert(dest_backward == result); + assert(res_copy_backward == dest_backward.begin()); + } + + { + vector dest_move(length, false); + const auto res_move = + move(next(source.begin()), source.begin() + static_cast(length) + 1, dest_move.begin()); + assert(dest_move == result); + assert(res_move == dest_move.end()); + } + + { + vector dest_move_backward(length, false); + const auto res_move_backward = move_backward( + next(source.begin()), source.begin() + static_cast(length) + 1, dest_move_backward.end()); + assert(dest_move_backward == result); + assert(res_move_backward == dest_move_backward.begin()); + } +} + +CONSTEXPR20 void test_copy_offset_dest(const size_t length) { + vector result; + switch (length) { + case 3: + result = {// + false, // + true, false, true}; + break; + case 8: + result = {// + false, // + true, false, true, false, true, true, true, false}; + break; + case 22: + result = {// + false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true}; + break; + case 31: + result = {// + false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true}; + break; + case 32: + result = {// + false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false}; + break; + case 67: + result = {// + false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true}; + break; + default: + assert(false); + } + + const vector source(begin(source_raw), end(source_raw)); + + { + vector dest(length + 1, false); + const auto res_copy = copy(source.begin(), source.begin() + static_cast(length), next(dest.begin())); + assert(dest == result); + assert(res_copy == dest.end()); + } + + { + vector dest_n(length + 1, false); + const auto res_copy_n = copy_n(source.begin(), static_cast(length), next(dest_n.begin())); + assert(dest_n == result); + assert(res_copy_n == dest_n.end()); + } + + { + vector dest_backward(length + 1, false); + const auto res_copy_backward = + copy_backward(source.begin(), source.begin() + static_cast(length), dest_backward.end()); + assert(dest_backward == result); + assert(res_copy_backward == next(dest_backward.begin())); + } + + { + vector dest_move(length + 1, false); + const auto res_move = + move(source.begin(), source.begin() + static_cast(length), next(dest_move.begin())); + assert(dest_move == result); + assert(res_move == dest_move.end()); + } + + { + vector dest_move_backward(length + 1, false); + const auto res_move_backward = + move_backward(source.begin(), source.begin() + static_cast(length), dest_move_backward.end()); + assert(dest_move_backward == result); + assert(res_move_backward == next(dest_move_backward.begin())); + } +} + +CONSTEXPR20 void test_copy_offset_match(const size_t length) { + vector result; + switch (length) { + case 3: + result = {// + false, // + /***/ false, true}; + break; + case 8: + result = {// + false, // + /***/ false, true, false, true, true, true, false}; + break; + case 22: + result = {// + false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true}; + break; + case 31: + result = {// + false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true}; + break; + case 32: + result = {// + false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false}; + break; + case 67: + result = {// + false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true}; + break; + default: + assert(false); + } + + const vector source(begin(source_raw), end(source_raw)); + + { + vector dest(length, false); + const auto res_copy = + copy(next(source.begin()), source.begin() + static_cast(length), next(dest.begin())); + assert(dest == result); + assert(res_copy == dest.end()); + } + + { + vector dest_n(length, false); + const auto res_copy_n = copy_n(next(source.begin()), static_cast(length) - 1, next(dest_n.begin())); + assert(dest_n == result); + assert(res_copy_n == dest_n.end()); + } + + { + vector dest_backward(length, false); + const auto res_copy_backward = + copy_backward(next(source.begin()), source.begin() + static_cast(length), dest_backward.end()); + assert(dest_backward == result); + assert(res_copy_backward == next(dest_backward.begin())); + } + + { + vector dest_move(length, false); + const auto res_move = + move(next(source.begin()), source.begin() + static_cast(length), next(dest_move.begin())); + assert(dest_move == result); + assert(res_move == dest_move.end()); + } + + { + vector dest_move_backward(length, false); + const auto res_move_backward = move_backward( + next(source.begin()), source.begin() + static_cast(length), dest_move_backward.end()); + assert(dest_move_backward == result); + assert(res_move_backward == next(dest_move_backward.begin())); + } +} + +CONSTEXPR20 void test_copy_offset_mismatch_leftshift(const size_t length) { + vector result; + switch (length) { + case 3: + result = {// + false, false, // + /***/ false, true}; + break; + case 8: + result = {// + false, false, // + /***/ false, true, false, true, true, true, false}; + break; + case 22: + result = {// + false, false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true}; + break; + case 31: + result = {// + false, false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true}; + break; + case 32: + result = {// + false, false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false}; + break; + case 67: + result = {// + false, false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true}; + break; + default: + assert(false); + } + + const vector source(begin(source_raw), end(source_raw)); + + { + vector dest(length + 1, false); + const auto res_copy = + copy(next(source.begin()), source.begin() + static_cast(length), next(dest.begin(), 2)); + assert(dest == result); + assert(res_copy == dest.end()); + } + + { + vector dest_n(length + 1, false); + const auto res_copy_n = + copy_n(next(source.begin()), static_cast(length) - 1, next(dest_n.begin(), 2)); + assert(dest_n == result); + assert(res_copy_n == dest_n.end()); + } + + { + vector dest_backward(length + 1, false); + const auto res_copy_backward = + copy_backward(next(source.begin()), source.begin() + static_cast(length), dest_backward.end()); + assert(dest_backward == result); + assert(res_copy_backward == next(dest_backward.begin(), 2)); + } + + { + vector dest_move(length + 1, false); + const auto res_move = + move(next(source.begin()), source.begin() + static_cast(length), next(dest_move.begin(), 2)); + assert(dest_move == result); + assert(res_move == dest_move.end()); + } + + { + vector dest_move_backward(length + 1, false); + const auto res_move_backward = move_backward( + next(source.begin()), source.begin() + static_cast(length), dest_move_backward.end()); + assert(dest_move_backward == result); + assert(res_move_backward == next(dest_move_backward.begin(), 2)); + } +} + +CONSTEXPR20 void test_copy_offset_mismatch_rightshift(const size_t length) { + vector result; + switch (length) { + case 3: + result = {// + false, // + /**********/ true, false}; + break; + case 8: + result = {// + false, // + /**********/ true, false, true, true, true, false, // + true}; + break; + case 22: + result = {// + false, // + /**********/ true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true}; + break; + case 31: + result = {// + false, // + /**********/ true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false}; + break; + case 32: + result = {// + false, // + /**********/ true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true}; + break; + case 67: + result = {// + false, // + /**********/ true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false}; + break; + default: + assert(false); + } + + const vector source(begin(source_raw), end(source_raw)); + + { + vector dest(length, false); + const auto res_copy = + copy(next(source.begin(), 2), source.begin() + static_cast(length) + 1, next(dest.begin())); + assert(dest == result); + assert(res_copy == dest.end()); + } + + { + vector dest_n(length, false); + const auto res_copy_n = + copy_n(next(source.begin(), 2), static_cast(length) - 1, next(dest_n.begin())); + assert(dest_n == result); + assert(res_copy_n == dest_n.end()); + } + + { + vector dest_backward(length, false); + const auto res_copy_backward = copy_backward( + next(source.begin(), 2), source.begin() + static_cast(length) + 1, dest_backward.end()); + assert(dest_backward == result); + assert(res_copy_backward == next(dest_backward.begin())); + } + + { + vector dest_move(length, false); + const auto res_move = + move(next(source.begin(), 2), source.begin() + static_cast(length) + 1, next(dest_move.begin())); + assert(dest_move == result); + assert(res_move == dest_move.end()); + } + + { + vector dest_move_backward(length, false); + const auto res_move_backward = move_backward( + next(source.begin(), 2), source.begin() + static_cast(length) + 1, dest_move_backward.end()); + assert(dest_move_backward == result); + assert(res_move_backward == next(dest_move_backward.begin())); + } +} + +CONSTEXPR20 void test_copy_offset_aligned(const size_t length) { + vector result; + switch (length) { + case 3: + result = {// + false, // + /***/ false, true}; + break; + case 8: + result = {// + false, // + /***/ false, true, false, true, true, true, false}; + break; + case 22: + result = {// + false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true}; + break; + case 31: + result = {// + false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true}; + break; + case 32: + result = {// + false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false}; + break; + case 67: + result = {// + false, // + /***/ false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true, false, true, true, true, false, // + true, false, true}; + break; + default: + assert(false); + } + + const vector source(begin(source_raw), end(source_raw)); + + { + vector dest(length, false); + const auto res_copy = + copy(next(source.begin(), 9), source.begin() + static_cast(length) + 8, next(dest.begin())); + assert(dest == result); + assert(res_copy == dest.end()); + } + + { + vector dest_n(length, false); + const auto res_copy_n = + copy_n(next(source.begin(), 9), static_cast(length) - 1, next(dest_n.begin())); + assert(dest_n == result); + assert(res_copy_n == dest_n.end()); + } + + { + vector dest_backward(length, false); + const auto res_copy_backward = copy_backward( + next(source.begin(), 9), source.begin() + static_cast(length) + 8, dest_backward.end()); + assert(dest_backward == result); + assert(res_copy_backward == next(dest_backward.begin())); + } + + { + vector dest_move(length, false); + const auto res_move = + move(next(source.begin(), 9), source.begin() + static_cast(length) + 8, next(dest_move.begin())); + assert(dest_move == result); + assert(res_move == dest_move.end()); + } + + { + vector dest_move_backward(length, false); + const auto res_move_backward = move_backward( + next(source.begin(), 9), source.begin() + static_cast(length) + 8, dest_move_backward.end()); + assert(dest_move_backward == result); + assert(res_move_backward == next(dest_move_backward.begin())); + } +} + +CONSTEXPR20 void test_copy_sub_char() { + const vector source(begin(source_raw), end(source_raw)); + + { // sub char copy unaligned + const vector result = {false, false, true, false, true, false, false, false}; + + { + vector dest(8, false); + const auto res_copy = copy(source.begin(), next(source.begin(), 3), next(dest.begin(), 2)); + assert(dest == result); + assert(res_copy == next(dest.begin(), 5)); + } + + { + vector dest_n(8, false); + const auto res_copy_n = copy_n(source.begin(), 3, next(dest_n.begin(), 2)); + assert(dest_n == result); + assert(res_copy_n == next(dest_n.begin(), 5)); + } + + { + vector dest_backward(8, false); + const auto res_copy_backward = + copy_backward(source.begin(), next(source.begin(), 3), next(dest_backward.begin(), 5)); + assert(dest_backward == result); + assert(res_copy_backward == next(dest_backward.begin(), 2)); + } + + { + vector dest_move(8, false); + const auto res_move = move(source.begin(), next(source.begin(), 3), next(dest_move.begin(), 2)); + assert(dest_move == result); + assert(res_move == next(dest_move.begin(), 5)); + } + + { + vector dest_move_backward(8, false); + const auto res_move_backward = + move_backward(source.begin(), next(source.begin(), 3), next(dest_move_backward.begin(), 5)); + assert(dest_move_backward == result); + assert(res_move_backward == next(dest_move_backward.begin(), 2)); + } + } + + { // sub char copy until char alignment source + const vector result = {false, false, true, true, false, false, false, false}; + + { + vector dest(8, false); + const auto res_copy = copy(next(source.begin(), 5), next(source.begin(), 8), next(dest.begin(), 2)); + assert(dest == result); + assert(res_copy == next(dest.begin(), 5)); + } + + { + vector dest_n(8, false); + const auto res_copy_n = copy_n(next(source.begin(), 5), 3, next(dest_n.begin(), 2)); + assert(dest_n == result); + assert(res_copy_n == next(dest_n.begin(), 5)); + } + + { + vector dest_backward(8, false); + const auto res_copy_backward = + copy_backward(next(source.begin(), 5), next(source.begin(), 8), next(dest_backward.begin(), 5)); + assert(dest_backward == result); + assert(res_copy_backward == next(dest_backward.begin(), 2)); + } + + { + vector dest_move(8, false); + const auto res_move = move(next(source.begin(), 5), next(source.begin(), 8), next(dest_move.begin(), 2)); + assert(dest_move == result); + assert(res_move == next(dest_move.begin(), 5)); + } + + { + vector dest_move_backward(8, false); + const auto res_move_backward = + move_backward(next(source.begin(), 5), next(source.begin(), 8), next(dest_move_backward.begin(), 5)); + assert(dest_move_backward == result); + assert(res_move_backward == next(dest_move_backward.begin(), 2)); + } + } + + { // sub char copy until char alignment dest + const vector result = {false, false, false, false, false, true, false, true, false, false, false, false, + false, false, false, false}; + + { + vector dest(16, false); + const auto res_copy = copy(source.begin(), next(source.begin(), 3), next(dest.begin(), 5)); + assert(dest == result); + assert(res_copy == next(dest.begin(), 8)); + } + + { + vector dest_n(16, false); + const auto res_copy_n = copy_n(source.begin(), 3, next(dest_n.begin(), 5)); + assert(dest_n == result); + assert(res_copy_n == next(dest_n.begin(), 8)); + } + + { + vector dest_backward(16, false); + const auto res_copy_backward = + copy_backward(source.begin(), next(source.begin(), 3), next(dest_backward.begin(), 8)); + assert(dest_backward == result); + assert(res_copy_backward == next(dest_backward.begin(), 5)); + } + + { + vector dest_move(16, false); + const auto res_move = move(source.begin(), next(source.begin(), 3), next(dest_move.begin(), 5)); + assert(dest_move == result); + assert(res_move == next(dest_move.begin(), 8)); + } + + { + vector dest_move_backward(16, false); + const auto res_move_backward = + move_backward(source.begin(), next(source.begin(), 3), next(dest_move_backward.begin(), 8)); + assert(dest_move_backward == result); + assert(res_move_backward == next(dest_move_backward.begin(), 5)); + } + } + + { // sub char copy over char alignment source + const vector result = {false, false, false, true, false, false, false, false}; + + { + vector dest(8, false); + const auto res_copy = copy(next(source.begin(), 7), next(source.begin(), 10), next(dest.begin(), 2)); + assert(dest == result); + assert(res_copy == next(dest.begin(), 5)); + } + + { + vector dest_n(8, false); + const auto res_copy_n = copy_n(next(source.begin(), 7), 3, next(dest_n.begin(), 2)); + assert(dest_n == result); + assert(res_copy_n == next(dest_n.begin(), 5)); + } + + { + vector dest_backward(8, false); + const auto res_copy_backward = + copy_backward(next(source.begin(), 7), next(source.begin(), 10), next(dest_backward.begin(), 5)); + assert(dest_backward == result); + assert(res_copy_backward == next(dest_backward.begin(), 2)); + } + + { + vector dest_move(8, false); + const auto res_move = move(next(source.begin(), 7), next(source.begin(), 10), next(dest_move.begin(), 2)); + assert(dest_move == result); + assert(res_move == next(dest_move.begin(), 5)); + } + + { + vector dest_move_backward(8, false); + const auto res_move_backward = + move_backward(next(source.begin(), 7), next(source.begin(), 10), next(dest_move_backward.begin(), 5)); + assert(dest_move_backward == result); + assert(res_move_backward == next(dest_move_backward.begin(), 2)); + } + } + + { // sub char copy over char alignment dest + const vector result = {false, false, false, false, false, false, false, true, false, true, false, false, + false, false, false, false}; + + { + vector dest(16, false); + const auto res_copy = copy(source.begin(), next(source.begin(), 3), next(dest.begin(), 7)); + assert(dest == result); + assert(res_copy == next(dest.begin(), 10)); + } + + { + vector dest_n(16, false); + const auto res_copy_n = copy_n(source.begin(), 3, next(dest_n.begin(), 7)); + assert(dest_n == result); + assert(res_copy_n == next(dest_n.begin(), 10)); + } + + { + vector dest_backward(16, false); + const auto res_copy_backward = + copy_backward(source.begin(), next(source.begin(), 3), next(dest_backward.begin(), 10)); + assert(dest_backward == result); + assert(res_copy_backward == next(dest_backward.begin(), 7)); + } + + { + vector dest_move(16, false); + const auto res_move = move(source.begin(), next(source.begin(), 3), next(dest_move.begin(), 7)); + assert(dest_move == result); + assert(res_move == next(dest_move.begin(), 10)); + } + + { + vector dest_move_backward(16, false); + const auto res_move_backward = + move_backward(source.begin(), next(source.begin(), 3), next(dest_move_backward.begin(), 10)); + assert(dest_move_backward == result); + assert(res_move_backward == next(dest_move_backward.begin(), 7)); + } + } +} + +CONSTEXPR20 void test_copy_regression() { + // This specific case was found by the randomized coverage below. + const vector src = {0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, + 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0}; + + vector dst = {0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, + 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, + 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1}; + + const int src_prefix = 24; + const int dst_prefix = 7; + const int copy_len = 48; + + copy(src.begin() + src_prefix, src.begin() + src_prefix + copy_len, dst.begin() + dst_prefix); + + const vector correct = {0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1}; + + assert(dst == correct); +} + +// Test copy() in multiple parts to stay within constexpr step limits. +CONSTEXPR20 bool test_copy_part_1() { + test_copy_no_offset(3); + test_copy_no_offset(8); + test_copy_no_offset(22); + test_copy_no_offset(31); + test_copy_no_offset(32); + test_copy_no_offset(67); + + test_copy_offset_source(3); + test_copy_offset_source(8); + test_copy_offset_source(22); + test_copy_offset_source(31); + test_copy_offset_source(32); + test_copy_offset_source(67); + + test_copy_offset_dest(3); + test_copy_offset_dest(8); + test_copy_offset_dest(22); + test_copy_offset_dest(31); + test_copy_offset_dest(32); + test_copy_offset_dest(67); + + test_copy_offset_match(3); + test_copy_offset_match(8); + test_copy_offset_match(22); + test_copy_offset_match(31); + test_copy_offset_match(32); + test_copy_offset_match(67); + + return true; +} + +CONSTEXPR20 bool test_copy_part_2() { + test_copy_offset_mismatch_leftshift(3); + test_copy_offset_mismatch_leftshift(8); + test_copy_offset_mismatch_leftshift(22); + test_copy_offset_mismatch_leftshift(31); + test_copy_offset_mismatch_leftshift(32); + test_copy_offset_mismatch_leftshift(67); + + test_copy_offset_mismatch_rightshift(3); + test_copy_offset_mismatch_rightshift(8); + test_copy_offset_mismatch_rightshift(22); + test_copy_offset_mismatch_rightshift(31); + test_copy_offset_mismatch_rightshift(32); + test_copy_offset_mismatch_rightshift(67); + + test_copy_offset_aligned(3); + test_copy_offset_aligned(8); + test_copy_offset_aligned(22); + test_copy_offset_aligned(31); + test_copy_offset_aligned(32); + test_copy_offset_aligned(67); + + test_copy_sub_char(); + + test_copy_regression(); + + return true; +} + +void initialize_randomness(mt19937_64& gen) { + constexpr size_t n = mt19937_64::state_size; + constexpr size_t w = mt19937_64::word_size; + static_assert(w % 32 == 0, "w should be evenly divisible by 32"); + constexpr size_t k = w / 32; + + vector vec(n * k); + + random_device rd; + generate(vec.begin(), vec.end(), ref(rd)); + + printf("This is a randomized test.\n"); + printf("DO NOT IGNORE/RERUN ANY FAILURES.\n"); + printf("You must report them to the STL maintainers.\n\n"); + + seed_seq seq(vec.cbegin(), vec.cend()); + gen.seed(seq); +} + +template +void print_vec(const char* const name, const vector& v) { + printf("%s: ", name); + for (const auto& e : v) { + printf("%d", static_cast(e)); + } + printf("\n"); +} + +void randomized_test_copy(mt19937_64& gen) { + uniform_int_distribution affix_dist{0, 2 * blockSize - 1}; // from nothing to a partial then whole block + uniform_int_distribution copy_len_dist{1, 3 * blockSize}; // from 1 bit to leading/middle/trailing blocks + auto bool_dist = [&gen] { return static_cast(gen() & 1); }; + + constexpr int repetitions = 10'000; // tune the number of tests to balance coverage vs. execution time + + for (int k = 0; k < repetitions; ++k) { + const int src_prefix = affix_dist(gen); + const int dst_prefix = affix_dist(gen); + const int copy_len = copy_len_dist(gen); + const int src_suffix = affix_dist(gen); + const int dst_suffix = affix_dist(gen); + + // src vector: + // dst vector: + + vector vb_src(static_cast(src_prefix + copy_len + src_suffix)); + vector vb_dst(static_cast(dst_prefix + copy_len + dst_suffix)); + + generate(vb_src.begin(), vb_src.end(), bool_dist); + generate(vb_dst.begin(), vb_dst.end(), bool_dist); + + const vector v8_src(vb_src.cbegin(), vb_src.cend()); + vector v8_dst(vb_dst.cbegin(), vb_dst.cend()); + + const vector orig_v8_dst = v8_dst; + + copy(vb_src.cbegin() + src_prefix, vb_src.cbegin() + src_prefix + copy_len, vb_dst.begin() + dst_prefix); + copy(v8_src.cbegin() + src_prefix, v8_src.cbegin() + src_prefix + copy_len, v8_dst.begin() + dst_prefix); + + if (!equal(vb_dst.cbegin(), vb_dst.cend(), v8_dst.cbegin(), v8_dst.cend(), equal_to{})) { + printf("src_prefix: %d\n", src_prefix); + printf("dst_prefix: %d\n", dst_prefix); + printf(" copy_len: %d\n", copy_len); + printf("src_suffix: %d\n", src_suffix); + printf("dst_suffix: %d\n", dst_suffix); + + print_vec(" Src", v8_src); + print_vec("Original", orig_v8_dst); + print_vec(" Got", vb_dst); + print_vec("Expected", v8_dst); + + assert(false); + } + } + + // Overlapping is permitted when the dst range starts before the src range. + for (int k = 0; k < repetitions; ++k) { + const int prefix = affix_dist(gen); + const int copy_len = copy_len_dist(gen); + const int overhang = uniform_int_distribution{1, copy_len + 30}(gen); + const int suffix = affix_dist(gen); + + // An overhang of 1 results in the maximum possible overlap. + // An overhang of copy_len results in non-overlapping but adjacent ranges. + // An overhang of copy_len + 30 is the maximum value where the dst and src ranges could share a block. + + // Vector diagram: + // + // ^ + // + + vector vb(static_cast(prefix + overhang + copy_len + suffix)); + + generate(vb.begin(), vb.end(), bool_dist); + + vector v8(vb.cbegin(), vb.cend()); + + const vector orig_v8 = v8; + + copy(vb.cbegin() + prefix + overhang, vb.cbegin() + prefix + overhang + copy_len, vb.begin() + prefix); + copy(v8.cbegin() + prefix + overhang, v8.cbegin() + prefix + overhang + copy_len, v8.begin() + prefix); + + if (!equal(vb.cbegin(), vb.cend(), v8.cbegin(), v8.cend(), equal_to{})) { + printf(" prefix: %d\n", prefix); + printf("copy_len: %d\n", copy_len); + printf("overhang: %d\n", overhang); + printf(" suffix: %d\n", suffix); + + print_vec("Original", orig_v8); + print_vec("Got", vb); + print_vec("Expected", v8); + + assert(false); + } + } + + uniform_int_distribution gap_dist{0, 30}; // 0 gap is adjacent; 30 is the max gap between 2 bits in a block + + // One more interesting case: when the src range is before the dst range, + // and they're non-overlapping but close enough that they could share a block. + for (int k = 0; k < repetitions; ++k) { + const int prefix = affix_dist(gen); + const int copy_len = copy_len_dist(gen); + const int gap = gap_dist(gen); + const int suffix = affix_dist(gen); + + // Vector diagram: + // + + vector vb(static_cast(prefix + copy_len + gap + copy_len + suffix)); + + generate(vb.begin(), vb.end(), bool_dist); + + vector v8(vb.cbegin(), vb.cend()); + + const vector orig_v8 = v8; + + copy(vb.cbegin() + prefix, vb.cbegin() + prefix + copy_len, vb.begin() + prefix + copy_len + gap); + copy(v8.cbegin() + prefix, v8.cbegin() + prefix + copy_len, v8.begin() + prefix + copy_len + gap); + + if (!equal(vb.cbegin(), vb.cend(), v8.cbegin(), v8.cend(), equal_to{})) { + printf(" prefix: %d\n", prefix); + printf("copy_len: %d\n", copy_len); + printf(" gap: %d\n", gap); + printf(" suffix: %d\n", suffix); + + print_vec("Original", orig_v8); + print_vec("Got", vb); + print_vec("Expected", v8); + + assert(false); + } + } +} + +#if _HAS_CXX20 +template +constexpr bool test_gh_5345() { + // GH-5345 : _Copy_vbool() mishandles vectors of size 32 and 64, revealed by constexpr Clang + vector src(N, true); + + for (size_t i = 2; i != N; ++i) { + for (size_t j = i * 2; j < N; j += i) { + src[j] = false; + } + } + + vector dst(N, false); + copy(src.begin() + Offset, src.end(), dst.begin() + Offset); + return equal(src.begin() + Offset, src.end(), dst.begin() + Offset, dst.end()); +} + +static_assert(test_gh_5345<17>()); +static_assert(test_gh_5345<17, 1>()); +static_assert(test_gh_5345<32>()); +static_assert(test_gh_5345<32, 5>()); +static_assert(test_gh_5345<43>()); +static_assert(test_gh_5345<43, 10>()); +static_assert(test_gh_5345<64>()); +static_assert(test_gh_5345<64, 16>()); +static_assert(test_gh_5345<120>()); +static_assert(test_gh_5345<120, 31>()); + +static_assert(test_fill()); +static_assert(test_find()); +static_assert(test_count()); +static_assert(test_transform()); + +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-2574489 +static_assert(test_copy_part_1()); +static_assert(test_copy_part_2()); +#endif // ^^^ no workaround ^^^ +#endif // _HAS_CXX20 + +int main() { + test_fill(); + test_find(); + test_count(); + test_transform(); + test_copy_part_1(); + test_copy_part_2(); + + test_huge_vector_bool(); + + mt19937_64 gen; + initialize_randomness(gen); + randomized_test_copy(gen); +}