1e7154709SEric Fiselier //===----------------------------------------------------------------------===// 2e7154709SEric Fiselier // 357b08b09SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 457b08b09SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 557b08b09SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e7154709SEric Fiselier // 7e7154709SEric Fiselier //===----------------------------------------------------------------------===// 8e7154709SEric Fiselier 9e7154709SEric Fiselier // UNSUPPORTED: c++98, c++03, c++11, c++14 10e7154709SEric Fiselier 11e7154709SEric Fiselier // <algorithm> 12e7154709SEric Fiselier 13e7154709SEric Fiselier // template <class PopulationIterator, class SampleIterator, class Distance, 14e7154709SEric Fiselier // class UniformRandomNumberGenerator> 15e7154709SEric Fiselier // SampleIterator sample(PopulationIterator first, PopulationIterator last, 16e7154709SEric Fiselier // SampleIterator out, Distance n, 17e7154709SEric Fiselier // UniformRandomNumberGenerator &&g); 18e7154709SEric Fiselier 19e7154709SEric Fiselier #include <algorithm> 20e7154709SEric Fiselier #include <random> 2109c311b9SStephan T. Lavavej #include <type_traits> 22e7154709SEric Fiselier #include <cassert> 2368a694b8SStephan T. Lavavej #include <cstddef> 24e7154709SEric Fiselier 25e7154709SEric Fiselier #include "test_iterators.h" 2609c311b9SStephan T. Lavavej #include "test_macros.h" 27e7154709SEric Fiselier 28e7154709SEric Fiselier struct ReservoirSampleExpectations { 29e7154709SEric Fiselier enum { os = 4 }; 30e7154709SEric Fiselier static int oa1[os]; 31e7154709SEric Fiselier static int oa2[os]; 32e7154709SEric Fiselier }; 33e7154709SEric Fiselier 34e7154709SEric Fiselier int ReservoirSampleExpectations::oa1[] = {10, 5, 9, 4}; 35e7154709SEric Fiselier int ReservoirSampleExpectations::oa2[] = {5, 2, 10, 4}; 36e7154709SEric Fiselier 37e7154709SEric Fiselier struct SelectionSampleExpectations { 38e7154709SEric Fiselier enum { os = 4 }; 39e7154709SEric Fiselier static int oa1[os]; 40e7154709SEric Fiselier static int oa2[os]; 41e7154709SEric Fiselier }; 42e7154709SEric Fiselier 43e7154709SEric Fiselier int SelectionSampleExpectations::oa1[] = {1, 4, 6, 7}; 44e7154709SEric Fiselier int SelectionSampleExpectations::oa2[] = {1, 2, 6, 8}; 45e7154709SEric Fiselier 46e7154709SEric Fiselier template <class IteratorCategory> struct TestExpectations 47e7154709SEric Fiselier : public SelectionSampleExpectations {}; 48e7154709SEric Fiselier 49e7154709SEric Fiselier template <> 50e7154709SEric Fiselier struct TestExpectations<std::input_iterator_tag> 51e7154709SEric Fiselier : public ReservoirSampleExpectations {}; 52e7154709SEric Fiselier 53e7154709SEric Fiselier template <template<class...> class PopulationIteratorType, class PopulationItem, 54e7154709SEric Fiselier template<class...> class SampleIteratorType, class SampleItem> 55e7154709SEric Fiselier void test() { 56e7154709SEric Fiselier typedef PopulationIteratorType<PopulationItem *> PopulationIterator; 57e7154709SEric Fiselier typedef SampleIteratorType<SampleItem *> SampleIterator; 58e7154709SEric Fiselier PopulationItem ia[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 59e7154709SEric Fiselier const unsigned is = sizeof(ia) / sizeof(ia[0]); 60e7154709SEric Fiselier typedef TestExpectations<typename std::iterator_traits< 61e7154709SEric Fiselier PopulationIterator>::iterator_category> Expectations; 62e7154709SEric Fiselier const unsigned os = Expectations::os; 63e7154709SEric Fiselier SampleItem oa[os]; 64e7154709SEric Fiselier const int *oa1 = Expectations::oa1; 6509c311b9SStephan T. Lavavej ((void)oa1); // Prevent unused warning 66e7154709SEric Fiselier const int *oa2 = Expectations::oa2; 6709c311b9SStephan T. Lavavej ((void)oa2); // Prevent unused warning 68e7154709SEric Fiselier std::minstd_rand g; 69e7154709SEric Fiselier SampleIterator end; 70e7154709SEric Fiselier end = std::sample(PopulationIterator(ia), 71e7154709SEric Fiselier PopulationIterator(ia + is), 72e7154709SEric Fiselier SampleIterator(oa), os, g); 7368a694b8SStephan T. Lavavej assert(static_cast<std::size_t>(end.base() - oa) == std::min(os, is)); 7409c311b9SStephan T. Lavavej // sample() is deterministic but non-reproducible; 7509c311b9SStephan T. Lavavej // its results can vary between implementations. 7609c311b9SStephan T. Lavavej LIBCPP_ASSERT(std::equal(oa, oa + os, oa1)); 77e7154709SEric Fiselier end = std::sample(PopulationIterator(ia), 78e7154709SEric Fiselier PopulationIterator(ia + is), 79e7154709SEric Fiselier SampleIterator(oa), os, std::move(g)); 8068a694b8SStephan T. Lavavej assert(static_cast<std::size_t>(end.base() - oa) == std::min(os, is)); 8109c311b9SStephan T. Lavavej LIBCPP_ASSERT(std::equal(oa, oa + os, oa2)); 82e7154709SEric Fiselier } 83e7154709SEric Fiselier 84e7154709SEric Fiselier template <template<class...> class PopulationIteratorType, class PopulationItem, 85e7154709SEric Fiselier template<class...> class SampleIteratorType, class SampleItem> 86e7154709SEric Fiselier void test_empty_population() { 87e7154709SEric Fiselier typedef PopulationIteratorType<PopulationItem *> PopulationIterator; 88e7154709SEric Fiselier typedef SampleIteratorType<SampleItem *> SampleIterator; 89e7154709SEric Fiselier PopulationItem ia[] = {42}; 90e7154709SEric Fiselier const unsigned os = 4; 91e7154709SEric Fiselier SampleItem oa[os]; 92e7154709SEric Fiselier std::minstd_rand g; 93e7154709SEric Fiselier SampleIterator end = 94e7154709SEric Fiselier std::sample(PopulationIterator(ia), PopulationIterator(ia), 95e7154709SEric Fiselier SampleIterator(oa), os, g); 96e7154709SEric Fiselier assert(end.base() == oa); 97e7154709SEric Fiselier } 98e7154709SEric Fiselier 99e7154709SEric Fiselier template <template<class...> class PopulationIteratorType, class PopulationItem, 100e7154709SEric Fiselier template<class...> class SampleIteratorType, class SampleItem> 101e7154709SEric Fiselier void test_empty_sample() { 102e7154709SEric Fiselier typedef PopulationIteratorType<PopulationItem *> PopulationIterator; 103e7154709SEric Fiselier typedef SampleIteratorType<SampleItem *> SampleIterator; 104e7154709SEric Fiselier PopulationItem ia[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; 105e7154709SEric Fiselier const unsigned is = sizeof(ia) / sizeof(ia[0]); 106e7154709SEric Fiselier SampleItem oa[1]; 107e7154709SEric Fiselier std::minstd_rand g; 108e7154709SEric Fiselier SampleIterator end = 109e7154709SEric Fiselier std::sample(PopulationIterator(ia), PopulationIterator(ia + is), 110e7154709SEric Fiselier SampleIterator(oa), 0, g); 111e7154709SEric Fiselier assert(end.base() == oa); 112e7154709SEric Fiselier } 113e7154709SEric Fiselier 114e7154709SEric Fiselier template <template<class...> class PopulationIteratorType, class PopulationItem, 115e7154709SEric Fiselier template<class...> class SampleIteratorType, class SampleItem> 116e7154709SEric Fiselier void test_small_population() { 117e7154709SEric Fiselier // The population size is less than the sample size. 118e7154709SEric Fiselier typedef PopulationIteratorType<PopulationItem *> PopulationIterator; 119e7154709SEric Fiselier typedef SampleIteratorType<SampleItem *> SampleIterator; 120e7154709SEric Fiselier PopulationItem ia[] = {1, 2, 3, 4, 5}; 121e7154709SEric Fiselier const unsigned is = sizeof(ia) / sizeof(ia[0]); 122e7154709SEric Fiselier const unsigned os = 8; 123e7154709SEric Fiselier SampleItem oa[os]; 124e7154709SEric Fiselier const SampleItem oa1[] = {1, 2, 3, 4, 5}; 125e7154709SEric Fiselier std::minstd_rand g; 126e7154709SEric Fiselier SampleIterator end; 127e7154709SEric Fiselier end = std::sample(PopulationIterator(ia), 128e7154709SEric Fiselier PopulationIterator(ia + is), 129e7154709SEric Fiselier SampleIterator(oa), os, g); 13068a694b8SStephan T. Lavavej assert(static_cast<std::size_t>(end.base() - oa) == std::min(os, is)); 13109c311b9SStephan T. Lavavej typedef typename std::iterator_traits<PopulationIterator>::iterator_category PopulationCategory; 13209c311b9SStephan T. Lavavej if (std::is_base_of<std::forward_iterator_tag, PopulationCategory>::value) { 133e7154709SEric Fiselier assert(std::equal(oa, end.base(), oa1)); 13409c311b9SStephan T. Lavavej } else { 13509c311b9SStephan T. Lavavej assert(std::is_permutation(oa, end.base(), oa1)); 13609c311b9SStephan T. Lavavej } 137e7154709SEric Fiselier } 138e7154709SEric Fiselier 139*2df59c50SJF Bastien int main(int, char**) { 140e7154709SEric Fiselier test<input_iterator, int, random_access_iterator, int>(); 141e7154709SEric Fiselier test<forward_iterator, int, output_iterator, int>(); 142e7154709SEric Fiselier test<forward_iterator, int, random_access_iterator, int>(); 143e7154709SEric Fiselier 144e7154709SEric Fiselier test<input_iterator, int, random_access_iterator, double>(); 145e7154709SEric Fiselier test<forward_iterator, int, output_iterator, double>(); 146e7154709SEric Fiselier test<forward_iterator, int, random_access_iterator, double>(); 147e7154709SEric Fiselier 148e7154709SEric Fiselier test_empty_population<input_iterator, int, random_access_iterator, int>(); 149e7154709SEric Fiselier test_empty_population<forward_iterator, int, output_iterator, int>(); 150e7154709SEric Fiselier test_empty_population<forward_iterator, int, random_access_iterator, int>(); 151e7154709SEric Fiselier 152e7154709SEric Fiselier test_empty_sample<input_iterator, int, random_access_iterator, int>(); 153e7154709SEric Fiselier test_empty_sample<forward_iterator, int, output_iterator, int>(); 154e7154709SEric Fiselier test_empty_sample<forward_iterator, int, random_access_iterator, int>(); 155e7154709SEric Fiselier 156e7154709SEric Fiselier test_small_population<input_iterator, int, random_access_iterator, int>(); 157e7154709SEric Fiselier test_small_population<forward_iterator, int, output_iterator, int>(); 158e7154709SEric Fiselier test_small_population<forward_iterator, int, random_access_iterator, int>(); 159*2df59c50SJF Bastien 160*2df59c50SJF Bastien return 0; 161e7154709SEric Fiselier } 162