xref: /llvm-project/libcxx/include/__algorithm/shuffle.h (revision e99c4906e44ae3f921fa05356909d006cda8d954)
1134723edSLouis Dionne //===----------------------------------------------------------------------===//
2134723edSLouis Dionne //
3134723edSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4134723edSLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
5134723edSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6134723edSLouis Dionne //
7134723edSLouis Dionne //===----------------------------------------------------------------------===//
8134723edSLouis Dionne 
9134723edSLouis Dionne #ifndef _LIBCPP___ALGORITHM_SHUFFLE_H
10134723edSLouis Dionne #define _LIBCPP___ALGORITHM_SHUFFLE_H
11134723edSLouis Dionne 
12a7c3379cSKonstantin Varlamov #include <__algorithm/iterator_operations.h>
13134723edSLouis Dionne #include <__config>
14*e99c4906SNikolas Klauser #include <__cstddef/ptrdiff_t.h>
15134723edSLouis Dionne #include <__iterator/iterator_traits.h>
16134723edSLouis Dionne #include <__random/uniform_int_distribution.h>
17a7c3379cSKonstantin Varlamov #include <__utility/forward.h>
18a7c3379cSKonstantin Varlamov #include <__utility/move.h>
19430b397fSNikolas Klauser #include <__utility/swap.h>
20134723edSLouis Dionne #include <cstdint>
21134723edSLouis Dionne 
22134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
23134723edSLouis Dionne #  pragma GCC system_header
24134723edSLouis Dionne #endif
25134723edSLouis Dionne 
26134723edSLouis Dionne _LIBCPP_PUSH_MACROS
27134723edSLouis Dionne #include <__undef_macros>
28134723edSLouis Dionne 
29134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD
30134723edSLouis Dionne 
31f1ea0b11SNikolas Klauser class _LIBCPP_EXPORTED_FROM_ABI __libcpp_debug_randomizer {
32a45d2287SDanila Kutenin public:
3383ce1397SNikolas Klauser   _LIBCPP_HIDE_FROM_ABI __libcpp_debug_randomizer() {
3484fc2c3cSNikolas Klauser     __state_ = __seed();
3584fc2c3cSNikolas Klauser     __inc_   = __state_ + 0xda3e39cb94b95bdbULL;
3684fc2c3cSNikolas Klauser     __inc_   = (__inc_ << 1) | 1;
37a45d2287SDanila Kutenin   }
38a45d2287SDanila Kutenin   typedef uint_fast32_t result_type;
39a45d2287SDanila Kutenin 
40a45d2287SDanila Kutenin   static const result_type _Min = 0;
41a45d2287SDanila Kutenin   static const result_type _Max = 0xFFFFFFFF;
42a45d2287SDanila Kutenin 
43a45d2287SDanila Kutenin   _LIBCPP_HIDE_FROM_ABI result_type operator()() {
4484fc2c3cSNikolas Klauser     uint_fast64_t __oldstate = __state_;
4584fc2c3cSNikolas Klauser     __state_                 = __oldstate * 6364136223846793005ULL + __inc_;
46a45d2287SDanila Kutenin     return __oldstate >> 32;
47a45d2287SDanila Kutenin   }
48a45d2287SDanila Kutenin 
49a45d2287SDanila Kutenin   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR result_type min() { return _Min; }
50a45d2287SDanila Kutenin   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR result_type max() { return _Max; }
51a45d2287SDanila Kutenin 
52a45d2287SDanila Kutenin private:
5384fc2c3cSNikolas Klauser   uint_fast64_t __state_;
5484fc2c3cSNikolas Klauser   uint_fast64_t __inc_;
55a45d2287SDanila Kutenin   _LIBCPP_HIDE_FROM_ABI static uint_fast64_t __seed() {
56a45d2287SDanila Kutenin #ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY_SEED
57a45d2287SDanila Kutenin     return _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY_SEED;
58a45d2287SDanila Kutenin #else
59a45d2287SDanila Kutenin     static char __x;
60a45d2287SDanila Kutenin     return reinterpret_cast<uintptr_t>(&__x);
61a45d2287SDanila Kutenin #endif
62a45d2287SDanila Kutenin   }
63a45d2287SDanila Kutenin };
64a45d2287SDanila Kutenin 
659783f28cSLouis Dionne #if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_RANDOM_SHUFFLE) || defined(_LIBCPP_BUILDING_LIBRARY)
66f1ea0b11SNikolas Klauser class _LIBCPP_EXPORTED_FROM_ABI __rs_default;
67134723edSLouis Dionne 
68f1ea0b11SNikolas Klauser _LIBCPP_EXPORTED_FROM_ABI __rs_default __rs_get();
69134723edSLouis Dionne 
709783f28cSLouis Dionne class _LIBCPP_EXPORTED_FROM_ABI __rs_default {
71134723edSLouis Dionne   static unsigned __c_;
72134723edSLouis Dionne 
73134723edSLouis Dionne   __rs_default();
749783f28cSLouis Dionne 
75134723edSLouis Dionne public:
76134723edSLouis Dionne   typedef uint_fast32_t result_type;
77134723edSLouis Dionne 
78134723edSLouis Dionne   static const result_type _Min = 0;
79134723edSLouis Dionne   static const result_type _Max = 0xFFFFFFFF;
80134723edSLouis Dionne 
81134723edSLouis Dionne   __rs_default(const __rs_default&);
82134723edSLouis Dionne   ~__rs_default();
83134723edSLouis Dionne 
84134723edSLouis Dionne   result_type operator()();
85134723edSLouis Dionne 
8683ce1397SNikolas Klauser   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR result_type min() { return _Min; }
8783ce1397SNikolas Klauser   static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR result_type max() { return _Max; }
88134723edSLouis Dionne 
89f1ea0b11SNikolas Klauser   friend _LIBCPP_EXPORTED_FROM_ABI __rs_default __rs_get();
90134723edSLouis Dionne };
91134723edSLouis Dionne 
92f1ea0b11SNikolas Klauser _LIBCPP_EXPORTED_FROM_ABI __rs_default __rs_get();
93134723edSLouis Dionne 
94134723edSLouis Dionne template <class _RandomAccessIterator>
9580c7e93aSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX14 void
969783f28cSLouis Dionne random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last) {
97134723edSLouis Dionne   typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
98134723edSLouis Dionne   typedef uniform_int_distribution<ptrdiff_t> _Dp;
99134723edSLouis Dionne   typedef typename _Dp::param_type _Pp;
100134723edSLouis Dionne   difference_type __d = __last - __first;
1019783f28cSLouis Dionne   if (__d > 1) {
102134723edSLouis Dionne     _Dp __uid;
103134723edSLouis Dionne     __rs_default __g = __rs_get();
1049783f28cSLouis Dionne     for (--__last, (void)--__d; __first < __last; ++__first, (void)--__d) {
105134723edSLouis Dionne       difference_type __i = __uid(__g, _Pp(0, __d));
106134723edSLouis Dionne       if (__i != difference_type(0))
107134723edSLouis Dionne         swap(*__first, *(__first + __i));
108134723edSLouis Dionne     }
109134723edSLouis Dionne   }
110134723edSLouis Dionne }
111134723edSLouis Dionne 
112134723edSLouis Dionne template <class _RandomAccessIterator, class _RandomNumberGenerator>
11380c7e93aSNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_DEPRECATED_IN_CXX14 void
1149783f28cSLouis Dionne random_shuffle(_RandomAccessIterator __first,
1159783f28cSLouis Dionne                _RandomAccessIterator __last,
116134723edSLouis Dionne #  ifndef _LIBCPP_CXX03_LANG
117134723edSLouis Dionne                _RandomNumberGenerator&& __rand)
118134723edSLouis Dionne #  else
119134723edSLouis Dionne                _RandomNumberGenerator& __rand)
120134723edSLouis Dionne #  endif
121134723edSLouis Dionne {
122134723edSLouis Dionne   typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
123134723edSLouis Dionne   difference_type __d = __last - __first;
1249783f28cSLouis Dionne   if (__d > 1) {
1259783f28cSLouis Dionne     for (--__last; __first < __last; ++__first, (void)--__d) {
126134723edSLouis Dionne       difference_type __i = __rand(__d);
127134723edSLouis Dionne       if (__i != difference_type(0))
128134723edSLouis Dionne         swap(*__first, *(__first + __i));
129134723edSLouis Dionne     }
130134723edSLouis Dionne   }
131134723edSLouis Dionne }
132134723edSLouis Dionne #endif
133134723edSLouis Dionne 
13414cf74d6SKonstantin Varlamov template <class _AlgPolicy, class _RandomAccessIterator, class _Sentinel, class _UniformRandomNumberGenerator>
1359783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _RandomAccessIterator
1369783f28cSLouis Dionne __shuffle(_RandomAccessIterator __first, _Sentinel __last_sentinel, _UniformRandomNumberGenerator&& __g) {
137134723edSLouis Dionne   typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
138134723edSLouis Dionne   typedef uniform_int_distribution<ptrdiff_t> _Dp;
139134723edSLouis Dionne   typedef typename _Dp::param_type _Pp;
14014cf74d6SKonstantin Varlamov 
14114cf74d6SKonstantin Varlamov   auto __original_last = _IterOps<_AlgPolicy>::next(__first, __last_sentinel);
14214cf74d6SKonstantin Varlamov   auto __last          = __original_last;
143134723edSLouis Dionne   difference_type __d  = __last - __first;
1449783f28cSLouis Dionne   if (__d > 1) {
145134723edSLouis Dionne     _Dp __uid;
1469783f28cSLouis Dionne     for (--__last, (void)--__d; __first < __last; ++__first, (void)--__d) {
147134723edSLouis Dionne       difference_type __i = __uid(__g, _Pp(0, __d));
148134723edSLouis Dionne       if (__i != difference_type(0))
149a7c3379cSKonstantin Varlamov         _IterOps<_AlgPolicy>::iter_swap(__first, __first + __i);
150134723edSLouis Dionne     }
151134723edSLouis Dionne   }
15214cf74d6SKonstantin Varlamov 
15314cf74d6SKonstantin Varlamov   return __original_last;
154134723edSLouis Dionne }
155134723edSLouis Dionne 
156a7c3379cSKonstantin Varlamov template <class _RandomAccessIterator, class _UniformRandomNumberGenerator>
15780c7e93aSNikolas Klauser _LIBCPP_HIDE_FROM_ABI void
15880c7e93aSNikolas Klauser shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last, _UniformRandomNumberGenerator&& __g) {
15914cf74d6SKonstantin Varlamov   (void)std::__shuffle<_ClassicAlgPolicy>(
160a7c3379cSKonstantin Varlamov       std::move(__first), std::move(__last), std::forward<_UniformRandomNumberGenerator>(__g));
161a7c3379cSKonstantin Varlamov }
162a7c3379cSKonstantin Varlamov 
163134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD
164134723edSLouis Dionne 
165134723edSLouis Dionne _LIBCPP_POP_MACROS
166134723edSLouis Dionne 
167134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_SHUFFLE_H
168