Skip to content

Commit 2d317d9

Browse files
authored
[libc++] Fix no-op shrink_to_fit for vector<bool> (#120495)
This PR addresses an issue where the `shrink_to_fit` function in `vector<bool>` is effectively a no-op, meaning it will never shrink the capacity. Fixes #122502
1 parent 48b2ce9 commit 2d317d9

File tree

2 files changed

+50
-8
lines changed

2 files changed

+50
-8
lines changed

libcxx/include/__vector/vector_bool.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -859,11 +859,13 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::reserve(size_type _
859859

860860
template <class _Allocator>
861861
_LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<bool, _Allocator>::shrink_to_fit() _NOEXCEPT {
862-
if (__external_cap_to_internal(size()) > __cap_) {
862+
if (__external_cap_to_internal(size()) < __cap_) {
863863
#if _LIBCPP_HAS_EXCEPTIONS
864864
try {
865865
#endif // _LIBCPP_HAS_EXCEPTIONS
866-
vector(*this, allocator_type(__alloc_)).swap(*this);
866+
vector __v(*this, allocator_type(__alloc_));
867+
if (__v.__cap_ < __cap_)
868+
__v.swap(*this);
867869
#if _LIBCPP_HAS_EXCEPTIONS
868870
} catch (...) {
869871
}

libcxx/test/std/containers/sequences/vector.bool/shrink_to_fit.pass.cpp

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111

1212
// void shrink_to_fit();
1313

14+
// XFAIL: FROZEN-CXX03-HEADERS-FIXME
15+
1416
#include <cassert>
17+
#include <climits>
1518
#include <vector>
1619

1720
#include "increasing_allocator.h"
@@ -20,19 +23,56 @@
2023

2124
TEST_CONSTEXPR_CXX20 bool tests() {
2225
{
23-
std::vector<bool> v(100);
26+
using C = std::vector<bool>;
27+
C v(100);
2428
v.push_back(1);
29+
C::size_type before_cap = v.capacity();
30+
v.clear();
2531
v.shrink_to_fit();
26-
assert(v.capacity() >= 101);
27-
assert(v.size() >= 101);
32+
assert(v.capacity() <= before_cap);
33+
LIBCPP_ASSERT(v.capacity() == 0); // libc++ honors the shrink_to_fit request as a QOI matter
34+
assert(v.size() == 0);
2835
}
29-
#if TEST_STD_VER >= 11
3036
{
31-
std::vector<bool, min_allocator<bool>> v(100);
37+
using C = std::vector<bool, min_allocator<bool> >;
38+
C v(100);
3239
v.push_back(1);
40+
C::size_type before_cap = v.capacity();
3341
v.shrink_to_fit();
3442
assert(v.capacity() >= 101);
35-
assert(v.size() >= 101);
43+
assert(v.capacity() <= before_cap);
44+
assert(v.size() == 101);
45+
v.erase(v.begin() + 1, v.end());
46+
v.shrink_to_fit();
47+
assert(v.capacity() <= before_cap);
48+
LIBCPP_ASSERT(v.capacity() == C(1).capacity()); // libc++ honors the shrink_to_fit request as a QOI matter.
49+
assert(v.size() == 1);
50+
}
51+
52+
#if defined(_LIBCPP_VERSION)
53+
{
54+
using C = std::vector<bool>;
55+
unsigned bits_per_word = static_cast<unsigned>(sizeof(C::__storage_type) * CHAR_BIT);
56+
C v(bits_per_word);
57+
v.push_back(1);
58+
assert(v.capacity() == bits_per_word * 2);
59+
assert(v.size() == bits_per_word + 1);
60+
v.pop_back();
61+
v.shrink_to_fit();
62+
assert(v.capacity() == bits_per_word);
63+
assert(v.size() == bits_per_word);
64+
}
65+
{
66+
using C = std::vector<bool>;
67+
unsigned bits_per_word = static_cast<unsigned>(sizeof(C::__storage_type) * CHAR_BIT);
68+
C v;
69+
v.reserve(bits_per_word * 2);
70+
v.push_back(1);
71+
assert(v.capacity() == bits_per_word * 2);
72+
assert(v.size() == 1);
73+
v.shrink_to_fit();
74+
assert(v.capacity() == bits_per_word);
75+
assert(v.size() == 1);
3676
}
3777
#endif
3878

0 commit comments

Comments
 (0)