[libcxx-commits] [libcxx] 9dc854c - [libc++] Improve test coverage for copy/move ctors for vector<bool> (#120132)
via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Mar 20 05:37:42 PDT 2025
Author: Peng Liu
Date: 2025-03-20T08:37:39-04:00
New Revision: 9dc854ccbd3d29c8dcf6b81b691724c9fc4bfc6c
URL: https://github.com/llvm/llvm-project/commit/9dc854ccbd3d29c8dcf6b81b691724c9fc4bfc6c
DIFF: https://github.com/llvm/llvm-project/commit/9dc854ccbd3d29c8dcf6b81b691724c9fc4bfc6c.diff
LOG: [libc++] Improve test coverage for copy/move ctors for vector<bool> (#120132)
The current tests for `vector<bool>` fail to adequately cover realistic
scenarios, as they are limited to cases of up to 3 bytes, representing
less than 1/2 of a word size on a 64-bit system. However, most
`vector<bool>` operations rely on code paths triggered only when
handling multiple storage words (8 bytes each). To address this gap,
this PR rewrites the tests for copy and move constructors, as well as
allocator-extended copy and move constructors, ensuring that previously
untested code paths are now thoroughly validated.
Added:
Modified:
libcxx/test/std/containers/sequences/vector.bool/copy.pass.cpp
libcxx/test/std/containers/sequences/vector.bool/copy_alloc.pass.cpp
libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
libcxx/test/std/containers/sequences/vector.bool/move_alloc.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/test/std/containers/sequences/vector.bool/copy.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/copy.pass.cpp
index 15b26e8054df8..ba957471927c3 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/copy.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/copy.pass.cpp
@@ -11,12 +11,13 @@
// vector(const vector& v);
-#include <vector>
+#include <array>
#include <cassert>
+#include <vector>
-#include "test_macros.h"
-#include "test_allocator.h"
#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
template <class C>
TEST_CONSTEXPR_CXX20 void test(const C& x) {
@@ -25,39 +26,56 @@ TEST_CONSTEXPR_CXX20 void test(const C& x) {
LIBCPP_ASSERT(c.__invariants());
assert(c.size() == s);
assert(c == x);
+#if TEST_STD_VER >= 11
+ assert(c.get_allocator() ==
+ std::allocator_traits<typename C::allocator_type>::select_on_container_copy_construction(x.get_allocator()));
+#endif
}
TEST_CONSTEXPR_CXX20 bool tests() {
- {
- bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
- bool* an = a + sizeof(a) / sizeof(a[0]);
- test(std::vector<bool>(a, an));
- }
- {
- std::vector<bool, test_allocator<bool> > v(3, true, test_allocator<bool>(5));
- std::vector<bool, test_allocator<bool> > v2 = v;
- assert(v2 == v);
- assert(v2.get_allocator() == v.get_allocator());
+ std::array<int, 5> a1 = {1, 0, 1, 0, 1};
+ std::array<int, 18> a2 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 33> a3 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 65> a4 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 299> a5 = {};
+ for (unsigned i = 0; i < a5.size(); i += 2)
+ a5[i] = 1;
+
+ // Tests for vector<bool> copy constructor with word size up to 5 (i.e., bit size > 256 on a 64-bit system)
+ { // Test with default std::allocator
+ test(std::vector<bool>(a1.begin(), a1.end()));
+ test(std::vector<bool>(a2.begin(), a2.end()));
+ test(std::vector<bool>(a3.begin(), a3.end()));
+ test(std::vector<bool>(a4.begin(), a4.end()));
+ test(std::vector<bool>(a5.begin(), a5.end()));
}
-#if TEST_STD_VER >= 11
- {
- std::vector<bool, other_allocator<bool> > v(3, true, other_allocator<bool>(5));
- std::vector<bool, other_allocator<bool> > v2 = v;
- assert(v2 == v);
- assert(v2.get_allocator() == other_allocator<bool>(-2));
+ { // Test with test_allocator
+ using A = test_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end()));
+ test(C(a2.begin(), a2.end()));
+ test(C(a3.begin(), a3.end()));
+ test(C(a4.begin(), a4.end()));
+ test(C(a5.begin(), a5.end()));
}
- {
- bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
- bool* an = a + sizeof(a) / sizeof(a[0]);
- test(std::vector<bool, min_allocator<bool>>(a, an));
+ { // Test with other_allocator
+ using A = other_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end()));
+ test(C(a2.begin(), a2.end()));
+ test(C(a3.begin(), a3.end()));
+ test(C(a4.begin(), a4.end()));
+ test(C(a5.begin(), a5.end()));
}
- {
- std::vector<bool, min_allocator<bool> > v(3, true, min_allocator<bool>());
- std::vector<bool, min_allocator<bool> > v2 = v;
- assert(v2 == v);
- assert(v2.get_allocator() == v.get_allocator());
+ { // Test with min_allocator
+ using A = min_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end()));
+ test(C(a2.begin(), a2.end()));
+ test(C(a3.begin(), a3.end()));
+ test(C(a4.begin(), a4.end()));
+ test(C(a5.begin(), a5.end()));
}
-#endif
return true;
}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/copy_alloc.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/copy_alloc.pass.cpp
index d22b7c5d58447..17967ff2713cd 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/copy_alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/copy_alloc.pass.cpp
@@ -7,15 +7,17 @@
//===----------------------------------------------------------------------===//
// <vector>
+// vector<bool>
// vector(const vector& v, const allocator_type& a);
-#include <vector>
+#include <array>
#include <cassert>
+#include <vector>
-#include "test_macros.h"
-#include "test_allocator.h"
#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
template <class C>
TEST_CONSTEXPR_CXX20 void test(const C& x, const typename C::allocator_type& a) {
@@ -24,39 +26,53 @@ TEST_CONSTEXPR_CXX20 void test(const C& x, const typename C::allocator_type& a)
LIBCPP_ASSERT(c.__invariants());
assert(c.size() == s);
assert(c == x);
+ assert(c.get_allocator() == a);
}
TEST_CONSTEXPR_CXX20 bool tests() {
- {
- bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
- bool* an = a + sizeof(a) / sizeof(a[0]);
- test(std::vector<bool>(a, an), std::allocator<bool>());
- }
- {
- std::vector<bool, test_allocator<bool> > l(3, true, test_allocator<bool>(5));
- std::vector<bool, test_allocator<bool> > l2(l, test_allocator<bool>(3));
- assert(l2 == l);
- assert(l2.get_allocator() == test_allocator<bool>(3));
+ std::array<int, 5> a1 = {1, 0, 1, 0, 1};
+ std::array<int, 18> a2 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 33> a3 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 65> a4 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 299> a5 = {};
+ for (unsigned i = 0; i < a5.size(); i += 2)
+ a5[i] = 1;
+
+ // Tests for allocator-extended copy constructor with word size up to 5 (i.e., bit size > 256 on a 64-bit system)
+ { // Test with the default std::allocator
+ test(std::vector<bool>(a1.begin(), a1.end()), std::allocator<bool>());
+ test(std::vector<bool>(a2.begin(), a2.end()), std::allocator<bool>());
+ test(std::vector<bool>(a3.begin(), a3.end()), std::allocator<bool>());
+ test(std::vector<bool>(a4.begin(), a4.end()), std::allocator<bool>());
+ test(std::vector<bool>(a5.begin(), a5.end()), std::allocator<bool>());
}
- {
- std::vector<bool, other_allocator<bool> > l(3, true, other_allocator<bool>(5));
- std::vector<bool, other_allocator<bool> > l2(l, other_allocator<bool>(3));
- assert(l2 == l);
- assert(l2.get_allocator() == other_allocator<bool>(3));
+ { // Test with test_allocator
+ using A = test_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end(), A(5)), A(3));
+ test(C(a2.begin(), a2.end(), A(5)), A(3));
+ test(C(a3.begin(), a3.end(), A(5)), A(3));
+ test(C(a4.begin(), a4.end(), A(5)), A(3));
+ test(C(a5.begin(), a5.end(), A(5)), A(3));
}
-#if TEST_STD_VER >= 11
- {
- bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
- bool* an = a + sizeof(a) / sizeof(a[0]);
- test(std::vector<bool, min_allocator<bool>>(a, an), min_allocator<bool>());
+ { // Test with other_allocator
+ using A = other_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end(), A(5)), A(3));
+ test(C(a2.begin(), a2.end(), A(5)), A(3));
+ test(C(a3.begin(), a3.end(), A(5)), A(3));
+ test(C(a4.begin(), a4.end(), A(5)), A(3));
+ test(C(a5.begin(), a5.end(), A(5)), A(3));
}
- {
- std::vector<bool, min_allocator<bool> > l(3, true, min_allocator<bool>());
- std::vector<bool, min_allocator<bool> > l2(l, min_allocator<bool>());
- assert(l2 == l);
- assert(l2.get_allocator() == min_allocator<bool>());
+ { // Test with min_allocator
+ using A = min_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end(), A()), A());
+ test(C(a2.begin(), a2.end(), A()), A());
+ test(C(a3.begin(), a3.end(), A()), A());
+ test(C(a4.begin(), a4.end(), A()), A());
+ test(C(a5.begin(), a5.end(), A()), A());
}
-#endif
return true;
}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
index a69f0b5738986..d1217ddbca89d 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
@@ -9,54 +9,70 @@
// UNSUPPORTED: c++03
// <vector>
+// vector<bool>
// vector(vector&& c);
-#include <vector>
+#include <array>
#include <cassert>
-#include "test_macros.h"
-#include "test_allocator.h"
+#include <vector>
+
#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+template <unsigned N, class A>
+TEST_CONSTEXPR_CXX20 void test(const A& a) {
+ std::vector<bool, A> v(N, false, a);
+ std::vector<bool, A> original(N, false, a);
+ for (unsigned i = 1; i < N; i += 2) {
+ v[i] = true;
+ original[i] = true;
+ }
+ std::vector<bool, A> v2 = std::move(v);
+ assert(v2 == original);
+ assert(v.empty()); // The moved-from vector is guaranteed to be empty after move-construction
+ assert(v2.get_allocator() == original.get_allocator());
+}
TEST_CONSTEXPR_CXX20 bool tests() {
test_allocator_statistics alloc_stats;
+
+ // Tests for move constructor with word size up to 5 (i.e., bit size > 256 for 64-bit system)
{
- std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5, &alloc_stats));
- std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5, &alloc_stats));
- for (int i = 1; i <= 3; ++i) {
- l.push_back(true);
- lo.push_back(true);
- }
- std::vector<bool, test_allocator<bool> > l2 = std::move(l);
- assert(l2 == lo);
- assert(l.empty());
- assert(l2.get_allocator() == lo.get_allocator());
+ using A = std::allocator<bool>;
+ test<5>(A());
+ test<18>(A());
+ test<33>(A());
+ test<65>(A());
+ test<299>(A());
}
{
- std::vector<bool, other_allocator<bool> > l(other_allocator<bool>(5));
- std::vector<bool, other_allocator<bool> > lo(other_allocator<bool>(5));
- for (int i = 1; i <= 3; ++i) {
- l.push_back(true);
- lo.push_back(true);
- }
- std::vector<bool, other_allocator<bool> > l2 = std::move(l);
- assert(l2 == lo);
- assert(l.empty());
- assert(l2.get_allocator() == lo.get_allocator());
+ using A = other_allocator<bool>;
+ test<5>(A(5));
+ test<18>(A(5));
+ test<33>(A(5));
+ test<65>(A(5));
+ test<299>(A(5));
}
{
- std::vector<bool, min_allocator<bool> > l(min_allocator<bool>{});
- std::vector<bool, min_allocator<bool> > lo(min_allocator<bool>{});
- for (int i = 1; i <= 3; ++i) {
- l.push_back(true);
- lo.push_back(true);
- }
- std::vector<bool, min_allocator<bool> > l2 = std::move(l);
- assert(l2 == lo);
- assert(l.empty());
- assert(l2.get_allocator() == lo.get_allocator());
+ using A = min_allocator<bool>;
+ test<5>(A());
+ test<18>(A());
+ test<33>(A());
+ test<65>(A());
+ test<299>(A());
}
{
+ using A = test_allocator<bool>;
+ test<5>(A(5, &alloc_stats));
+ test<18>(A(5, &alloc_stats));
+ test<33>(A(5, &alloc_stats));
+ test<65>(A(5, &alloc_stats));
+ test<299>(A(5, &alloc_stats));
+ }
+
+ { // Tests to verify the allocator statistics after move
alloc_stats.clear();
using Vect = std::vector<bool, test_allocator<bool> >;
using AllocT = Vect::allocator_type;
@@ -83,7 +99,6 @@ TEST_CONSTEXPR_CXX20 bool tests() {
const AllocT& a2 = v2.get_allocator();
assert(a2.get_id() == 101);
assert(a2.get_data() == 42);
-
assert(a1 == a2);
}
}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/move_alloc.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/move_alloc.pass.cpp
index 01e7410040686..a6f28eb2f9f35 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/move_alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/move_alloc.pass.cpp
@@ -9,63 +9,79 @@
// UNSUPPORTED: c++03
// <vector>
+// vector<bool>
// vector(vector&& c, const allocator_type& a);
-#include <vector>
+#include <array>
#include <cassert>
-#include "test_macros.h"
-#include "test_allocator.h"
+#include <vector>
+
#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+template <unsigned N, class A>
+TEST_CONSTEXPR_CXX20 void test(const A& a, const A& a0) {
+ std::vector<bool, A> v(N, false, a);
+ std::vector<bool, A> original(N, false, a0);
+ for (unsigned i = 1; i < N; i += 2) {
+ v[i] = true;
+ original[i] = true;
+ }
+ std::vector<bool, A> v2(std::move(v), a0);
+ assert(v2 == original);
+ assert(v2.get_allocator() == a0);
+ if (a == a0)
+ assert(v.empty()); // After container-move, the vector is guaranteed to be empty
+ else
+ LIBCPP_ASSERT(!v.empty()); // After element-wise move, the RHS vector is not necessarily empty
+}
TEST_CONSTEXPR_CXX20 bool tests() {
- {
- std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
- std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
- for (int i = 1; i <= 3; ++i) {
- l.push_back(i);
- lo.push_back(i);
- }
- std::vector<bool, test_allocator<bool> > l2(std::move(l), test_allocator<bool>(6));
- assert(l2 == lo);
- assert(!l.empty());
- assert(l2.get_allocator() == test_allocator<bool>(6));
+ { // Test with default allocator: compatible allocators
+ using A = std::allocator<bool>;
+ test<5>(A(), A());
+ test<17>(A(), A());
+ test<65>(A(), A());
+ test<299>(A(), A());
}
- {
- std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
- std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
- for (int i = 1; i <= 3; ++i) {
- l.push_back(i);
- lo.push_back(i);
- }
- std::vector<bool, test_allocator<bool> > l2(std::move(l), test_allocator<bool>(5));
- assert(l2 == lo);
- assert(l.empty());
- assert(l2.get_allocator() == test_allocator<bool>(5));
+ { // Test with test_allocator: compatible and incompatible allocators
+ using A = test_allocator<bool>;
+
+ // Compatible allocators
+ test<5>(A(5), A(5));
+ test<17>(A(5), A(5));
+ test<65>(A(5), A(5));
+ test<299>(A(5), A(5));
+
+ // Incompatible allocators
+ test<5>(A(5), A(6));
+ test<17>(A(5), A(6));
+ test<65>(A(5), A(6));
+ test<299>(A(5), A(6));
}
- {
- std::vector<bool, other_allocator<bool> > l(other_allocator<bool>(5));
- std::vector<bool, other_allocator<bool> > lo(other_allocator<bool>(5));
- for (int i = 1; i <= 3; ++i) {
- l.push_back(i);
- lo.push_back(i);
- }
- std::vector<bool, other_allocator<bool> > l2(std::move(l), other_allocator<bool>(4));
- assert(l2 == lo);
- assert(!l.empty());
- assert(l2.get_allocator() == other_allocator<bool>(4));
+ { // Test with other_allocator: compatible and incompatible allocators
+ using A = other_allocator<bool>;
+
+ // Compatible allocators
+ test<5>(A(5), A(5));
+ test<17>(A(5), A(5));
+ test<65>(A(5), A(5));
+ test<299>(A(5), A(5));
+
+ // Incompatible allocators
+ test<5>(A(5), A(3));
+ test<17>(A(5), A(3));
+ test<65>(A(5), A(3));
+ test<299>(A(5), A(3));
}
- {
- std::vector<bool, min_allocator<bool> > l(min_allocator<bool>{});
- std::vector<bool, min_allocator<bool> > lo(min_allocator<bool>{});
- for (int i = 1; i <= 3; ++i) {
- l.push_back(i);
- lo.push_back(i);
- }
- std::vector<bool, min_allocator<bool> > l2(std::move(l), min_allocator<bool>());
- assert(l2 == lo);
- assert(l.empty());
- assert(l2.get_allocator() == min_allocator<bool>());
+ { // Test with min_allocator: compatible allocators
+ using A = min_allocator<bool>;
+ test<5>(A(), A());
+ test<17>(A(), A());
+ test<65>(A(), A());
+ test<299>(A(), A());
}
return true;
More information about the libcxx-commits
mailing list