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/alg.modifying.operations | |
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/alg.modifying.operations')
4 files changed, 316 insertions, 157 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; |