[As a WIP, this patch is mostly limited to std::sort and what
it uses, also touching heap primitives. Covering the rest of
stl_algo.h will go quickly if we decide we want that.]
In GCC 16, algorithms like std::sort pass predicates exclusively
by copying. This patch replaces all such copies with move
construction and move assignment, passing function objects into
helper functions that then return them so they may be passed
along to the next operation.
The number of moves performed approximates twice the number of
copies in GCC 16, corresponding to predicates moved into and
returned from helper functions, and half the number of calls
to the predicates. It is possible that minor reorganizing can
reduce the number of moves substantially.
This probably slows down C++98 sorting, but uglifying with a
pair of macros should be able to mitigate that, if we care.
libstdc++-v3/Changelog:
PR libstdc++/111963
* include/bits/stl_algo.h: [Many functions touched.]
* include/bits/stl_heap.h: likewise.
---
libstdc++-v3/include/bits/stl_algo.h | 168 ++++++++++++++++-----------
libstdc++-v3/include/bits/stl_heap.h | 35 +++---
2 files changed, 120 insertions(+), 83 deletions(-)
diff --git a/libstdc++-v3/include/bits/stl_algo.h
b/libstdc++-v3/include/bits/stl_algo.h
index adf9b9e0f28..bee340d08be 100644
--- a/libstdc++-v3/include/bits/stl_algo.h
+++ b/libstdc++-v3/include/bits/stl_algo.h
@@ -84,10 +84,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Swaps the median value of *__a, *__b and *__c under __comp to *__result
template<typename _Iterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- void
- __move_median_to_first(_Iterator __result, _Iterator __a, _Iterator __b,
- _Iterator __c, _Compare __comp)
+ pair<_Compare, _Iterator>
+ __move_median_to_first(pair<_Compare, _Iterator> __cmp_result,
+ _Iterator __a, _Iterator __b, _Iterator __c)
{
+ _Compare& __comp = __cmp_result.first;
+ _Iterator __result = __cmp_result.second;
if (__comp(*__a, *__b))
{
if (__comp(*__b, *__c))
@@ -103,6 +105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
std::iter_swap(__result, __c);
else
std::iter_swap(__result, __b);
+ return __cmp_result;
}
/// Provided for stable_partition to use.
@@ -1585,15 +1588,17 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
/// This is a helper function for the sort routines.
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- void
+ _Compare
__heap_select(_RandomAccessIterator __first,
_RandomAccessIterator __middle,
_RandomAccessIterator __last, _Compare __comp)
{
- std::__make_heap(__first, __middle, __comp);
+ __comp = std::__make_heap(__first, __middle, _GLIBCXX_MOVE(__comp));
for (_RandomAccessIterator __i = __middle; __i < __last; ++__i)
if (__comp(*__i, *__first))
- std::__pop_heap(__first, __middle, __i, __comp);
+ __comp = std::__pop_heap(
+ __first, __middle, __i, _GLIBCXX_MOVE(__comp));
+ return __comp;
}
// partial_sort
@@ -1622,17 +1627,20 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
++__first;
}
- std::__make_heap(__result_first, __result_real_last, __comp);
+ __comp = std::__make_heap(
+ __result_first, __result_real_last, _GLIBCXX_MOVE(__comp));
while (__first != __last)
{
if (__comp(*__first, *__result_first))
- std::__adjust_heap(__result_first, _DistanceType(0),
+ __comp = std::__adjust_heap(__result_first, _DistanceType(0),
_DistanceType(__result_real_last
- __result_first),
- _InputValueType(*__first), __comp);
+ _InputValueType(*__first),
+ _GLIBCXX_MOVE(__comp));
++__first;
}
- std::__sort_heap(__result_first, __result_real_last, __comp);
+ std::__sort_heap(__result_first, __result_real_last,
+ _GLIBCXX_MOVE(__comp));
return __result_real_last;
}
@@ -1746,7 +1754,7 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
/// This is a helper function for the sort routine.
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- void
+ _Compare
__unguarded_linear_insert(_RandomAccessIterator __last,
_Compare __comp)
{
@@ -1761,17 +1769,18 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
--__next;
}
*__last = _GLIBCXX_MOVE(__val);
+ return __comp;
}
/// This is a helper function for the sort routine.
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- void
+ _Compare
__insertion_sort(_RandomAccessIterator __first,
_RandomAccessIterator __last, _Compare __comp)
{
if (__first == __last)
- return;
+ return __comp;
typedef iterator_traits<_RandomAccessIterator> _IterTraits;
typedef typename _IterTraits::difference_type _Dist;
@@ -1785,19 +1794,21 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
*__first = _GLIBCXX_MOVE(__val);
}
else
- std::__unguarded_linear_insert(__i, __comp);
+ __comp = std::__unguarded_linear_insert(__i, _GLIBCXX_MOVE(__comp));
}
+ return __comp;
}
/// This is a helper function for the sort routine.
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- inline void
+ inline _Compare
__unguarded_insertion_sort(_RandomAccessIterator __first,
_RandomAccessIterator __last, _Compare __comp)
{
for (_RandomAccessIterator __i = __first; __i != __last; ++__i)
- std::__unguarded_linear_insert(__i, __comp);
+ __comp = std::__unguarded_linear_insert(__i, _GLIBCXX_MOVE(__comp));
+ return __comp;
}
/**
@@ -1818,86 +1829,99 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
if (__last - __first > __threshold)
{
- std::__insertion_sort(__first, __first + __threshold, __comp);
- std::__unguarded_insertion_sort(__first + __threshold, __last,
- __comp);
+ __comp = std::__insertion_sort(
+ __first, __first + __threshold, _GLIBCXX_MOVE(__comp));
+ std::__unguarded_insertion_sort(
+ __first + __threshold, __last, _GLIBCXX_MOVE(__comp));
}
else
- std::__insertion_sort(__first, __last, __comp);
+ std::__insertion_sort(__first, __last, _GLIBCXX_MOVE(__comp));
}
/// This is a helper function...
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- _RandomAccessIterator
- __unguarded_partition(_RandomAccessIterator __first,
- _RandomAccessIterator __last,
- _RandomAccessIterator __pivot, _Compare __comp)
+ pair<_Compare, _RandomAccessIterator>
+ __unguarded_partition(pair<_Compare, _RandomAccessIterator> __cmp_pivot,
+ _RandomAccessIterator __first,
+ _RandomAccessIterator __last)
{
while (true)
{
+ _Compare& __comp = __cmp_pivot.first;
+ _RandomAccessIterator __pivot = __cmp_pivot.second;
while (__comp(*__first, *__pivot))
++__first;
--__last;
while (__comp(*__pivot, *__last))
--__last;
if (!(__first < __last))
- return __first;
+ break;
std::iter_swap(__first, __last);
++__first;
}
+ __cmp_pivot.second = __first;
+ return __cmp_pivot;
}
/// This is a helper function...
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- inline _RandomAccessIterator
- __unguarded_partition_pivot(_RandomAccessIterator __first,
- _RandomAccessIterator __last, _Compare __comp)
+ inline pair<_Compare, _RandomAccessIterator>
+ __unguarded_partition_pivot(
+ pair<_Compare, _RandomAccessIterator> __cmp_first,
+ _RandomAccessIterator __last)
{
- typedef iterator_traits<_RandomAccessIterator> _IterTraits;
- typedef typename _IterTraits::difference_type _Dist;
+ typedef _RandomAccessIterator _Iter;
+ typedef typename iterator_traits<_Iter>::difference_type _Dist;
- _RandomAccessIterator __mid = __first + _Dist((__last - __first) / 2);
- _RandomAccessIterator __second = __first + _Dist(1);
- std::__move_median_to_first(__first, __second, __mid, __last - _Dist(1),
- __comp);
- return std::__unguarded_partition(__second, __last, __first, __comp);
+ const _Iter __first = __cmp_first.second;
+ const _Iter __mid = __first + _Dist((__last - __first) / 2);
+ const _Iter __second = __first + _Dist(1);
+ __cmp_first = std::__move_median_to_first(
+ _GLIBCXX_MOVE(__cmp_first), __second, __mid, __last - _Dist(1));
+ return std::__unguarded_partition(
+ _GLIBCXX_MOVE(__cmp_first), __second, __last);
}
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- inline void
+ inline _Compare
__partial_sort(_RandomAccessIterator __first,
_RandomAccessIterator __middle,
_RandomAccessIterator __last,
_Compare __comp)
{
- std::__heap_select(__first, __middle, __last, __comp);
- std::__sort_heap(__first, __middle, __comp);
+ __comp = std::__heap_select(
+ __first, __middle, __last, _GLIBCXX_MOVE(__comp));
+ return std::__sort_heap(__first, __middle, _GLIBCXX_MOVE(__comp));
}
/// This is a helper function for the sort routine.
template<typename _RandomAccessIterator, typename _Size, typename _Compare>
_GLIBCXX20_CONSTEXPR
- void
- __introsort_loop(_RandomAccessIterator __first,
- _RandomAccessIterator __last,
- _Size __depth_limit, _Compare __comp)
+ pair<_Compare, _RandomAccessIterator>
+ __introsort_loop(pair<_Compare, _RandomAccessIterator> __cmp_first,
+ _RandomAccessIterator __last, _Size __depth_limit)
{
+ const _RandomAccessIterator __first = __cmp_first.second;
while (__last - __first > int(_S_threshold))
{
if (__depth_limit == 0)
{
- std::__partial_sort(__first, __last, __last, __comp);
- return;
+ __cmp_first.first = std::__partial_sort(
+ __first, __last, __last, _GLIBCXX_MOVE(__cmp_first.first));
+ break;
}
--__depth_limit;
- _RandomAccessIterator __cut =
- std::__unguarded_partition_pivot(__first, __last, __comp);
- std::__introsort_loop(__cut, __last, __depth_limit, __comp);
- __last = __cut;
+ __cmp_first = std::__unguarded_partition_pivot(
+ _GLIBCXX_MOVE(__cmp_first), __last),
+ __cmp_first = std::__introsort_loop(
+ _GLIBCXX_MOVE(__cmp_first), __last, __depth_limit);
+ __last = __cmp_first.second;
+ __cmp_first.second = __first;
}
+ return __cmp_first;
}
// sort
@@ -1905,15 +1929,16 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
inline void
- __sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
- _Compare __comp)
+ __sort(pair<_Compare, _RandomAccessIterator> __cmp_first,
+ _RandomAccessIterator __last)
{
+ const _RandomAccessIterator __first = __cmp_first.second;
if (__first != __last)
{
- std::__introsort_loop(__first, __last,
- std::__lg(__last - __first) * 2,
- __comp);
- std::__final_insertion_sort(__first, __last, __comp);
+ __cmp_first = std::__introsort_loop(
+ _GLIBCXX_MOVE(__cmp_first), __last, std::__lg(__last-__first) * 2);
+ std::__final_insertion_sort(__first, __last,
+ _GLIBCXX_MOVE(__cmp_first.first));
}
}
@@ -1927,24 +1952,29 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
_RandomAccessIterator __after_nth = __nth;
++__after_nth;
+ typedef pair<_Compare, _RandomAccessIterator> _CmpFirst;
+ _CmpFirst __cmp_first(_GLIBCXX_MOVE(__comp), __first);
while (__last - __first > 3)
{
if (__depth_limit == 0)
{
- std::__heap_select(__first, __after_nth, __last, __comp);
+ std::__heap_select(
+ __first, __after_nth, __last, __cmp_first.first);
// Place the nth largest element in its final position.
std::iter_swap(__first, __nth);
return;
}
--__depth_limit;
- _RandomAccessIterator __cut =
- std::__unguarded_partition_pivot(__first, __last, __comp);
+ __cmp_first.second = __first;
+ __cmp_first = std::__unguarded_partition_pivot(
+ __GLIBCXX_MOVE(__cmp_first), __last);
+ _RandomAccessIterator __cut = __cmp_first.second;
if (__cut <= __nth)
__first = __cut;
else
__last = __cut;
}
- std::__insertion_sort(__first, __last, __comp);
+ std::__insertion_sort(__first, __last, __cmp_first.first);
}
/// @endcond
@@ -2666,10 +2696,11 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
{
while (__last - __first >= __chunk_size)
{
- std::__insertion_sort(__first, __first + __chunk_size, __comp);
+ __comp = std::__insertion_sort(
+ __first, __first + __chunk_size, _GLIBCXX_MOVE(__comp));
__first += __chunk_size;
}
- std::__insertion_sort(__first, __last, __comp);
+ std::__insertion_sort(__first, __last, _GLIBCXX_MOVE(__comp));
}
enum { _S_chunk_size = 7 };
@@ -2751,16 +2782,16 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
{
if (__last - __first < 15)
{
- std::__insertion_sort(__first, __last, __comp);
+ std::__insertion_sort(__first, __last, _GLIBCXX_MOVE(__comp));
return;
}
_RandomAccessIterator __middle = __first + (__last - __first) / 2;
- std::__inplace_stable_sort(__first, __middle, __comp);
- std::__inplace_stable_sort(__middle, __last, __comp);
+ __comp = std::__inplace_stable_sort(
+ __first, __middle, _GLIBCXX_MOVE(__comp));
+ __comp = std::__inplace_stable_sort(
+ __middle, __last, _GLIBCXX_MOVE(__comp));
std::__merge_without_buffer(__first, __middle, __last,
- __middle - __first,
- __last - __middle,
- __comp);
+ __middle - __first, __last - __middle, _GLIBCXX_MOVE(__comp));
}
// stable_sort
@@ -4814,7 +4845,7 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
__glibcxx_requires_valid_range(__first, __last);
__glibcxx_requires_irreflexive(__first, __last);
- std::__sort(__first, __last, __gnu_cxx::__ops::less());
+ std::sort(__first, __last, __gnu_cxx::__ops::less());
}
/**
@@ -4846,7 +4877,8 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
__glibcxx_requires_valid_range(__first, __last);
__glibcxx_requires_irreflexive_pred(__first, __last, __comp);
- std::__sort(__first, __last, __comp);
+ typedef pair<_Compare, _RandomAccessIterator> _CmpFirst;
+ std::__sort(_CmpFirst(_GLIBCXX_MOVE(__comp), __first), __last);
}
template<typename _InputIterator1, typename _InputIterator2,
diff --git a/libstdc++-v3/include/bits/stl_heap.h
b/libstdc++-v3/include/bits/stl_heap.h
index 8c5c5df5266..458803e0c45 100644
--- a/libstdc++-v3/include/bits/stl_heap.h
+++ b/libstdc++-v3/include/bits/stl_heap.h
@@ -224,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _RandomAccessIterator, typename _Distance,
typename _Tp, typename _Compare>
_GLIBCXX20_CONSTEXPR
- void
+ _Compare
__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
_Distance __len, _Tp __value, _Compare __comp)
{
@@ -248,13 +248,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
std::__push_heap(__first, __holeIndex, __topIndex,
_GLIBCXX_MOVE(__value), __comp);
+ return __comp;
}
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- inline void
+ inline _Compare
__pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
- _RandomAccessIterator __result, _Compare& __comp)
+ _RandomAccessIterator __result, _GLIBCXX_FWDREF(_Compare) __comp)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
@@ -263,9 +264,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_ValueType __value = _GLIBCXX_MOVE(*__result);
*__result = _GLIBCXX_MOVE(*__first);
- std::__adjust_heap(__first, _DistanceType(0),
+ return std::__adjust_heap(__first, _DistanceType(0),
_DistanceType(__last - __first),
- _GLIBCXX_MOVE(__value), __comp);
+ _GLIBCXX_MOVE(__value),
+ _GLIBCXX_FORWARD(_Compare, __comp));
}
/**
@@ -330,15 +332,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
if (__last - __first > 1)
{
--__last;
- std::__pop_heap(__first, __last, __last, __comp);
+ std::__pop_heap(__first, __last, __last, _GLIBCXX_MOVE(__comp));
}
}
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- void
+ _Compare
__make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
- _Compare& __comp)
+ _Compare __comp)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
@@ -346,19 +348,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_DistanceType;
if (__last - __first < 2)
- return;
+ return __comp;
const _DistanceType __len = __last - __first;
_DistanceType __parent = (__len - 2) / 2;
while (true)
{
_ValueType __value = _GLIBCXX_MOVE(*(__first + __parent));
- std::__adjust_heap(__first, __parent, __len, _GLIBCXX_MOVE(__value),
- __comp);
+ __comp = std::__adjust_heap( __first, __parent, __len,
+ _GLIBCXX_MOVE(__value), _GLIBCXX_MOVE(__comp));
if (__parent == 0)
- return;
+ break;
__parent--;
}
+ return __comp;
}
/**
@@ -413,15 +416,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
- void
+ _Compare
__sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
- _Compare& __comp)
+ _Compare __comp)
{
while (__last - __first > 1)
{
--__last;
- std::__pop_heap(__first, __last, __last, __comp);
+ __comp = std::__pop_heap(
+ __first, __last, __last, _GLIBCXX_MOVE(__comp));
}
+ return __comp;
}
/**
--
2.54.0