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

JuliaLang / julia / #37997

29 Jan 2025 02:08AM UTC coverage: 17.283% (-68.7%) from 85.981%
#37997

push

local

web-flow
bpart: Start enforcing min_world for global variable definitions (#57150)

This is the analog of #57102 for global variables. Unlike for consants,
there is no automatic global backdate mechanism. The reasoning for this
is that global variables can be declared at any time, unlike constants
which can only be decalared once their value is available. As a result
code patterns using `Core.eval` to declare globals are rarer and likely
incorrect.

1 of 22 new or added lines in 3 files covered. (4.55%)

31430 existing lines in 188 files now uncovered.

7903 of 45728 relevant lines covered (17.28%)

98663.7 hits per line

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

24.67
/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

UNCOV
30
    function SubString{T}(s::T, i::Int, j::Int) where T<:AbstractString
×
UNCOV
31
        i ≤ j || return new(s, 0, 0)
×
UNCOV
32
        @boundscheck begin
×
UNCOV
33
            checkbounds(s, i:j)
×
UNCOV
34
            @inbounds isvalid(s, i) || string_index_err(s, i)
×
UNCOV
35
            @inbounds isvalid(s, j) || string_index_err(s, j)
×
36
        end
UNCOV
37
        return new(s, i-1, nextind(s,j)-i)
×
38
    end
UNCOV
39
    function SubString{T}(s::T, i::Int, j::Int, ::Val{:noshift}) where T<:AbstractString
×
UNCOV
40
        @boundscheck if !(i == j == 0)
×
UNCOV
41
            si, sj = i + 1, prevind(s, j + i + 1)
×
UNCOV
42
            @inbounds isvalid(s, si) || string_index_err(s, si)
×
UNCOV
43
            @inbounds isvalid(s, sj) || string_index_err(s, sj)
×
44
        end
UNCOV
45
        new(s, i, j)
×
46
    end
47
end
48

49
@propagate_inbounds SubString(s::T, i::Int, j::Int) where {T<:AbstractString} = SubString{T}(s, i, j)
45,115✔
UNCOV
50
@propagate_inbounds SubString(s::T, i::Int, j::Int, v::Val{:noshift}) where {T<:AbstractString} = SubString{T}(s, i, j, v)
×
51
@propagate_inbounds SubString(s::AbstractString, i::Integer, j::Integer=lastindex(s)) = SubString(s, Int(i), Int(j))
204✔
52
@propagate_inbounds SubString(s::AbstractString, r::AbstractUnitRange{<:Integer}) = SubString(s, first(r), last(r))
39,413✔
53

54
@propagate_inbounds function SubString(s::SubString, i::Int, j::Int)
55
    @boundscheck i ≤ j && checkbounds(s, i:j)
5,584✔
56
    SubString(s.string, s.offset+i, s.offset+j)
5,584✔
57
end
58

UNCOV
59
SubString(s::AbstractString) = SubString(s, 1, lastindex(s)::Int)
×
UNCOV
60
SubString{T}(s::T) where {T<:AbstractString} = SubString{T}(s, 1, lastindex(s)::Int)
×
61

UNCOV
62
@propagate_inbounds view(s::AbstractString, r::AbstractUnitRange{<:Integer}) = SubString(s, r)
×
UNCOV
63
@propagate_inbounds maybeview(s::AbstractString, r::AbstractUnitRange{<:Integer}) = view(s, r)
×
UNCOV
64
@propagate_inbounds maybeview(s::AbstractString, args...) = getindex(s, args...)
×
65

UNCOV
66
convert(::Type{SubString{S}}, s::AbstractString) where {S<:AbstractString} =
×
67
    SubString(convert(S, s))::SubString{S}
UNCOV
68
convert(::Type{T}, s::T) where {T<:SubString} = s
×
69

70
# Regex match allows only Union{String, SubString{String}} so define conversion to this type
UNCOV
71
convert(::Type{Union{String, SubString{String}}}, s::String) = s
×
72
convert(::Type{Union{String, SubString{String}}}, s::SubString{String}) = s
×
73
convert(::Type{Union{String, SubString{String}}}, s::AbstractString) = convert(String, s)::String
×
74

75
function String(s::SubString{String})
76
    parent = s.string
228,431✔
77
    copy = GC.@preserve parent unsafe_string(pointer(parent, s.offset+1), s.ncodeunits)
228,431✔
78
    return copy
228,431✔
79
end
80

81
ncodeunits(s::SubString) = s.ncodeunits
1,444,861✔
82
codeunit(s::SubString) = codeunit(s.string)::CodeunitType
×
UNCOV
83
length(s::SubString) = length(s.string, s.offset+1, s.offset+s.ncodeunits)
×
84

85
function codeunit(s::SubString, i::Integer)
86
    @boundscheck checkbounds(s, i)
5,665✔
87
    @inbounds return codeunit(s.string, s.offset + i)
5,665✔
88
end
89

90
function iterate(s::SubString, i::Integer=firstindex(s))
91
    i == ncodeunits(s)+1 && return nothing
24,958✔
92
    @boundscheck checkbounds(s, i)
18,919✔
93
    y = iterate(s.string, s.offset + i)
37,838✔
94
    y === nothing && return nothing
18,919✔
95
    c, i = y::Tuple{AbstractChar,Int}
18,919✔
96
    return c, i - s.offset
18,919✔
97
end
98

99
function getindex(s::SubString, i::Integer)
100
    @boundscheck checkbounds(s, i)
15,162✔
101
    @inbounds return getindex(s.string, s.offset + i)
30,324✔
102
end
103

104
isascii(ss::SubString{String}) = isascii(codeunits(ss))
×
105

106
function isvalid(s::SubString, i::Integer)
UNCOV
107
    ib = true
×
108
    @boundscheck ib = checkbounds(Bool, s, i)
3,525✔
109
    @inbounds return ib && isvalid(s.string, s.offset + i)::Bool
7,050✔
110
end
111

112
thisind(s::SubString{String}, i::Int) = _thisind_str(s, i)
11,038✔
113
nextind(s::SubString{String}, i::Int) = _nextind_str(s, i)
4✔
114

UNCOV
115
parent(s::SubString) = s.string
×
UNCOV
116
parentindices(s::SubString) = (s.offset + 1 : thisind(s.string, s.offset + s.ncodeunits),)
×
117

118
function ==(a::Union{String, SubString{String}}, b::Union{String, SubString{String}})
119
    sizeof(a) == sizeof(b) && _memcmp(a, b) == 0
551,558✔
120
end
121

122
function cmp(a::SubString{String}, b::SubString{String})
×
123
    c = _memcmp(a, b)
×
124
    return c < 0 ? -1 : c > 0 ? +1 : cmp(sizeof(a), sizeof(b))
×
125
end
126

127
# don't make unnecessary copies when passing substrings to C functions
128
cconvert(::Type{Ptr{UInt8}}, s::SubString{String}) = s
×
UNCOV
129
cconvert(::Type{Ptr{Int8}}, s::SubString{String}) = s
×
130

131
function unsafe_convert(::Type{Ptr{R}}, s::SubString{String}) where R<:Union{Int8, UInt8}
132
    convert(Ptr{R}, pointer(s.string)) + s.offset
430,707✔
133
end
134

135
pointer(x::SubString{String}) = pointer(x.string) + x.offset
3,987✔
UNCOV
136
pointer(x::SubString{String}, i::Integer) = pointer(x.string) + x.offset + (i-1)
×
137

138
function hash(s::SubString{String}, h::UInt)
UNCOV
139
    h += memhash_seed
×
140
    ccall(memhash, UInt, (Ptr{UInt8}, Csize_t, UInt32), s, sizeof(s), h % UInt32) + h
129,421✔
141
end
142

143
_isannotated(::SubString{T}) where {T} = _isannotated(T)
×
144

145
"""
146
    reverse(s::AbstractString) -> AbstractString
147

148
Reverses a string. Technically, this function reverses the codepoints in a string and its
149
main utility is for reversed-order string processing, especially for reversed
150
regular-expression searches. See also [`reverseind`](@ref) to convert indices in `s` to
151
indices in `reverse(s)` and vice-versa, and `graphemes` from module `Unicode` to
152
operate on user-visible "characters" (graphemes) rather than codepoints.
153
See also [`Iterators.reverse`](@ref) for
154
reverse-order iteration without making a copy. Custom string types must implement the
155
`reverse` function themselves and should typically return a string with the same type
156
and encoding. If they return a string with a different encoding, they must also override
157
`reverseind` for that string type to satisfy `s[reverseind(s,i)] == reverse(s)[i]`.
158

159
# Examples
160
```jldoctest
161
julia> reverse("JuliaLang")
162
"gnaLailuJ"
163
```
164

165
!!! note
166
    The examples below may be rendered differently on different systems.
167
    The comments indicate how they're supposed to be rendered
168

169
Combining characters can lead to surprising results:
170

171
```jldoctest
172
julia> reverse("ax̂e") # hat is above x in the input, above e in the output
173
"êxa"
174

175
julia> using Unicode
176

177
julia> join(reverse(collect(graphemes("ax̂e")))) # reverses graphemes; hat is above x in both in- and output
178
"ex̂a"
179
```
180
"""
UNCOV
181
function reverse(s::Union{String,SubString{String}})::String
×
182
    # Read characters forwards from `s` and write backwards to `out`
UNCOV
183
    out = _string_n(sizeof(s))
×
UNCOV
184
    offs = sizeof(s) + 1
×
UNCOV
185
    for c in s
×
UNCOV
186
        offs -= ncodeunits(c)
×
UNCOV
187
        __unsafe_string!(out, c, offs)
×
UNCOV
188
    end
×
UNCOV
189
    return out
×
190
end
191

UNCOV
192
string(a::String)            = String(a)
×
193
string(a::SubString{String}) = String(a)
14✔
194

195
function Symbol(s::SubString{String})
UNCOV
196
    return ccall(:jl_symbol_n, Ref{Symbol}, (Ptr{UInt8}, Int), s, sizeof(s))
×
197
end
198

199
@inline function __unsafe_string!(out, c::Char, offs::Integer) # out is a (new) String (or StringVector)
200
    x = bswap(reinterpret(UInt32, c))
18,663✔
201
    n = ncodeunits(c)
18,663✔
202
    GC.@preserve out begin
18,663✔
203
        unsafe_store!(pointer(out, offs), x % UInt8)
18,663✔
204
        n == 1 && return n
18,663✔
UNCOV
205
        x >>= 8
×
UNCOV
206
        unsafe_store!(pointer(out, offs+1), x % UInt8)
×
UNCOV
207
        n == 2 && return n
×
UNCOV
208
        x >>= 8
×
UNCOV
209
        unsafe_store!(pointer(out, offs+2), x % UInt8)
×
UNCOV
210
        n == 3 && return n
×
UNCOV
211
        x >>= 8
×
UNCOV
212
        unsafe_store!(pointer(out, offs+3), x % UInt8)
×
213
    end
UNCOV
214
    return n
×
215
end
216

UNCOV
217
@assume_effects :nothrow @inline function __unsafe_string!(out, s::String, offs::Integer)
×
UNCOV
218
    n = sizeof(s)
×
UNCOV
219
    GC.@preserve s out unsafe_copyto!(pointer(out, offs), pointer(s), n)
×
UNCOV
220
    return n
×
221
end
222

UNCOV
223
@inline function __unsafe_string!(out, s::SubString{String}, offs::Integer)
×
UNCOV
224
    n = sizeof(s)
×
UNCOV
225
    GC.@preserve s out unsafe_copyto!(pointer(out, offs), pointer(s), n)
×
UNCOV
226
    return n
×
227
end
228

UNCOV
229
@assume_effects :nothrow @inline function __unsafe_string!(out, s::Symbol, offs::Integer)
×
UNCOV
230
    n = sizeof(s)
×
UNCOV
231
    GC.@preserve s out unsafe_copyto!(pointer(out, offs), unsafe_convert(Ptr{UInt8},s), n)
×
UNCOV
232
    return n
×
233
end
234

235
# nothrow needed here because for v in a can't prove the indexing is inbounds.
236
@assume_effects :foldable :nothrow string(a::Union{Char, String, Symbol}...) = _string(a...)
258,361✔
237

238
string(a::Union{Char, String, SubString{String}, Symbol}...) = _string(a...)
257,243✔
239

240
function _string(a::Union{Char, String, SubString{String}, Symbol}...)
UNCOV
241
    n = 0
×
UNCOV
242
    for v in a
×
243
        # 4 types is too many for automatic Union-splitting, so we split manually
244
        # and allow one specializable call site per concrete type
UNCOV
245
        if v isa Char
×
UNCOV
246
            n += ncodeunits(v)
×
UNCOV
247
        elseif v isa String
×
UNCOV
248
            n += sizeof(v)
×
UNCOV
249
        elseif v isa SubString{String}
×
UNCOV
250
            n += sizeof(v)
×
251
        else
UNCOV
252
            n += sizeof(v::Symbol)
×
253
        end
UNCOV
254
    end
×
UNCOV
255
    out = _string_n(n)
×
UNCOV
256
    offs = 1
×
UNCOV
257
    for v in a
×
UNCOV
258
        if v isa Char
×
UNCOV
259
            offs += __unsafe_string!(out, v, offs)
×
UNCOV
260
        elseif v isa String || v isa SubString{String}
×
UNCOV
261
            offs += __unsafe_string!(out, v, offs)
×
262
        else
UNCOV
263
            offs += __unsafe_string!(out, v::Symbol, offs)
×
264
        end
UNCOV
265
    end
×
UNCOV
266
    return out
×
267
end
268

269
# don't assume effects for general integers since we cannot know their implementation
270
# not nothrow because r<0 throws
271
@assume_effects :foldable repeat(s::String, r::BitInteger) = @invoke repeat(s::String, r::Integer)
67✔
272

UNCOV
273
function repeat(s::Union{String, SubString{String}}, r::Integer)
×
UNCOV
274
    r < 0 && throw(ArgumentError("can't repeat a string $r times"))
×
UNCOV
275
    r = UInt(r)::UInt
×
UNCOV
276
    r == 0 && return ""
×
UNCOV
277
    r == 1 && return String(s)
×
UNCOV
278
    n = sizeof(s)
×
UNCOV
279
    out = _string_n(n*r)
×
UNCOV
280
    if n == 1 # common case: repeating a single-byte string
×
UNCOV
281
        @inbounds b = codeunit(s, 1)
×
UNCOV
282
        memset(unsafe_convert(Ptr{UInt8}, out), b, r)
×
283
    else
UNCOV
284
        for i = 0:r-1
×
UNCOV
285
            GC.@preserve s out unsafe_copyto!(pointer(out, i*n+1), pointer(s), n)
×
UNCOV
286
        end
×
287
    end
UNCOV
288
    return out
×
289
end
290

UNCOV
291
function filter(f, s::Union{String, SubString{String}})
×
UNCOV
292
    out = StringVector(sizeof(s))
×
UNCOV
293
    offset = 1
×
UNCOV
294
    for c in s
×
UNCOV
295
        if f(c)
×
UNCOV
296
            offset += __unsafe_string!(out, c, offset)
×
297
        end
UNCOV
298
    end
×
UNCOV
299
    resize!(out, offset-1)
×
UNCOV
300
    sizehint!(out, offset-1)
×
UNCOV
301
    return String(out)
×
302
end
303

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