/// \file // Range v3 library // // Copyright Eric Niebler 2014-present // 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 #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \addtogroup group-algorithms /// @{ template using sample_result = detail::in_out_result; /// \cond namespace detail { template sample_result sample_sized_impl(I first, S last, iter_difference_t pop_size, O out, iter_difference_t sample_size, Gen && gen) { if(pop_size > 0 && sample_size > 0) { std::uniform_int_distribution> dist; using param_t = typename decltype(dist)::param_type; for(; first != last; ++first) { if(sample_size >= pop_size) return copy_n(std::move(first), pop_size, std::move(out)); if(dist(gen, param_t{0, --pop_size}) < sample_size) { *out = *first; ++out; if(--sample_size == 0) break; } } } return {std::move(first), std::move(out)}; } } // namespace detail /// \endcond RANGES_FUNC_BEGIN(sample) /// \brief function template \c sample template(typename I, typename S, typename O, typename Gen = detail::default_random_engine &)( requires input_iterator AND sentinel_for AND weakly_incrementable AND indirectly_copyable AND uniform_random_bit_generator> AND (random_access_iterator || forward_iterator || sized_sentinel_for)) sample_result RANGES_FUNC(sample)(I first, S last, O out, iter_difference_t const n, Gen && gen = detail::get_random_engine()) { if(RANGES_CONSTEXPR_IF(forward_iterator || sized_sentinel_for)) // { auto const k = distance(first, last); return detail::sample_sized_impl(std::move(first), std::move(last), k, std::move(out), n, static_cast(gen)); } else { // out is random-access here; calls to advance(out,n) and // next(out,n) are O(1). if(n > 0) { for(iter_difference_t i = 0; i < n; (void)++i, ++first) { if(first == last) { advance(out, i); goto done; } *next(out, i) = *first; } std::uniform_int_distribution> 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) *next(out, i) = *first; } advance(out, n); } done: return {std::move(first), std::move(out)}; } } /// \overload template(typename I, typename S, typename ORng, typename Gen = detail::default_random_engine &)( requires input_iterator AND sentinel_for AND weakly_incrementable> AND indirectly_copyable> AND uniform_random_bit_generator> AND (forward_range || sized_range) AND (random_access_iterator> || forward_iterator || sized_sentinel_for)) sample_result> RANGES_FUNC(sample)( I first, S last, ORng && out, Gen && gen = detail::get_random_engine()) // { if(RANGES_CONSTEXPR_IF(forward_iterator || sized_sentinel_for)) // { auto k = distance(first, last); return detail::sample_sized_impl(std::move(first), std::move(last), k, begin(out), distance(out), static_cast(gen)); } else { return (*this)(std::move(first), std::move(last), begin(out), distance(out), static_cast(gen)); } } /// \overload template(typename Rng, typename O, typename Gen = detail::default_random_engine &)( requires input_range AND weakly_incrementable AND indirectly_copyable, O> AND uniform_random_bit_generator> AND (random_access_iterator || forward_range || sized_range)) sample_result, O> RANGES_FUNC(sample)( Rng && rng, O out, iter_difference_t const n, Gen && gen = detail::get_random_engine()) // { if(RANGES_CONSTEXPR_IF(forward_range || sized_range)) // { return detail::sample_sized_impl(begin(rng), end(rng), distance(rng), std::move(out), n, static_cast(gen)); } else { return (*this)( begin(rng), end(rng), std::move(out), n, static_cast(gen)); } } /// \overload template(typename IRng, typename ORng, typename Gen = detail::default_random_engine &)( requires input_range AND range AND indirectly_copyable, iterator_t> AND uniform_random_bit_generator> AND (random_access_iterator> || forward_range || sized_range) AND (forward_range || sized_range)) sample_result, borrowed_iterator_t> // RANGES_FUNC(sample)(IRng && rng, ORng && out, Gen && gen = detail::get_random_engine()) { if(RANGES_CONSTEXPR_IF(forward_range || sized_range)) // { return detail::sample_sized_impl(begin(rng), end(rng), distance(rng), begin(out), distance(out), static_cast(gen)); } else { return (*this)(begin(rng), end(rng), begin(out), distance(out), static_cast(gen)); } } RANGES_FUNC_END(sample) namespace cpp20 { using ranges::sample_result; using ranges::sample; } /// @} } // namespace ranges #include #endif