search_n.hpp 13 KB

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