diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h index 36eb7f350ac40..a5f0eb0751e0f 100644 --- a/libcxx/include/__vector/vector_bool.h +++ b/libcxx/include/__vector/vector_bool.h @@ -699,14 +699,7 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 vector& vector::operator=(const vector& __v) { if (this != std::addressof(__v)) { __copy_assign_alloc(__v); - if (__v.__size_) { - if (__v.__size_ > capacity()) { - __vdeallocate(); - __vallocate(__v.__size_); - } - std::copy(__v.__begin_, __v.__begin_ + __external_cap_to_internal(__v.__size_), __begin_); - } - __size_ = __v.__size_; + __assign_with_size(__v.begin(), __v.end(), __v.size()); } return *this; } @@ -754,7 +747,7 @@ vector::operator=(vector&& __v) template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__move_assign(vector& __c, false_type) { if (__alloc_ != __c.__alloc_) - assign(__c.begin(), __c.end()); + __assign_with_size(__c.begin(), __c.end(), __c.size()); else __move_assign(__c, true_type()); } @@ -773,19 +766,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::__move_assign(vecto template _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector::assign(size_type __n, const value_type& __x) { - __size_ = 0; if (__n > 0) { - size_type __c = capacity(); - if (__n <= __c) - __size_ = __n; - else { - vector __v(get_allocator()); - __v.reserve(__recommend(__n)); - __v.__size_ = __n; - swap(__v); + if (__n > capacity()) { + __vdeallocate(); + __vallocate(__n); } std::fill_n(begin(), __n, __x); } + this->__size_ = __n; } template @@ -814,17 +802,15 @@ template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void vector::__assign_with_size(_ForwardIterator __first, _Sentinel __last, difference_type __ns) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(__ns >= 0, "invalid range specified"); - - clear(); - - const size_t __n = static_cast(__ns); + const size_type __n = static_cast(__ns); if (__n) { if (__n > capacity()) { __vdeallocate(); __vallocate(__n); } - __construct_at_end(__first, __last, __n); + std::__copy(__first, __last, this->begin()); } + this->__size_ = __n; } template diff --git a/libcxx/test/std/containers/sequences/vector.bool/assign_copy.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/assign_copy.pass.cpp index c4866ea4c9b45..889acb88bfcec 100644 --- a/libcxx/test/std/containers/sequences/vector.bool/assign_copy.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/assign_copy.pass.cpp @@ -10,46 +10,65 @@ // vector& operator=(const vector& c); -#include #include -#include "test_macros.h" -#include "test_allocator.h" +#include + #include "min_allocator.h" +#include "test_allocator.h" +#include "test_macros.h" -TEST_CONSTEXPR_CXX20 bool tests() -{ - { - std::vector > l(3, true, test_allocator(5)); - std::vector > l2(l, test_allocator(3)); - l2 = l; - assert(l2 == l); - assert(l2.get_allocator() == test_allocator(3)); - } - { - std::vector > l(3, true, other_allocator(5)); - std::vector > l2(l, other_allocator(3)); - l2 = l; - assert(l2 == l); - assert(l2.get_allocator() == other_allocator(5)); - } +TEST_CONSTEXPR_CXX20 bool tests() { + // Test with insufficient space where reallocation occurs during assignment + { + std::vector > l(3, true, test_allocator(5)); + std::vector > l2(l, test_allocator(3)); + l2 = l; + assert(l2 == l); + assert(l2.get_allocator() == test_allocator(3)); + } + { + std::vector > l(3, true, other_allocator(5)); + std::vector > l2(l, other_allocator(3)); + l2 = l; + assert(l2 == l); + assert(l2.get_allocator() == other_allocator(5)); + } #if TEST_STD_VER >= 11 - { - std::vector > l(3, true, min_allocator()); - std::vector > l2(l, min_allocator()); - l2 = l; - assert(l2 == l); - assert(l2.get_allocator() == min_allocator()); - } + { + std::vector > l(3, true, min_allocator()); + std::vector > l2(l, min_allocator()); + l2 = l; + assert(l2 == l); + assert(l2.get_allocator() == min_allocator()); + } #endif - return true; + // Test with sufficient size where no reallocation occurs during assignment + { + std::vector > l(4, true, test_allocator(5)); + std::vector > l2(5, false, test_allocator(3)); + l2 = l; + assert(l2 == l); + assert(l2.get_allocator() == test_allocator(3)); + } + + // Test with sufficient spare space where no reallocation occurs during assignment + { + std::vector > l(4, true, test_allocator(5)); + std::vector > l2(2, false, test_allocator(3)); + l2.reserve(5); + l2 = l; + assert(l2 == l); + assert(l2.get_allocator() == test_allocator(3)); + } + + return true; } -int main(int, char**) -{ - tests(); +int main(int, char**) { + tests(); #if TEST_STD_VER > 17 - static_assert(tests()); + static_assert(tests()); #endif - return 0; + return 0; } diff --git a/libcxx/test/std/containers/sequences/vector.bool/assign_move.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/assign_move.pass.cpp index 10271efc3f403..e047807d68f73 100644 --- a/libcxx/test/std/containers/sequences/vector.bool/assign_move.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/assign_move.pass.cpp @@ -12,79 +12,116 @@ // vector& operator=(vector&& c); -#include #include -#include "test_macros.h" -#include "test_allocator.h" +#include + #include "min_allocator.h" +#include "test_allocator.h" +#include "test_macros.h" -TEST_CONSTEXPR_CXX20 bool tests() -{ - { - std::vector > l(test_allocator(5)); - std::vector > lo(test_allocator(5)); - for (int i = 1; i <= 3; ++i) - { - l.push_back(i); - lo.push_back(i); - } - std::vector > l2(test_allocator(5)); - l2 = std::move(l); - assert(l2 == lo); - LIBCPP_ASSERT(l.empty()); - assert(l2.get_allocator() == lo.get_allocator()); +TEST_CONSTEXPR_CXX20 bool tests() { + // + // Testing for O(1) ownership move + // + { // Test with pocma = true_type, thus performing an ownership move. + std::vector > l(other_allocator(5)); + std::vector > lo(other_allocator(5)); + std::vector > l2(other_allocator(6)); + for (int i = 1; i <= 3; ++i) { + l.push_back(i); + lo.push_back(i); + } + l2 = std::move(l); + assert(l2 == lo); + assert(l.empty()); + assert(l2.get_allocator() == lo.get_allocator()); + } + { // Test with pocma = false_type and equal allocators, thus performing an ownership move. + std::vector > l(test_allocator(5)); + std::vector > lo(test_allocator(5)); + std::vector > l2(test_allocator(5)); + for (int i = 1; i <= 3; ++i) { + l.push_back(i); + lo.push_back(i); } - { - std::vector > l(test_allocator(5)); - std::vector > lo(test_allocator(5)); - for (int i = 1; i <= 3; ++i) - { - l.push_back(i); - lo.push_back(i); - } - std::vector > l2(test_allocator(6)); - l2 = std::move(l); - assert(l2 == lo); - assert(!l.empty()); - assert(l2.get_allocator() == test_allocator(6)); + l2 = std::move(l); + assert(l2 == lo); + LIBCPP_ASSERT(l.empty()); + assert(l2.get_allocator() == lo.get_allocator()); + } + { // Test with pocma = false_type and equal allocators, thus performing an ownership move. + std::vector > l(min_allocator{}); + std::vector > lo(min_allocator{}); + std::vector > l2(min_allocator{}); + for (int i = 1; i <= 3; ++i) { + l.push_back(i); + lo.push_back(i); } - { - std::vector > l(other_allocator(5)); - std::vector > lo(other_allocator(5)); - for (int i = 1; i <= 3; ++i) - { - l.push_back(i); - lo.push_back(i); - } - std::vector > l2(other_allocator(6)); - l2 = std::move(l); - assert(l2 == lo); - assert(l.empty()); - assert(l2.get_allocator() == lo.get_allocator()); + l2 = std::move(l); + assert(l2 == lo); + assert(l.empty()); + assert(l2.get_allocator() == lo.get_allocator()); + } + + // + // Testing for O(n) element-wise move + // + { // Test with pocma = false_type and unequal allocators, thus performing an element-wise move. + // Reallocation occurs during the element-wise move due to insufficient space. + std::vector > l(test_allocator(5)); + std::vector > lo(test_allocator(5)); + std::vector > l2(test_allocator(6)); + for (int i = 1; i <= 3; ++i) { + l.push_back(i); + lo.push_back(i); + } + l2 = std::move(l); + assert(l2 == lo); + assert(!l.empty()); + assert(l2.get_allocator() == test_allocator(6)); + } + + { // Test with pocma = false_type and unequal allocators, thus performing an element-wise move. + // No reallocation occurs since source data fits within current size. + std::vector > l(test_allocator(5)); + std::vector > lo(test_allocator(5)); + std::vector > l2(test_allocator(6)); + for (int i = 1; i <= 3; ++i) { + l.push_back(i); + lo.push_back(i); } - { - std::vector > l(min_allocator{}); - std::vector > lo(min_allocator{}); - for (int i = 1; i <= 3; ++i) - { - l.push_back(i); - lo.push_back(i); - } - std::vector > l2(min_allocator{}); - l2 = std::move(l); - assert(l2 == lo); - assert(l.empty()); - assert(l2.get_allocator() == lo.get_allocator()); + for (int i = 1; i <= 5; ++i) + l2.push_back(i); + l2 = std::move(l); + assert(l2 == lo); + assert(!l.empty()); + assert(l2.get_allocator() == test_allocator(6)); + } + { // Test with pocma = false_type and unequal allocators, thus performing an element-wise move. + // No reallocation occurs since source data fits within current spare space. + std::vector > l(test_allocator(5)); + std::vector > lo(test_allocator(5)); + std::vector > l2(test_allocator(6)); + for (int i = 1; i <= 3; ++i) { + l.push_back(i); + lo.push_back(i); } + for (int i = 1; i <= 2; ++i) + l2.push_back(i); + l2.reserve(5); + l2 = std::move(l); + assert(l2 == lo); + assert(!l.empty()); + assert(l2.get_allocator() == test_allocator(6)); + } - return true; + return true; } -int main(int, char**) -{ - tests(); +int main(int, char**) { + tests(); #if TEST_STD_VER > 17 - static_assert(tests()); + static_assert(tests()); #endif - return 0; + return 0; }