xref: /openbsd-src/gnu/llvm/libcxx/include/__algorithm/sample.h (revision 4bdff4bed0e3d54e55670334c7d0077db4170f86)
176d0caaeSpatrick //===----------------------------------------------------------------------===//
276d0caaeSpatrick //
376d0caaeSpatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
476d0caaeSpatrick // See https://llvm.org/LICENSE.txt for license information.
576d0caaeSpatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
676d0caaeSpatrick //
776d0caaeSpatrick //===----------------------------------------------------------------------===//
876d0caaeSpatrick 
976d0caaeSpatrick #ifndef _LIBCPP___ALGORITHM_SAMPLE_H
1076d0caaeSpatrick #define _LIBCPP___ALGORITHM_SAMPLE_H
1176d0caaeSpatrick 
12*4bdff4beSrobert #include <__algorithm/iterator_operations.h>
1376d0caaeSpatrick #include <__algorithm/min.h>
14*4bdff4beSrobert #include <__assert>
15*4bdff4beSrobert #include <__config>
16*4bdff4beSrobert #include <__iterator/distance.h>
17*4bdff4beSrobert #include <__iterator/iterator_traits.h>
1876d0caaeSpatrick #include <__random/uniform_int_distribution.h>
19*4bdff4beSrobert #include <__utility/move.h>
20*4bdff4beSrobert #include <type_traits>
2176d0caaeSpatrick 
2276d0caaeSpatrick #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
2376d0caaeSpatrick #  pragma GCC system_header
2476d0caaeSpatrick #endif
2576d0caaeSpatrick 
2676d0caaeSpatrick _LIBCPP_PUSH_MACROS
2776d0caaeSpatrick #include <__undef_macros>
2876d0caaeSpatrick 
2976d0caaeSpatrick _LIBCPP_BEGIN_NAMESPACE_STD
3076d0caaeSpatrick 
31*4bdff4beSrobert template <class _AlgPolicy,
32*4bdff4beSrobert           class _PopulationIterator, class _PopulationSentinel, class _SampleIterator, class _Distance,
3376d0caaeSpatrick           class _UniformRandomNumberGenerator>
3476d0caaeSpatrick _LIBCPP_INLINE_VISIBILITY
__sample(_PopulationIterator __first,_PopulationSentinel __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator & __g,input_iterator_tag)3576d0caaeSpatrick _SampleIterator __sample(_PopulationIterator __first,
36*4bdff4beSrobert                          _PopulationSentinel __last, _SampleIterator __output_iter,
3776d0caaeSpatrick                          _Distance __n,
3876d0caaeSpatrick                          _UniformRandomNumberGenerator& __g,
3976d0caaeSpatrick                          input_iterator_tag) {
4076d0caaeSpatrick 
4176d0caaeSpatrick   _Distance __k = 0;
4276d0caaeSpatrick   for (; __first != __last && __k < __n; ++__first, (void) ++__k)
4376d0caaeSpatrick     __output_iter[__k] = *__first;
4476d0caaeSpatrick   _Distance __sz = __k;
4576d0caaeSpatrick   for (; __first != __last; ++__first, (void) ++__k) {
4676d0caaeSpatrick     _Distance __r = uniform_int_distribution<_Distance>(0, __k)(__g);
4776d0caaeSpatrick     if (__r < __sz)
4876d0caaeSpatrick       __output_iter[__r] = *__first;
4976d0caaeSpatrick   }
5076d0caaeSpatrick   return __output_iter + _VSTD::min(__n, __k);
5176d0caaeSpatrick }
5276d0caaeSpatrick 
53*4bdff4beSrobert template <class _AlgPolicy,
54*4bdff4beSrobert           class _PopulationIterator, class _PopulationSentinel, class _SampleIterator, class _Distance,
5576d0caaeSpatrick           class _UniformRandomNumberGenerator>
5676d0caaeSpatrick _LIBCPP_INLINE_VISIBILITY
__sample(_PopulationIterator __first,_PopulationSentinel __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator & __g,forward_iterator_tag)5776d0caaeSpatrick _SampleIterator __sample(_PopulationIterator __first,
58*4bdff4beSrobert                          _PopulationSentinel __last, _SampleIterator __output_iter,
5976d0caaeSpatrick                          _Distance __n,
6076d0caaeSpatrick                          _UniformRandomNumberGenerator& __g,
6176d0caaeSpatrick                          forward_iterator_tag) {
62*4bdff4beSrobert   _Distance __unsampled_sz = _IterOps<_AlgPolicy>::distance(__first, __last);
6376d0caaeSpatrick   for (__n = _VSTD::min(__n, __unsampled_sz); __n != 0; ++__first) {
6476d0caaeSpatrick     _Distance __r = uniform_int_distribution<_Distance>(0, --__unsampled_sz)(__g);
6576d0caaeSpatrick     if (__r < __n) {
6676d0caaeSpatrick       *__output_iter++ = *__first;
6776d0caaeSpatrick       --__n;
6876d0caaeSpatrick     }
6976d0caaeSpatrick   }
7076d0caaeSpatrick   return __output_iter;
7176d0caaeSpatrick }
7276d0caaeSpatrick 
73*4bdff4beSrobert template <class _AlgPolicy,
74*4bdff4beSrobert           class _PopulationIterator, class _PopulationSentinel, class _SampleIterator, class _Distance,
7576d0caaeSpatrick           class _UniformRandomNumberGenerator>
7676d0caaeSpatrick _LIBCPP_INLINE_VISIBILITY
__sample(_PopulationIterator __first,_PopulationSentinel __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator & __g)7776d0caaeSpatrick _SampleIterator __sample(_PopulationIterator __first,
78*4bdff4beSrobert                          _PopulationSentinel __last, _SampleIterator __output_iter,
7976d0caaeSpatrick                          _Distance __n, _UniformRandomNumberGenerator& __g) {
8076d0caaeSpatrick   _LIBCPP_ASSERT(__n >= 0, "N must be a positive number.");
81*4bdff4beSrobert 
82*4bdff4beSrobert   using _PopIterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_PopulationIterator>;
83*4bdff4beSrobert   using _Difference = typename _IterOps<_AlgPolicy>::template __difference_type<_PopulationIterator>;
84*4bdff4beSrobert   using _CommonType = typename common_type<_Distance, _Difference>::type;
85*4bdff4beSrobert 
86*4bdff4beSrobert   return std::__sample<_AlgPolicy>(
87*4bdff4beSrobert       std::move(__first), std::move(__last), std::move(__output_iter), _CommonType(__n),
88*4bdff4beSrobert       __g, _PopIterCategory());
8976d0caaeSpatrick }
9076d0caaeSpatrick 
9176d0caaeSpatrick #if _LIBCPP_STD_VER > 14
9276d0caaeSpatrick template <class _PopulationIterator, class _SampleIterator, class _Distance,
9376d0caaeSpatrick           class _UniformRandomNumberGenerator>
9476d0caaeSpatrick inline _LIBCPP_INLINE_VISIBILITY
sample(_PopulationIterator __first,_PopulationIterator __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator && __g)9576d0caaeSpatrick _SampleIterator sample(_PopulationIterator __first,
9676d0caaeSpatrick                        _PopulationIterator __last, _SampleIterator __output_iter,
9776d0caaeSpatrick                        _Distance __n, _UniformRandomNumberGenerator&& __g) {
98*4bdff4beSrobert   static_assert(__is_cpp17_forward_iterator<_PopulationIterator>::value ||
99*4bdff4beSrobert                 __is_cpp17_random_access_iterator<_SampleIterator>::value,
100*4bdff4beSrobert                 "SampleIterator must meet the requirements of RandomAccessIterator");
101*4bdff4beSrobert 
102*4bdff4beSrobert   return std::__sample<_ClassicAlgPolicy>(
103*4bdff4beSrobert       std::move(__first), std::move(__last), std::move(__output_iter), __n, __g);
10476d0caaeSpatrick }
105*4bdff4beSrobert 
10676d0caaeSpatrick #endif // _LIBCPP_STD_VER > 14
10776d0caaeSpatrick 
10876d0caaeSpatrick _LIBCPP_END_NAMESPACE_STD
10976d0caaeSpatrick 
11076d0caaeSpatrick _LIBCPP_POP_MACROS
11176d0caaeSpatrick 
11276d0caaeSpatrick #endif // _LIBCPP___ALGORITHM_SAMPLE_H
113