-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
uuid.jl
109 lines (96 loc) · 3.17 KB
/
uuid.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# This file is a part of Julia. License is MIT: https://julialang.org/license
"""
Represents a Universally Unique Identifier (UUID).
Can be built from one `UInt128` (all byte values), two `UInt64`, or four `UInt32`.
Conversion from a string will check the UUID validity.
"""
struct UUID
value::UInt128
end
UUID(u::UUID) = u
UUID(u::NTuple{2, UInt64}) = UUID((UInt128(u[1]) << 64) | UInt128(u[2]))
UUID(u::NTuple{4, UInt32}) = UUID((UInt128(u[1]) << 96) | (UInt128(u[2]) << 64) |
(UInt128(u[3]) << 32) | UInt128(u[4]))
function convert(::Type{NTuple{2, UInt64}}, uuid::UUID)
bytes = uuid.value
hi = UInt64((bytes >> 64) & 0xffffffffffffffff)
lo = UInt64(bytes & 0xffffffffffffffff)
return (hi, lo)
end
function convert(::Type{NTuple{4, UInt32}}, uuid::UUID)
bytes = uuid.value
hh = UInt32((bytes >> 96) & 0xffffffff)
hl = UInt32((bytes >> 64) & 0xffffffff)
lh = UInt32((bytes >> 32) & 0xffffffff)
ll = UInt32(bytes & 0xffffffff)
return (hh, hl, lh, ll)
end
UInt128(u::UUID) = u.value
let
uuid_hash_seed = UInt === UInt64 ? 0xd06fa04f86f11b53 : 0x96a1f36d
Base.hash(uuid::UUID, h::UInt) = hash(uuid_hash_seed, hash(convert(NTuple{2, UInt64}, uuid), h))
end
let
@inline function uuid_kernel(s, i, u)
_c = UInt32(@inbounds codeunit(s, i))
d = __convert_digit(_c, UInt32(16))
d >= 16 && return nothing
u <<= 4
return u | d
end
function Base.tryparse(::Type{UUID}, s::AbstractString)
u = UInt128(0)
ncodeunits(s) != 36 && return nothing
for i in 1:8
u = uuid_kernel(s, i, u)
u === nothing && return nothing
end
@inbounds codeunit(s, 9) == UInt8('-') || return nothing
for i in 10:13
u = uuid_kernel(s, i, u)
u === nothing && return nothing
end
@inbounds codeunit(s, 14) == UInt8('-') || return nothing
for i in 15:18
u = uuid_kernel(s, i, u)
u === nothing && return nothing
end
@inbounds codeunit(s, 19) == UInt8('-') || return nothing
for i in 20:23
u = uuid_kernel(s, i, u)
u === nothing && return nothing
end
@inbounds codeunit(s, 24) == UInt8('-') || return nothing
for i in 25:36
u = uuid_kernel(s, i, u)
u === nothing && return nothing
end
return Base.UUID(u)
end
end
let
@noinline throw_malformed_uuid(s) = throw(ArgumentError("Malformed UUID string: $(repr(s))"))
function Base.parse(::Type{UUID}, s::AbstractString)
uuid = tryparse(UUID, s)
return uuid === nothing ? throw_malformed_uuid(s) : uuid
end
end
UUID(s::AbstractString) = parse(UUID, s)
let groupings = [36:-1:25; 23:-1:20; 18:-1:15; 13:-1:10; 8:-1:1]
global string
function string(u::UUID)
u = u.value
a = Base.StringVector(36)
for i in groupings
@inbounds a[i] = hex_chars[1 + u & 0xf]
u >>= 4
end
@inbounds a[24] = a[19] = a[14] = a[9] = '-'
return String(a)
end
end
print(io::IO, u::UUID) = print(io, string(u))
show(io::IO, u::UUID) = print(io, "UUID(\"", u, "\")")
isless(a::UUID, b::UUID) = isless(a.value, b.value)
# give UUID scalar behavior in broadcasting
Base.broadcastable(x::UUID) = Ref(x)