/// \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_HPP #define RANGES_V3_ALGORITHM_SEARCH_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_sized_impl(I1 const begin1_, S1 end1, D1 const d1_, I2 begin2, S2 end2, D2 d2, C & pred, P1 & proj1, P2 & proj2) { D1 d1 = d1_; auto begin1 = uncounted(begin1_); while(true) { // Find first element in sequence 1 that matches *begin2, with a mininum // of loop checks while(true) { if(d1 < d2) // return the last if we've run out of room { auto e = ranges::next(recounted(begin1_, std::move(begin1), d1_ - d1), std::move(end1)); return {e, e}; } if(invoke(pred, invoke(proj1, *begin1), invoke(proj2, *begin2))) break; ++begin1; --d1; } // *begin1 matches *begin2, now match elements after here auto m1 = begin1; I2 m2 = begin2; while(true) { if(++m2 == end2) // If pattern exhausted, begin1 is the answer (works // for 1 element pattern) { return {recounted(begin1_, std::move(begin1), d1_ - d1), recounted(begin1_, std::move(++m1), d1_ - d1)}; } ++m1; // No need to check, we know we have room to match successfully if(!invoke( pred, invoke(proj1, *m1), invoke( proj2, *m2))) // if there is a mismatch, restart with a new begin1 { ++begin1; --d1; break; } // else there is a match, check next elements } } } template subrange search_impl(I1 begin1, S1 end1, I2 begin2, S2 end2, C & pred, P1 & proj1, P2 & proj2) { while(true) { // Find first element in sequence 1 that matches *begin2, with a mininum // of loop checks while(true) { if(begin1 == end1) // return end1 if no element matches *begin2 return {begin1, begin1}; if(invoke(pred, invoke(proj1, *begin1), invoke(proj2, *begin2))) break; ++begin1; } // *begin1 matches *begin2, now match elements after here I1 m1 = begin1; I2 m2 = begin2; while(true) { if(++m2 == end2) // If pattern exhausted, begin1 is the answer (works // for 1 element pattern) return {begin1, ++m1}; if(++m1 == end1) // Otherwise if source exhausted, pattern not found return {m1, m1}; if(!invoke( pred, invoke(proj1, *m1), invoke( proj2, *m2))) // if there is a mismatch, restart with a new begin1 { ++begin1; break; } // else there is a match, check next elements } } } } // namespace detail /// \endcond RANGES_BEGIN_NIEBLOID(search) /// \brief function template \c search template auto RANGES_FUN_NIEBLOID(search)(I1 begin1, S1 end1, I2 begin2, S2 end2, C pred = C{}, P1 proj1 = P1{}, P2 proj2 = P2{}) // ->CPP_ret(subrange)( // requires forward_iterator && sentinel_for && forward_iterator && sentinel_for && indirectly_comparable) { if(begin2 == end2) return {begin1, begin1}; if(RANGES_CONSTEXPR_IF(sized_sentinel_for && sized_sentinel_for)) return detail::search_sized_impl(std::move(begin1), std::move(end1), distance(begin1, end1), std::move(begin2), std::move(end2), distance(begin2, end2), pred, proj1, proj2); else return detail::search_impl(std::move(begin1), std::move(end1), std::move(begin2), std::move(end2), pred, proj1, proj2); } /// \overload template auto RANGES_FUN_NIEBLOID(search)( Rng1 && rng1, Rng2 && rng2, C pred = C{}, P1 proj1 = P1{}, P2 proj2 = P2{}) // ->CPP_ret(safe_subrange_t)( // requires forward_range && forward_range && indirectly_comparable, iterator_t, C, P1, P2>) { if(empty(rng2)) return subrange>{begin(rng1), begin(rng1)}; if(RANGES_CONSTEXPR_IF(sized_range && sized_range)) return detail::search_sized_impl(begin(rng1), end(rng1), distance(rng1), begin(rng2), end(rng2), distance(rng2), pred, proj1, proj2); else return detail::search_impl( begin(rng1), end(rng1), begin(rng2), end(rng2), pred, proj1, proj2); } RANGES_END_NIEBLOID(search) namespace cpp20 { using ranges::search; } /// @} } // namespace ranges #endif // include guard