123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- // Copyright Neil Groves 2009. Use, modification and
- // distribution is subject to the Boost Software License, Version
- // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- //
- //
- // For more information, see http://www.boost.org/libs/range/
- //
- #ifndef BOOST_RANGE_ALGORITHM_SEARCH_N_HPP_INCLUDED
- #define BOOST_RANGE_ALGORITHM_SEARCH_N_HPP_INCLUDED
- #include <boost/concept_check.hpp>
- #include <boost/range/begin.hpp>
- #include <boost/range/end.hpp>
- #include <boost/range/concepts.hpp>
- #include <boost/range/detail/range_return.hpp>
- #include <boost/range/value_type.hpp>
- #include <iterator>
- #include <algorithm>
- namespace boost
- {
- namespace range_detail
- {
- // Rationale: search_n is implemented rather than delegate to
- // the standard library implementation because some standard
- // library implementations are broken eg. MSVC.
- // search_n forward iterator version
- template<typename ForwardIterator, typename Integer, typename Value>
- inline ForwardIterator
- search_n_impl(ForwardIterator first, ForwardIterator last, Integer count,
- const Value& value, std::forward_iterator_tag)
- {
- first = std::find(first, last, value);
- while (first != last)
- {
- typename std::iterator_traits<ForwardIterator>::difference_type n = count;
- ForwardIterator i = first;
- ++i;
- while (i != last && n != 1 && *i==value)
- {
- ++i;
- --n;
- }
- if (n == 1)
- return first;
- if (i == last)
- return last;
- first = std::find(++i, last, value);
- }
- return last;
- }
- // search_n random-access iterator version
- template<typename RandomAccessIterator, typename Integer, typename Value>
- inline RandomAccessIterator
- search_n_impl(RandomAccessIterator first, RandomAccessIterator last,
- Integer count, const Value& value,
- std::random_access_iterator_tag)
- {
- typedef typename std::iterator_traits<RandomAccessIterator>::difference_type difference_t;
- difference_t tail_size = last - first;
- const difference_t pattern_size = count;
- if (tail_size < pattern_size)
- return last;
- const difference_t skip_offset = pattern_size - 1;
- RandomAccessIterator look_ahead = first + skip_offset;
- tail_size -= pattern_size;
- while (1)
- {
- // look_ahead here is pointing to the last element of the
- // next possible match
- while (!(*look_ahead == value)) // skip loop...
- {
- if (tail_size < pattern_size)
- return last; // no match
- look_ahead += pattern_size;
- tail_size -= pattern_size;
- }
- difference_t remainder = skip_offset;
- for (RandomAccessIterator back_track = look_ahead - 1;
- *back_track == value; --back_track)
- {
- if (--remainder == 0)
- {
- return look_ahead - skip_offset; // matched
- }
- }
- if (remainder > tail_size)
- return last; // no match
- look_ahead += remainder;
- tail_size -= remainder;
- }
- return last;
- }
- // search_n for forward iterators using a binary predicate
- // to determine a match
- template<typename ForwardIterator, typename Integer, typename Value,
- typename BinaryPredicate>
- inline ForwardIterator
- search_n_pred_impl(ForwardIterator first, ForwardIterator last,
- Integer count, const Value& value,
- BinaryPredicate pred, std::forward_iterator_tag)
- {
- typedef typename std::iterator_traits<ForwardIterator>::difference_type difference_t;
- while (first != last && !static_cast<bool>(pred(*first, value)))
- ++first;
- while (first != last)
- {
- difference_t n = count;
- ForwardIterator i = first;
- ++i;
- while (i != last && n != 1 && static_cast<bool>(pred(*i, value)))
- {
- ++i;
- --n;
- }
- if (n == 1)
- return first;
- if (i == last)
- return last;
- first = ++i;
- while (first != last && !static_cast<bool>(pred(*first, value)))
- ++first;
- }
- return last;
- }
- // search_n for random-access iterators using a binary predicate
- // to determine a match
- template<typename RandomAccessIterator, typename Integer,
- typename Value, typename BinaryPredicate>
- inline RandomAccessIterator
- search_n_pred_impl(RandomAccessIterator first, RandomAccessIterator last,
- Integer count, const Value& value,
- BinaryPredicate pred, std::random_access_iterator_tag)
- {
- typedef typename std::iterator_traits<RandomAccessIterator>::difference_type difference_t;
- difference_t tail_size = last - first;
- const difference_t pattern_size = count;
- if (tail_size < pattern_size)
- return last;
- const difference_t skip_offset = pattern_size - 1;
- RandomAccessIterator look_ahead = first + skip_offset;
- tail_size -= pattern_size;
- while (1)
- {
- // look_ahead points to the last element of the next
- // possible match
- while (!static_cast<bool>(pred(*look_ahead, value))) // skip loop
- {
- if (tail_size < pattern_size)
- return last; // no match
- look_ahead += pattern_size;
- tail_size -= pattern_size;
- }
- difference_t remainder = skip_offset;
- for (RandomAccessIterator back_track = look_ahead - 1;
- pred(*back_track, value); --back_track)
- {
- if (--remainder == 0)
- return look_ahead -= skip_offset; // success
- }
- if (remainder > tail_size)
- {
- return last; // no match
- }
- look_ahead += remainder;
- tail_size -= remainder;
- }
- }
- template<typename ForwardIterator, typename Integer, typename Value>
- inline ForwardIterator
- search_n_impl(ForwardIterator first, ForwardIterator last,
- Integer count, const Value& value)
- {
- BOOST_RANGE_CONCEPT_ASSERT((ForwardIteratorConcept<ForwardIterator>));
- BOOST_RANGE_CONCEPT_ASSERT((EqualityComparableConcept<Value>));
- BOOST_RANGE_CONCEPT_ASSERT((EqualityComparableConcept<typename std::iterator_traits<ForwardIterator>::value_type>));
- //BOOST_RANGE_CONCEPT_ASSERT((EqualityComparableConcept2<typename std::iterator_traits<ForwardIterator>::value_type, Value>));
- typedef typename std::iterator_traits<ForwardIterator>::iterator_category cat_t;
- if (count <= 0)
- return first;
- if (count == 1)
- return std::find(first, last, value);
- return range_detail::search_n_impl(first, last, count, value, cat_t());
- }
- template<typename ForwardIterator, typename Integer, typename Value,
- typename BinaryPredicate>
- inline ForwardIterator
- search_n_pred_impl(ForwardIterator first, ForwardIterator last,
- Integer count, const Value& value,
- BinaryPredicate pred)
- {
- BOOST_RANGE_CONCEPT_ASSERT((ForwardIteratorConcept<ForwardIterator>));
- BOOST_RANGE_CONCEPT_ASSERT((
- BinaryPredicateConcept<
- BinaryPredicate,
- typename std::iterator_traits<ForwardIterator>::value_type,
- Value>
- ));
- typedef typename std::iterator_traits<ForwardIterator>::iterator_category cat_t;
- if (count <= 0)
- return first;
- if (count == 1)
- {
- while (first != last && !static_cast<bool>(pred(*first, value)))
- ++first;
- return first;
- }
- return range_detail::search_n_pred_impl(first, last, count,
- value, pred, cat_t());
- }
- } // namespace range_detail
- namespace range {
- /// \brief template function search
- ///
- /// range-based version of the search std algorithm
- ///
- /// \pre ForwardRange is a model of the ForwardRangeConcept
- /// \pre Integer is an integral type
- /// \pre Value is a model of the EqualityComparableConcept
- /// \pre ForwardRange's value type is a model of the EqualityComparableConcept
- /// \pre Object's of ForwardRange's value type can be compared for equality with Objects of type Value
- template< class ForwardRange, class Integer, class Value >
- inline BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::type
- search_n(ForwardRange& rng, Integer count, const Value& value)
- {
- BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<ForwardRange>));
- return range_detail::search_n_impl(boost::begin(rng),boost::end(rng), count, value);
- }
- /// \overload
- template< class ForwardRange, class Integer, class Value >
- inline BOOST_DEDUCED_TYPENAME range_iterator<const ForwardRange>::type
- search_n(const ForwardRange& rng, Integer count, const Value& value)
- {
- BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<const ForwardRange>));
- return range_detail::search_n_impl(boost::begin(rng), boost::end(rng), count, value);
- }
- /// \overload
- template< class ForwardRange, class Integer, class Value,
- class BinaryPredicate >
- inline BOOST_DEDUCED_TYPENAME range_iterator<ForwardRange>::type
- search_n(ForwardRange& rng, Integer count, const Value& value,
- BinaryPredicate binary_pred)
- {
- BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<ForwardRange>));
- BOOST_RANGE_CONCEPT_ASSERT((BinaryPredicateConcept<BinaryPredicate,
- BOOST_DEDUCED_TYPENAME range_value<ForwardRange>::type, const Value&>));
- return range_detail::search_n_pred_impl(boost::begin(rng), boost::end(rng),
- count, value, binary_pred);
- }
- /// \overload
- template< class ForwardRange, class Integer, class Value,
- class BinaryPredicate >
- inline BOOST_DEDUCED_TYPENAME range_iterator<const ForwardRange>::type
- search_n(const ForwardRange& rng, Integer count, const Value& value,
- BinaryPredicate binary_pred)
- {
- BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<const ForwardRange>));
- BOOST_RANGE_CONCEPT_ASSERT((BinaryPredicateConcept<BinaryPredicate,
- BOOST_DEDUCED_TYPENAME range_value<const ForwardRange>::type, const Value&>));
- return range_detail::search_n_pred_impl(boost::begin(rng), boost::end(rng),
- count, value, binary_pred);
- }
- // range_return overloads
- /// \overload
- template< range_return_value re, class ForwardRange, class Integer,
- class Value >
- inline BOOST_DEDUCED_TYPENAME range_return<ForwardRange,re>::type
- search_n(ForwardRange& rng, Integer count, const Value& value)
- {
- BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<ForwardRange>));
- return range_return<ForwardRange,re>::
- pack(range_detail::search_n_impl(boost::begin(rng),boost::end(rng),
- count, value),
- rng);
- }
- /// \overload
- template< range_return_value re, class ForwardRange, class Integer,
- class Value >
- inline BOOST_DEDUCED_TYPENAME range_return<const ForwardRange,re>::type
- search_n(const ForwardRange& rng, Integer count, const Value& value)
- {
- BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<const ForwardRange>));
- return range_return<const ForwardRange,re>::
- pack(range_detail::search_n_impl(boost::begin(rng), boost::end(rng),
- count, value),
- rng);
- }
- /// \overload
- template< range_return_value re, class ForwardRange, class Integer,
- class Value, class BinaryPredicate >
- inline BOOST_DEDUCED_TYPENAME range_return<ForwardRange,re>::type
- search_n(ForwardRange& rng, Integer count, const Value& value,
- BinaryPredicate pred)
- {
- BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<ForwardRange>));
- BOOST_RANGE_CONCEPT_ASSERT((BinaryPredicateConcept<BinaryPredicate,
- BOOST_DEDUCED_TYPENAME range_value<ForwardRange>::type,
- const Value&>));
- return range_return<ForwardRange,re>::
- pack(range_detail::search_n_pred_impl(boost::begin(rng),
- boost::end(rng),
- count, value, pred),
- rng);
- }
- /// \overload
- template< range_return_value re, class ForwardRange, class Integer,
- class Value, class BinaryPredicate >
- inline BOOST_DEDUCED_TYPENAME range_return<const ForwardRange,re>::type
- search_n(const ForwardRange& rng, Integer count, const Value& value,
- BinaryPredicate pred)
- {
- BOOST_RANGE_CONCEPT_ASSERT((ForwardRangeConcept<const ForwardRange>));
- BOOST_RANGE_CONCEPT_ASSERT((BinaryPredicateConcept<BinaryPredicate,
- BOOST_DEDUCED_TYPENAME range_value<const ForwardRange>::type,
- const Value&>));
- return range_return<const ForwardRange,re>::
- pack(range_detail::search_n_pred_impl(boost::begin(rng),
- boost::end(rng),
- count, value, pred),
- rng);
- }
- } // namespace range
- using range::search_n;
- } // namespace boost
- #endif // include guard
|