Skip to content

Commit a430796

Browse files
committed
Implement fully recursive segmented_remove_if
1 parent a14cf02 commit a430796

1 file changed

Lines changed: 216 additions & 6 deletions

File tree

include/boost/container/experimental/segmented_remove_if.hpp

Lines changed: 216 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,240 @@
2222
#include <boost/container/detail/workaround.hpp>
2323
#include <boost/container/experimental/segmented_iterator_traits.hpp>
2424
#include <boost/container/experimental/segmented_find_if.hpp>
25-
#include <boost/container/experimental/segmented_remove_copy_if.hpp>
2625

2726
#include <boost/move/utility_core.hpp>
2827

2928
namespace boost {
3029
namespace container {
3130

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
32240

33241
//! Removes all elements for which \c pred returns true from [first, last),
34242
//! moving retained elements forward. Returns iterator to new end.
35243
template <class FwdIt, class Sent, class Predicate>
36244
BOOST_CONTAINER_FORCEINLINE
37245
FwdIt segmented_remove_if(FwdIt first, Sent last, Predicate pred)
38246
{
247+
typedef segmented_iterator_traits<FwdIt> traits;
39248
first = segmented_find_if(first, last, pred);
40-
if (first == last)
249+
if(first == last)
41250
return last;
42251

43252
FwdIt next = first;
44253
++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());
49259
}
50260

51261
} // namespace container

0 commit comments

Comments
 (0)