114cf74d6SKonstantin Varlamov //===----------------------------------------------------------------------===//
214cf74d6SKonstantin Varlamov //
314cf74d6SKonstantin Varlamov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
414cf74d6SKonstantin Varlamov // See https://llvm.org/LICENSE.txt for license information.
514cf74d6SKonstantin Varlamov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
614cf74d6SKonstantin Varlamov //
714cf74d6SKonstantin Varlamov //===----------------------------------------------------------------------===//
814cf74d6SKonstantin Varlamov 
914cf74d6SKonstantin Varlamov // UNSUPPORTED: c++03, c++11, c++14, c++17
1014cf74d6SKonstantin Varlamov 
1114cf74d6SKonstantin Varlamov // <algorithm>
1214cf74d6SKonstantin Varlamov 
1314cf74d6SKonstantin Varlamov // template<random_access_iterator I, sentinel_for<I> S, class Gen>
1414cf74d6SKonstantin Varlamov //   requires permutable<I> &&
1514cf74d6SKonstantin Varlamov //            uniform_random_bit_generator<remove_reference_t<Gen>>
1614cf74d6SKonstantin Varlamov //   I shuffle(I first, S last, Gen&& g);                                                           // Since C++20
1714cf74d6SKonstantin Varlamov //
1814cf74d6SKonstantin Varlamov // template<random_access_range R, class Gen>
1914cf74d6SKonstantin Varlamov //   requires permutable<iterator_t<R>> &&
2014cf74d6SKonstantin Varlamov //            uniform_random_bit_generator<remove_reference_t<Gen>>
2114cf74d6SKonstantin Varlamov //   borrowed_iterator_t<R> shuffle(R&& r, Gen&& g);                                                // Since C++20
2214cf74d6SKonstantin Varlamov 
2314cf74d6SKonstantin Varlamov #include <algorithm>
2414cf74d6SKonstantin Varlamov #include <array>
2514cf74d6SKonstantin Varlamov #include <concepts>
2614cf74d6SKonstantin Varlamov #include <functional>
2714cf74d6SKonstantin Varlamov #include <random>
2814cf74d6SKonstantin Varlamov #include <ranges>
2914cf74d6SKonstantin Varlamov #include <utility>
3014cf74d6SKonstantin Varlamov 
3114cf74d6SKonstantin Varlamov #include "almost_satisfies_types.h"
3214cf74d6SKonstantin Varlamov #include "test_iterators.h"
3314cf74d6SKonstantin Varlamov #include "test_macros.h"
3414cf74d6SKonstantin Varlamov 
3514cf74d6SKonstantin Varlamov class RandGen {
3614cf74d6SKonstantin Varlamov public:
min()37*fb855eb9SMark de Wever   constexpr static std::size_t min() { return 0; }
max()38*fb855eb9SMark de Wever   constexpr static std::size_t max() { return 255; }
3914cf74d6SKonstantin Varlamov 
operator ()()40*fb855eb9SMark de Wever   constexpr std::size_t operator()() {
4114cf74d6SKonstantin Varlamov     flip = !flip;
4214cf74d6SKonstantin Varlamov     return flip;
4314cf74d6SKonstantin Varlamov   }
4414cf74d6SKonstantin Varlamov 
4514cf74d6SKonstantin Varlamov private:
4614cf74d6SKonstantin Varlamov   bool flip = false;
4714cf74d6SKonstantin Varlamov };
4814cf74d6SKonstantin Varlamov 
4914cf74d6SKonstantin Varlamov static_assert(std::uniform_random_bit_generator<RandGen>);
5014cf74d6SKonstantin Varlamov // `std::uniform_random_bit_generator` is a subset of requirements of `__libcpp_random_is_valid_urng`. Make sure that
5114cf74d6SKonstantin Varlamov // a type satisfying the required minimum is still accepted by `ranges::shuffle`.
5214cf74d6SKonstantin Varlamov LIBCPP_STATIC_ASSERT(!std::__libcpp_random_is_valid_urng<RandGen>::value);
5314cf74d6SKonstantin Varlamov 
5414cf74d6SKonstantin Varlamov struct BadGen {
minBadGen55*fb855eb9SMark de Wever   constexpr static std::size_t min() { return 255; }
maxBadGen56*fb855eb9SMark de Wever   constexpr static std::size_t max() { return 0; }
57*fb855eb9SMark de Wever   constexpr std::size_t operator()() const;
5814cf74d6SKonstantin Varlamov };
5914cf74d6SKonstantin Varlamov static_assert(!std::uniform_random_bit_generator<BadGen>);
6014cf74d6SKonstantin Varlamov 
6114cf74d6SKonstantin Varlamov // Test constraints of the (iterator, sentinel) overload.
6214cf74d6SKonstantin Varlamov // ======================================================
6314cf74d6SKonstantin Varlamov 
6414cf74d6SKonstantin Varlamov template <class Iter = int*, class Sent = int*, class Gen = RandGen>
6514cf74d6SKonstantin Varlamov concept HasShuffleIter =
6614cf74d6SKonstantin Varlamov     requires(Iter&& iter, Sent&& sent, Gen&& gen) {
6714cf74d6SKonstantin Varlamov       std::ranges::shuffle(std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Gen>(gen));
6814cf74d6SKonstantin Varlamov     };
6914cf74d6SKonstantin Varlamov 
7014cf74d6SKonstantin Varlamov static_assert(HasShuffleIter<int*, int*, RandGen>);
7114cf74d6SKonstantin Varlamov 
7214cf74d6SKonstantin Varlamov // !random_access_iterator<I>
7314cf74d6SKonstantin Varlamov static_assert(!HasShuffleIter<RandomAccessIteratorNotDerivedFrom>);
7414cf74d6SKonstantin Varlamov static_assert(!HasShuffleIter<RandomAccessIteratorBadIndex>);
7514cf74d6SKonstantin Varlamov 
7614cf74d6SKonstantin Varlamov // !sentinel_for<S, I>
7714cf74d6SKonstantin Varlamov static_assert(!HasShuffleIter<int*, SentinelForNotSemiregular>);
7814cf74d6SKonstantin Varlamov static_assert(!HasShuffleIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
7914cf74d6SKonstantin Varlamov 
8014cf74d6SKonstantin Varlamov // !permutable<I>
8114cf74d6SKonstantin Varlamov static_assert(!HasShuffleIter<PermutableNotForwardIterator>);
8214cf74d6SKonstantin Varlamov static_assert(!HasShuffleIter<PermutableNotSwappable>);
8314cf74d6SKonstantin Varlamov 
8414cf74d6SKonstantin Varlamov // !uniform_random_bit_generator<remove_reference_t<Gen>>
8514cf74d6SKonstantin Varlamov static_assert(!HasShuffleIter<int*, int*, BadGen>);
8614cf74d6SKonstantin Varlamov 
8714cf74d6SKonstantin Varlamov // Test constraints of the (range) overload.
8814cf74d6SKonstantin Varlamov // =========================================
8914cf74d6SKonstantin Varlamov 
9014cf74d6SKonstantin Varlamov template <class Range, class Gen = RandGen>
9114cf74d6SKonstantin Varlamov concept HasShuffleRange =
9214cf74d6SKonstantin Varlamov     requires(Range&& range, Gen&& gen) {
9314cf74d6SKonstantin Varlamov       std::ranges::shuffle(std::forward<Range>(range), std::forward<Gen>(gen));
9414cf74d6SKonstantin Varlamov     };
9514cf74d6SKonstantin Varlamov 
9614cf74d6SKonstantin Varlamov template <class T>
9714cf74d6SKonstantin Varlamov using R = UncheckedRange<T>;
9814cf74d6SKonstantin Varlamov 
9914cf74d6SKonstantin Varlamov static_assert(HasShuffleRange<R<int*>, RandGen>);
10014cf74d6SKonstantin Varlamov 
10114cf74d6SKonstantin Varlamov // !random_access_range<R>
10214cf74d6SKonstantin Varlamov static_assert(!HasShuffleRange<RandomAccessRangeNotDerivedFrom>);
10314cf74d6SKonstantin Varlamov static_assert(!HasShuffleRange<RandomAccessRangeBadIndex>);
10414cf74d6SKonstantin Varlamov 
10514cf74d6SKonstantin Varlamov // !permutable<iterator_t<R>>
10614cf74d6SKonstantin Varlamov static_assert(!HasShuffleRange<PermutableNotForwardIterator>);
10714cf74d6SKonstantin Varlamov static_assert(!HasShuffleRange<PermutableNotSwappable>);
10814cf74d6SKonstantin Varlamov 
10914cf74d6SKonstantin Varlamov // !uniform_random_bit_generator<remove_reference_t<Gen>>
11014cf74d6SKonstantin Varlamov static_assert(!HasShuffleRange<R<int*>, BadGen>);
11114cf74d6SKonstantin Varlamov 
112*fb855eb9SMark de Wever template <class Iter, class Sent, std::size_t N, class Gen>
test_one(const std::array<int,N> input,Gen gen)11314cf74d6SKonstantin Varlamov void test_one(const std::array<int, N> input, Gen gen) {
11414cf74d6SKonstantin Varlamov   { // (iterator, sentinel) overload.
11514cf74d6SKonstantin Varlamov     auto shuffled = input;
11614cf74d6SKonstantin Varlamov     auto begin = Iter(shuffled.data());
11714cf74d6SKonstantin Varlamov     auto end = Sent(Iter(shuffled.data() + shuffled.size()));
11814cf74d6SKonstantin Varlamov 
11914cf74d6SKonstantin Varlamov     std::same_as<Iter> decltype(auto) result = std::ranges::shuffle(begin, end, gen);
12014cf74d6SKonstantin Varlamov 
12114cf74d6SKonstantin Varlamov     assert(result == Iter(shuffled.data() + shuffled.size()));
12214cf74d6SKonstantin Varlamov     // TODO(ranges): uncomment `ranges::is_permutation` once https://reviews.llvm.org/D127194 lands and remove sorting.
12314cf74d6SKonstantin Varlamov     //assert(std::ranges::is_permutation(shuffled, input);
12414cf74d6SKonstantin Varlamov     {
12514cf74d6SKonstantin Varlamov       auto shuffled_sorted = shuffled;
12614cf74d6SKonstantin Varlamov       std::ranges::sort(shuffled_sorted);
12714cf74d6SKonstantin Varlamov       auto original_sorted = input;
12814cf74d6SKonstantin Varlamov       std::ranges::sort(original_sorted);
12914cf74d6SKonstantin Varlamov       assert(shuffled_sorted == original_sorted);
13014cf74d6SKonstantin Varlamov     }
13114cf74d6SKonstantin Varlamov   }
13214cf74d6SKonstantin Varlamov 
13314cf74d6SKonstantin Varlamov   { // (range) overload.
13414cf74d6SKonstantin Varlamov     auto shuffled = input;
13514cf74d6SKonstantin Varlamov     auto begin = Iter(shuffled.data());
13614cf74d6SKonstantin Varlamov     auto end = Sent(Iter(shuffled.data() + shuffled.size()));
13714cf74d6SKonstantin Varlamov     auto range = std::ranges::subrange(begin, end);
13814cf74d6SKonstantin Varlamov 
13914cf74d6SKonstantin Varlamov     std::same_as<Iter> decltype(auto) result = std::ranges::shuffle(range, gen);
14014cf74d6SKonstantin Varlamov 
14114cf74d6SKonstantin Varlamov     assert(result == Iter(shuffled.data() + shuffled.size()));
14214cf74d6SKonstantin Varlamov     // TODO(ranges): uncomment `ranges::is_permutation` once https://reviews.llvm.org/D127194 lands and remove sorting.
14314cf74d6SKonstantin Varlamov     //assert(std::ranges::is_permutation(shuffled, input);
14414cf74d6SKonstantin Varlamov     {
14514cf74d6SKonstantin Varlamov       auto shuffled_sorted = shuffled;
14614cf74d6SKonstantin Varlamov       std::ranges::sort(shuffled_sorted);
14714cf74d6SKonstantin Varlamov       auto original_sorted = input;
14814cf74d6SKonstantin Varlamov       std::ranges::sort(original_sorted);
14914cf74d6SKonstantin Varlamov       assert(shuffled_sorted == original_sorted);
15014cf74d6SKonstantin Varlamov     }
15114cf74d6SKonstantin Varlamov   }
15214cf74d6SKonstantin Varlamov }
15314cf74d6SKonstantin Varlamov 
15414cf74d6SKonstantin Varlamov template <class Iter, class Sent>
test_iterators_iter_sent()15514cf74d6SKonstantin Varlamov void test_iterators_iter_sent() {
15614cf74d6SKonstantin Varlamov   RandGen gen;
15714cf74d6SKonstantin Varlamov 
15814cf74d6SKonstantin Varlamov   // Empty sequence.
15914cf74d6SKonstantin Varlamov   test_one<Iter, Sent, 0>({}, gen);
16014cf74d6SKonstantin Varlamov   // 1-element sequence.
16114cf74d6SKonstantin Varlamov   test_one<Iter, Sent, 1>({1}, gen);
16214cf74d6SKonstantin Varlamov   // 2-element sequence.
16314cf74d6SKonstantin Varlamov   test_one<Iter, Sent, 2>({2, 1}, gen);
16414cf74d6SKonstantin Varlamov   // 3-element sequence.
16514cf74d6SKonstantin Varlamov   test_one<Iter, Sent, 3>({2, 1, 3}, gen);
16614cf74d6SKonstantin Varlamov   // Longer sequence.
16714cf74d6SKonstantin Varlamov   test_one<Iter, Sent, 8>({2, 1, 3, 6, 8, 4, 11, 5}, gen);
16814cf74d6SKonstantin Varlamov   // Longer sequence with duplicates.
16914cf74d6SKonstantin Varlamov   test_one<Iter, Sent, 8>({2, 1, 3, 6, 2, 8, 1, 6}, gen);
17014cf74d6SKonstantin Varlamov   // All elements are the same.
17114cf74d6SKonstantin Varlamov   test_one<Iter, Sent, 3>({1, 1, 1}, gen);
17214cf74d6SKonstantin Varlamov }
17314cf74d6SKonstantin Varlamov 
17414cf74d6SKonstantin Varlamov template <class Iter>
test_iterators_iter()17514cf74d6SKonstantin Varlamov void test_iterators_iter() {
17614cf74d6SKonstantin Varlamov   test_iterators_iter_sent<Iter, Iter>();
17714cf74d6SKonstantin Varlamov   test_iterators_iter_sent<Iter, sentinel_wrapper<Iter>>();
17814cf74d6SKonstantin Varlamov }
17914cf74d6SKonstantin Varlamov 
test_iterators()18014cf74d6SKonstantin Varlamov void test_iterators() {
18114cf74d6SKonstantin Varlamov   test_iterators_iter<random_access_iterator<int*>>();
18214cf74d6SKonstantin Varlamov   test_iterators_iter<contiguous_iterator<int*>>();
18314cf74d6SKonstantin Varlamov   test_iterators_iter<int*>();
18414cf74d6SKonstantin Varlamov }
18514cf74d6SKonstantin Varlamov 
18614cf74d6SKonstantin Varlamov // Checks the logic for wrapping the given iterator to make sure it works correctly regardless of the value category of
18714cf74d6SKonstantin Varlamov // the given generator object.
18814cf74d6SKonstantin Varlamov template <class Gen, bool CheckConst = true>
test_generator()18914cf74d6SKonstantin Varlamov void test_generator() {
19014cf74d6SKonstantin Varlamov   std::array in = {1, 2, 3, 4, 5, 6, 7, 8};
19114cf74d6SKonstantin Varlamov   auto begin = in.begin();
19214cf74d6SKonstantin Varlamov   auto end = in.end();
19314cf74d6SKonstantin Varlamov 
19414cf74d6SKonstantin Varlamov   { // Lvalue.
19514cf74d6SKonstantin Varlamov     Gen g;
19614cf74d6SKonstantin Varlamov     std::ranges::shuffle(begin, end, g);
19714cf74d6SKonstantin Varlamov     std::ranges::shuffle(in, g);
19814cf74d6SKonstantin Varlamov   }
19914cf74d6SKonstantin Varlamov 
20014cf74d6SKonstantin Varlamov   if constexpr (CheckConst) { // Const lvalue.
20114cf74d6SKonstantin Varlamov     const Gen g;
20214cf74d6SKonstantin Varlamov     std::ranges::shuffle(begin, end, g);
20314cf74d6SKonstantin Varlamov     std::ranges::shuffle(in, g);
20414cf74d6SKonstantin Varlamov   }
20514cf74d6SKonstantin Varlamov 
20614cf74d6SKonstantin Varlamov   { // Prvalue.
20714cf74d6SKonstantin Varlamov     std::ranges::shuffle(begin, end, Gen());
20814cf74d6SKonstantin Varlamov     std::ranges::shuffle(in, Gen());
20914cf74d6SKonstantin Varlamov   }
21014cf74d6SKonstantin Varlamov 
21114cf74d6SKonstantin Varlamov   { // Xvalue.
21214cf74d6SKonstantin Varlamov     Gen g1, g2;
21314cf74d6SKonstantin Varlamov     std::ranges::shuffle(begin, end, std::move(g1));
21414cf74d6SKonstantin Varlamov     std::ranges::shuffle(in, std::move(g2));
21514cf74d6SKonstantin Varlamov   }
21614cf74d6SKonstantin Varlamov }
21714cf74d6SKonstantin Varlamov 
21814cf74d6SKonstantin Varlamov // Checks the logic for wrapping the given iterator to make sure it works correctly regardless of whether the given
21914cf74d6SKonstantin Varlamov // generator class has a const or non-const invocation operator (or both).
test_generators()22014cf74d6SKonstantin Varlamov void test_generators() {
22114cf74d6SKonstantin Varlamov   struct GenBase {
222*fb855eb9SMark de Wever     constexpr static std::size_t min() { return 0; }
223*fb855eb9SMark de Wever     constexpr static std::size_t max() { return 255; }
22414cf74d6SKonstantin Varlamov   };
22514cf74d6SKonstantin Varlamov   struct NonconstGen : GenBase {
226*fb855eb9SMark de Wever     std::size_t operator()() { return 1; }
22714cf74d6SKonstantin Varlamov   };
22814cf74d6SKonstantin Varlamov   struct ConstGen : GenBase {
229*fb855eb9SMark de Wever     std::size_t operator()() const { return 1; }
23014cf74d6SKonstantin Varlamov   };
23114cf74d6SKonstantin Varlamov   struct ConstAndNonconstGen : GenBase {
232*fb855eb9SMark de Wever     std::size_t operator()() { return 1; }
233*fb855eb9SMark de Wever     std::size_t operator()() const { return 1; }
23414cf74d6SKonstantin Varlamov   };
23514cf74d6SKonstantin Varlamov 
23614cf74d6SKonstantin Varlamov   test_generator<ConstGen>();
23714cf74d6SKonstantin Varlamov   test_generator<NonconstGen, /*CheckConst=*/false>();
23814cf74d6SKonstantin Varlamov   test_generator<ConstAndNonconstGen>();
23914cf74d6SKonstantin Varlamov }
24014cf74d6SKonstantin Varlamov 
test()24114cf74d6SKonstantin Varlamov void test() {
24214cf74d6SKonstantin Varlamov   test_iterators();
24314cf74d6SKonstantin Varlamov   test_generators();
24414cf74d6SKonstantin Varlamov 
24514cf74d6SKonstantin Varlamov   { // Complexity: Exactly `(last - first) - 1` swaps.
24614cf74d6SKonstantin Varlamov     {
24714cf74d6SKonstantin Varlamov       std::array in = {-2, -5, -8, -11, -10, -5, 1, 3, 9, 6, 8, 2, 4, 2}; //14
24814cf74d6SKonstantin Varlamov 
24914cf74d6SKonstantin Varlamov       int swaps = 0;
25014cf74d6SKonstantin Varlamov       auto begin = adl::Iterator::TrackSwaps(in.data(), swaps);
25114cf74d6SKonstantin Varlamov       auto end = adl::Iterator::TrackSwaps(in.data() + in.size(), swaps);
25214cf74d6SKonstantin Varlamov 
25314cf74d6SKonstantin Varlamov       std::ranges::shuffle(begin, end, RandGen());
25414cf74d6SKonstantin Varlamov       int expected = in.size() - 1;
25514cf74d6SKonstantin Varlamov       // Note: our implementation doesn't perform a swap when the distribution returns 0, so the actual number of swaps
25614cf74d6SKonstantin Varlamov       // might be less than specified in the standard.
25714cf74d6SKonstantin Varlamov       assert(swaps <= expected);
25814cf74d6SKonstantin Varlamov       swaps = 0;
25914cf74d6SKonstantin Varlamov     }
26014cf74d6SKonstantin Varlamov   }
26114cf74d6SKonstantin Varlamov }
26214cf74d6SKonstantin Varlamov 
main(int,char **)26314cf74d6SKonstantin Varlamov int main(int, char**) {
26414cf74d6SKonstantin Varlamov   test();
26514cf74d6SKonstantin Varlamov   // Note: `ranges::shuffle` is not `constexpr`.
26614cf74d6SKonstantin Varlamov 
26714cf74d6SKonstantin Varlamov   return 0;
26814cf74d6SKonstantin Varlamov }
269