eedb/share/include/range/v3/algorithm/find_end.hpp
Wieczorek Bartosz f4ef592706 add ranges lib
2017-03-18 08:15:40 +01:00

196 lines
7.6 KiB
C++

/// \file
// Range v3 library
//
// Copyright Eric Niebler 2014
//
// 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/begin_end.hpp>
#include <range/v3/range_concepts.hpp>
#include <range/v3/range_traits.hpp>
#include <range/v3/utility/iterator_concepts.hpp>
#include <range/v3/utility/iterator_traits.hpp>
#include <range/v3/utility/functional.hpp>
#include <range/v3/utility/static_const.hpp>
namespace ranges
{
inline namespace v3
{
/// \cond
namespace detail
{
template<typename I, typename S,
CONCEPT_REQUIRES_(InputIterator<I>() && Sentinel<S, I>())>
I next_to_if(I i, S s, std::true_type)
{
return ranges::next(i, s);
}
template<typename I, typename S,
CONCEPT_REQUIRES_(InputIterator<I>() && Sentinel<S, I>())>
S next_to_if(I, S s, std::false_type)
{
return s;
}
template<bool B, typename I, typename S,
CONCEPT_REQUIRES_(InputIterator<I>() && Sentinel<S, I>())>
meta::if_c<B, I, S> next_to_if(I i, S s)
{
return detail::next_to_if(std::move(i), std::move(s), meta::bool_<B>{});
}
}
/// \endcond
/// \addtogroup group-algorithms
/// @{
struct find_end_fn
{
private:
template<typename I1, typename S1, typename I2, typename S2, typename R, typename P>
static I1
impl(I1 begin1, S1 end1, I2 begin2, S2 end2, R pred, P proj,
concepts::ForwardIterator*, concepts::ForwardIterator*)
{
bool found = false;
I1 res;
if(begin2 == end2)
return ranges::next(begin1, end1);
while(true)
{
while(true)
{
if(begin1 == end1)
return found ? res : begin1;
if(invoke(pred, invoke(proj, *begin1), *begin2))
break;
++begin1;
}
auto tmp1 = begin1;
auto tmp2 = begin2;
while(true)
{
if(++tmp2 == end2)
{
res = begin1++;
found = true;
break;
}
if(++tmp1 == end1)
return found ? res : tmp1;
if(!invoke(pred, invoke(proj, *tmp1), *tmp2))
{
++begin1;
break;
}
}
}
}
template<typename I1, typename I2, typename R, typename P>
static I1
impl(I1 begin1, I1 end1, I2 begin2, I2 end2, R pred, P proj,
concepts::BidirectionalIterator*, concepts::BidirectionalIterator*)
{
// modeled after search algorithm (in reverse)
if(begin2 == end2)
return 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
// return end1 if no element matches *begin2
do if(begin1 == l1) return end1;
while(!invoke(pred, invoke(proj, *--l1), *l2));
// *l1 matches *l2, now match elements before here
I1 m1 = l1;
I2 m2 = l2;
// If pattern exhausted, m1 is the answer (works for 1 element pattern)
do if(m2 == begin2) return m1;
// Otherwise if source exhausted, pattern not found
else if(m1 == begin1) return 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>
static I1
impl(I1 begin1, I1 end1, I2 begin2, I2 end2, R pred, P proj,
concepts::RandomAccessIterator*, concepts::RandomAccessIterator*)
{
// 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;
auto len1 = end1 - begin1;
if(len1 < len2)
return end1;
const I1 s = begin1 + (len2 - 1); // End of pattern match can't go before here
I1 l1 = end1;
I2 l2 = end2;
--l2;
while(true)
{
do if(s == l1) return end1;
while(!invoke(pred, invoke(proj, *--l1), *l2));
I1 m1 = l1;
I2 m2 = l2;
do if(m2 == begin2) return m1;
// no need to check range on m1 because s guarantees we have enough source
while(invoke(pred, invoke(proj, *--m1), *--m2));
}
}
public:
template<typename I1, typename S1, typename I2, typename S2, typename R = equal_to,
typename P = ident,
CONCEPT_REQUIRES_(ForwardIterator<I1>() && Sentinel<S1, I1>() &&
ForwardIterator<I2>() && Sentinel<S2, I2>() &&
IndirectRelation<R, projected<I1, P>, I2>())>
I1 operator()(I1 begin1, S1 end1, I2 begin2, S2 end2, R pred = R{}, P proj = P{}) const
{
constexpr bool Bidi = BidirectionalIterator<I1>() && BidirectionalIterator<I2>();
return find_end_fn::impl(
begin1, detail::next_to_if<Bidi>(begin1, end1),
begin2, detail::next_to_if<Bidi>(begin2, end2),
std::move(pred), std::move(proj),
iterator_concept<I1>(), iterator_concept<I2>());
}
template<typename Rng1, typename Rng2, typename R = equal_to, typename P = ident,
typename I1 = iterator_t<Rng1>,
typename I2 = iterator_t<Rng2>,
CONCEPT_REQUIRES_(ForwardRange<Rng1>() && ForwardRange<Rng2>() &&
IndirectRelation<R, projected<I1, P>, I2>())>
safe_iterator_t<Rng1> operator()(Rng1 &&rng1, Rng2 &&rng2, R pred = R{}, P proj = P{}) const
{
return (*this)(begin(rng1), end(rng1), begin(rng2), end(rng2), std::move(pred),
std::move(proj));
}
};
/// \sa `find_end_fn`
/// \ingroup group-algorithms
RANGES_INLINE_VARIABLE(with_braced_init_args<find_end_fn>, find_end)
/// @}
} // namespace v3
} // namespace ranges
#endif // include guard