/// \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