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