xref: /llvm-project/libcxx/include/__algorithm/sample.h (revision 1638657dce0ca03c7d5cd9dfc23bf31485b4ac43)
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 
126bdb6422SKonstantin 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>
19e698c595SNikolas Klauser #include <__type_traits/common_type.h>
206bdb6422SKonstantin Varlamov #include <__utility/move.h>
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 
316bdb6422SKonstantin Varlamov template <class _AlgPolicy,
329783f28cSLouis Dionne           class _PopulationIterator,
339783f28cSLouis Dionne           class _PopulationSentinel,
349783f28cSLouis Dionne           class _SampleIterator,
359783f28cSLouis Dionne           class _Distance,
36134723edSLouis Dionne           class _UniformRandomNumberGenerator>
__sample(_PopulationIterator __first,_PopulationSentinel __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator & __g,input_iterator_tag)379783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _SampleIterator __sample(
389783f28cSLouis Dionne     _PopulationIterator __first,
399783f28cSLouis Dionne     _PopulationSentinel __last,
409783f28cSLouis Dionne     _SampleIterator __output_iter,
41134723edSLouis Dionne     _Distance __n,
42134723edSLouis Dionne     _UniformRandomNumberGenerator& __g,
43134723edSLouis Dionne     input_iterator_tag) {
44134723edSLouis Dionne   _Distance __k = 0;
45134723edSLouis Dionne   for (; __first != __last && __k < __n; ++__first, (void)++__k)
46134723edSLouis Dionne     __output_iter[__k] = *__first;
47134723edSLouis Dionne   _Distance __sz = __k;
48134723edSLouis Dionne   for (; __first != __last; ++__first, (void)++__k) {
49134723edSLouis Dionne     _Distance __r = uniform_int_distribution<_Distance>(0, __k)(__g);
50134723edSLouis Dionne     if (__r < __sz)
51134723edSLouis Dionne       __output_iter[__r] = *__first;
52134723edSLouis Dionne   }
5377a00c0dSLouis Dionne   return __output_iter + std::min(__n, __k);
54134723edSLouis Dionne }
55134723edSLouis Dionne 
566bdb6422SKonstantin Varlamov template <class _AlgPolicy,
579783f28cSLouis Dionne           class _PopulationIterator,
589783f28cSLouis Dionne           class _PopulationSentinel,
599783f28cSLouis Dionne           class _SampleIterator,
609783f28cSLouis Dionne           class _Distance,
61134723edSLouis Dionne           class _UniformRandomNumberGenerator>
__sample(_PopulationIterator __first,_PopulationSentinel __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator & __g,forward_iterator_tag)629783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _SampleIterator __sample(
639783f28cSLouis Dionne     _PopulationIterator __first,
649783f28cSLouis Dionne     _PopulationSentinel __last,
659783f28cSLouis Dionne     _SampleIterator __output_iter,
66134723edSLouis Dionne     _Distance __n,
67134723edSLouis Dionne     _UniformRandomNumberGenerator& __g,
68134723edSLouis Dionne     forward_iterator_tag) {
696bdb6422SKonstantin Varlamov   _Distance __unsampled_sz = _IterOps<_AlgPolicy>::distance(__first, __last);
7077a00c0dSLouis Dionne   for (__n = std::min(__n, __unsampled_sz); __n != 0; ++__first) {
71134723edSLouis Dionne     _Distance __r = uniform_int_distribution<_Distance>(0, --__unsampled_sz)(__g);
72134723edSLouis Dionne     if (__r < __n) {
73134723edSLouis Dionne       *__output_iter++ = *__first;
74134723edSLouis Dionne       --__n;
75134723edSLouis Dionne     }
76134723edSLouis Dionne   }
77134723edSLouis Dionne   return __output_iter;
78134723edSLouis Dionne }
79134723edSLouis Dionne 
806bdb6422SKonstantin Varlamov template <class _AlgPolicy,
819783f28cSLouis Dionne           class _PopulationIterator,
829783f28cSLouis Dionne           class _PopulationSentinel,
839783f28cSLouis Dionne           class _SampleIterator,
849783f28cSLouis Dionne           class _Distance,
85134723edSLouis Dionne           class _UniformRandomNumberGenerator>
__sample(_PopulationIterator __first,_PopulationSentinel __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator & __g)869783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _SampleIterator __sample(
879783f28cSLouis Dionne     _PopulationIterator __first,
889783f28cSLouis Dionne     _PopulationSentinel __last,
899783f28cSLouis Dionne     _SampleIterator __output_iter,
909783f28cSLouis Dionne     _Distance __n,
919783f28cSLouis Dionne     _UniformRandomNumberGenerator& __g) {
92*1638657dSKonstantin Varlamov   _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n >= 0, "N must be a positive number.");
936bdb6422SKonstantin Varlamov 
946bdb6422SKonstantin Varlamov   using _PopIterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_PopulationIterator>;
956bdb6422SKonstantin Varlamov   using _Difference      = typename _IterOps<_AlgPolicy>::template __difference_type<_PopulationIterator>;
966bdb6422SKonstantin Varlamov   using _CommonType      = typename common_type<_Distance, _Difference>::type;
976bdb6422SKonstantin Varlamov 
986bdb6422SKonstantin Varlamov   return std::__sample<_AlgPolicy>(
999783f28cSLouis Dionne       std::move(__first), std::move(__last), std::move(__output_iter), _CommonType(__n), __g, _PopIterCategory());
100134723edSLouis Dionne }
101134723edSLouis Dionne 
1024f15267dSNikolas Klauser #if _LIBCPP_STD_VER >= 17
1039783f28cSLouis Dionne template <class _PopulationIterator, class _SampleIterator, class _Distance, class _UniformRandomNumberGenerator>
1049783f28cSLouis Dionne inline _LIBCPP_HIDE_FROM_ABI _SampleIterator
sample(_PopulationIterator __first,_PopulationIterator __last,_SampleIterator __output_iter,_Distance __n,_UniformRandomNumberGenerator && __g)1059783f28cSLouis Dionne sample(_PopulationIterator __first,
1069783f28cSLouis Dionne        _PopulationIterator __last,
1079783f28cSLouis Dionne        _SampleIterator __output_iter,
1089783f28cSLouis Dionne        _Distance __n,
1099783f28cSLouis Dionne        _UniformRandomNumberGenerator&& __g) {
11080643d93SNikolas Klauser   static_assert(__has_forward_iterator_category<_PopulationIterator>::value ||
11180643d93SNikolas Klauser                     __has_random_access_iterator_category<_SampleIterator>::value,
1126bdb6422SKonstantin Varlamov                 "SampleIterator must meet the requirements of RandomAccessIterator");
1136bdb6422SKonstantin Varlamov 
1149783f28cSLouis Dionne   return std::__sample<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__output_iter), __n, __g);
115134723edSLouis Dionne }
1166bdb6422SKonstantin Varlamov 
1174f15267dSNikolas Klauser #endif // _LIBCPP_STD_VER >= 17
118134723edSLouis Dionne 
119134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD
120134723edSLouis Dionne 
121134723edSLouis Dionne _LIBCPP_POP_MACROS
122134723edSLouis Dionne 
123134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_SAMPLE_H
124