Unroll segmented_reverse

This commit is contained in:
Ion Gaztañaga
2026-03-29 18:53:13 +02:00
parent 1ca061fb10
commit 568bfdfc2b
@@ -22,6 +22,7 @@
#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 {
@@ -30,15 +31,46 @@ namespace detail_algo {
//Same-segment reverse: simply a reverse loop with move-swaps. No segmentation
template <class BidirIt>
void segmented_reverse_dispatch(BidirIt first, BidirIt last, non_segmented_iterator_tag)
void segmented_reverse_dispatch(BidirIt first, BidirIt last, non_segmented_iterator_tag, const std::bidirectional_iterator_tag &)
{
while(first != last && first != --last) {
boost::adl_move_swap(*first, *last);
++first;
}
}
#define BOOST_CONTAINER_SEGMENTED_REVERSE_RECURSIVE
#ifdef BOOST_CONTAINER_SEGMENTED_REVERSE_RECURSIVE
#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING)
template <class RAIter>
void segmented_reverse_dispatch(RAIter first, RAIter last, non_segmented_iterator_tag, const std::random_access_iterator_tag &)
{
typedef typename iterator_traits<RAIter>::difference_type difference_type;
difference_type pairs = (last - first) / difference_type(2);
while(pairs >= difference_type(4)) {
--last; boost::adl_move_swap(*first, *last); ++first;
--last; boost::adl_move_swap(*first, *last); ++first;
--last; boost::adl_move_swap(*first, *last); ++first;
--last; boost::adl_move_swap(*first, *last); ++first;
pairs -= 4;
}
switch (pairs % 4) {
case 3:
--last; boost::adl_move_swap(*first, *last); ++first;
BOOST_FALLTHROUGH;
case 2:
--last; boost::adl_move_swap(*first, *last); ++first;
BOOST_FALLTHROUGH;
case 1:
--last; boost::adl_move_swap(*first, *last); //No need to increment first since we're done after this.
BOOST_FALLTHROUGH;
default:
break;
}
}
#endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING
//////////////////////////////////////////////
// segmented_reverse_disjoint_ranges: swaps elements between
@@ -48,7 +80,8 @@ void segmented_reverse_dispatch(BidirIt first, BidirIt last, non_segmented_itera
//////////////////////////////////////////////
template <class It>
void segmented_reverse_disjoint_ranges(It& f_out, It const f_end, It const l_beg, It& l_out, non_segmented_iterator_tag)
void segmented_reverse_disjoint_ranges
(It& f_out, It const f_end, It const l_beg, It& l_out, non_segmented_iterator_tag, const std::bidirectional_iterator_tag &)
{
It f = f_out;
It l = l_out;
@@ -62,14 +95,58 @@ void segmented_reverse_disjoint_ranges(It& f_out, It const f_end, It const l_beg
l_out = l;
}
#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING)
template <class It>
void segmented_reverse_disjoint_ranges(It& f, It f_end, It l_beg, It& l, segmented_iterator_tag)
void segmented_reverse_disjoint_ranges
(It& f_out, It const f_end, It const l_beg, It& l_out, non_segmented_iterator_tag, const std::random_access_iterator_tag &)
{
typedef typename iterator_traits<It>::difference_type difference_type;
It f = f_out;
It l = l_out;
difference_type n_f = f_end - f;
difference_type n_l = l - l_beg;
difference_type n = n_f < n_l ? n_f : n_l;
while(n >= difference_type(4)) {
--l; boost::adl_move_swap(*f, *l); ++f;
--l; boost::adl_move_swap(*f, *l); ++f;
--l; boost::adl_move_swap(*f, *l); ++f;
--l; boost::adl_move_swap(*f, *l); ++f;
n -= 4;
}
switch (n % 4) {
case 3:
--l; boost::adl_move_swap(*f, *l); ++f;
BOOST_FALLTHROUGH;
case 2:
--l; boost::adl_move_swap(*f, *l); ++f;
BOOST_FALLTHROUGH;
case 1:
--l; boost::adl_move_swap(*f, *l); ++f;
BOOST_FALLTHROUGH;
default:
break;
}
f_out = f;
l_out = l;
}
#endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING
template <class It, class Cat>
void segmented_reverse_disjoint_ranges(It& f, It f_end, It l_beg, It& l, segmented_iterator_tag, const Cat&)
{
typedef segmented_iterator_traits<It> 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;
typedef typename iterator_traits
<local_iterator>::iterator_category local_cat_t;
//Nothing to swap here if a range is empty
if (f == f_end || l == l_beg)
@@ -89,7 +166,7 @@ void segmented_reverse_disjoint_ranges(It& f, It f_end, It l_beg, It& l, segment
//since the ranges are guaranteed not to overlap
while (true) {
//Reverse the front and back segments recursively
segmented_reverse_disjoint_ranges(fi, fi_end, li_beg, li, is_local_seg_t());
segmented_reverse_disjoint_ranges(fi, fi_end, li_beg, li, is_local_seg_t(), local_cat_t());
//Independent advancement of forward and backward segments since ranges do not to overlap
@@ -123,16 +200,16 @@ void segmented_reverse_disjoint_ranges(It& f, It f_end, It l_beg, It& l, segment
}
}
#endif // BOOST_CONTAINER_SEGMENTED_REVERSE_RECURSIVE
template <class SegIt>
void segmented_reverse_dispatch(SegIt first, SegIt last, segmented_iterator_tag)
template <class SegIt, class Cat>
void segmented_reverse_dispatch(SegIt first, SegIt last, segmented_iterator_tag, const Cat &)
{
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;
typedef typename iterator_traits
<local_iterator>::iterator_category local_cat_t;
segment_iterator sf = traits::segment(first);
segment_iterator sl = traits::segment(last);
@@ -144,7 +221,7 @@ void segmented_reverse_dispatch(SegIt first, SegIt last, segmented_iterator_tag)
local_iterator l_beg = traits::begin(sl);
while (true) {
segmented_reverse_disjoint_ranges(f_loc, f_end, l_beg, l_loc, is_local_seg_t());
segmented_reverse_disjoint_ranges(f_loc, f_end, l_beg, l_loc, is_local_seg_t(), local_cat_t());
//Check if the backward side reached the end of its segment
if (l_loc == l_beg) {
@@ -180,7 +257,7 @@ void segmented_reverse_dispatch(SegIt first, SegIt last, segmented_iterator_tag)
}
}
//Final reverse loop within the final segment
segmented_reverse_dispatch(f_loc, l_loc, is_local_seg_t());
segmented_reverse_dispatch(f_loc, l_loc, is_local_seg_t(), local_cat_t());
}
} // namespace detail_algo
@@ -194,7 +271,9 @@ void segmented_reverse(BidirIter first, BidirIter last)
{
typedef segmented_iterator_traits<BidirIter> traits;
detail_algo::segmented_reverse_dispatch
(first, last, typename traits::is_segmented_iterator());
( first, last
, typename traits::is_segmented_iterator()
, typename iterator_traits<BidirIter>::iterator_category());
}
} // namespace container