[libcxx-commits] [libcxx] [libc++] ~vector: Don't __clear trivial typed elements (PR #86947)
Johan Gardell via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Mar 28 05:52:25 PDT 2024
https://github.com/gardell created https://github.com/llvm/llvm-project/pull/86947
I've been optimizing some code that streams large amounts of binary data using `std::vector<uint8_t>` and in the profiler I can see that the application spends a lot of time in `~vector()`, specifically `__clear()`.
For the `std::vector<bool>` specialization, `__clear` is not called when destructing the vector. I believe this is because `bool` is trivially destructible.
In this PR I propose a template specialization of `__destroy_vector` in the general `vector<T>` case that allows us to suppress the call to `__clear` if the element type in question is `is_trivially_destructible`.
Please let me know if I should clarify something. This is my first submission so I am sure I've gotten a lot of stuff wrong!
Regards
>From 6917d186bbb197356bdeaf663380976c8080aba1 Mon Sep 17 00:00:00 2001
From: Johan Gardell <grdll at amazon.com>
Date: Thu, 28 Mar 2024 10:38:12 +0100
Subject: [PATCH] [libc++] ~vector: Don't __clear trivial elements
If the element type of a `vector` is `trivially_destructible` do not
call `__clear` when destroying the `vector`.
---
libcxx/include/vector | 10 +++
...dtor_no_trivial_element_dtor_call.pass.cpp | 85 +++++++++++++++++++
2 files changed, 95 insertions(+)
create mode 100644 libcxx/test/std/containers/sequences/vector/vector.cons/dtor_no_trivial_element_dtor_call.pass.cpp
diff --git a/libcxx/include/vector b/libcxx/include/vector
index 0908482600c533..e0df865366103a 100644
--- a/libcxx/include/vector
+++ b/libcxx/include/vector
@@ -347,6 +347,7 @@ template<class T, class charT> requires is-vector-bool-reference<T> // Since C++
#include <__type_traits/is_allocator.h>
#include <__type_traits/is_constructible.h>
#include <__type_traits/is_nothrow_assignable.h>
+#include <__type_traits/is_trivially_destructible.h>
#include <__type_traits/noexcept_move_assign_container.h>
#include <__type_traits/type_identity.h>
#include <__utility/exception_guard.h>
@@ -486,6 +487,15 @@ private:
public:
_LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI __destroy_vector(vector& __vec) : __vec_(__vec) {}
+ template <typename _Tp2 = _Tp, __enable_if_t<is_trivially_destructible<_Tp2>::value, int> = 0>
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()() {
+ if (__vec_.__begin_ != nullptr) {
+ __vec_.__annotate_delete();
+ __alloc_traits::deallocate(__vec_.__alloc(), __vec_.__begin_, __vec_.capacity());
+ }
+ }
+
+ template <typename _Tp2 = _Tp, __enable_if_t<!is_trivially_destructible<_Tp2>::value, int> = 0>
_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void operator()() {
if (__vec_.__begin_ != nullptr) {
__vec_.__clear();
diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/dtor_no_trivial_element_dtor_call.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/dtor_no_trivial_element_dtor_call.pass.cpp
new file mode 100644
index 00000000000000..5a5399e2fffc68
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector/vector.cons/dtor_no_trivial_element_dtor_call.pass.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+#include <cassert>
+
+struct int_alloc
+{
+ typedef int value_type;
+
+ template< class U >
+ struct rebind
+ {
+ typedef int_alloc other;
+ };
+
+ int* allocate(std::size_t n)
+ {
+ return new int[n];
+ }
+ void deallocate(int* p, std::size_t n)
+ {
+ for (std::size_t i = 0; i < n; ++i) {
+ assert(p[i] != 0);
+ }
+ delete p;
+ }
+};
+
+struct with_dtor
+{
+ with_dtor() = default;
+ with_dtor(const with_dtor &) = default;
+
+ int x = 42;
+
+ ~with_dtor() {
+ x = 0;
+ }
+};
+
+struct with_dtor_alloc
+{
+ typedef with_dtor value_type;
+
+ template< class U >
+ struct rebind
+ {
+ typedef with_dtor_alloc other;
+ };
+
+ with_dtor* allocate(std::size_t n)
+ {
+ return new with_dtor[n];
+ }
+ void deallocate(with_dtor* p, std::size_t n)
+ {
+ for (std::size_t i = 0; i < n; ++i) {
+ assert(p[i].x == 0);
+ }
+ delete[] p;
+ }
+};
+
+void tests()
+{
+ {
+ std::vector<with_dtor, with_dtor_alloc> v(5, with_dtor());
+ }
+ {
+ std::vector<int, int_alloc> v(5, 42);
+ }
+}
+
+int main(int, char**)
+{
+ tests();
+ return 0;
+}
+
More information about the libcxx-commits
mailing list