boost/range/algorithm/search_n.hpp
// 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