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

210 lines
9.1 KiB
C++

/// \file
// Range v3 library
//
// Copyright Eric Niebler 2014
// Copyright Casey Carter 2016
//
// 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_SAMPLE_HPP
#define RANGES_V3_ALGORITHM_SAMPLE_HPP
#include <utility>
#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/distance.hpp>
#include <range/v3/algorithm/min.hpp>
#include <range/v3/utility/random.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/static_const.hpp>
#include <range/v3/utility/tagged_pair.hpp>
RANGES_DISABLE_WARNINGS
namespace ranges
{
inline namespace v3
{
/// \addtogroup group-algorithms
/// @{
class sample_fn
{
template<typename I, typename S, typename O, typename Gen>
using Constraint = meta::strict_and<
InputIterator<I>, Sentinel<S, I>, WeaklyIncrementable<O>,
IndirectlyCopyable<I, O>, UniformRandomNumberGenerator<Gen>,
ConvertibleTo<concepts::UniformRandomNumberGenerator::result_t<Gen>,
difference_type_t<I>>>;
template<typename I, typename S, typename O,
typename Gen = detail::default_random_engine&,
CONCEPT_REQUIRES_(Constraint<I, S, O, Gen>())>
static tagged_pair<tag::in(I), tag::out(O)>
sized_impl(I first, S last, difference_type_t<I> pop_size,
O out, difference_type_t<I> n, Gen && gen)
{
std::uniform_int_distribution<difference_type_t<I>> dist;
using param_t = typename decltype(dist)::param_type;
n = ranges::min(pop_size, n);
for (; n > 0 && first != last; ++first)
{
if (dist(gen, param_t{0, --pop_size}) < n)
{
--n;
*out = *first;
++out;
}
}
return {std::move(first), std::move(out)};
}
public:
template<typename I, typename S, typename O,
typename Gen = detail::default_random_engine&,
CONCEPT_REQUIRES_(
(ForwardIterator<I>() || SizedSentinel<S, I>()) &&
Constraint<I, S, O, Gen>())>
tagged_pair<tag::in(I), tag::out(O)>
operator()(I first, S last, O out, difference_type_t<I> n,
Gen && gen = detail::get_random_engine()) const
{
auto k = distance(first, last);
return sample_fn::sized_impl(std::move(first), std::move(last),
k, std::move(out), n, std::forward<Gen>(gen));
}
template<typename I, typename S, typename O,
typename Gen = detail::default_random_engine&,
CONCEPT_REQUIRES_(RandomAccessIterator<O>() &&
!(ForwardIterator<I>() || SizedSentinel<S, I>()) &&
Constraint<I, S, O, Gen>())>
tagged_pair<tag::in(I), tag::out(O)>
operator()(I first, S last, O out, difference_type_t<I> n,
Gen && gen = detail::get_random_engine()) const
{
if (n <= 0)
goto done;
for (difference_type_t<I> i = 0; i < n; (void)++i, ++first)
{
if (first == last)
{
out += i;
goto done;
}
out[i] = *first;
}
std::uniform_int_distribution<difference_type_t<I>> dist;
using param_t = typename decltype(dist)::param_type;
for (auto pop_size = n; first != last; (void)++first, ++pop_size)
{
auto const i = dist(gen, param_t{0, pop_size});
if (i < n)
out[i] = *first;
}
out += n;
done:
return {std::move(first), std::move(out)};
}
template<typename I, typename S, typename ORng,
typename Gen = detail::default_random_engine&,
CONCEPT_REQUIRES_(
(ForwardIterator<I>() || SizedSentinel<S, I>()) &&
(ForwardRange<ORng>() || SizedRange<ORng>()) &&
Constraint<I, S, iterator_t<ORng>, Gen>())>
tagged_pair<tag::in(I), tag::out(safe_iterator_t<ORng>)>
operator()(I first, S last, ORng && out,
Gen && gen = detail::get_random_engine()) const
{
auto k = distance(first, last);
return sample_fn::sized_impl(std::move(first), std::move(last),
k, begin(out), distance(out), std::forward<Gen>(gen));
}
template<typename I, typename S, typename ORng,
typename Gen = detail::default_random_engine&,
CONCEPT_REQUIRES_(RandomAccessIterator<iterator_t<ORng>>() &&
!(ForwardIterator<I>() || SizedSentinel<S, I>()) &&
(ForwardRange<ORng>() || SizedRange<ORng>()) &&
Constraint<I, S, iterator_t<ORng>, Gen>())>
tagged_pair<tag::in(I), tag::out(safe_iterator_t<ORng>)>
operator()(I first, S last, ORng && out,
Gen && gen = detail::get_random_engine()) const
{
return (*this)(std::move(first), std::move(last), begin(out),
distance(out), std::forward<Gen>(gen));
}
template<typename Rng, typename O,
typename Gen = detail::default_random_engine&,
CONCEPT_REQUIRES_(RandomAccessIterator<O>() &&
!(ForwardRange<Rng>() || SizedRange<Rng>()) &&
Constraint<iterator_t<Rng>, sentinel_t<Rng>, O, Gen>())>
tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
operator()(Rng && rng, O out, range_difference_type_t<Rng> n,
Gen && gen = detail::get_random_engine()) const
{
return (*this)(begin(rng), end(rng),
std::move(out), n, std::forward<Gen>(gen));
}
template<typename Rng, typename O,
typename Gen = detail::default_random_engine&,
CONCEPT_REQUIRES_(
(ForwardRange<Rng>() || SizedRange<Rng>()) &&
Constraint<iterator_t<Rng>, sentinel_t<Rng>, O, Gen>())>
tagged_pair<tag::in(safe_iterator_t<Rng>), tag::out(O)>
operator()(Rng && rng, O out, range_difference_type_t<Rng> n,
Gen && gen = detail::get_random_engine()) const
{
return sample_fn::sized_impl(begin(rng), end(rng), distance(rng),
std::move(out), n, std::forward<Gen>(gen));
}
template<typename IRng, typename ORng,
typename Gen = detail::default_random_engine&,
CONCEPT_REQUIRES_(RandomAccessIterator<iterator_t<ORng>>() &&
!(ForwardRange<IRng>() || SizedRange<IRng>()) &&
(ForwardRange<ORng>() || SizedRange<ORng>()) &&
Constraint<iterator_t<IRng>, sentinel_t<IRng>,
iterator_t<ORng>, Gen>())>
tagged_pair<
tag::in(safe_iterator_t<IRng>),
tag::out(safe_iterator_t<ORng>)>
operator()(IRng && rng, ORng && out,
Gen && gen = detail::get_random_engine()) const
{
return (*this)(begin(rng), end(rng),
begin(out), distance(out), std::forward<Gen>(gen));
}
template<typename IRng, typename ORng,
typename Gen = detail::default_random_engine&,
CONCEPT_REQUIRES_(
(ForwardRange<IRng>() || SizedRange<IRng>()) &&
(ForwardRange<ORng>() || SizedRange<ORng>()) &&
Constraint<iterator_t<IRng>, sentinel_t<IRng>,
iterator_t<ORng>, Gen>())>
tagged_pair<
tag::in(safe_iterator_t<IRng>),
tag::out(safe_iterator_t<ORng>)>
operator()(IRng && rng, ORng && out,
Gen && gen = detail::get_random_engine()) const
{
return sample_fn::sized_impl(begin(rng), end(rng), distance(rng),
begin(out), distance(out), std::forward<Gen>(gen));
}
};
/// \sa `sample_fn`
/// \ingroup group-algorithms
RANGES_INLINE_VARIABLE(with_braced_init_args<sample_fn>, sample)
/// @}
} // namespace v3
} // namespace ranges
RANGES_RE_ENABLE_WARNINGS
#endif