• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37917

27 Sep 2024 02:34AM UTC coverage: 87.243% (-0.5%) from 87.72%
#37917

push

local

web-flow
inference: add missing `TypeVar` handling for `instanceof_tfunc` (#55884)

I thought these sort of problems had been addressed by d60f92c, but it
seems some were missed. Specifically, `t.a` and `t.b` from `t::Union`
could be `TypeVar`, and if they are passed to a subroutine or recursed
without being unwrapped or rewrapped, errors like JuliaLang/julia#55882
could occur.

This commit resolves the issue by calling `unwraptv` in the `Union`
handling within `instanceof_tfunc`. I also found a similar issue inside
`nfields_tfunc`, so that has also been fixed, and test cases have been
added. While I haven't been able to make up a test case specifically for
the fix in `instanceof_tfunc`, I have confirmed that this commit
certainly fixes the issue reported in JuliaLang/julia#55882.

- fixes JuliaLang/julia#55882

4 of 4 new or added lines in 1 file covered. (100.0%)

448 existing lines in 25 files now uncovered.

77170 of 88454 relevant lines covered (87.24%)

16041082.61 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.91
/stdlib/Random/src/generation.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
# Uniform random generation
4

5
# This file contains the creation of Sampler objects and the associated generation of
6
# random values from them. More specifically, given the specification S of a set
7
# of values to pick from (e.g. 1:10, or "a string"), we define
8
#
9
# 1) Sampler(rng, S, ::Repetition) -> sampler
10
# 2) rand(rng, sampler) -> random value
11
#
12
# Note that the 1) is automated when the sampler is not intended to carry information,
13
# i.e. the default fall-backs SamplerType and SamplerTrivial are used.
14

15
## from types: rand(::Type, [dims...])
16

17
### random floats
18

19
Sampler(::Type{RNG}, ::Type{T}, n::Repetition) where {RNG<:AbstractRNG,T<:AbstractFloat} =
46,589,668✔
20
    Sampler(RNG, CloseOpen01(T), n)
21

22
# generic random generation function which can be used by RNG implementers
23
# it is not defined as a fallback rand method as this could create ambiguities
24

25
rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen01{Float16}}) =
6,703✔
26
    Float16(reinterpret(Float32,
27
                        (rand(r, UInt10(UInt32)) << 13)  | 0x3f800000) - 1)
28

29
rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen01{Float32}}) =
6,647✔
30
    reinterpret(Float32, rand(r, UInt23()) | 0x3f800000) - 1
31

32
rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen12_64}) =
44,884✔
33
    reinterpret(Float64, 0x3ff0000000000000 | rand(r, UInt52()))
34

35
rand(r::AbstractRNG, ::SamplerTrivial{CloseOpen01_64}) = rand(r, CloseOpen12()) - 1.0
411,207✔
36

37
#### BigFloat
38

39
const bits_in_Limb = sizeof(Limb) << 3
40
const Limb_high_bit = one(Limb) << (bits_in_Limb-1)
41

42
struct SamplerBigFloat{I<:FloatInterval{BigFloat}} <: Sampler{BigFloat}
43
    prec::Int
44
    nlimbs::Int
45
    limbs::Vector{Limb}
46
    shift::UInt
47

48
    function SamplerBigFloat{I}(prec::Int) where I<:FloatInterval{BigFloat}
49
        nlimbs = (prec-1) ÷ bits_in_Limb + 1
1,518,825✔
50
        limbs = Vector{Limb}(undef, nlimbs)
3,037,650✔
51
        shift = nlimbs * bits_in_Limb - prec
1,518,825✔
52
        new(prec, nlimbs, limbs, shift)
1,518,825✔
53
    end
54
end
55

56
Sampler(::Type{<:AbstractRNG}, I::FloatInterval{BigFloat}, ::Repetition) =
1,518,825✔
57
    SamplerBigFloat{typeof(I)}(precision(BigFloat))
58

59
function _rand!(rng::AbstractRNG, z::BigFloat, sp::SamplerBigFloat)
1,560,495✔
60
    precision(z) == sp.prec || throw(ArgumentError("incompatible BigFloat precision"))
1,560,497✔
61
    limbs = sp.limbs
1,560,493✔
62
    rand!(rng, limbs)
1,560,493✔
63
    @inbounds begin
1,560,493✔
64
        limbs[1] <<= sp.shift
1,560,493✔
65
        randbool = iszero(limbs[end] & Limb_high_bit)
