@@ -183,6 +183,34 @@ ltm52(n::Int, mask::Int=nextpow(2, n)-1) = LessThan(n-1, Masked(mask, UInt52Raw(
183183
184184# # shuffle & shuffle!
185185
186+ function shuffle (rng:: AbstractRNG , tup:: NTuple{N} ) where {N}
187+ # `@inline` and `@inbounds` are here to help escape analysis eliminate the `Memory` allocation
188+ #
189+ # * `@inline` might be necessary because escape analysis relies on everything
190+ # touching the `Memory` being inlined because there's no interprocedural escape
191+ # analysis yet, relevant WIP PR: https://github.com/JuliaLang/julia/pull/56849
192+ #
193+ # * `@inbounds` might be necessary because escape analysis requires any throws of
194+ # `BoundsError` to be eliminated as dead code, because `BoundsError` stores the
195+ # array itself, making the throw escape the array from the function, relevant
196+ # WIP PR: https://github.com/JuliaLang/julia/pull/56167
197+ @inline let
198+ # use a narrow integer type to save stack space and prevent heap allocation
199+ Ind = if N ≤ typemax (UInt8)
200+ UInt8
201+ elseif N ≤ typemax (UInt16)
202+ UInt16
203+ else
204+ UInt
205+ end
206+ mem = @inbounds randperm! (rng, Memory {Ind} (undef, N))
207+ function closure (i:: Int )
208+ @inbounds tup[mem[i]]
209+ end
210+ ntuple (closure, Val {N} ())
211+ end
212+ end
213+
186214"""
187215 shuffle!([rng=default_rng(),] v::AbstractArray)
188216
@@ -238,13 +266,16 @@ end
238266shuffle! (a:: AbstractArray ) = shuffle! (default_rng (), a)
239267
240268"""
241- shuffle([rng=default_rng(),] v::AbstractArray)
269+ shuffle([rng=default_rng(),] v::Union{NTuple, AbstractArray} )
242270
243271Return a randomly permuted copy of `v`. The optional `rng` argument specifies a random
244272number generator (see [Random Numbers](@ref)).
245273To permute `v` in-place, see [`shuffle!`](@ref). To obtain randomly permuted
246274indices, see [`randperm`](@ref).
247275
276+ !!! compat "Julia 1.13"
277+ Shuffling an `NTuple` value requires Julia v1.13 or above.
278+
248279# Examples
249280```jldoctest
250281julia> shuffle(Xoshiro(123), Vector(1:10))
@@ -261,8 +292,10 @@ julia> shuffle(Xoshiro(123), Vector(1:10))
261292 7
262293```
263294"""
295+ function shuffle end
296+
264297shuffle (r:: AbstractRNG , a:: AbstractArray ) = shuffle! (r, copymutable (a))
265- shuffle (a:: AbstractArray ) = shuffle (default_rng (), a)
298+ shuffle (a:: Union{NTuple, AbstractArray} ) = shuffle (default_rng (), a)
266299
267300shuffle (r:: AbstractRNG , a:: Base.OneTo ) = randperm (r, last (a))
268301
0 commit comments