Skip to content

Commit 70480fc

Browse files
authored
[libc++] Validate vector<bool> copy/move-assignment operators in realistic scenarios (#119817)
The existing tests for `vector<bool>` copy- and move-assignment operators are limited to 3 bits only, which are inadequate to cover realistic scenarios. Most `vector<bool>` operations have code paths that are executed only when multiple storage words are involved, with each storage word typically comprising 64 bits on a 64-bit platform. Furthermore, the existing tests fail to cover all combinations `POCCA`/`POCMA`, along with different allocator equality and/or reallocation scenarios, leaving some critical code paths untested. This patch enhances the test coverage by introducing new tests covering up to 5 storage words, ensuring that partial words in the front or tail, and whole words in the middle are all properly tested. Moreover, these new tests ensure that the copy- and move-assignment operators are tested under all combinations of `POCCA`/`POCMA` and various allocator equality scenarios, both with or without reallocations.
1 parent 029cb8a commit 70480fc

File tree

2 files changed

+108
-59
lines changed

2 files changed

+108
-59
lines changed

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

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,69 @@
77
//===----------------------------------------------------------------------===//
88

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

1112
// vector& operator=(const vector& c);
1213

13-
#include <vector>
1414
#include <cassert>
15-
#include "test_macros.h"
16-
#include "test_allocator.h"
15+
#include <vector>
16+
1717
#include "min_allocator.h"
18+
#include "test_allocator.h"
19+
#include "test_macros.h"
1820

19-
TEST_CONSTEXPR_CXX20 bool tests() {
20-
{
21-
std::vector<bool, test_allocator<bool> > l(3, true, test_allocator<bool>(5));
22-
std::vector<bool, test_allocator<bool> > l2(l, test_allocator<bool>(3));
21+
TEST_CONSTEXPR_CXX20 void test_copy_assignment(unsigned N) {
22+
//
23+
// Test with insufficient space where reallocation occurs during assignment
24+
//
25+
{ // POCCA = true_type, thus copy-assign the allocator
26+
std::vector<bool, other_allocator<bool> > l(N, true, other_allocator<bool>(5));
27+
std::vector<bool, other_allocator<bool> > l2(other_allocator<bool>(3));
2328
l2 = l;
2429
assert(l2 == l);
25-
assert(l2.get_allocator() == test_allocator<bool>(3));
30+
assert(l2.get_allocator() == other_allocator<bool>(5));
2631
}
27-
{
28-
std::vector<bool, other_allocator<bool> > l(3, true, other_allocator<bool>(5));
29-
std::vector<bool, other_allocator<bool> > l2(l, other_allocator<bool>(3));
32+
{ // POCCA = false_type, thus allocator is unchanged
33+
std::vector<bool, test_allocator<bool> > l(N + 64, true, test_allocator<bool>(5));
34+
std::vector<bool, test_allocator<bool> > l2(10, false, test_allocator<bool>(3));
3035
l2 = l;
3136
assert(l2 == l);
32-
assert(l2.get_allocator() == other_allocator<bool>(5));
37+
assert(l2.get_allocator() == test_allocator<bool>(3));
3338
}
34-
#if TEST_STD_VER >= 11
35-
{
36-
std::vector<bool, min_allocator<bool> > l(3, true, min_allocator<bool>());
37-
std::vector<bool, min_allocator<bool> > l2(l, min_allocator<bool>());
39+
{ // Stateless allocator
40+
std::vector<bool, min_allocator<bool> > l(N + 64, true, min_allocator<bool>());
41+
std::vector<bool, min_allocator<bool> > l2(N / 2, false, min_allocator<bool>());
3842
l2 = l;
3943
assert(l2 == l);
4044
assert(l2.get_allocator() == min_allocator<bool>());
4145
}
42-
#endif
46+
47+
//
48+
// Test with sufficient size where no reallocation occurs during assignment
49+
//
50+
{ // POCCA = false_type, thus allocator is unchanged
51+
std::vector<bool, test_allocator<bool> > l(N, true, test_allocator<bool>(5));
52+
std::vector<bool, test_allocator<bool> > l2(N + 64, false, test_allocator<bool>(3));
53+
l2 = l;
54+
assert(l2 == l);
55+
assert(l2.get_allocator() == test_allocator<bool>(3));
56+
}
57+
{ // POCCA = true_type, thus copy-assign the allocator
58+
std::vector<bool, other_allocator<bool> > l(N, true, other_allocator<bool>(5));
59+
std::vector<bool, other_allocator<bool> > l2(N * 2, false, other_allocator<bool>(3));
60+
l2.reserve(5);
61+
l2 = l;
62+
assert(l2 == l);
63+
assert(l2.get_allocator() == other_allocator<bool>(5));
64+
}
65+
}
66+
67+
TEST_CONSTEXPR_CXX20 bool tests() {
68+
test_copy_assignment(3);
69+
test_copy_assignment(18);
70+
test_copy_assignment(33);
71+
test_copy_assignment(65);
72+
test_copy_assignment(299);
4373

4474
return true;
4575
}

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

Lines changed: 61 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,68 +9,87 @@
99
// UNSUPPORTED: c++03
1010

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

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

15-
#include <vector>
1616
#include <cassert>
17-
#include "test_macros.h"
18-
#include "test_allocator.h"
17+
#include <vector>
18+
1919
#include "min_allocator.h"
20+
#include "test_allocator.h"
21+
#include "test_macros.h"
2022

21-
TEST_CONSTEXPR_CXX20 bool tests() {
22-
{
23-
std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
24-
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
25-
for (int i = 1; i <= 3; ++i) {
26-
l.push_back(i);
27-
lo.push_back(i);
28-
}
29-
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(5));
23+
TEST_CONSTEXPR_CXX20 void test_move_assignment(unsigned N) {
24+
//
25+
// Testing for container move where either POCMA = true_type or the allocators compare equal
26+
//
27+
{ // Test with POCMA = true_type
28+
std::vector<bool, other_allocator<bool> > l(N, true, other_allocator<bool>(5));
29+
std::vector<bool, other_allocator<bool> > lo(N, true, other_allocator<bool>(5));
30+
std::vector<bool, other_allocator<bool> > l2(N + 10, false, other_allocator<bool>(42));
3031
l2 = std::move(l);
3132
assert(l2 == lo);
32-
LIBCPP_ASSERT(l.empty());
33+
LIBCPP_ASSERT(l.empty()); // After move, source vector is in a vliad but unspecified state. libc++ leaves it empty.
3334
assert(l2.get_allocator() == lo.get_allocator());
3435
}
35-
{
36-
std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
37-
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
38-
for (int i = 1; i <= 3; ++i) {
39-
l.push_back(i);
40-
lo.push_back(i);
41-
}
42-
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(6));
36+
{ // Test with POCMA = false_type and allocators compare equal
37+
std::vector<bool, test_allocator<bool> > l(N, true, test_allocator<bool>(5));
38+
std::vector<bool, test_allocator<bool> > lo(N, true, test_allocator<bool>(5));
39+
std::vector<bool, test_allocator<bool> > l2(N + 10, false, test_allocator<bool>(5));
4340
l2 = std::move(l);
4441
assert(l2 == lo);
45-
assert(!l.empty());
46-
assert(l2.get_allocator() == test_allocator<bool>(6));
42+
LIBCPP_ASSERT(l.empty());
43+
assert(l2.get_allocator() == lo.get_allocator());
4744
}
48-
{
49-
std::vector<bool, other_allocator<bool> > l(other_allocator<bool>(5));
50-
std::vector<bool, other_allocator<bool> > lo(other_allocator<bool>(5));
51-
for (int i = 1; i <= 3; ++i) {
52-
l.push_back(i);
53-
lo.push_back(i);
54-
}
55-
std::vector<bool, other_allocator<bool> > l2(other_allocator<bool>(6));
45+
{ // Test with POCMA = false_type and allocators compare equal
46+
std::vector<bool, min_allocator<bool> > l(N, true, min_allocator<bool>{});
47+
std::vector<bool, min_allocator<bool> > lo(N, true, min_allocator<bool>{});
48+
std::vector<bool, min_allocator<bool> > l2(N + 10, false, min_allocator<bool>{});
5649
l2 = std::move(l);
5750
assert(l2 == lo);
58-
assert(l.empty());
51+
LIBCPP_ASSERT(l.empty());
5952
assert(l2.get_allocator() == lo.get_allocator());
6053
}
61-
{
62-
std::vector<bool, min_allocator<bool> > l(min_allocator<bool>{});
63-
std::vector<bool, min_allocator<bool> > lo(min_allocator<bool>{});
64-
for (int i = 1; i <= 3; ++i) {
65-
l.push_back(i);
66-
lo.push_back(i);
67-
}
68-
std::vector<bool, min_allocator<bool> > l2(min_allocator<bool>{});
54+
55+
//
56+
// Testing for element-wise move where POCMA = false_type and allocators compare unequal
57+
//
58+
{ // Test with reallocation during the element-wise move due to empty destination vector.
59+
std::vector<bool, test_allocator<bool> > l(N, true, test_allocator<bool>(5));
60+
std::vector<bool, test_allocator<bool> > lo(N, true, test_allocator<bool>(5));
61+
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(42));
6962
l2 = std::move(l);
7063
assert(l2 == lo);
71-
assert(l.empty());
72-
assert(l2.get_allocator() == lo.get_allocator());
64+
LIBCPP_ASSERT(!l.empty());
65+
assert(l2.get_allocator() == test_allocator<bool>(42));
66+
}
67+
{ // Test with reallocation occurs during the element-wise move due to insufficient destination space.
68+
std::vector<bool, test_allocator<bool> > l(N + 64, true, test_allocator<bool>(5));
69+
std::vector<bool, test_allocator<bool> > lo(N + 64, true, test_allocator<bool>(5));
70+
std::vector<bool, test_allocator<bool> > l2(10, false, test_allocator<bool>(42));
71+
l2 = std::move(l);
72+
assert(l2 == lo);
73+
LIBCPP_ASSERT(!l.empty());
74+
assert(l2.get_allocator() == test_allocator<bool>(42));
7375
}
76+
{ // Test without reallocation where source vector elements fit within destination size.
77+
std::vector<bool, test_allocator<bool> > l(N, true, test_allocator<bool>(5));
78+
std::vector<bool, test_allocator<bool> > lo(N, true, test_allocator<bool>(5));
79+
std::vector<bool, test_allocator<bool> > l2(N * 2, false, test_allocator<bool>(42));
80+
l2 = std::move(l);
81+
assert(l2 == lo);
82+
LIBCPP_ASSERT(!l.empty());
83+
assert(l2.get_allocator() == test_allocator<bool>(42));
84+
}
85+
}
86+
87+
TEST_CONSTEXPR_CXX20 bool tests() {
88+
test_move_assignment(3);
89+
test_move_assignment(18);
90+
test_move_assignment(33);
91+
test_move_assignment(65);
92+
test_move_assignment(299);
7493

7594
return true;
7695
}

0 commit comments

Comments
 (0)