Skip to content

Commit 9dc854c

Browse files
authored
[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.
1 parent a5d4b50 commit 9dc854c

File tree

4 files changed

+204
-139
lines changed

4 files changed

+204
-139
lines changed

libcxx/test/std/containers/sequences/vector.bool/copy.pass.cpp

Lines changed: 47 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@
1111

1212
// vector(const vector& v);
1313

14-
#include <vector>
14+
#include <array>
1515
#include <cassert>
16+
#include <vector>
1617

17-
#include "test_macros.h"
18-
#include "test_allocator.h"
1918
#include "min_allocator.h"
19+
#include "test_allocator.h"
20+
#include "test_macros.h"
2021

2122
template <class C>
2223
TEST_CONSTEXPR_CXX20 void test(const C& x) {
@@ -25,39 +26,56 @@ TEST_CONSTEXPR_CXX20 void test(const C& x) {
2526
LIBCPP_ASSERT(c.__invariants());
2627
assert(c.size() == s);
2728
assert(c == x);
29+
#if TEST_STD_VER >= 11
30+
assert(c.get_allocator() ==
31+
std::allocator_traits<typename C::allocator_type>::select_on_container_copy_construction(x.get_allocator()));
32+
#endif
2833
}
2934

3035
TEST_CONSTEXPR_CXX20 bool tests() {
31-
{
32-
bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
33-
bool* an = a + sizeof(a) / sizeof(a[0]);
34-
test(std::vector<bool>(a, an));
35-
}
36-
{
37-
std::vector<bool, test_allocator<bool> > v(3, true, test_allocator<bool>(5));
38-
std::vector<bool, test_allocator<bool> > v2 = v;
39-
assert(v2 == v);
40-
assert(v2.get_allocator() == v.get_allocator());
36+
std::array<int, 5> a1 = {1, 0, 1, 0, 1};
37+
std::array<int, 18> a2 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
38+
std::array<int, 33> a3 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
39+
std::array<int, 65> a4 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
40+
std::array<int, 299> a5 = {};
41+
for (unsigned i = 0; i < a5.size(); i += 2)
42+
a5[i] = 1;
43+
44+
// Tests for vector<bool> copy constructor with word size up to 5 (i.e., bit size > 256 on a 64-bit system)
45+
{ // Test with default std::allocator
46+
test(std::vector<bool>(a1.begin(), a1.end()));
47+
test(std::vector<bool>(a2.begin(), a2.end()));
48+
test(std::vector<bool>(a3.begin(), a3.end()));
49+
test(std::vector<bool>(a4.begin(), a4.end()));
50+
test(std::vector<bool>(a5.begin(), a5.end()));
4151
}
42-
#if TEST_STD_VER >= 11
43-
{
44-
std::vector<bool, other_allocator<bool> > v(3, true, other_allocator<bool>(5));
45-
std::vector<bool, other_allocator<bool> > v2 = v;
46-
assert(v2 == v);
47-
assert(v2.get_allocator() == other_allocator<bool>(-2));
52+
{ // Test with test_allocator
53+
using A = test_allocator<bool>;
54+
using C = std::vector<bool, A>;
55+
test(C(a1.begin(), a1.end()));
56+
test(C(a2.begin(), a2.end()));
57+
test(C(a3.begin(), a3.end()));
58+
test(C(a4.begin(), a4.end()));
59+
test(C(a5.begin(), a5.end()));
4860
}
49-
{
50-
bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
51-
bool* an = a + sizeof(a) / sizeof(a[0]);
52-
test(std::vector<bool, min_allocator<bool>>(a, an));
61+
{ // Test with other_allocator
62+
using A = other_allocator<bool>;
63+
using C = std::vector<bool, A>;
64+
test(C(a1.begin(), a1.end()));
65+
test(C(a2.begin(), a2.end()));
66+
test(C(a3.begin(), a3.end()));
67+
test(C(a4.begin(), a4.end()));
68+
test(C(a5.begin(), a5.end()));
5369
}
54-
{
55-
std::vector<bool, min_allocator<bool> > v(3, true, min_allocator<bool>());
56-
std::vector<bool, min_allocator<bool> > v2 = v;
57-
assert(v2 == v);
58-
assert(v2.get_allocator() == v.get_allocator());
70+
{ // Test with min_allocator
71+
using A = min_allocator<bool>;
72+
using C = std::vector<bool, A>;
73+
test(C(a1.begin(), a1.end()));
74+
test(C(a2.begin(), a2.end()));
75+
test(C(a3.begin(), a3.end()));
76+
test(C(a4.begin(), a4.end()));
77+
test(C(a5.begin(), a5.end()));
5978
}
60-
#endif
6179

6280
return true;
6381
}

libcxx/test/std/containers/sequences/vector.bool/copy_alloc.pass.cpp

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@
77
//===----------------------------------------------------------------------===//
88

99
// <vector>
10+
// vector<bool>
1011

1112
// vector(const vector& v, const allocator_type& a);
1213

13-
#include <vector>
14+
#include <array>
1415
#include <cassert>
16+
#include <vector>
1517

16-
#include "test_macros.h"
17-
#include "test_allocator.h"
1818
#include "min_allocator.h"
19+
#include "test_allocator.h"
20+
#include "test_macros.h"
1921

2022
template <class C>
2123
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)
2426
LIBCPP_ASSERT(c.__invariants());
2527
assert(c.size() == s);
2628
assert(c == x);
29+
assert(c.get_allocator() == a);
2730
}
2831

2932
TEST_CONSTEXPR_CXX20 bool tests() {
30-
{
31-
bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
32-
bool* an = a + sizeof(a) / sizeof(a[0]);
33-
test(std::vector<bool>(a, an), std::allocator<bool>());
34-
}
35-
{
36-
std::vector<bool, test_allocator<bool> > l(3, true, test_allocator<bool>(5));
37-
std::vector<bool, test_allocator<bool> > l2(l, test_allocator<bool>(3));
38-
assert(l2 == l);
39-
assert(l2.get_allocator() == test_allocator<bool>(3));
33+
std::array<int, 5> a1 = {1, 0, 1, 0, 1};
34+
std::array<int, 18> a2 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
35+
std::array<int, 33> a3 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
36+
std::array<int, 65> a4 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
37+
std::array<int, 299> a5 = {};
38+
for (unsigned i = 0; i < a5.size(); i += 2)
39+
a5[i] = 1;
40+
41+
// Tests for allocator-extended copy constructor with word size up to 5 (i.e., bit size > 256 on a 64-bit system)
42+
{ // Test with the default std::allocator
43+
test(std::vector<bool>(a1.begin(), a1.end()), std::allocator<bool>());
44+
test(std::vector<bool>(a2.begin(), a2.end()), std::allocator<bool>());
45+
test(std::vector<bool>(a3.begin(), a3.end()), std::allocator<bool>());
46+
test(std::vector<bool>(a4.begin(), a4.end()), std::allocator<bool>());
47+
test(std::vector<bool>(a5.begin(), a5.end()), std::allocator<bool>());
4048
}
41-
{
42-
std::vector<bool, other_allocator<bool> > l(3, true, other_allocator<bool>(5));
43-
std::vector<bool, other_allocator<bool> > l2(l, other_allocator<bool>(3));
44-
assert(l2 == l);
45-
assert(l2.get_allocator() == other_allocator<bool>(3));
49+
{ // Test with test_allocator
50+
using A = test_allocator<bool>;
51+
using C = std::vector<bool, A>;
52+
test(C(a1.begin(), a1.end(), A(5)), A(3));
53+
test(C(a2.begin(), a2.end(), A(5)), A(3));
54+
test(C(a3.begin(), a3.end(), A(5)), A(3));
55+
test(C(a4.begin(), a4.end(), A(5)), A(3));
56+
test(C(a5.begin(), a5.end(), A(5)), A(3));
4657
}
47-
#if TEST_STD_VER >= 11
48-
{
49-
bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
50-
bool* an = a + sizeof(a) / sizeof(a[0]);
51-
test(std::vector<bool, min_allocator<bool>>(a, an), min_allocator<bool>());
58+
{ // Test with other_allocator
59+
using A = other_allocator<bool>;
60+
using C = std::vector<bool, A>;
61+
test(C(a1.begin(), a1.end(), A(5)), A(3));
62+
test(C(a2.begin(), a2.end(), A(5)), A(3));
63+
test(C(a3.begin(), a3.end(), A(5)), A(3));
64+
test(C(a4.begin(), a4.end(), A(5)), A(3));
65+
test(C(a5.begin(), a5.end(), A(5)), A(3));
5266
}
53-
{
54-
std::vector<bool, min_allocator<bool> > l(3, true, min_allocator<bool>());
55-
std::vector<bool, min_allocator<bool> > l2(l, min_allocator<bool>());
56-
assert(l2 == l);
57-
assert(l2.get_allocator() == min_allocator<bool>());
67+
{ // Test with min_allocator
68+
using A = min_allocator<bool>;
69+
using C = std::vector<bool, A>;
70+
test(C(a1.begin(), a1.end(), A()), A());
71+
test(C(a2.begin(), a2.end(), A()), A());
72+
test(C(a3.begin(), a3.end(), A()), A());
73+
test(C(a4.begin(), a4.end(), A()), A());
74+
test(C(a5.begin(), a5.end(), A()), A());
5875
}
59-
#endif
6076

6177
return true;
6278
}

libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -9,54 +9,70 @@
99
// UNSUPPORTED: c++03
1010

1111
// <vector>
12+
// vector<bool>
1213

1314
// vector(vector&& c);
1415

15-
#include <vector>
16+
#include <array>
1617
#include <cassert>
17-
#include "test_macros.h"
18-
#include "test_allocator.h"
18+
#include <vector>
19+
1920
#include "min_allocator.h"
21+
#include "test_allocator.h"
22+
#include "test_macros.h"
23+
24+
template <unsigned N, class A>
25+
TEST_CONSTEXPR_CXX20 void test(const A& a) {
26+
std::vector<bool, A> v(N, false, a);
27+
std::vector<bool, A> original(N, false, a);
28+
for (unsigned i = 1; i < N; i += 2) {
29+
v[i] = true;
30+
original[i] = true;
31+
}
32+
std::vector<bool, A> v2 = std::move(v);
33+
assert(v2 == original);
34+
assert(v.empty()); // The moved-from vector is guaranteed to be empty after move-construction
35+
assert(v2.get_allocator() == original.get_allocator());
36+
}
2037

2138
TEST_CONSTEXPR_CXX20 bool tests() {
2239
test_allocator_statistics alloc_stats;
40+
41+
// Tests for move constructor with word size up to 5 (i.e., bit size > 256 for 64-bit system)
2342
{
24-
std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5, &alloc_stats));
25-
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5, &alloc_stats));
26-
for (int i = 1; i <= 3; ++i) {
27-
l.push_back(true);
28-
lo.push_back(true);
29-
}
30-
std::vector<bool, test_allocator<bool> > l2 = std::move(l);
31-
assert(l2 == lo);
32-
assert(l.empty());
33-
assert(l2.get_allocator() == lo.get_allocator());
43+
using A = std::allocator<bool>;
44+
test<5>(A());
45+
test<18>(A());
46+
test<33>(A());
47+
test<65>(A());
48+
test<299>(A());
3449
}
3550
{
36-
std::vector<bool, other_allocator<bool> > l(other_allocator<bool>(5));
37-
std::vector<bool, other_allocator<bool> > lo(other_allocator<bool>(5));
38-
for (int i = 1; i <= 3; ++i) {
39-
l.push_back(true);
40-
lo.push_back(true);
41-
}
42-
std::vector<bool, other_allocator<bool> > l2 = std::move(l);
43-
assert(l2 == lo);
44-
assert(l.empty());
45-
assert(l2.get_allocator() == lo.get_allocator());
51+
using A = other_allocator<bool>;
52+
test<5>(A(5));
53+
test<18>(A(5));
54+
test<33>(A(5));
55+
test<65>(A(5));
56+
test<299>(A(5));
4657
}
4758
{
48-
std::vector<bool, min_allocator<bool> > l(min_allocator<bool>{});
49-
std::vector<bool, min_allocator<bool> > lo(min_allocator<bool>{});
50-
for (int i = 1; i <= 3; ++i) {
51-
l.push_back(true);
52-
lo.push_back(true);
53-
}
54-
std::vector<bool, min_allocator<bool> > l2 = std::move(l);
55-
assert(l2 == lo);
56-
assert(l.empty());
57-
assert(l2.get_allocator() == lo.get_allocator());
59+
using A = min_allocator<bool>;
60+
test<5>(A());
61+
test<18>(A());
62+
test<33>(A());
63+
test<65>(A());
64+
test<299>(A());
5865
}
5966
{
67+
using A = test_allocator<bool>;
68+
test<5>(A(5, &alloc_stats));
69+
test<18>(A(5, &alloc_stats));
70+
test<33>(A(5, &alloc_stats));
71+
test<65>(A(5, &alloc_stats));
72+
test<299>(A(5, &alloc_stats));
73+
}
74+
75+
{ // Tests to verify the allocator statistics after move
6076
alloc_stats.clear();
6177
using Vect = std::vector<bool, test_allocator<bool> >;
6278
using AllocT = Vect::allocator_type;
@@ -83,7 +99,6 @@ TEST_CONSTEXPR_CXX20 bool tests() {
8399
const AllocT& a2 = v2.get_allocator();
84100
assert(a2.get_id() == 101);
85101
assert(a2.get_data() == 42);
86-
87102
assert(a1 == a2);
88103
}
89104
}

0 commit comments

Comments
 (0)