xref: /freebsd/contrib/llvm-project/libcxx/include/__memory/uninitialized_algorithms.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 // -*- C++ -*-
2 //===----------------------------------------------------------------------===//
3 //
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #ifndef _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H
11 #define _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H
12 
13 #include <__algorithm/copy.h>
14 #include <__algorithm/move.h>
15 #include <__algorithm/unwrap_iter.h>
16 #include <__algorithm/unwrap_range.h>
17 #include <__config>
18 #include <__cstddef/size_t.h>
19 #include <__fwd/memory.h>
20 #include <__iterator/iterator_traits.h>
21 #include <__iterator/reverse_iterator.h>
22 #include <__memory/addressof.h>
23 #include <__memory/allocator_traits.h>
24 #include <__memory/construct_at.h>
25 #include <__memory/destroy.h>
26 #include <__memory/pointer_traits.h>
27 #include <__type_traits/enable_if.h>
28 #include <__type_traits/extent.h>
29 #include <__type_traits/is_array.h>
30 #include <__type_traits/is_constant_evaluated.h>
31 #include <__type_traits/is_same.h>
32 #include <__type_traits/is_trivially_assignable.h>
33 #include <__type_traits/is_trivially_constructible.h>
34 #include <__type_traits/is_trivially_relocatable.h>
35 #include <__type_traits/is_unbounded_array.h>
36 #include <__type_traits/remove_const.h>
37 #include <__type_traits/remove_extent.h>
38 #include <__utility/exception_guard.h>
39 #include <__utility/move.h>
40 #include <__utility/pair.h>
41 
42 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
43 #  pragma GCC system_header
44 #endif
45 
46 _LIBCPP_PUSH_MACROS
47 #include <__undef_macros>
48 
49 _LIBCPP_BEGIN_NAMESPACE_STD
50 
51 struct __always_false {
52   template <class... _Args>
operator__always_false53   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool operator()(_Args&&...) const _NOEXCEPT {
54     return false;
55   }
56 };
57 
58 // uninitialized_copy
59 
60 template <class _ValueType, class _InputIterator, class _Sentinel1, class _ForwardIterator, class _EndPredicate>
__uninitialized_copy(_InputIterator __ifirst,_Sentinel1 __ilast,_ForwardIterator __ofirst,_EndPredicate __stop_copying)61 inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_copy(
62     _InputIterator __ifirst, _Sentinel1 __ilast, _ForwardIterator __ofirst, _EndPredicate __stop_copying) {
63   _ForwardIterator __idx = __ofirst;
64 #if _LIBCPP_HAS_EXCEPTIONS
65   try {
66 #endif
67     for (; __ifirst != __ilast && !__stop_copying(__idx); ++__ifirst, (void)++__idx)
68       ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(*__ifirst);
69 #if _LIBCPP_HAS_EXCEPTIONS
70   } catch (...) {
71     std::__destroy(__ofirst, __idx);
72     throw;
73   }
74 #endif
75 
76   return pair<_InputIterator, _ForwardIterator>(std::move(__ifirst), std::move(__idx));
77 }
78 
79 template <class _InputIterator, class _ForwardIterator>
80 _LIBCPP_HIDE_FROM_ABI _ForwardIterator
uninitialized_copy(_InputIterator __ifirst,_InputIterator __ilast,_ForwardIterator __ofirst)81 uninitialized_copy(_InputIterator __ifirst, _InputIterator __ilast, _ForwardIterator __ofirst) {
82   typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
83   auto __result = std::__uninitialized_copy<_ValueType>(
84       std::move(__ifirst), std::move(__ilast), std::move(__ofirst), __always_false());
85   return std::move(__result.second);
86 }
87 
88 // uninitialized_copy_n
89 
90 template <class _ValueType, class _InputIterator, class _Size, class _ForwardIterator, class _EndPredicate>
91 inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator>
__uninitialized_copy_n(_InputIterator __ifirst,_Size __n,_ForwardIterator __ofirst,_EndPredicate __stop_copying)92 __uninitialized_copy_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst, _EndPredicate __stop_copying) {
93   _ForwardIterator __idx = __ofirst;
94 #if _LIBCPP_HAS_EXCEPTIONS
95   try {
96 #endif
97     for (; __n > 0 && !__stop_copying(__idx); ++__ifirst, (void)++__idx, (void)--__n)
98       ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(*__ifirst);
99 #if _LIBCPP_HAS_EXCEPTIONS
100   } catch (...) {
101     std::__destroy(__ofirst, __idx);
102     throw;
103   }
104 #endif
105 
106   return pair<_InputIterator, _ForwardIterator>(std::move(__ifirst), std::move(__idx));
107 }
108 
109 template <class _InputIterator, class _Size, class _ForwardIterator>
110 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
uninitialized_copy_n(_InputIterator __ifirst,_Size __n,_ForwardIterator __ofirst)111 uninitialized_copy_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst) {
112   typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
113   auto __result =
114       std::__uninitialized_copy_n<_ValueType>(std::move(__ifirst), __n, std::move(__ofirst), __always_false());
115   return std::move(__result.second);
116 }
117 
118 // uninitialized_fill
119 
120 template <class _ValueType, class _ForwardIterator, class _Sentinel, class _Tp>
121 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
__uninitialized_fill(_ForwardIterator __first,_Sentinel __last,const _Tp & __x)122 __uninitialized_fill(_ForwardIterator __first, _Sentinel __last, const _Tp& __x) {
123   _ForwardIterator __idx = __first;
124 #if _LIBCPP_HAS_EXCEPTIONS
125   try {
126 #endif
127     for (; __idx != __last; ++__idx)
128       ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__x);
129 #if _LIBCPP_HAS_EXCEPTIONS
130   } catch (...) {
131     std::__destroy(__first, __idx);
132     throw;
133   }
134 #endif
135 
136   return __idx;
137 }
138 
139 template <class _ForwardIterator, class _Tp>
140 inline _LIBCPP_HIDE_FROM_ABI void
uninitialized_fill(_ForwardIterator __first,_ForwardIterator __last,const _Tp & __x)141 uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) {
142   typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
143   (void)std::__uninitialized_fill<_ValueType>(__first, __last, __x);
144 }
145 
146 // uninitialized_fill_n
147 
148 template <class _ValueType, class _ForwardIterator, class _Size, class _Tp>
149 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
__uninitialized_fill_n(_ForwardIterator __first,_Size __n,const _Tp & __x)150 __uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) {
151   _ForwardIterator __idx = __first;
152 #if _LIBCPP_HAS_EXCEPTIONS
153   try {
154 #endif
155     for (; __n > 0; ++__idx, (void)--__n)
156       ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__x);
157 #if _LIBCPP_HAS_EXCEPTIONS
158   } catch (...) {
159     std::__destroy(__first, __idx);
160     throw;
161   }
162 #endif
163 
164   return __idx;
165 }
166 
167 template <class _ForwardIterator, class _Size, class _Tp>
168 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
uninitialized_fill_n(_ForwardIterator __first,_Size __n,const _Tp & __x)169 uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) {
170   typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
171   return std::__uninitialized_fill_n<_ValueType>(__first, __n, __x);
172 }
173 
174 #if _LIBCPP_STD_VER >= 17
175 
176 // uninitialized_default_construct
177 
178 template <class _ValueType, class _ForwardIterator, class _Sentinel>
179 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
__uninitialized_default_construct(_ForwardIterator __first,_Sentinel __last)180 __uninitialized_default_construct(_ForwardIterator __first, _Sentinel __last) {
181   auto __idx = __first;
182 #  if _LIBCPP_HAS_EXCEPTIONS
183   try {
184 #  endif
185     for (; __idx != __last; ++__idx)
186       ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType;
187 #  if _LIBCPP_HAS_EXCEPTIONS
188   } catch (...) {
189     std::__destroy(__first, __idx);
190     throw;
191   }
192 #  endif
193 
194   return __idx;
195 }
196 
197 template <class _ForwardIterator>
uninitialized_default_construct(_ForwardIterator __first,_ForwardIterator __last)198 inline _LIBCPP_HIDE_FROM_ABI void uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) {
199   using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
200   (void)std::__uninitialized_default_construct<_ValueType>(std::move(__first), std::move(__last));
201 }
202 
203 // uninitialized_default_construct_n
204 
205 template <class _ValueType, class _ForwardIterator, class _Size>
__uninitialized_default_construct_n(_ForwardIterator __first,_Size __n)206 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
207   auto __idx = __first;
208 #  if _LIBCPP_HAS_EXCEPTIONS
209   try {
210 #  endif
211     for (; __n > 0; ++__idx, (void)--__n)
212       ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType;
213 #  if _LIBCPP_HAS_EXCEPTIONS
214   } catch (...) {
215     std::__destroy(__first, __idx);
216     throw;
217   }
218 #  endif
219 
220   return __idx;
221 }
222 
223 template <class _ForwardIterator, class _Size>
uninitialized_default_construct_n(_ForwardIterator __first,_Size __n)224 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
225   using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
226   return std::__uninitialized_default_construct_n<_ValueType>(std::move(__first), __n);
227 }
228 
229 // uninitialized_value_construct
230 
231 template <class _ValueType, class _ForwardIterator, class _Sentinel>
232 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
__uninitialized_value_construct(_ForwardIterator __first,_Sentinel __last)233 __uninitialized_value_construct(_ForwardIterator __first, _Sentinel __last) {
234   auto __idx = __first;
235 #  if _LIBCPP_HAS_EXCEPTIONS
236   try {
237 #  endif
238     for (; __idx != __last; ++__idx)
239       ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType();
240 #  if _LIBCPP_HAS_EXCEPTIONS
241   } catch (...) {
242     std::__destroy(__first, __idx);
243     throw;
244   }
245 #  endif
246 
247   return __idx;
248 }
249 
250 template <class _ForwardIterator>
uninitialized_value_construct(_ForwardIterator __first,_ForwardIterator __last)251 inline _LIBCPP_HIDE_FROM_ABI void uninitialized_value_construct(_ForwardIterator __first, _ForwardIterator __last) {
252   using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
253   (void)std::__uninitialized_value_construct<_ValueType>(std::move(__first), std::move(__last));
254 }
255 
256 // uninitialized_value_construct_n
257 
258 template <class _ValueType, class _ForwardIterator, class _Size>
__uninitialized_value_construct_n(_ForwardIterator __first,_Size __n)259 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator __uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) {
260   auto __idx = __first;
261 #  if _LIBCPP_HAS_EXCEPTIONS
262   try {
263 #  endif
264     for (; __n > 0; ++__idx, (void)--__n)
265       ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType();
266 #  if _LIBCPP_HAS_EXCEPTIONS
267   } catch (...) {
268     std::__destroy(__first, __idx);
269     throw;
270   }
271 #  endif
272 
273   return __idx;
274 }
275 
276 template <class _ForwardIterator, class _Size>
uninitialized_value_construct_n(_ForwardIterator __first,_Size __n)277 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) {
278   using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
279   return std::__uninitialized_value_construct_n<_ValueType>(std::move(__first), __n);
280 }
281 
282 // uninitialized_move
283 
284 template <class _ValueType,
285           class _InputIterator,
286           class _Sentinel1,
287           class _ForwardIterator,
288           class _EndPredicate,
289           class _IterMove>
__uninitialized_move(_InputIterator __ifirst,_Sentinel1 __ilast,_ForwardIterator __ofirst,_EndPredicate __stop_moving,_IterMove __iter_move)290 inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_move(
291     _InputIterator __ifirst,
292     _Sentinel1 __ilast,
293     _ForwardIterator __ofirst,
294     _EndPredicate __stop_moving,
295     _IterMove __iter_move) {
296   auto __idx = __ofirst;
297 #  if _LIBCPP_HAS_EXCEPTIONS
298   try {
299 #  endif
300     for (; __ifirst != __ilast && !__stop_moving(__idx); ++__idx, (void)++__ifirst) {
301       ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__iter_move(__ifirst));
302     }
303 #  if _LIBCPP_HAS_EXCEPTIONS
304   } catch (...) {
305     std::__destroy(__ofirst, __idx);
306     throw;
307   }
308 #  endif
309 
310   return {std::move(__ifirst), std::move(__idx)};
311 }
312 
313 template <class _InputIterator, class _ForwardIterator>
314 inline _LIBCPP_HIDE_FROM_ABI _ForwardIterator
uninitialized_move(_InputIterator __ifirst,_InputIterator __ilast,_ForwardIterator __ofirst)315 uninitialized_move(_InputIterator __ifirst, _InputIterator __ilast, _ForwardIterator __ofirst) {
316   using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
317   auto __iter_move = [](auto&& __iter) -> decltype(auto) { return std::move(*__iter); };
318 
319   auto __result = std::__uninitialized_move<_ValueType>(
320       std::move(__ifirst), std::move(__ilast), std::move(__ofirst), __always_false(), __iter_move);
321   return std::move(__result.second);
322 }
323 
324 // uninitialized_move_n
325 
326 template <class _ValueType,
327           class _InputIterator,
328           class _Size,
329           class _ForwardIterator,
330           class _EndPredicate,
331           class _IterMove>
__uninitialized_move_n(_InputIterator __ifirst,_Size __n,_ForwardIterator __ofirst,_EndPredicate __stop_moving,_IterMove __iter_move)332 inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator> __uninitialized_move_n(
333     _InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst, _EndPredicate __stop_moving, _IterMove __iter_move) {
334   auto __idx = __ofirst;
335 #  if _LIBCPP_HAS_EXCEPTIONS
336   try {
337 #  endif
338     for (; __n > 0 && !__stop_moving(__idx); ++__idx, (void)++__ifirst, --__n)
339       ::new (static_cast<void*>(std::addressof(*__idx))) _ValueType(__iter_move(__ifirst));
340 #  if _LIBCPP_HAS_EXCEPTIONS
341   } catch (...) {
342     std::__destroy(__ofirst, __idx);
343     throw;
344   }
345 #  endif
346 
347   return {std::move(__ifirst), std::move(__idx)};
348 }
349 
350 template <class _InputIterator, class _Size, class _ForwardIterator>
351 inline _LIBCPP_HIDE_FROM_ABI pair<_InputIterator, _ForwardIterator>
uninitialized_move_n(_InputIterator __ifirst,_Size __n,_ForwardIterator __ofirst)352 uninitialized_move_n(_InputIterator __ifirst, _Size __n, _ForwardIterator __ofirst) {
353   using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
354   auto __iter_move = [](auto&& __iter) -> decltype(auto) { return std::move(*__iter); };
355 
356   return std::__uninitialized_move_n<_ValueType>(
357       std::move(__ifirst), __n, std::move(__ofirst), __always_false(), __iter_move);
358 }
359 
360 // TODO: Rewrite this to iterate left to right and use reverse_iterators when calling
361 // Destroys every element in the range [first, last) FROM RIGHT TO LEFT using allocator
362 // destruction. If elements are themselves C-style arrays, they are recursively destroyed
363 // in the same manner.
364 //
365 // This function assumes that destructors do not throw, and that the allocator is bound to
366 // the correct type.
367 template <class _Alloc,
368           class _BidirIter,
369           __enable_if_t<__has_bidirectional_iterator_category<_BidirIter>::value, int> = 0>
370 _LIBCPP_HIDE_FROM_ABI constexpr void
__allocator_destroy_multidimensional(_Alloc & __alloc,_BidirIter __first,_BidirIter __last)371 __allocator_destroy_multidimensional(_Alloc& __alloc, _BidirIter __first, _BidirIter __last) noexcept {
372   using _ValueType = typename iterator_traits<_BidirIter>::value_type;
373   static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _ValueType>,
374                 "The allocator should already be rebound to the correct type");
375 
376   if (__first == __last)
377     return;
378 
379   if constexpr (is_array_v<_ValueType>) {
380     static_assert(!__is_unbounded_array_v<_ValueType>,
381                   "arrays of unbounded arrays don't exist, but if they did we would mess up here");
382 
383     using _Element = remove_extent_t<_ValueType>;
384     __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc);
385     do {
386       --__last;
387       decltype(auto) __array = *__last;
388       std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + extent_v<_ValueType>);
389     } while (__last != __first);
390   } else {
391     do {
392       --__last;
393       allocator_traits<_Alloc>::destroy(__alloc, std::addressof(*__last));
394     } while (__last != __first);
395   }
396 }
397 
398 // Constructs the object at the given location using the allocator's construct method.
399 //
400 // If the object being constructed is an array, each element of the array is allocator-constructed,
401 // recursively. If an exception is thrown during the construction of an array, the initialized
402 // elements are destroyed in reverse order of initialization using allocator destruction.
403 //
404 // This function assumes that the allocator is bound to the correct type.
405 template <class _Alloc, class _Tp>
__allocator_construct_at_multidimensional(_Alloc & __alloc,_Tp * __loc)406 _LIBCPP_HIDE_FROM_ABI constexpr void __allocator_construct_at_multidimensional(_Alloc& __alloc, _Tp* __loc) {
407   static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _Tp>,
408                 "The allocator should already be rebound to the correct type");
409 
410   if constexpr (is_array_v<_Tp>) {
411     using _Element = remove_extent_t<_Tp>;
412     __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc);
413     size_t __i   = 0;
414     _Tp& __array = *__loc;
415 
416     // If an exception is thrown, destroy what we have constructed so far in reverse order.
417     auto __guard = std::__make_exception_guard([&]() {
418       std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i);
419     });
420 
421     for (; __i != extent_v<_Tp>; ++__i) {
422       std::__allocator_construct_at_multidimensional(__elem_alloc, std::addressof(__array[__i]));
423     }
424     __guard.__complete();
425   } else {
426     allocator_traits<_Alloc>::construct(__alloc, __loc);
427   }
428 }
429 
430 // Constructs the object at the given location using the allocator's construct method, passing along
431 // the provided argument.
432 //
433 // If the object being constructed is an array, the argument is also assumed to be an array. Each
434 // each element of the array being constructed is allocator-constructed from the corresponding
435 // element of the argument array. If an exception is thrown during the construction of an array,
436 // the initialized elements are destroyed in reverse order of initialization using allocator
437 // destruction.
438 //
439 // This function assumes that the allocator is bound to the correct type.
440 template <class _Alloc, class _Tp, class _Arg>
441 _LIBCPP_HIDE_FROM_ABI constexpr void
__allocator_construct_at_multidimensional(_Alloc & __alloc,_Tp * __loc,_Arg const & __arg)442 __allocator_construct_at_multidimensional(_Alloc& __alloc, _Tp* __loc, _Arg const& __arg) {
443   static_assert(is_same_v<typename allocator_traits<_Alloc>::value_type, _Tp>,
444                 "The allocator should already be rebound to the correct type");
445 
446   if constexpr (is_array_v<_Tp>) {
447     static_assert(is_array_v<_Arg>,
448                   "Provided non-array initialization argument to __allocator_construct_at_multidimensional when "
449                   "trying to construct an array.");
450 
451     using _Element = remove_extent_t<_Tp>;
452     __allocator_traits_rebind_t<_Alloc, _Element> __elem_alloc(__alloc);
453     size_t __i   = 0;
454     _Tp& __array = *__loc;
455 
456     // If an exception is thrown, destroy what we have constructed so far in reverse order.
457     auto __guard = std::__make_exception_guard([&]() {
458       std::__allocator_destroy_multidimensional(__elem_alloc, __array, __array + __i);
459     });
460     for (; __i != extent_v<_Tp>; ++__i) {
461       std::__allocator_construct_at_multidimensional(__elem_alloc, std::addressof(__array[__i]), __arg[__i]);
462     }
463     __guard.__complete();
464   } else {
465     allocator_traits<_Alloc>::construct(__alloc, __loc, __arg);
466   }
467 }
468 
469 // Given a range starting at it and containing n elements, initializes each element in the
470 // range from left to right using the construct method of the allocator (rebound to the
471 // correct type).
472 //
473 // If an exception is thrown, the initialized elements are destroyed in reverse order of
474 // initialization using allocator_traits destruction. If the elements in the range are C-style
475 // arrays, they are initialized element-wise using allocator construction, and recursively so.
476 template <class _Alloc,
477           class _BidirIter,
478           class _Tp,
479           class _Size = typename iterator_traits<_BidirIter>::difference_type>
480 _LIBCPP_HIDE_FROM_ABI constexpr void
__uninitialized_allocator_fill_n_multidimensional(_Alloc & __alloc,_BidirIter __it,_Size __n,_Tp const & __value)481 __uninitialized_allocator_fill_n_multidimensional(_Alloc& __alloc, _BidirIter __it, _Size __n, _Tp const& __value) {
482   using _ValueType = typename iterator_traits<_BidirIter>::value_type;
483   __allocator_traits_rebind_t<_Alloc, _ValueType> __value_alloc(__alloc);
484   _BidirIter __begin = __it;
485 
486   // If an exception is thrown, destroy what we have constructed so far in reverse order.
487   auto __guard =
488       std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
489   for (; __n != 0; --__n, ++__it) {
490     std::__allocator_construct_at_multidimensional(__value_alloc, std::addressof(*__it), __value);
491   }
492   __guard.__complete();
493 }
494 
495 // Same as __uninitialized_allocator_fill_n_multidimensional, but doesn't pass any initialization argument
496 // to the allocator's construct method, which results in value initialization.
497 template <class _Alloc, class _BidirIter, class _Size = typename iterator_traits<_BidirIter>::difference_type>
498 _LIBCPP_HIDE_FROM_ABI constexpr void
__uninitialized_allocator_value_construct_n_multidimensional(_Alloc & __alloc,_BidirIter __it,_Size __n)499 __uninitialized_allocator_value_construct_n_multidimensional(_Alloc& __alloc, _BidirIter __it, _Size __n) {
500   using _ValueType = typename iterator_traits<_BidirIter>::value_type;
501   __allocator_traits_rebind_t<_Alloc, _ValueType> __value_alloc(__alloc);
502   _BidirIter __begin = __it;
503 
504   // If an exception is thrown, destroy what we have constructed so far in reverse order.
505   auto __guard =
506       std::__make_exception_guard([&]() { std::__allocator_destroy_multidimensional(__value_alloc, __begin, __it); });
507   for (; __n != 0; --__n, ++__it) {
508     std::__allocator_construct_at_multidimensional(__value_alloc, std::addressof(*__it));
509   }
510   __guard.__complete();
511 }
512 
513 #endif // _LIBCPP_STD_VER >= 17
514 
515 template <class _Alloc, class _Iter>
516 class _AllocatorDestroyRangeReverse {
517 public:
518   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
_AllocatorDestroyRangeReverse(_Alloc & __alloc,_Iter & __first,_Iter & __last)519   _AllocatorDestroyRangeReverse(_Alloc& __alloc, _Iter& __first, _Iter& __last)
520       : __alloc_(__alloc), __first_(__first), __last_(__last) {}
521 
operator()522   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void operator()() const {
523     std::__allocator_destroy(__alloc_, std::reverse_iterator<_Iter>(__last_), std::reverse_iterator<_Iter>(__first_));
524   }
525 
526 private:
527   _Alloc& __alloc_;
528   _Iter& __first_;
529   _Iter& __last_;
530 };
531 
532 // Copy-construct [__first1, __last1) in [__first2, __first2 + N), where N is distance(__first1, __last1).
533 //
534 // The caller has to ensure that __first2 can hold at least N uninitialized elements. If an exception is thrown the
535 // already copied elements are destroyed in reverse order of their construction.
536 template <class _Alloc, class _Iter1, class _Sent1, class _Iter2>
537 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2
__uninitialized_allocator_copy_impl(_Alloc & __alloc,_Iter1 __first1,_Sent1 __last1,_Iter2 __first2)538 __uninitialized_allocator_copy_impl(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) {
539   auto __destruct_first = __first2;
540   auto __guard =
541       std::__make_exception_guard(_AllocatorDestroyRangeReverse<_Alloc, _Iter2>(__alloc, __destruct_first, __first2));
542   while (__first1 != __last1) {
543     allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__first2), *__first1);
544     ++__first1;
545     ++__first2;
546   }
547   __guard.__complete();
548   return __first2;
549 }
550 
551 template <class _Alloc, class _Type>
552 inline const bool __allocator_has_trivial_copy_construct_v = !__has_construct_v<_Alloc, _Type*, const _Type&>;
553 
554 template <class _Type>
555 inline const bool __allocator_has_trivial_copy_construct_v<allocator<_Type>, _Type> = true;
556 
557 template <class _Alloc,
558           class _In,
559           class _Out,
560           __enable_if_t<is_trivially_copy_constructible<_In>::value && is_trivially_copy_assignable<_In>::value &&
561                             is_same<__remove_const_t<_In>, __remove_const_t<_Out> >::value &&
562                             __allocator_has_trivial_copy_construct_v<_Alloc, _In>,
563                         int> = 0>
564 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Out*
__uninitialized_allocator_copy_impl(_Alloc &,_In * __first1,_In * __last1,_Out * __first2)565 __uninitialized_allocator_copy_impl(_Alloc&, _In* __first1, _In* __last1, _Out* __first2) {
566   if (__libcpp_is_constant_evaluated()) {
567     while (__first1 != __last1) {
568       std::__construct_at(std::__to_address(__first2), *__first1);
569       ++__first1;
570       ++__first2;
571     }
572     return __first2;
573   } else {
574     return std::copy(__first1, __last1, __first2);
575   }
576 }
577 
578 template <class _Alloc, class _Iter1, class _Sent1, class _Iter2>
579 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter2
__uninitialized_allocator_copy(_Alloc & __alloc,_Iter1 __first1,_Sent1 __last1,_Iter2 __first2)580 __uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1, _Iter2 __first2) {
581   auto __unwrapped_range = std::__unwrap_range(std::move(__first1), std::move(__last1));
582   auto __result          = std::__uninitialized_allocator_copy_impl(
583       __alloc, std::move(__unwrapped_range.first), std::move(__unwrapped_range.second), std::__unwrap_iter(__first2));
584   return std::__rewrap_iter(__first2, __result);
585 }
586 
587 template <class _Alloc, class _Type>
588 inline const bool __allocator_has_trivial_move_construct_v = !__has_construct_v<_Alloc, _Type*, _Type&&>;
589 
590 template <class _Type>
591 inline const bool __allocator_has_trivial_move_construct_v<allocator<_Type>, _Type> = true;
592 
593 template <class _Alloc, class _Tp>
594 inline const bool __allocator_has_trivial_destroy_v = !__has_destroy_v<_Alloc, _Tp*>;
595 
596 template <class _Tp, class _Up>
597 inline const bool __allocator_has_trivial_destroy_v<allocator<_Tp>, _Up> = true;
598 
599 // __uninitialized_allocator_relocate relocates the objects in [__first, __last) into __result.
600 // Relocation means that the objects in [__first, __last) are placed into __result as-if by move-construct and destroy,
601 // except that the move constructor and destructor may never be called if they are known to be equivalent to a memcpy.
602 //
603 // Preconditions:  __result doesn't contain any objects and [__first, __last) contains objects
604 // Postconditions: __result contains the objects from [__first, __last) and
605 //                 [__first, __last) doesn't contain any objects
606 //
607 // The strong exception guarantee is provided if any of the following are true:
608 // - is_nothrow_move_constructible<_ValueType>
609 // - is_copy_constructible<_ValueType>
610 // - __libcpp_is_trivially_relocatable<_ValueType>
611 template <class _Alloc, class _ContiguousIterator>
__uninitialized_allocator_relocate(_Alloc & __alloc,_ContiguousIterator __first,_ContiguousIterator __last,_ContiguousIterator __result)612 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __uninitialized_allocator_relocate(
613     _Alloc& __alloc, _ContiguousIterator __first, _ContiguousIterator __last, _ContiguousIterator __result) {
614   static_assert(__libcpp_is_contiguous_iterator<_ContiguousIterator>::value, "");
615   using _ValueType = typename iterator_traits<_ContiguousIterator>::value_type;
616   static_assert(
617       __is_cpp17_move_insertable_v<_Alloc>, "The specified type does not meet the requirements of Cpp17MoveInsertable");
618   if (__libcpp_is_constant_evaluated() || !__libcpp_is_trivially_relocatable<_ValueType>::value ||
619       !__allocator_has_trivial_move_construct_v<_Alloc, _ValueType> ||
620       !__allocator_has_trivial_destroy_v<_Alloc, _ValueType>) {
621     auto __destruct_first = __result;
622     auto __guard          = std::__make_exception_guard(
623         _AllocatorDestroyRangeReverse<_Alloc, _ContiguousIterator>(__alloc, __destruct_first, __result));
624     auto __iter = __first;
625     while (__iter != __last) {
626 #if _LIBCPP_HAS_EXCEPTIONS
627       allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__result), std::move_if_noexcept(*__iter));
628 #else
629       allocator_traits<_Alloc>::construct(__alloc, std::__to_address(__result), std::move(*__iter));
630 #endif
631       ++__iter;
632       ++__result;
633     }
634     __guard.__complete();
635     std::__allocator_destroy(__alloc, __first, __last);
636   } else {
637     // Casting to void* to suppress clang complaining that this is technically UB.
638     __builtin_memcpy(static_cast<void*>(std::__to_address(__result)),
639                      std::__to_address(__first),
640                      sizeof(_ValueType) * (__last - __first));
641   }
642 }
643 
644 _LIBCPP_END_NAMESPACE_STD
645 
646 _LIBCPP_POP_MACROS
647 
648 #endif // _LIBCPP___MEMORY_UNINITIALIZED_ALGORITHMS_H
649