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