diff --git a/include/boost/container/experimental/segmented_iterator_traits.hpp b/include/boost/container/experimental/segmented_iterator_traits.hpp index a7ed737..bf636af 100644 --- a/include/boost/container/experimental/segmented_iterator_traits.hpp +++ b/include/boost/container/experimental/segmented_iterator_traits.hpp @@ -106,6 +106,22 @@ struct constref_generator BOOST_CONTAINER_FORCEINLINE const T& operator()() const { return value; } }; +////////////////////////////////////////////////////////////////////////////// +// Transfer helper: copy (Move=false) or move (Move=true) a single element. +////////////////////////////////////////////////////////////////////////////// + +template struct transfer_op; +template <> struct transfer_op +{ + template + BOOST_CONTAINER_FORCEINLINE static void apply(D& d, S& s) { d = s; } +}; +template <> struct transfer_op +{ + template + BOOST_CONTAINER_FORCEINLINE static void apply(D& d, S& s) { d = boost::move(s); } +}; + } // namespace detail_algo //! Traits class to detect and decompose segmented iterators. diff --git a/include/boost/container/experimental/segmented_remove_copy_if.hpp b/include/boost/container/experimental/segmented_remove_copy_if.hpp index 481b253..542389e 100644 --- a/include/boost/container/experimental/segmented_remove_copy_if.hpp +++ b/include/boost/container/experimental/segmented_remove_copy_if.hpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace boost { namespace container { @@ -31,82 +32,201 @@ OutIter segmented_remove_copy_if(InIter first, Sent last, OutIter result, Pred p namespace detail_algo { +////////////////////////////////////////////////////////////////////////////// +// Bounded destination helper: fills [dst_first, dst_last) from source +// elements not matching pred. Advances first_out (by reference) until +// source is exhausted or destination is full. +// Recursively walks destination segments when dst is segmented. +// SrcCat is threaded through so the RA-optimized leaf is selected. +// +// When dst_last is unreachable_sentinel_t the destination-full check +// is optimised away, giving the same code as an unbounded loop. +// +// Move (first template parameter): true = move, false = copy. +////////////////////////////////////////////////////////////////////////////// + #if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING) -template -OutIter segmented_remove_copy_if_dispatch - (InIter first, InIter last, OutIter result, Pred pred, const non_segmented_iterator_tag &, const std::random_access_iterator_tag &) +template +DstIter segmented_remove_copy_if_dst_bounded + (RASrcIter& first_out, RASrcIter last, DstIter dst_first, DstSent dst_last, Pred pred, + const non_segmented_iterator_tag &, const std::random_access_iterator_tag &) { - typedef typename iterator_traits::difference_type difference_type; + typedef typename iterator_traits::difference_type difference_type; + RASrcIter first = first_out; + difference_type n = last - first; while(n >= difference_type(4)) { - if(!pred(*first)) { *result = *first; ++result; } ++first; - if(!pred(*first)) { *result = *first; ++result; } ++first; - if(!pred(*first)) { *result = *first; ++result; } ++first; - if(!pred(*first)) { *result = *first; ++result; } ++first; + if(!pred(*first)) { if(dst_first == dst_last) goto out_path; transfer_op::apply(*dst_first, *first); ++dst_first; } ++first; + if(!pred(*first)) { if(dst_first == dst_last) goto out_path; transfer_op::apply(*dst_first, *first); ++dst_first; } ++first; + if(!pred(*first)) { if(dst_first == dst_last) goto out_path; transfer_op::apply(*dst_first, *first); ++dst_first; } ++first; + if(!pred(*first)) { if(dst_first == dst_last) goto out_path; transfer_op::apply(*dst_first, *first); ++dst_first; } ++first; n -= 4; } switch(n) { case 3: - if(!pred(*first)) { *result = *first; ++result; } ++first; - if(!pred(*first)) { *result = *first; ++result; } ++first; - if(!pred(*first)) { *result = *first; ++result; } - break; + if(!pred(*first)) { if(dst_first == dst_last) goto out_path; transfer_op::apply(*dst_first, *first); ++dst_first; } ++first; + BOOST_FALLTHROUGH; case 2: - if(!pred(*first)) { *result = *first; ++result; } ++first; - if(!pred(*first)) { *result = *first; ++result; } - break; + if(!pred(*first)) { if(dst_first == dst_last) goto out_path; transfer_op::apply(*dst_first, *first); ++dst_first; } ++first; + BOOST_FALLTHROUGH; case 1: - if(!pred(*first)) { *result = *first; ++result; } - break; + if(!pred(*first)) { if(dst_first == dst_last) goto out_path; transfer_op::apply(*dst_first, *first); ++dst_first; } ++first; + BOOST_FALLTHROUGH; default: break; } - return result; + out_path: + first_out = first; + return dst_first; } #endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING -template -typename algo_enable_if_c< - !Tag::value || is_sentinel::value, OutIter>::type -segmented_remove_copy_if_dispatch - (InIter first, Sent last, OutIter result, Pred pred, Tag, Cat) +template +typename algo_enable_if_c::type +segmented_remove_copy_if_dst_bounded + (SrcIter& first_out, Sent last, DstIter dst_first, DstSent dst_last, Pred pred, DstTag, SrcCat) { + SrcIter first = first_out; + for(; first != last; ++first) { if(!pred(*first)) { - *result = *first; - ++result; + if(dst_first == dst_last) + goto out_path; + transfer_op::apply(*dst_first, *first); + ++dst_first; } } - return result; + out_path: + first_out = first; + return dst_first; } -template +template +SegDstIter segmented_remove_copy_if_dst_bounded + (SrcIter& first, Sent last, SegDstIter dst_first, SegDstIter dst_last, Pred pred, + segmented_iterator_tag, SrcCat) +{ + typedef segmented_iterator_traits dst_traits; + typedef typename dst_traits::local_iterator dst_local_iterator; + typedef typename dst_traits::segment_iterator dst_segment_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator dst_is_local_seg_t; + + dst_segment_iterator sfirst = dst_traits::segment(dst_first); + const dst_segment_iterator slast = dst_traits::segment(dst_last); + + if(sfirst == slast) { + dst_local_iterator r = (segmented_remove_copy_if_dst_bounded) + (first, last, dst_traits::local(dst_first), dst_traits::local(dst_last), pred, dst_is_local_seg_t(), SrcCat()); + return dst_traits::compose(sfirst, r); + } + else { + dst_local_iterator dst_local = (segmented_remove_copy_if_dst_bounded) + (first, last, dst_traits::local(dst_first), dst_traits::end(sfirst), pred, dst_is_local_seg_t(), SrcCat()); + if(first == last) + return dst_traits::compose(sfirst, dst_local); + + for(++sfirst; sfirst != slast; ++sfirst) { + dst_local = (segmented_remove_copy_if_dst_bounded) + (first, last, dst_traits::begin(sfirst), dst_traits::end(sfirst), pred, dst_is_local_seg_t(), SrcCat()); + if(first == last) + return dst_traits::compose(sfirst, dst_local); + } + + dst_local = (segmented_remove_copy_if_dst_bounded) + (first, last, dst_traits::begin(slast), dst_traits::local(dst_last), pred, dst_is_local_seg_t(), SrcCat()); + return dst_traits::compose(sfirst, dst_local); + } +} + +////////////////////////////////////////////////////////////////////////////// +// Destination dispatch: routes to bounded helper. +// Non-segmented destination: single unbounded call (unreachable_sentinel_t). +// Segmented destination: loop over destination segments, bounded per segment. +////////////////////////////////////////////////////////////////////////////// + +template +BOOST_CONTAINER_FORCEINLINE DstIter segmented_remove_copy_if_dst_dispatch + (SrcIter first, Sent last, DstIter result, Pred pred, + const non_segmented_iterator_tag &, Cat) +{ + return (segmented_remove_copy_if_dst_bounded) + (first, last, result, unreachable_sentinel_t(), pred, non_segmented_iterator_tag(), Cat()); +} + +template +SegDstIter segmented_remove_copy_if_dst_dispatch + (SrcIter first, Sent last, SegDstIter result, Pred pred, + const segmented_iterator_tag &, Cat) +{ + typedef segmented_iterator_traits dst_traits; + typedef typename dst_traits::local_iterator dst_local_iterator; + typedef typename dst_traits::segment_iterator dst_segment_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator dst_is_local_seg_t; + + if(first == last) + return result; + + dst_segment_iterator dst_seg = dst_traits::segment(result); + dst_local_iterator dst_local = dst_traits::local(result); + + while(first != last) { + dst_local_iterator dst_end = dst_traits::end(dst_seg); + dst_local = (segmented_remove_copy_if_dst_bounded) + (first, last, dst_local, dst_end, pred, dst_is_local_seg_t(), Cat()); + if(first != last) { + ++dst_seg; + dst_local = dst_traits::begin(dst_seg); + } + } + return dst_traits::compose(dst_seg, dst_local); +} + +////////////////////////////////////////////////////////////////////////////// +// Source dispatch: walks the source (read pointer) segments +////////////////////////////////////////////////////////////////////////////// + +template +typename algo_enable_if_c< + !Tag::value || is_sentinel::value, OutIter>::type +segmented_remove_copy_if_dispatch + (SrcIter first, Sent last, OutIter result, Pred pred, Tag, Cat) +{ + typedef segmented_iterator_traits dst_traits; + return (segmented_remove_copy_if_dst_dispatch) + (first, last, result, pred, typename dst_traits::is_segmented_iterator(), Cat()); +} + +template OutIter segmented_remove_copy_if_dispatch (SegIter first, SegIter last, OutIter result, Pred pred, segmented_iterator_tag, Cat) { - typedef segmented_iterator_traits traits; - typedef typename traits::local_iterator local_iterator; - typedef typename traits::segment_iterator segment_iterator; - typedef typename segmented_iterator_traits::is_segmented_iterator is_local_seg_t; - typedef typename iterator_traits::iterator_category local_cat_t; + typedef segmented_iterator_traits src_traits; + typedef typename src_traits::local_iterator src_local_iterator; + typedef typename src_traits::segment_iterator src_segment_iterator; + typedef typename segmented_iterator_traits::is_segmented_iterator src_is_local_seg_t; + typedef typename iterator_traits::iterator_category src_local_cat_t; - segment_iterator sfirst = traits::segment(first); - segment_iterator slast = traits::segment(last); + src_segment_iterator sfirst = src_traits::segment(first); + const src_segment_iterator slast = src_traits::segment(last); if(sfirst == slast) { - return (segmented_remove_copy_if_dispatch)(traits::local(first), traits::local(last), result, pred, is_local_seg_t(), local_cat_t()); + return (segmented_remove_copy_if_dispatch) + (src_traits::local(first), src_traits::local(last), result, pred, src_is_local_seg_t(), src_local_cat_t()); } else { - result = (segmented_remove_copy_if_dispatch)(traits::local(first), traits::end(sfirst), result, pred, is_local_seg_t(), local_cat_t()); + result = (segmented_remove_copy_if_dispatch) + (src_traits::local(first), src_traits::end(sfirst), result, pred, src_is_local_seg_t(), src_local_cat_t()); for(++sfirst; sfirst != slast; ++sfirst) - result = (segmented_remove_copy_if_dispatch)(traits::begin(sfirst), traits::end(sfirst), result, pred, is_local_seg_t(), local_cat_t()); + result = (segmented_remove_copy_if_dispatch) + (src_traits::begin(sfirst), src_traits::end(sfirst), result, pred, src_is_local_seg_t(), src_local_cat_t()); - return (segmented_remove_copy_if_dispatch)(traits::begin(sfirst), traits::local(last), result, pred, is_local_seg_t(), local_cat_t()); + return (segmented_remove_copy_if_dispatch) + (src_traits::begin(slast), src_traits::local(last), result, pred, src_is_local_seg_t(), src_local_cat_t()); } } @@ -120,7 +240,7 @@ BOOST_CONTAINER_FORCEINLINE OutIter segmented_remove_copy_if(InIter first, Sent last, OutIter result, Pred pred) { typedef segmented_iterator_traits traits; - return detail_algo::segmented_remove_copy_if_dispatch + return detail_algo::segmented_remove_copy_if_dispatch (first, last, result, pred, typename traits::is_segmented_iterator(), typename iterator_traits::iterator_category()); } diff --git a/include/boost/container/experimental/segmented_remove_if.hpp b/include/boost/container/experimental/segmented_remove_if.hpp index 37f1a7b..2ce0728 100644 --- a/include/boost/container/experimental/segmented_remove_if.hpp +++ b/include/boost/container/experimental/segmented_remove_if.hpp @@ -20,224 +20,12 @@ #include #include -#include +#include #include -#include - namespace boost { namespace container { -template -FwdIt segmented_remove_if(FwdIt first, Sent last, Predicate pred); - -namespace detail_algo { - -////////////////////////////////////////////////////////////////////////////// -// Bounded result helper: fills destination range [dst_first, dst_last) -// from source elements not matching pred. Advances next (by reference) -// until source is exhausted or destination is full. -// Recursively walks destination segments when dst is segmented. -// SrcCat is threaded through so the RA-optimized leaf is selected. -// -// When dst_last is unreachable_sentinel_t the destination-full check -// is optimised away, giving the same code as an unbounded loop. -////////////////////////////////////////////////////////////////////////////// - -#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING) - -template -DstIter segmented_remove_if_dst_bounded - (RASrcIter& next_out, RASrcIter last, DstIter dst_first, DstSent dst_last, Pred pred, - const non_segmented_iterator_tag &, const std::random_access_iterator_tag &) -{ - typedef typename iterator_traits::difference_type difference_type; - RASrcIter next = next_out; - - difference_type n = last - next; - - while(n >= difference_type(4)) { - if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; - if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; - if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; - if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; - n -= 4; - } - - switch(n) { - case 3: - if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; - BOOST_FALLTHROUGH; - case 2: - if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; - BOOST_FALLTHROUGH; - case 1: - if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; - BOOST_FALLTHROUGH; - default: - break; - } - out_path: - next_out = next; - return dst_first; -} - -#endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING - -template -typename algo_enable_if_c::type -segmented_remove_if_dst_bounded - (SrcIter& next_out, Sent last, DstIter dst_first, DstSent dst_last, Pred pred, DstTag, SrcCat) -{ - SrcIter next = next_out; - - for(; next != last; ++next) { - if(!pred(*next)) { - if(dst_first == dst_last) - goto out_path; - *dst_first = boost::move(*next); - ++dst_first; - } - } - out_path: - next_out = next; - return dst_first; -} - -template -SegDstIter segmented_remove_if_dst_bounded - (SrcIter& next, Sent last, SegDstIter dst_first, SegDstIter dst_last, Pred pred, - segmented_iterator_tag, SrcCat) -{ - typedef segmented_iterator_traits dst_traits; - typedef typename dst_traits::local_iterator dst_local_iterator; - typedef typename dst_traits::segment_iterator dst_segment_iterator; - typedef typename segmented_iterator_traits::is_segmented_iterator dst_is_local_seg_t; - - dst_segment_iterator sfirst = dst_traits::segment(dst_first); - const dst_segment_iterator slast = dst_traits::segment(dst_last); - - if(sfirst == slast) { - dst_local_iterator r = (segmented_remove_if_dst_bounded) - (next, last, dst_traits::local(dst_first), dst_traits::local(dst_last), pred, dst_is_local_seg_t(), SrcCat()); - return dst_traits::compose(sfirst, r); - } - else { - dst_local_iterator dst_local = (segmented_remove_if_dst_bounded) - (next, last, dst_traits::local(dst_first), dst_traits::end(sfirst), pred, dst_is_local_seg_t(), SrcCat()); - if(next == last) - return dst_traits::compose(sfirst, dst_local); - - for(++sfirst; sfirst != slast; ++sfirst) { - dst_local = (segmented_remove_if_dst_bounded) - (next, last, dst_traits::begin(sfirst), dst_traits::end(sfirst), pred, dst_is_local_seg_t(), SrcCat()); - if(next == last) - return dst_traits::compose(sfirst, dst_local); - } - - dst_local = (segmented_remove_if_dst_bounded) - (next, last, dst_traits::begin(slast), dst_traits::local(dst_last), pred, dst_is_local_seg_t(), SrcCat()); - return dst_traits::compose(sfirst, dst_local); - } -} - -////////////////////////////////////////////////////////////////////////////// -// Result dispatch: routes to bounded helper. -// Non-segmented destination: single unbounded call (unreachable_sentinel_t). -// Segmented destination: loop over destination segments, bounded per segment. -////////////////////////////////////////////////////////////////////////////// - -template -BOOST_CONTAINER_FORCEINLINE DstIter segmented_remove_if_dst_dispatch - (SrcIter next, Sent last, DstIter first, Pred pred, - const non_segmented_iterator_tag &, Cat) -{ - return (segmented_remove_if_dst_bounded) - (next, last, first, unreachable_sentinel_t(), pred, non_segmented_iterator_tag(), Cat()); -} - -template -SegDstIter segmented_remove_if_dst_dispatch - (SrcIter next, Sent last, SegDstIter first, Pred pred, - const segmented_iterator_tag &, Cat) -{ - typedef segmented_iterator_traits dst_traits; - typedef typename dst_traits::local_iterator dst_local_iterator; - typedef typename dst_traits::segment_iterator dst_segment_iterator; - typedef typename segmented_iterator_traits::is_segmented_iterator dst_is_local_seg_t; - - if(next == last) - return first; - - dst_segment_iterator dst_seg = dst_traits::segment(first); - dst_local_iterator dst_local = dst_traits::local(first); - - while(next != last) { - dst_local_iterator dst_end = dst_traits::end(dst_seg); - dst_local = (segmented_remove_if_dst_bounded) - (next, last, dst_local, dst_end, pred, dst_is_local_seg_t(), Cat()); - if(next != last) { - ++dst_seg; - dst_local = dst_traits::begin(dst_seg); - } - } - return dst_traits::compose(dst_seg, dst_local); -} - -////////////////////////////////////////////////////////////////////////////// -// Source dispatch: walks the source (read pointer) segments -////////////////////////////////////////////////////////////////////////////// - -template -typename algo_enable_if_c< - !Tag::value || is_sentinel::value, DstIter>::type -segmented_remove_if_dispatch - (SrcIter next, Sent last, DstIter first, Pred pred, Tag, Cat) -{ - // No longer segmented source, now dispatch on destination segmentation. - typedef segmented_iterator_traits dst_traits; - return (segmented_remove_if_dst_dispatch) - (next, last, first, pred, - typename dst_traits::is_segmented_iterator(), Cat()); -} - -template -DstIter segmented_remove_if_dispatch - (SegSrcIter next, SegSrcIter last, DstIter first, Pred pred, - segmented_iterator_tag, Cat) -{ - typedef segmented_iterator_traits src_traits; - typedef typename src_traits::local_iterator src_local_iterator; - typedef typename src_traits::segment_iterator src_segment_iterator; - typedef typename segmented_iterator_traits::is_segmented_iterator src_is_local_seg_t; - typedef typename iterator_traits::iterator_category src_local_cat_t; - - src_segment_iterator sfirst = src_traits::segment(next); - const src_segment_iterator slast = src_traits::segment(last); - - if(sfirst == slast) { - return (segmented_remove_if_dispatch) - (src_traits::local(next), src_traits::local(last), first, pred, - src_is_local_seg_t(), src_local_cat_t()); - } - else { - first = (segmented_remove_if_dispatch) - (src_traits::local(next), src_traits::end(sfirst), first, pred, - src_is_local_seg_t(), src_local_cat_t()); - - for(++sfirst; sfirst != slast; ++sfirst) - first = (segmented_remove_if_dispatch) - (src_traits::begin(sfirst), src_traits::end(sfirst), first, pred, - src_is_local_seg_t(), src_local_cat_t()); - - return (segmented_remove_if_dispatch) - (src_traits::begin(slast), src_traits::local(last), first, pred, - src_is_local_seg_t(), src_local_cat_t()); - } -} - -} // namespace detail_algo - //! Removes all elements for which \c pred returns true from [first, last), //! moving retained elements forward. Returns iterator to new end. template @@ -252,7 +40,7 @@ FwdIt segmented_remove_if(FwdIt first, Sent last, Predicate pred) FwdIt next = first; ++next; - return detail_algo::segmented_remove_if_dispatch + return detail_algo::segmented_remove_copy_if_dispatch (next, last, first, pred, typename traits::is_segmented_iterator(), typename iterator_traits::iterator_category());