From 241835d601fe0a0398570b6a87f1235e91b75445 Mon Sep 17 00:00:00 2001 From: Peng Liu <winner245@hotmail.com> Date: Fri, 27 Dec 2024 08:20:39 -0500 Subject: [PATCH 1/3] Augment ranges::{fill, fill_n, find} with missing tests --- .../alg.fill/fill.pass.cpp | 52 +++--------- .../alg.fill/fill_n.pass.cpp | 17 +++- .../alg.fill/ranges.fill.pass.cpp | 14 +++- .../alg.fill/ranges.fill_n.pass.cpp | 12 +++ .../alg.count/ranges.count.pass.cpp | 79 +++++++++++-------- .../alg.nonmodifying/alg.find/find.pass.cpp | 15 ++++ .../alg.find/ranges.find.pass.cpp | 58 +++++++++----- 7 files changed, 151 insertions(+), 96 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 0e532ae834e7f..a0d04b2c2ab07 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 @@ -84,48 +84,16 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { 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); - 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); - 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); - 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); - assert(in == expected); + + { // Test vector<bool>::iterator optimization + for (std::size_t N = 8; N <= 256; N *= 2) { + // Test with both full and partial bytes + for (std::size_t offset = 0; offset <= 4; offset += 4) { + std::vector<bool> in(N + 2 * offset); + std::vector<bool> expected(N, true); + std::fill(in.begin() + offset, in.end() - offset, true); + assert(std::equal(in.begin() + offset, in.end() - offset, expected.begin())); + } } } 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 98c412fb6cdc0..d2c8eb02ab05e 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 @@ -169,8 +169,21 @@ TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::forward_iterator_list<int*>(), Test<int>()); test_int_array(); - test_struct_array(); - test_int_array_struct_source(); + test_struct_array(); + test_int_array_struct_source(); + + { // Test vector<bool>::iterator optimization + for (std::size_t N = 8; N <= 256; N *= 2) { + // Test with both full and partial bytes + for (std::size_t offset = 0; offset <= 4; offset += 4) { + std::vector<bool> in(N + 2 * offset); + std::vector<bool> expected(N, true); + std::fill_n(in.begin() + offset, N + offset, true); + assert(std::equal(in.begin() + offset, in.end() - offset, expected.begin())); + } + } + } + test_bititer_with_custom_sized_types(); 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 30dfdd5486f5b..b48c89b6e454d 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 @@ -173,7 +173,19 @@ constexpr bool test() { } } -#if TEST_STD_VER >= 23 +#if TEST_STD_VER >= 23 + { // Test vector<bool>::iterator optimization + for (std::size_t N = 8; N <= 256; N *= 2) { + // Test with both full and partial bytes + for (std::size_t offset : {0, 4}) { + std::vector<bool> in(N + 2 * offset); + std::vector<bool> expected(N, true); + std::ranges::fill(std::ranges::begin(in) + offset, std::ranges::end(in) - offset, true); + assert(std::equal(in.begin() + offset, in.end() - offset, expected.begin())); + } + } + } + test_bititer_with_custom_sized_types(); #endif 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 ae70e7155f67f..c49baa2b05ac9 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 @@ -122,6 +122,18 @@ constexpr bool test() { } #if TEST_STD_VER >= 23 + { // Test vector<bool>::iterator optimization + for (std::size_t N = 8; N <= 256; N *= 2) { + // Test with both full and partial bytes + for (std::size_t offset : {0, 4}) { + std::vector<bool> in(N + 2 * offset); + std::vector<bool> expected(N, true); + std::ranges::fill_n(std::ranges::begin(in) + offset, N, true); + assert(std::equal(in.begin() + offset, in.end() - offset, expected.begin())); + } + } + } + test_bititer_with_custom_sized_types(); #endif diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp index 6030bed47ec6a..877b6fa34e5bc 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp @@ -67,13 +67,13 @@ constexpr void test_iterators() { { // simple test { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(It(a), Sent(It(a + 4)), 3); assert(ret == 1); } { - int a[] = {1, 2, 3, 4}; - auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); + int a[] = {1, 2, 3, 4}; + auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(range, 3); assert(ret == 1); } @@ -83,13 +83,13 @@ constexpr void test_iterators() { // check that an empty range works { std::array<int, 0> a = {}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1); assert(ret == 0); } { std::array<int, 0> a = {}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 1); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 1); assert(ret == 0); } } @@ -98,13 +98,13 @@ constexpr void test_iterators() { // check that a range with a single element works { std::array a = {2}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2); assert(ret == 1); } { std::array a = {2}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 2); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 2); assert(ret == 1); } } @@ -113,13 +113,13 @@ constexpr void test_iterators() { // check that 0 is returned with no match { std::array a = {1, 1, 1}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0); assert(ret == 0); } { std::array a = {1, 1, 1}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 0); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 0); assert(ret == 0); } } @@ -128,13 +128,13 @@ constexpr void test_iterators() { // check that more than one element is counted { std::array a = {3, 3, 4, 3, 3}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3); assert(ret == 4); } { std::array a = {3, 3, 4, 3, 3}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 3); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 3); assert(ret == 4); } } @@ -143,13 +143,13 @@ constexpr void test_iterators() { // check that all elements are counted { std::array a = {5, 5, 5, 5}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5); assert(ret == 4); } { std::array a = {5, 5, 5, 5}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 5); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 5); assert(ret == 4); } } @@ -167,12 +167,12 @@ constexpr bool test() { { // check that projections are used properly and that they are called with the iterator directly { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; auto ret = std::ranges::count(a, a + 4, a + 3, [](int& i) { return &i; }); assert(ret == 1); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; auto ret = std::ranges::count(a, a + 3, [](int& i) { return &i; }); assert(ret == 1); } @@ -180,8 +180,10 @@ constexpr bool test() { { // check that std::invoke is used - struct S { int i; }; - S a[] = { S{1}, S{3}, S{2} }; + struct S { + int i; + }; + S a[] = {S{1}, S{3}, S{2}}; std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(a, 4, &S::i); assert(ret == 0); } @@ -189,16 +191,22 @@ 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::count(a, a + 4, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::count(a, a + 4, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == 1); assert(projection_count == 4); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::count(a, 2, [&](int i) { ++projection_count; return i; }); + auto ret = std::ranges::count(a, 2, [&](int i) { + ++projection_count; + return i; + }); assert(ret == 1); assert(projection_count == 4); } @@ -208,7 +216,7 @@ constexpr bool test() { // check that an immobile type works struct NonMovable { NonMovable(const NonMovable&) = delete; - NonMovable(NonMovable&&) = delete; + NonMovable(NonMovable&&) = delete; constexpr NonMovable(int i_) : i(i_) {} int i; @@ -216,12 +224,12 @@ constexpr bool test() { }; { NonMovable a[] = {9, 8, 4, 3}; - auto ret = std::ranges::count(a, a + 4, NonMovable(8)); + auto ret = std::ranges::count(a, a + 4, NonMovable(8)); assert(ret == 1); } { NonMovable a[] = {9, 8, 4, 3}; - auto ret = std::ranges::count(a, NonMovable(8)); + auto ret = std::ranges::count(a, NonMovable(8)); assert(ret == 1); } } @@ -230,7 +238,7 @@ constexpr bool test() { // check that difference_type is used struct DiffTypeIterator { using difference_type = signed char; - using value_type = int; + using value_type = int; int* it = nullptr; @@ -238,7 +246,10 @@ constexpr bool test() { constexpr DiffTypeIterator(int* i) : it(i) {} constexpr int& operator*() const { return *it; } - constexpr DiffTypeIterator& operator++() { ++it; return *this; } + constexpr DiffTypeIterator& operator++() { + ++it; + return *this; + } constexpr void operator++(int) { ++it; } bool operator==(const DiffTypeIterator&) const = default; @@ -251,7 +262,7 @@ constexpr bool test() { assert(ret == 1); } { - int a[] = {5, 5, 4, 3, 2, 1}; + int a[] = {5, 5, 4, 3, 2, 1}; auto range = std::ranges::subrange(DiffTypeIterator(a), DiffTypeIterator(a + 6)); std::same_as<signed char> decltype(auto) ret = std::ranges::count(range, 4); assert(ret == 1); @@ -264,7 +275,9 @@ constexpr bool test() { for (size_t offset = 0; offset != 64; ++offset) { std::fill(vec.begin(), vec.end(), false); std::fill(vec.begin() + offset, vec.begin() + i + offset, true); - assert(std::ranges::count(vec.begin() + offset, vec.begin() + offset + 256, true) == i); + + // check both (range) and (iterator, sentinel) overloads + assert(std::ranges::count(vec, true) == i); assert(std::ranges::count(vec.begin() + offset, vec.begin() + offset + 256, false) == 256 - i); } } 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 2dbad321b782e..e916fd9d8bd3c 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.begin() + i + offset, 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 760ee231bb9b6..9473d6ecf890a 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 @@ class Comparable { 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; } }; From df759c7d5429f00a3ec9c55c4e9a14deb63fcc76 Mon Sep 17 00:00:00 2001 From: Peng Liu <winner245@hotmail.com> Date: Thu, 30 Jan 2025 10:27:35 -0500 Subject: [PATCH 2/3] Add test cases for odd-sized vector<bool> --- .../alg.fill/fill.pass.cpp | 33 +++++--- .../alg.fill/fill_n.pass.cpp | 39 ++++++--- .../alg.fill/ranges.fill.pass.cpp | 35 +++++--- .../alg.fill/ranges.fill_n.pass.cpp | 33 +++++--- .../alg.count/ranges.count.pass.cpp | 79 ++++++++----------- .../alg.nonmodifying/alg.find/find.pass.cpp | 2 +- .../alg.find/ranges.find.pass.cpp | 2 +- 7 files changed, 135 insertions(+), 88 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 a0d04b2c2ab07..42c72f310d6dd 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,6 +48,23 @@ struct Test { } }; +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + { // Test with full bytes + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::fill(in.begin(), in.end(), true); + assert(in == expected); + } + { // Test with partial bytes with offset + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::fill(in.begin() + 4, in.end() - 4, true); + assert(std::equal(in.begin() + 4, in.end() - 4, expected.begin())); + } + + return true; +} + // 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() { @@ -86,15 +103,13 @@ TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::forward_iterator_list<int*>(), Test<int>()); { // Test vector<bool>::iterator optimization - for (std::size_t N = 8; N <= 256; N *= 2) { - // Test with both full and partial bytes - for (std::size_t offset = 0; offset <= 4; offset += 4) { - std::vector<bool> in(N + 2 * offset); - std::vector<bool> expected(N, true); - std::fill(in.begin() + offset, in.end() - offset, true); - assert(std::equal(in.begin() + offset, in.end() - offset, expected.begin())); - } - } + 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)); } test_bititer_with_custom_sized_types(); 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 d2c8eb02ab05e..5327bf03c0bbf 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,6 +109,23 @@ struct Storage { }; }; +TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { + { // Test with full bytes + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::fill_n(in.begin(), N, true); + assert(in == expected); + } + { // Test with partial bytes with offset + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::fill_n(in.begin() + 4, N - 4, true); + assert(std::equal(in.begin() + 4, in.end() - 4, expected.begin())); + } + + return true; +} + // 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() { @@ -169,21 +186,19 @@ TEST_CONSTEXPR_CXX20 bool test() { types::for_each(types::forward_iterator_list<int*>(), Test<int>()); test_int_array(); - test_struct_array(); - test_int_array_struct_source(); + test_struct_array(); + test_int_array_struct_source(); { // Test vector<bool>::iterator optimization - for (std::size_t N = 8; N <= 256; N *= 2) { - // Test with both full and partial bytes - for (std::size_t offset = 0; offset <= 4; offset += 4) { - std::vector<bool> in(N + 2 * offset); - std::vector<bool> expected(N, true); - std::fill_n(in.begin() + offset, N + offset, true); - assert(std::equal(in.begin() + offset, in.end() - offset, expected.begin())); - } - } + 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)); } - + test_bititer_with_custom_sized_types(); 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 b48c89b6e454d..583d857cbbb3c 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 @@ -115,6 +115,23 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { assert(in == expected); } } + +constexpr bool test_vector_bool(std::size_t N) { + { // Test with full bytes + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::ranges::fill(std::ranges::begin(in), std::ranges::end(in), true); + assert(in == expected); + } + { // Test with partial bytes with offset + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::ranges::fill(std::ranges::begin(in) + 4, std::ranges::end(in) - 4, true); + assert(std::equal(in.begin() + 4, in.end() - 4, expected.begin())); + } + + return true; +} #endif constexpr bool test() { @@ -173,17 +190,15 @@ constexpr bool test() { } } -#if TEST_STD_VER >= 23 +#if TEST_STD_VER >= 23 { // Test vector<bool>::iterator optimization - for (std::size_t N = 8; N <= 256; N *= 2) { - // Test with both full and partial bytes - for (std::size_t offset : {0, 4}) { - std::vector<bool> in(N + 2 * offset); - std::vector<bool> expected(N, true); - std::ranges::fill(std::ranges::begin(in) + offset, std::ranges::end(in) - offset, true); - assert(std::equal(in.begin() + offset, in.end() - offset, expected.begin())); - } - } + 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)); } test_bititer_with_custom_sized_types(); 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 c49baa2b05ac9..3f23fb0fc4ffe 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 @@ -88,6 +88,23 @@ TEST_CONSTEXPR_CXX20 void test_bititer_with_custom_sized_types() { assert(in == expected); } } + +constexpr bool test_vector_bool(std::size_t N) { + { // Test with full bytes + 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); + } + { // Test with partial bytes with offset + std::vector<bool> in(N, false); + std::vector<bool> expected(N, true); + std::ranges::fill_n(std::ranges::begin(in) + 4, N - 4, true); + assert(std::equal(in.begin() + 4, in.end(), expected.begin())); + } + + return true; +} #endif constexpr bool test() { @@ -123,15 +140,13 @@ constexpr bool test() { #if TEST_STD_VER >= 23 { // Test vector<bool>::iterator optimization - for (std::size_t N = 8; N <= 256; N *= 2) { - // Test with both full and partial bytes - for (std::size_t offset : {0, 4}) { - std::vector<bool> in(N + 2 * offset); - std::vector<bool> expected(N, true); - std::ranges::fill_n(std::ranges::begin(in) + offset, N, true); - assert(std::equal(in.begin() + offset, in.end() - offset, expected.begin())); - } - } + 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)); } test_bititer_with_custom_sized_types(); diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp index 877b6fa34e5bc..6030bed47ec6a 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.count/ranges.count.pass.cpp @@ -67,13 +67,13 @@ constexpr void test_iterators() { { // simple test { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(It(a), Sent(It(a + 4)), 3); assert(ret == 1); } { - int a[] = {1, 2, 3, 4}; - auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); + int a[] = {1, 2, 3, 4}; + auto range = std::ranges::subrange(It(a), Sent(It(a + 4))); std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(range, 3); assert(ret == 1); } @@ -83,13 +83,13 @@ constexpr void test_iterators() { // check that an empty range works { std::array<int, 0> a = {}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 1); assert(ret == 0); } { std::array<int, 0> a = {}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 1); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 1); assert(ret == 0); } } @@ -98,13 +98,13 @@ constexpr void test_iterators() { // check that a range with a single element works { std::array a = {2}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 2); assert(ret == 1); } { std::array a = {2}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 2); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 2); assert(ret == 1); } } @@ -113,13 +113,13 @@ constexpr void test_iterators() { // check that 0 is returned with no match { std::array a = {1, 1, 1}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 0); assert(ret == 0); } { std::array a = {1, 1, 1}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 0); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 0); assert(ret == 0); } } @@ -128,13 +128,13 @@ constexpr void test_iterators() { // check that more than one element is counted { std::array a = {3, 3, 4, 3, 3}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 3); assert(ret == 4); } { std::array a = {3, 3, 4, 3, 3}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 3); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 3); assert(ret == 4); } } @@ -143,13 +143,13 @@ constexpr void test_iterators() { // check that all elements are counted { std::array a = {5, 5, 5, 5}; - auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5); + auto ret = std::ranges::count(It(a.data()), Sent(It(a.data() + a.size())), 5); assert(ret == 4); } { std::array a = {5, 5, 5, 5}; - auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); - auto ret = std::ranges::count(range, 5); + auto range = std::ranges::subrange(It(a.data()), Sent(It(a.data() + a.size()))); + auto ret = std::ranges::count(range, 5); assert(ret == 4); } } @@ -167,12 +167,12 @@ constexpr bool test() { { // check that projections are used properly and that they are called with the iterator directly { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; auto ret = std::ranges::count(a, a + 4, a + 3, [](int& i) { return &i; }); assert(ret == 1); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; auto ret = std::ranges::count(a, a + 3, [](int& i) { return &i; }); assert(ret == 1); } @@ -180,10 +180,8 @@ constexpr bool test() { { // check that std::invoke is used - struct S { - int i; - }; - S a[] = {S{1}, S{3}, S{2}}; + struct S { int i; }; + S a[] = { S{1}, S{3}, S{2} }; std::same_as<std::ptrdiff_t> auto ret = std::ranges::count(a, 4, &S::i); assert(ret == 0); } @@ -191,22 +189,16 @@ 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::count(a, a + 4, 2, [&](int i) { - ++projection_count; - return i; - }); + auto ret = std::ranges::count(a, a + 4, 2, [&](int i) { ++projection_count; return i; }); assert(ret == 1); assert(projection_count == 4); } { - int a[] = {1, 2, 3, 4}; + int a[] = {1, 2, 3, 4}; int projection_count = 0; - auto ret = std::ranges::count(a, 2, [&](int i) { - ++projection_count; - return i; - }); + auto ret = std::ranges::count(a, 2, [&](int i) { ++projection_count; return i; }); assert(ret == 1); assert(projection_count == 4); } @@ -216,7 +208,7 @@ constexpr bool test() { // check that an immobile type works struct NonMovable { NonMovable(const NonMovable&) = delete; - NonMovable(NonMovable&&) = delete; + NonMovable(NonMovable&&) = delete; constexpr NonMovable(int i_) : i(i_) {} int i; @@ -224,12 +216,12 @@ constexpr bool test() { }; { NonMovable a[] = {9, 8, 4, 3}; - auto ret = std::ranges::count(a, a + 4, NonMovable(8)); + auto ret = std::ranges::count(a, a + 4, NonMovable(8)); assert(ret == 1); } { NonMovable a[] = {9, 8, 4, 3}; - auto ret = std::ranges::count(a, NonMovable(8)); + auto ret = std::ranges::count(a, NonMovable(8)); assert(ret == 1); } } @@ -238,7 +230,7 @@ constexpr bool test() { // check that difference_type is used struct DiffTypeIterator { using difference_type = signed char; - using value_type = int; + using value_type = int; int* it = nullptr; @@ -246,10 +238,7 @@ constexpr bool test() { constexpr DiffTypeIterator(int* i) : it(i) {} constexpr int& operator*() const { return *it; } - constexpr DiffTypeIterator& operator++() { - ++it; - return *this; - } + constexpr DiffTypeIterator& operator++() { ++it; return *this; } constexpr void operator++(int) { ++it; } bool operator==(const DiffTypeIterator&) const = default; @@ -262,7 +251,7 @@ constexpr bool test() { assert(ret == 1); } { - int a[] = {5, 5, 4, 3, 2, 1}; + int a[] = {5, 5, 4, 3, 2, 1}; auto range = std::ranges::subrange(DiffTypeIterator(a), DiffTypeIterator(a + 6)); std::same_as<signed char> decltype(auto) ret = std::ranges::count(range, 4); assert(ret == 1); @@ -275,9 +264,7 @@ constexpr bool test() { for (size_t offset = 0; offset != 64; ++offset) { 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::count(vec, true) == i); + assert(std::ranges::count(vec.begin() + offset, vec.begin() + offset + 256, true) == i); assert(std::ranges::count(vec.begin() + offset, vec.begin() + offset + 256, false) == 256 - i); } } 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 e916fd9d8bd3c..dd89f2c5ae944 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 @@ -234,7 +234,7 @@ TEST_CONSTEXPR_CXX20 bool test() { 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.begin() + i + offset, true) == vec.begin() + offset); + assert(std::find(vec.begin(), vec.end(), true) == vec.begin() + offset); assert(std::find(vec.begin() + offset, vec.end(), false) == vec.begin() + offset + i); } } 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 9473d6ecf890a..46accc5e36f0a 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 @@ -209,7 +209,7 @@ constexpr bool test() { std::fill(vec.begin(), vec.end(), false); std::fill(vec.begin() + offset, vec.begin() + i + offset, true); - // check both (range) and (iterator, sentinel) overloads + // 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); From 34bbd487c714fd66ebea8a5b65fa95ba832d6f5a Mon Sep 17 00:00:00 2001 From: Peng Liu <winner245@hotmail.com> Date: Thu, 20 Feb 2025 18:15:22 -0500 Subject: [PATCH 3/3] Fix test coverage and inline tests for vector<bool> --- .../alg.fill/fill.pass.cpp | 114 ++++++++++------- .../alg.fill/fill_n.pass.cpp | 114 ++++++++++------- .../alg.fill/ranges.fill.pass.cpp | 115 +++++++++++------- .../alg.fill/ranges.fill_n.pass.cpp | 115 +++++++++++------- 4 files changed, 276 insertions(+), 182 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 42c72f310d6dd..9b403db85ebf9 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 @@ -49,55 +49,50 @@ struct Test { }; TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { - { // Test with full bytes - std::vector<bool> in(N, false); - std::vector<bool> expected(N, true); - std::fill(in.begin(), in.end(), true); - assert(in == expected); + { // 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); + } } - { // Test with partial bytes with offset - std::vector<bool> in(N, false); - std::vector<bool> expected(N, true); - std::fill(in.begin() + 4, in.end() - 4, true); - assert(std::equal(in.begin() + 4, in.end() - 4, expected.begin())); + + { // 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; } -// 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); - } - { - 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_CONSTEXPR_CXX20 bool test() { types::for_each(types::forward_iterator_list<char*>(), Test<char>()); types::for_each(types::forward_iterator_list<int*>(), Test<int>()); @@ -110,9 +105,38 @@ TEST_CONSTEXPR_CXX20 bool test() { assert(test_vector_bool(64)); assert(test_vector_bool(199)); assert(test_vector_bool(256)); - } - test_bititer_with_custom_sized_types(); + // 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); + } + { + 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); + } + { + 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); + } + } 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 5327bf03c0bbf..4dda8714d2cfa 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 @@ -110,55 +110,50 @@ struct Storage { }; TEST_CONSTEXPR_CXX20 bool test_vector_bool(std::size_t N) { - { // Test with full bytes - std::vector<bool> in(N, false); - std::vector<bool> expected(N, true); - std::fill_n(in.begin(), N, true); - assert(in == expected); + { // 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); + } } - { // Test with partial bytes with offset - std::vector<bool> in(N, false); - std::vector<bool> expected(N, true); - std::fill_n(in.begin() + 4, N - 4, true); - assert(std::equal(in.begin() + 4, in.end() - 4, expected.begin())); + + { // 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; } -// 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); - } - { - 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_CONSTEXPR_CXX20 void test_struct_array() { { A a[3]; @@ -197,9 +192,38 @@ TEST_CONSTEXPR_CXX20 bool test() { assert(test_vector_bool(64)); assert(test_vector_bool(199)); assert(test_vector_bool(256)); - } - test_bititer_with_custom_sized_types(); + // 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 583d857cbbb3c..61a659fb0028c 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,56 +78,50 @@ 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); - } - { - 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); - } -} - constexpr bool test_vector_bool(std::size_t N) { - { // Test with full bytes - std::vector<bool> in(N, false); - std::vector<bool> expected(N, true); - std::ranges::fill(std::ranges::begin(in), std::ranges::end(in), true); - assert(in == expected); + { // 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); + } } - { // Test with partial bytes with offset - std::vector<bool> in(N, false); - std::vector<bool> expected(N, true); - std::ranges::fill(std::ranges::begin(in) + 4, std::ranges::end(in) - 4, true); - assert(std::equal(in.begin() + 4, in.end() - 4, expected.begin())); + + { // 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; @@ -199,9 +193,38 @@ constexpr bool test() { assert(test_vector_bool(64)); assert(test_vector_bool(199)); assert(test_vector_bool(256)); - } - test_bititer_with_custom_sized_types(); + // 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 3f23fb0fc4ffe..2d6e24a03e0b3 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,56 +51,50 @@ 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); - } - { - 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); - } -} - constexpr bool test_vector_bool(std::size_t N) { - { // Test with full bytes - 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); + { // 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); + } } - { // Test with partial bytes with offset - std::vector<bool> in(N, false); - std::vector<bool> expected(N, true); - std::ranges::fill_n(std::ranges::begin(in) + 4, N - 4, true); - assert(std::equal(in.begin() + 4, in.end(), expected.begin())); + + { // 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; @@ -147,9 +141,38 @@ constexpr bool test() { assert(test_vector_bool(64)); assert(test_vector_bool(199)); assert(test_vector_bool(256)); - } - test_bititer_with_custom_sized_types(); + // 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;