1134723edSLouis Dionne //===----------------------------------------------------------------------===//
2134723edSLouis Dionne //
3134723edSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4134723edSLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
5134723edSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6134723edSLouis Dionne //
7134723edSLouis Dionne //===----------------------------------------------------------------------===//
8134723edSLouis Dionne 
9134723edSLouis Dionne #ifndef _LIBCPP___ALGORITHM_SAMPLE_H
10134723edSLouis Dionne #define _LIBCPP___ALGORITHM_SAMPLE_H
11134723edSLouis Dionne 
12*732cb123SKonstantin Varlamov #include <__algorithm/iterator_operations.h>
13134723edSLouis Dionne #include <__algorithm/min.h>
14f87aa19bSLouis Dionne #include <__assert>
15f221d905SArthur O'Dwyer #include <__config>
163cd4531bSNikolas Klauser #include <__iterator/distance.h>
173cd4531bSNikolas Klauser #include <__iterator/iterator_traits.h>
18134723edSLouis Dionne #include <__random/uniform_int_distribution.h>
19*732cb123SKonstantin Varlamov #include <__utility/move.h>
203cd4531bSNikolas Klauser #include <type_traits>
21134723edSLouis Dionne 
22134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23134723edSLouis Dionne #  pragma GCC system_header
24134723edSLouis Dionne #endif
25134723edSLouis Dionne 
26134723edSLouis Dionne _LIBCPP_PUSH_MACROS
27134723edSLouis Dionne #include <__undef_macros>
28134723edSLouis Dionne 
29134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD
30134723edSLouis Dionne 
31*732cb123SKonstantin Varlamov template <class _AlgPolicy,
32*732cb123SKonstantin Varlamov           class _PopulationIterator, class _PopulationSentinel, class _SampleIterator, class _Distance,
33134723edSLouis Dionne           class _UniformRandomNumberGenerator>
34134723edSLouis Dionne _LIBCPP_INLINE_VISIBILITY
__sample(_PopulationIterator __first,_PopulationSentinel __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator & __g,input_iterator_tag)35134723edSLouis Dionne _SampleIterator __sample(_PopulationIterator __first,
36*732cb123SKonstantin Varlamov                          _PopulationSentinel __last, _SampleIterator __output_iter,
37134723edSLouis Dionne                          _Distance __n,
38134723edSLouis Dionne                          _UniformRandomNumberGenerator& __g,
39134723edSLouis Dionne                          input_iterator_tag) {
40134723edSLouis Dionne 
41134723edSLouis Dionne   _Distance __k = 0;
42134723edSLouis Dionne   for (; __first != __last && __k < __n; ++__first, (void) ++__k)
43134723edSLouis Dionne     __output_iter[__k] = *__first;
44134723edSLouis Dionne   _Distance __sz = __k;
45134723edSLouis Dionne   for (; __first != __last; ++__first, (void) ++__k) {
46134723edSLouis Dionne     _Distance __r = uniform_int_distribution<_Distance>(0, __k)(__g);
47134723edSLouis Dionne     if (__r < __sz)
48134723edSLouis Dionne       __output_iter[__r] = *__first;
49134723edSLouis Dionne   }
50134723edSLouis Dionne   return __output_iter + _VSTD::min(__n, __k);
51134723edSLouis Dionne }
52134723edSLouis Dionne 
53*732cb123SKonstantin Varlamov template <class _AlgPolicy,
54*732cb123SKonstantin Varlamov           class _PopulationIterator, class _PopulationSentinel, class _SampleIterator, class _Distance,
55134723edSLouis Dionne           class _UniformRandomNumberGenerator>
56134723edSLouis Dionne _LIBCPP_INLINE_VISIBILITY
__sample(_PopulationIterator __first,_PopulationSentinel __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator & __g,forward_iterator_tag)57134723edSLouis Dionne _SampleIterator __sample(_PopulationIterator __first,
58*732cb123SKonstantin Varlamov                          _PopulationSentinel __last, _SampleIterator __output_iter,
59134723edSLouis Dionne                          _Distance __n,
60134723edSLouis Dionne                          _UniformRandomNumberGenerator& __g,
61134723edSLouis Dionne                          forward_iterator_tag) {
62*732cb123SKonstantin Varlamov   _Distance __unsampled_sz = _IterOps<_AlgPolicy>::distance(__first, __last);
63134723edSLouis Dionne   for (__n = _VSTD::min(__n, __unsampled_sz); __n != 0; ++__first) {
64134723edSLouis Dionne     _Distance __r = uniform_int_distribution<_Distance>(0, --__unsampled_sz)(__g);
65134723edSLouis Dionne     if (__r < __n) {
66134723edSLouis Dionne       *__output_iter++ = *__first;
67134723edSLouis Dionne       --__n;
68134723edSLouis Dionne     }
69134723edSLouis Dionne   }
70134723edSLouis Dionne   return __output_iter;
71134723edSLouis Dionne }
72134723edSLouis Dionne 
73*732cb123SKonstantin Varlamov template <class _AlgPolicy,
74*732cb123SKonstantin Varlamov           class _PopulationIterator, class _PopulationSentinel, class _SampleIterator, class _Distance,
75134723edSLouis Dionne           class _UniformRandomNumberGenerator>
76134723edSLouis Dionne _LIBCPP_INLINE_VISIBILITY
__sample(_PopulationIterator __first,_PopulationSentinel __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator & __g)77134723edSLouis Dionne _SampleIterator __sample(_PopulationIterator __first,
78*732cb123SKonstantin Varlamov                          _PopulationSentinel __last, _SampleIterator __output_iter,
79134723edSLouis Dionne                          _Distance __n, _UniformRandomNumberGenerator& __g) {
80134723edSLouis Dionne   _LIBCPP_ASSERT(__n >= 0, "N must be a positive number.");
81*732cb123SKonstantin Varlamov 
82*732cb123SKonstantin Varlamov   using _PopIterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_PopulationIterator>;
83*732cb123SKonstantin Varlamov   using _Difference = typename _IterOps<_AlgPolicy>::template __difference_type<_PopulationIterator>;
84*732cb123SKonstantin Varlamov   using _CommonType = typename common_type<_Distance, _Difference>::type;
85*732cb123SKonstantin Varlamov 
86*732cb123SKonstantin Varlamov   return std::__sample<_AlgPolicy>(
87*732cb123SKonstantin Varlamov       std::move(__first), std::move(__last), std::move(__output_iter), _CommonType(__n),
88*732cb123SKonstantin Varlamov       __g, _PopIterCategory());
89134723edSLouis Dionne }
90134723edSLouis Dionne 
91134723edSLouis Dionne #if _LIBCPP_STD_VER > 14
92134723edSLouis Dionne template <class _PopulationIterator, class _SampleIterator, class _Distance,
93134723edSLouis Dionne           class _UniformRandomNumberGenerator>
94134723edSLouis Dionne inline _LIBCPP_INLINE_VISIBILITY
sample(_PopulationIterator __first,_PopulationIterator __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator && __g)95134723edSLouis Dionne _SampleIterator sample(_PopulationIterator __first,
96134723edSLouis Dionne                        _PopulationIterator __last, _SampleIterator __output_iter,
97134723edSLouis Dionne                        _Distance __n, _UniformRandomNumberGenerator&& __g) {
98*732cb123SKonstantin Varlamov   static_assert(__is_cpp17_forward_iterator<_PopulationIterator>::value ||
99*732cb123SKonstantin Varlamov                 __is_cpp17_random_access_iterator<_SampleIterator>::value,
100*732cb123SKonstantin Varlamov                 "SampleIterator must meet the requirements of RandomAccessIterator");
101*732cb123SKonstantin Varlamov 
102*732cb123SKonstantin Varlamov   return std::__sample<_ClassicAlgPolicy>(
103*732cb123SKonstantin Varlamov       std::move(__first), std::move(__last), std::move(__output_iter), __n, __g);
104134723edSLouis Dionne }
105*732cb123SKonstantin Varlamov 
106134723edSLouis Dionne #endif // _LIBCPP_STD_VER > 14
107134723edSLouis Dionne 
108134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD
109134723edSLouis Dionne 
110134723edSLouis Dionne _LIBCPP_POP_MACROS
111134723edSLouis Dionne 
112134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_SAMPLE_H
113