1,560,493✔
66
        limbs[end] |= Limb_high_bit
1,560,493✔
67
    end
68
    z.sign = 1
1,560,493✔
69
    GC.@preserve limbs unsafe_copyto!(z.d, pointer(limbs), sp.nlimbs)
1,560,493✔
70
    randbool
1,560,493✔
71
end
72

73
function _rand!(rng::AbstractRNG, z::BigFloat, sp::SamplerBigFloat, ::CloseOpen12{BigFloat})
74
    _rand!(rng, z, sp)
3✔
75
    z.exp = 1
2✔
76
    z
2✔
77
end
78

79
function _rand!(rng::AbstractRNG, z::BigFloat, sp::SamplerBigFloat, ::CloseOpen01{BigFloat})
80
    randbool = _rand!(rng, z, sp)
1,560,492✔
81
    z.exp = 0
1,560,491✔
82
    randbool &&
1,560,491✔
83
        ccall((:mpfr_sub_d, :libmpfr), Int32,
84
              (Ref{BigFloat}, Ref{BigFloat}, Cdouble, Base.MPFR.MPFRRoundingMode),
85
              z, z, 0.5, Base.MPFR.ROUNDING_MODE[])
86
    z
1,560,491✔
87
end
88

89
# alternative, with 1 bit less of precision
90
# TODO: make an API for requesting full or not-full precision
91
function _rand!(rng::AbstractRNG, z::BigFloat, sp::SamplerBigFloat, ::CloseOpen01{BigFloat},
×
92
                ::Nothing)
93
    _rand!(rng, z, sp, CloseOpen12(BigFloat))
×
94
    ccall((:mpfr_sub_ui, :libmpfr), Int32, (Ref{BigFloat}, Ref{BigFloat}, Culong, Base.MPFR.MPFRRoundingMode),
×
95
          z, z, 1, Base.MPFR.ROUNDING_MODE[])
96
    z
×
97
end
98

99
rand!(rng::AbstractRNG, z::BigFloat, sp::SamplerBigFloat{T}
×
100
      ) where {T<:FloatInterval{BigFloat}} =
1,560,495✔
101
          _rand!(rng, z, sp, T())
102

103
rand(rng::AbstractRNG, sp::SamplerBigFloat{T}) where {T<:FloatInterval{BigFloat}} =
1,560,491✔
104
    rand!(rng, BigFloat(; precision=sp.prec), sp)
105

106

107
### random integers
108

109
#### UniformBits
110

111
rand(r::AbstractRNG, ::SamplerTrivial{UInt10Raw{UInt16}}) = rand(r, UInt16)
6,703✔
112
rand(r::AbstractRNG, ::SamplerTrivial{UInt23Raw{UInt32}}) = rand(r, UInt32)
6,647✔
113

114
rand(r::AbstractRNG, ::SamplerTrivial{UInt52Raw{UInt64}}) =
5,640✔
115
    _rand52(r, rng_native_52(r))
116

117
_rand52(r::AbstractRNG, ::Type{Float64}) = reinterpret(UInt64, rand(r, CloseOpen12()))
×
118
_rand52(r::AbstractRNG, ::Type{UInt64})  = rand(r, UInt64)
5,640✔
119

120
rand(r::AbstractRNG, ::SamplerTrivial{UInt104Raw{UInt128}}) =
2✔
121
    rand(r, UInt52Raw(UInt128)) << 52 ⊻ rand(r, UInt52Raw(UInt128))
122

123
rand(r::AbstractRNG, ::SamplerTrivial{UInt10{UInt16}})   = rand(r, UInt10Raw())  & 0x03ff
6,703✔
124
rand(r::AbstractRNG, ::SamplerTrivial{UInt23{UInt32}})   = rand(r, UInt23Raw())  & 0x007fffff
6,647✔
125
rand(r::AbstractRNG, ::SamplerTrivial{UInt52{UInt64}})   = rand(r, UInt52Raw())  & 0x000fffffffffffff
6,176✔
126
rand(r::AbstractRNG, ::SamplerTrivial{UInt104{UInt128}}) = rand(r, UInt104Raw()) & 0x000000ffffffffffffffffffffffffff
×
127

128
rand(r::AbstractRNG, sp::SamplerTrivial{<:UniformBits{T}}) where {T} =
81,933✔
129
        rand(r, uint_default(sp[])) % T
130

