• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37502

pending completion
#37502

push

local

web-flow
delete unnecessary `getindex` method (#49310)

xref: <https://github.com/JuliaLang/julia/pull/47154#discussion_r1161062960>

70609 of 82885 relevant lines covered (85.19%)

32589426.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.02
/base/parse.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
import Base.Checked: add_with_overflow, mul_with_overflow
4

5
## string to integer functions ##
6

7
"""
8
    parse(type, str; base)
9

10
Parse a string as a number. For `Integer` types, a base can be specified
11
(the default is 10). For floating-point types, the string is parsed as a decimal
12
floating-point number.  `Complex` types are parsed from decimal strings
13
of the form `"R±Iim"` as a `Complex(R,I)` of the requested type; `"i"` or `"j"` can also be
14
used instead of `"im"`, and `"R"` or `"Iim"` are also permitted.
15
If the string does not contain a valid number, an error is raised.
16

17
!!! compat "Julia 1.1"
18
    `parse(Bool, str)` requires at least Julia 1.1.
19

20
# Examples
21
```jldoctest
22
julia> parse(Int, "1234")
23
1234
24

25
julia> parse(Int, "1234", base = 5)
26
194
27

28
julia> parse(Int, "afc", base = 16)
29
2812
30

31
julia> parse(Float64, "1.2e-3")
32
0.0012
33

34
julia> parse(Complex{Float64}, "3.2e-1 + 4.5im")
35
0.32 + 4.5im
36
```
37
"""
38
parse(T::Type, str; base = Int)
39

40
function parse(::Type{T}, c::AbstractChar; base::Integer = 10) where T<:Integer
72✔
41
    a::Int = (base <= 36 ? 10 : 36)
36✔
42
    2 <= base <= 62 || throw(ArgumentError("invalid base: base must be 2 ≤ base ≤ 62, got $base"))
36✔
43
    d = '0' <= c <= '9' ? c-'0'    :
36✔
44
        'A' <= c <= 'Z' ? c-'A'+10 :
45
        'a' <= c <= 'z' ? c-'a'+a  : throw(ArgumentError("invalid digit: $(repr(c))"))
46
    d < base || throw(ArgumentError("invalid base $base digit $(repr(c))"))
36✔
47
    convert(T, d)
36✔
48
end
49

50
function parseint_iterate(s::AbstractString, startpos::Int, endpos::Int)
127,480✔
51
    (0 < startpos <= endpos) || (return Char(0), 0, 0)
249,586✔
52
    j = startpos
×
53
    c, startpos = iterate(s,startpos)::Tuple{Char, Int}
482,668✔
54
    c, startpos, j
241,520✔
55
end
56

57
function parseint_preamble(signed::Bool, base::Int, s::AbstractString, startpos::Int, endpos::Int)
112,212✔
58
    c, i, j = parseint_iterate(s, startpos, endpos)
167,304✔
59

60
    while isspace(c)
232,946✔
61
        c, i, j = parseint_iterate(s,i,endpos)
8,544✔
62
    end
8,522✔
63
    (j == 0) && (return 0, 0, 0)
112,212✔
64

65
    sgn = 1
×
66
    if signed
108,179✔
67
        if c == '-' || c == '+'
175,801✔
68
            (c == '-') && (sgn = -1)
10,578✔
69
            c, i, j = parseint_iterate(s,i,endpos)
12,456✔
70
        end
71
    end
72

73
    while isspace(c)
216,358✔
74
        c, i, j = parseint_iterate(s,i,endpos)
×
75
    end
×
76
    (j == 0) && (return 0, 0, 0)
108,179✔
77

78
    if base == 0
108,179✔
79
        if c == '0' && i <= endpos
99,506✔
80
            c, i = iterate(s,i)::Tuple{Char, Int}
31,650✔
81
            base = c=='b' ? 2 : c=='o' ? 8 : c=='x' ? 16 : 10
31,612✔
82
            if base != 10
15,825✔
83
                c, i, j = parseint_iterate(s,i,endpos)
13,786✔
84
            end
85
        else
86
            base = 10
×
87
        end
88
    end
89
    return sgn, base, j
108,179✔
90
end
91

92
# '0':'9' -> 0:9
93
# 'A':'Z' -> 10:35
94
# 'a':'z' -> 10:35 if base <= 36, 36:61 otherwise
95
# input outside of that is mapped to base
96
@inline function __convert_digit(_c::UInt32, base::UInt32)
37,781✔
97
    _0 = UInt32('0')
×
98
    _9 = UInt32('9')
×
99
    _A = UInt32('A')
×
100
    _a = UInt32('a')
×
101
    _Z = UInt32('Z')
×
102
    _z = UInt32('z')
×
103
    a = base <= 36 ? UInt32(10) : UInt32(36) # converting here instead of via a type assertion prevents typeassert related errors
11,317,322✔
104
    d = _0 <= _c <= _9 ? _c-_0             :
15,540,011✔
105
        _A <= _c <= _Z ? _c-_A+ UInt32(10) :
106
        _a <= _c <= _z ? _c-_a+a           :
107
        base
108
end
109

110

111
function tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int, base_::Integer, raise::Bool) where T<:Integer
111,331✔
112
    sgn, base, i = parseint_preamble(T<:Signed, Int(base_), s, startpos, endpos)
