Skip to content

Commit

Permalink
use O(1) algo for generic AbstractString (StefanKarpinski)
Browse files Browse the repository at this point in the history
  • Loading branch information
rfourquet committed Jun 7, 2017
1 parent 86713e6 commit e2cefe4
Showing 1 changed file with 11 additions and 20 deletions.
31 changes: 11 additions & 20 deletions base/random.jl
Original file line number Diff line number Diff line change
Expand Up @@ -264,10 +264,6 @@ Pick a random element or array of random elements from the set of values specifi
`S` defaults to [`Float64`](@ref).
Note that the complexity of `rand(rng, s::AbstractString)` is linear
in the length of `s` if `s` is not of type `String`. If called more
than a few times, you should use `rand(rng, collect(s))` instead.
# Examples
```julia-repl
Expand Down Expand Up @@ -691,32 +687,27 @@ rand(rng::AbstractRNG, r::AbstractArray, dims::Int...) = rand(rng, r, dims)

# rand from a string

rand(rng::AbstractRNG, s::AbstractString) = rand_iter(rng, s, Base.iteratorsize(s))
rand(s::AbstractString) = rand(GLOBAL_RNG, s)

## optimization for String

isvalid_unsafe(s::String, i) = !Base.is_valid_continuation(unsafe_load(pointer(s), i))

function rand(rng::AbstractRNG, s::String)
rg = RangeGenerator(1:s.len)
function rand(rng::AbstractRNG, s::String)::Char
g = RangeGenerator(1:s.len)
while true
pos = rand(rng, rg)
pos = rand(rng, g)
isvalid_unsafe(s, pos) && return s[pos]
end
end

## rand from an iterator

rand_iter(rng, s, ::Base.IteratorSize) = throw(ArgumentError("iterator must have a known length"))

function rand_iter(rng::AbstractRNG, s, ::Union{Base.HasShape,Base.HasLength})::eltype(s)
pos = rand(rng, 1:length(s))
for (i, c) in enumerate(s)
i == pos && return c
function rand(rng::AbstractRNG, s::AbstractString)::Char
g = RangeGenerator(1:endof(s))
while true
try # the generic `isvalid` includes an equivalent try/catch statement
return s[rand(rng, g)]
end
end
end

rand(s::AbstractString) = rand(GLOBAL_RNG, s)

## rand from a string for arrays
# we use collect(str), which is most of the time more efficient than specialized methods
# (except maybe for very small arrays)
Expand Down

0 comments on commit e2cefe4

Please sign in to comment.