131
#### BitInteger
132

133
# rand_generic methods are intended to help RNG implementers with common operations
134
# we don't call them simply `rand` as this can easily contribute to create
135
# ambiguities with user-side methods (forcing the user to resort to @eval)
136

137
rand_generic(r::AbstractRNG, T::Union{Bool,Int8,UInt8,Int16,UInt16,Int32,UInt32}) =
×
138
    rand(r, UInt52Raw()) % T[]
139

140
rand_generic(r::AbstractRNG, ::Type{UInt64}) =
×
141
    rand(r, UInt52Raw()) << 32 ⊻ rand(r, UInt52Raw())
142

143
rand_generic(r::AbstractRNG, ::Type{UInt128}) = _rand128(r, rng_native_52(r))
×
144

145
_rand128(r::AbstractRNG, ::Type{UInt64}) =
×
146
    ((rand(r, UInt64) % UInt128) << 64) ⊻ rand(r, UInt64)
147

148
function _rand128(r::AbstractRNG, ::Type{Float64})
×
149
    xor(rand(r, UInt52Raw(UInt128))  << 96,
×
150
        rand(r, UInt52Raw(UInt128))  << 48,
151
        rand(r, UInt52Raw(UInt128)))
152
end
153

154
rand_generic(r::AbstractRNG, ::Type{Int128}) = rand(r, UInt128) % Int128
×
155
rand_generic(r::AbstractRNG, ::Type{Int64})  = rand(r, UInt64) % Int64
×
156

157
### random complex numbers
158

159
rand(r::AbstractRNG, ::SamplerType{Complex{T}}) where {T<:Real} =
173,180✔
160
    complex(rand(r, T), rand(r, T))
161

162
### random characters
163

164
# returns a random valid Unicode scalar value (i.e. 0 - 0xd7ff, 0xe000 - # 0x10ffff)
165
function rand(r::AbstractRNG, ::SamplerType{T}) where {T<:AbstractChar}
6✔
166
    c = rand(r, 0x00000000:0x0010f7ff)
879✔
167
    (c < 0xd800) ? T(c) : T(c+0x800)
927✔
168
end
169

170
### random tuples
171

172
function Sampler(::Type{RNG}, ::Type{T}, n::Repetition) where {T<:Tuple, RNG<:AbstractRNG}
5✔
173
    tail_sp_ = Sampler(RNG, Tuple{Base.tail(fieldtypes(T))...}, n)
76✔
174
    SamplerTag{Ref{T}}((Sampler(RNG, fieldtype(T, 1), n), tail_sp_.data...))
71✔
175
    # Ref so that the gentype is `T` in SamplerTag's constructor
176
end
177

178
function Sampler(::Type{RNG}, ::Type{Tuple{Vararg{T, N}}}, n::Repetition) where {T, N, RNG<:AbstractRNG}
179
    if N > 0
72✔
180
        SamplerTag{Ref{Tuple{Vararg{T, N}}}}((Sampler(RNG, T, n),))
71✔
181
    else
182
        SamplerTag{Ref{Tuple{}}}(())
1✔
183
    end
184
end
185

186
function rand(rng::AbstractRNG, sp::SamplerTag{Ref{T}}) where T<:Tuple
193✔
187
    ntuple(i -> rand(rng, sp.data[min(i, length(sp.data))]), Val{fieldcount(T)}())::T
1,986✔
188
end
189

190
### random pairs
191

192
function Sampler(::Type{RNG}, ::Type{Pair{A, B}}, n::Repetition) where {RNG<:AbstractRNG, A, B}
193
    sp1 = Sampler(RNG, A, n)
32✔
194
    sp2 = A === B ? sp1 : Sampler(RNG, B, n)
32✔
195
    SamplerTag{Ref{Pair{A,B}}}(sp1 => sp2) # Ref so that the gentype is Pair{A, B}
32✔
196
                                           # in SamplerTag's constructor
197
end
198

199
rand(rng::AbstractRNG, sp::SamplerTag{<:Ref{<:Pair}}) =
296✔
200
    rand(rng, sp.data.first) => rand(rng, sp.data.second)
201

202

203
## Generate random integer within a range
204

205
### BitInteger
206

