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

JuliaLang / julia / #37545

pending completion
#37545

push

local

web-flow
Fix jl_timing_show_method_instance for top-level thunks (#49862)

This was causing invalid pointer dereferences when the method instance
had no backing method.

72631 of 83733 relevant lines covered (86.74%)

33727021.22 hits per line

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

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

3
"""
4
    SubString(s::AbstractString, i::Integer, j::Integer=lastindex(s))
5
    SubString(s::AbstractString, r::UnitRange{<:Integer})
6

7
Like [`getindex`](@ref), but returns a view into the parent string `s`
8
within range `i:j` or `r` respectively instead of making a copy.
9

10
The [`@views`](@ref) macro converts any string slices `s[i:j]` into
11
substrings `SubString(s, i, j)` in a block of code.
12

13
# Examples
14
```jldoctest
15
julia> SubString("abc", 1, 2)
16
"ab"
17

18
julia> SubString("abc", 1:2)
19
"ab"
20

21
julia> SubString("abc", 2)
22
"bc"
23
```
24
"""
25
struct SubString{T<:AbstractString} <: AbstractString
26
    string::T
27
    offset::Int
28
    ncodeunits::Int
29

30
    function SubString{T}(s::T, i::Int, j::Int) where T<:AbstractString
6,867,383✔
31
        i ≤ j || return new(s, 0, 0)
7,609,873✔
32
        @boundscheck begin
6,124,882✔
33
            checkbounds(s, i:j)
6,124,899✔
34
            @inbounds isvalid(s, i) || string_index_err(s, i)
6,124,863✔
35
            @inbounds isvalid(s, j) || string_index_err(s, j)
6,124,869✔
36
        end
37
        return new(s, i-1, nextind(s,j)-i)
6,124,849✔
38
    end
39
end
40

41
@propagate_inbounds SubString(s::T, i::Int, j::Int) where {T<:AbstractString} = SubString{T}(s, i, j)
6,867,469✔
42
@propagate_inbounds SubString(s::AbstractString, i::Integer, j::Integer=lastindex(s)) = SubString(s, Int(i), Int(j))
3,350,574✔
43
@propagate_inbounds SubString(s::AbstractString, r::AbstractUnitRange{<:Integer}) = SubString(s, first(r), last(r))
101,106✔
44

45
@propagate_inbounds function SubString(s::SubString, i::Int, j::Int)
389✔
46
    @boundscheck i ≤ j && checkbounds(s, i:j)
142,022✔
47
    SubString(s.string, s.offset+i, s.offset+j)
142,011✔
48
end
49

50
SubString(s::AbstractString) = SubString(s, 1, lastindex(s)::Int)
641✔
51
SubString{T}(s::T) where {T<:AbstractString} = SubString{T}(s, 1, lastindex(s)::Int)
×
52

53
@propagate_inbounds view(s::AbstractString, r::AbstractUnitRange{<:Integer}) = SubString(s, r)
453✔
54
@propagate_inbounds maybeview(s::AbstractString, r::AbstractUnitRange{<:Integer}) = view(s, r)
3✔
55
@propagate_inbounds maybeview(s::AbstractString, args...) = getindex(s, args...)
6✔
56

57
convert(::Type{SubString{S}}, s::AbstractString) where {S<:AbstractString} =
60✔
58
    SubString(convert(S, s))::SubString{S}
59
convert(::Type{T}, s::T) where {T<:SubString} = s
2✔
60

61
# Regex match allows only Union{String, SubString{String}} so define conversion to this type
62
convert(::Type{Union{String, SubString{String}}}, s::String) = s
×
63
convert(::Type{Union{String, SubString{String}}}, s::SubString{String}) = s
×
64
convert(::Type{Union{String, SubString{String}}}, s::AbstractString) = convert(String, s)::String
×
65

66
function String(s::SubString{String})
67,219✔
67
    parent = s.string
723,873✔
68
    copy = GC.@preserve parent unsafe_string(pointer(parent, s.offset+1), s.ncodeunits)
723,873✔
69
    return copy
723,873✔
70
end
71

72
ncodeunits(s::SubString) = s.ncodeunits
26,041,067✔
73
codeunit(s::SubString) = codeunit(s.string)::CodeunitType
×
74
length(s::SubString) = length(s.string, s.offset+1, s.offset+s.ncodeunits)
161,947✔
75

76
function codeunit(s::SubString, i::Integer)
1✔
77
    @boundscheck checkbounds(s, i)
1,191,877✔
78
    @inbounds return codeunit(s.string, s.offset + i)
1,191,877✔
79
end
80

81
function iterate(s::SubString, i::Integer=firstindex(s))
2,707✔
82
    i == ncodeunits(s)+1 && return nothing
6,312,604✔
83
    @boundscheck checkbounds(s, i)
3,140,963✔
84
    y = iterate(s.string, s.offset + i)
5,987,672✔
85
    y === nothing && return nothing
3,140,959✔
86
    c, i = y::Tuple{AbstractChar,Int}
3,140,755✔
87
    return c, i - s.offset
3,140,959✔
88
end
89

90
function getindex(s::SubString, i::Integer)
506,199✔
91
    @boundscheck checkbounds(s, i)
506,201✔
92
    @inbounds return getindex(s.string, s.offset + i)
506,197✔
93
end
94

95
isascii(ss::SubString{String}) = isascii(codeunits(ss))
×
96

97
function isvalid(s::SubString, i::Integer)
70,695✔
98
    ib = true
233✔
99
    @boundscheck ib = checkbounds(Bool, s, i)
24,926,168✔
100
    @inbounds return ib && isvalid(s.string, s.offset + i)::Bool
24,928,151✔
101
end
102

103
thisind(s::SubString{String}, i::Int) = _thisind_str(s, i)
620,262✔
104
nextind(s::SubString{String}, i::Int) = _nextind_str(s, i)
527,158✔
105

106
parent(s::SubString) = s.string
1✔
107
parentindices(s::SubString) = (s.offset + 1 : thisind(s.string, s.offset + s.ncodeunits),)
1✔
108

109
function ==(a::Union{String, SubString{String}}, b::Union{String, SubString{String}})
128,176✔
110
    sizeof(a) == sizeof(b) && _memcmp(a, b) == 0
15,665,307✔
111
end
112

113
function cmp(a::SubString{String}, b::SubString{String})
×
114
    c = _memcmp(a, b)
×
115
    return c < 0 ? -1 : c > 0 ? +1 : cmp(sizeof(a), sizeof(b))
×
116
end
117

118
# don't make unnecessary copies when passing substrings to C functions
119
cconvert(::Type{Ptr{UInt8}}, s::SubString{String}) = s
×
120
cconvert(::Type{Ptr{Int8}}, s::SubString{String}) = s
2✔
121

122
function unsafe_convert(::Type{Ptr{R}}, s::SubString{String}) where R<:Union{Int8, UInt8}
189✔
123
    convert(Ptr{R}, pointer(s.string)) + s.offset
696,097✔
124
end
125

126
pointer(x::SubString{String}) = pointer(x.string) + x.offset
3,249,235✔
127
pointer(x::SubString{String}, i::Integer) = pointer(x.string) + x.offset + (i-1)
65✔
128

129
function hash(s::SubString{String}, h::UInt)
284✔
130
    h += memhash_seed
284✔
131
    ccall(memhash, UInt, (Ptr{UInt8}, Csize_t, UInt32), s, sizeof(s), h % UInt32) + h
134,018✔
132
end
133

134
"""
135
    reverse(s::AbstractString) -> AbstractString
136

137
Reverses a string. Technically, this function reverses the codepoints in a string and its
138
main utility is for reversed-order string processing, especially for reversed
139
regular-expression searches. See also [`reverseind`](@ref) to convert indices in `s` to
140
indices in `reverse(s)` and vice-versa, and `graphemes` from module `Unicode` to
141
operate on user-visible "characters" (graphemes) rather than codepoints.
142
See also [`Iterators.reverse`](@ref) for
143
reverse-order iteration without making a copy. Custom string types must implement the
144
`reverse` function themselves and should typically return a string with the same type
145
and encoding. If they return a string with a different encoding, they must also override
146
`reverseind` for that string type to satisfy `s[reverseind(s,i)] == reverse(s)[i]`.
147

148
# Examples
149
```jldoctest
150
julia> reverse("JuliaLang")
151
"gnaLailuJ"
152
```
153

154
!!! note
155
    The examples below may be rendered differently on different systems.
156
    The comments indicate how they're supposed to be rendered
157

158
Combining characters can lead to surprising results:
159

160
```jldoctest
161
julia> reverse("ax̂e") # hat is above x in the input, above e in the output
162
"êxa"
163

164
julia> using Unicode
165

166
julia> join(reverse(collect(graphemes("ax̂e")))) # reverses graphemes; hat is above x in both in- and output
167
"ex̂a"
168
```
169
"""
170
function reverse(s::Union{String,SubString{String}})::String
1,042✔
171
    # Read characters forwards from `s` and write backwards to `out`
172
    out = _string_n(sizeof(s))
1,042✔
173
    offs = sizeof(s) + 1
1,042✔
174
    for c in s
1,960✔
175
        offs -= ncodeunits(c)
42,107✔
176
        __unsafe_string!(out, c, offs)
39,641✔
177
    end
74,105✔
178
    return out
1,042✔
179
end
180

181
string(a::String)            = String(a)
46,557✔
182
string(a::SubString{String}) = String(a)
81✔
183

184
function Symbol(s::SubString{String})
116✔
185
    return ccall(:jl_symbol_n, Ref{Symbol}, (Ptr{UInt8}, Int), s, sizeof(s))
10,327✔
186
end
187

188
@inline function __unsafe_string!(out, c::Char, offs::Integer) # out is a (new) String (or StringVector)
266✔
189
    x = bswap(reinterpret(UInt32, c))
1,825,847✔
190
    n = ncodeunits(c)
1,941,308✔
191
    GC.@preserve out begin
1,825,847✔
192
        unsafe_store!(pointer(out, offs), x % UInt8)
1,825,847✔
193
        n == 1 && return n
1,825,847✔
194
        x >>= 8
58,242✔
195
        unsafe_store!(pointer(out, offs+1), x % UInt8)
58,242✔
196
        n == 2 && return n
58,242✔
197
        x >>= 8
54,566✔
198
        unsafe_store!(pointer(out, offs+2), x % UInt8)
54,566✔
199
        n == 3 && return n
54,566✔
200
        x >>= 8
2,653✔
201
        unsafe_store!(pointer(out, offs+3), x % UInt8)
2,653✔
202
    end
203
    return n
2,653✔
204
end
205

206
@assume_effects :nothrow @inline function __unsafe_string!(out, s::String, offs::Integer)
×
207
    n = sizeof(s)
12,061,973✔
208
    GC.@preserve s out unsafe_copyto!(pointer(out, offs), pointer(s), n)
12,061,973✔
209
    return n
12,061,973✔
210
end
211

212
@inline function __unsafe_string!(out, s::SubString{String}, offs::Integer)
×
213
    n = sizeof(s)
558,250✔
214
    GC.@preserve s out unsafe_copyto!(pointer(out, offs), pointer(s), n)
558,250✔
215
    return n
558,250✔
216
end
217

218
@assume_effects :nothrow @inline function __unsafe_string!(out, s::Symbol, offs::Integer)
×
219
    n = sizeof(s)
15,934✔
220
    GC.@preserve s out unsafe_copyto!(pointer(out, offs), unsafe_convert(Ptr{UInt8},s), n)
15,934✔
221
    return n
15,934✔
222
end
223

224
# nothrow needed here because for v in a can't prove the indexing is inbounds.
225
@assume_effects :foldable :nothrow string(a::Union{Char, String, Symbol}...) = _string(a...)
5,572,220✔
226

227
string(a::Union{Char, String, SubString{String}, Symbol}...) = _string(a...)
553,453✔
228

229
function _string(a::Union{Char, String, SubString{String}, Symbol}...)
6,125,418✔
230
    n = 0
×
231
    for v in a
6,125,418✔
232
        # 4 types is too many for automatic Union-splitting, so we split manually
233
        # and allow one specializable call site per concrete type
234
        if v isa Char
1,688,969✔
235
            n += ncodeunits(v)
318,524✔
236
        elseif v isa String
1,655,647✔
237
            n += sizeof(v)
12,061,973✔
238
        elseif v isa SubString{String}
574,172✔
239
            n += sizeof(v)
558,250✔
240
        else
241
            n += sizeof(v::Symbol)
15,934✔
242
        end
243
    end
18,623,396✔
244
    out = _string_n(n)
6,125,418✔
245
    offs = 1
×
246
    for v in a
6,125,418✔
247
        if v isa Char
1,688,969✔
248
            offs += __unsafe_string!(out, v, offs)
266,551✔
249
        elseif v isa String || v isa SubString{String}
2,229,819✔
250
            offs += __unsafe_string!(out, v, offs)
12,620,223✔
251
        else
252
            offs += __unsafe_string!(out, v::Symbol, offs)
15,934✔
253
        end
254
    end
18,623,396✔
255
    return out
6,125,418✔
256
end
257

258
# don't assume effects for general integers since we cannot know their implementation
259
# not nothrow because r<0 throws
260
@assume_effects :foldable repeat(s::String, r::BitInteger) = @invoke repeat(s::String, r::Integer)
436,312✔
261

262
function repeat(s::Union{String, SubString{String}}, r::Integer)
436,295✔
263
    r < 0 && throw(ArgumentError("can't repeat a string $r times"))
436,295✔
264
    r == 0 && return ""
436,287✔
265
    r == 1 && return String(s)
326,595✔
266
    n = sizeof(s)
242,385✔
267
    out = _string_n(n*r)
242,385✔
268
    if n == 1 # common case: repeating a single-byte string
242,385✔
269
        @inbounds b = codeunit(s, 1)
200,932✔
270
        ccall(:memset, Ptr{Cvoid}, (Ptr{UInt8}, Cint, Csize_t), out, b, r)
200,932✔
271
    else
272
        for i = 0:r-1
82,906✔
273
            GC.@preserve s out unsafe_copyto!(pointer(out, i*n+1), pointer(s), n)
2,047,153✔
274
        end
2,047,153✔
275
    end
276
    return out
242,385✔
277
end
278

279
function filter(f, s::Union{String, SubString{String}})
42✔
280
    out = StringVector(sizeof(s))
42✔
281
    offset = 1
3✔
282
    for c in s
84✔
283
        if f(c)
844✔
284
            offset += __unsafe_string!(out, c, offset)
664✔
285
        end
286
    end
1,637✔
287
    resize!(out, offset-1)
84✔
288
    sizehint!(out, offset-1)
42✔
289
    return String(out)
42✔
290
end
291

292
getindex(s::AbstractString, r::AbstractUnitRange{<:Integer}) = SubString(s, r)
2,736✔
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