[libcxx-commits] [libcxx] 1b2efd2 - [libc++] Split the multidimensional algorithms out of uninitialized_algorithms.h (#207447)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jul 6 00:29:01 PDT 2026
Author: Nikolas Klauser
Date: 2026-07-06T09:28:56+02:00
New Revision: 1b2efd2e079a7fe86888cb7da12a5efa84b131fc
URL: https://github.com/llvm/llvm-project/commit/1b2efd2e079a7fe86888cb7da12a5efa84b131fc
DIFF: https://github.com/llvm/llvm-project/commit/1b2efd2e079a7fe86888cb7da12a5efa84b131fc.diff
LOG: [libc++] Split the multidimensional algorithms out of uninitialized_algorithms.h (#207447)
While these algorithms are conceptually related to other
`uninitialized_*` algorithms, they're likely only ever going to be used
by `shared_ptr`. `uninitialized_algorithms.h` itself is also getting
rather large, so it makes sense to split the multidimensional versions
into their own header.
Fixes #207417
Added:
libcxx/include/__memory/uninitialized_multidimensional_algorithms.h
Modified:
libcxx/include/CMakeLists.txt
libcxx/include/__memory/shared_ptr.h
libcxx/include/__memory/uninitialized_algorithms.h
libcxx/include/module.modulemap.in
Removed:
################################################################################
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index d65e66e221766..b40f586161e62 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -618,6 +618,7 @@ set(files
__memory/temp_value.h
__memory/temporary_buffer.h
__memory/uninitialized_algorithms.h
+ __memory/uninitialized_multidimensional_algorithms.h
__memory/unique_ptr.h
__memory/unique_temporary_buffer.h
__memory/uses_allocator.h
diff --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 750d253912ab1..ebd542ba14d01 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -33,6 +33,7 @@
#include <__memory/pointer_traits.h>
#include <__memory/shared_count.h>
#include <__memory/uninitialized_algorithms.h>
+#include <__memory/uninitialized_multidimensional_algorithms.h>
#include <__memory/unique_ptr.h>
#include <__type_traits/add_reference.h>
#include <__type_traits/conditional.h>
diff --git a/libcxx/include/__memory/uninitialized_algorithms.h b/libcxx/include/__memory/uninitialized_algorithms.h
index 45c8b71459eef..d4cd49a1deb6e 100644
--- a/libcxx/include/__memory/uninitialized_algorithms.h
+++ b/libcxx/include/__memory/uninitialized_algorithms.h
@@ -11,11 +11,10 @@
#define _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H
#include <__algorithm/copy.h>
-#include <__algorithm/move.h>
+#include <__algorithm/in_out_result.h>
#include <__algorithm/unwrap_iter.h>
#include <__algorithm/unwrap_range.h>
#include <__config>
-#include <__cstddef/size_t.h>
#include <__fwd/memory.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/reverse_iterator.h>
@@ -25,15 +24,12 @@
#include <__memory/destroy.h>
#include <__memory/pointer_traits.h>
#include <__type_traits/enable_if.h>
-#include <__type_traits/extent.h>
-#include <__type_traits/is_array.h>
#include <__type_traits/is_constant_evaluated.h>
#include <__type_traits/is_same.h>
#include <__type_traits/is_trivially_assignable.h>
#include <__type_traits/is_trivially_constructible.h>
#include <__type_traits/is_trivially_relocatable.h>
#include <__type_traits/remove_const.h>
-#include <__type_traits/remove_extent.h>
#include <__utility/exception_guard.h>
#include <__utility/move.h>
#include <__utility/pair.h>
@@ -295,159 +291,6 @@ uninitialized_move_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofir
return {std::move(__result.__in_), std::move(__result.__out_)};
}
-// TODO: Rewrite this to iterate left to right and use reverse_iterators when calling
-// Destroys every element in the range [first, last) FROM RIGHT TO LEFT using allocator
-// destruction. If elements are themselves C-style arrays, they are recursively destroyed
-// in the same manner.
-//
-// This function assumes that destructors do not throw, and that the allocator is bound to
-// the correct type.
-template <class _Alloc,
- class _BidirIter,
- __enable_if_t<__has_bidirectional_iterator_category<_BidirIter>::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr void
-__allocator_destroy_multidimensional(_Alloc& __alloc, _BidirIter __first, _BidirIter __last) noexcept {
- using _ValueType = typename iterator_traits<_BidirIter>::value_type;
- static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _ValueType>,
- "The allocator should already be rebound to the correct type");
-
- if (__first == __last)
- return;
-
- if constexpr (is_array_v<_ValueType>) {
- static_assert(!__is_unbounded_array_v<_ValueType>,
- "arrays of unbounded arrays don't exist, but if they did we would mess up here");
-
- using _Element = remove_extent_t<_ValueType>;
- __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc);
- do {
- --__last;
- decltype(auto) __array = *__last;
- std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + extent_v<_ValueType>);
- } while (__last != __first);
- } else {
- do {
- --__last;
- allocator_traits<_Alloc>::destroy(__alloc, std::addressof(*__last));
- } while (__last != __first);
- }
-}
-
-// Constructs the object at the given location using the allocator's construct method.
-//
-// If the object being constructed is an array, each element of the array is allocator-constructed,
-// recursively. If an exception is thrown during the construction of an array, the initialized
-// elements are destroyed in reverse order of initialization using allocator destruction.
-//
-// This function assumes that the allocator is bound to the correct type.
-template <class _Alloc, class _Tp>
-_LIBCPP_HIDE_FROM_ABI constexpr void __allocator_construct_at_multidimensional(_Alloc& __alloc, _Tp* __loc) {
- static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _Tp>,
- "The allocator should already be rebound to the correct type");
-
- if constexpr (is_array_v<_Tp>) {
- using _Element = remove_extent_t<_Tp>;
- __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc);
- size_t __i = 0;
- _Tp& __array = *__loc;
-
- // If an exception is thrown, destroy what we have constructed so far in reverse order.
- auto __guard = std::__make_exception_guard([&]() {
- std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i);
- });
-
- for (; __i != extent_v<_Tp>; ++__i) {
- std::__allocator_construct_at_multidimensional(__elem_alloc, std::addressof(__array[__i]));
- }
- __guard.__complete();
- } else {
- allocator_traits<_Alloc>::construct(__alloc, __loc);
- }
-}
-
-// Constructs the object at the given location using the allocator's construct method, passing along
-// the provided argument.
-//
-// If the object being constructed is an array, the argument is also assumed to be an array. Each
-// each element of the array being constructed is allocator-constructed from the corresponding
-// element of the argument array. If an exception is thrown during the construction of an array,
-// the initialized elements are destroyed in reverse order of initialization using allocator
-// destruction.
-//
-// This function assumes that the allocator is bound to the correct type.
-template <class _Alloc, class _Tp, class _Arg>
-_LIBCPP_HIDE_FROM_ABI constexpr void
-__allocator_construct_at_multidimensional(_Alloc& __alloc, _Tp* __loc, _Arg const& __arg) {
- static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _Tp>,
- "The allocator should already be rebound to the correct type");
-
- if constexpr (is_array_v<_Tp>) {
- static_assert(is_array_v<_Arg>,
- "Provided non-array initialization argument to __allocator_construct_at_multidimensional when "
- "trying to construct an array.");
-
- using _Element = remove_extent_t<_Tp>;
- __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc);
- size_t __i = 0;
- _Tp& __array = *__loc;
-
- // If an exception is thrown, destroy what we have constructed so far in reverse order.
- auto __guard = std::__make_exception_guard([&]() {
- std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i);
- });
- for (; __i != extent_v<_Tp>; ++__i) {
- std::__allocator_construct_at_multidimensional(__elem_alloc, std::addressof(__array[__i]), __arg[__i]);
- }
- __guard.__complete();
- } else {
- allocator_traits<_Alloc>::construct(__alloc, __loc, __arg);
- }
-}
-
-// Given a range starting at it and containing n elements, initializes each element in the
-// range from left to right using the construct method of the allocator (rebound to the
-// correct type).
-//
-// If an exception is thrown, the initialized elements are destroyed in reverse order of
-// initialization using allocator_traits destruction. If the elements in the range are C-style
-// arrays, they are initialized element-wise using allocator construction, and recursively so.
-template <class _Alloc,
- class _BidirIter,
- class _Tp,
- class _Size = typename iterator_traits<_BidirIter>::
diff erence_type>
-_LIBCPP_HIDE_FROM_ABI constexpr void
-__uninitialized_allocator_fill_n_multidimensional(_Alloc& __alloc, _BidirIter __it, _Size __n, _Tp const& __value) {
- using _ValueType = typename iterator_traits<_BidirIter>::value_type;
- __allocator_traits_rebind_t<_Alloc, _ValueType> __value_alloc(__alloc);
- _BidirIter __begin = __it;
-
- // If an exception is thrown, destroy what we have constructed so far in reverse order.
- auto __guard =
- std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
- for (; __n != 0; --__n, ++__it) {
- std::__allocator_construct_at_multidimensional(__value_alloc, std::addressof(*__it), __value);
- }
- __guard.__complete();
-}
-
-// Same as __uninitialized_allocator_fill_n_multidimensional, but doesn't pass any initialization argument
-// to the allocator's construct method, which results in value initialization.
-template <class _Alloc, class _BidirIter, class _Size = typename iterator_traits<_BidirIter>::
diff erence_type>
-_LIBCPP_HIDE_FROM_ABI constexpr void
-__uninitialized_allocator_value_construct_n_multidimensional(_Alloc& __alloc, _BidirIter __it, _Size __n) {
- using _ValueType = typename iterator_traits<_BidirIter>::value_type;
- __allocator_traits_rebind_t<_Alloc, _ValueType> __value_alloc(__alloc);
- _BidirIter __begin = __it;
-
- // If an exception is thrown, destroy what we have constructed so far in reverse order.
- auto __guard =
- std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
- for (; __n != 0; --__n, ++__it) {
- std::__allocator_construct_at_multidimensional(__value_alloc, std::addressof(*__it));
- }
- __guard.__complete();
-}
-
#endif // _LIBCPP_STD_VER >= 17
template <class _Alloc, class _Iter>
diff --git a/libcxx/include/__memory/uninitialized_multidimensional_algorithms.h b/libcxx/include/__memory/uninitialized_multidimensional_algorithms.h
new file mode 100644
index 0000000000000..2496ce6af1e15
--- /dev/null
+++ b/libcxx/include/__memory/uninitialized_multidimensional_algorithms.h
@@ -0,0 +1,194 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_UNINITIALIZED_MULTIDIMENSIONAL_ALGORITHMS_H
+#define _LIBCPP___MEMORY_UNINITIALIZED_MULTIDIMENSIONAL_ALGORITHMS_H
+
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/addressof.h>
+#include <__memory/allocator_traits.h>
+#include <__type_traits/enable_if.h>
+#include <__type_traits/extent.h>
+#include <__type_traits/is_array.h>
+#include <__type_traits/is_same.h>
+#include <__type_traits/remove_extent.h>
+#include <__utility/exception_guard.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// TODO: Rewrite this to iterate left to right and use reverse_iterators when calling
+// Destroys every element in the range [first, last) FROM RIGHT TO LEFT using allocator
+// destruction. If elements are themselves C-style arrays, they are recursively destroyed
+// in the same manner.
+//
+// This function assumes that destructors do not throw, and that the allocator is bound to
+// the correct type.
+template <class _Alloc,
+ class _BidirIter,
+ __enable_if_t<__has_bidirectional_iterator_category<_BidirIter>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI constexpr void
+__allocator_destroy_multidimensional(_Alloc& __alloc, _BidirIter __first, _BidirIter __last) noexcept {
+ using _ValueType = typename iterator_traits<_BidirIter>::value_type;
+ static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _ValueType>,
+ "The allocator should already be rebound to the correct type");
+
+ if (__first == __last)
+ return;
+
+ if constexpr (is_array_v<_ValueType>) {
+ static_assert(!__is_unbounded_array_v<_ValueType>,
+ "arrays of unbounded arrays don't exist, but if they did we would mess up here");
+
+ using _Element = remove_extent_t<_ValueType>;
+ __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc);
+ do {
+ --__last;
+ decltype(auto) __array = *__last;
+ std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + extent_v<_ValueType>);
+ } while (__last != __first);
+ } else {
+ do {
+ --__last;
+ allocator_traits<_Alloc>::destroy(__alloc, std::addressof(*__last));
+ } while (__last != __first);
+ }
+}
+
+// Constructs the object at the given location using the allocator's construct method.
+//
+// If the object being constructed is an array, each element of the array is allocator-constructed,
+// recursively. If an exception is thrown during the construction of an array, the initialized
+// elements are destroyed in reverse order of initialization using allocator destruction.
+//
+// This function assumes that the allocator is bound to the correct type.
+template <class _Alloc, class _Tp>
+_LIBCPP_HIDE_FROM_ABI constexpr void __allocator_construct_at_multidimensional(_Alloc& __alloc, _Tp* __loc) {
+ static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _Tp>,
+ "The allocator should already be rebound to the correct type");
+
+ if constexpr (is_array_v<_Tp>) {
+ using _Element = remove_extent_t<_Tp>;
+ __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc);
+ size_t __i = 0;
+ _Tp& __array = *__loc;
+
+ // If an exception is thrown, destroy what we have constructed so far in reverse order.
+ auto __guard = std::__make_exception_guard([&]() {
+ std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i);
+ });
+
+ for (; __i != extent_v<_Tp>; ++__i) {
+ std::__allocator_construct_at_multidimensional(__elem_alloc, std::addressof(__array[__i]));
+ }
+ __guard.__complete();
+ } else {
+ allocator_traits<_Alloc>::construct(__alloc, __loc);
+ }
+}
+
+// Constructs the object at the given location using the allocator's construct method, passing along
+// the provided argument.
+//
+// If the object being constructed is an array, the argument is also assumed to be an array. Each
+// each element of the array being constructed is allocator-constructed from the corresponding
+// element of the argument array. If an exception is thrown during the construction of an array,
+// the initialized elements are destroyed in reverse order of initialization using allocator
+// destruction.
+//
+// This function assumes that the allocator is bound to the correct type.
+template <class _Alloc, class _Tp, class _Arg>
+_LIBCPP_HIDE_FROM_ABI constexpr void
+__allocator_construct_at_multidimensional(_Alloc& __alloc, _Tp* __loc, _Arg const& __arg) {
+ static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _Tp>,
+ "The allocator should already be rebound to the correct type");
+
+ if constexpr (is_array_v<_Tp>) {
+ static_assert(is_array_v<_Arg>,
+ "Provided non-array initialization argument to __allocator_construct_at_multidimensional when "
+ "trying to construct an array.");
+
+ using _Element = remove_extent_t<_Tp>;
+ __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc);
+ size_t __i = 0;
+ _Tp& __array = *__loc;
+
+ // If an exception is thrown, destroy what we have constructed so far in reverse order.
+ auto __guard = std::__make_exception_guard([&]() {
+ std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i);
+ });
+ for (; __i != extent_v<_Tp>; ++__i) {
+ std::__allocator_construct_at_multidimensional(__elem_alloc, std::addressof(__array[__i]), __arg[__i]);
+ }
+ __guard.__complete();
+ } else {
+ allocator_traits<_Alloc>::construct(__alloc, __loc, __arg);
+ }
+}
+
+// Given a range starting at it and containing n elements, initializes each element in the
+// range from left to right using the construct method of the allocator (rebound to the
+// correct type).
+//
+// If an exception is thrown, the initialized elements are destroyed in reverse order of
+// initialization using allocator_traits destruction. If the elements in the range are C-style
+// arrays, they are initialized element-wise using allocator construction, and recursively so.
+template <class _Alloc,
+ class _BidirIter,
+ class _Tp,
+ class _Size = typename iterator_traits<_BidirIter>::
diff erence_type>
+_LIBCPP_HIDE_FROM_ABI constexpr void
+__uninitialized_allocator_fill_n_multidimensional(_Alloc& __alloc, _BidirIter __it, _Size __n, _Tp const& __value) {
+ using _ValueType = typename iterator_traits<_BidirIter>::value_type;
+ __allocator_traits_rebind_t<_Alloc, _ValueType> __value_alloc(__alloc);
+ _BidirIter __begin = __it;
+
+ // If an exception is thrown, destroy what we have constructed so far in reverse order.
+ auto __guard =
+ std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
+ for (; __n != 0; --__n, ++__it) {
+ std::__allocator_construct_at_multidimensional(__value_alloc, std::addressof(*__it), __value);
+ }
+ __guard.__complete();
+}
+
+// Same as __uninitialized_allocator_fill_n_multidimensional, but doesn't pass any initialization argument
+// to the allocator's construct method, which results in value initialization.
+template <class _Alloc, class _BidirIter, class _Size = typename iterator_traits<_BidirIter>::
diff erence_type>
+_LIBCPP_HIDE_FROM_ABI constexpr void
+__uninitialized_allocator_value_construct_n_multidimensional(_Alloc& __alloc, _BidirIter __it, _Size __n) {
+ using _ValueType = typename iterator_traits<_BidirIter>::value_type;
+ __allocator_traits_rebind_t<_Alloc, _ValueType> __value_alloc(__alloc);
+ _BidirIter __begin = __it;
+
+ // If an exception is thrown, destroy what we have constructed so far in reverse order.
+ auto __guard =
+ std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
+ for (; __n != 0; --__n, ++__it) {
+ std::__allocator_construct_at_multidimensional(__value_alloc, std::addressof(*__it));
+ }
+ __guard.__complete();
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___MEMORY_UNINITIALIZED_MULTIDIMENSIONAL_ALGORITHMS_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 2d4ba2b5876a7..39b4e0bb986c6 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1705,6 +1705,9 @@ module std {
export std.memory.destroy
export std.utility.pair
}
+ module uninitialized_multidimensional_algorithms {
+ header "__memory/uninitialized_multidimensional_algorithms.h"
+ }
module unique_ptr {
header "__memory/unique_ptr.h"
export std.functional.hash
More information about the libcxx-commits
mailing list