207
# there are three implemented samplers for unit ranges, the second one
208
# assumes that Float64 (i.e. 52 random bits) is the native type for the RNG:
209
# 1) "Fast" (SamplerRangeFast), which is most efficient when the range length is close
210
#    (or equal) to a power of 2 from below.
211
#    The tradeoff is faster creation of the sampler, but more consumption of entropy bits.
212
# 2) "Slow" (SamplerRangeInt) which tries to use as few entropy bits as possible, at the
213
#    cost of a bigger upfront price associated with the creation of the sampler.
214
#    This sampler is most appropriate for slower random generators.
215
# 3) "Nearly Division Less" (NDL) which is generally the fastest algorithm for types of size
216
#    up to 64 bits. This is the default for these types since Julia 1.5.
217
#    The "Fast" algorithm can be faster than NDL when the length of the range is
218
#    less than and close to a power of 2.
219

220
Sampler(::Type{<:AbstractRNG}, r::AbstractUnitRange{T},
×
221
        ::Repetition) where {T<:Base.BitInteger64} = SamplerRangeNDL(r)
5,093,066✔
222

223
Sampler(::Type{<:AbstractRNG}, r::AbstractUnitRange{T},
×
224
        ::Repetition) where {T<:Union{Int128,UInt128}} = SamplerRangeFast(r)
40✔
225

226
#### helper functions
227

228
uint_sup(::Type{<:Base.BitInteger32}) = UInt32
×
229
uint_sup(::Type{<:Union{Int64,UInt64}}) = UInt64
×
230
uint_sup(::Type{<:Union{Int128,UInt128}}) = UInt128
×
231

232
#### Fast
233

234
struct SamplerRangeFast{U<:BitUnsigned,T<:BitInteger} <: Sampler{T}
235
    a::T      # first element of the range
103✔
236
    bw::UInt  # bit width
237
    m::U      # range length - 1
238
    mask::U   # mask generated values before threshold rejection
239
end
240

241
SamplerRangeFast(r::AbstractUnitRange{T}) where T<:BitInteger =
103✔
242
    SamplerRangeFast(r, uint_sup(T))
243

244
function SamplerRangeFast(r::AbstractUnitRange{T}, ::Type{U}) where {T,U}
245
    isempty(r) && throw(ArgumentError("collection must be non-empty"))
103✔
246
    m = (last(r) - first(r)) % unsigned(T) % U # % unsigned(T) to not propagate sign bit
103✔
247
    bw = (Base.top_set_bit(m)) % UInt # bit-width
103✔
248
    mask = ((1 % U) << bw) - (1 % U)
103✔
249
    SamplerRangeFast{U,T}(first(r), bw, m, mask)
103✔
250
end
251

252
function rand(rng::AbstractRNG, sp::SamplerRangeFast{UInt32,T}) where T
36✔
253
    a, bw, m, mask = sp.a, sp.bw, sp.m, sp.mask
36✔
254
    # below, we don't use UInt32, to get reproducible values, whether Int is Int64 or Int32
255
    x = rand(rng, LessThan(m, Masked(mask, UInt52Raw(UInt32))))
37✔
256
    (x + a % UInt32) % T
36✔
257
end
258

259
has_fast_64(rng::AbstractRNG) = rng_native_52(rng) != Float64
73✔
260
# for MersenneTwister, both options have very similar performance
261

262
function rand(rng::AbstractRNG, sp::SamplerRangeFast{UInt64,T}) where T
9✔
263
    a, bw, m, mask = sp.a, sp.bw, sp.m, sp.mask
9✔
264
    if !has_fast_64(rng) && bw <= 52
9✔
265
        x = rand(rng, LessThan(m, Masked(mask, UInt52Raw())))
3✔
266
    else
267
        x = rand(rng, LessThan(m, Masked(mask, uniform(UInt64))))
7✔
268
    end
269
    (x + a % UInt64) % T
9✔
270
end
271

272
function rand(rng::AbstractRNG, sp::SamplerRangeFast{UInt128,T}) where T
34✔
273
    a, bw, m, mask = sp.a, sp.bw, sp.m, sp.mask
64✔
274
    if has_fast_64(rng)
64✔
275
        x = bw <= 64 ?
56✔
276
            rand(rng, LessThan(m % UInt64, Masked(mask % UInt64, uniform(UInt64)))) % UInt128 :
277
            rand(rng, LessThan(m, Masked(mask, uniform(UInt128))))
278
    else
279
        x = bw <= 52  ?
15✔
280
            rand(rng, LessThan(m % UInt64, Masked(mask % UInt64, UInt52Raw()))) % UInt128 :
