[libcxx-commits] [libcxx] [libc++] Fix no-op shrink_to_fit for vector<bool> (PR #120495)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Mon Jan 20 10:58:35 PST 2025


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/120495

>From db6047340bfc70962496053b24c68f5f68954a7f Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Wed, 18 Dec 2024 18:23:11 -0500
Subject: [PATCH 1/2] Fix no-op shrink_to_fit in vector<bool>

---
 libcxx/include/__vector/vector_bool.h         |  6 ++-
 .../vector.bool/shrink_to_fit.pass.cpp        | 45 ++++++++++++++++---
 2 files changed, 43 insertions(+), 8 deletions(-)

diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h
index 2b721e00058bc6..b35f3f1fdf322d 100644
--- a/libcxx/include/__vector/vector_bool.h
+++ b/libcxx/include/__vector/vector_bool.h
@@ -859,11 +859,13 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::reserve(size_type _
 
 template <class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::shrink_to_fit() _NOEXCEPT {
-  if (__external_cap_to_internal(size()) > __cap_) {
+  if (__external_cap_to_internal(size()) < __cap_) {
 #if _LIBCPP_HAS_EXCEPTIONS
     try {
 #endif // _LIBCPP_HAS_EXCEPTIONS
-      vector(*this, allocator_type(__alloc_)).swap(*this);
+      vector __v(*this, allocator_type(__alloc_));
+      if (__v.__cap_ < __cap_)
+        __v.swap(*this);
 #if _LIBCPP_HAS_EXCEPTIONS
     } catch (...) {
     }
diff --git a/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp
index 3bc639d0479f96..59dea978f0194a 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp
@@ -11,7 +11,10 @@
 
 // void shrink_to_fit();
 
+// XFAIL: FROZEN-CXX03-HEADERS-FIXME
+
 #include <cassert>
+#include <climits>
 #include <vector>
 
 #include "increasing_allocator.h"
@@ -20,19 +23,49 @@
 
 TEST_CONSTEXPR_CXX20 bool tests() {
   {
-    std::vector<bool> v(100);
+    using C = std::vector<bool>;
+    C v(100);
     v.push_back(1);
+    v.clear();
     v.shrink_to_fit();
-    assert(v.capacity() >= 101);
-    assert(v.size() >= 101);
+    assert(v.capacity() == 0);
+    assert(v.size() == 0);
   }
-#if TEST_STD_VER >= 11
   {
-    std::vector<bool, min_allocator<bool>> v(100);
+    using C = std::vector<bool, min_allocator<bool> >;
+    C v(100);
     v.push_back(1);
+    C::size_type before_cap = v.capacity();
     v.shrink_to_fit();
     assert(v.capacity() >= 101);
-    assert(v.size() >= 101);
+    assert(v.capacity() <= before_cap);
+    assert(v.size() == 101);
+  }
+
+#if defined(_LIBCPP_VERSION)
+  {
+    using C                = std::vector<bool>;
+    unsigned bits_per_word = static_cast<unsigned>(sizeof(C::__storage_type) * CHAR_BIT);
+    C v(bits_per_word);
+    v.push_back(1);
+    assert(v.capacity() == bits_per_word * 2);
+    assert(v.size() == bits_per_word + 1);
+    v.pop_back();
+    v.shrink_to_fit();
+    assert(v.capacity() == bits_per_word);
+    assert(v.size() == bits_per_word);
+  }
+  {
+    using C                = std::vector<bool>;
+    unsigned bits_per_word = static_cast<unsigned>(sizeof(C::__storage_type) * CHAR_BIT);
+    C v;
+    v.reserve(bits_per_word * 2);
+    v.push_back(1);
+    assert(v.capacity() == bits_per_word * 2);
+    assert(v.size() == 1);
+    v.shrink_to_fit();
+    assert(v.capacity() == bits_per_word);
+    assert(v.size() == 1);
   }
 #endif
 

>From 110829580f8b50a56cff3301cd855d1fb13d69e0 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Mon, 20 Jan 2025 13:29:39 -0500
Subject: [PATCH 2/2] Use LIBCPP_ASSERT for portability

---
 .../sequences/vector.bool/shrink_to_fit.pass.cpp         | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp
index 59dea978f0194a..30efe047054ab0 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp
@@ -26,9 +26,11 @@ TEST_CONSTEXPR_CXX20 bool tests() {
     using C = std::vector<bool>;
     C v(100);
     v.push_back(1);
+    C::size_type before_cap = v.capacity();
     v.clear();
     v.shrink_to_fit();
-    assert(v.capacity() == 0);
+    assert(v.capacity() <= before_cap);
+    LIBCPP_ASSERT(v.capacity() == 0); // libc++ honors the shrink_to_fit request as a QOI matter
     assert(v.size() == 0);
   }
   {
@@ -40,6 +42,11 @@ TEST_CONSTEXPR_CXX20 bool tests() {
     assert(v.capacity() >= 101);
     assert(v.capacity() <= before_cap);
     assert(v.size() == 101);
+    v.erase(v.begin() + 1, v.end());
+    v.shrink_to_fit();
+    assert(v.capacity() <= before_cap);
+    LIBCPP_ASSERT(v.capacity() == C(1).capacity()); // libc++ honors the shrink_to_fit request as a QOI matter.
+    assert(v.size() == 1);
   }
 
 #if defined(_LIBCPP_VERSION)



More information about the libcxx-commits mailing list