Skip to content

[libc++] Refactor vector<bool> assign functions and add new tests #119502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 9 additions & 23 deletions libcxx/include/__vector/vector_bool.h
Original file line number Diff line number Diff line change
Expand Up @@ -699,14 +699,7 @@ template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 vector<bool, _Allocator>& vector<bool, _Allocator>::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;
}
Expand Down Expand Up @@ -754,7 +747,7 @@ vector<bool, _Allocator>::operator=(vector&& __v)
template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::__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());
}
Expand All @@ -773,19 +766,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::__move_assign(vecto

template <class _Allocator>
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::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 <class _Allocator>
Expand Down Expand Up @@ -814,17 +802,15 @@ template <class _ForwardIterator, class _Sentinel>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
vector<bool, _Allocator>::__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<size_type>(__ns);
const size_type __n = static_cast<size_type>(__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 <class _Allocator>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,46 +10,65 @@

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

#include <vector>
#include <cassert>
#include "test_macros.h"
#include "test_allocator.h"
#include <vector>

#include "min_allocator.h"
#include "test_allocator.h"
#include "test_macros.h"

TEST_CONSTEXPR_CXX20 bool tests()
{
{
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));
l2 = l;
assert(l2 == l);
assert(l2.get_allocator() == test_allocator<bool>(3));
}
{
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));
l2 = l;
assert(l2 == l);
assert(l2.get_allocator() == other_allocator<bool>(5));
}
TEST_CONSTEXPR_CXX20 bool tests() {
// Test with insufficient space where reallocation occurs during assignment
{
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));
l2 = l;
assert(l2 == l);
assert(l2.get_allocator() == test_allocator<bool>(3));
}
{
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));
l2 = l;
assert(l2 == l);
assert(l2.get_allocator() == other_allocator<bool>(5));
}
#if TEST_STD_VER >= 11
{
std::vector<bool, min_allocator<bool> > l(3, true, min_allocator<bool>());
std::vector<bool, min_allocator<bool> > l2(l, min_allocator<bool>());
l2 = l;
assert(l2 == l);
assert(l2.get_allocator() == min_allocator<bool>());
}
{
std::vector<bool, min_allocator<bool> > l(3, true, min_allocator<bool>());
std::vector<bool, min_allocator<bool> > l2(l, min_allocator<bool>());
l2 = l;
assert(l2 == l);
assert(l2.get_allocator() == min_allocator<bool>());
}
#endif

return true;
// Test with sufficient size where no reallocation occurs during assignment
{
std::vector<bool, test_allocator<bool> > l(4, true, test_allocator<bool>(5));
std::vector<bool, test_allocator<bool> > l2(5, false, test_allocator<bool>(3));
l2 = l;
assert(l2 == l);
assert(l2.get_allocator() == test_allocator<bool>(3));
}

// Test with sufficient spare space where no reallocation occurs during assignment
{
std::vector<bool, test_allocator<bool> > l(4, true, test_allocator<bool>(5));
std::vector<bool, test_allocator<bool> > l2(2, false, test_allocator<bool>(3));
l2.reserve(5);
l2 = l;
assert(l2 == l);
assert(l2.get_allocator() == test_allocator<bool>(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;
}
163 changes: 100 additions & 63 deletions libcxx/test/std/containers/sequences/vector.bool/assign_move.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,79 +12,116 @@

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

#include <vector>
#include <cassert>
#include "test_macros.h"
#include "test_allocator.h"
#include <vector>

#include "min_allocator.h"
#include "test_allocator.h"
#include "test_macros.h"

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(test_allocator<bool>(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<bool, other_allocator<bool> > l(other_allocator<bool>(5));
std::vector<bool, other_allocator<bool> > lo(other_allocator<bool>(5));
std::vector<bool, other_allocator<bool> > l2(other_allocator<bool>(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<bool, test_allocator<bool> > l(test_allocator<bool>(5));
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
std::vector<bool, test_allocator<bool> > l2(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> > 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(test_allocator<bool>(6));
l2 = std::move(l);
assert(l2 == lo);
assert(!l.empty());
assert(l2.get_allocator() == test_allocator<bool>(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<bool, min_allocator<bool> > l(min_allocator<bool>{});
std::vector<bool, min_allocator<bool> > lo(min_allocator<bool>{});
std::vector<bool, min_allocator<bool> > l2(min_allocator<bool>{});
for (int i = 1; i <= 3; ++i) {
l.push_back(i);
lo.push_back(i);
}
{
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(other_allocator<bool>(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<bool, test_allocator<bool> > l(test_allocator<bool>(5));
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(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<bool>(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<bool, test_allocator<bool> > l(test_allocator<bool>(5));
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(6));
for (int i = 1; i <= 3; ++i) {
l.push_back(i);
lo.push_back(i);
}
{
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(min_allocator<bool>{});
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<bool>(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<bool, test_allocator<bool> > l(test_allocator<bool>(5));
std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
std::vector<bool, test_allocator<bool> > l2(test_allocator<bool>(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<bool>(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;
}
Loading