Skip to content

Commit c513406

Browse files
committed
Implemented first recursive search_n implementation. Add random-access iterator overloads
1 parent 77952aa commit c513406

1 file changed

Lines changed: 227 additions & 84 deletions

File tree

include/boost/container/experimental/segmented_search_n.hpp

Lines changed: 227 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,221 @@ FwdIt segmented_search_n
3232

3333
namespace detail_algo {
3434

35+
template <class RAIter, class Size, class T>
36+
BOOST_CONTAINER_FORCEINLINE
37+
RAIter segmented_search_n_dispatch
38+
(RAIter first, RAIter last, Size count, const T& value,
39+
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &)
40+
{
41+
typedef typename iterator_traits<RAIter>::difference_type difference_type;
42+
43+
const difference_type len = last - first;
44+
const difference_type dcount = static_cast<difference_type>(count);
45+
if (dcount > len)
46+
return last;
47+
48+
const RAIter scan_end = last - (dcount - 1);
49+
50+
for (; first < scan_end; ++first) {
51+
if (*first == value) {
52+
RAIter candidate = first;
53+
const RAIter run_end = first + dcount;
54+
++first;
55+
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
56+
for (; first != run_end; ++first) {
57+
if (!(*first == value))
58+
goto continue_scan;
59+
}
60+
return candidate;
61+
continue_scan:;
62+
}
63+
}
64+
return last;
65+
}
66+
67+
template <class FwdIt, class Sent, class Size, class T, class Tag, class Cat>
68+
typename algo_enable_if_c<
69+
!Tag::value || is_sentinel<Sent, FwdIt>::value, FwdIt>::type
70+
segmented_search_n_dispatch
71+
(FwdIt first, Sent last, Size count, const T& value, Tag, Cat)
72+
{
73+
for(; first != last; ++first) {
74+
if(*first == value) {
75+
FwdIt candidate = first;
76+
Size matched = 1;
77+
++first;
78+
BOOST_CONTAINER_SEGMENTED_UNROLL(4)
79+
for(; matched < count; ++matched, ++first) {
80+
if(first == last)
81+
return last;
82+
if(!(*first == value))
83+
goto continue_scan;
84+
}
85+
return candidate;
86+
continue_scan:;
87+
}
88+
}
89+
return last;
90+
}
91+
92+
// Scans local range [lcur, lend) for search_n, updating cross-segment state.
93+
// Returns true if a run of 'count' consecutive matches has been completed.
94+
// On return, lcur is past the last element processed, consecutive/match_start
95+
// are updated to reflect any partial match at the segment tail.
96+
template <class LocalIter, class Size, class T, class SegIter, class SegmentIter>
97+
bool search_n_scan_segment
98+
(LocalIter& lcur, LocalIter lend,
99+
Size& consecutive, Size count, const T& value,
100+
SegIter& match_start, SegmentIter scur,
101+
const non_segmented_iterator_tag &, const std::random_access_iterator_tag &src_tag)
102+
{
103+
typedef segmented_iterator_traits<SegIter> seg_traits;
104+
typedef typename iterator_traits<LocalIter>::difference_type difference_type;
105+
106+
while(lcur != lend) {
107+
if(consecutive == 0) {
108+
// Use find to skip non-matching elements (benefits from RA/vectorization)
109+
lcur = (segmented_find_dispatch)(lcur, lend, value, non_segmented_iterator_tag(), src_tag);
110+
if(lcur == lend)
111+
return false;
112+
113+
match_start = seg_traits::compose(scur, lcur);
114+
consecutive = 1;
115+
if(consecutive == count)
116+
return true;
117+
++lcur;
118+
}
119+
else {
120+
// Verify consecutive matches; we know exactly how many to check
121+
const difference_type need = static_cast<difference_type>(count - consecutive);
122+
const difference_type avail = lend - lcur;
123+
const difference_type ncheck = need < avail ? need : avail;
124+
const LocalIter check_end = lcur + ncheck;
125+
126+
for(; lcur != check_end; ++lcur) {
127+
if(!(*lcur == value)) {
128+
consecutive = 0;
129+
++lcur;
130+
break;
131+
}
132+
++consecutive;
133+
if(consecutive == count)
134+
return true;
135+
}
136+
}
137+
}
138+
return false;
139+
}
140+
141+
template <class LocalIter, class Size, class T, class SegIter, class SegmentIter, class Tag, class Cat>
142+
typename algo_enable_if_c<!Tag::value, bool>::type
143+
search_n_scan_segment
144+
(LocalIter& lcur, LocalIter lend,
145+
Size& consecutive, Size count, const T& value,
146+
SegIter& match_start, SegmentIter scur, Tag, Cat)
147+
{
148+
typedef segmented_iterator_traits<SegIter> seg_traits;
149+
150+
for(; lcur != lend; ++lcur) {
151+
if(*lcur == value) {
152+
if(consecutive == 0)
153+
match_start = seg_traits::compose(scur, lcur);
154+
++consecutive;
155+
if(consecutive == count)
156+
return true;
157+
}
158+
else {
159+
consecutive = 0;
160+
}
161+
}
162+
return false;
163+
}
164+
165+
// Recursively segmented local iterators: decompose into sub-segments
166+
// so that the innermost (non-segmented) level gets RA optimization.
167+
// Uses lend as sentinel to detect whether local_match was set by inner calls
168+
// (a match position is always before lend).
169+
template <class LocalIter, class Size, class T, class SegIter, class SegmentIter, class Cat>
170+
bool search_n_scan_segment
171+
(LocalIter& lcur, LocalIter lend,
172+
Size& consecutive, Size count, const T& value,
173+
SegIter& match_start, SegmentIter scur,
174+
segmented_iterator_tag, Cat)
175+
{
176+
typedef segmented_iterator_traits<SegIter> outer_traits;
177+
typedef segmented_iterator_traits<LocalIter> local_traits;
178+
typedef typename local_traits::segment_iterator sub_seg_iter;
179+
typedef typename local_traits::local_iterator sub_local_iter;
180+
typedef typename segmented_iterator_traits<sub_local_iter>::is_segmented_iterator sub_is_seg_t;
181+
typedef typename iterator_traits<sub_local_iter>::iterator_category sub_cat_t;
182+
183+
sub_seg_iter sub_scur = local_traits::segment(lcur);
184+
sub_seg_iter sub_slast = local_traits::segment(lend);
185+
sub_local_iter sub_lcur = local_traits::local(lcur);
186+
187+
LocalIter local_match = lend;
188+
189+
if(sub_scur == sub_slast) {
190+
sub_local_iter sub_lend = local_traits::local(lend);
191+
if(search_n_scan_segment(sub_lcur, sub_lend, consecutive, count, value,
192+
local_match, sub_scur, sub_is_seg_t(), sub_cat_t())) {
193+
if(local_match != lend)
194+
match_start = outer_traits::compose(scur, local_match);
195+
lcur = lend;
196+
return true;
197+
}
198+
}
199+
else {
200+
{
201+
sub_local_iter sub_lend = local_traits::end(sub_scur);
202+
if(search_n_scan_segment(sub_lcur, sub_lend, consecutive, count, value,
203+
local_match, sub_scur, sub_is_seg_t(), sub_cat_t())) {
204+
if(local_match != lend)
205+
match_start = outer_traits::compose(scur, local_match);
206+
lcur = lend;
207+
return true;
208+
}
209+
}
210+
for(++sub_scur; sub_scur != sub_slast; ++sub_scur) {
211+
sub_lcur = local_traits::begin(sub_scur);
212+
sub_local_iter sub_le = local_traits::end(sub_scur);
213+
if(search_n_scan_segment(sub_lcur, sub_le, consecutive, count, value,
214+
local_match, sub_scur, sub_is_seg_t(), sub_cat_t())) {
215+
if(local_match != lend)
216+
match_start = outer_traits::compose(scur, local_match);
217+
lcur = lend;
218+
return true;
219+
}
220+
}
221+
{
222+
sub_lcur = local_traits::begin(sub_scur);
223+
sub_local_iter sub_ll = local_traits::local(lend);
224+
if(search_n_scan_segment(sub_lcur, sub_ll, consecutive, count, value,
225+
local_match, sub_scur, sub_is_seg_t(), sub_cat_t())) {
226+
if(local_match != lend)
227+
match_start = outer_traits::compose(scur, local_match);
228+
lcur = lend;
229+
return true;
230+
}
231+
}
232+
}
233+
if(local_match != lend)
234+
match_start = outer_traits::compose(scur, local_match);
235+
lcur = lend;
236+
return false;
237+
}
238+
35239
// Non-recursive: must carry cross-segment state (consecutive count,
36240
// match_start) to track runs that span segment boundaries.
37-
template <class SegIter, class Size, class T>
241+
template <class SegIter, class Size, class T, class Cat>
38242
SegIter segmented_search_n_dispatch
39-
(SegIter first, SegIter last, Size count, const T& value, segmented_iterator_tag)
243+
(SegIter first, SegIter last, Size count, const T& value, segmented_iterator_tag, Cat)
40244
{
41-
if(count <= 0) return first;
42-
43245
typedef segmented_iterator_traits<SegIter> traits;
44246
typedef typename traits::segment_iterator segment_iterator;
45247
typedef typename traits::local_iterator local_iterator;
248+
typedef typename segmented_iterator_traits<local_iterator>::is_segmented_iterator is_local_seg_t;
249+
typedef typename iterator_traits<local_iterator>::iterator_category local_cat_t;
46250

47251
Size consecutive = 0;
48252
SegIter match_start = first;
@@ -54,94 +258,30 @@ SegIter segmented_search_n_dispatch
54258

55259
if(scur == slast) {
56260
local_iterator lend = traits::local(last);
57-
for(; lcur != lend; ++lcur) {
58-
if(*lcur == value) {
59-
if(consecutive == 0)
60-
match_start = traits::compose(scur, lcur);
61-
++consecutive;
62-
if(consecutive == count)
63-
return match_start;
64-
}
65-
else {
66-
consecutive = 0;
67-
}
68-
}
261+
if(search_n_scan_segment(lcur, lend, consecutive, count, value,
262+
match_start, scur, is_local_seg_t(), local_cat_t()))
263+
return match_start;
69264
}
70265
else {
71266
{
72267
local_iterator lend = traits::end(scur);
73-
for(; lcur != lend; ++lcur) {
74-
if(*lcur == value) {
75-
if(consecutive == 0)
76-
match_start = traits::compose(scur, lcur);
77-
++consecutive;
78-
if(consecutive == count)
79-
return match_start;
80-
}
81-
else {
82-
consecutive = 0;
83-
}
84-
}
268+
if(search_n_scan_segment(lcur, lend, consecutive, count, value,
269+
match_start, scur, is_local_seg_t(), local_cat_t()))
270+
return match_start;
85271
}
86272
for(++scur; scur != slast; ++scur) {
87-
local_iterator lb = traits::begin(scur);
273+
lcur = traits::begin(scur);
88274
local_iterator le = traits::end(scur);
89-
for(lcur = lb; lcur != le; ++lcur) {
90-
if(*lcur == value) {
91-
if(consecutive == 0)
92-
match_start = traits::compose(scur, lcur);
93-
++consecutive;
94-
if(consecutive == count)
95-
return match_start;
96-
}
97-
else {
98-
consecutive = 0;
99-
}
100-
}
275+
if(search_n_scan_segment(lcur, le, consecutive, count, value,
276+
match_start, scur, is_local_seg_t(), local_cat_t()))
277+
return match_start;
101278
}
102279
{
103-
local_iterator lb = traits::begin(scur);
280+
lcur = traits::begin(scur);
104281
local_iterator ll = traits::local(last);
105-
for(lcur = lb; lcur != ll; ++lcur) {
106-
if(*lcur == value) {
107-
if(consecutive == 0)
108-
match_start = traits::compose(scur, lcur);
109-
++consecutive;
110-
if(consecutive == count)
111-
return match_start;
112-
}
113-
else {
114-
consecutive = 0;
115-
}
116-
}
117-
}
118-
}
119-
return last;
120-
}
121-
122-
template <class FwdIt, class Sent, class Size, class T, class Tag>
123-
typename algo_enable_if_c<
124-
!Tag::value || is_sentinel<Sent, FwdIt>::value, FwdIt>::type
125-
segmented_search_n_dispatch
126-
(FwdIt first, Sent last, Size count, const T& value, Tag)
127-
{
128-
if(count <= 0)
129-
return first;
130-
131-
for(; first != last; ++first) {
132-
if(*first == value) {
133-
FwdIt candidate = first;
134-
Size matched = 1;
135-
FwdIt it = first;
136-
++it;
137-
for(; matched < count; ++matched, ++it) {
138-
if(it == last)
139-
return last;
140-
if(!(*it == value))
141-
break;
142-
}
143-
if(matched == count)
144-
return candidate;
282+
if(search_n_scan_segment(lcur, ll, consecutive, count, value,
283+
match_start, scur, is_local_seg_t(), local_cat_t()))
284+
return match_start;
145285
}
146286
}
147287
return last;
@@ -155,12 +295,15 @@ template <class FwdIt, class Sent, class Size, class T>
155295
inline FwdIt segmented_search_n
156296
(FwdIt first, Sent last, Size count, const T& value)
157297
{
158-
if(count == 1)
298+
if (BOOST_UNLIKELY(count <= 0))
299+
return first;
300+
else if(BOOST_UNLIKELY(count == 1))
159301
return (segmented_find)(first, last, value);
160302

161303
typedef segmented_iterator_traits<FwdIt> traits;
162304
return detail_algo::segmented_search_n_dispatch
163-
(first, last, count, value, typename traits::is_segmented_iterator());
305+
(first, last, count, value, typename traits::is_segmented_iterator(),
306+
typename iterator_traits<FwdIt>::iterator_category());
164307
}
165308

166309
} // namespace container

0 commit comments

Comments
 (0)