Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add bytes2hex(io, a) method #27124

Merged
merged 1 commit into from
May 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,9 @@ Library improvements
* `Char` is now a subtype of `AbstractChar`, and most of the functions that
take character arguments now accept any `AbstractChar` ([#26286]).

* `bytes2hex` now accepts an optional `io` argument to output to a hexadecimal stream
without allocating a `String` first ([#27121]).

* `String(array)` now accepts an arbitrary `AbstractVector{UInt8}`. For `Vector`
inputs, it "steals" the memory buffer, leaving them with an empty buffer which
is guaranteed not to be shared with the `String` object. For other types of vectors
Expand Down
5 changes: 3 additions & 2 deletions base/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,11 @@ struct SHA1
end
end
SHA1(s::AbstractString) = SHA1(hex2bytes(s))

string(hash::SHA1) = bytes2hex(hash.bytes)
print(io::IO, hash::SHA1) = print(io, string(hash))
print(io::IO, hash::SHA1) = bytes2hex(io, hash.bytes)
show(io::IO, hash::SHA1) = print(io, "SHA1(\"", hash, "\")")

show(io::IO, hash::SHA1) = print(io, "SHA1(\"", string(hash), "\")")
isless(a::SHA1, b::SHA1) = lexless(a.bytes, b.bytes)
hash(a::SHA1, h::UInt) = hash((SHA1, a.bytes), h)
==(a::SHA1, b::SHA1) = a.bytes == b.bytes
Expand Down
18 changes: 14 additions & 4 deletions base/strings/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -547,10 +547,13 @@ end
throw(ArgumentError("byte is not an ASCII hexadecimal digit"))

"""
bytes2hex(bin_arr::Array{UInt8, 1}) -> String
bytes2hex(a::AbstractArray{UInt8}) -> String
bytes2hex(io::IO, a::AbstractArray{UInt8})

Convert an array `a` of bytes to its hexadecimal string representation, either
returning a `String` via `bytes2hex(a)` or writing the string to an `io` stream
via `bytes2hex(io, a)`. The hexadecimal characters are all lowercase.

Convert an array of bytes to its hexadecimal representation.
All characters are in lower-case.
# Examples
```jldoctest
julia> a = string(12345, base = 16)
Expand All @@ -565,8 +568,10 @@ julia> bytes2hex(b)
"3039"
```
"""
function bytes2hex end

function bytes2hex(a::AbstractArray{UInt8})
b = Vector{UInt8}(undef, 2*length(a))
b = Base.StringVector(2*length(a))
i = 0
for x in a
b[i += 1] = hex_chars[1 + x >> 4]
Expand All @@ -575,6 +580,11 @@ function bytes2hex(a::AbstractArray{UInt8})
return String(b)
end

bytes2hex(io::IO, a::AbstractArray{UInt8}) =
for x in a
print(io, Char(hex_chars[1 + x >> 4]), Char(hex_chars[1 + x & 0xf]))
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

write(io, hex_chars[1 + (x >> 4)]) would probably be faster, since it'll save us from needing to decode the Char into the stream

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Faster but wrong, unfortunately. Writing bytes directly assumes that io uses an ASCII-compatible encoding (#26286). We would need an ASCIIChar type to get both encoding-independence and maximum performance here.

end

# check for pure ASCII-ness

function ascii(s::String)
Expand Down
3 changes: 1 addition & 2 deletions base/uuid.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ let groupings = [36:-1:25; 23:-1:20; 18:-1:15; 13:-1:10; 8:-1:1]
u = u.value
a = Base.StringVector(36)
for i in groupings
d = u & 0xf
a[i] = '0' + d + 39*(d > 9)
a[i] = hex_chars[1 + u & 0xf]
u >>= 4
end
a[24] = a[19] = a[14] = a[9] = '-'
Expand Down
2 changes: 1 addition & 1 deletion test/loading.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ end
let uuidstr = "ab"^4 * "-" * "ab"^2 * "-" * "ab"^2 * "-" * "ab"^2 * "-" * "ab"^6
uuid = UUID(uuidstr)
@test uuid == eval(Meta.parse(repr(uuid))) # check show method
@test string(uuid) == uuidstr
@test string(uuid) == uuidstr == sprint(print, uuid)
@test "check $uuid" == "check $uuidstr"
end

Expand Down
2 changes: 1 addition & 1 deletion test/strings/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ end
bin_val = hex2bytes(hex_str)

@test div(length(hex_str), 2) == length(bin_val)
@test hex_str == bytes2hex(bin_val)
@test hex_str == bytes2hex(bin_val) == sprint(bytes2hex, bin_val)

bin_val = hex2bytes("07bf")
@test bin_val[1] == 7
Expand Down