Chris@16
|
1 // Copyright Neil Groves 2009. Use, modification and
|
Chris@16
|
2 // distribution is subject to the Boost Software License, Version
|
Chris@16
|
3 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
4 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
5 //
|
Chris@16
|
6 //
|
Chris@16
|
7 // For more information, see http://www.boost.org/libs/range/
|
Chris@16
|
8 //
|
Chris@16
|
9 #ifndef BOOST_RANGE_ALGORITHM_SEARCH_N_HPP_INCLUDED
|
Chris@16
|
10 #define BOOST_RANGE_ALGORITHM_SEARCH_N_HPP_INCLUDED
|
Chris@16
|
11
|
Chris@16
|
12 #include <boost/concept_check.hpp>
|
Chris@16
|
13 #include <boost/range/begin.hpp>
|
Chris@16
|
14 #include <boost/range/end.hpp>
|
Chris@16
|
15 #include <boost/range/concepts.hpp>
|
Chris@16
|
16 #include <boost/range/detail/range_return.hpp>
|
Chris@16
|
17 #include <boost/range/value_type.hpp>
|
Chris@16
|
18 #include <iterator>
|
Chris@16
|
19 #include <algorithm>
|
Chris@16
|
20
|
Chris@16
|
21 namespace boost
|
Chris@16
|
22 {
|
Chris@16
|
23
|
Chris@16
|
24 namespace range_detail
|
Chris@16
|
25 {
|
Chris@16
|
26 // Rationale: search_n is implemented rather than delegate to
|
Chris@16
|
27 // the standard library implementation because some standard
|
Chris@16
|
28 // library implementations are broken eg. MSVC.
|
Chris@16
|
29
|
Chris@16
|
30 // search_n forward iterator version
|
Chris@16
|
31 template<typename ForwardIterator, typename Integer, typename Value>
|
Chris@16
|
32 inline ForwardIterator
|
Chris@16
|
33 search_n_impl(ForwardIterator first, ForwardIterator last, Integer count,
|
Chris@16
|
34 const Value& value, std::forward_iterator_tag)
|
Chris@16
|
35 {
|
Chris@16
|
36 first = std::find(first, last, value);
|
Chris@16
|
37 while (first != last)
|
Chris@16
|
38 {
|
Chris@16
|
39 typename std::iterator_traits<ForwardIterator>::difference_type n = count;
|
Chris@16
|
40 ForwardIterator i = first;
|
Chris@16
|
41 ++i;
|
Chris@16
|
42 while (i != last && n != 1 && *i==value)
|
Chris@16
|
43 {
|
Chris@16
|
44 ++i;
|
Chris@16
|
45 --n;
|
Chris@16
|
46 }
|
Chris@16
|
47 if (n == 1)
|
Chris@16
|
48 return first;
|
Chris@16
|
49 if (i == last)
|
Chris@16
|
50 return last;
|
Chris@16
|
51 first = std::find(++i, last, value);
|
Chris@16
|
52 }
|
Chris@16
|
53 return last;
|
Chris@16
|
54 }
|
Chris@16
|
55
|
Chris@16
|
56 // search_n random-access iterator version
|
Chris@16
|
57 template<typename RandomAccessIterator, typename Integer, typename Value>
|
Chris@16
|
58 inline RandomAccessIterator
|
Chris@16
|
59 search_n_impl(RandomAccessIterator first, RandomAccessIterator last,
|
Chris@16
|
60 Integer count, const Value& value,
|
Chris@16
|
61 std::random_access_iterator_tag)
|
Chris@16
|
62 {
|
Chris@16
|
63 typedef typename std::iterator_traits<RandomAccessIterator>::difference_type difference_t;
|
Chris@16
|
64
|
Chris@16
|
65 difference_t tail_size = last - first;
|
Chris@16
|
66 const difference_t pattern_size = count;
|
Chris@16
|
67
|
Chris@16
|
68 if (tail_size < pattern_size)
|
Chris@16
|
69 return last;
|
Chris@16
|
70
|
Chris@16
|
71 const difference_t skip_offset = pattern_size - 1;
|
Chris@16
|
72 RandomAccessIterator look_ahead = first + skip_offset;
|
Chris@16
|
73 tail_size -= pattern_size;
|
Chris@16
|
74
|
Chris@16
|
75 while (1)
|
Chris@16
|
76 {
|
Chris@16
|
77 // look_ahead here is pointing to the last element of the
|
Chris@16
|
78 // next possible match
|
Chris@16
|
79 while (!(*look_ahead == value)) // skip loop...
|
Chris@16
|
80 {
|
Chris@16
|
81 if (tail_size < pattern_size)
|
Chris@16
|
82 return last; // no match
|
Chris@16
|
83 look_ahead += pattern_size;
|
Chris@16
|
84 tail_size -= pattern_size;
|
Chris@16
|
85 }
|
Chris@16
|
86 difference_t remainder = skip_offset;
|
Chris@16
|
87 for (RandomAccessIterator back_track = look_ahead - 1;
|
Chris@16
|
88 *back_track == value; --back_track)
|
Chris@16
|
89 {
|
Chris@16
|
90 if (--remainder == 0)
|
Chris@16
|
91 {
|
Chris@16
|
92 return look_ahead - skip_offset; // matched
|
Chris@16
|
93 }
|
Chris@16
|
94 }
|
Chris@16
|
95 if (remainder > tail_size)
|
Chris@16
|
96 return last; // no match
|
Chris@16
|
97 look_ahead += remainder;
|
Chris@16
|
98 tail_size -= remainder;
|
Chris@16
|
99 }
|
Chris@16
|
100
|
Chris@16
|
101 return last;
|
Chris@16
|
102 }
|
Chris@16
|
103
|
Chris@16
|
104 // search_n for forward iterators using a binary predicate
|
Chris@16
|
105 // to determine a match
|
Chris@16
|
106 template<typename ForwardIterator, typename Integer, typename Value,
|
Chris@16
|
107 typename BinaryPredicate>
|
Chris@16
|
108 inline ForwardIterator
|
Chris@16
|
109 search_n_pred_impl(ForwardIterator first, ForwardIterator last,
|
Chris@16
|
110 Integer count, const Value& value,
|
Chris@16
|
111 BinaryPredicate pred, std::forward_iterator_tag)
|
Chris@16
|
112 {
|
Chris@16
|
113 typedef typename std::iterator_traits<ForwardIterator>::difference_type difference_t;
|
Chris@16
|
114
|
Chris@16
|
115 while (first != last && !static_cast<bool>(pred(*first, value)))
|
Chris@16
|
116 ++first;
|
Chris@16
|
117
|
Chris@16
|
118 while (first != last)
|
Chris@16
|
119 {
|
Chris@16
|
120 difference_t n = count;
|
Chris@16
|
121 ForwardIterator i = first;
|
Chris@16
|
122 ++i;
|
Chris@16
|
123 while (i != last && n != 1 && static_cast<bool>(pred(*i, value)))
|
Chris@16
|
124 {
|
Chris@16
|
125 ++i;
|
Chris@16
|
126 --n;
|
Chris@16
|
127 }
|
Chris@16
|
128 if (n == 1)
|
Chris@16
|
129 return first;
|
Chris@16
|
130 if (i == last)
|
Chris@16
|
131 return last;
|
Chris@16
|
132 first = ++i;
|
Chris@16
|
133 while (first != last && !static_cast<bool>(pred(*first, value)))
|
Chris@16
|
134 ++first;
|
Chris@16
|
135 }
|
Chris@16
|
136 return last;
|
Chris@16
|
137 }
|
Chris@16
|
138
|
Chris@16
|
139 // search_n for random-access iterators using a binary predicate
|
Chris@16
|
140 // to determine a match
|
Chris@16
|
141 template<typename RandomAccessIterator, typename Integer,
|
Chris@16
|
142 typename Value, typename BinaryPredicate>
|
Chris@16
|
143 inline RandomAccessIterator
|
Chris@16
|
144 search_n_pred_impl(RandomAccessIterator first, RandomAccessIterator last,
|
Chris@16
|
145 Integer count, const Value& value,
|
Chris@16
|
146 BinaryPredicate pred, std::random_access_iterator_tag)
|
Chris@16
|
147 {
|
Chris@16
|
148 typedef typename std::iterator_traits<RandomAccessIterator>::difference_type difference_t;
|
Chris@16
|
149
|
Chris@16
|
150 difference_t tail_size = last - first;
|
Chris@16
|
151 const difference_t pattern_size = count;
|
Chris@16
|
152
|
Chris@16
|
153 if (tail_size < pattern_size)
|
Chris@16
|
154 return last;
|
Chris@16
|
155
|
Chris@16
|
156 const difference_t skip_offset = pattern_size - 1;
|
Chris@16
|
157 RandomAccessIterator look_ahead = first + skip_offset;
|
Chris@16
|
158 tail_size -= pattern_size;
|
Chris@16
|
159
|
Chris@16
|
160 while (1)
|
Chris@16
|
161 {
|
Chris@16
|
162 // look_ahead points to the last element of the next
|
Chris@16
|
163 // possible match
|
Chris@16
|
164 while (!static_cast<bool>(pred(*look_ahead, value))) // skip loop
|
Chris@16
|
165 {
|
Chris@16
|
166 if (tail_size < pattern_size)
|
Chris@16
|
167 return last; // no match
|
Chris@16
|
168 look_ahead += pattern_size;
|
Chris@16
|
169 tail_size -= pattern_size;
|
Chris@16
|
170 }
|
Chris@16
|
171 difference_t remainder = skip_offset;
|
Chris@16
|
172 for (RandomAccessIterator back_track = look_ahead - 1;
|
Chris@16
|
173 pred(*back_track, value); --back_track)
|
Chris@16
|
174 {
|
Chris@16
|
175 if (--remainder == 0)
|
Chris@16
|
176 return look_ahead -= skip_offset; // success
|
Chris@16
|
177 }
|
Chris@16
|
178 if (remainder > tail_size)
|
Chris@16
|
179 {
|
Chris@16
|
180 return last; // no match
|
Chris@16
|
181 }
|
Chris@16
|
182 look_ahead += remainder;
|
Chris@16
|
183 tail_size -= remainder;
|
Chris@16
|
184 }
|
Chris@16
|
185 }
|
Chris@16
|
186
|
Chris@16
|
187 template<typename ForwardIterator, typename Integer, typename Value>
|
Chris@16
|
188 inline ForwardIterator
|
Chris@16
|
189 search_n_impl(ForwardIterator first, ForwardIterator last,
|
Chris@16
|
190 Integer count, const Value& value)
|
Chris@16
|
191 {
|
Chris@16
|
192 BOOST_RANGE_CONCEPT_ASSERT((ForwardIteratorConcept<ForwardIterator>));
|
Chris@16
|
193 BOOST_RANGE_CONCEPT_ASSERT((EqualityComparableConcept<Value>));
|
Chris@16
|
194 BOOST_RANGE_CONCEPT_ASSERT((EqualityComparableConcept<typename std::iterator_traits<ForwardIterator>::value_type>));
|
Chris@16
|
195 //BOOST_RANGE_CONCEPT_ASSERT((EqualityComparableConcept2<typename std::iterator_traits<ForwardIterator>::value_type, Value>));
|
Chris@16
|
196
|
Chris@16
|
197 typedef typename std::iterator_traits<ForwardIterator>::iterator_category cat_t;
|
Chris@16
|
198
|
Chris@16
|
199 if (count <= 0)
|
Chris@16
|
200 return first;
|
Chris@16
|
201 if (count == 1)
|
Chris@16
|
202 return std::find(first, last, value);
|
Chris@16
|
203 return range_detail::search_n_impl(first, last, count, value, cat_t());
|
Chris@16
|
204 }
|
Chris@16
|
205
|
Chris@16
|
206 template<typename ForwardIterator, typename Integer, typename Value,
|
Chris@16
|
207 typename BinaryPredicate>
|
Chris@16
|
208 inline ForwardIterator
|
Chris@16
|
209 search_n_pred_impl(ForwardIterator first, ForwardIterator last,
|
Chris@16
|
210 Integer count, const Value& value,
|
Chris@16
|
211 BinaryPredicate pred)
|
Chris@16
|
212 {
|
Chris@16
|
213 BOOST_RANGE_CONCEPT_ASSERT((ForwardIteratorConcept<ForwardIterator>));
|
Chris@16
|
214 BOOST_RANGE_CONCEPT_ASSERT((
|
Chris@16
|
215 BinaryPredicateConcept<
|
Chris@16
|
216 BinaryPredicate,
|
Chris@16
|
217 typename std::iterator_traits<ForwardIterator>::value_type,
|
Chris@16
|
218 Value>
|
Chris@16
|
219 ));
|
Chris@16
|
220
|
Chris@16
|
221 typedef typename std::iterator_traits<ForwardIterator>::iterator_category cat_t;
|
Chris@16
|
222
|
Chris@16
|
223 if (count <= 0)
|
Chris@16
|
224 return first;
|
Chris@16
|
225 if (count == 1)
|
Chris@16
|
226 {
|
Chris@16
|
227 while (first != last && !static_cast<bool>(pred(*first, value)))
|
Chris@16
|
228 ++first;
|
Chris@16
|
229 return first;
|
Chris@16
|
230 }
|
Chris@16
|
231 return range_detail::search_n_pred_impl(first, last, count,
|
Chris@16
|
232 value, pred, cat_t());
|
Chris@16
|
233 }
|
Chris@16
|
234 } // namespace range_detail
|
Chris@16
|
235
|
Chris@16
|
236 namespace range {
|
Chris@16
|
237
|
Chris@16
|
238 /// \brief template function search
|
Chris@16
|
239 ///
|
Chris@16
|
240 /// range-based version of the search std algorithm
|
Chris@16
|
241 ///
|
Chris@16
|
242 /// \pre ForwardRange is a model of the ForwardRangeConcept
|
Chris@16
|
243 /// \pre Integer is an integral type
|
Chris@16
|
244 /// \pre Value is a model of the EqualityComparableConcept
|
Chris@16
|
245 /// \pre ForwardRange's value type is a model of the EqualityComparableConcept
|
Chris@16
|
246 /// \pre Object's of ForwardRange's value type can be compared for equality with Objects of type Value
|
Chris@16
|
247 template< class ForwardRange, class Integer, class Value >
|
Chris@16
|
248 inline BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::type
|
Chris@16
|
249 search_n(ForwardRange& rng, Integer count, const Value& value)
|
Chris@16
|
250 {
|
Chris@16
|
251 BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<ForwardRange>));
|
Chris@16
|
252 return range_detail::search_n_impl(boost::begin(rng),boost::end(rng), count, value);
|
Chris@16
|
253 }
|
Chris@16
|
254
|
Chris@16
|
255 /// \overload
|
Chris@16
|
256 template< class ForwardRange, class Integer, class Value >
|
Chris@16
|
257 inline BOOST_DEDUCED_TYPENAME range_iterator<const ForwardRange>::type
|
Chris@16
|
258 search_n(const ForwardRange& rng, Integer count, const Value& value)
|
Chris@16
|
259 {
|
Chris@16
|
260 BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<const ForwardRange>));
|
Chris@16
|
261 return range_detail::search_n_impl(boost::begin(rng), boost::end(rng), count, value);
|
Chris@16
|
262 }
|
Chris@16
|
263
|
Chris@16
|
264 /// \overload
|
Chris@16
|
265 template< class ForwardRange, class Integer, class Value,
|
Chris@16
|
266 class BinaryPredicate >
|
Chris@16
|
267 inline BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::type
|
Chris@16
|
268 search_n(ForwardRange& rng, Integer count, const Value& value,
|
Chris@16
|
269 BinaryPredicate binary_pred)
|
Chris@16
|
270 {
|
Chris@16
|
271 BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<ForwardRange>));
|
Chris@16
|
272 BOOST_RANGE_CONCEPT_ASSERT((BinaryPredicateConcept<BinaryPredicate,
|
Chris@16
|
273 BOOST_DEDUCED_TYPENAME range_value<ForwardRange>::type, const Value&>));
|
Chris@16
|
274 return range_detail::search_n_pred_impl(boost::begin(rng), boost::end(rng),
|
Chris@16
|
275 count, value, binary_pred);
|
Chris@16
|
276 }
|
Chris@16
|
277
|
Chris@16
|
278 /// \overload
|
Chris@16
|
279 template< class ForwardRange, class Integer, class Value,
|
Chris@16
|
280 class BinaryPredicate >
|
Chris@16
|
281 inline BOOST_DEDUCED_TYPENAME range_iterator<const ForwardRange>::type
|
Chris@16
|
282 search_n(const ForwardRange& rng, Integer count, const Value& value,
|
Chris@16
|
283 BinaryPredicate binary_pred)
|
Chris@16
|
284 {
|
Chris@16
|
285 BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<const ForwardRange>));
|
Chris@16
|
286 BOOST_RANGE_CONCEPT_ASSERT((BinaryPredicateConcept<BinaryPredicate,
|
Chris@16
|
287 BOOST_DEDUCED_TYPENAME range_value<const ForwardRange>::type, const Value&>));
|
Chris@16
|
288 return range_detail::search_n_pred_impl(boost::begin(rng), boost::end(rng),
|
Chris@16
|
289 count, value, binary_pred);
|
Chris@16
|
290 }
|
Chris@16
|
291
|
Chris@16
|
292 // range_return overloads
|
Chris@16
|
293
|
Chris@16
|
294 /// \overload
|
Chris@16
|
295 template< range_return_value re, class ForwardRange, class Integer,
|
Chris@16
|
296 class Value >
|
Chris@16
|
297 inline BOOST_DEDUCED_TYPENAME range_return<ForwardRange,re>::type
|
Chris@16
|
298 search_n(ForwardRange& rng, Integer count, const Value& value)
|
Chris@16
|
299 {
|
Chris@16
|
300 BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<ForwardRange>));
|
Chris@16
|
301 return range_return<ForwardRange,re>::
|
Chris@16
|
302 pack(range_detail::search_n_impl(boost::begin(rng),boost::end(rng),
|
Chris@16
|
303 count, value),
|
Chris@16
|
304 rng);
|
Chris@16
|
305 }
|
Chris@16
|
306
|
Chris@16
|
307 /// \overload
|
Chris@16
|
308 template< range_return_value re, class ForwardRange, class Integer,
|
Chris@16
|
309 class Value >
|
Chris@16
|
310 inline BOOST_DEDUCED_TYPENAME range_return<const ForwardRange,re>::type
|
Chris@16
|
311 search_n(const ForwardRange& rng, Integer count, const Value& value)
|
Chris@16
|
312 {
|
Chris@16
|
313 BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<const ForwardRange>));
|
Chris@16
|
314 return range_return<const ForwardRange,re>::
|
Chris@16
|
315 pack(range_detail::search_n_impl(boost::begin(rng), boost::end(rng),
|
Chris@16
|
316 count, value),
|
Chris@16
|
317 rng);
|
Chris@16
|
318 }
|
Chris@16
|
319
|
Chris@16
|
320 /// \overload
|
Chris@16
|
321 template< range_return_value re, class ForwardRange, class Integer,
|
Chris@16
|
322 class Value, class BinaryPredicate >
|
Chris@16
|
323 inline BOOST_DEDUCED_TYPENAME range_return<ForwardRange,re>::type
|
Chris@16
|
324 search_n(ForwardRange& rng, Integer count, const Value& value,
|
Chris@16
|
325 BinaryPredicate pred)
|
Chris@16
|
326 {
|
Chris@16
|
327 BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<ForwardRange>));
|
Chris@16
|
328 BOOST_RANGE_CONCEPT_ASSERT((BinaryPredicateConcept<BinaryPredicate,
|
Chris@16
|
329 BOOST_DEDUCED_TYPENAME range_value<ForwardRange>::type,
|
Chris@16
|
330 const Value&>));
|
Chris@16
|
331 return range_return<ForwardRange,re>::
|
Chris@16
|
332 pack(range_detail::search_n_pred_impl(boost::begin(rng),
|
Chris@16
|
333 boost::end(rng),
|
Chris@16
|
334 count, value, pred),
|
Chris@16
|
335 rng);
|
Chris@16
|
336 }
|
Chris@16
|
337
|
Chris@16
|
338 /// \overload
|
Chris@16
|
339 template< range_return_value re, class ForwardRange, class Integer,
|
Chris@16
|
340 class Value, class BinaryPredicate >
|
Chris@16
|
341 inline BOOST_DEDUCED_TYPENAME range_return<const ForwardRange,re>::type
|
Chris@16
|
342 search_n(const ForwardRange& rng, Integer count, const Value& value,
|
Chris@16
|
343 BinaryPredicate pred)
|
Chris@16
|
344 {
|
Chris@16
|
345 BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<const ForwardRange>));
|
Chris@16
|
346 BOOST_RANGE_CONCEPT_ASSERT((BinaryPredicateConcept<BinaryPredicate,
|
Chris@16
|
347 BOOST_DEDUCED_TYPENAME range_value<const ForwardRange>::type,
|
Chris@16
|
348 const Value&>));
|
Chris@16
|
349 return range_return<const ForwardRange,re>::
|
Chris@16
|
350 pack(range_detail::search_n_pred_impl(boost::begin(rng),
|
Chris@16
|
351 boost::end(rng),
|
Chris@16
|
352 count, value, pred),
|
Chris@16
|
353 rng);
|
Chris@16
|
354 }
|
Chris@16
|
355
|
Chris@16
|
356 } // namespace range
|
Chris@16
|
357 using range::search_n;
|
Chris@16
|
358 } // namespace boost
|
Chris@16
|
359
|
Chris@16
|
360 #endif // include guard
|