111,331✔
113
    if sgn == 0 && base == 0 && i == 0
111,331✔
114
        raise && throw(ArgumentError("input string is empty or only contains whitespace"))
4,033✔
115
        return nothing
4,033✔
116
    end
117
    if !(2 <= base <= 62)
107,298✔
118
        raise && throw(ArgumentError(LazyString("invalid base: base must be 2 ≤ base ≤ 62, got ", base)))
×
119
        return nothing
×
120
    end
121
    if i == 0
107,298✔
122
        raise && throw(ArgumentError("premature end of integer: $(repr(SubString(s,startpos,endpos)))"))
×
123
        return nothing
×
124
    end
125
    c, i = parseint_iterate(s,i,endpos)
161,503✔
126
    if i == 0
107,298✔
127
        raise && throw(ArgumentError("premature end of integer: $(repr(SubString(s,startpos,endpos)))"))
×
128
        return nothing
×
129
    end
130

131
    base = convert(T, base)
19,745✔
132
    # Special case the common cases of base being 10 or 16 to avoid expensive runtime div
133
    m::T = base == 10 ? div(typemax(T) - T(9), T(10)) :
120,316✔
134
           base == 16 ? div(typemax(T) - T(15), T(16)) :
135
                        div(typemax(T) - base + 1, base)
136
    n::T = 0
92,034✔
137
    while n <= m
494,663✔
138
        # Fast path from `UInt32(::Char)`; non-ascii will be >= 0x80
139
        _c = reinterpret(UInt32, c) >> 24
494,507✔
140
        d::T = __convert_digit(_c, base % UInt32) # we know 2 <= base <= 62, so prevent an incorrect InexactError here
628,737✔
141
        if d >= base
494,507✔
142
            raise && throw(ArgumentError("invalid base $base digit $(repr(c)) in $(repr(SubString(s,startpos,endpos)))"))
733✔
143
            return nothing
704✔
144
        end
145
        n *= base
493,774✔
146
        n += d
493,774✔
147
        if i > endpos
493,774✔
148
            n *= sgn
106,383✔
149
            return n
106,383✔
150
        end
151
        c, i = iterate(s,i)::Tuple{Char, Int}
774,779✔
152
        isspace(c) && break
774,757✔
153
    end
387,365✔
154
    (T <: Signed) && (n *= sgn)
182✔
155
    while !isspace(c)
359✔
156
        # Fast path from `UInt32(::Char)`; non-ascii will be >= 0x80
157
        _c = reinterpret(UInt32, c) >> 24
166✔
158
        d::T = __convert_digit(_c, base % UInt32) # we know 2 <= base <= 62
166✔
159
        if d >= base
166✔
160
            raise && throw(ArgumentError("invalid base $base digit $(repr(c)) in $(repr(SubString(s,startpos,endpos)))"))
1✔
161
            return nothing
1✔
162
        end
163
        (T <: Signed) && (d *= sgn)
163✔
164

165
        n, ov_mul = mul_with_overflow(n, base)
165✔
166
        n, ov_add = add_with_overflow(n, d)
165✔
167
        if ov_mul | ov_add
