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