xref: /freebsd/contrib/llvm-project/libcxx/include/__algorithm/sample.h (revision a977168c48d45085cdf0c40f9b9bde3850b1f3ea)
1  //===----------------------------------------------------------------------===//
2  //
3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4  // See https://llvm.org/LICENSE.txt for license information.
5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6  //
7  //===----------------------------------------------------------------------===//
8  
9  #ifndef _LIBCPP___ALGORITHM_SAMPLE_H
10  #define _LIBCPP___ALGORITHM_SAMPLE_H
11  
12  #include <__algorithm/min.h>
13  #include <__config>
14  #include <__debug>
15  #include <__random/uniform_int_distribution.h>
16  #include <iterator>
17  
18  #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
19  #pragma GCC system_header
20  #endif
21  
22  _LIBCPP_PUSH_MACROS
23  #include <__undef_macros>
24  
25  _LIBCPP_BEGIN_NAMESPACE_STD
26  
27  template <class _PopulationIterator, class _SampleIterator, class _Distance,
28            class _UniformRandomNumberGenerator>
29  _LIBCPP_INLINE_VISIBILITY
30  _SampleIterator __sample(_PopulationIterator __first,
31                           _PopulationIterator __last, _SampleIterator __output_iter,
32                           _Distance __n,
33                           _UniformRandomNumberGenerator & __g,
34                           input_iterator_tag) {
35  
36    _Distance __k = 0;
37    for (; __first != __last && __k < __n; ++__first, (void) ++__k)
38      __output_iter[__k] = *__first;
39    _Distance __sz = __k;
40    for (; __first != __last; ++__first, (void) ++__k) {
41      _Distance __r = uniform_int_distribution<_Distance>(0, __k)(__g);
42      if (__r < __sz)
43        __output_iter[__r] = *__first;
44    }
45    return __output_iter + _VSTD::min(__n, __k);
46  }
47  
48  template <class _PopulationIterator, class _SampleIterator, class _Distance,
49            class _UniformRandomNumberGenerator>
50  _LIBCPP_INLINE_VISIBILITY
51  _SampleIterator __sample(_PopulationIterator __first,
52                           _PopulationIterator __last, _SampleIterator __output_iter,
53                           _Distance __n,
54                           _UniformRandomNumberGenerator& __g,
55                           forward_iterator_tag) {
56    _Distance __unsampled_sz = _VSTD::distance(__first, __last);
57    for (__n = _VSTD::min(__n, __unsampled_sz); __n != 0; ++__first) {
58      _Distance __r = uniform_int_distribution<_Distance>(0, --__unsampled_sz)(__g);
59      if (__r < __n) {
60        *__output_iter++ = *__first;
61        --__n;
62      }
63    }
64    return __output_iter;
65  }
66  
67  template <class _PopulationIterator, class _SampleIterator, class _Distance,
68            class _UniformRandomNumberGenerator>
69  _LIBCPP_INLINE_VISIBILITY
70  _SampleIterator __sample(_PopulationIterator __first,
71                           _PopulationIterator __last, _SampleIterator __output_iter,
72                           _Distance __n, _UniformRandomNumberGenerator& __g) {
73    typedef typename iterator_traits<_PopulationIterator>::iterator_category
74          _PopCategory;
75    typedef typename iterator_traits<_PopulationIterator>::difference_type
76          _Difference;
77    static_assert(__is_cpp17_forward_iterator<_PopulationIterator>::value ||
78                  __is_cpp17_random_access_iterator<_SampleIterator>::value,
79                  "SampleIterator must meet the requirements of RandomAccessIterator");
80    typedef typename common_type<_Distance, _Difference>::type _CommonType;
81    _LIBCPP_ASSERT(__n >= 0, "N must be a positive number.");
82    return _VSTD::__sample(
83        __first, __last, __output_iter, _CommonType(__n),
84        __g, _PopCategory());
85  }
86  
87  #if _LIBCPP_STD_VER > 14
88  template <class _PopulationIterator, class _SampleIterator, class _Distance,
89            class _UniformRandomNumberGenerator>
90  inline _LIBCPP_INLINE_VISIBILITY
91  _SampleIterator sample(_PopulationIterator __first,
92                         _PopulationIterator __last, _SampleIterator __output_iter,
93                         _Distance __n, _UniformRandomNumberGenerator&& __g) {
94      return _VSTD::__sample(__first, __last, __output_iter, __n, __g);
95  }
96  #endif // _LIBCPP_STD_VER > 14
97  
98  _LIBCPP_END_NAMESPACE_STD
99  
100  _LIBCPP_POP_MACROS
101  
102  #endif // _LIBCPP___ALGORITHM_SAMPLE_H
103