|
- /// \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
- //
- #ifndef RANGES_V3_ALGORITHM_FIND_END_HPP
- #define RANGES_V3_ALGORITHM_FIND_END_HPP
-
- #include <utility>
-
- #include <meta/meta.hpp>
-
- #include <range/v3/range_fwd.hpp>
-
- #include <range/v3/functional/comparisons.hpp>
- #include <range/v3/functional/identity.hpp>
- #include <range/v3/functional/invoke.hpp>
- #include <range/v3/iterator/concepts.hpp>
- #include <range/v3/iterator/operations.hpp>
- #include <range/v3/iterator/traits.hpp>
- #include <range/v3/range/access.hpp>
- #include <range/v3/range/concepts.hpp>
- #include <range/v3/range/traits.hpp>
- #include <range/v3/utility/static_const.hpp>
- #include <range/v3/view/subrange.hpp>
-
- namespace ranges
- {
- /// \cond
- namespace detail
- {
- template<typename I, typename S>
- auto next_to_if(I i, S s, std::true_type) -> CPP_ret(I)( //
- requires input_iterator<I> && sentinel_for<S, I>)
- {
- return ranges::next(i, s);
- }
-
- template<typename I, typename S>
- auto next_to_if(I, S s, std::false_type) -> CPP_ret(S)( //
- requires input_iterator<I> && sentinel_for<S, I>)
- {
- return s;
- }
-
- template<bool B, typename I, typename S>
- auto next_to_if(I i, S s) -> CPP_ret(meta::if_c<B, I, S>)( //
- requires input_iterator<I> && sentinel_for<S, I>)
- {
- return detail::next_to_if(std::move(i), std::move(s), meta::bool_<B>{});
- }
-
- template<typename I1, typename S1, typename I2, typename S2, typename R,
- typename P>
- subrange<I1> find_end_impl(I1 begin1, S1 end1, I2 begin2, S2 end2, R pred, P proj,
- detail::forward_iterator_tag_,
- detail::forward_iterator_tag_)
- {
- bool found = false;
- I1 res_begin, res_end;
- if(begin2 == end2)
- {
- auto e1 = ranges::next(begin1, end1);
- return {e1, e1};
- }
- while(true)
- {
- while(true)
- {
- if(begin1 == end1)
- return {(found ? res_begin : begin1), (found ? res_end : begin1)};
- if(invoke(pred, invoke(proj, *begin1), *begin2))
- break;
- ++begin1;
- }
- auto tmp1 = begin1;
- auto tmp2 = begin2;
- while(true)
- {
- if(++tmp2 == end2)
- {
- res_begin = begin1++;
- res_end = ++tmp1;
- found = true;
- break;
- }
- if(++tmp1 == end1)
- return {(found ? res_begin : tmp1), (found ? res_end : tmp1)};
- if(!invoke(pred, invoke(proj, *tmp1), *tmp2))
- {
- ++begin1;
- break;
- }
- }
- }
- }
-
- template<typename I1, typename I2, typename R, typename P>
- subrange<I1> find_end_impl(I1 begin1, I1 end1, I2 begin2, I2 end2, R pred, P proj,
- detail::bidirectional_iterator_tag_,
- detail::bidirectional_iterator_tag_)
- {
- // modeled after search algorithm (in reverse)
- if(begin2 == end2)
- return {end1, end1}; // Everything matches an empty sequence
- I1 l1 = end1;
- I2 l2 = end2;
- --l2;
- while(true)
- {
- // Find end element in sequence 1 that matches *(end2-1), with a mininum
- // of loop checks
- do
- // return {end1,end1} if no element matches *begin2
- if(begin1 == l1)
- return {end1, end1};
- while(!invoke(pred, invoke(proj, *--l1), *l2));
- // *l1 matches *l2, now match elements before here
- I1 m1 = l1;
- I2 m2 = l2;
- do
- // If pattern exhausted, {m1,++l1} is the answer
- // (works for 1 element pattern)
- if(m2 == begin2)
- return {m1, ++l1};
- // Otherwise if source exhausted, pattern not found
- else if(m1 == begin1)
- return {end1, end1};
- // if there is a mismatch, restart with a new l1
- // else there is a match, check next elements
- while(invoke(pred, invoke(proj, *--m1), *--m2));
- }
- }
-
- template<typename I1, typename I2, typename R, typename P>
- subrange<I1> find_end_impl(I1 begin1, I1 end1, I2 begin2, I2 end2, R pred, P proj,
- detail::random_access_iterator_tag_,
- detail::random_access_iterator_tag_)
- {
- // Take advantage of knowing source and pattern lengths. Stop short when
- // source is smaller than pattern
- auto len2 = end2 - begin2;
- if(len2 == 0)
- return {end1, end1};
- auto len1 = end1 - begin1;
- if(len1 < len2)
- return {end1, end1};
- I1 const start =
- begin1 + (len2 - 1); // End of pattern match can't go before here
- I1 l1 = end1;
- I2 l2 = end2;
- --l2;
- while(true)
- {
- do
- if(start == l1)
- return {end1, end1};
- while(!invoke(pred, invoke(proj, *--l1), *l2));
- I1 m1 = l1;
- I2 m2 = l2;
- do
- if(m2 == begin2)
- return {m1, ++l1};
- // no need to check range on m1 because s guarantees we have enough source
- while(invoke(pred, invoke(proj, *--m1), *--m2));
- }
- }
- } // namespace detail
- /// \endcond
-
- /// \addtogroup group-algorithms
- /// @{
- RANGES_BEGIN_NIEBLOID(find_end)
-
- /// \brief function template \c find_end
- template<typename I1,
- typename S1,
- typename I2,
- typename S2,
- typename R = equal_to,
- typename P = identity>
- auto RANGES_FUN_NIEBLOID(find_end)(
- I1 begin1, S1 end1, I2 begin2, S2 end2, R pred = R{}, P proj = P{}) //
- ->CPP_ret(subrange<I1>)( //
- requires forward_iterator<I1> && sentinel_for<S1, I1> &&
- forward_iterator<I2> && sentinel_for<S2, I2> &&
- indirect_relation<R, projected<I1, P>, I2>)
- {
- constexpr bool Bidi =
- bidirectional_iterator<I1> && bidirectional_iterator<I2>;
- return detail::find_end_impl(begin1,
- detail::next_to_if<Bidi>(begin1, end1),
- begin2,
- detail::next_to_if<Bidi>(begin2, end2),
- std::move(pred),
- std::move(proj),
- iterator_tag_of<I1>(),
- iterator_tag_of<I2>());
- }
-
- /// \overload
- template<typename Rng1,
- typename Rng2,
- typename R = equal_to,
- typename P = identity>
- auto RANGES_FUN_NIEBLOID(find_end)(
- Rng1 && rng1, Rng2 && rng2, R pred = R{}, P proj = P{}) //
- ->CPP_ret(safe_subrange_t<Rng1>)( //
- requires forward_range<Rng1> && forward_range<Rng2> &&
- indirect_relation<R, projected<iterator_t<Rng1>, P>, iterator_t<Rng2>>)
- {
- return (*this)(begin(rng1),
- end(rng1),
- begin(rng2),
- end(rng2),
- std::move(pred),
- std::move(proj));
- }
-
- RANGES_END_NIEBLOID(find_end)
-
- namespace cpp20
- {
- using ranges::find_end;
- }
- /// @}
- } // namespace ranges
-
- #endif // include guard
|