From f332455dd9a2b2b3ecb20f28349673313c5b440b Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 10 Feb 2025 21:19:46 +0100 Subject: [PATCH] [libc++] Extract destroy algorithms into separate headers (#126449) This patch separates the destroy algorithms from the primitive construct_at and destroy_at operations, which are conceptually not algorithms. This makes it easier to start using these destroy algorithms from upcoming relocation facilities. As part of this, it also implements `std::destroy_at` for arrays without relying on the `std::destroy` algorithm, which is conceptually a higher-level facility. --- libcxx/include/CMakeLists.txt | 2 + libcxx/include/__format/buffer.h | 7 +- libcxx/include/__memory/construct_at.h | 37 +-------- libcxx/include/__memory/destroy.h | 71 +++++++++++++++++ libcxx/include/__memory/ranges_construct_at.h | 35 -------- libcxx/include/__memory/ranges_destroy.h | 79 +++++++++++++++++++ libcxx/include/__memory/shared_ptr.h | 1 + .../__memory/uninitialized_algorithms.h | 9 +-- libcxx/include/__pstl/backends/libdispatch.h | 1 + libcxx/include/memory | 2 + libcxx/include/module.modulemap | 2 + 11 files changed, 165 insertions(+), 81 deletions(-) create mode 100644 libcxx/include/__memory/destroy.h create mode 100644 libcxx/include/__memory/ranges_destroy.h diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index ce805b4eb7b8..255a0474c0f6 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -557,12 +557,14 @@ set(files __memory/compressed_pair.h __memory/concepts.h __memory/construct_at.h + __memory/destroy.h __memory/destruct_n.h __memory/inout_ptr.h __memory/noexcept_move_assign_container.h __memory/out_ptr.h __memory/pointer_traits.h __memory/ranges_construct_at.h + __memory/ranges_destroy.h __memory/ranges_uninitialized_algorithms.h __memory/raw_storage_iterator.h __memory/shared_count.h diff --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h index 0c054bbc3a1d..c88b7f322201 100644 --- a/libcxx/include/__format/buffer.h +++ b/libcxx/include/__format/buffer.h @@ -15,7 +15,6 @@ #include <__algorithm/max.h> #include <__algorithm/min.h> #include <__algorithm/ranges_copy.h> -#include <__algorithm/ranges_copy_n.h> #include <__algorithm/transform.h> #include <__algorithm/unwrap_iter.h> #include <__concepts/same_as.h> @@ -33,7 +32,7 @@ #include <__memory/allocator.h> #include <__memory/allocator_traits.h> #include <__memory/construct_at.h> -#include <__memory/ranges_construct_at.h> +#include <__memory/destroy.h> #include <__memory/uninitialized_algorithms.h> #include <__type_traits/add_pointer.h> #include <__type_traits/conditional.h> @@ -621,7 +620,7 @@ public: } _LIBCPP_HIDE_FROM_ABI ~__retarget_buffer() { - ranges::destroy_n(__ptr_, __size_); + std::destroy_n(__ptr_, __size_); allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_); } @@ -686,7 +685,7 @@ private: // guard is optimized away so there is no runtime overhead. std::uninitialized_move_n(__ptr_, __size_, __result.ptr); __guard.__complete(); - ranges::destroy_n(__ptr_, __size_); + std::destroy_n(__ptr_, __size_); allocator_traits<_Alloc>::deallocate(__alloc_, __ptr_, __capacity_); __ptr_ = __result.ptr; diff --git a/libcxx/include/__memory/construct_at.h b/libcxx/include/__memory/construct_at.h index 1f129d17970b..21337e766b2d 100644 --- a/libcxx/include/__memory/construct_at.h +++ b/libcxx/include/__memory/construct_at.h @@ -57,9 +57,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp* __construct_at(_Tp* __l // The internal functions are available regardless of the language version (with the exception of the `__destroy_at` // taking an array). -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator __destroy(_ForwardIterator, _ForwardIterator); - template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __destroy_at(_Tp* __loc) { _LIBCPP_ASSERT_NON_NULL(__loc != nullptr, "null pointer given to destroy_at"); @@ -70,28 +67,12 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __destroy_at(_Tp* __loc template ::value, int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __destroy_at(_Tp* __loc) { _LIBCPP_ASSERT_NON_NULL(__loc != nullptr, "null pointer given to destroy_at"); - std::__destroy(std::begin(*__loc), std::end(*__loc)); + auto const __end = std::end(*__loc); + for (auto __it = std::begin(*__loc); __it != __end; ++__it) + std::__destroy_at(__it); } #endif -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator -__destroy(_ForwardIterator __first, _ForwardIterator __last) { - for (; __first != __last; ++__first) - std::__destroy_at(std::addressof(*__first)); - return __first; -} - -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIterator -__reverse_destroy(_BidirectionalIterator __first, _BidirectionalIterator __last) { - while (__last != __first) { - --__last; - std::__destroy_at(std::addressof(*__last)); - } - return __last; -} - #if _LIBCPP_STD_VER >= 17 template , int> = 0> @@ -106,18 +87,6 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void destroy_at(_Tp* __loc) } # endif -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void destroy(_ForwardIterator __first, _ForwardIterator __last) { - (void)std::__destroy(std::move(__first), std::move(__last)); -} - -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator destroy_n(_ForwardIterator __first, _Size __n) { - for (; __n > 0; (void)++__first, --__n) - std::__destroy_at(std::addressof(*__first)); - return __first; -} - #endif // _LIBCPP_STD_VER >= 17 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__memory/destroy.h b/libcxx/include/__memory/destroy.h new file mode 100644 index 000000000000..69a252ba1331 --- /dev/null +++ b/libcxx/include/__memory/destroy.h @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_DESTROY_H +#define _LIBCPP___MEMORY_DESTROY_H + +#include <__config> +#include <__memory/addressof.h> +#include <__memory/allocator_traits.h> +#include <__memory/construct_at.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator +__destroy(_ForwardIterator __first, _ForwardIterator __last) { + for (; __first != __last; ++__first) + std::__destroy_at(std::addressof(*__first)); + return __first; +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIterator +__reverse_destroy(_BidirectionalIterator __first, _BidirectionalIterator __last) { + while (__last != __first) { + --__last; + std::__destroy_at(std::addressof(*__last)); + } + return __last; +} + +// Destroy all elements in [__first, __last) from left to right using allocator destruction. +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void +__allocator_destroy(_Alloc& __alloc, _Iter __first, _Sent __last) { + for (; __first != __last; ++__first) + allocator_traits<_Alloc>::destroy(__alloc, std::addressof(*__first)); +} + +#if _LIBCPP_STD_VER >= 17 +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void destroy(_ForwardIterator __first, _ForwardIterator __last) { + (void)std::__destroy(std::move(__first), std::move(__last)); +} + +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator destroy_n(_ForwardIterator __first, _Size __n) { + for (; __n > 0; (void)++__first, --__n) + std::__destroy_at(std::addressof(*__first)); + return __first; +} +#endif + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MEMORY_DESTROY_H diff --git a/libcxx/include/__memory/ranges_construct_at.h b/libcxx/include/__memory/ranges_construct_at.h index 35ed79651000..b8a94678c10c 100644 --- a/libcxx/include/__memory/ranges_construct_at.h +++ b/libcxx/include/__memory/ranges_construct_at.h @@ -61,41 +61,6 @@ inline namespace __cpo { inline constexpr auto destroy_at = __destroy_at{}; } // namespace __cpo -// destroy - -struct __destroy { - template <__nothrow_input_iterator _InputIterator, __nothrow_sentinel_for<_InputIterator> _Sentinel> - requires destructible> - _LIBCPP_HIDE_FROM_ABI constexpr _InputIterator operator()(_InputIterator __first, _Sentinel __last) const noexcept { - return std::__destroy(std::move(__first), std::move(__last)); - } - - template <__nothrow_input_range _InputRange> - requires destructible> - _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_InputRange> operator()(_InputRange&& __range) const noexcept { - return (*this)(ranges::begin(__range), ranges::end(__range)); - } -}; - -inline namespace __cpo { -inline constexpr auto destroy = __destroy{}; -} // namespace __cpo - -// destroy_n - -struct __destroy_n { - template <__nothrow_input_iterator _InputIterator> - requires destructible> - _LIBCPP_HIDE_FROM_ABI constexpr _InputIterator - operator()(_InputIterator __first, iter_difference_t<_InputIterator> __n) const noexcept { - return std::destroy_n(std::move(__first), __n); - } -}; - -inline namespace __cpo { -inline constexpr auto destroy_n = __destroy_n{}; -} // namespace __cpo - } // namespace ranges #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__memory/ranges_destroy.h b/libcxx/include/__memory/ranges_destroy.h new file mode 100644 index 000000000000..f134f1422e82 --- /dev/null +++ b/libcxx/include/__memory/ranges_destroy.h @@ -0,0 +1,79 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___MEMORY_RANGES_DESTROY_H +#define _LIBCPP___MEMORY_RANGES_DESTROY_H + +#include <__concepts/destructible.h> +#include <__config> +#include <__iterator/incrementable_traits.h> +#include <__iterator/iterator_traits.h> +#include <__memory/concepts.h> +#include <__memory/destroy.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER >= 20 +namespace ranges { + +// destroy + +struct __destroy { + template <__nothrow_input_iterator _InputIterator, __nothrow_sentinel_for<_InputIterator> _Sentinel> + requires destructible> + _LIBCPP_HIDE_FROM_ABI constexpr _InputIterator operator()(_InputIterator __first, _Sentinel __last) const noexcept { + return std::__destroy(std::move(__first), std::move(__last)); + } + + template <__nothrow_input_range _InputRange> + requires destructible> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_InputRange> operator()(_InputRange&& __range) const noexcept { + return (*this)(ranges::begin(__range), ranges::end(__range)); + } +}; + +inline namespace __cpo { +inline constexpr auto destroy = __destroy{}; +} // namespace __cpo + +// destroy_n + +struct __destroy_n { + template <__nothrow_input_iterator _InputIterator> + requires destructible> + _LIBCPP_HIDE_FROM_ABI constexpr _InputIterator + operator()(_InputIterator __first, iter_difference_t<_InputIterator> __n) const noexcept { + return std::destroy_n(std::move(__first), __n); + } +}; + +inline namespace __cpo { +inline constexpr auto destroy_n = __destroy_n{}; +} // namespace __cpo + +} // namespace ranges + +#endif // _LIBCPP_STD_VER >= 20 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___MEMORY_RANGES_DESTROY_H diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h index 06b1fc488cf5..d513fa692c1f 100644 --- a/libcxx/include/__memory/shared_ptr.h +++ b/libcxx/include/__memory/shared_ptr.h @@ -29,6 +29,7 @@ #include <__memory/auto_ptr.h> #include <__memory/compressed_pair.h> #include <__memory/construct_at.h> +#include <__memory/destroy.h> #include <__memory/pointer_traits.h> #include <__memory/shared_count.h> #include <__memory/uninitialized_algorithms.h> diff --git a/libcxx/include/__memory/uninitialized_algorithms.h b/libcxx/include/__memory/uninitialized_algorithms.h index a02a88399a7a..d7f210d12a21 100644 --- a/libcxx/include/__memory/uninitialized_algorithms.h +++ b/libcxx/include/__memory/uninitialized_algorithms.h @@ -21,6 +21,7 @@ #include <__memory/addressof.h> #include <__memory/allocator_traits.h> #include <__memory/construct_at.h> +#include <__memory/destroy.h> #include <__memory/pointer_traits.h> #include <__type_traits/enable_if.h> #include <__type_traits/extent.h> @@ -511,14 +512,6 @@ __uninitialized_allocator_value_construct_n_multidimensional(_Alloc& __alloc, _B #endif // _LIBCPP_STD_VER >= 17 -// Destroy all elements in [__first, __last) from left to right using allocator destruction. -template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void -__allocator_destroy(_Alloc& __alloc, _Iter __first, _Sent __last) { - for (; __first != __last; ++__first) - allocator_traits<_Alloc>::destroy(__alloc, std::__to_address(__first)); -} - template class _AllocatorDestroyRangeReverse { public: diff --git a/libcxx/include/__pstl/backends/libdispatch.h b/libcxx/include/__pstl/backends/libdispatch.h index 4c63c4c84420..a640a40352f5 100644 --- a/libcxx/include/__pstl/backends/libdispatch.h +++ b/libcxx/include/__pstl/backends/libdispatch.h @@ -22,6 +22,7 @@ #include <__iterator/move_iterator.h> #include <__memory/allocator.h> #include <__memory/construct_at.h> +#include <__memory/destroy.h> #include <__memory/unique_ptr.h> #include <__new/exceptions.h> #include <__numeric/reduce.h> diff --git a/libcxx/include/memory b/libcxx/include/memory index fc62606ea0fd..6661bc4f4375 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -958,12 +958,14 @@ template # if _LIBCPP_STD_VER >= 17 # include <__memory/construct_at.h> +# include <__memory/destroy.h> # endif # if _LIBCPP_STD_VER >= 20 # include <__memory/assume_aligned.h> # include <__memory/concepts.h> # include <__memory/ranges_construct_at.h> +# include <__memory/ranges_destroy.h> # include <__memory/ranges_uninitialized_algorithms.h> # include <__memory/uses_allocator_construction.h> # endif diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index fd39c946b992..b0720703bd0d 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -1567,6 +1567,7 @@ module std [system] { module compressed_pair { header "__memory/compressed_pair.h" } module concepts { header "__memory/concepts.h" } module construct_at { header "__memory/construct_at.h" } + module destroy { header "__memory/destroy.h" } module destruct_n { header "__memory/destruct_n.h" } module fwd { header "__fwd/memory.h" } module inout_ptr { header "__memory/inout_ptr.h" } @@ -1574,6 +1575,7 @@ module std [system] { module out_ptr { header "__memory/out_ptr.h" } module pointer_traits { header "__memory/pointer_traits.h" } module ranges_construct_at { header "__memory/ranges_construct_at.h" } + module ranges_destroy { header "__memory/ranges_destroy.h" } module ranges_uninitialized_algorithms { header "__memory/ranges_uninitialized_algorithms.h" export std.algorithm.in_out_result