/// \file // Range v3 library // // Copyright Eric Niebler 2014-present // // 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) // // Project home: https://github.com/ericniebler/range-v3 // //===----------------------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef RANGES_V3_ALGORITHM_SEARCH_N_HPP #define RANGES_V3_ALGORITHM_SEARCH_N_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-algorithms /// @{ /// \cond namespace detail { template subrange search_n_sized_impl(I const begin_, S last, D const d_, D cnt, V const & val, C & pred, P & proj) { D d = d_; // always the distance from first to end auto first = uncounted(begin_); while(true) { // Find first element in sequence 1 that matches val, with a mininum of // loop checks while(true) { if(d < cnt) // return the last if we've run out of room { auto e = ranges::next(recounted(begin_, std::move(first), d_ - d), std::move(last)); return {e, e}; } if(invoke(pred, invoke(proj, *first), val)) break; ++first; --d; } // *first matches val, now match elements after here auto m = first; D c = 0; while(true) { if(++c == cnt) // If pattern exhausted, first is the answer (works // for 1 element pattern) return {recounted(begin_, std::move(first), d_ - d), recounted(begin_, std::move(++m), d_ - d)}; ++m; // No need to check, we know we have room to match successfully if(!invoke(pred, invoke(proj, *m), val)) // if there is a mismatch, restart with a new begin { first = next(std::move(m)); d -= (c + 1); break; } // else there is a match, check next elements } } } template subrange search_n_impl(I first, S last, D cnt, V const & val, C & pred, P & proj) { while(true) { // Find first element in sequence 1 that matches val, with a mininum of // loop checks while(true) { if(first == last) // return last if no element matches val return {first, first}; if(invoke(pred, invoke(proj, *first), val)) break; ++first; } // *first matches val, now match elements after here I m = first; D c = 0; while(true) { if(++c == cnt) // If pattern exhausted, first is the answer (works // for 1 element pattern) return {first, ++m}; if(++m == last) // Otherwise if source exhausted, pattern not found return {m, m}; if(!invoke(pred, invoke(proj, *m), val)) // if there is a mismatch, restart with a new begin { first = next(std::move(m)); break; } // else there is a match, check next elements } } } } // namespace detail /// \endcond RANGES_BEGIN_NIEBLOID(search_n) /// \brief function template \c search_n template auto RANGES_FUN_NIEBLOID(search_n)(I first, S last, iter_difference_t cnt, V const & val, C pred = C{}, P proj = P{}) // ->CPP_ret(subrange)( // requires forward_iterator && sentinel_for && indirectly_comparable) { if(cnt <= 0) return {first, first}; if(RANGES_CONSTEXPR_IF(sized_sentinel_for)) return detail::search_n_sized_impl(std::move(first), std::move(last), distance(first, last), cnt, val, pred, proj); else return detail::search_n_impl( std::move(first), std::move(last), cnt, val, pred, proj); } /// \overload template auto RANGES_FUN_NIEBLOID(search_n)(Rng && rng, iter_difference_t> cnt, V const & val, C pred = C{}, P proj = P{}) // ->CPP_ret(safe_subrange_t)( // requires forward_range && indirectly_comparable, V const *, C, P>) { if(cnt <= 0) return subrange>{begin(rng), begin(rng)}; if(RANGES_CONSTEXPR_IF(sized_range)) return detail::search_n_sized_impl( begin(rng), end(rng), distance(rng), cnt, val, pred, proj); else return detail::search_n_impl(begin(rng), end(rng), cnt, val, pred, proj); } RANGES_END_NIEBLOID(search_n) namespace cpp20 { using ranges::search_n; } /// @} } // namespace ranges #endif // include guard