1111
1212#include < __config>
1313#include < __iterator/iterator_traits.h>
14+ #include < __memory/addressof.h>
1415#include < __memory/allocator_traits.h>
16+ #include < __memory/destroy.h>
1517#include < __memory/is_trivially_allocator_relocatable.h>
1618#include < __memory/pointer_traits.h>
1719#include < __memory/relocate_at.h>
@@ -30,8 +32,6 @@ _LIBCPP_PUSH_MACROS
3032
3133_LIBCPP_BEGIN_NAMESPACE_STD
3234
33- // TODO: We currently use std::__to_address but we don't guarantee contiguous iterators. How does that work?
34-
3535// __uninitialized_relocate relocates the objects in [__first, __last) into __result.
3636//
3737// Relocation means that the objects in [__first, __last) are placed into __result as-if by move-construct and destroy,
@@ -49,7 +49,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
4949// - __result contains the objects from [__first, __last)
5050// - [__first, __last) doesn't contain any objects
5151template <class _InputIter , class _NothrowForwardIter >
52- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _InputIter
52+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _NothrowForwardIter
5353__uninitialized_relocate (_InputIter __first, _InputIter __last, _NothrowForwardIter __result) {
5454 if constexpr (__libcpp_is_contiguous_iterator<_InputIter>::value &&
5555 __libcpp_is_contiguous_iterator<_NothrowForwardIter>::value) {
@@ -64,10 +64,12 @@ __uninitialized_relocate(_InputIter __first, _InputIter __last, _NothrowForwardI
6464 if constexpr (__libcpp_is_contiguous_iterator<_InputIter>::value &&
6565 __libcpp_is_contiguous_iterator<_NothrowForwardIter>::value &&
6666 __libcpp_is_trivially_relocatable<_ValueType>::value) {
67- // TODO: We might be able to memcpy if we don't overlap at all?
68- std::__libcpp_builtin_trivially_relocate_at (
69- std::__to_address (__first), std::__to_address (__last), std::__to_address (__result));
70- return __result + (__last - __first);
67+ if (!__libcpp_is_constant_evaluated ()) {
68+ // TODO: We might be able to memcpy if we don't overlap at all?
69+ std::__libcpp_builtin_trivially_relocate_at (
70+ std::__to_address (__first), std::__to_address (__last), std::__to_address (__result));
71+ return __result + (__last - __first);
72+ }
7173 }
7274
7375 // Otherwise, relocate elements one by one.
@@ -77,7 +79,7 @@ __uninitialized_relocate(_InputIter __first, _InputIter __last, _NothrowForwardI
7779 auto const __first_result = __result;
7880 try {
7981 while (__first != __last) {
80- std::__relocate_at (std::__to_address ( __first), std::__to_address ( __result));
82+ std::__relocate_at (std::addressof (* __first), std::addressof (* __result));
8183 ++__first;
8284 ++__result;
8385 }
@@ -93,14 +95,13 @@ __uninitialized_relocate(_InputIter __first, _InputIter __last, _NothrowForwardI
9395// the range [first, last) to another range ending at __result_last. The elements are relocated in reverse
9496// order, but their relative order is preserved.
9597template <class _BidirectionalIter , class _NothrowBidirectionalIter >
96- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIter __uninitialized_relocate_backward (
98+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _NothrowBidirectionalIter __uninitialized_relocate_backward (
9799 _BidirectionalIter __first, _BidirectionalIter __last, _NothrowBidirectionalIter __result_last) {
98100 if constexpr (__libcpp_is_contiguous_iterator<_BidirectionalIter>::value &&
99101 __libcpp_is_contiguous_iterator<_NothrowBidirectionalIter>::value) {
100- // TODO: Check for off-by-one here, we might want to check __result_last - 1
101102 _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES (
102103 !std::__is_pointer_in_range (
103- std::__to_address (__first), std::__to_address (__last), std::__to_address (__result_last)),
104+ std::__to_address (__first), std::__to_address (__last), std::__to_address (__result_last) - 1 ),
104105 " uninitialized_relocate_backward requires the end of the result not to overlap with the input range" );
105106 }
106107 using _ValueType = typename iterator_traits<_BidirectionalIter>::value_type;
@@ -110,11 +111,13 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIter __uniniti
110111 if constexpr (__libcpp_is_contiguous_iterator<_BidirectionalIter>::value &&
111112 __libcpp_is_contiguous_iterator<_NothrowBidirectionalIter>::value &&
112113 __libcpp_is_trivially_relocatable<_ValueType>::value) {
113- auto __result = __result_last - (__last - __first);
114- // TODO: We might be able to memcpy if we don't overlap at all?
115- std::__libcpp_builtin_trivially_relocate_at (
116- std::__to_address (__first), std::__to_address (__last), std::__to_address (__result));
117- return __result;
114+ if (!__libcpp_is_constant_evaluated ()) {
115+ auto __result = __result_last - (__last - __first);
116+ // TODO: We might be able to memcpy if we don't overlap at all?
117+ std::__libcpp_builtin_trivially_relocate_at (
118+ std::__to_address (__first), std::__to_address (__last), std::__to_address (__result));
119+ return __result;
120+ }
118121 }
119122
120123 // Otherwise, relocate elements one by one, starting from the end.
@@ -126,7 +129,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIter __uniniti
126129 while (__last != __first) {
127130 --__last;
128131 --__result;
129- std::__relocate_at (std::__to_address ( __last), std::__to_address ( __result));
132+ std::__relocate_at (std::addressof (* __last), std::addressof (* __result));
130133 }
131134 } catch (...) {
132135 std::destroy (__first, __last);
@@ -156,7 +159,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _NothrowForwardIter __uninit
156159 auto const __first_result = __result;
157160 try {
158161 while (__first != __last) {
159- std::__allocator_relocate_at (__alloc, std::__to_address ( __first), std::__to_address ( __result));
162+ std::__allocator_relocate_at (__alloc, std::addressof (* __first), std::addressof (* __result));
160163 ++__first;
161164 ++__result;
162165 }
@@ -176,10 +179,9 @@ __uninitialized_allocator_relocate_backward(
176179 _Alloc& __alloc, _BidirectionalIter __first, _BidirectionalIter __last, _NothrowBidirectionalIter __result_last) {
177180 if constexpr (__libcpp_is_contiguous_iterator<_BidirectionalIter>::value &&
178181 __libcpp_is_contiguous_iterator<_NothrowBidirectionalIter>::value) {
179- // TODO: Off by one?
180182 _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES (
181183 !std::__is_pointer_in_range (
182- std::__to_address (__first), std::__to_address (__last), std::__to_address (__result_last)),
184+ std::__to_address (__first), std::__to_address (__last), std::__to_address (__result_last) - 1 ),
183185 " uninitialized_allocator_relocate_backward requires the end of the result not to overlap with the input range" );
184186 }
185187
@@ -194,7 +196,7 @@ __uninitialized_allocator_relocate_backward(
194196 while (__last != __first) {
195197 --__last;
196198 --__result;
197- std::__allocator_relocate_at (__alloc, std::__to_address ( __last), std::__to_address ( __result));
199+ std::__allocator_relocate_at (__alloc, std::addressof (* __last), std::addressof (* __result));
198200 }
199201 } catch (...) {
200202 std::__allocator_destroy (__alloc, __first, __last);
0 commit comments