Skip to content

Commit e2cefe4

Browse files
committed
use O(1) algo for generic AbstractString (StefanKarpinski)
1 parent 86713e6 commit e2cefe4

File tree

1 file changed

+11
-20
lines changed

1 file changed

+11
-20
lines changed

base/random.jl

+11-20
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,6 @@ Pick a random element or array of random elements from the set of values specifi
264264
265265
`S` defaults to [`Float64`](@ref).
266266
267-
Note that the complexity of `rand(rng, s::AbstractString)` is linear
268-
in the length of `s` if `s` is not of type `String`. If called more
269-
than a few times, you should use `rand(rng, collect(s))` instead.
270-
271267
# Examples
272268
273269
```julia-repl
@@ -691,32 +687,27 @@ rand(rng::AbstractRNG, r::AbstractArray, dims::Int...) = rand(rng, r, dims)
691687

692688
# rand from a string
693689

694-
rand(rng::AbstractRNG, s::AbstractString) = rand_iter(rng, s, Base.iteratorsize(s))
695-
rand(s::AbstractString) = rand(GLOBAL_RNG, s)
696-
697-
## optimization for String
698-
699690
isvalid_unsafe(s::String, i) = !Base.is_valid_continuation(unsafe_load(pointer(s), i))
700691

701-
function rand(rng::AbstractRNG, s::String)
702-
rg = RangeGenerator(1:s.len)
692+
function rand(rng::AbstractRNG, s::String)::Char
693+
g = RangeGenerator(1:s.len)
703694
while true
704-
pos = rand(rng, rg)
695+
pos = rand(rng, g)
705696
isvalid_unsafe(s, pos) && return s[pos]
706697
end
707698
end
708699

709-
## rand from an iterator
710-
711-
rand_iter(rng, s, ::Base.IteratorSize) = throw(ArgumentError("iterator must have a known length"))
712-
713-
function rand_iter(rng::AbstractRNG, s, ::Union{Base.HasShape,Base.HasLength})::eltype(s)
714-
pos = rand(rng, 1:length(s))
715-
for (i, c) in enumerate(s)
716-
i == pos && return c
700+
function rand(rng::AbstractRNG, s::AbstractString)::Char
701+
g = RangeGenerator(1:endof(s))
702+
while true
703+
try # the generic `isvalid` includes an equivalent try/catch statement
704+
return s[rand(rng, g)]
705+
end
717706
end
718707
end
719708

709+
rand(s::AbstractString) = rand(GLOBAL_RNG, s)
710+
720711
## rand from a string for arrays
721712
# we use collect(str), which is most of the time more efficient than specialized methods
722713
# (except maybe for very small arrays)

0 commit comments

Comments
 (0)