sample.hpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2014-present
  5. // Copyright Casey Carter 2016
  6. //
  7. // Use, modification and distribution is subject to the
  8. // Boost Software License, Version 1.0. (See accompanying
  9. // file LICENSE_1_0.txt or copy at
  10. // http://www.boost.org/LICENSE_1_0.txt)
  11. //
  12. // Project home: https://github.com/ericniebler/range-v3
  13. //
  14. #ifndef RANGES_V3_ALGORITHM_SAMPLE_HPP
  15. #define RANGES_V3_ALGORITHM_SAMPLE_HPP
  16. #include <utility>
  17. #include <range/v3/range_fwd.hpp>
  18. #include <range/v3/algorithm/copy_n.hpp>
  19. #include <range/v3/iterator/concepts.hpp>
  20. #include <range/v3/iterator/operations.hpp>
  21. #include <range/v3/iterator/traits.hpp>
  22. #include <range/v3/range/access.hpp>
  23. #include <range/v3/range/concepts.hpp>
  24. #include <range/v3/range/dangling.hpp>
  25. #include <range/v3/range/traits.hpp>
  26. #include <range/v3/utility/random.hpp>
  27. #include <range/v3/utility/static_const.hpp>
  28. #include <range/v3/detail/prologue.hpp>
  29. namespace ranges
  30. {
  31. /// \addtogroup group-algorithms
  32. /// @{
  33. template<typename I, typename O>
  34. using sample_result = detail::in_out_result<I, O>;
  35. /// \cond
  36. namespace detail
  37. {
  38. template<typename I, typename S, typename O, typename Gen>
  39. sample_result<I, O> sample_sized_impl(I first,
  40. S last,
  41. iter_difference_t<I> pop_size,
  42. O out,
  43. iter_difference_t<O> sample_size,
  44. Gen && gen)
  45. {
  46. if(pop_size > 0 && sample_size > 0)
  47. {
  48. std::uniform_int_distribution<iter_difference_t<I>> dist;
  49. using param_t = typename decltype(dist)::param_type;
  50. for(; first != last; ++first)
  51. {
  52. if(sample_size >= pop_size)
  53. return copy_n(std::move(first), pop_size, std::move(out));
  54. if(dist(gen, param_t{0, --pop_size}) < sample_size)
  55. {
  56. *out = *first;
  57. ++out;
  58. if(--sample_size == 0)
  59. break;
  60. }
  61. }
  62. }
  63. return {std::move(first), std::move(out)};
  64. }
  65. } // namespace detail
  66. /// \endcond
  67. RANGES_FUNC_BEGIN(sample)
  68. /// \brief function template \c sample
  69. template(typename I,
  70. typename S,
  71. typename O,
  72. typename Gen = detail::default_random_engine &)(
  73. requires input_iterator<I> AND sentinel_for<S, I> AND
  74. weakly_incrementable<O> AND indirectly_copyable<I, O> AND
  75. uniform_random_bit_generator<std::remove_reference_t<Gen>> AND
  76. (random_access_iterator<O> || forward_iterator<I> ||
  77. sized_sentinel_for<S, I>))
  78. sample_result<I, O> RANGES_FUNC(sample)(I first,
  79. S last,
  80. O out,
  81. iter_difference_t<O> const n,
  82. Gen && gen = detail::get_random_engine())
  83. {
  84. if(RANGES_CONSTEXPR_IF(forward_iterator<I> || sized_sentinel_for<S, I>)) //
  85. {
  86. auto const k = distance(first, last);
  87. return detail::sample_sized_impl(std::move(first),
  88. std::move(last),
  89. k,
  90. std::move(out),
  91. n,
  92. static_cast<Gen &&>(gen));
  93. }
  94. else
  95. {
  96. // out is random-access here; calls to advance(out,n) and
  97. // next(out,n) are O(1).
  98. if(n > 0)
  99. {
  100. for(iter_difference_t<O> i = 0; i < n; (void)++i, ++first)
  101. {
  102. if(first == last)
  103. {
  104. advance(out, i);
  105. goto done;
  106. }
  107. *next(out, i) = *first;
  108. }
  109. std::uniform_int_distribution<iter_difference_t<O>> dist;
  110. using param_t = typename decltype(dist)::param_type;
  111. for(auto pop_size = n; first != last; (void)++first, ++pop_size)
  112. {
  113. auto const i = dist(gen, param_t{0, pop_size});
  114. if(i < n)
  115. *next(out, i) = *first;
  116. }
  117. advance(out, n);
  118. }
  119. done:
  120. return {std::move(first), std::move(out)};
  121. }
  122. }
  123. /// \overload
  124. template(typename I,
  125. typename S,
  126. typename ORng,
  127. typename Gen = detail::default_random_engine &)(
  128. requires input_iterator<I> AND sentinel_for<S, I> AND
  129. weakly_incrementable<iterator_t<ORng>> AND
  130. indirectly_copyable<I, iterator_t<ORng>> AND
  131. uniform_random_bit_generator<std::remove_reference_t<Gen>> AND
  132. (forward_range<ORng> || sized_range<ORng>) AND
  133. (random_access_iterator<iterator_t<ORng>> || forward_iterator<I> ||
  134. sized_sentinel_for<S, I>))
  135. sample_result<I, borrowed_iterator_t<ORng>> RANGES_FUNC(sample)(
  136. I first,
  137. S last,
  138. ORng && out,
  139. Gen && gen = detail::get_random_engine()) //
  140. {
  141. if(RANGES_CONSTEXPR_IF(forward_iterator<I> || sized_sentinel_for<S, I>)) //
  142. {
  143. auto k = distance(first, last);
  144. return detail::sample_sized_impl(std::move(first),
  145. std::move(last),
  146. k,
  147. begin(out),
  148. distance(out),
  149. static_cast<Gen &&>(gen));
  150. }
  151. else
  152. {
  153. return (*this)(std::move(first),
  154. std::move(last),
  155. begin(out),
  156. distance(out),
  157. static_cast<Gen &&>(gen));
  158. }
  159. }
  160. /// \overload
  161. template(typename Rng,
  162. typename O,
  163. typename Gen = detail::default_random_engine &)(
  164. requires input_range<Rng> AND weakly_incrementable<O> AND
  165. indirectly_copyable<iterator_t<Rng>, O> AND
  166. uniform_random_bit_generator<std::remove_reference_t<Gen>> AND
  167. (random_access_iterator<O> || forward_range<Rng> || sized_range<Rng>))
  168. sample_result<borrowed_iterator_t<Rng>, O> RANGES_FUNC(sample)(
  169. Rng && rng,
  170. O out,
  171. iter_difference_t<O> const n,
  172. Gen && gen = detail::get_random_engine()) //
  173. {
  174. if(RANGES_CONSTEXPR_IF(forward_range<Rng> || sized_range<Rng>)) //
  175. {
  176. return detail::sample_sized_impl(begin(rng),
  177. end(rng),
  178. distance(rng),
  179. std::move(out),
  180. n,
  181. static_cast<Gen &&>(gen));
  182. }
  183. else
  184. {
  185. return (*this)(
  186. begin(rng), end(rng), std::move(out), n, static_cast<Gen &&>(gen));
  187. }
  188. }
  189. /// \overload
  190. template(typename IRng,
  191. typename ORng,
  192. typename Gen = detail::default_random_engine &)(
  193. requires input_range<IRng> AND range<ORng> AND
  194. indirectly_copyable<iterator_t<IRng>, iterator_t<ORng>> AND
  195. uniform_random_bit_generator<std::remove_reference_t<Gen>> AND
  196. (random_access_iterator<iterator_t<ORng>> || forward_range<IRng> ||
  197. sized_range<IRng>) AND
  198. (forward_range<ORng> || sized_range<ORng>))
  199. sample_result<borrowed_iterator_t<IRng>, borrowed_iterator_t<ORng>> //
  200. RANGES_FUNC(sample)(IRng && rng,
  201. ORng && out,
  202. Gen && gen = detail::get_random_engine())
  203. {
  204. if(RANGES_CONSTEXPR_IF(forward_range<IRng> || sized_range<IRng>)) //
  205. {
  206. return detail::sample_sized_impl(begin(rng),
  207. end(rng),
  208. distance(rng),
  209. begin(out),
  210. distance(out),
  211. static_cast<Gen &&>(gen));
  212. }
  213. else
  214. {
  215. return (*this)(begin(rng),
  216. end(rng),
  217. begin(out),
  218. distance(out),
  219. static_cast<Gen &&>(gen));
  220. }
  221. }
  222. RANGES_FUNC_END(sample)
  223. namespace cpp20
  224. {
  225. using ranges::sample_result;
  226. using ranges::sample;
  227. }
  228. /// @}
  229. } // namespace ranges
  230. #include <range/v3/detail/epilogue.hpp>
  231. #endif