|
22 | 22 | #include <boost/container/detail/workaround.hpp> |
23 | 23 | #include <boost/container/experimental/segmented_iterator_traits.hpp> |
24 | 24 | #include <boost/container/experimental/segmented_find_if.hpp> |
25 | | -#include <boost/container/experimental/segmented_remove_copy_if.hpp> |
26 | 25 |
|
27 | 26 | #include <boost/move/utility_core.hpp> |
28 | 27 |
|
29 | 28 | namespace boost { |
30 | 29 | namespace container { |
31 | 30 |
|
| 31 | +template <class FwdIt, class Sent, class Predicate> |
| 32 | +FwdIt segmented_remove_if(FwdIt first, Sent last, Predicate pred); |
| 33 | + |
| 34 | +namespace detail_algo { |
| 35 | + |
| 36 | +////////////////////////////////////////////////////////////////////////////// |
| 37 | +// Bounded result helper: fills destination range [dst_first, dst_last) |
| 38 | +// from source elements not matching pred. Advances next (by reference) |
| 39 | +// until source is exhausted or destination is full. |
| 40 | +// Recursively walks destination segments when dst is segmented. |
| 41 | +// SrcCat is threaded through so the RA-optimized leaf is selected. |
| 42 | +// |
| 43 | +// When dst_last is unreachable_sentinel_t the destination-full check |
| 44 | +// is optimised away, giving the same code as an unbounded loop. |
| 45 | +////////////////////////////////////////////////////////////////////////////// |
| 46 | + |
| 47 | +#if defined(BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING) |
| 48 | + |
| 49 | +template <class RASrcIter, class DstIter, class DstSent, class Pred> |
| 50 | +DstIter segmented_remove_if_dst_bounded |
| 51 | + (RASrcIter& next_out, RASrcIter last, DstIter dst_first, DstSent dst_last, Pred pred, |
| 52 | + const non_segmented_iterator_tag &, const std::random_access_iterator_tag &) |
| 53 | +{ |
| 54 | + typedef typename iterator_traits<RASrcIter>::difference_type difference_type; |
| 55 | + RASrcIter next = next_out; |
| 56 | + |
| 57 | + difference_type n = last - next; |
| 58 | + |
| 59 | + while(n >= difference_type(4)) { |
| 60 | + if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; |
| 61 | + if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; |
| 62 | + if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; |
| 63 | + if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; |
| 64 | + n -= 4; |
| 65 | + } |
| 66 | + |
| 67 | + switch(n) { |
| 68 | + case 3: |
| 69 | + if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; |
| 70 | + BOOST_FALLTHROUGH; |
| 71 | + case 2: |
| 72 | + if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; |
| 73 | + BOOST_FALLTHROUGH; |
| 74 | + case 1: |
| 75 | + if(!pred(*next)) { if(dst_first == dst_last) goto out_path; *dst_first = boost::move(*next); ++dst_first; } ++next; |
| 76 | + BOOST_FALLTHROUGH; |
| 77 | + default: |
| 78 | + break; |
| 79 | + } |
| 80 | + out_path: |
| 81 | + next_out = next; |
| 82 | + return dst_first; |
| 83 | +} |
| 84 | + |
| 85 | +#endif //BOOST_CONTAINER_SEGMENTED_LOOP_UNROLLING |
| 86 | + |
| 87 | +template <class SrcIter, class Sent, class DstIter, class DstSent, class Pred, class DstTag, class SrcCat> |
| 88 | +typename algo_enable_if_c<!DstTag::value, DstIter>::type |
| 89 | +segmented_remove_if_dst_bounded |
| 90 | + (SrcIter& next_out, Sent last, DstIter dst_first, DstSent dst_last, Pred pred, DstTag, SrcCat) |
| 91 | +{ |
| 92 | + SrcIter next = next_out; |
| 93 | + |
| 94 | + for(; next != last; ++next) { |
| 95 | + if(!pred(*next)) { |
| 96 | + if(dst_first == dst_last) |
| 97 | + goto out_path; |
| 98 | + *dst_first = boost::move(*next); |
| 99 | + ++dst_first; |
| 100 | + } |
| 101 | + } |
| 102 | + out_path: |
| 103 | + next_out = next; |
| 104 | + return dst_first; |
| 105 | +} |
| 106 | + |
| 107 | +template <class SrcIter, class Sent, class SegDstIter, class Pred, class SrcCat> |
| 108 | +SegDstIter segmented_remove_if_dst_bounded |
| 109 | + (SrcIter& next, Sent last, SegDstIter dst_first, SegDstIter dst_last, Pred pred, |
| 110 | + segmented_iterator_tag, SrcCat) |
| 111 | +{ |
| 112 | + typedef segmented_iterator_traits<SegDstIter> dst_traits; |
| 113 | + typedef typename dst_traits::local_iterator dst_local_iterator; |
| 114 | + typedef typename dst_traits::segment_iterator dst_segment_iterator; |
| 115 | + typedef typename segmented_iterator_traits<dst_local_iterator>::is_segmented_iterator dst_is_local_seg_t; |
| 116 | + |
| 117 | + dst_segment_iterator sfirst = dst_traits::segment(dst_first); |
| 118 | + const dst_segment_iterator slast = dst_traits::segment(dst_last); |
| 119 | + |
| 120 | + if(sfirst == slast) { |
| 121 | + dst_local_iterator r = (segmented_remove_if_dst_bounded) |
| 122 | + (next, last, dst_traits::local(dst_first), dst_traits::local(dst_last), pred, dst_is_local_seg_t(), SrcCat()); |
| 123 | + return dst_traits::compose(sfirst, r); |
| 124 | + } |
| 125 | + else { |
| 126 | + dst_local_iterator dst_local = (segmented_remove_if_dst_bounded) |
| 127 | + (next, last, dst_traits::local(dst_first), dst_traits::end(sfirst), pred, dst_is_local_seg_t(), SrcCat()); |
| 128 | + if(next == last) |
| 129 | + return dst_traits::compose(sfirst, dst_local); |
| 130 | + |
| 131 | + for(++sfirst; sfirst != slast; ++sfirst) { |
| 132 | + dst_local = (segmented_remove_if_dst_bounded) |
| 133 | + (next, last, dst_traits::begin(sfirst), dst_traits::end(sfirst), pred, dst_is_local_seg_t(), SrcCat()); |
| 134 | + if(next == last) |
| 135 | + return dst_traits::compose(sfirst, dst_local); |
| 136 | + } |
| 137 | + |
| 138 | + dst_local = (segmented_remove_if_dst_bounded) |
| 139 | + (next, last, dst_traits::begin(slast), dst_traits::local(dst_last), pred, dst_is_local_seg_t(), SrcCat()); |
| 140 | + return dst_traits::compose(sfirst, dst_local); |
| 141 | + } |
| 142 | +} |
| 143 | + |
| 144 | +////////////////////////////////////////////////////////////////////////////// |
| 145 | +// Result dispatch: routes to bounded helper. |
| 146 | +// Non-segmented destination: single unbounded call (unreachable_sentinel_t). |
| 147 | +// Segmented destination: loop over destination segments, bounded per segment. |
| 148 | +////////////////////////////////////////////////////////////////////////////// |
| 149 | + |
| 150 | +template <class SrcIter, class Sent, class DstIter, class Pred, class Cat> |
| 151 | +BOOST_CONTAINER_FORCEINLINE DstIter segmented_remove_if_dst_dispatch |
| 152 | + (SrcIter next, Sent last, DstIter first, Pred pred, |
| 153 | + const non_segmented_iterator_tag &, Cat) |
| 154 | +{ |
| 155 | + return (segmented_remove_if_dst_bounded) |
| 156 | + (next, last, first, unreachable_sentinel_t(), pred, non_segmented_iterator_tag(), Cat()); |
| 157 | +} |
| 158 | + |
| 159 | +template <class SrcIter, class Sent, class SegDstIter, class Pred, class Cat> |
| 160 | +SegDstIter segmented_remove_if_dst_dispatch |
| 161 | + (SrcIter next, Sent last, SegDstIter first, Pred pred, |
| 162 | + const segmented_iterator_tag &, Cat) |
| 163 | +{ |
| 164 | + typedef segmented_iterator_traits<SegDstIter> dst_traits; |
| 165 | + typedef typename dst_traits::local_iterator dst_local_iterator; |
| 166 | + typedef typename dst_traits::segment_iterator dst_segment_iterator; |
| 167 | + typedef typename segmented_iterator_traits<dst_local_iterator>::is_segmented_iterator dst_is_local_seg_t; |
| 168 | + |
| 169 | + if(next == last) |
| 170 | + return first; |
| 171 | + |
| 172 | + dst_segment_iterator dst_seg = dst_traits::segment(first); |
| 173 | + dst_local_iterator dst_local = dst_traits::local(first); |
| 174 | + |
| 175 | + while(next != last) { |
| 176 | + dst_local_iterator dst_end = dst_traits::end(dst_seg); |
| 177 | + dst_local = (segmented_remove_if_dst_bounded) |
| 178 | + (next, last, dst_local, dst_end, pred, dst_is_local_seg_t(), Cat()); |
| 179 | + if(next != last) { |
| 180 | + ++dst_seg; |
| 181 | + dst_local = dst_traits::begin(dst_seg); |
| 182 | + } |
| 183 | + } |
| 184 | + return dst_traits::compose(dst_seg, dst_local); |
| 185 | +} |
| 186 | + |
| 187 | +////////////////////////////////////////////////////////////////////////////// |
| 188 | +// Source dispatch: walks the source (read pointer) segments |
| 189 | +////////////////////////////////////////////////////////////////////////////// |
| 190 | + |
| 191 | +template <class SrcIter, class Sent, class DstIter, class Pred, class Tag, class Cat> |
| 192 | +typename algo_enable_if_c< |
| 193 | + !Tag::value || is_sentinel<Sent, SrcIter>::value, DstIter>::type |
| 194 | +segmented_remove_if_dispatch |
| 195 | + (SrcIter next, Sent last, DstIter first, Pred pred, Tag, Cat) |
| 196 | +{ |
| 197 | + // No longer segmented source, now dispatch on destination segmentation. |
| 198 | + typedef segmented_iterator_traits<DstIter> dst_traits; |
| 199 | + return (segmented_remove_if_dst_dispatch) |
| 200 | + (next, last, first, pred, |
| 201 | + typename dst_traits::is_segmented_iterator(), Cat()); |
| 202 | +} |
| 203 | + |
| 204 | +template <class SegSrcIter, class DstIter, class Pred, class Cat> |
| 205 | +DstIter segmented_remove_if_dispatch |
| 206 | + (SegSrcIter next, SegSrcIter last, DstIter first, Pred pred, |
| 207 | + segmented_iterator_tag, Cat) |
| 208 | +{ |
| 209 | + typedef segmented_iterator_traits<SegSrcIter> src_traits; |
| 210 | + typedef typename src_traits::local_iterator src_local_iterator; |
| 211 | + typedef typename src_traits::segment_iterator src_segment_iterator; |
| 212 | + typedef typename segmented_iterator_traits<src_local_iterator>::is_segmented_iterator src_is_local_seg_t; |
| 213 | + typedef typename iterator_traits<src_local_iterator>::iterator_category src_local_cat_t; |
| 214 | + |
| 215 | + src_segment_iterator sfirst = src_traits::segment(next); |
| 216 | + const src_segment_iterator slast = src_traits::segment(last); |
| 217 | + |
| 218 | + if(sfirst == slast) { |
| 219 | + return (segmented_remove_if_dispatch) |
| 220 | + (src_traits::local(next), src_traits::local(last), first, pred, |
| 221 | + src_is_local_seg_t(), src_local_cat_t()); |
| 222 | + } |
| 223 | + else { |
| 224 | + first = (segmented_remove_if_dispatch) |
| 225 | + (src_traits::local(next), src_traits::end(sfirst), first, pred, |
| 226 | + src_is_local_seg_t(), src_local_cat_t()); |
| 227 | + |
| 228 | + for(++sfirst; sfirst != slast; ++sfirst) |
| 229 | + first = (segmented_remove_if_dispatch) |
| 230 | + (src_traits::begin(sfirst), src_traits::end(sfirst), first, pred, |
| 231 | + src_is_local_seg_t(), src_local_cat_t()); |
| 232 | + |
| 233 | + return (segmented_remove_if_dispatch) |
| 234 | + (src_traits::begin(slast), src_traits::local(last), first, pred, |
| 235 | + src_is_local_seg_t(), src_local_cat_t()); |
| 236 | + } |
| 237 | +} |
| 238 | + |
| 239 | +} // namespace detail_algo |
32 | 240 |
|
33 | 241 | //! Removes all elements for which \c pred returns true from [first, last), |
34 | 242 | //! moving retained elements forward. Returns iterator to new end. |
35 | 243 | template <class FwdIt, class Sent, class Predicate> |
36 | 244 | BOOST_CONTAINER_FORCEINLINE |
37 | 245 | FwdIt segmented_remove_if(FwdIt first, Sent last, Predicate pred) |
38 | 246 | { |
| 247 | + typedef segmented_iterator_traits<FwdIt> traits; |
39 | 248 | first = segmented_find_if(first, last, pred); |
40 | | - if (first == last) |
| 249 | + if(first == last) |
41 | 250 | return last; |
42 | 251 |
|
43 | 252 | FwdIt next = first; |
44 | 253 | ++next; |
45 | | - //TODO: This is not the most efficient way to implement segmented_remove_if |
46 | | - //because it does not take advantage that both ranges are segmented, |
47 | | - //but it is the simplest way to implement it |
48 | | - return segmented_remove_copy_if(next, last, first, pred); |
| 254 | + |
| 255 | + return detail_algo::segmented_remove_if_dispatch |
| 256 | + (next, last, first, pred, |
| 257 | + typename traits::is_segmented_iterator(), |
| 258 | + typename iterator_traits<FwdIt>::iterator_category()); |
49 | 259 | } |
50 | 260 |
|
51 | 261 | } // namespace container |
|
0 commit comments