Optimized "reverse" algorithms

This commit is contained in:
Ion Gaztañaga
2026-03-12 23:08:06 +01:00
parent ad3db6feec
commit bf5248374f
2 changed files with 85 additions and 64 deletions
@@ -22,61 +22,12 @@
#include <boost/container/detail/workaround.hpp>
#include <boost/container/experimental/segmented_iterator_traits.hpp>
#include <boost/move/adl_move_swap.hpp>
#include <boost/container/detail/iterator.hpp>
namespace boost {
namespace container {
namespace detail_algo {
template <class FwdIt, class BidirIt, class Size>
BidirIt reverse_scan(FwdIt first, FwdIt last, BidirIt back, Size& count, non_segmented_iterator_tag)
{
for(; first != last && count > 0; ++first, --count) {
--back;
boost::adl_move_swap(*first, *back);
}
return back;
}
template <class SegIt, class BidirIt, class Size>
BidirIt reverse_scan(SegIt first, SegIt last, BidirIt back, Size& count, segmented_iterator_tag)
{
typedef segmented_iterator_traits<SegIt> traits;
typedef typename traits::local_iterator local_iterator;
typedef typename segmented_iterator_traits<local_iterator>::is_segmented_iterator is_local_seg_t;
typename traits::segment_iterator scur = traits::segment(first);
typename traits::segment_iterator slast = traits::segment(last);
local_iterator lcur = traits::local(first);
if(scur == slast) {
back = reverse_scan(lcur, traits::local(last), back, count, is_local_seg_t());
}
else {
back = reverse_scan(lcur, traits::end(scur), back, count,
is_local_seg_t());
for(++scur; scur != slast && count > 0; ++scur)
back = reverse_scan(traits::begin(scur), traits::end(scur), back, count,
is_local_seg_t());
if(count > 0)
back = reverse_scan(traits::begin(scur), traits::local(last), back, count,
is_local_seg_t());
}
return back;
}
template <class SegIter>
void segmented_reverse_dispatch(SegIter first, SegIter last, segmented_iterator_tag)
{
typedef typename boost::container::iterator_traits<SegIter>::difference_type diff_t;
diff_t n = 0;
for(SegIter it = first; it != last; ++it)
++n;
diff_t swaps = n / 2;
if(swaps <= 0) return;
SegIter back = last;
reverse_scan(first, last, back, swaps, segmented_iterator_tag());
}
template <class BidirIt>
void segmented_reverse_dispatch(BidirIt first, BidirIt last, non_segmented_iterator_tag)
{
@@ -88,11 +39,76 @@ void segmented_reverse_dispatch(BidirIt first, BidirIt last, non_segmented_itera
}
}
template <class SegIt>
void segmented_reverse_dispatch(SegIt first, SegIt last, segmented_iterator_tag)
{
typedef segmented_iterator_traits<SegIt> traits;
typedef typename traits::segment_iterator segment_iterator;
typedef typename traits::local_iterator local_iterator;
typedef typename segmented_iterator_traits<local_iterator>::is_segmented_iterator is_local_seg_t;
if(first == last) return;
segment_iterator sf = traits::segment(first);
segment_iterator sl = traits::segment(last);
if(sf == sl) {
segmented_reverse_dispatch(traits::local(first), traits::local(last), is_local_seg_t());
return;
}
local_iterator f = traits::local(first);
local_iterator f_end = traits::end(sf);
local_iterator l_beg = traits::begin(sl);
local_iterator l = traits::local(last);
for(;;) {
while(f != f_end && l != l_beg) {
--l;
boost::adl_move_swap(*f, *l);
++f;
}
if(f == f_end && l == l_beg) {
++sf;
if(sf == sl) return;
--sl;
if(sf == sl) {
segmented_reverse_dispatch(
traits::begin(sf), traits::end(sf), is_local_seg_t());
return;
}
f = traits::begin(sf);
f_end = traits::end(sf);
l_beg = traits::begin(sl);
l = traits::end(sl);
}
else if(f == f_end) {
++sf;
if(sf == sl) {
segmented_reverse_dispatch(l_beg, l, is_local_seg_t());
return;
}
f = traits::begin(sf);
f_end = traits::end(sf);
}
else {
--sl;
if(sf == sl) {
segmented_reverse_dispatch(f, f_end, is_local_seg_t());
return;
}
l_beg = traits::begin(sl);
l = traits::end(sl);
}
}
}
} // namespace detail_algo
//! Reverses the order of elements in [first, last).
//! When the iterator is segmented, exploits segmentation on the
//! forward side to reduce per-element overhead.
//! When the iterator is segmented, exploits segmentation on both
//! the forward and backward sides to reduce per-element overhead.
template <class BidirIter>
void segmented_reverse(BidirIter first, BidirIter last)
{
@@ -35,27 +35,29 @@ OutIter segmented_reverse_copy_dispatch
(SegIter first, SegIter last, OutIter result, segmented_iterator_tag)
{
typedef segmented_iterator_traits<SegIter> traits;
typedef typename traits::segment_iterator segment_iterator;
if(first == last)
return result;
typename traits::segment_iterator sfirst = traits::segment(first);
typename traits::segment_iterator slast = traits::segment(last);
segment_iterator sfirst = traits::segment(first);
segment_iterator slast = traits::segment(last);
if(sfirst == slast) {
return boost::container::segmented_reverse_copy(traits::local(first), traits::local(last), result);
return boost::container::segmented_reverse_copy(
traits::local(first), traits::local(last), result);
}
result = boost::container::segmented_reverse_copy(traits::begin(slast), traits::local(last), result);
result = boost::container::segmented_reverse_copy(
traits::begin(slast), traits::local(last), result);
typename traits::segment_iterator s = slast;
while(s != sfirst) {
--s;
if(s != sfirst) {
result = boost::container::segmented_reverse_copy(traits::begin(s), traits::end(s), result);
}
}
segment_iterator s = slast;
for(--s; s != sfirst; --s)
result = boost::container::segmented_reverse_copy(
traits::begin(s), traits::end(s), result);
result = boost::container::segmented_reverse_copy(traits::local(first), traits::end(sfirst), result);
result = boost::container::segmented_reverse_copy(
traits::local(first), traits::end(sfirst), result);
return result;
}
@@ -75,7 +77,10 @@ OutIter segmented_reverse_copy_dispatch
} // namespace detail_algo
//! Copies elements from [first, last) to the range beginning at \c result
//! in reverse order. Returns the output iterator past the last element written.
//! in reverse order. When the source range uses segmented iterators,
//! exploits segmentation by walking segments in reverse order, processing
//! each local range without per-element segment-boundary overhead.
//! Returns the output iterator past the last element written.
template <class BidirIter, class OutIter>
inline OutIter segmented_reverse_copy(BidirIter first, BidirIter last, OutIter result)
{