Warning: This file is not a C or C++ file. It does not have highlighting.
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> |
53 | _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> |
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 |
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> |
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 |
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 |
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 |
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 |
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 |
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 |
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> |
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> |
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> |
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 |
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> |
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> |
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> |
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> |
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 |
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> |
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> |
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 |
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> |
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 |
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 |
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 |
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 |
519 | _AllocatorDestroyRangeReverse(_Alloc& __alloc, _Iter& __first, _Iter& __last) |
520 | : __alloc_(__alloc), __first_(__first), __last_(__last) {} |
521 | |
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 |
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* |
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 |
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> |
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 |
Warning: This file is not a C or C++ file. It does not have highlighting.