xref: /freebsd/contrib/llvm-project/libcxx/include/__algorithm/sample.h (revision cb14a3fe5122c879eae1fb480ed7ce82a699ddb6)
1fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
2fe6060f1SDimitry Andric //
3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fe6060f1SDimitry Andric //
7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8fe6060f1SDimitry Andric 
9fe6060f1SDimitry Andric #ifndef _LIBCPP___ALGORITHM_SAMPLE_H
10fe6060f1SDimitry Andric #define _LIBCPP___ALGORITHM_SAMPLE_H
11fe6060f1SDimitry Andric 
1261cfbce3SDimitry Andric #include <__algorithm/iterator_operations.h>
13fe6060f1SDimitry Andric #include <__algorithm/min.h>
1481ad6265SDimitry Andric #include <__assert>
15349cc55cSDimitry Andric #include <__config>
1681ad6265SDimitry Andric #include <__iterator/distance.h>
1781ad6265SDimitry Andric #include <__iterator/iterator_traits.h>
18fe6060f1SDimitry Andric #include <__random/uniform_int_distribution.h>
1906c3fb27SDimitry Andric #include <__type_traits/common_type.h>
2061cfbce3SDimitry Andric #include <__utility/move.h>
21fe6060f1SDimitry Andric 
22fe6060f1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23fe6060f1SDimitry Andric #  pragma GCC system_header
24fe6060f1SDimitry Andric #endif
25fe6060f1SDimitry Andric 
26fe6060f1SDimitry Andric _LIBCPP_PUSH_MACROS
27fe6060f1SDimitry Andric #include <__undef_macros>
28fe6060f1SDimitry Andric 
29fe6060f1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
30fe6060f1SDimitry Andric 
3161cfbce3SDimitry Andric template <class _AlgPolicy,
32*cb14a3feSDimitry Andric           class _PopulationIterator,
33*cb14a3feSDimitry Andric           class _PopulationSentinel,
34*cb14a3feSDimitry Andric           class _SampleIterator,
35*cb14a3feSDimitry Andric           class _Distance,
36fe6060f1SDimitry Andric           class _UniformRandomNumberGenerator>
37*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _SampleIterator __sample(
38*cb14a3feSDimitry Andric     _PopulationIterator __first,
39*cb14a3feSDimitry Andric     _PopulationSentinel __last,
40*cb14a3feSDimitry Andric     _SampleIterator __output_iter,
41fe6060f1SDimitry Andric     _Distance __n,
42fe6060f1SDimitry Andric     _UniformRandomNumberGenerator& __g,
43fe6060f1SDimitry Andric     input_iterator_tag) {
44fe6060f1SDimitry Andric   _Distance __k = 0;
45fe6060f1SDimitry Andric   for (; __first != __last && __k < __n; ++__first, (void)++__k)
46fe6060f1SDimitry Andric     __output_iter[__k] = *__first;
47fe6060f1SDimitry Andric   _Distance __sz = __k;
48fe6060f1SDimitry Andric   for (; __first != __last; ++__first, (void)++__k) {
49fe6060f1SDimitry Andric     _Distance __r = uniform_int_distribution<_Distance>(0, __k)(__g);
50fe6060f1SDimitry Andric     if (__r < __sz)
51fe6060f1SDimitry Andric       __output_iter[__r] = *__first;
52fe6060f1SDimitry Andric   }
535f757f3fSDimitry Andric   return __output_iter + std::min(__n, __k);
54fe6060f1SDimitry Andric }
55fe6060f1SDimitry Andric 
5661cfbce3SDimitry Andric template <class _AlgPolicy,
57*cb14a3feSDimitry Andric           class _PopulationIterator,
58*cb14a3feSDimitry Andric           class _PopulationSentinel,
59*cb14a3feSDimitry Andric           class _SampleIterator,
60*cb14a3feSDimitry Andric           class _Distance,
61fe6060f1SDimitry Andric           class _UniformRandomNumberGenerator>
62*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _SampleIterator __sample(
63*cb14a3feSDimitry Andric     _PopulationIterator __first,
64*cb14a3feSDimitry Andric     _PopulationSentinel __last,
65*cb14a3feSDimitry Andric     _SampleIterator __output_iter,
66fe6060f1SDimitry Andric     _Distance __n,
67fe6060f1SDimitry Andric     _UniformRandomNumberGenerator& __g,
68fe6060f1SDimitry Andric     forward_iterator_tag) {
6961cfbce3SDimitry Andric   _Distance __unsampled_sz = _IterOps<_AlgPolicy>::distance(__first, __last);
705f757f3fSDimitry Andric   for (__n = std::min(__n, __unsampled_sz); __n != 0; ++__first) {
71fe6060f1SDimitry Andric     _Distance __r = uniform_int_distribution<_Distance>(0, --__unsampled_sz)(__g);
72fe6060f1SDimitry Andric     if (__r < __n) {
73fe6060f1SDimitry Andric       *__output_iter++ = *__first;
74fe6060f1SDimitry Andric       --__n;
75fe6060f1SDimitry Andric     }
76fe6060f1SDimitry Andric   }
77fe6060f1SDimitry Andric   return __output_iter;
78fe6060f1SDimitry Andric }
79fe6060f1SDimitry Andric 
8061cfbce3SDimitry Andric template <class _AlgPolicy,
81*cb14a3feSDimitry Andric           class _PopulationIterator,
82*cb14a3feSDimitry Andric           class _PopulationSentinel,
83*cb14a3feSDimitry Andric           class _SampleIterator,
84*cb14a3feSDimitry Andric           class _Distance,
85fe6060f1SDimitry Andric           class _UniformRandomNumberGenerator>
86*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _SampleIterator __sample(
87*cb14a3feSDimitry Andric     _PopulationIterator __first,
88*cb14a3feSDimitry Andric     _PopulationSentinel __last,
89*cb14a3feSDimitry Andric     _SampleIterator __output_iter,
90*cb14a3feSDimitry Andric     _Distance __n,
91*cb14a3feSDimitry Andric     _UniformRandomNumberGenerator& __g) {
92*cb14a3feSDimitry Andric   _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n >= 0, "N must be a positive number.");
9361cfbce3SDimitry Andric 
9461cfbce3SDimitry Andric   using _PopIterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_PopulationIterator>;
9561cfbce3SDimitry Andric   using _Difference      = typename _IterOps<_AlgPolicy>::template __difference_type<_PopulationIterator>;
9661cfbce3SDimitry Andric   using _CommonType      = typename common_type<_Distance, _Difference>::type;
9761cfbce3SDimitry Andric 
9861cfbce3SDimitry Andric   return std::__sample<_AlgPolicy>(
99*cb14a3feSDimitry Andric       std::move(__first), std::move(__last), std::move(__output_iter), _CommonType(__n), __g, _PopIterCategory());
100fe6060f1SDimitry Andric }
101fe6060f1SDimitry Andric 
10206c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 17
103*cb14a3feSDimitry Andric template <class _PopulationIterator, class _SampleIterator, class _Distance, class _UniformRandomNumberGenerator>
104*cb14a3feSDimitry Andric inline _LIBCPP_HIDE_FROM_ABI _SampleIterator
105*cb14a3feSDimitry Andric sample(_PopulationIterator __first,
106*cb14a3feSDimitry Andric        _PopulationIterator __last,
107*cb14a3feSDimitry Andric        _SampleIterator __output_iter,
108*cb14a3feSDimitry Andric        _Distance __n,
109*cb14a3feSDimitry Andric        _UniformRandomNumberGenerator&& __g) {
11006c3fb27SDimitry Andric   static_assert(__has_forward_iterator_category<_PopulationIterator>::value ||
11106c3fb27SDimitry Andric                     __has_random_access_iterator_category<_SampleIterator>::value,
11261cfbce3SDimitry Andric                 "SampleIterator must meet the requirements of RandomAccessIterator");
11361cfbce3SDimitry Andric 
114*cb14a3feSDimitry Andric   return std::__sample<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__output_iter), __n, __g);
115fe6060f1SDimitry Andric }
11661cfbce3SDimitry Andric 
11706c3fb27SDimitry Andric #endif // _LIBCPP_STD_VER >= 17
118fe6060f1SDimitry Andric 
119fe6060f1SDimitry Andric _LIBCPP_END_NAMESPACE_STD
120fe6060f1SDimitry Andric 
121fe6060f1SDimitry Andric _LIBCPP_POP_MACROS
122fe6060f1SDimitry Andric 
123fe6060f1SDimitry Andric #endif // _LIBCPP___ALGORITHM_SAMPLE_H
124