Skip to content

Commit

Permalink
Optimize swap_ranges for contigious, replaceable ranges
Browse files Browse the repository at this point in the history
  • Loading branch information
mclow committed Oct 7, 2024
1 parent 4c4b7b0 commit 1eb88fc
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions libcxx/include/__algorithm/swap_ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,48 @@ __swap_ranges(_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2
template <class _AlgPolicy, class _ForwardIterator1, class _Sentinel1, class _ForwardIterator2>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_ForwardIterator1, _ForwardIterator2>
__swap_ranges(_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2) {
#if _LIBCPP_STD_VER >= 26
if ! consteval {
using _V1Type = iterator_traits<_ForwardIterator1>::value_type;
using _V2Type = iterator_traits<_ForwardIterator2>::value_type;
if constexpr(__libcpp_is_contiguous_iterator<_ForwardIterator1>::value &&
__libcpp_is_contiguous_iterator<_ForwardIterator2>::value &&
is_same_v<_V1Type, _V2Type> && is_replaceable_v<_V1Type>) {
size_t __distance = distance(__first1, __last1);
if (__distance == 1) {
using std::swap;
swap(*__first1, *__first2);
}
else if (__distance > 0) {
size_t __numBytes = __distance * sizeof(_V1Type);
byte *__aptr = reinterpret_cast<byte *> (addressof(*__first1));
byte *__bptr = reinterpret_cast<byte *> (addressof(*__first2));

size_t __size = __numBytes < 512 ? __numBytes : 512;
size_t __chunk = __numBytes / __size;
size_t __rem = __numBytes % __size;

char __buffer[__size];
if (__chunk > 0) {
for (std::size_t __n = 0; __n < __chunk; __n++, __aptr += __size, __bptr += __size) {
__builtin_memcpy(__buffer, __aptr, __size);
__builtin_memcpy(__aptr, __bptr, __size);
__builtin_memcpy(__bptr, __buffer, __size);
}
}

if (__rem > 0) {
__builtin_memcpy(__buffer, __aptr, __rem);
__builtin_memcpy(__aptr, __bptr, __rem);
__builtin_memcpy(__bptr, __buffer, __rem);
}
}
return pair<_ForwardIterator1, _ForwardIterator2>(__first1 + __distance, __first2 + __distance);
}
}
#endif

// else not replaceable, not contiguous, or constexpr
while (__first1 != __last1) {
_IterOps<_AlgPolicy>::iter_swap(__first1, __first2);
++__first1;
Expand Down

0 comments on commit 1eb88fc

Please sign in to comment.