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

160 lines
6.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
//
//===----------------------------------------------------------------------===//
//
// 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 <meta/meta.hpp>
#include <range/v3/range_fwd.hpp>
#include <range/v3/begin_end.hpp>
#include <range/v3/empty.hpp>
#include <range/v3/distance.hpp>
#include <range/v3/range_concepts.hpp>
#include <range/v3/range_traits.hpp>
#include <range/v3/utility/iterator.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
{
/// ingroup group-concepts
template<typename I, typename V, typename C = equal_to, typename P = ident>
using Searchnable = meta::strict_and<
ForwardIterator<I>,
IndirectRelation<C, projected<I, P>, V const *>>;
/// \addtogroup group-algorithms
/// @{
struct search_n_fn
{
private:
template<typename I, typename S, typename D, typename V, typename C, typename P>
static I sized_impl(I const begin_, S end, D const d_, D count,
V const &val, C &pred, P &proj)
{
D d = d_; // always the distance from begin to end
auto begin = uncounted(begin_);
while(true)
{
// Find begin element in sequence 1 that matches val, with a mininum of loop checks
while(true)
{
if(d < count) // return the end if we've run out of room
return ranges::next(recounted(begin_, std::move(begin), d_ - d), std::move(end));
if(invoke(pred, invoke(proj, *begin), val))
break;
++begin;
--d;
}
// *begin matches val, now match elements after here
auto m = begin;
D c = 0;
while(true)
{
if(++c == count) // If pattern exhausted, begin is the answer (works for 1 element pattern)
return recounted(begin_, std::move(begin), 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
{
begin = next(std::move(m));
d -= (c+1);
break;
} // else there is a match, check next elements
}
}
}
template<typename I, typename S, typename D, typename V, typename C, typename P>
static I impl(I begin, S end, D count, V const &val, C &pred, P &proj)
{
while(true)
{
// Find begin element in sequence 1 that matches val, with a mininum of loop checks
while(true)
{
if(begin == end) // return end if no element matches val
return begin;
if(invoke(pred, invoke(proj, *begin), val))
break;
++begin;
}
// *begin matches val, now match elements after here
I m = begin;
D c = 0;
while(true)
{
if(++c == count) // If pattern exhausted, begin is the answer (works for 1 element pattern)
return begin;
if(++m == end) // Otherwise if source exhausted, pattern not found
return m;
if(!invoke(pred, invoke(proj, *m), val)) // if there is a mismatch, restart with a new begin
{
begin = next(std::move(m));
break;
} // else there is a match, check next elements
}
}
}
public:
template<typename I, typename S, typename V, typename C = equal_to, typename P = ident,
CONCEPT_REQUIRES_(Searchnable<I, V, C, P>() && Sentinel<S, I>())>
I operator()(I begin, S end, difference_type_t<I> count, V const &val,
C pred = C{}, P proj = P{}) const
{
if(count <= 0)
return begin;
if(SizedSentinel<S, I>())
return search_n_fn::sized_impl(std::move(begin), std::move(end),
distance(begin, end), count, val, pred, proj);
else
return search_n_fn::impl(std::move(begin), std::move(end), count, val, pred,
proj);
}
template<typename Rng, typename V, typename C = equal_to, typename P = ident,
typename I = iterator_t<Rng>,
CONCEPT_REQUIRES_(Searchnable<I, V, C, P>() && Range<Rng>())>
safe_iterator_t<Rng>
operator()(Rng &&rng, difference_type_t<I> count, V const &val, C pred = C{},
P proj = P{}) const
{
if(count <= 0)
return begin(rng);
if(SizedRange<Rng>())
return search_n_fn::sized_impl(begin(rng), end(rng), distance(rng), count, val,
pred, proj);
else
return search_n_fn::impl(begin(rng), end(rng), count, val, pred, proj);
}
};
/// \sa `search_n_fn`
/// \ingroup group-algorithms
RANGES_INLINE_VARIABLE(with_braced_init_args<search_n_fn>, search_n)
/// @}
} // namespace v3
} // namespace ranges
#endif // include guard