[libcxx-commits] [libcxx] [libc++] Simplify vector<bool>::flip() and add new tests (PR #119607)

Peng Liu via libcxx-commits libcxx-commits at lists.llvm.org
Tue Dec 17 09:49:59 PST 2024


https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/119607

>From bb31bba77d25c690df461d839556366e39ce5361 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Wed, 11 Dec 2024 14:25:56 -0500
Subject: [PATCH 1/3] Simplify vector<bool>::flip() and add new tests

---
 libcxx/include/__vector/vector_bool.h         |  12 +--
 .../sequences/vector.bool/flip.pass.cpp       | 100 ++++++++++++++++++
 2 files changed, 104 insertions(+), 8 deletions(-)
 create mode 100644 libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp

diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h
index 36eb7f350ac406..1021465a9325b9 100644
--- a/libcxx/include/__vector/vector_bool.h
+++ b/libcxx/include/__vector/vector_bool.h
@@ -1049,18 +1049,14 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::resize(size_type __
 
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::flip() _NOEXCEPT {
-  // do middle whole words
+  // Process the whole words in the front
   size_type __n         = __size_;
   __storage_pointer __p = __begin_;
   for (; __n >= __bits_per_word; ++__p, __n -= __bits_per_word)
     *__p = ~*__p;
-  // do last partial word
-  if (__n > 0) {
-    __storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
-    __storage_type __b = *__p & __m;
-    *__p &= ~__m;
-    *__p |= ~__b & __m;
-  }
+  // Process the last partial word, if it exists
+  if (__n > 0)
+    *__p ^= ~__storage_type(0) >> (__bits_per_word - __n);
 }
 
 template <class _Allocator>
diff --git a/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp
new file mode 100644
index 00000000000000..5be52bffc5ffb5
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp
@@ -0,0 +1,100 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <vector>
+
+// flip()
+
+#include <cassert>
+#include <vector>
+
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_macros.h"
+
+TEST_CONSTEXPR_CXX20 bool tests() {
+  //
+  // Testing flip() function with small vectors and various allocators
+  //
+  {
+    std::vector<bool> v;
+    v.push_back(true);
+    v.push_back(false);
+    v.push_back(true);
+    v.flip();
+    assert(!v[0]);
+    assert(v[1]);
+    assert(!v[2]);
+  }
+  {
+    std::vector<bool, min_allocator<bool> > v;
+    v.push_back(true);
+    v.push_back(false);
+    v.push_back(true);
+    v.flip();
+    assert(!v[0]);
+    assert(v[1]);
+    assert(!v[2]);
+  }
+  {
+    std::vector<bool, test_allocator<bool> > v(test_allocator<bool>(5));
+    v.push_back(true);
+    v.push_back(false);
+    v.push_back(true);
+    v.flip();
+    assert(!v[0]);
+    assert(v[1]);
+    assert(!v[2]);
+  }
+
+  //
+  // Testing flip() function with larger vectors
+  //
+  {
+    std::vector<bool> v(1000);
+    for (std::size_t i = 0; i < v.size(); ++i)
+      v[i] = i & 1;
+    std::vector<bool> original = v;
+    v.flip();
+    for (size_t i = 0; i < v.size(); ++i) {
+      assert(v[i] == !original[i]);
+    }
+  }
+  {
+    std::vector<bool, min_allocator<bool> > v(1000, false, min_allocator<bool>());
+    for (std::size_t i = 0; i < v.size(); ++i)
+      v[i] = i & 1;
+    std::vector<bool, min_allocator<bool> > original = v;
+    v.flip();
+    for (size_t i = 0; i < v.size(); ++i)
+      assert(v[i] == !original[i]);
+    v.flip();
+    assert(v == original);
+  }
+  {
+    std::vector<bool, test_allocator<bool> > v(1000, false, test_allocator<bool>(5));
+    for (std::size_t i = 0; i < v.size(); ++i)
+      v[i] = i & 1;
+    std::vector<bool, test_allocator<bool> > original = v;
+    v.flip();
+    for (size_t i = 0; i < v.size(); ++i)
+      assert(v[i] == !original[i]);
+    v.flip();
+    assert(v == original);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  tests();
+#if TEST_STD_VER > 17
+  static_assert(tests());
+#endif
+  return 0;
+}

>From a1d4c0c6a92f0cacd121cc2b237ca4028206d238 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Thu, 12 Dec 2024 11:22:17 -0500
Subject: [PATCH 2/3] Unconditionally flip the last word

---
 libcxx/include/__vector/vector_bool.h                    | 9 +++------
 .../std/containers/sequences/vector.bool/flip.pass.cpp   | 2 +-
 2 files changed, 4 insertions(+), 7 deletions(-)

diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h
index 1021465a9325b9..d6574596802497 100644
--- a/libcxx/include/__vector/vector_bool.h
+++ b/libcxx/include/__vector/vector_bool.h
@@ -1049,14 +1049,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::resize(size_type __
 
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::flip() _NOEXCEPT {
-  // Process the whole words in the front
-  size_type __n         = __size_;
+  // Flip each storage word entirely, including the last potentially partial word.
+  // The unused bits in the last word are safe to flip as they won't be accessed.
   __storage_pointer __p = __begin_;
-  for (; __n >= __bits_per_word; ++__p, __n -= __bits_per_word)
+  for (size_type __n = __external_cap_to_internal(size()); __n; ++__p, --__n)
     *__p = ~*__p;
-  // Process the last partial word, if it exists
-  if (__n > 0)
-    *__p ^= ~__storage_type(0) >> (__bits_per_word - __n);
 }
 
 template <class _Allocator>
diff --git a/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp
index 5be52bffc5ffb5..2c3d4c8f53fdff 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp
@@ -8,7 +8,7 @@
 
 // <vector>
 
-// flip()
+// void flip();
 
 #include <cassert>
 #include <vector>

>From 4c38c1ef77f935e0feb75aa2f98eabf34e45a51a Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Sat, 14 Dec 2024 08:02:37 -0500
Subject: [PATCH 3/3] Refactor test file

---
 libcxx/include/__vector/vector_bool.h         |  2 +-
 .../sequences/vector.bool/flip.pass.cpp       | 92 +++++--------------
 2 files changed, 24 insertions(+), 70 deletions(-)

diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h
index d6574596802497..525fc35b26cc9e 100644
--- a/libcxx/include/__vector/vector_bool.h
+++ b/libcxx/include/__vector/vector_bool.h
@@ -1052,7 +1052,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::flip() _NOEXCEPT {
   // Flip each storage word entirely, including the last potentially partial word.
   // The unused bits in the last word are safe to flip as they won't be accessed.
   __storage_pointer __p = __begin_;
-  for (size_type __n = __external_cap_to_internal(size()); __n; ++__p, --__n)
+  for (size_type __n = __external_cap_to_internal(size()); __n != 0; ++__p, --__n)
     *__p = ~*__p;
 }
 
diff --git a/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp
index 2c3d4c8f53fdff..f8f575cdc0e219 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/flip.pass.cpp
@@ -11,89 +11,43 @@
 // void flip();
 
 #include <cassert>
+#include <memory>
 #include <vector>
 
 #include "min_allocator.h"
 #include "test_allocator.h"
 #include "test_macros.h"
 
+template <typename Allocator>
+TEST_CONSTEXPR_CXX20 void test_vector_flip(std::size_t n, Allocator a) {
+  std::vector<bool, Allocator> v(n, false, a);
+  for (std::size_t i = 0; i < n; ++i)
+    v[i] = i & 1;
+  std::vector<bool, Allocator> original = v;
+  v.flip();
+  for (size_t i = 0; i < n; ++i)
+    assert(v[i] == !original[i]);
+  v.flip();
+  assert(v == original);
+}
+
 TEST_CONSTEXPR_CXX20 bool tests() {
-  //
-  // Testing flip() function with small vectors and various allocators
-  //
-  {
-    std::vector<bool> v;
-    v.push_back(true);
-    v.push_back(false);
-    v.push_back(true);
-    v.flip();
-    assert(!v[0]);
-    assert(v[1]);
-    assert(!v[2]);
-  }
-  {
-    std::vector<bool, min_allocator<bool> > v;
-    v.push_back(true);
-    v.push_back(false);
-    v.push_back(true);
-    v.flip();
-    assert(!v[0]);
-    assert(v[1]);
-    assert(!v[2]);
-  }
-  {
-    std::vector<bool, test_allocator<bool> > v(test_allocator<bool>(5));
-    v.push_back(true);
-    v.push_back(false);
-    v.push_back(true);
-    v.flip();
-    assert(!v[0]);
-    assert(v[1]);
-    assert(!v[2]);
-  }
+  // Test small vectors with different allocators
+  test_vector_flip(3, std::allocator<bool>());
+  test_vector_flip(3, min_allocator<bool>());
+  test_vector_flip(3, test_allocator<bool>(5));
 
-  //
-  // Testing flip() function with larger vectors
-  //
-  {
-    std::vector<bool> v(1000);
-    for (std::size_t i = 0; i < v.size(); ++i)
-      v[i] = i & 1;
-    std::vector<bool> original = v;
-    v.flip();
-    for (size_t i = 0; i < v.size(); ++i) {
-      assert(v[i] == !original[i]);
-    }
-  }
-  {
-    std::vector<bool, min_allocator<bool> > v(1000, false, min_allocator<bool>());
-    for (std::size_t i = 0; i < v.size(); ++i)
-      v[i] = i & 1;
-    std::vector<bool, min_allocator<bool> > original = v;
-    v.flip();
-    for (size_t i = 0; i < v.size(); ++i)
-      assert(v[i] == !original[i]);
-    v.flip();
-    assert(v == original);
-  }
-  {
-    std::vector<bool, test_allocator<bool> > v(1000, false, test_allocator<bool>(5));
-    for (std::size_t i = 0; i < v.size(); ++i)
-      v[i] = i & 1;
-    std::vector<bool, test_allocator<bool> > original = v;
-    v.flip();
-    for (size_t i = 0; i < v.size(); ++i)
-      assert(v[i] == !original[i]);
-    v.flip();
-    assert(v == original);
-  }
+  // Test large vectors with different allocators
+  test_vector_flip(1000, std::allocator<bool>());
+  test_vector_flip(1000, min_allocator<bool>());
+  test_vector_flip(1000, test_allocator<bool>(5));
 
   return true;
 }
 
 int main(int, char**) {
   tests();
-#if TEST_STD_VER > 17
+#if TEST_STD_VER >= 20
   static_assert(tests());
 #endif
   return 0;



More information about the libcxx-commits mailing list