281
        bw <= 104 ?
282
            rand(rng, LessThan(m, Masked(mask, UInt104Raw()))) :
283
            rand(rng, LessThan(m, Masked(mask, uniform(UInt128))))
284
    end
285
    x % T + a
64✔
286
end
287

288
#### "Slow" / SamplerRangeInt
289

290
# remainder function according to Knuth, where rem_knuth(a, 0) = a
291
rem_knuth(a::UInt, b::UInt) = a % (b + (b == 0)) + a * (b == 0)
9✔
292
rem_knuth(a::T, b::T) where {T<:Unsigned} = b != 0 ? a % b : a
54✔
293

294
# maximum multiple of k <= sup decremented by one,
295
# that is 0xFFFF...FFFF if k = (typemax(T) - typemin(T)) + 1 and sup == typemax(T) - 1
296
# with intentional underflow
297
# see https://stackoverflow.com/questions/29182036/integer-arithmetic-add-1-to-uint-max-and-divide-by-n-without-overflow
298

299
# sup == 0 means typemax(T) + 1
300
maxmultiple(k::T, sup::T=zero(T)) where {T<:Unsigned} =
1,670✔
301
    (div(sup - k, k + (k == 0))*k + k - one(k))::T
302

303
# similar but sup must not be equal to typemax(T)
304
unsafe_maxmultiple(k::T, sup::T) where {T<:Unsigned} =
118✔
305
    div(sup, k + (k == 0))*k - one(k)
306

307
struct SamplerRangeInt{T<:Integer,U<:Unsigned} <: Sampler{T}
308
    a::T      # first element of the range
185✔
309
    bw::Int   # bit width
310
    k::U      # range length or zero for full range
311
    u::U      # rejection threshold
312
end
313

314

315
SamplerRangeInt(r::AbstractUnitRange{T}) where T<:BitInteger =
185✔
316
    SamplerRangeInt(r, uint_sup(T))
317

318
function SamplerRangeInt(r::AbstractUnitRange{T}, ::Type{U}) where {T,U}
18✔
319
    isempty(r) && throw(ArgumentError("collection must be non-empty"))
185✔
320
    a = first(r)
185✔
321
    m = (last(r) - first(r)) % unsigned(T) % U
185✔
322
    k = m + one(U)
185✔
323
    bw = (Base.top_set_bit(m)) % Int
185✔
324
    mult = if U === UInt32
185✔
325
        maxmultiple(k)
36✔
326
    elseif U === UInt64
149✔
327
        bw <= 52 ? unsafe_maxmultiple(k, one(UInt64) << 52) :
156✔
328
                   maxmultiple(k)
329
    else # U === UInt128
330
        bw <= 52  ? unsafe_maxmultiple(k, one(UInt128) << 52) :
24✔
331
        bw <= 104 ? unsafe_maxmultiple(k, one(UInt128) << 104) :
332
                    maxmultiple(k)
333
    end
334

335
    SamplerRangeInt{T,U}(a, bw, k, mult) # overflow ok
185✔
336
end
337

338
rand(rng::AbstractRNG, sp::SamplerRangeInt{T,UInt32}) where {T<:BitInteger} =
36✔
339
    (unsigned(sp.a) + rem_knuth(rand(rng, LessThan(sp.u, UInt52Raw(UInt32))), sp.k)) % T
340

341
# this function uses 52 bit entropy for small ranges of length <= 2^52
342
function rand(rng::AbstractRNG, sp::SamplerRangeInt{T,UInt64}) where T<:BitInteger
9✔
343
    x = sp.bw <= 52 ? rand(rng, LessThan(sp.u, UInt52())) :
10✔
344
                      rand(rng, LessThan(sp.u, uniform(UInt64)))
345
    return ((sp.a % UInt64) + rem_knuth(x, sp.k)) % T
9✔
346
end
347

348
function rand(rng::AbstractRNG, sp::SamplerRangeInt{T,UInt128}) where T<:BitInteger
18✔
349
    x = sp.bw <= 52  ? rand(rng, LessThan(sp.u, UInt52(UInt128))) :
20✔
350
        sp.bw <= 104 ? rand(rng, LessThan(sp.u, UInt104(UInt128))) :
351
                       rand(rng, LessThan(sp.u, uniform(UInt128)))
352
    return ((sp.a % UInt128) + rem_knuth(x, sp.k)) % T
18✔
353
end
354

355
#### Nearly Division Less
356

