Skip to content

Commit

Permalink
Merge pull request #2 from antimon2/tuning
Browse files Browse the repository at this point in the history
Performance Tuning
  • Loading branch information
antimon2 authored Nov 25, 2019
2 parents 659890e + 936dedd commit 4a0659f
Showing 1 changed file with 92 additions and 8 deletions.
100 changes: 92 additions & 8 deletions src/Hashids.jl
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,21 @@ function _reorder!(list::Vector{Char}, salt)
list
end

"""
Hashids.Configuration
Hashids' parameter-configuration.
Be sure to place the instance as the 1st argument of [`encode`](@ref), [`decode`](@ref), [`encodehex`](@ref) and [`decodehex`](@ref).
See also: [`configure`](@ref)
"""
struct Configuration
salt::String
min_length::Int
alphabet::String
guards::String
separators::String
function Configuration(salt::String, min_length::Int, alphabet::AbstractString)
function Configuration(salt::AbstractString, min_length::Int, alphabet::AbstractString)
separators_list = [c for c = DEFAULT_SEPARATORS if c alphabet]
alphabet_list = [c for c = unique(alphabet) if c separators_list && !isspace(c)]
len_alphabet = length(alphabet_list)
Expand All @@ -61,11 +69,31 @@ struct Configuration
alphabet_list = alphabet_list[num_guards + 1:end]
end

new(salt, max(min_length, 0), String(alphabet_list), String(guards_list), String(separators_list))
new(string(salt), max(min_length, 0), String(alphabet_list), String(guards_list), String(separators_list))
end
end
Configuration(; salt::String = "", min_length::Int = 0, alphabet::String = DEFAULT_ALPHABET) = Configuration(salt, min_length, alphabet)
Configuration(; salt::AbstractString = "", min_length::Int = 0, alphabet::AbstractString = DEFAULT_ALPHABET) = Configuration(salt, min_length, alphabet)

"""
Hashids.configure()
Hashids.configure(salt)
Hashids.configure(salt="", min_length=0, alphabet=DEFAULT_ALPHABET)
Configure Hashids with parameters, and return [`Hashids.Configuration`](@ref) instance.
`Hashids.configure()` returns default-configuration.
# Example
```julia-repl
julia> config = Hashids.configure();
julia> config = Hashids.configure("this is my salt");
julia> config = Hashids.configure(salt="this is another salt", min_length=16, alphabet="abcdefghijklmnopqrstuvwxyz");
```
See also: [`Configuration`](@ref)
"""
configure(salt) = Configuration(string(salt), 0, DEFAULT_ALPHABET)
configure(; kwargs...) = Configuration(; kwargs...)

Expand All @@ -85,16 +113,17 @@ function _checked_muladd(x::T, y::T, z::T) where {T<:Integer}
end
_checked_muladd(x::BigInt, y::Integer, z::Integer) = muladd(x, y, z)

_unhash(hashed, alphabet_list) = _unhash(Int, hashed, alphabet_list)
function _unhash(::Type{I}, hashed, alphabet_list) where {I <: Integer}
number = zero(I)
_unhash(hashed, alphabet_list) = _checked_unhash(0, hashed, iterate(hashed), alphabet_list)
function _checked_unhash(number::I, hashed, hashed_status, alphabet_list) where {I <: Integer}
len_alphabet = length(alphabet_list)
for character in hashed
while !isnothing(hashed_status)
(character, st) = hashed_status
position = findfirst(isequal(character), alphabet_list)
isnothing(position) && return nothing
_number = _checked_muladd(number, len_alphabet, position - 1)
isnothing(_number) && return _unhash(widen(I), hashed, alphabet_list)
isnothing(_number) && return _checked_unhash(widen(number), hashed, hashed_status, alphabet_list)
number = something(_number)
hashed_status = iterate(hashed, st)
end
return number
end
Expand Down Expand Up @@ -124,6 +153,22 @@ function _ensure_length!(encoded, min_length, alphabet_list, guards, values_hash
return encoded
end

"""
encode(config::Hashids.Configuration, values::Array{<:Integer})
encode(config::Hashids.Configuration, values::Integer...)
Encode the passed `values` to a hash.
# Example
```julia-repl
julia> encode(Hashids.configure(), 1, 2, 3)
"o2fXhV"
julia> encode(Hashids.configure(), [1, 2, 3])
"o2fXhV"
```
"""
encode(config::Configuration, values::Array{<:Integer}) = encode(config, values...)
function encode(config::Configuration, values::Vararg{Integer})
alphabet_list = collect(config.alphabet)
Expand All @@ -150,6 +195,21 @@ function encode(config::Configuration, values::Vararg{Integer})
return String(encoded)
end

"""
decode(config::Hashids.Configuration, hashid::AbstractString)
Restore a numbers list from the passed `hashid`.
# Example
```julia-repl
julia> decode(Hashids.configure(), "o2fXhV")
3-element Array{Int64,1}:
1
2
3
```
"""
function decode(config::Configuration, hashid::AbstractString)
parts = split(hashid, in(config.guards))
_hashid = 2 length(parts) 3 ? parts[2] : parts[1]
Expand Down Expand Up @@ -177,12 +237,36 @@ function decode(config::Configuration, hashid::AbstractString)
return [numbers...]
end

"""
encodehex(config::Hashids.Configuration, hex::AbstractString)
Convert a hexadecimal string (e.g. a MongoDB id) to a hashid.
# Example
```julia-repl
julia> encodehex(Hashids.configure(), "abcdef123456")
"kmP69lB3xv"
```
"""
function encodehex(config::Configuration, hex::AbstractString)
isnothing(match(r"^[0-9a-fA-F]+$", hex)) && return ""
numbers = [parse(Int64, "1" * hex[i:min(i+11,end)], base=16) for i in 1:12:lastindex(hex)]
encode(config, numbers)
end

"""
decodehex(config::Hashids.Configuration, hashid::AbstractString)
Resrtore a hexadecimal string (e.g. a MongoDB id) from the passed `hashid`.
# Example
```julia-repl
julia> decodehex(Hashids.configure(), "kmP69lB3xv")
"abcdef123456"
```
"""
function decodehex(config::Configuration, hashid::AbstractString)
numbers = decode(config, hashid)
join(string(number, base=16)[2:end] for number in numbers)
Expand Down

0 comments on commit 4a0659f

Please sign in to comment.