165✔
168
            raise && throw(OverflowError("overflow parsing $(repr(SubString(s,startpos,endpos)))"))
17✔
169
            return nothing
13✔
170
        end
171
        (i > endpos) && return n
148✔
172
        c, i = iterate(s,i)::Tuple{Char, Int}
20✔
173
    end
10✔
174
    while i <= endpos
34✔
175
        c, i = iterate(s,i)::Tuple{Char, Int}
42✔
176
        if !isspace(c)
36✔
177
            raise && throw(ArgumentError("extra characters after whitespace in $(repr(SubString(s,startpos,endpos)))"))
14✔
178
            return nothing
×
179
        end
180
    end
8✔
181
    return n
12✔
182
end
183

184
function tryparse_internal(::Type{Bool}, sbuff::AbstractString,
737✔
185
        startpos::Int, endpos::Int, base::Integer, raise::Bool)
186
    if isempty(sbuff)
737✔
187
        raise && throw(ArgumentError("input string is empty"))
×
188
        return nothing
×
189
    end
190

191
    if isnumeric(sbuff[1])
1,453✔
192
        intres = tryparse_internal(UInt8, sbuff, startpos, endpos, base, false)
11✔
193
        (intres == 1) && return true
11✔
194
        (intres == 0) && return false
11✔
195
        raise && throw(ArgumentError("invalid Bool representation: $(repr(sbuff))"))
11✔
196
    end
197

198
    orig_start = startpos
737✔
199
    orig_end   = endpos
737✔
200

201
    # Ignore leading and trailing whitespace
202
    while startpos <= endpos && isspace(sbuff[startpos])
1,475✔
203
        startpos = nextind(sbuff, startpos)
2✔
204
    end
2✔
205
    while endpos >= startpos && isspace(sbuff[endpos])
1,474✔
206
        endpos = prevind(sbuff, endpos)
1✔
207
    end
1✔
208

209
    len = endpos - startpos + 1
737✔
210
    if sbuff isa Union{String, SubString{String}}
737✔
211
        p = pointer(sbuff) + startpos - 1
737✔
212
        GC.@preserve sbuff begin
737✔
213
            (len == 4) && (0 == _memcmp(p, "true", 4)) && (return true)
737✔
214
            (len == 5) && (0 == _memcmp(p, "false", 5)) && (return false)
715✔
215
        end
216
    else
217
        (len == 4) && (SubString(sbuff, startpos:startpos+3) == "true") && (return true)
×
218
        (len == 5) && (SubString(sbuff, startpos:startpos+4) == "false") && (return false)
×
219
    end
220

221
    if raise
683✔
222
        substr = SubString(sbuff, orig_start, orig_end) # show input string in the error to avoid confusion
×
223
        if all(isspace, substr)
×
224
            throw(ArgumentError("input string only contains whitespace"))
×
225
        else
226
            throw(ArgumentError("invalid Bool representation: $(repr(substr))"))
×
227
        end
228
    end
229
    return nothing
683✔
230
end
231

232
@inline function check_valid_base(base)
6,727✔
233
    if 2 <= base <= 62
8,669✔
234
        return base
8,669✔
235
    end
236
    throw(ArgumentError("invalid base: base must be 2 ≤ base ≤ 62, got $base"))
×
237
end
238

239
"""
240
    tryparse(type, str; base)
241

242
Like [`parse`](@ref), but returns either a value of the requested type,
243
or [`nothing`](@ref) if the string does not contain a valid number.
244
"""
245
function tryparse(::Type{T}, s::AbstractString; base::Union{Nothing,Integer} = nothing) where {T<:Integer}
5,029✔
246
    # Zero base means, "figure it out"
247
    tryparse_internal(T, s, firstindex(s), lastindex(s), base===nothing ? 0 : check_valid_base(base), false)
4,759✔
248
end
249

250
function parse(::Type{T}, s::AbstractString; base::Union{Nothing,Integer} = nothing) where {T<:Integer}
213,126✔
251
    convert(T, tryparse_internal(T, s, firstindex(s), lastindex(s),
106,558✔
252
                                 base===nothing ? 0 : check_valid_base(base), true))
253
end
254

255
## string to float functions ##
256

