diff options
author | Peng Liu <winner245@hotmail.com> | 2025-02-26 11:38:15 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-26 11:38:15 -0500 |
commit | 1d583ed2fb76c3d944ffab012c21b8fc0a93cac1 (patch) | |
tree | c784a5ba70a1ae6990b3e19c233ecce7ec683a3a /libcxx/test/std/algorithms | |
parent | 1ec1d25f691b92fb6aec8d0564139a5ba6c721b7 (diff) | |
download | llvm-1d583ed2fb76c3d944ffab012c21b8fc0a93cac1.zip llvm-1d583ed2fb76c3d944ffab012c21b8fc0a93cac1.tar.gz llvm-1d583ed2fb76c3d944ffab012c21b8fc0a93cac1.tar.bz2 |
[libc++][test] Augment ranges::{fill, fill_n, find} with missing tests (#121209)
libc++ currently has very limited test coverage for `std::ranges{fill, fill_n, find}`
with `vector<bool>::iterator` optimizations. Specifically, the existing tests for
`std::ranges::fill` only covers cases of 1 - 2 bytes, which is merely 1/8 to 1/4
of the `__storage_type` word size. This renders the tests insufficient to validate
functionality for whole words, with or without partial words (which necessitates at
least 8 bytes of data). Moreover, no tests were provided for `ranges::{find, fill_n}`
with `vector<bool>::iterator` optimizations. This PR fills in the gap.
Diffstat (limited to 'libcxx/test/std/algorithms')
6 files changed, 371 insertions, 175 deletions
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/fill.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/fill.pass.cpp index 0e532ae..9b403db 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/fill.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/fill.pass.cpp @@ -48,89 +48,96 @@ struct Test { } }; -// Make sure std::fill behaves properly with std::vector<bool> iterators with custom size types. -// See https://github.com/llvm/llvm-project/pull/122410. -TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { - { - using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>; - std::vector<bool, Alloc> in(100, false, Alloc(1)); - std::vector<bool, Alloc> expected(100, true, Alloc(1)); - std::fill(in.begin(), in.end(), true); - assert(in == expected); - } - { - using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::fill(in.begin(), in.end(), true); - assert(in == expected); - } - { - using Alloc = sized_allocator<bool, std::uint32_t, std::int32_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::fill(in.begin(), in.end(), true); - assert(in == expected); +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + { // Test cases validating leading/trailing bits unfilled remain unchanged + { // Leading bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[0] = expected[1] = false; + std::fill(in.begin() + 2, in.end(), true); + assert(in == expected); + } + { // Trailing bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[N - 1] = expected[N - 2] = false; + std::fill(in.begin(), in.end() - 2, true); + assert(in == expected); + } + { // Leading and trailing bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[0] = expected[1] = expected[N - 1] = expected[N - 2] = false; + std::fill(in.begin() + 2, in.end() - 2, true); + assert(in == expected); + } } - { - using Alloc = sized_allocator<bool, std::uint64_t, std::int64_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::fill(in.begin(), in.end(), true); - assert(in == expected); + + { // Test cases with full or partial bytes filled + { // Full bytes filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::fill(in.begin(), in.end(), true); + assert(in == expected); + } + { // Partial bytes with offset filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::fill(in.begin() + 4, in.end() - 4, true); + std::fill(expected.begin(), expected.begin() + 4, false); + std::fill(expected.end() - 4, expected.end(), false); + assert(in == expected); + } } + + return true; } TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::forward_iterator_list<char*>(), Test<char>()); types::for_each(types::forward_iterator_list<int*>(), Test<int>()); - { // test vector<bool>::iterator optimization - { // simple case - std::vector<bool> in(4, false); - std::vector<bool> expected(4, true); + + { // Test vector<bool>::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + + // Make sure std::fill behaves properly with std::vector<bool> iterators with custom size types. + // See https://github.com/llvm/llvm-project/pull/122410. + { + using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>; + std::vector<bool, Alloc> in(100, false, Alloc(1)); + std::vector<bool, Alloc> expected(100, true, Alloc(1)); std::fill(in.begin(), in.end(), true); assert(in == expected); } - { // partial byte in the front is not filled - std::vector<bool> in(8, false); - std::vector<bool> expected(8, true); - expected[0] = false; - expected[1] = false; - std::fill(in.begin() + 2, in.end(), true); - assert(in == expected); - } - { // partial byte in the back is not filled - std::vector<bool> in(8, false); - std::vector<bool> expected(8, true); - expected[6] = false; - expected[7] = false; - std::fill(in.begin(), in.end() - 2, true); + { + using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::fill(in.begin(), in.end(), true); assert(in == expected); } - { // partial byte in the front and back is not filled - std::vector<bool> in(16, false); - std::vector<bool> expected(16, true); - expected[0] = false; - expected[1] = false; - expected[14] = false; - expected[15] = false; - std::fill(in.begin() + 2, in.end() - 2, true); + { + using Alloc = sized_allocator<bool, std::uint32_t, std::int32_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::fill(in.begin(), in.end(), true); assert(in == expected); } - { // only a few bits of a byte are set - std::vector<bool> in(8, false); - std::vector<bool> expected(8, true); - expected[0] = false; - expected[1] = false; - expected[6] = false; - expected[7] = false; - std::fill(in.begin() + 2, in.end() - 2, true); + { + using Alloc = sized_allocator<bool, std::uint64_t, std::int64_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::fill(in.begin(), in.end(), true); assert(in == expected); } } - test_bititer_with_custom_sized_types(); - return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/fill_n.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/fill_n.pass.cpp index 98c412f..4dda871 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/fill_n.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/fill_n.pass.cpp @@ -109,37 +109,49 @@ struct Storage { }; }; -// Make sure std::fill_n behaves properly with std::vector<bool> iterators with custom size types. -// See https://github.com/llvm/llvm-project/pull/122410. -TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { - { - using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>; - std::vector<bool, Alloc> in(100, false, Alloc(1)); - std::vector<bool, Alloc> expected(100, true, Alloc(1)); - std::fill_n(in.begin(), in.size(), true); - assert(in == expected); - } - { - using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::fill_n(in.begin(), in.size(), true); - assert(in == expected); - } - { - using Alloc = sized_allocator<bool, std::uint32_t, std::int32_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::fill_n(in.begin(), in.size(), true); - assert(in == expected); +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + { // Test cases validating leading/trailing bits unfilled remain unchanged + { // Leading bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[0] = expected[1] = false; + std::fill_n(in.begin() + 2, N - 2, true); + assert(in == expected); + } + { // Trailing bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[N - 1] = expected[N - 2] = false; + std::fill_n(in.begin(), N - 2, true); + assert(in == expected); + } + { // Leading and trailing bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[0] = expected[1] = expected[N - 1] = expected[N - 2] = false; + std::fill_n(in.begin() + 2, N - 4, true); + assert(in == expected); + } } - { - using Alloc = sized_allocator<bool, std::uint64_t, std::int64_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::fill_n(in.begin(), in.size(), true); - assert(in == expected); + + { // Test cases with full or partial bytes filled + { // Full bytes filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::fill_n(in.begin(), N, true); + assert(in == expected); + } + { // Partial bytes with offset filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::fill_n(in.begin() + 4, N - 8, true); + std::fill_n(expected.begin(), 4, false); + std::fill_n(expected.end() - 4, 4, false); + assert(in == expected); + } } + + return true; } TEST_CONSTEXPR_CXX20 void test_struct_array() { @@ -171,7 +183,47 @@ TEST_CONSTEXPR_CXX20 bool test() { test_int_array(); test_struct_array(); test_int_array_struct_source(); - test_bititer_with_custom_sized_types(); + + { // Test vector<bool>::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + + // Make sure std::fill_n behaves properly with std::vector<bool> iterators with custom size types. + // See https://github.com/llvm/llvm-project/pull/122410. + { + using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>; + std::vector<bool, Alloc> in(100, false, Alloc(1)); + std::vector<bool, Alloc> expected(100, true, Alloc(1)); + std::fill_n(in.begin(), in.size(), true); + assert(in == expected); + } + { + using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::fill_n(in.begin(), in.size(), true); + assert(in == expected); + } + { + using Alloc = sized_allocator<bool, std::uint32_t, std::int32_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::fill_n(in.begin(), in.size(), true); + assert(in == expected); + } + { + using Alloc = sized_allocator<bool, std::uint64_t, std::int64_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::fill_n(in.begin(), in.size(), true); + assert(in == expected); + } + } return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/ranges.fill.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/ranges.fill.pass.cpp index 30dfdd5..61a659f 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/ranges.fill.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/ranges.fill.pass.cpp @@ -78,42 +78,53 @@ constexpr void test_iterators() { } } -// Make sure std::ranges::fill behaves properly with std::vector<bool> iterators with custom -// size types. See https://github.com/llvm/llvm-project/pull/122410. -// // The `ranges::{fill, fill_n}` algorithms require `vector<bool, Alloc>::iterator` to satisfy // the `std::indirectly_writable` concept when used with `vector<bool, Alloc>`, which is only // satisfied since C++23. #if TEST_STD_VER >= 23 -TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { - { - using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>; - std::vector<bool, Alloc> in(100, false, Alloc(1)); - std::vector<bool, Alloc> expected(100, true, Alloc(1)); - std::ranges::fill(in, true); - assert(in == expected); - } - { - using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::ranges::fill(in, true); - assert(in == expected); - } - { - using Alloc = sized_allocator<bool, std::uint32_t, std::int32_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::ranges::fill(in, true); - assert(in == expected); +constexpr bool test_vector_bool(std::size_t N) { + { // Test cases validating leading/trailing bits unfilled remain unchanged + { // Leading bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[0] = expected[1] = false; + std::ranges::fill(std::ranges::subrange(in.begin() + 2, in.end()), true); + assert(in == expected); + } + { // Trailing bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[N - 1] = expected[N - 2] = false; + std::ranges::fill(std::ranges::subrange(in.begin(), in.end() - 2), true); + assert(in == expected); + } + { // Leading and trailing bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[0] = expected[1] = expected[N - 1] = expected[N - 2] = false; + std::ranges::fill(std::ranges::subrange(in.begin() + 2, in.end() - 2), true); + assert(in == expected); + } } - { - using Alloc = sized_allocator<bool, std::uint64_t, std::int64_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::ranges::fill(in, true); - assert(in == expected); + + { // Test cases with full or partial bytes filled + { // Full bytes filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::ranges::fill(in, true); + assert(in == expected); + } + { // Partial bytes with offset filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::ranges::fill(std::ranges::subrange(std::ranges::begin(in) + 4, std::ranges::end(in) - 4), true); + std::ranges::fill(std::ranges::subrange(std::ranges::begin(expected), std::ranges::begin(expected) + 4), false); + std::ranges::fill(std::ranges::subrange(std::ranges::end(expected) - 4, std::ranges::end(expected)), false); + assert(in == expected); + } } + + return true; } #endif @@ -174,7 +185,46 @@ constexpr bool test() { } #if TEST_STD_VER >= 23 - test_bititer_with_custom_sized_types(); + { // Test vector<bool>::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + + // Make sure std::ranges::fill behaves properly with std::vector<bool> iterators with custom + // size types. See https://github.com/llvm/llvm-project/pull/122410. + { + using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>; + std::vector<bool, Alloc> in(100, false, Alloc(1)); + std::vector<bool, Alloc> expected(100, true, Alloc(1)); + std::ranges::fill(in, true); + assert(in == expected); + } + { + using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::ranges::fill(in, true); + assert(in == expected); + } + { + using Alloc = sized_allocator<bool, std::uint32_t, std::int32_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::ranges::fill(in, true); + assert(in == expected); + } + { + using Alloc = sized_allocator<bool, std::uint64_t, std::int64_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::ranges::fill(in, true); + assert(in == expected); + } + } #endif return true; diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/ranges.fill_n.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/ranges.fill_n.pass.cpp index ae70e71..2d6e24a 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/ranges.fill_n.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.fill/ranges.fill_n.pass.cpp @@ -51,42 +51,53 @@ constexpr void test_iterators() { } } -// Make sure std::ranges::fill_n behaves properly with std::vector<bool> iterators with custom -// size types. See https://github.com/llvm/llvm-project/pull/122410. -// // The `ranges::{fill, fill_n}` algorithms require `vector<bool, Alloc>::iterator` to satisfy // the `std::indirectly_writable` concept when used with `vector<bool, Alloc>`, which is only // satisfied since C++23. #if TEST_STD_VER >= 23 -TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { - { - using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>; - std::vector<bool, Alloc> in(100, false, Alloc(1)); - std::vector<bool, Alloc> expected(100, true, Alloc(1)); - std::ranges::fill_n(std::ranges::begin(in), in.size(), true); - assert(in == expected); - } - { - using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::ranges::fill_n(std::ranges::begin(in), in.size(), true); - assert(in == expected); +constexpr bool test_vector_bool(std::size_t N) { + { // Test cases validating leading/trailing bits unfilled remain unchanged + { // Leading bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[0] = expected[1] = false; + std::ranges::fill_n(std::ranges::begin(in) + 2, N - 2, true); + assert(in == expected); + } + { // Trailing bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[N - 1] = expected[N - 2] = false; + std::ranges::fill_n(std::ranges::begin(in), N - 2, true); + assert(in == expected); + } + { // Leading and trailing bits are not filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + expected[0] = expected[1] = expected[N - 1] = expected[N - 2] = false; + std::ranges::fill_n(std::ranges::begin(in) + 2, N - 4, true); + assert(in == expected); + } } - { - using Alloc = sized_allocator<bool, std::uint32_t, std::int32_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::ranges::fill_n(std::ranges::begin(in), in.size(), true); - assert(in == expected); - } - { - using Alloc = sized_allocator<bool, std::uint64_t, std::int64_t>; - std::vector<bool, Alloc> in(200, false, Alloc(1)); - std::vector<bool, Alloc> expected(200, true, Alloc(1)); - std::ranges::fill_n(std::ranges::begin(in), in.size(), true); - assert(in == expected); + + { // Test cases with full or partial bytes filled + { // Full bytes filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::ranges::fill_n(std::ranges::begin(in), N, true); + assert(in == expected); + } + { // Partial bytes with offset filled + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::ranges::fill_n(std::ranges::begin(in) + 4, N - 8, true); + std::ranges::fill_n(std::ranges::begin(expected), 4, false); + std::ranges::fill_n(std::ranges::end(expected) - 4, 4, false); + assert(in == expected); + } } + + return true; } #endif @@ -122,7 +133,46 @@ constexpr bool test() { } #if TEST_STD_VER >= 23 - test_bititer_with_custom_sized_types(); + { // Test vector<bool>::iterator optimization + assert(test_vector_bool(8)); + assert(test_vector_bool(19)); + assert(test_vector_bool(32)); + assert(test_vector_bool(49)); + assert(test_vector_bool(64)); + assert(test_vector_bool(199)); + assert(test_vector_bool(256)); + + // Make sure std::ranges::fill_n behaves properly with std::vector<bool> iterators with custom + // size types. See https://github.com/llvm/llvm-project/pull/122410. + { + using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>; + std::vector<bool, Alloc> in(100, false, Alloc(1)); + std::vector<bool, Alloc> expected(100, true, Alloc(1)); + std::ranges::fill_n(std::ranges::begin(in), in.size(), true); + assert(in == expected); + } + { + using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::ranges::fill_n(std::ranges::begin(in), in.size(), true); + assert(in == expected); + } + { + using Alloc = sized_allocator<bool, std::uint32_t, std::int32_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::ranges::fill_n(std::ranges::begin(in), in.size(), true); + assert(in == expected); + } + { + using Alloc = sized_allocator<bool, std::uint64_t, std::int64_t>; + std::vector<bool, Alloc> in(200, false, Alloc(1)); + std::vector<bool, Alloc> expected(200, true, Alloc(1)); + std::ranges::fill_n(std::ranges::begin(in), in.size(), true); + assert(in == expected); + } + } #endif return true; diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp index 2dbad32..dd89f2c 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/find.pass.cpp @@ -14,6 +14,8 @@ // MSVC warning C4389: '==': signed/unsigned mismatch // MSVC warning C4805: '==': unsafe mix of type 'char' and type 'bool' in operation // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4245 /wd4305 /wd4310 /wd4389 /wd4805 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000 // <algorithm> @@ -24,6 +26,7 @@ #include <algorithm> #include <cassert> +#include <cstddef> #include <deque> #include <vector> #include <type_traits> @@ -225,6 +228,18 @@ TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::integral_types(), TestIntegerPromotions()); + { // Test vector<bool>::iterator optimization + std::vector<bool> vec(256 + 8); + for (ptrdiff_t i = 8; i <= 256; i *= 2) { + for (size_t offset = 0; offset < 8; offset += 2) { + std::fill(vec.begin(), vec.end(), false); + std::fill(vec.begin() + offset, vec.begin() + i + offset, true); + assert(std::find(vec.begin(), vec.end(), true) == vec.begin() + offset); + assert(std::find(vec.begin() + offset, vec.end(), false) == vec.begin() + offset + i); + } + } + } + return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index 760ee23..46accc5 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -14,6 +14,8 @@ // MSVC warning C4242: 'argument': conversion from 'const _Ty' to 'ElementT', possible loss of data // MSVC warning C4244: 'argument': conversion from 'const _Ty' to 'ElementT', possible loss of data // ADDITIONAL_COMPILE_FLAGS(cl-style-warnings): /wd4242 /wd4244 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=20000000 +// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-ops-limit): -fconstexpr-ops-limit=80000000 // template<input_iterator I, sentinel_for<I> S, class T, class Proj = identity> // requires indirect_binary_predicate<ranges::equal_to, projected<I, Proj>, const T*> @@ -26,6 +28,7 @@ #include <algorithm> #include <array> #include <cassert> +#include <cstddef> #include <deque> #include <ranges> #include <vector> @@ -66,14 +69,14 @@ constexpr void test_iterators() { using ValueT = std::iter_value_t<It>; { // simple test { - ValueT a[] = {1, 2, 3, 4}; + ValueT a[] = {1, 2, 3, 4}; std::same_as<It> auto ret = std::ranges::find(It(a), Sent(It(a + 4)), 4); assert(base(ret) == a + 3); assert(*ret == 4); } { - ValueT a[] = {1, 2, 3, 4}; - auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); + ValueT a[] = {1, 2, 3, 4}; + auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); std::same_as<It> auto ret = std::ranges::find(range, 4); assert(base(ret) == a + 3); assert(*ret == 4); @@ -83,13 +86,13 @@ constexpr void test_iterators() { { // check that an empty range works { std::array<ValueT, 0> a = {}; - auto ret = std::ranges::find(It(a.data()), Sent(It(a.data())), 1); + auto ret = std::ranges::find(It(a.data()), Sent(It(a.data())), 1); assert(base(ret) == a.data()); } { std::array<ValueT, 0> a = {}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data()))); - auto ret = std::ranges::find(range, 1); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data()))); + auto ret = std::ranges::find(range, 1); assert(base(ret) == a.data()); } } @@ -97,12 +100,12 @@ constexpr void test_iterators() { { // check that last is returned with no match { ValueT a[] = {1, 1, 1}; - auto ret = std::ranges::find(a, a + 3, 0); + auto ret = std::ranges::find(a, a + 3, 0); assert(ret == a + 3); } { ValueT a[] = {1, 1, 1}; - auto ret = std::ranges::find(a, 0); + auto ret = std::ranges::find(a, 0); assert(ret == a + 3); } } @@ -146,7 +149,7 @@ constexpr bool test() { int comp; int other; }; - S a[] = { {0, 0}, {0, 2}, {0, 1} }; + S a[] = {{0, 0}, {0, 2}, {0, 1}}; auto ret = std::ranges::find(a, 0, &S::comp); assert(ret == a); assert(ret->comp == 0); @@ -157,7 +160,7 @@ constexpr bool test() { int comp; int other; }; - S a[] = { {0, 0}, {0, 2}, {0, 1} }; + S a[] = {{0, 0}, {0, 2}, {0, 1}}; auto ret = std::ranges::find(a, a + 3, 0, &S::comp); assert(ret == a); assert(ret->comp == 0); @@ -167,7 +170,7 @@ constexpr bool test() { { // check that an iterator is returned with a borrowing range - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; std::same_as<int*> auto ret = std::ranges::find(std::views::all(a), 1); assert(ret == a); assert(*ret == 1); @@ -176,23 +179,44 @@ constexpr bool test() { { // count invocations of the projection { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::find(a, a + 4, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::find(a, a + 4, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == a + 1); assert(*ret == 2); assert(projection_count == 2); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::find(a, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::find(a, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == a + 1); assert(*ret == 2); assert(projection_count == 2); } } + { // Test vector<bool>::iterator optimization + std::vector<bool> vec(256 + 8); + for (ptrdiff_t i = 8; i <= 256; i *= 2) { + for (size_t offset = 0; offset < 8; offset += 2) { + std::fill(vec.begin(), vec.end(), false); + std::fill(vec.begin() + offset, vec.begin() + i + offset, true); + + // check both range and iterator-sentinel overloads + assert(std::ranges::find(vec, true) == std::ranges::begin(vec) + offset); + assert(std::ranges::find(std::ranges::begin(vec) + offset, std::ranges::end(vec), false) == + std::ranges::begin(vec) + offset + i); + } + } + } + return true; } @@ -208,9 +232,7 @@ public: return size; }()) {} - bool operator==(const Comparable& other) const { - return comparable_data[other.index_] == comparable_data[index_]; - } + bool operator==(const Comparable& other) const { return comparable_data[other.index_] == comparable_data[index_]; } friend bool operator==(const Comparable& lhs, long long rhs) { return comparable_data[lhs.index_] == rhs; } }; |