Skip to content

Commit fbdaa5f

Browse files
committed
Refactor vector<bool> assign functions
1 parent 22780f8 commit fbdaa5f

File tree

3 files changed

+160
-118
lines changed

3 files changed

+160
-118
lines changed

libcxx/include/__vector/vector_bool.h

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -699,14 +699,7 @@ template <class _Allocator>
699699
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>& vector<bool, _Allocator>::operator=(const vector& __v) {
700700
if (this != std::addressof(__v)) {
701701
__copy_assign_alloc(__v);
702-
if (__v.__size_) {
703-
if (__v.__size_ > capacity()) {
704-
__vdeallocate();
705-
__vallocate(__v.__size_);
706-
}
707-
std::copy(__v.__begin_, __v.__begin_ + __external_cap_to_internal(__v.__size_), __begin_);
708-
}
709-
__size_ = __v.__size_;
702+
__assign_with_size(__v.begin(), __v.end(), __v.size());
710703
}
711704
return *this;
712705
}
@@ -754,7 +747,7 @@ vector<bool, _Allocator>::operator=(vector&& __v)
754747
template <class _Allocator>
755748
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::__move_assign(vector& __c, false_type) {
756749
if (__alloc_ != __c.__alloc_)
757-
assign(__c.begin(), __c.end());
750+
__assign_with_size(__c.begin(), __c.end(), __c.size());
758751
else
759752
__move_assign(__c, true_type());
760753
}
@@ -773,19 +766,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::__move_assign(vecto
773766

774767
template <class _Allocator>
775768
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::assign(size_type __n, const value_type& __x) {
776-
__size_ = 0;
777769
if (__n > 0) {
778-
size_type __c = capacity();
779-
if (__n <= __c)
780-
__size_ = __n;
781-
else {
782-
vector __v(get_allocator());
783-
__v.reserve(__recommend(__n));
784-
__v.__size_ = __n;
785-
swap(__v);
770+
if (__n > capacity()) {
771+
__vdeallocate();
772+
__vallocate(__n);
786773
}
787774
std::fill_n(begin(), __n, __x);
788775
}
776+
this->__size_ = __n;
789777
}
790778

791779
template <class _Allocator>
@@ -814,17 +802,15 @@ template <class _ForwardIterator, class _Sentinel>
814802
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
815803
vector<bool, _Allocator>::__assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __ns) {
816804
_LIBCPP_ASSERT_VALID_INPUT_RANGE(__ns >= 0, "invalid range specified");
817-
818-
clear();
819-
820-
const size_t __n = static_cast<size_type>(__ns);
805+
const size_type __n = static_cast<size_type>(__ns);
821806
if (__n) {
822807
if (__n > capacity()) {
823808
__vdeallocate();
824809
__vallocate(__n);
825810
}
826-
__construct_at_end(__first, __last, __n);
811+
std::__copy(__first, __last, this->begin());
827812
}
813+
this->__size_ = __n;
828814
}
829815

830816
template <class _Allocator>

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

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -10,46 +10,65 @@
1010

1111
// vector& operator=(const vector& c);
1212

13-
#include <vector>
1413
#include <cassert>
15-
#include "test_macros.h"
16-
#include "test_allocator.h"
14+
#include <vector>
15+
1716
#include "min_allocator.h"
17+
#include "test_allocator.h"
18+
#include "test_macros.h"
1819

19-
TEST_CONSTEXPR_CXX20 bool tests()
20-
{
21-
{
22-
std::vector<bool, test_allocator<bool> > l(3, true, test_allocator<bool>(5));
23-
std::vector<bool, test_allocator<bool> > l2(l, test_allocator<bool>(3));
24-
l2 = l;
25-
assert(l2 == l);
26-
assert(l2.get_allocator() == test_allocator<bool>(3));
27-
}
28-
{
29-
std::vector<bool, other_allocator<bool> > l(3, true, other_allocator<bool>(5));
30-
std::vector<bool, other_allocator<bool> > l2(l, other_allocator<bool>(3));
31-
l2 = l;
32-
assert(l2 == l);
33-
assert(l2.get_allocator() == other_allocator<bool>(5));
34-
}
20+
TEST_CONSTEXPR_CXX20 bool tests() {
21+
// Test with insufficient space where reallocation occurs during assignment
22+
{
23+
std::vector<bool, test_allocator<bool> > l(3, true, test_allocator<bool>(5));
24+
std::vector<bool, test_allocator<bool> > l2(l, test_allocator<bool>(3));
25+
l2 = l;
26+
assert(l2 == l);
27+
assert(l2.get_allocator() == test_allocator<bool>(3));
28+
}
29+
{
30+
std::vector<bool, other_allocator<bool> > l(3, true, other_allocator<bool>(5));
31+
std::vector<bool, other_allocator<bool> > l2(l, other_allocator<bool>(3));
32+
l2 = l;
33+
assert(l2 == l);
34+
assert(l2.get_allocator() == other_allocator<bool>(5));
35+
}
3536
#if TEST_STD_VER >= 11
36-
{
37-
std::vector<bool, min_allocator<bool> > l(3, true, min_allocator<bool>());
38-
std::vector<bool, min_allocator<bool> > l2(l, min_allocator<bool>());
39-
l2 = l;
40-
assert(l2 == l);
41-
assert(l2.get_allocator() == min_allocator<bool>());
42-
}
37+
{
38+
std::vector<bool, min_allocator<bool> > l(3, true, min_allocator<bool>());
39+
std::vector<bool, min_allocator<bool> > l2(l, min_allocator<bool>());
40+
l2 = l;
41+
assert(l2 == l);
42+
assert(l2.get_allocator() == min_allocator<bool>());
43+
}
4344
#endif
4445

45-
return true;
46+
// Test with sufficient size where no reallocation occurs during assignment
47+
{
48+
std::vector<bool, test_allocator<bool> > l(4, true, test_allocator<bool>(5));
49+
std::vector<bool, test_allocator<bool> > l2(5, false, test_allocator<bool>(3));
50+
l2 = l;
51+
assert(l2 == l);
52+
assert(l2.get_allocator() == test_allocator<bool>(3));
53+
}
54+
55+
// Test with sufficient spare space where no reallocation occurs during assignment
56+
{
57+
std::vector<bool, test_allocator<bool> > l(4, true, test_allocator<bool>(5));
58+
std::vector<bool, test_allocator<bool> > l2(2, false, test_allocator<bool>(3));
59+
l2.reserve(5);
60+
l2 = l;
61+
assert(l2 == l);
62+
assert(l2.get_allocator() == test_allocator<bool>(3));
63+
}
64+
65+
return true;
4666
}
4767

48-
int main(int, char**)
49-
{
50-
tests();
68+
int main(int, char**) {
69+
tests();
5170
#if TEST_STD_VER > 17
52-
static_assert(tests());
71+
static_assert(tests());
5372
#endif
54-
return 0;
73+
return 0;
5574
}

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

Lines changed: 100 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -12,79 +12,116 @@
1212

1313
// vector& operator=(vector&& c);
1414

15-
#include <vector>
1615
#include <cassert>
17-
#include "test_macros.h"
18-
#include "test_allocator.h"
16+
#include <vector>
17+
1918
#include "min_allocator.h"
19+
#include "test_allocator.h"
20+
#include "test_macros.h"
2021

21-
TEST_CONSTEXPR_CXX20 bool tests()
22-
{
23-
{
24-
std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
25-
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
26-
for (int i = 1; i <= 3; ++i)
27-
{
28-
l.push_back(i);
29-
lo.push_back(i);
30-
}
31-
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(5));
32-
l2 = std::move(l);
33-
assert(l2 == lo);
34-
LIBCPP_ASSERT(l.empty());
35-
assert(l2.get_allocator() == lo.get_allocator());
22+
TEST_CONSTEXPR_CXX20 bool tests() {
23+
//
24+
// Testing for O(1) ownership move
25+
//
26+
{ // Test with pocma = true_type, thus performing an ownership move.
27+
std::vector<bool, other_allocator<bool> > l(other_allocator<bool>(5));
28+
std::vector<bool, other_allocator<bool> > lo(other_allocator<bool>(5));
29+
std::vector<bool, other_allocator<bool> > l2(other_allocator<bool>(6));
30+
for (int i = 1; i <= 3; ++i) {
31+
l.push_back(i);
32+
lo.push_back(i);
33+
}
34+
l2 = std::move(l);
35+
assert(l2 == lo);
36+
assert(l.empty());
37+
assert(l2.get_allocator() == lo.get_allocator());
38+
}
39+
{ // Test with pocma = false_type and equal allocators, thus performing an ownership move.
40+
std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
41+
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
42+
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(5));
43+
for (int i = 1; i <= 3; ++i) {
44+
l.push_back(i);
45+
lo.push_back(i);
3646
}
37-
{
38-
std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
39-
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
40-
for (int i = 1; i <= 3; ++i)
41-
{
42-
l.push_back(i);
43-
lo.push_back(i);
44-
}
45-
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(6));
46-
l2 = std::move(l);
47-
assert(l2 == lo);
48-
assert(!l.empty());
49-
assert(l2.get_allocator() == test_allocator<bool>(6));
47+
l2 = std::move(l);
48+
assert(l2 == lo);
49+
LIBCPP_ASSERT(l.empty());
50+
assert(l2.get_allocator() == lo.get_allocator());
51+
}
52+
{ // Test with pocma = false_type and equal allocators, thus performing an ownership move.
53+
std::vector<bool, min_allocator<bool> > l(min_allocator<bool>{});
54+
std::vector<bool, min_allocator<bool> > lo(min_allocator<bool>{});
55+
std::vector<bool, min_allocator<bool> > l2(min_allocator<bool>{});
56+
for (int i = 1; i <= 3; ++i) {
57+
l.push_back(i);
58+
lo.push_back(i);
5059
}
51-
{
52-
std::vector<bool, other_allocator<bool> > l(other_allocator<bool>(5));
53-
std::vector<bool, other_allocator<bool> > lo(other_allocator<bool>(5));
54-
for (int i = 1; i <= 3; ++i)
55-
{
56-
l.push_back(i);
57-
lo.push_back(i);
58-
}
59-
std::vector<bool, other_allocator<bool> > l2(other_allocator<bool>(6));
60-
l2 = std::move(l);
61-
assert(l2 == lo);
62-
assert(l.empty());
63-
assert(l2.get_allocator() == lo.get_allocator());
60+
l2 = std::move(l);
61+
assert(l2 == lo);
62+
assert(l.empty());
63+
assert(l2.get_allocator() == lo.get_allocator());
64+
}
65+
66+
//
67+
// Testing for O(n) element-wise move
68+
//
69+
{ // Test with pocma = false_type and unequal allocators, thus performing an element-wise move.
70+
// Reallocation occurs during the element-wise move due to insufficient space.
71+
std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
72+
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
73+
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(6));
74+
for (int i = 1; i <= 3; ++i) {
75+
l.push_back(i);
76+
lo.push_back(i);
77+
}
78+
l2 = std::move(l);
79+
assert(l2 == lo);
80+
assert(!l.empty());
81+
assert(l2.get_allocator() == test_allocator<bool>(6));
82+
}
83+
84+
{ // Test with pocma = false_type and unequal allocators, thus performing an element-wise move.
85+
// No reallocation occurs since source data fits within current size.
86+
std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
87+
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
88+
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(6));
89+
for (int i = 1; i <= 3; ++i) {
90+
l.push_back(i);
91+
lo.push_back(i);
6492
}
65-
{
66-
std::vector<bool, min_allocator<bool> > l(min_allocator<bool>{});
67-
std::vector<bool, min_allocator<bool> > lo(min_allocator<bool>{});
68-
for (int i = 1; i <= 3; ++i)
69-
{
70-
l.push_back(i);
71-
lo.push_back(i);
72-
}
73-
std::vector<bool, min_allocator<bool> > l2(min_allocator<bool>{});
74-
l2 = std::move(l);
75-
assert(l2 == lo);
76-
assert(l.empty());
77-
assert(l2.get_allocator() == lo.get_allocator());
93+
for (int i = 1; i <= 5; ++i)
94+
l2.push_back(i);
95+
l2 = std::move(l);
96+
assert(l2 == lo);
97+
assert(!l.empty());
98+
assert(l2.get_allocator() == test_allocator<bool>(6));
99+
}
100+
{ // Test with pocma = false_type and unequal allocators, thus performing an element-wise move.
101+
// No reallocation occurs since source data fits within current spare space.
102+
std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
103+
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
104+
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(6));
105+
for (int i = 1; i <= 3; ++i) {
106+
l.push_back(i);
107+
lo.push_back(i);
78108
}
109+
for (int i = 1; i <= 2; ++i)
110+
l2.push_back(i);
111+
l2.reserve(5);
112+
l2 = std::move(l);
113+
assert(l2 == lo);
114+
assert(!l.empty());
115+
assert(l2.get_allocator() == test_allocator<bool>(6));
116+
}
79117

80-
return true;
118+
return true;
81119
}
82120

83-
int main(int, char**)
84-
{
85-
tests();
121+
int main(int, char**) {
122+
tests();
86123
#if TEST_STD_VER > 17
87-
static_assert(tests());
124+
static_assert(tests());
88125
#endif
89-
return 0;
126+
return 0;
90127
}

0 commit comments

Comments
 (0)