Skip to content
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

[libc++][vector] Fixes shrink_to_fit. #97895

Merged
merged 2 commits into from
Jul 20, 2024

Conversation

mordante
Copy link
Member

@mordante mordante commented Jul 6, 2024

This assures shrink_to_fit does not increase the allocated size.

Partly addresses #95161

@mordante mordante requested a review from a team as a code owner July 6, 2024 13:05
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jul 6, 2024
@llvmbot
Copy link
Collaborator

llvmbot commented Jul 6, 2024

@llvm/pr-subscribers-libcxx

Author: Mark de Wever (mordante)

Changes

This assures shrink_to_fit does not increase the allocated size.

Partly addresses #95161


Full diff: https://github.com/llvm/llvm-project/pull/97895.diff

2 Files Affected:

  • (modified) libcxx/include/vector (+5-1)
  • (modified) libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp (+37)
diff --git a/libcxx/include/vector b/libcxx/include/vector
index 299ad8c9b23f2..7c7adb0da7da5 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -1443,7 +1443,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE
 #endif // _LIBCPP_HAS_NO_EXCEPTIONS
       allocator_type& __a = this->__alloc();
       __split_buffer<value_type, allocator_type&> __v(size(), size(), __a);
-      __swap_out_circular_buffer(__v);
+      // The Standard mandates shrink_to_fit() does not increase the capacity.
+      // With equal capacity keep the existing buffer. This avoids extra work
+      // due to swapping the elements.
+      if (__v.capacity() < capacity())
+        __swap_out_circular_buffer(__v);
 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
     } catch (...) {
     }
diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp
index 8851e2a9ed0c7..facb724c713af 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp
@@ -71,9 +71,46 @@ TEST_CONSTEXPR_CXX20 bool tests() {
     return true;
 }
 
+std::size_t min_bytes = 1000;
+
+template <typename T>
+struct increasing_allocator {
+  using value_type       = T;
+  increasing_allocator() = default;
+  template <typename U>
+  increasing_allocator(const increasing_allocator<U>&) noexcept {}
+  std::allocation_result<T*> allocate_at_least(std::size_t n) {
+    std::size_t allocation_amount = n * sizeof(T);
+    if (allocation_amount < min_bytes)
+      allocation_amount = min_bytes;
+    min_bytes += 1000;
+    return {static_cast<T*>(::operator new(allocation_amount)), allocation_amount};
+  }
+  T* allocate(std::size_t n) { return allocate_at_least(n).ptr; }
+  void deallocate(T* p, std::size_t) noexcept { ::operator delete(static_cast<void*>(p)); }
+};
+
+template <typename T, typename U>
+bool operator==(increasing_allocator<T>, increasing_allocator<U>) {
+  return true;
+}
+
+// https://github.com/llvm/llvm-project/issues/95161
+void test_increasing_allocator() {
+  std::vector<int, increasing_allocator<int>> v;
+  v.push_back(1);
+  assert(is_contiguous_container_asan_correct(v));
+  std::size_t capacity = v.capacity();
+  v.shrink_to_fit();
+  assert(v.capacity() == capacity);
+  assert(v.size() == 1);
+  assert(is_contiguous_container_asan_correct(v));
+}
+
 int main(int, char**)
 {
     tests();
+    test_increasing_allocator();
 #if TEST_STD_VER > 17
     static_assert(tests());
 #endif

@mordante mordante force-pushed the review/vector_shrink_to_fit branch from c7f62ec to 2e82109 Compare July 6, 2024 13:49
Copy link

github-actions bot commented Jul 7, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@ldionne ldionne added this to the LLVM 19.X Release milestone Jul 9, 2024
Copy link
Member

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is somewhat frustrating to throw away the allocation we just made because it ends up being larger than the one we already had, but it makes us conforming and it does save us from having to copy the elements over to the new buffer. So technically we are saving some work (depending on the relative cost of everything, of course).

What we'd really like is a way to ask the allocator for at most n bytes. That way the allocator could instead report that it can only give us more than n bytes, and we'd likely prevent the system allocator from having to do additional work.

Anyway, this LGTM with a suggestion for the tests.

mordante and others added 2 commits July 16, 2024 19:57
This assures shrink_to_fit does not increase the allocated size.

Partly addresses llvm#95161
@mordante mordante force-pushed the review/vector_shrink_to_fit branch from 78dedd7 to a9f9e7a Compare July 16, 2024 17:58
@mordante
Copy link
Member Author

What we'd really like is a way to ask the allocator for at most n bytes. That way the allocator could instead report that it can only give us more than n bytes, and we'd likely prevent the system allocator from having to do additional work.

That is what allocate does, but that secretly throws away bytes. I expect the case where the allocator gives more bytes would be rare, the arena allocator in the example seems a good example.

@mordante mordante merged commit f65d7fd into llvm:main Jul 20, 2024
55 checks passed
@mordante mordante deleted the review/vector_shrink_to_fit branch July 20, 2024 10:55
sgundapa pushed a commit to sgundapa/upstream_effort that referenced this pull request Jul 23, 2024
This assures shrink_to_fit does not increase the allocated size.

Partly addresses llvm#95161

---------

Co-authored-by: Mital Ashok <[email protected]>
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
Summary:
This assures shrink_to_fit does not increase the allocated size.

Partly addresses #95161

---------

Co-authored-by: Mital Ashok <[email protected]>

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60251479
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants