1*732cb123SKonstantin Varlamov //===----------------------------------------------------------------------===//
2*732cb123SKonstantin Varlamov //
3*732cb123SKonstantin Varlamov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*732cb123SKonstantin Varlamov // See https://llvm.org/LICENSE.txt for license information.
5*732cb123SKonstantin Varlamov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*732cb123SKonstantin Varlamov //
7*732cb123SKonstantin Varlamov //===----------------------------------------------------------------------===//
8*732cb123SKonstantin Varlamov 
9*732cb123SKonstantin Varlamov // UNSUPPORTED: c++03, c++11, c++14, c++17
10*732cb123SKonstantin Varlamov // UNSUPPORTED: libcpp-has-no-incomplete-ranges
11*732cb123SKonstantin Varlamov 
12*732cb123SKonstantin Varlamov // <algorithm>
13*732cb123SKonstantin Varlamov 
14*732cb123SKonstantin Varlamov // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Gen>
15*732cb123SKonstantin Varlamov //   requires (forward_iterator<I> || random_access_iterator<O>) &&
16*732cb123SKonstantin Varlamov //           indirectly_copyable<I, O> &&
17*732cb123SKonstantin Varlamov //           uniform_random_bit_generator<remove_reference_t<Gen>>
18*732cb123SKonstantin Varlamov //   O sample(I first, S last, O out, iter_difference_t<I> n, Gen&& g);                              // Since C++20
19*732cb123SKonstantin Varlamov //
20*732cb123SKonstantin Varlamov // template<input_range R, weakly_incrementable O, class Gen>
21*732cb123SKonstantin Varlamov //   requires (forward_range<R> || random_access_iterator<O>) &&
22*732cb123SKonstantin Varlamov //           indirectly_copyable<iterator_t<R>, O> &&
23*732cb123SKonstantin Varlamov //           uniform_random_bit_generator<remove_reference_t<Gen>>
24*732cb123SKonstantin Varlamov //   O sample(R&& r, O out, range_difference_t<R> n, Gen&& g);                                       // Since C++20
25*732cb123SKonstantin Varlamov 
26*732cb123SKonstantin Varlamov #include <algorithm>
27*732cb123SKonstantin Varlamov #include <array>
28*732cb123SKonstantin Varlamov #include <concepts>
29*732cb123SKonstantin Varlamov #include <functional>
30*732cb123SKonstantin Varlamov #include <random>
31*732cb123SKonstantin Varlamov #include <ranges>
32*732cb123SKonstantin Varlamov #include <utility>
33*732cb123SKonstantin Varlamov 
34*732cb123SKonstantin Varlamov #include "almost_satisfies_types.h"
35*732cb123SKonstantin Varlamov #include "test_iterators.h"
36*732cb123SKonstantin Varlamov #include "test_macros.h"
37*732cb123SKonstantin Varlamov 
38*732cb123SKonstantin Varlamov class RandGen {
39*732cb123SKonstantin Varlamov public:
min()40*732cb123SKonstantin Varlamov   constexpr static size_t min() { return 0; }
max()41*732cb123SKonstantin Varlamov   constexpr static size_t max() { return 255; }
42*732cb123SKonstantin Varlamov 
operator ()()43*732cb123SKonstantin Varlamov   constexpr size_t operator()() {
44*732cb123SKonstantin Varlamov     flip = !flip;
45*732cb123SKonstantin Varlamov     return flip;
46*732cb123SKonstantin Varlamov   }
47*732cb123SKonstantin Varlamov 
48*732cb123SKonstantin Varlamov private:
49*732cb123SKonstantin Varlamov   bool flip = false;
50*732cb123SKonstantin Varlamov };
51*732cb123SKonstantin Varlamov 
52*732cb123SKonstantin Varlamov static_assert(std::uniform_random_bit_generator<RandGen>);
53*732cb123SKonstantin Varlamov // `std::uniform_random_bit_generator` is a subset of requirements of `__libcpp_random_is_valid_urng`. Make sure that
54*732cb123SKonstantin Varlamov // a type satisfying the required minimum is still accepted by `ranges::shuffle`.
55*732cb123SKonstantin Varlamov LIBCPP_STATIC_ASSERT(!std::__libcpp_random_is_valid_urng<RandGen>::value);
56*732cb123SKonstantin Varlamov 
57*732cb123SKonstantin Varlamov struct BadGen {
minBadGen58*732cb123SKonstantin Varlamov   constexpr static size_t min() { return 255; }
maxBadGen59*732cb123SKonstantin Varlamov   constexpr static size_t max() { return 0; }
60*732cb123SKonstantin Varlamov   constexpr size_t operator()() const;
61*732cb123SKonstantin Varlamov };
62*732cb123SKonstantin Varlamov static_assert(!std::uniform_random_bit_generator<BadGen>);
63*732cb123SKonstantin Varlamov 
64*732cb123SKonstantin Varlamov // Test constraints of the (iterator, sentinel) overload.
65*732cb123SKonstantin Varlamov // ======================================================
66*732cb123SKonstantin Varlamov 
67*732cb123SKonstantin Varlamov template <class Iter = int*, class Sent = int*, class Out = int*, class Gen = RandGen>
68*732cb123SKonstantin Varlamov concept HasSampleIter =
69*732cb123SKonstantin Varlamov     requires(Iter&& iter, Sent&& sent, Out&& out, std::iter_difference_t<Iter> n, Gen&& gen) {
70*732cb123SKonstantin Varlamov       std::ranges::sample(std::forward<Iter>(iter), std::forward<Sent>(sent),
71*732cb123SKonstantin Varlamov                           std::forward<Out>(out), n, std::forward<Gen>(gen));
72*732cb123SKonstantin Varlamov     };
73*732cb123SKonstantin Varlamov 
74*732cb123SKonstantin Varlamov static_assert(HasSampleIter<int*, int*, int*, RandGen>);
75*732cb123SKonstantin Varlamov 
76*732cb123SKonstantin Varlamov // !input_iterator<I>
77*732cb123SKonstantin Varlamov static_assert(!HasSampleIter<InputIteratorNotDerivedFrom>);
78*732cb123SKonstantin Varlamov static_assert(!HasSampleIter<InputIteratorNotIndirectlyReadable>);
79*732cb123SKonstantin Varlamov static_assert(!HasSampleIter<InputIteratorNotInputOrOutputIterator>);
80*732cb123SKonstantin Varlamov 
81*732cb123SKonstantin Varlamov // !sentinel_for<S, I>
82*732cb123SKonstantin Varlamov static_assert(!HasSampleIter<int*, SentinelForNotSemiregular>);
83*732cb123SKonstantin Varlamov static_assert(!HasSampleIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
84*732cb123SKonstantin Varlamov 
85*732cb123SKonstantin Varlamov // !weakly_incrementable<O>
86*732cb123SKonstantin Varlamov static_assert(!HasSampleIter<int*, int*, WeaklyIncrementableNotMovable>);
87*732cb123SKonstantin Varlamov 
88*732cb123SKonstantin Varlamov // (forward_iterator<I> || random_access_iterator<O>)
89*732cb123SKonstantin Varlamov static_assert(HasSampleIter<
90*732cb123SKonstantin Varlamov     forward_iterator<int*>, forward_iterator<int*>,
91*732cb123SKonstantin Varlamov     cpp20_output_iterator<int*>
92*732cb123SKonstantin Varlamov >);
93*732cb123SKonstantin Varlamov static_assert(HasSampleIter<
94*732cb123SKonstantin Varlamov     cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>,
95*732cb123SKonstantin Varlamov     random_access_iterator<int*>
96*732cb123SKonstantin Varlamov >);
97*732cb123SKonstantin Varlamov // !(forward_iterator<I> || random_access_iterator<O>)
98*732cb123SKonstantin Varlamov static_assert(!HasSampleIter<
99*732cb123SKonstantin Varlamov     cpp20_input_iterator<int*>, sentinel_wrapper<cpp20_input_iterator<int*>>,
100*732cb123SKonstantin Varlamov     cpp20_output_iterator<int*>
101*732cb123SKonstantin Varlamov >);
102*732cb123SKonstantin Varlamov 
103*732cb123SKonstantin Varlamov // !indirectly_copyable<I, O>
104*732cb123SKonstantin Varlamov static_assert(!HasSampleIter<int*, int*, int**>);
105*732cb123SKonstantin Varlamov 
106*732cb123SKonstantin Varlamov // !uniform_random_bit_generator<remove_reference_t<Gen>>
107*732cb123SKonstantin Varlamov static_assert(!HasSampleIter<int*, int*, int*, BadGen>);
108*732cb123SKonstantin Varlamov 
109*732cb123SKonstantin Varlamov // Test constraints of the (range) overload.
110*732cb123SKonstantin Varlamov // =========================================
111*732cb123SKonstantin Varlamov 
112*732cb123SKonstantin Varlamov template <class Range, class Out = int*, class Gen = RandGen>
113*732cb123SKonstantin Varlamov concept HasSampleRange =
114*732cb123SKonstantin Varlamov     requires(Range&& range, Out&& out, std::ranges::range_difference_t<Range> n, Gen&& gen) {
115*732cb123SKonstantin Varlamov       std::ranges::sample(std::forward<Range>(range), std::forward<Out>(out), n, std::forward<Gen>(gen));
116*732cb123SKonstantin Varlamov     };
117*732cb123SKonstantin Varlamov 
118*732cb123SKonstantin Varlamov template <class T>
119*732cb123SKonstantin Varlamov using R = UncheckedRange<T>;
120*732cb123SKonstantin Varlamov 
121*732cb123SKonstantin Varlamov static_assert(HasSampleRange<R<int*>, int*, RandGen>);
122*732cb123SKonstantin Varlamov 
123*732cb123SKonstantin Varlamov // !input_range<R>
124*732cb123SKonstantin Varlamov static_assert(!HasSampleRange<InputRangeNotDerivedFrom>);
125*732cb123SKonstantin Varlamov static_assert(!HasSampleRange<InputRangeNotIndirectlyReadable>);
126*732cb123SKonstantin Varlamov static_assert(!HasSampleRange<InputRangeNotInputOrOutputIterator>);
127*732cb123SKonstantin Varlamov 
128*732cb123SKonstantin Varlamov // !weakly_incrementable<O>
129*732cb123SKonstantin Varlamov static_assert(!HasSampleRange<R<int*>, WeaklyIncrementableNotMovable>);
130*732cb123SKonstantin Varlamov 
131*732cb123SKonstantin Varlamov // (forward_range<R> || random_access_iterator<O>)
132*732cb123SKonstantin Varlamov static_assert(HasSampleRange<
133*732cb123SKonstantin Varlamov     R<forward_iterator<int*>>,
134*732cb123SKonstantin Varlamov     cpp20_output_iterator<int*>
135*732cb123SKonstantin Varlamov >);
136*732cb123SKonstantin Varlamov static_assert(HasSampleRange<
137*732cb123SKonstantin Varlamov     R<cpp20_input_iterator<int*>>,
138*732cb123SKonstantin Varlamov     random_access_iterator<int*>
139*732cb123SKonstantin Varlamov >);
140*732cb123SKonstantin Varlamov // !(forward_range<R> || random_access_iterator<O>)
141*732cb123SKonstantin Varlamov static_assert(!HasSampleRange<
142*732cb123SKonstantin Varlamov     R<cpp20_input_iterator<int*>>,
143*732cb123SKonstantin Varlamov     cpp20_output_iterator<int*>
144*732cb123SKonstantin Varlamov >);
145*732cb123SKonstantin Varlamov 
146*732cb123SKonstantin Varlamov // !indirectly_copyable<I, O>
147*732cb123SKonstantin Varlamov static_assert(!HasSampleRange<R<int*>, int**>);
148*732cb123SKonstantin Varlamov 
149*732cb123SKonstantin Varlamov // !uniform_random_bit_generator<remove_reference_t<Gen>>
150*732cb123SKonstantin Varlamov static_assert(!HasSampleRange<R<int*>, int*, BadGen>);
151*732cb123SKonstantin Varlamov 
152*732cb123SKonstantin Varlamov template <class Iter, class Sent, class Out, size_t N, class Gen>
test_one(std::array<int,N> in,size_t n,Gen gen)153*732cb123SKonstantin Varlamov void test_one(std::array<int, N> in, size_t n, Gen gen) {
154*732cb123SKonstantin Varlamov   assert(n <= static_cast<size_t>(N));
155*732cb123SKonstantin Varlamov 
156*732cb123SKonstantin Varlamov   auto verify_is_subsequence = [&] (auto output) {
157*732cb123SKonstantin Varlamov     auto sorted_input = in;
158*732cb123SKonstantin Varlamov     std::ranges::sort(sorted_input);
159*732cb123SKonstantin Varlamov     auto sorted_output = std::ranges::subrange(output.begin(), output.begin() + n);
160*732cb123SKonstantin Varlamov     std::ranges::sort(sorted_output);
161*732cb123SKonstantin Varlamov     assert(std::ranges::includes(sorted_input, sorted_output));
162*732cb123SKonstantin Varlamov   };
163*732cb123SKonstantin Varlamov 
164*732cb123SKonstantin Varlamov   { // (iterator, sentinel) overload.
165*732cb123SKonstantin Varlamov     auto begin = Iter(in.data());
166*732cb123SKonstantin Varlamov     auto end = Sent(Iter(in.data() + in.size()));
167*732cb123SKonstantin Varlamov     std::array<int, N> output;
168*732cb123SKonstantin Varlamov     auto out = Out(output.begin());
169*732cb123SKonstantin Varlamov 
170*732cb123SKonstantin Varlamov     std::same_as<Out> decltype(auto) result = std::ranges::sample(
171*732cb123SKonstantin Varlamov         std::move(begin), std::move(end), std::move(out), n, gen);
172*732cb123SKonstantin Varlamov     assert(base(result) == output.data() + n);
173*732cb123SKonstantin Varlamov     verify_is_subsequence(output);
174*732cb123SKonstantin Varlamov     // The output of `sample` is implementation-specific.
175*732cb123SKonstantin Varlamov   }
176*732cb123SKonstantin Varlamov 
177*732cb123SKonstantin Varlamov   { // (range) overload.
178*732cb123SKonstantin Varlamov     auto begin = Iter(in.data());
179*732cb123SKonstantin Varlamov     auto end = Sent(Iter(in.data() + in.size()));
180*732cb123SKonstantin Varlamov     std::array<int, N> output;
181*732cb123SKonstantin Varlamov     auto out = Out(output.begin());
182*732cb123SKonstantin Varlamov 
183*732cb123SKonstantin Varlamov     std::same_as<Out> decltype(auto) result = std::ranges::sample(std::ranges::subrange(
184*732cb123SKonstantin Varlamov         std::move(begin), std::move(end)), std::move(out), n, gen);
185*732cb123SKonstantin Varlamov     assert(base(result) == output.data() + n);
186*732cb123SKonstantin Varlamov     verify_is_subsequence(output);
187*732cb123SKonstantin Varlamov     // The output of `sample` is implementation-specific.
188*732cb123SKonstantin Varlamov   }
189*732cb123SKonstantin Varlamov }
190*732cb123SKonstantin Varlamov 
191*732cb123SKonstantin Varlamov template <class Iter, class Sent, class Out>
test_iterators_iter_sent_out()192*732cb123SKonstantin Varlamov void test_iterators_iter_sent_out() {
193*732cb123SKonstantin Varlamov   RandGen gen;
194*732cb123SKonstantin Varlamov 
195*732cb123SKonstantin Varlamov   // Empty sequence.
196*732cb123SKonstantin Varlamov   test_one<Iter, Sent, Out, 0>({}, 0, gen);
197*732cb123SKonstantin Varlamov   // 1-element sequence.
198*732cb123SKonstantin Varlamov   test_one<Iter, Sent, Out, 1>({1}, 1, gen);
199*732cb123SKonstantin Varlamov   // 2-element sequence.
200*732cb123SKonstantin Varlamov   test_one<Iter, Sent, Out, 2>({1, 2}, 1, gen);
201*732cb123SKonstantin Varlamov   test_one<Iter, Sent, Out, 2>({1, 2}, 2, gen);
202*732cb123SKonstantin Varlamov   // n == 0.
203*732cb123SKonstantin Varlamov   test_one<Iter, Sent, Out, 3>({1, 2, 3}, 0, gen);
204*732cb123SKonstantin Varlamov 
205*732cb123SKonstantin Varlamov   // Longer sequence.
206*732cb123SKonstantin Varlamov   {
207*732cb123SKonstantin Varlamov     std::array input = {1, 8, 2, 3, 4, 6, 5, 7};
208*732cb123SKonstantin Varlamov     for (int i = 0; i <= static_cast<int>(input.size()); ++i){
209*732cb123SKonstantin Varlamov       test_one<Iter, Sent, Out, input.size()>(input, i, gen);
210*732cb123SKonstantin Varlamov     }
211*732cb123SKonstantin Varlamov   }
212*732cb123SKonstantin Varlamov }
213*732cb123SKonstantin Varlamov 
214*732cb123SKonstantin Varlamov template <class Iter, class Sent>
test_iterators_iter_sent()215*732cb123SKonstantin Varlamov void test_iterators_iter_sent() {
216*732cb123SKonstantin Varlamov   if constexpr (std::forward_iterator<Iter>) {
217*732cb123SKonstantin Varlamov     test_iterators_iter_sent_out<Iter, Sent, cpp20_output_iterator<int*>>();
218*732cb123SKonstantin Varlamov     test_iterators_iter_sent_out<Iter, Sent, forward_iterator<int*>>();
219*732cb123SKonstantin Varlamov   }
220*732cb123SKonstantin Varlamov   test_iterators_iter_sent_out<Iter, Sent, random_access_iterator<int*>>();
221*732cb123SKonstantin Varlamov   test_iterators_iter_sent_out<Iter, Sent, contiguous_iterator<int*>>();
222*732cb123SKonstantin Varlamov   test_iterators_iter_sent_out<Iter, Sent, int*>();
223*732cb123SKonstantin Varlamov }
224*732cb123SKonstantin Varlamov 
225*732cb123SKonstantin Varlamov template <class Iter>
test_iterators_iter()226*732cb123SKonstantin Varlamov void test_iterators_iter() {
227*732cb123SKonstantin Varlamov   if constexpr (std::sentinel_for<Iter, Iter>) {
228*732cb123SKonstantin Varlamov     test_iterators_iter_sent<Iter, Iter>();
229*732cb123SKonstantin Varlamov   }
230*732cb123SKonstantin Varlamov   test_iterators_iter_sent<Iter, sentinel_wrapper<Iter>>();
231*732cb123SKonstantin Varlamov }
232*732cb123SKonstantin Varlamov 
test_iterators()233*732cb123SKonstantin Varlamov void test_iterators() {
234*732cb123SKonstantin Varlamov   test_iterators_iter<cpp20_input_iterator<int*>>();
235*732cb123SKonstantin Varlamov   test_iterators_iter<random_access_iterator<int*>>();
236*732cb123SKonstantin Varlamov   test_iterators_iter<contiguous_iterator<int*>>();
237*732cb123SKonstantin Varlamov   test_iterators_iter<int*>();
238*732cb123SKonstantin Varlamov   test_iterators_iter<const int*>();
239*732cb123SKonstantin Varlamov }
240*732cb123SKonstantin Varlamov 
241*732cb123SKonstantin Varlamov // Checks the logic for wrapping the given iterator to make sure it works correctly regardless of the value category of
242*732cb123SKonstantin Varlamov // the given generator object.
243*732cb123SKonstantin Varlamov template <class Gen, bool CheckConst = true>
test_generator()244*732cb123SKonstantin Varlamov void test_generator() {
245*732cb123SKonstantin Varlamov   std::array in = {1, 2, 3, 4, 5, 6, 7, 8};
246*732cb123SKonstantin Varlamov   constexpr int N = 5;
247*732cb123SKonstantin Varlamov   std::array<int, N> output;
248*732cb123SKonstantin Varlamov   auto begin = in.begin();
249*732cb123SKonstantin Varlamov   auto end = in.end();
250*732cb123SKonstantin Varlamov   auto out = output.begin();
251*732cb123SKonstantin Varlamov 
252*732cb123SKonstantin Varlamov   { // Lvalue.
253*732cb123SKonstantin Varlamov     Gen g;
254*732cb123SKonstantin Varlamov     std::ranges::sample(begin, end, out, N, g);
255*732cb123SKonstantin Varlamov     std::ranges::sample(in, out, N, g);
256*732cb123SKonstantin Varlamov   }
257*732cb123SKonstantin Varlamov 
258*732cb123SKonstantin Varlamov   if constexpr (CheckConst) { // Const lvalue.
259*732cb123SKonstantin Varlamov     const Gen g;
260*732cb123SKonstantin Varlamov     std::ranges::sample(begin, end, out, N, g);
261*732cb123SKonstantin Varlamov     std::ranges::sample(in, out, N, g);
262*732cb123SKonstantin Varlamov   }
263*732cb123SKonstantin Varlamov 
264*732cb123SKonstantin Varlamov   { // Prvalue.
265*732cb123SKonstantin Varlamov     std::ranges::sample(begin, end, out, N, Gen());
266*732cb123SKonstantin Varlamov     std::ranges::sample(in, out, N, Gen());
267*732cb123SKonstantin Varlamov   }
268*732cb123SKonstantin Varlamov 
269*732cb123SKonstantin Varlamov   { // Xvalue.
270*732cb123SKonstantin Varlamov     Gen g1, g2;
271*732cb123SKonstantin Varlamov     std::ranges::sample(begin, end, out, N, std::move(g1));
272*732cb123SKonstantin Varlamov     std::ranges::sample(in, out, N, std::move(g2));
273*732cb123SKonstantin Varlamov   }
274*732cb123SKonstantin Varlamov }
275*732cb123SKonstantin Varlamov 
276*732cb123SKonstantin Varlamov // Checks the logic for wrapping the given iterator to make sure it works correctly regardless of whether the given
277*732cb123SKonstantin Varlamov // generator class has a const or non-const invocation operator (or both).
test_generators()278*732cb123SKonstantin Varlamov void test_generators() {
279*732cb123SKonstantin Varlamov   struct GenBase {
280*732cb123SKonstantin Varlamov     constexpr static size_t min() { return 0; }
281*732cb123SKonstantin Varlamov     constexpr static size_t max() { return 255; }
282*732cb123SKonstantin Varlamov   };
283*732cb123SKonstantin Varlamov   struct NonconstGen : GenBase {
284*732cb123SKonstantin Varlamov     size_t operator()() { return 1; }
285*732cb123SKonstantin Varlamov   };
286*732cb123SKonstantin Varlamov   struct ConstGen : GenBase {
287*732cb123SKonstantin Varlamov     size_t operator()() const { return 1; }
288*732cb123SKonstantin Varlamov   };
289*732cb123SKonstantin Varlamov   struct ConstAndNonconstGen : GenBase {
290*732cb123SKonstantin Varlamov     size_t operator()() { return 1; }
291*732cb123SKonstantin Varlamov     size_t operator()() const { return 1; }
292*732cb123SKonstantin Varlamov   };
293*732cb123SKonstantin Varlamov 
294*732cb123SKonstantin Varlamov   test_generator<ConstGen>();
295*732cb123SKonstantin Varlamov   test_generator<NonconstGen, /*CheckConst=*/false>();
296*732cb123SKonstantin Varlamov   test_generator<ConstAndNonconstGen>();
297*732cb123SKonstantin Varlamov }
298*732cb123SKonstantin Varlamov 
test()299*732cb123SKonstantin Varlamov void test() {
300*732cb123SKonstantin Varlamov   test_iterators();
301*732cb123SKonstantin Varlamov   test_generators();
302*732cb123SKonstantin Varlamov 
303*732cb123SKonstantin Varlamov   { // Stable (if `I` models `forward_iterator`).
304*732cb123SKonstantin Varlamov     struct OrderedValue {
305*732cb123SKonstantin Varlamov       int value;
306*732cb123SKonstantin Varlamov       int original_order;
307*732cb123SKonstantin Varlamov       bool operator==(const OrderedValue&) const = default;
308*732cb123SKonstantin Varlamov       auto operator<=>(const OrderedValue& rhs) const { return value <=> rhs.value; }
309*732cb123SKonstantin Varlamov     };
310*732cb123SKonstantin Varlamov 
311*732cb123SKonstantin Varlamov     const std::array<OrderedValue, 8> in = {{
312*732cb123SKonstantin Varlamov       {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}
313*732cb123SKonstantin Varlamov     }};
314*732cb123SKonstantin Varlamov 
315*732cb123SKonstantin Varlamov     { // (iterator, sentinel) overload.
316*732cb123SKonstantin Varlamov       std::array<OrderedValue, in.size()> out;
317*732cb123SKonstantin Varlamov       std::ranges::sample(in.begin(), in.end(), out.begin(), in.size(), RandGen());
318*732cb123SKonstantin Varlamov       assert(out == in);
319*732cb123SKonstantin Varlamov     }
320*732cb123SKonstantin Varlamov 
321*732cb123SKonstantin Varlamov     { // (range) overload.
322*732cb123SKonstantin Varlamov       std::array<OrderedValue, in.size()> out;
323*732cb123SKonstantin Varlamov       std::ranges::sample(in, out.begin(), in.size(), RandGen());
324*732cb123SKonstantin Varlamov       assert(out == in);
325*732cb123SKonstantin Varlamov     }
326*732cb123SKonstantin Varlamov   }
327*732cb123SKonstantin Varlamov }
328*732cb123SKonstantin Varlamov 
main(int,char **)329*732cb123SKonstantin Varlamov int main(int, char**) {
330*732cb123SKonstantin Varlamov   test();
331*732cb123SKonstantin Varlamov   // Note: `ranges::sample` is not `constexpr`.
332*732cb123SKonstantin Varlamov 
333*732cb123SKonstantin Varlamov   return 0;
334*732cb123SKonstantin Varlamov }
335