357
# cf. https://arxiv.org/abs/1805.10941 (algorithm 5)
358

359
struct SamplerRangeNDL{U<:Unsigned,T} <: Sampler{T}
360
    a::T  # first element of the range
5,093,060✔
361
    s::U  # range length or zero for full range
362
end
363

364
function SamplerRangeNDL(r::AbstractUnitRange{T}) where {T}
45✔
365
    isempty(r) && throw(ArgumentError("collection must be non-empty"))
5,093,111✔
366
    a = first(r)
5,092,984✔
367
    U = uint_sup(T)
5,092,984✔
368
    s = (last(r) - first(r)) % unsigned(T) % U + one(U) # overflow ok
5,093,060✔
369
    # mod(-s, s) could be put in the Sampler object for repeated calls, but
370
    # this would be an advantage only for very big s and number of calls
371
    SamplerRangeNDL(a, s)
5,093,060✔
372
end
373

374
function rand(rng::AbstractRNG, sp::SamplerRangeNDL{U,T}) where {U,T}
8,703,238✔
375
    s = sp.s
8,703,238✔
376
    x = widen(rand(rng, U))
8,703,238✔
377
    m = x * s
8,703,238✔
378
    l = m % U
8,703,238✔
379
    if l < s
8,703,238✔
380
        t = mod(-s, s) # as s is unsigned, -s is equal to 2^L - s in the paper
87✔
381
        while l < t
103✔
382
            x = widen(rand(rng, U))
16✔
383
            m = x * s
16✔
384
            l = m % U
16✔
385
        end
16✔
386
    end
387
    (s == 0 ? x : m >> (8*sizeof(U))) % T + sp.a
8,703,238✔
388
end
389

390

391
### BigInt
392

393
struct SamplerBigInt{SP<:Sampler{Limb}} <: Sampler{BigInt}
394
    a::BigInt         # first
72✔
395
    m::BigInt         # range length - 1
396
    nlimbs::Int       # number of limbs in generated BigInt's (z ∈ [0, m])
397
    nlimbsmax::Int    # max number of limbs for z+a
398
    highsp::SP        # sampler for the highest limb of z
399
end
400

401
function SamplerBigInt(::Type{RNG}, r::AbstractUnitRange{BigInt}, N::Repetition=Val(Inf)
1✔
402
                       ) where {RNG<:AbstractRNG}
403
    m = last(r) - first(r)
73✔
404
    m.size < 0 && throw(ArgumentError("collection must be non-empty"))
72✔
405
    nlimbs = Int(m.size)
72✔
406
    hm = nlimbs == 0 ? Limb(0) : GC.@preserve m unsafe_load(m.d, nlimbs)
141✔
407
    highsp = Sampler(RNG, Limb(0):hm, N)
72✔
408
    nlimbsmax = max(nlimbs, abs(last(r).size), abs(first(r).size))
72✔
409
    return SamplerBigInt(first(r), m, nlimbs, nlimbsmax, highsp)
72✔
410
end
411

412
Sampler(::Type{RNG}, r::AbstractUnitRange{BigInt}, N::Repetition) where {RNG<:AbstractRNG} =
136✔
413
    SamplerBigInt(RNG, r, N)
414

415
rand(rng::AbstractRNG, sp::SamplerBigInt) =
8,071✔
416
    rand!(rng, BigInt(nbits = sp.nlimbsmax*8*sizeof(Limb)), sp)
417

418
function rand!(rng::AbstractRNG, x::BigInt, sp::SamplerBigInt)
8,078✔
419
    nlimbs = sp.nlimbs
8,078✔
420
    nlimbs == 0 && return MPZ.set!(x, sp.a)
8,078✔
421
    MPZ.realloc2!(x, sp.nlimbsmax*8*sizeof(Limb))
8,072✔
422
    @assert x.alloc >= nlimbs
8,072✔
423
    # we randomize x ∈ [0, m] with rejection sampling:
424
    # 1. the first nlimbs-1 limbs of x are uniformly randomized
425
    # 2. the high limb hx of x is sampled from 0:hm where hm is the
426
    #    high limb of m
427
    # We repeat 1. and 2. until x <= m
428
    hm = GC.@preserve sp unsafe_load(sp.m.d, nlimbs)
8,072✔
429
    GC.@preserve x begin
8,072✔
430
        limbs = UnsafeView(x.d, nlimbs-1)
8,072✔
431
        while true
