1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, class Gen>
14 // requires (forward_iterator<I> || random_access_iterator<O>) &&
15 // indirectly_copyable<I, O> &&
16 // uniform_random_bit_generator<remove_reference_t<Gen>>
17 // O sample(I first, S last, O out, iter_difference_t<I> n, Gen&& g); // Since C++20
19 // template<input_range R, weakly_incrementable O, class Gen>
20 // requires (forward_range<R> || random_access_iterator<O>) &&
21 // indirectly_copyable<iterator_t<R>, O> &&
22 // uniform_random_bit_generator<remove_reference_t<Gen>>
23 // O sample(R&& r, O out, range_difference_t<R> n, Gen&& g); // Since C++20
33 #include "almost_satisfies_types.h"
34 #include "test_iterators.h"
35 #include "test_macros.h"
39 constexpr static std::size_t min() { return 0; }
40 constexpr static std::size_t max() { return 255; }
42 constexpr std::size_t operator()() {
51 static_assert(std::uniform_random_bit_generator
<RandGen
>);
52 // `std::uniform_random_bit_generator` is a subset of requirements of `__libcpp_random_is_valid_urng`. Make sure that
53 // a type satisfying the required minimum is still accepted by `ranges::shuffle`.
54 LIBCPP_STATIC_ASSERT(!std::__libcpp_random_is_valid_urng
<RandGen
>::value
);
57 constexpr static std::size_t min() { return 255; }
58 constexpr static std::size_t max() { return 0; }
59 constexpr std::size_t operator()() const;
61 static_assert(!std::uniform_random_bit_generator
<BadGen
>);
63 // Test constraints of the (iterator, sentinel) overload.
64 // ======================================================
66 template <class Iter
= int*, class Sent
= int*, class Out
= int*, class Gen
= RandGen
>
67 concept HasSampleIter
=
68 requires(Iter
&& iter
, Sent
&& sent
, Out
&& out
, std::iter_difference_t
<Iter
> n
, Gen
&& gen
) {
69 std::ranges::sample(std::forward
<Iter
>(iter
), std::forward
<Sent
>(sent
),
70 std::forward
<Out
>(out
), n
, std::forward
<Gen
>(gen
));
73 static_assert(HasSampleIter
<int*, int*, int*, RandGen
>);
76 static_assert(!HasSampleIter
<InputIteratorNotDerivedFrom
>);
77 static_assert(!HasSampleIter
<InputIteratorNotIndirectlyReadable
>);
78 static_assert(!HasSampleIter
<InputIteratorNotInputOrOutputIterator
>);
80 // !sentinel_for<S, I>
81 static_assert(!HasSampleIter
<int*, SentinelForNotSemiregular
>);
82 static_assert(!HasSampleIter
<int*, SentinelForNotWeaklyEqualityComparableWith
>);
84 // !weakly_incrementable<O>
85 static_assert(!HasSampleIter
<int*, int*, WeaklyIncrementableNotMovable
>);
87 // (forward_iterator<I> || random_access_iterator<O>)
88 static_assert(HasSampleIter
<
89 forward_iterator
<int*>, forward_iterator
<int*>,
90 cpp20_output_iterator
<int*>
92 static_assert(HasSampleIter
<
93 cpp20_input_iterator
<int*>, sentinel_wrapper
<cpp20_input_iterator
<int*>>,
94 random_access_iterator
<int*>
96 // !(forward_iterator<I> || random_access_iterator<O>)
97 static_assert(!HasSampleIter
<
98 cpp20_input_iterator
<int*>, sentinel_wrapper
<cpp20_input_iterator
<int*>>,
99 cpp20_output_iterator
<int*>
102 // !indirectly_copyable<I, O>
103 static_assert(!HasSampleIter
<int*, int*, int**>);
105 // !uniform_random_bit_generator<remove_reference_t<Gen>>
106 static_assert(!HasSampleIter
<int*, int*, int*, BadGen
>);
108 // Test constraints of the (range) overload.
109 // =========================================
111 template <class Range
, class Out
= int*, class Gen
= RandGen
>
112 concept HasSampleRange
=
113 requires(Range
&& range
, Out
&& out
, std::ranges::range_difference_t
<Range
> n
, Gen
&& gen
) {
114 std::ranges::sample(std::forward
<Range
>(range
), std::forward
<Out
>(out
), n
, std::forward
<Gen
>(gen
));
118 using R
= UncheckedRange
<T
>;
120 static_assert(HasSampleRange
<R
<int*>, int*, RandGen
>);
123 static_assert(!HasSampleRange
<InputRangeNotDerivedFrom
>);
124 static_assert(!HasSampleRange
<InputRangeNotIndirectlyReadable
>);
125 static_assert(!HasSampleRange
<InputRangeNotInputOrOutputIterator
>);
127 // !weakly_incrementable<O>
128 static_assert(!HasSampleRange
<R
<int*>, WeaklyIncrementableNotMovable
>);
130 // (forward_range<R> || random_access_iterator<O>)
131 static_assert(HasSampleRange
<
132 R
<forward_iterator
<int*>>,
133 cpp20_output_iterator
<int*>
135 static_assert(HasSampleRange
<
136 R
<cpp20_input_iterator
<int*>>,
137 random_access_iterator
<int*>
139 // !(forward_range<R> || random_access_iterator<O>)
140 static_assert(!HasSampleRange
<
141 R
<cpp20_input_iterator
<int*>>,
142 cpp20_output_iterator
<int*>
145 // !indirectly_copyable<I, O>
146 static_assert(!HasSampleRange
<R
<int*>, int**>);
148 // !uniform_random_bit_generator<remove_reference_t<Gen>>
149 static_assert(!HasSampleRange
<R
<int*>, int*, BadGen
>);
151 template <class Iter
, class Sent
, class Out
, std::size_t N
, class Gen
>
152 void test_one(std::array
<int, N
> in
, std::size_t n
, Gen gen
) {
153 assert(n
<= static_cast<std::size_t>(N
));
155 auto verify_is_subsequence
= [&] (auto output
) {
156 auto sorted_input
= in
;
157 std::ranges::sort(sorted_input
);
158 auto sorted_output
= std::ranges::subrange(output
.begin(), output
.begin() + n
);
159 std::ranges::sort(sorted_output
);
160 assert(std::ranges::includes(sorted_input
, sorted_output
));
163 { // (iterator, sentinel) overload.
164 auto begin
= Iter(in
.data());
165 auto end
= Sent(Iter(in
.data() + in
.size()));
166 std::array
<int, N
> output
;
167 auto out
= Out(output
.begin());
169 std::same_as
<Out
> decltype(auto) result
= std::ranges::sample(
170 std::move(begin
), std::move(end
), std::move(out
), n
, gen
);
171 assert(base(result
) == output
.data() + n
);
172 verify_is_subsequence(output
);
173 // The output of `sample` is implementation-specific.
176 { // (range) overload.
177 auto begin
= Iter(in
.data());
178 auto end
= Sent(Iter(in
.data() + in
.size()));
179 std::array
<int, N
> output
;
180 auto out
= Out(output
.begin());
182 std::same_as
<Out
> decltype(auto) result
= std::ranges::sample(std::ranges::subrange(
183 std::move(begin
), std::move(end
)), std::move(out
), n
, gen
);
184 assert(base(result
) == output
.data() + n
);
185 verify_is_subsequence(output
);
186 // The output of `sample` is implementation-specific.
190 template <class Iter
, class Sent
, class Out
>
191 void test_iterators_iter_sent_out() {
195 test_one
<Iter
, Sent
, Out
, 0>({}, 0, gen
);
196 // 1-element sequence.
197 test_one
<Iter
, Sent
, Out
, 1>({1}, 1, gen
);
198 // 2-element sequence.
199 test_one
<Iter
, Sent
, Out
, 2>({1, 2}, 1, gen
);
200 test_one
<Iter
, Sent
, Out
, 2>({1, 2}, 2, gen
);
202 test_one
<Iter
, Sent
, Out
, 3>({1, 2, 3}, 0, gen
);
206 std::array input
= {1, 8, 2, 3, 4, 6, 5, 7};
207 for (int i
= 0; i
<= static_cast<int>(input
.size()); ++i
){
208 test_one
<Iter
, Sent
, Out
, input
.size()>(input
, i
, gen
);
213 template <class Iter
, class Sent
>
214 void test_iterators_iter_sent() {
215 if constexpr (std::forward_iterator
<Iter
>) {
216 test_iterators_iter_sent_out
<Iter
, Sent
, cpp20_output_iterator
<int*>>();
217 test_iterators_iter_sent_out
<Iter
, Sent
, forward_iterator
<int*>>();
219 test_iterators_iter_sent_out
<Iter
, Sent
, random_access_iterator
<int*>>();
220 test_iterators_iter_sent_out
<Iter
, Sent
, contiguous_iterator
<int*>>();
221 test_iterators_iter_sent_out
<Iter
, Sent
, int*>();
224 template <class Iter
>
225 void test_iterators_iter() {
226 if constexpr (std::sentinel_for
<Iter
, Iter
>) {
227 test_iterators_iter_sent
<Iter
, Iter
>();
229 test_iterators_iter_sent
<Iter
, sentinel_wrapper
<Iter
>>();
232 void test_iterators() {
233 test_iterators_iter
<cpp20_input_iterator
<int*>>();
234 test_iterators_iter
<random_access_iterator
<int*>>();
235 test_iterators_iter
<contiguous_iterator
<int*>>();
236 test_iterators_iter
<int*>();
237 test_iterators_iter
<const int*>();
240 // Checks the logic for wrapping the given iterator to make sure it works correctly regardless of the value category of
241 // the given generator object.
242 template <class Gen
, bool CheckConst
= true>
243 void test_generator() {
244 std::array in
= {1, 2, 3, 4, 5, 6, 7, 8};
246 std::array
<int, N
> output
;
247 auto begin
= in
.begin();
249 auto out
= output
.begin();
253 std::ranges::sample(begin
, end
, out
, N
, g
);
254 std::ranges::sample(in
, out
, N
, g
);
257 if constexpr (CheckConst
) { // Const lvalue.
259 std::ranges::sample(begin
, end
, out
, N
, g
);
260 std::ranges::sample(in
, out
, N
, g
);
264 std::ranges::sample(begin
, end
, out
, N
, Gen());
265 std::ranges::sample(in
, out
, N
, Gen());
270 std::ranges::sample(begin
, end
, out
, N
, std::move(g1
));
271 std::ranges::sample(in
, out
, N
, std::move(g2
));
275 // Checks the logic for wrapping the given iterator to make sure it works correctly regardless of whether the given
276 // generator class has a const or non-const invocation operator (or both).
277 void test_generators() {
279 constexpr static std::size_t min() { return 0; }
280 constexpr static std::size_t max() { return 255; }
282 struct NonconstGen
: GenBase
{
283 std::size_t operator()() { return 1; }
285 struct ConstGen
: GenBase
{
286 std::size_t operator()() const { return 1; }
288 struct ConstAndNonconstGen
: GenBase
{
289 std::size_t operator()() { return 1; }
290 std::size_t operator()() const { return 1; }
293 test_generator
<ConstGen
>();
294 test_generator
<NonconstGen
, /*CheckConst=*/false>();
295 test_generator
<ConstAndNonconstGen
>();
302 { // Stable (if `I` models `forward_iterator`).
303 struct OrderedValue
{
306 bool operator==(const OrderedValue
&) const = default;
307 auto operator<=>(const OrderedValue
& rhs
) const { return value
<=> rhs
.value
; }
310 const std::array
<OrderedValue
, 8> in
= {{
311 {1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}, {1, 7}, {1, 8}
314 { // (iterator, sentinel) overload.
315 std::array
<OrderedValue
, in
.size()> out
;
316 std::ranges::sample(in
.begin(), in
.end(), out
.begin(), in
.size(), RandGen());
320 { // (range) overload.
321 std::array
<OrderedValue
, in
.size()> out
;
322 std::ranges::sample(in
, out
.begin(), in
.size(), RandGen());
328 int main(int, char**) {
330 // Note: `ranges::sample` is not `constexpr`.