#endif
#if __cplusplus >= 202002L
# include <compare>
+# include <bits/ptr_traits.h> // std::to_address
#endif
namespace std _GLIBCXX_VISIBILITY(default)
return __a;
}
- // All of these auxiliary structs serve two purposes. (1) Replace
- // calls to copy with memmove whenever possible. (Memmove, not memcpy,
- // because the input and output ranges are permitted to overlap.)
- // (2) If we're using random access iterators, then write the loop as
- // a for loop with an explicit count.
-
- template<bool _IsMove, bool _IsSimple, typename _Category>
- struct __copy_move
- {
- template<typename _II, typename _OI>
- _GLIBCXX20_CONSTEXPR
- static _OI
- __copy_m(_II __first, _II __last, _OI __result)
- {
- for (; __first != __last; ++__result, (void)++__first)
- *__result = *__first;
- return __result;
- }
- };
-
-#if __cplusplus >= 201103L
- template<typename _Category>
- struct __copy_move<true, false, _Category>
- {
- template<typename _II, typename _OI>
- _GLIBCXX20_CONSTEXPR
- static _OI
- __copy_m(_II __first, _II __last, _OI __result)
- {
- for (; __first != __last; ++__result, (void)++__first)
- *__result = std::move(*__first);
- return __result;
- }
- };
-#endif
-
- template<>
- struct __copy_move<false, false, random_access_iterator_tag>
- {
- template<typename _II, typename _OI>
- _GLIBCXX20_CONSTEXPR
- static _OI
- __copy_m(_II __first, _II __last, _OI __result)
- {
- typedef typename iterator_traits<_II>::difference_type _Distance;
- for(_Distance __n = __last - __first; __n > 0; --__n)
- {
- *__result = *__first;
- ++__first;
- ++__result;
- }
- return __result;
- }
-
- template<typename _Tp, typename _Up>
- static void
- __assign_one(_Tp* __to, _Up* __from)
- { *__to = *__from; }
- };
-
-#if __cplusplus >= 201103L
- template<>
- struct __copy_move<true, false, random_access_iterator_tag>
- {
- template<typename _II, typename _OI>
- _GLIBCXX20_CONSTEXPR
- static _OI
- __copy_m(_II __first, _II __last, _OI __result)
- {
- typedef typename iterator_traits<_II>::difference_type _Distance;
- for(_Distance __n = __last - __first; __n > 0; --__n)
- {
- *__result = std::move(*__first);
- ++__first;
- ++__result;
- }
- return __result;
- }
-
- template<typename _Tp, typename _Up>
- static void
- __assign_one(_Tp* __to, _Up* __from)
- { *__to = std::move(*__from); }
- };
-#endif
-
- template<bool _IsMove>
- struct __copy_move<_IsMove, true, random_access_iterator_tag>
- {
- template<typename _Tp, typename _Up>
- _GLIBCXX20_CONSTEXPR
- static _Up*
- __copy_m(_Tp* __first, _Tp* __last, _Up* __result)
- {
- const ptrdiff_t _Num = __last - __first;
- if (__builtin_expect(_Num > 1, true))
- __builtin_memmove(__result, __first, sizeof(_Tp) * _Num);
- else if (_Num == 1)
- std::__copy_move<_IsMove, false, random_access_iterator_tag>::
- __assign_one(__result, __first);
- return __result + _Num;
- }
- };
-
_GLIBCXX_BEGIN_NAMESPACE_CONTAINER
template<typename _Tp, typename _Ref, typename _Ptr>
_GLIBCXX_STD_C::_Deque_iterator<_CharT, _CharT&, _CharT*>);
#endif // HOSTED
- template<bool _IsMove, typename _II, typename _OI>
- _GLIBCXX20_CONSTEXPR
- inline _OI
- __copy_move_a2(_II __first, _II __last, _OI __result)
+#if __cpp_lib_concepts
+ // N.B. this is not the same as nothrow-forward-iterator, which doesn't
+ // require noexcept operations, it just says it's undefined if they throw.
+ // Here we require them to be actually noexcept.
+ template<typename _Iter>
+ concept __nothrow_contiguous_iterator
+ = contiguous_iterator<_Iter> && requires (_Iter __i) {
+ // If this operation can throw then the iterator could cause
+ // the algorithm to exit early via an exception, in which case
+ // we can't use memcpy.
+ { *__i } noexcept;
+ };
+
+ template<typename _OutIter, typename _InIter, typename _Sent = _InIter>
+ concept __memcpyable_iterators
+ = __nothrow_contiguous_iterator<_OutIter>
+ && __nothrow_contiguous_iterator<_InIter>
+ && sized_sentinel_for<_Sent, _InIter>
+ && requires (_OutIter __o, _InIter __i, _Sent __s) {
+ requires !!__memcpyable<decltype(std::to_address(__o)),
+ decltype(std::to_address(__i))>::__value;
+ { __i != __s } noexcept;
+ };
+#endif
+
+#if __cplusplus < 201103L
+ // Used by __copy_move_a2, __copy_n_a and __copy_move_backward_a2 to
+ // get raw pointers so that calls to __builtin_memmove will compile,
+ // because C++98 can't use 'if constexpr' so statements that use memmove
+ // with pointer arguments need to also compile for arbitrary iterator types.
+ template<typename _Iter> __attribute__((__always_inline__))
+ inline void* __ptr_or_null(_Iter) { return 0; }
+ template<typename _Tp> __attribute__((__always_inline__))
+ inline void* __ptr_or_null(_Tp* __p) { return (void*)__p; }
+# define _GLIBCXX_TO_ADDR(P) std::__ptr_or_null(P)
+ // Used to advance output iterators (std::advance requires InputIterator).
+ template<typename _Iter> __attribute__((__always_inline__))
+ inline void __ptr_advance(_Iter&, ptrdiff_t) { }
+ template<typename _Tp> __attribute__((__always_inline__))
+ inline void __ptr_advance(_Tp*& __p, ptrdiff_t __n) { __p += __n; }
+# define _GLIBCXX_ADVANCE(P, N) std::__ptr_advance(P, N)
+#else
+ // For C++11 mode the __builtin_memmove calls are guarded by 'if constexpr'
+ // so we know the iterators used with memmove are guaranteed to be pointers.
+# define _GLIBCXX_TO_ADDR(P) P
+# define _GLIBCXX_ADVANCE(P, N) P += N
+#endif
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
+ template<bool _IsMove, typename _OutIter, typename _InIter>
+ __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR
+ inline void
+ __assign_one(_OutIter& __out, _InIter& __in)
{
- typedef typename iterator_traits<_II>::iterator_category _Category;
-#ifdef __cpp_lib_is_constant_evaluated
- if (std::is_constant_evaluated())
- return std::__copy_move<_IsMove, false, _Category>::
- __copy_m(__first, __last, __result);
+#if __cplusplus >= 201103L
+ if constexpr (_IsMove)
+ *__out = std::move(*__in);
+ else
#endif
- return std::__copy_move<_IsMove, __memcpyable<_OI, _II>::__value,
- _Category>::__copy_m(__first, __last, __result);
+ *__out = *__in;
}
+ template<bool _IsMove, typename _InIter, typename _Sent, typename _OutIter>
+ _GLIBCXX20_CONSTEXPR
+ inline _OutIter
+ __copy_move_a2(_InIter __first, _Sent __last, _OutIter __result)
+ {
+ typedef __decltype(*__first) _InRef;
+ typedef __decltype(*__result) _OutRef;
+ if _GLIBCXX_CONSTEXPR (!__is_trivially_assignable(_OutRef, _InRef))
+ { } /* Skip the optimizations and use the loop at the end. */
+ else if (std::__is_constant_evaluated())
+ { } /* Skip the optimizations and use the loop at the end. */
+ else if _GLIBCXX_CONSTEXPR (__memcpyable<_OutIter, _InIter>::__value)
+ {
+ ptrdiff_t __n = std::distance(__first, __last);
+ if (__builtin_expect(__n > 1, true))
+ {
+ __builtin_memmove(_GLIBCXX_TO_ADDR(__result),
+ _GLIBCXX_TO_ADDR(__first),
+ __n * sizeof(*__first));
+ _GLIBCXX_ADVANCE(__result, __n);
+ }
+ else if (__n == 1)
+ {
+ std::__assign_one<_IsMove>(__result, __first);
+ ++__result;
+ }
+ return __result;
+ }
+#if __cpp_lib_concepts
+ else if constexpr (__memcpyable_iterators<_OutIter, _InIter, _Sent>)
+ {
+ if (auto __n = __last - __first; __n > 1) [[likely]]
+ {
+ void* __dest = std::to_address(__result);
+ const void* __src = std::to_address(__first);
+ size_t __nbytes = __n * sizeof(iter_value_t<_InIter>);
+ // Advance the iterators first, in case doing so throws.
+ __result += __n;
+ __first += __n;
+ __builtin_memmove(__dest, __src, __nbytes);
+ }
+ else if (__n == 1)
+ {
+ std::__assign_one<_IsMove>(__result, __first);
+ ++__result;
+ }
+ return __result;
+ }
+#endif
+
+ for (; __first != __last; ++__result, (void)++__first)
+ std::__assign_one<_IsMove>(__result, __first);
+ return __result;
+ }
+#pragma GCC diagnostic pop
+
template<bool _IsMove,
typename _Tp, typename _Ref, typename _Ptr, typename _OI>
_OI
const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>&,
const ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>&);
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions" // for if-constexpr
template<typename _InputIterator, typename _Size, typename _OutputIterator>
_GLIBCXX20_CONSTEXPR
_OutputIterator
__copy_n_a(_InputIterator __first, _Size __n, _OutputIterator __result,
bool)
{
+ typedef __decltype(*__first) _InRef;
+ typedef __decltype(*__result) _OutRef;
+ if _GLIBCXX_CONSTEXPR (!__is_trivially_assignable(_OutRef, _InRef))
+ { } /* Skip the optimizations and use the loop at the end. */
+#ifdef __cpp_lib_is_constant_evaluated
+ else if (std::is_constant_evaluated())
+ { } /* Skip the optimizations and use the loop at the end. */
+#endif
+ else if _GLIBCXX_CONSTEXPR (__memcpyable<_OutputIterator,
+ _InputIterator>::__value)
+ {
+ if (__builtin_expect(__n > 1, true))
+ {
+ __builtin_memmove(_GLIBCXX_TO_ADDR(__result),
+ _GLIBCXX_TO_ADDR(__first),
+ __n * sizeof(*__first));
+ _GLIBCXX_ADVANCE(__result, __n);
+ }
+ else if (__n == 1)
+ *__result++ = *__first;
+ return __result;
+ }
+#if __cpp_lib_concepts
+ else if constexpr (__memcpyable_iterators<_OutputIterator,
+ _InputIterator>)
+ {
+ if (__n > 1) [[likely]]
+ {
+ void* __dest = std::to_address(__result);
+ const void* __src = std::to_address(__first);
+ size_t __nbytes = __n * sizeof(iter_value_t<_InputIterator>);
+ // Advance the iterators first, in case doing so throws.
+ __result += __n;
+ __first += __n;
+ __builtin_memmove(__dest, __src, __nbytes);
+ }
+ else if (__n == 1)
+ *__result++ = *__first;
+ return __result;
+ }
+#endif
+
if (__n > 0)
{
while (true)
}
return __result;
}
+#pragma GCC diagnostic pop
#if _GLIBCXX_HOSTED
template<typename _CharT, typename _Size>
#define _GLIBCXX_MOVE3(_Tp, _Up, _Vp) std::copy(_Tp, _Up, _Vp)
#endif
- template<bool _IsMove, bool _IsSimple, typename _Category>
- struct __copy_move_backward
- {
- template<typename _BI1, typename _BI2>
- _GLIBCXX20_CONSTEXPR
- static _BI2
- __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
- {
- while (__first != __last)
- *--__result = *--__last;
- return __result;
- }
- };
-
-#if __cplusplus >= 201103L
- template<typename _Category>
- struct __copy_move_backward<true, false, _Category>
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wc++17-extensions"
+ template<bool _IsMove, typename _BI1, typename _BI2>
+ _GLIBCXX20_CONSTEXPR
+ inline _BI2
+ __copy_move_backward_a2(_BI1 __first, _BI1 __last, _BI2 __result)
{
- template<typename _BI1, typename _BI2>
- _GLIBCXX20_CONSTEXPR
- static _BI2
- __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
- {
- while (__first != __last)
- *--__result = std::move(*--__last);
- return __result;
- }
- };
+ typedef __decltype(*__first) _InRef;
+ typedef __decltype(*__result) _OutRef;
+ if _GLIBCXX_CONSTEXPR (!__is_trivially_assignable(_OutRef, _InRef))
+ { } /* Skip the optimizations and use the loop at the end. */
+#ifdef __cpp_lib_is_constant_evaluated
+ else if (std::is_constant_evaluated())
+ { } /* Skip the optimizations and use the loop at the end. */
#endif
-
- template<>
- struct __copy_move_backward<false, false, random_access_iterator_tag>
- {
- template<typename _BI1, typename _BI2>
- _GLIBCXX20_CONSTEXPR
- static _BI2
- __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
+ else if _GLIBCXX_CONSTEXPR (__memcpyable<_BI2, _BI1>::__value)
{
- typename iterator_traits<_BI1>::difference_type
- __n = __last - __first;
- for (; __n > 0; --__n)
- *--__result = *--__last;
+ ptrdiff_t __n = std::distance(__first, __last);
+ std::advance(__result, -__n);
+ if (__builtin_expect(__n > 1, true))
+ {
+ __builtin_memmove(_GLIBCXX_TO_ADDR(__result),
+ _GLIBCXX_TO_ADDR(__first),
+ __n * sizeof(*__first));
+ }
+ else if (__n == 1)
+ std::__assign_one<_IsMove>(__result, __first);
return __result;
}
- };
-
-#if __cplusplus >= 201103L
- template<>
- struct __copy_move_backward<true, false, random_access_iterator_tag>
- {
- template<typename _BI1, typename _BI2>
- _GLIBCXX20_CONSTEXPR
- static _BI2
- __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
+#if __cpp_lib_concepts
+ else if constexpr (__memcpyable_iterators<_BI2, _BI1>)
{
- typename iterator_traits<_BI1>::difference_type
- __n = __last - __first;
- for (; __n > 0; --__n)
- *--__result = std::move(*--__last);
+ if (auto __n = __last - __first; __n > 1) [[likely]]
+ {
+ const void* __src = std::to_address(__first);
+ // Advance the iterators first, in case doing so throws.
+ __result -= __n;
+ __first += __n;
+ void* __dest = std::to_address(__result);
+ size_t __nbytes = __n * sizeof(iter_value_t<_BI1>);
+ __builtin_memmove(__dest, __src, __nbytes);
+ }
+ else if (__n == 1)
+ {
+ --__result;
+ std::__assign_one<_IsMove>(__result, __first);
+ }
return __result;
}
- };
#endif
- template<bool _IsMove>
- struct __copy_move_backward<_IsMove, true, random_access_iterator_tag>
- {
- template<typename _Tp, typename _Up>
- _GLIBCXX20_CONSTEXPR
- static _Up*
- __copy_move_b(_Tp* __first, _Tp* __last, _Up* __result)
+ while (__first != __last)
{
- const ptrdiff_t _Num = __last - __first;
- if (__builtin_expect(_Num > 1, true))
- __builtin_memmove(__result - _Num, __first, sizeof(_Tp) * _Num);
- else if (_Num == 1)
- std::__copy_move<_IsMove, false, random_access_iterator_tag>::
- __assign_one(__result - 1, __first);
- return __result - _Num;
+ --__last;
+ --__result;
+ std::__assign_one<_IsMove>(__result, __last);
}
- };
-
- template<bool _IsMove, typename _BI1, typename _BI2>
- _GLIBCXX20_CONSTEXPR
- inline _BI2
- __copy_move_backward_a2(_BI1 __first, _BI1 __last, _BI2 __result)
- {
- typedef typename iterator_traits<_BI1>::iterator_category _Category;
-#ifdef __cpp_lib_is_constant_evaluated
- if (std::is_constant_evaluated())
- return std::__copy_move_backward<_IsMove, false, _Category>::
- __copy_move_b(__first, __last, __result);
-#endif
- return std::__copy_move_backward<_IsMove,
- __memcpyable<_BI2, _BI1>::__value,
- _Category>::__copy_move_b(__first,
- __last,
- __result);
+ return __result;
}
+#pragma GCC diagnostic pop
+
+#undef _GLIBCXX_TO_ADDR
+#undef _GLIBCXX_ADVANCE
template<bool _IsMove, typename _BI1, typename _BI2>
_GLIBCXX20_CONSTEXPR