8,072✔
432
            rand!(rng, limbs)
8,072✔
433
            hx = limbs[nlimbs] = rand(rng, sp.highsp)
8,072✔
434
            hx < hm && break # avoid calling mpn_cmp most of the time
8,072✔
435
            MPZ.mpn_cmp(x, sp.m, nlimbs) <= 0 && break
1✔
UNCOV
436
        end
×
437
        # adjust x.size (normally done by mpz_limbs_finish, in GMP version >= 6)
438
        while nlimbs > 0
8,074✔
439
            limbs[nlimbs] != 0 && break
8,072✔
440
            nlimbs -= 1
2✔
441
        end
2✔
442
        x.size = nlimbs
8,072✔
443
    end
444
    MPZ.add!(x, sp.a)
8,072✔
445
end
446

447

448
## random values from AbstractArray
449

450
Sampler(::Type{RNG}, r::AbstractArray, n::Repetition) where {RNG<:AbstractRNG} =
1,131,418✔
451
    SamplerSimple(r, Sampler(RNG, firstindex(r):lastindex(r), n))
452

453
rand(rng::AbstractRNG, sp::SamplerSimple{<:AbstractArray,<:Sampler}) =
1,200,227✔
454
    @inbounds return sp[][rand(rng, sp.data)]
455

456

457
## random values from Dict
458

459
function Sampler(::Type{RNG}, t::Dict, ::Repetition) where RNG<:AbstractRNG
460
    isempty(t) && throw(ArgumentError("collection must be non-empty"))
2,025✔
461
    # we use Val(Inf) below as rand is called repeatedly internally
462
    # even for generating only one random value from t
463
    SamplerSimple(t, Sampler(RNG, LinearIndices(t.slots), Val(Inf)))
2,009✔
464
end
465

466
function rand(rng::AbstractRNG, sp::SamplerSimple{<:Dict,<:Sampler})
2,196✔
467
    while true
13,716✔
468
        i = rand(rng, sp.data)
13,716✔
469
        Base.isslotfilled(sp[], i) && @inbounds return (sp[].keys[i] => sp[].vals[i])
13,716✔
470
    end
8,420✔
471
end
472

473
rand(rng::AbstractRNG, sp::SamplerTrivial{<:Base.KeySet{<:Any,<:Dict}}) =
996✔
474
    rand(rng, sp[].dict).first
475

476
rand(rng::AbstractRNG, sp::SamplerTrivial{<:Base.ValueIterator{<:Dict}}) =
684✔
477
    rand(rng, sp[].dict).second
478

479
## random values from Set
480

481
Sampler(::Type{RNG}, t::Set{T}, n::Repetition) where {RNG<:AbstractRNG,T} =
66✔
482
    SamplerTag{Set{T}}(Sampler(RNG, t.dict, n))
483

484
rand(rng::AbstractRNG, sp::SamplerTag{<:Set,<:Sampler}) = rand(rng, sp.data).first
1,268✔
485

486
## random values from BitSet
487

488
function Sampler(RNG::Type{<:AbstractRNG}, t::BitSet, n::Repetition)
62✔
489
    isempty(t) && throw(ArgumentError("collection must be non-empty"))
62✔
490
    SamplerSimple(t, Sampler(RNG, minimum(t):maximum(t), Val(Inf)))
54✔
491
end
492

493
function rand(rng::AbstractRNG, sp::SamplerSimple{BitSet,<:Sampler})
6✔
494
    while true
3,350✔
495
        n = rand(rng, sp.data)
3,350✔
496
        n in sp[] && return n
3,350✔
497
    end
2,664✔
498
end
499

500
## random values from AbstractDict/AbstractSet
501

502
# we defer to _Sampler to avoid ambiguities with a call like Sampler(rng, Set(1), Val(1))
503
Sampler(RNG::Type{<:AbstractRNG}, t::Union{AbstractDict,AbstractSet}, n::Repetition) =
976✔
504
    _Sampler(RNG, t, n)
505

506
# avoid linear complexity for repeated calls
507
_Sampler(RNG::Type{<:AbstractRNG}, t::Union{AbstractDict,AbstractSet}, n::Val{Inf}) =
180✔
508
    Sampler(RNG, collect(t), n)
509

510
# when generating only one element, avoid the call to collect
511
_Sampler(::Type{<:AbstractRNG}, t::Union{AbstractDict,AbstractSet}, ::Val{1}) =
796✔
512
    SamplerTrivial(t)
