@@ -32,17 +32,221 @@ FwdIt segmented_search_n
3232
3333namespace 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 >
38242SegIter 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>
155295inline 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