257
function tryparse(::Type{Float64}, s::String)
3✔
258
    hasvalue, val = ccall(:jl_try_substrtod, Tuple{Bool, Float64},
393✔
259
                          (Ptr{UInt8},Csize_t,Csize_t), s, 0, sizeof(s))
260
    hasvalue ? val : nothing
393✔
261
end
262
function tryparse(::Type{Float64}, s::SubString{String})
8,187✔
263
    hasvalue, val = ccall(:jl_try_substrtod, Tuple{Bool, Float64},
8,281✔
264
                          (Ptr{UInt8},Csize_t,Csize_t), s.string, s.offset, s.ncodeunits)
265
    hasvalue ? val : nothing
8,289✔
266
end
267
function tryparse_internal(::Type{Float64}, s::String, startpos::Int, endpos::Int)
288✔
268
    hasvalue, val = ccall(:jl_try_substrtod, Tuple{Bool, Float64},
288✔
269
                          (Ptr{UInt8},Csize_t,Csize_t), s, startpos-1, endpos-startpos+1)
270
    hasvalue ? val : nothing
320✔
271
end
272
function tryparse_internal(::Type{Float64}, s::SubString{String}, startpos::Int, endpos::Int)
×
273
    hasvalue, val = ccall(:jl_try_substrtod, Tuple{Bool, Float64},
×
274
                          (Ptr{UInt8},Csize_t,Csize_t), s.string, s.offset+startpos-1, endpos-startpos+1)
275
    hasvalue ? val : nothing
×
276
end
277
function tryparse(::Type{Float32}, s::String)
30,724✔
278
    hasvalue, val = ccall(:jl_try_substrtof, Tuple{Bool, Float32},
30,724✔
279
                          (Ptr{UInt8},Csize_t,Csize_t), s, 0, sizeof(s))
280
    hasvalue ? val : nothing
30,724✔
281
end
282
function tryparse(::Type{Float32}, s::SubString{String})
4✔
283
    hasvalue, val = ccall(:jl_try_substrtof, Tuple{Bool, Float32},
4✔
284
                          (Ptr{UInt8},Csize_t,Csize_t), s.string, s.offset, s.ncodeunits)
285
    hasvalue ? val : nothing
5✔
286
end
287
function tryparse_internal(::Type{Float32}, s::String, startpos::Int, endpos::Int)
×
288
    hasvalue, val = ccall(:jl_try_substrtof, Tuple{Bool, Float32},
×
289
                          (Ptr{UInt8},Csize_t,Csize_t), s, startpos-1, endpos-startpos+1)
290
    hasvalue ? val : nothing
×
291
end
292
function tryparse_internal(::Type{Float32}, s::SubString{String}, startpos::Int, endpos::Int)
×
293
    hasvalue, val = ccall(:jl_try_substrtof, Tuple{Bool, Float32},
×
294
                          (Ptr{UInt8},Csize_t,Csize_t), s.string, s.offset+startpos-1, endpos-startpos+1)
295
    hasvalue ? val : nothing
×
296
end
297
tryparse(::Type{T}, s::AbstractString) where {T<:Union{Float32,Float64}} = tryparse(T, String(s))
×
298
tryparse(::Type{Float16}, s::AbstractString) =
61,440✔
299
    convert(Union{Float16, Nothing}, tryparse(Float32, s))
300
tryparse_internal(::Type{Float16}, s::AbstractString, startpos::Int, endpos::Int) =
×
301
    convert(Union{Float16, Nothing}, tryparse_internal(Float32, s, startpos, endpos))
302

303
## string to complex functions ##
304

305
function tryparse_internal(::Type{Complex{T}}, s::Union{String,SubString{String}}, i::Int, e::Int, raise::Bool) where {T<:Real}
2✔
306
    # skip initial whitespace
307
    while i ≤ e && isspace(s[i])
4✔
308
        i = nextind(s, i)
1✔
309
    end
1✔
310
    if i > e
2✔
311
        raise && throw(ArgumentError("input string is empty or only contains whitespace"))
×
312
        return nothing
×
313
    end
314

315
    # find index of ± separating real/imaginary parts (if any)
316
    i₊ = something(findnext(in(('+','-')), s, i), 0)