513

514
function nth(iter, n::Integer)::eltype(iter)
464✔
515
    for (i, x) in enumerate(iter)
928✔
516
        i == n && return x
3,566✔
517
    end
3,102✔
518
end
519

520
rand(rng::AbstractRNG, sp::SamplerTrivial{<:Union{AbstractDict,AbstractSet}}) =
472✔
521
    nth(sp[], rand(rng, 1:length(sp[])))
522

523

524
## random characters from a string
525

526
# we use collect(str), which is most of the time more efficient than specialized methods
527
# (except maybe for very small arrays)
528
Sampler(RNG::Type{<:AbstractRNG}, str::AbstractString, n::Val{Inf}) = Sampler(RNG, collect(str), n)
2,344✔
529

530
# when generating only one char from a string, the specialized method below
531
# is usually more efficient
532
Sampler(RNG::Type{<:AbstractRNG}, str::AbstractString, ::Val{1}) =
24✔
533
    SamplerSimple(str, Sampler(RNG, 1:_lastindex(str), Val(Inf)))
534

535
isvalid_unsafe(s::String, i) = !Base.is_valid_continuation(GC.@preserve s unsafe_load(pointer(s), i))
296✔
536
isvalid_unsafe(s::AbstractString, i) = isvalid(s, i)
273✔
537
_lastindex(s::String) = sizeof(s)
12✔
538
_lastindex(s::AbstractString) = lastindex(s)
12✔
539

540
function rand(rng::AbstractRNG, sp::SamplerSimple{<:AbstractString,<:Sampler})::Char
464✔
541
    str = sp[]
464✔
542
    while true
569✔
543
        pos = rand(rng, sp.data)
569✔
544
        isvalid_unsafe(str, pos) && return str[pos]
569✔
545
    end
105✔
546
end
547

548

549
## random elements from tuples
550

551
### 1
552

553
Sampler(::Type{<:AbstractRNG}, t::Tuple{A}, ::Repetition) where {A} =
2✔
554
    SamplerTrivial(t)
555

556
rand(rng::AbstractRNG, sp::SamplerTrivial{Tuple{A}}) where {A} =
2✔
557
    @inbounds return sp[][1]
558

559
### 2
560

561
Sampler(RNG::Type{<:AbstractRNG}, t::Tuple{A,B}, n::Repetition) where {A,B} =
12✔
562
    SamplerSimple(t, Sampler(RNG, Bool, n))
563

564
rand(rng::AbstractRNG, sp::SamplerSimple{Tuple{A,B}}) where {A,B} =
202✔
565
    @inbounds return sp[][1 + rand(rng, sp.data)]
566

567
### 3
568

569
Sampler(RNG::Type{<:AbstractRNG}, t::Tuple{A,B,C}, n::Repetition) where {A,B,C} =
2✔
570
    SamplerSimple(t, Sampler(RNG, UInt52(), n))
571

572
function rand(rng::AbstractRNG, sp::SamplerSimple{Tuple{A,B,C}}) where {A,B,C}
2✔
573
    local r
2✔
574
    while true
2✔
575
        r = rand(rng, sp.data)
2✔
576
        r != 0x000fffffffffffff && break # _very_ likely
2✔
577
    end
×
578
    @inbounds return sp[][1 + r ÷ 0x0005555555555555]
2✔
579
end
580

581
### n
582

583
@generated function Sampler(RNG::Type{<:AbstractRNG}, t::Tuple, n::Repetition)
4,012✔
584
    l = fieldcount(t)
14✔
585
    if l < typemax(UInt32) && ispow2(l)
14✔
586
        :(SamplerSimple(t, Sampler(RNG, UInt32, n)))
8✔
587
    else
588
        :(SamplerSimple(t, Sampler(RNG, Base.OneTo(length(t)), n)))
14✔
589
    end
590
end
591

592
@generated function rand(rng::AbstractRNG, sp::SamplerSimple{T}) where T<:Tuple
2,010✔
593
    l = fieldcount(T)
11✔
594
    if l < typemax(UInt32) && ispow2(l)
11✔
595
        quote
5✔
596
            r = rand(rng, sp.data) & ($l-1)
2,002✔
597
            @inbounds return sp[][1 + r]
2,002✔
598
        end
599
    else
600
        :(@inbounds return sp[][rand(rng, sp.data)])
11✔
601
    end
602
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc