[libcxx-commits] [libcxx] [libc++] Speed up vector<bool> copy/move-ctors [1/3] (PR #120132)
Peng Liu via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Mar 14 08:47:17 PDT 2025
https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/120132
>From 84025be070497af6bb68b38e841c809578f79ad9 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Fri, 14 Mar 2025 11:29:47 -0400
Subject: [PATCH] Enhance tests for copy/move constructors for vector<bool>
---
.../sequences/vector.bool/copy.pass.cpp | 76 +++++++-----
.../sequences/vector.bool/copy_alloc.pass.cpp | 74 +++++++-----
.../sequences/vector.bool/move.pass.cpp | 83 +++++++------
.../sequences/vector.bool/move_alloc.pass.cpp | 110 ++++++++++--------
4 files changed, 204 insertions(+), 139 deletions(-)
diff --git a/libcxx/test/std/containers/sequences/vector.bool/copy.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/copy.pass.cpp
index 15b26e8054df8..ba957471927c3 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/copy.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/copy.pass.cpp
@@ -11,12 +11,13 @@
// vector(const vector& v);
-#include <vector>
+#include <array>
#include <cassert>
+#include <vector>
-#include "test_macros.h"
-#include "test_allocator.h"
#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
template <class C>
TEST_CONSTEXPR_CXX20 void test(const C& x) {
@@ -25,39 +26,56 @@ TEST_CONSTEXPR_CXX20 void test(const C& x) {
LIBCPP_ASSERT(c.__invariants());
assert(c.size() == s);
assert(c == x);
+#if TEST_STD_VER >= 11
+ assert(c.get_allocator() ==
+ std::allocator_traits<typename C::allocator_type>::select_on_container_copy_construction(x.get_allocator()));
+#endif
}
TEST_CONSTEXPR_CXX20 bool tests() {
- {
- bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
- bool* an = a + sizeof(a) / sizeof(a[0]);
- test(std::vector<bool>(a, an));
- }
- {
- std::vector<bool, test_allocator<bool> > v(3, true, test_allocator<bool>(5));
- std::vector<bool, test_allocator<bool> > v2 = v;
- assert(v2 == v);
- assert(v2.get_allocator() == v.get_allocator());
+ std::array<int, 5> a1 = {1, 0, 1, 0, 1};
+ std::array<int, 18> a2 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 33> a3 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 65> a4 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 299> a5 = {};
+ for (unsigned i = 0; i < a5.size(); i += 2)
+ a5[i] = 1;
+
+ // Tests for vector<bool> copy constructor with word size up to 5 (i.e., bit size > 256 on a 64-bit system)
+ { // Test with default std::allocator
+ test(std::vector<bool>(a1.begin(), a1.end()));
+ test(std::vector<bool>(a2.begin(), a2.end()));
+ test(std::vector<bool>(a3.begin(), a3.end()));
+ test(std::vector<bool>(a4.begin(), a4.end()));
+ test(std::vector<bool>(a5.begin(), a5.end()));
}
-#if TEST_STD_VER >= 11
- {
- std::vector<bool, other_allocator<bool> > v(3, true, other_allocator<bool>(5));
- std::vector<bool, other_allocator<bool> > v2 = v;
- assert(v2 == v);
- assert(v2.get_allocator() == other_allocator<bool>(-2));
+ { // Test with test_allocator
+ using A = test_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end()));
+ test(C(a2.begin(), a2.end()));
+ test(C(a3.begin(), a3.end()));
+ test(C(a4.begin(), a4.end()));
+ test(C(a5.begin(), a5.end()));
}
- {
- bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
- bool* an = a + sizeof(a) / sizeof(a[0]);
- test(std::vector<bool, min_allocator<bool>>(a, an));
+ { // Test with other_allocator
+ using A = other_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end()));
+ test(C(a2.begin(), a2.end()));
+ test(C(a3.begin(), a3.end()));
+ test(C(a4.begin(), a4.end()));
+ test(C(a5.begin(), a5.end()));
}
- {
- std::vector<bool, min_allocator<bool> > v(3, true, min_allocator<bool>());
- std::vector<bool, min_allocator<bool> > v2 = v;
- assert(v2 == v);
- assert(v2.get_allocator() == v.get_allocator());
+ { // Test with min_allocator
+ using A = min_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end()));
+ test(C(a2.begin(), a2.end()));
+ test(C(a3.begin(), a3.end()));
+ test(C(a4.begin(), a4.end()));
+ test(C(a5.begin(), a5.end()));
}
-#endif
return true;
}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/copy_alloc.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/copy_alloc.pass.cpp
index d22b7c5d58447..17967ff2713cd 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/copy_alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/copy_alloc.pass.cpp
@@ -7,15 +7,17 @@
//===----------------------------------------------------------------------===//
// <vector>
+// vector<bool>
// vector(const vector& v, const allocator_type& a);
-#include <vector>
+#include <array>
#include <cassert>
+#include <vector>
-#include "test_macros.h"
-#include "test_allocator.h"
#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
template <class C>
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)
LIBCPP_ASSERT(c.__invariants());
assert(c.size() == s);
assert(c == x);
+ assert(c.get_allocator() == a);
}
TEST_CONSTEXPR_CXX20 bool tests() {
- {
- bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
- bool* an = a + sizeof(a) / sizeof(a[0]);
- test(std::vector<bool>(a, an), std::allocator<bool>());
- }
- {
- 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));
- assert(l2 == l);
- assert(l2.get_allocator() == test_allocator<bool>(3));
+ std::array<int, 5> a1 = {1, 0, 1, 0, 1};
+ std::array<int, 18> a2 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 33> a3 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 65> a4 = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
+ std::array<int, 299> a5 = {};
+ for (unsigned i = 0; i < a5.size(); i += 2)
+ a5[i] = 1;
+
+ // Tests for allocator-extended copy constructor with word size up to 5 (i.e., bit size > 256 on a 64-bit system)
+ { // Test with the default std::allocator
+ test(std::vector<bool>(a1.begin(), a1.end()), std::allocator<bool>());
+ test(std::vector<bool>(a2.begin(), a2.end()), std::allocator<bool>());
+ test(std::vector<bool>(a3.begin(), a3.end()), std::allocator<bool>());
+ test(std::vector<bool>(a4.begin(), a4.end()), std::allocator<bool>());
+ test(std::vector<bool>(a5.begin(), a5.end()), std::allocator<bool>());
}
- {
- 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));
- assert(l2 == l);
- assert(l2.get_allocator() == other_allocator<bool>(3));
+ { // Test with test_allocator
+ using A = test_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end(), A(5)), A(3));
+ test(C(a2.begin(), a2.end(), A(5)), A(3));
+ test(C(a3.begin(), a3.end(), A(5)), A(3));
+ test(C(a4.begin(), a4.end(), A(5)), A(3));
+ test(C(a5.begin(), a5.end(), A(5)), A(3));
}
-#if TEST_STD_VER >= 11
- {
- bool a[] = {0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0};
- bool* an = a + sizeof(a) / sizeof(a[0]);
- test(std::vector<bool, min_allocator<bool>>(a, an), min_allocator<bool>());
+ { // Test with other_allocator
+ using A = other_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end(), A(5)), A(3));
+ test(C(a2.begin(), a2.end(), A(5)), A(3));
+ test(C(a3.begin(), a3.end(), A(5)), A(3));
+ test(C(a4.begin(), a4.end(), A(5)), A(3));
+ test(C(a5.begin(), a5.end(), A(5)), A(3));
}
- {
- std::vector<bool, min_allocator<bool> > l(3, true, min_allocator<bool>());
- std::vector<bool, min_allocator<bool> > l2(l, min_allocator<bool>());
- assert(l2 == l);
- assert(l2.get_allocator() == min_allocator<bool>());
+ { // Test with min_allocator
+ using A = min_allocator<bool>;
+ using C = std::vector<bool, A>;
+ test(C(a1.begin(), a1.end(), A()), A());
+ test(C(a2.begin(), a2.end(), A()), A());
+ test(C(a3.begin(), a3.end(), A()), A());
+ test(C(a4.begin(), a4.end(), A()), A());
+ test(C(a5.begin(), a5.end(), A()), A());
}
-#endif
return true;
}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
index a69f0b5738986..96bd37f2566fb 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
@@ -9,54 +9,70 @@
// UNSUPPORTED: c++03
// <vector>
+// vector<bool>
// vector(vector&& c);
-#include <vector>
+#include <array>
#include <cassert>
-#include "test_macros.h"
-#include "test_allocator.h"
+#include <vector>
+
#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+template <unsigned N, class A>
+TEST_CONSTEXPR_CXX20 void test(const A& a) {
+ std::vector<bool, A> v(N, false, a);
+ std::vector<bool, A> v0(N, false, a);
+ for (unsigned i = 1; i < N; i += 2) {
+ v[i] = true;
+ v0[i] = true;
+ }
+ std::vector<bool, A> v2 = std::move(v);
+ assert(v2 == v0);
+ assert(v.empty()); // The moved-from vector is guarantted to be empty after move-construction
+ assert(v2.get_allocator() == v0.get_allocator());
+}
TEST_CONSTEXPR_CXX20 bool tests() {
test_allocator_statistics alloc_stats;
+
+ // Tests for move constructor with word size up to 5 (i.e., bit size > 256 for 64-bit system)
{
- std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5, &alloc_stats));
- std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5, &alloc_stats));
- for (int i = 1; i <= 3; ++i) {
- l.push_back(true);
- lo.push_back(true);
- }
- std::vector<bool, test_allocator<bool> > l2 = std::move(l);
- assert(l2 == lo);
- assert(l.empty());
- assert(l2.get_allocator() == lo.get_allocator());
+ using A = std::allocator<bool>;
+ test<5>(A());
+ test<18>(A());
+ test<33>(A());
+ test<65>(A());
+ test<299>(A());
}
{
- 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(true);
- lo.push_back(true);
- }
- std::vector<bool, other_allocator<bool> > l2 = std::move(l);
- assert(l2 == lo);
- assert(l.empty());
- assert(l2.get_allocator() == lo.get_allocator());
+ using A = other_allocator<bool>;
+ test<5>(A(5));
+ test<18>(A(5));
+ test<33>(A(5));
+ test<65>(A(5));
+ test<299>(A(5));
}
{
- 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(true);
- lo.push_back(true);
- }
- std::vector<bool, min_allocator<bool> > l2 = std::move(l);
- assert(l2 == lo);
- assert(l.empty());
- assert(l2.get_allocator() == lo.get_allocator());
+ using A = min_allocator<bool>;
+ test<5>(A());
+ test<18>(A());
+ test<33>(A());
+ test<65>(A());
+ test<299>(A());
}
{
+ using A = test_allocator<bool>;
+ test<5>(A(5, &alloc_stats));
+ test<18>(A(5, &alloc_stats));
+ test<33>(A(5, &alloc_stats));
+ test<65>(A(5, &alloc_stats));
+ test<299>(A(5, &alloc_stats));
+ }
+
+ { // Tests to verify the allocator statistics after move
alloc_stats.clear();
using Vect = std::vector<bool, test_allocator<bool> >;
using AllocT = Vect::allocator_type;
@@ -83,7 +99,6 @@ TEST_CONSTEXPR_CXX20 bool tests() {
const AllocT& a2 = v2.get_allocator();
assert(a2.get_id() == 101);
assert(a2.get_data() == 42);
-
assert(a1 == a2);
}
}
diff --git a/libcxx/test/std/containers/sequences/vector.bool/move_alloc.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/move_alloc.pass.cpp
index 01e7410040686..f2d576c092c09 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/move_alloc.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/move_alloc.pass.cpp
@@ -9,63 +9,79 @@
// UNSUPPORTED: c++03
// <vector>
+// vector<bool>
// vector(vector&& c, const allocator_type& a);
-#include <vector>
+#include <array>
#include <cassert>
-#include "test_macros.h"
-#include "test_allocator.h"
+#include <vector>
+
#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+template <unsigned N, class A>
+TEST_CONSTEXPR_CXX20 void test(const A& a, const A& a0) {
+ std::vector<bool, A> v(N, false, a);
+ std::vector<bool, A> v0(N, false, a0);
+ for (unsigned i = 1; i < N; i += 2) {
+ v[i] = true;
+ v0[i] = true;
+ }
+ std::vector<bool, A> v2(std::move(v), a0);
+ assert(v2 == v0);
+ assert(v2.get_allocator() == a0);
+ if (a == a0)
+ assert(v.empty()); // After container-move, the vector is guarantted to be empty
+ else
+ LIBCPP_ASSERT(!v.empty()); // After element-wise move, the RHS vector is not necessarily empty
+}
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(std::move(l), test_allocator<bool>(6));
- assert(l2 == lo);
- assert(!l.empty());
- assert(l2.get_allocator() == test_allocator<bool>(6));
+ { // Test with default allocator: compatible allocators
+ using A = std::allocator<bool>;
+ test<5>(A(), A());
+ test<17>(A(), A());
+ test<65>(A(), A());
+ test<299>(A(), A());
}
- {
- 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(std::move(l), test_allocator<bool>(5));
- assert(l2 == lo);
- assert(l.empty());
- assert(l2.get_allocator() == test_allocator<bool>(5));
+ { // Test with test_allocator: compatible and incompatible allocators
+ using A = test_allocator<bool>;
+
+ // Compatible allocators
+ test<5>(A(5), A(5));
+ test<17>(A(5), A(5));
+ test<65>(A(5), A(5));
+ test<299>(A(5), A(5));
+
+ // Incompatible allocators
+ test<5>(A(5), A(6));
+ test<17>(A(5), A(6));
+ test<65>(A(5), A(6));
+ test<299>(A(5), A(6));
}
- {
- 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(std::move(l), other_allocator<bool>(4));
- assert(l2 == lo);
- assert(!l.empty());
- assert(l2.get_allocator() == other_allocator<bool>(4));
+ { // Test with other_allocator: compatible and incompatible allocators
+ using A = other_allocator<bool>;
+
+ // Compatible allocators
+ test<5>(A(5), A(5));
+ test<17>(A(5), A(5));
+ test<65>(A(5), A(5));
+ test<299>(A(5), A(5));
+
+ // Incompatible allocators
+ test<5>(A(5), A(3));
+ test<17>(A(5), A(3));
+ test<65>(A(5), A(3));
+ test<299>(A(5), A(3));
}
- {
- 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(std::move(l), min_allocator<bool>());
- assert(l2 == lo);
- assert(l.empty());
- assert(l2.get_allocator() == min_allocator<bool>());
+ { // Test with min_allocator: compatible allocators
+ using A = min_allocator<bool>;
+ test<5>(A(), A());
+ test<17>(A(), A());
+ test<65>(A(), A());
+ test<299>(A(), A());
}
return true;
More information about the libcxx-commits
mailing list