4✔
317
    if i₊ == i # leading ± sign
2✔
318
        i₊ = something(findnext(in(('+','-')), s, i₊+1), 0)
×
319
    end
320
    if i₊ != 0 && s[i₊-1] in ('e','E') # exponent sign
6✔
321
        i₊ = something(findnext(in(('+','-')), s, i₊+1), 0)
×
322
    end
323

324
    # find trailing im/i/j
325
    iᵢ = something(findprev(in(('m','i','j')), s, e), 0)
4✔
326
    if iᵢ > 0 && s[iᵢ] == 'm' # im
4✔
327
        iᵢ -= 1
2✔
328
        if s[iᵢ] != 'i'
4✔
329
            raise && throw(ArgumentError("expected trailing \"im\", found only \"m\""))
×
330
            return nothing
×
331
        end
332
    end
333

334
    if i₊ == 0 # purely real or imaginary value
2✔
335
        if iᵢ > i && !(iᵢ == i+1 && s[i] in ('+','-')) # purely imaginary (not "±inf")
×
336
            x = tryparse_internal(T, s, i, iᵢ-1, raise)
×
337
            x === nothing && return nothing
×
338
            return Complex{T}(zero(x),x)
×
339
        else # purely real
340
            x = tryparse_internal(T, s, i, e, raise)
×
341
            x === nothing && return nothing
×
342
            return Complex{T}(x)
×
343
        end
344
    end
345

346
    if iᵢ < i₊
2✔
347
        raise && throw(ArgumentError("missing imaginary unit"))
×
348
        return nothing # no imaginary part
×
349
    end
350

351
    # parse real part
352
    re = tryparse_internal(T, s, i, i₊-1, raise)
2✔
353
    re === nothing && return nothing
2✔
354

355
    # parse imaginary part
356
    im = tryparse_internal(T, s, i₊+1, iᵢ-1, raise)
2✔
357
    im === nothing && return nothing
2✔
358

359
    return Complex{T}(re, s[i₊]=='-' ? -im : im)
2✔
360
end
361

362
# the ±1 indexing above for ascii chars is specific to String, so convert:
363
tryparse_internal(T::Type{Complex{S}}, s::AbstractString, i::Int, e::Int, raise::Bool) where S<:Real =
×
364
    tryparse_internal(T, String(s), i, e, raise)
365

366
# fallback methods for tryparse_internal
367
tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int) where T<:Real =
×
368
    startpos == firstindex(s) && endpos == lastindex(s) ? tryparse(T, s) : tryparse(T, SubString(s, startpos, endpos))
369
function tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int, raise::Bool) where T<:Real
288✔
370
    result = tryparse_internal(T, s, startpos, endpos)
320✔
371
    if raise && result === nothing
288✔
372
        _parse_failure(T, s, startpos, endpos)
×
373
    end
374
    return result
288✔
375
end
376
function tryparse_internal(::Type{T}, s::AbstractString, raise::Bool; kwargs...) where T<:Real
109,166✔
377
    result = tryparse(T, s; kwargs...)
70,139✔
378
    if raise && result === nothing
39,416✔
379
        _parse_failure(T, s)
2✔
380
    end
381
    return result
39,414✔
382
end
383
@noinline _parse_failure(T, s::AbstractString, startpos = firstindex(s), endpos = lastindex(s)) =
4✔
384
    throw(ArgumentError("cannot parse $(repr(s[startpos:endpos])) as $T"))
385

386
tryparse_internal(::Type{T}, s::AbstractString, startpos::Int, endpos::Int, raise::Bool) where T<:Integer =
4✔
387
    tryparse_internal(T, s, startpos, endpos, 10, raise)
388

389
parse(::Type{T}, s::AbstractString; kwargs...) where T<:Real =
109,556✔
390
    convert(T, tryparse_internal(T, s, true; kwargs...))
391
parse(::Type{T}, s::AbstractString) where T<:Complex =
×
392
    convert(T, tryparse_internal(T, s, firstindex(s), lastindex(s), true))
393

394
tryparse(T::Type{Complex{S}}, s::AbstractString) where S<:Real =
×
395
    tryparse_internal(T, s, firstindex(s), lastindex(s), false)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc