diff --git a/include/boost/container/experimental/segmented_reverse.hpp b/include/boost/container/experimental/segmented_reverse.hpp index 4ecc57c..67bb9b9 100644 --- a/include/boost/container/experimental/segmented_reverse.hpp +++ b/include/boost/container/experimental/segmented_reverse.hpp @@ -22,61 +22,12 @@ #include #include #include -#include namespace boost { namespace container { namespace detail_algo { -template -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 -BidirIt reverse_scan(SegIt first, SegIt last, BidirIt back, Size& count, segmented_iterator_tag) -{ - typedef segmented_iterator_traits traits; - typedef typename traits::local_iterator local_iterator; - typedef typename segmented_iterator_traits::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 -void segmented_reverse_dispatch(SegIter first, SegIter last, segmented_iterator_tag) -{ - typedef typename boost::container::iterator_traits::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 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 +void segmented_reverse_dispatch(SegIt first, SegIt last, segmented_iterator_tag) +{ + typedef segmented_iterator_traits traits; + typedef typename traits::segment_iterator segment_iterator; + typedef typename traits::local_iterator local_iterator; + typedef typename segmented_iterator_traits::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 void segmented_reverse(BidirIter first, BidirIter last) { diff --git a/include/boost/container/experimental/segmented_reverse_copy.hpp b/include/boost/container/experimental/segmented_reverse_copy.hpp index 14bdb77..8dc903d 100644 --- a/include/boost/container/experimental/segmented_reverse_copy.hpp +++ b/include/boost/container/experimental/segmented_reverse_copy.hpp @@ -35,27 +35,29 @@ OutIter segmented_reverse_copy_dispatch (SegIter first, SegIter last, OutIter result, segmented_iterator_tag) { typedef segmented_iterator_traits 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 inline OutIter segmented_reverse_copy(BidirIter first, BidirIter last, OutIter result) {