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

JuliaLang / julia / #37497

pending completion
#37497

push

local

web-flow
<a href="https://github.com/JuliaLang/julia/commit/<a class=hub.com/JuliaLang/julia/commit/def2ddacc9a9b064d06c24d12885427fb0502465">def2ddacc<a href="https://github.com/JuliaLang/julia/commit/def2ddacc9a9b064d06c24d12885427fb0502465">&quot;&gt;make default worker pool an AbstractWorkerPool (#49101)

Changes [Distributed._default_worker_pool](https://github.com/JuliaLang/julia/blob/</a><a class="double-link" href="https://github.com/JuliaLang/julia/commit/<a class="double-link" href="https://github.com/JuliaLang/julia/commit/5f5d2040511b42ba74bd7529a0eac9cf817ad496">5f5d20405</a>">5f5d20405</a><a href="https://github.com/JuliaLang/julia/commit/def2ddacc9a9b064d06c24d12885427fb0502465">/stdlib/Distributed/src/workerpool.jl#L242) to hold an `AbstractWorkerPool` instead of `WorkerPool`. With this, alternate implementations can be plugged in as the default pool. Helps in cases where a cluster is always meant to use a certain custom pool. Lower level calls can then work without having to pass a custom pool reference with every call.

4 of 4 new or added lines in 2 files covered. (100.0%)

71044 of 82770 relevant lines covered (85.83%)

33857692.69 hits per line

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

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

3
"""
4
    StringIndexError(str, i)
5

6
An error occurred when trying to access `str` at index `i` that is not valid.
7
"""
8
struct StringIndexError <: Exception
9
    string::AbstractString
665✔
10
    index::Integer
11
end
12
@noinline string_index_err(s::AbstractString, i::Integer) =
661✔
13
    throw(StringIndexError(s, Int(i)))
14
function Base.showerror(io::IO, exc::StringIndexError)
4✔
15
    s = exc.string
4✔
16
    print(io, "StringIndexError: ", "invalid index [$(exc.index)]")
4✔
17
    if firstindex(s) <= exc.index <= ncodeunits(s)
4✔
18
        iprev = thisind(s, exc.index)
4✔
19
        inext = nextind(s, iprev)
4✔
20
        escprev = escape_string(s[iprev:iprev])
4✔
21
        if inext <= ncodeunits(s)
4✔
22
            escnext = escape_string(s[inext:inext])
3✔
23
            print(io, ", valid nearby indices [$iprev]=>'$escprev', [$inext]=>'$escnext'")
3✔
24
        else
25
            print(io, ", valid nearby index [$iprev]=>'$escprev'")
1✔
26
        end
27
    end
28
end
29

30
const ByteArray = Union{CodeUnits{UInt8,String}, Vector{UInt8},Vector{Int8}, FastContiguousSubArray{UInt8,1,CodeUnits{UInt8,String}}, FastContiguousSubArray{UInt8,1,Vector{UInt8}}, FastContiguousSubArray{Int8,1,Vector{Int8}}}
31

32
@inline between(b::T, lo::T, hi::T) where {T<:Integer} = (lo ≤ b) & (b ≤ hi)
156,396,838✔
33

34
"""
35
    String <: AbstractString
36

37
The default string type in Julia, used by e.g. string literals.
38

39
`String`s are immutable sequences of `Char`s. A `String` is stored internally as
40
a contiguous byte array, and while they are interpreted as being UTF-8 encoded,
41
they can be composed of any byte sequence. Use [`isvalid`](@ref) to validate
42
that the underlying byte sequence is valid as UTF-8.
43
"""
44
String
45

46
## constructors and conversions ##
47

48
# String constructor docstring from boot.jl, workaround for #16730
49
# and the unavailability of @doc in boot.jl context.
50
"""
51
    String(v::AbstractVector{UInt8})
52

53
Create a new `String` object using the data buffer from byte vector `v`.
54
If `v` is a `Vector{UInt8}` it will be truncated to zero length and future
55
modification of `v` cannot affect the contents of the resulting string.
56
To avoid truncation of `Vector{UInt8}` data, use `String(copy(v))`; for other
57
`AbstractVector` types, `String(v)` already makes a copy.
58

59
When possible, the memory of `v` will be used without copying when the `String`
60
object is created. This is guaranteed to be the case for byte vectors returned
61
by [`take!`](@ref) on a writable [`IOBuffer`](@ref) and by calls to
62
[`read(io, nb)`](@ref). This allows zero-copy conversion of I/O data to strings.
63
In other cases, `Vector{UInt8}` data may be copied, but `v` is truncated anyway
64
to guarantee consistent behavior.
65
"""
66
String(v::AbstractVector{UInt8}) = String(copyto!(StringVector(length(v)), v))
2,612,856✔
67
String(v::Vector{UInt8}) = ccall(:jl_array_to_string, Ref{String}, (Any,), v)
6,680,791✔
68

69
"""
70
    unsafe_string(p::Ptr{UInt8}, [length::Integer])
71

72
Copy a string from the address of a C-style (NUL-terminated) string encoded as UTF-8.
73
(The pointer can be safely freed afterwards.) If `length` is specified
74
(the length of the data in bytes), the string does not have to be NUL-terminated.
75

76
This function is labeled "unsafe" because it will crash if `p` is not
77
a valid memory address to data of the requested length.
78
"""
79
function unsafe_string(p::Union{Ptr{UInt8},Ptr{Int8}}, len::Integer)
1,143✔
80
    p == C_NULL && throw(ArgumentError("cannot convert NULL to string"))
614,527✔
81
    ccall(:jl_pchar_to_string, Ref{String}, (Ptr{UInt8}, Int), p, len)
614,526✔
82
end
83
function unsafe_string(p::Union{Ptr{UInt8},Ptr{Int8}})
10,142✔
84
    p == C_NULL && throw(ArgumentError("cannot convert NULL to string"))
3,039,483✔
85
    ccall(:jl_cstr_to_string, Ref{String}, (Ptr{UInt8},), p)
3,039,482✔
86
end
87

88
# This is @assume_effects :effect_free :nothrow :terminates_globally @ccall jl_alloc_string(n::Csize_t)::Ref{String},
89
# but the macro is not available at this time in bootstrap, so we write it manually.
90
@eval _string_n(n::Integer) = $(Expr(:foreigncall, QuoteNode(:jl_alloc_string), Ref{String}, Expr(:call, Expr(:core, :svec), :Csize_t), 1, QuoteNode((:ccall,0xe)), :(convert(Csize_t, n))))
109,233,171✔
91

92
"""
93
    String(s::AbstractString)
94

95
Create a new `String` from an existing `AbstractString`.
96
"""
97
String(s::AbstractString) = print_to_string(s)
397✔
98
@assume_effects :total String(s::Symbol) = unsafe_string(unsafe_convert(Ptr{UInt8}, s))
612,947✔
99

100
unsafe_wrap(::Type{Vector{UInt8}}, s::String) = ccall(:jl_string_to_array, Ref{Vector{UInt8}}, (Any,), s)
6,479,132✔
101

102
Vector{UInt8}(s::CodeUnits{UInt8,String}) = copyto!(Vector{UInt8}(undef, length(s)), s)
20,936✔
103
Vector{UInt8}(s::String) = Vector{UInt8}(codeunits(s))
20,860✔
104
Array{UInt8}(s::String)  = Vector{UInt8}(codeunits(s))
×
105

106
String(s::CodeUnits{UInt8,String}) = s.s
3✔
107

108
## low-level functions ##
109

110
pointer(s::String) = unsafe_convert(Ptr{UInt8}, s)
417,254,465✔
111
pointer(s::String, i::Integer) = pointer(s) + Int(i)::Int - 1
292,908,341✔
112

113
ncodeunits(s::String) = Core.sizeof(s)
355,099,131✔
114
codeunit(s::String) = UInt8
×
115

116
codeunit(s::String, i::Integer) = codeunit(s, Int(i))
×
117
@assume_effects :foldable @inline function codeunit(s::String, i::Int)
678,984✔
118
    @boundscheck checkbounds(s, i)
273,204,275✔
119
    b = GC.@preserve s unsafe_load(pointer(s, i))
273,204,275✔
120
    return b
273,204,275✔
121
end
122

123
## comparison ##
124

125
@assume_effects :total _memcmp(a::String, b::String) = @invoke _memcmp(a::Union{Ptr{UInt8},AbstractString},b::Union{Ptr{UInt8},AbstractString})
370,258✔
126

127
_memcmp(a::Union{Ptr{UInt8},AbstractString}, b::Union{Ptr{UInt8},AbstractString}) = _memcmp(a, b, min(sizeof(a), sizeof(b)))
716,697✔
128
function _memcmp(a::Union{Ptr{UInt8},AbstractString}, b::Union{Ptr{UInt8},AbstractString}, len::Int)
297✔
129
    ccall(:memcmp, Cint, (Ptr{UInt8}, Ptr{UInt8}, Csize_t), a, b, len % Csize_t) % Int
1,406,585✔
130
end
131

132
function cmp(a::String, b::String)
1✔
133
    al, bl = sizeof(a), sizeof(b)
370,258✔
134
    c = _memcmp(a, b)
370,258✔
135
    return c < 0 ? -1 : c > 0 ? +1 : cmp(al,bl)
588,047✔
136
end
137

138
==(a::String, b::String) = a===b
10,452,809✔
139

140
typemin(::Type{String}) = ""
2✔
141
typemin(::String) = typemin(String)
1✔
142

143
## thisind, nextind ##
144

145
@propagate_inbounds thisind(s::String, i::Int) = _thisind_str(s, i)
181,211,392✔
146

147
# s should be String or SubString{String}
148
@inline function _thisind_str(s, i::Int)
×
149
    i == 0 && return 0
91,217,909✔
150
    n = ncodeunits(s)
91,189,640✔
151
    i == n + 1 && return i
91,189,640✔
152
    @boundscheck between(i, 1, n) || throw(BoundsError(s, i))
91,167,198✔
153
    @inbounds b = codeunit(s, i)
91,167,174✔
154
    (b & 0xc0 == 0x80) & (i-1 > 0) || return i
162,266,284✔
155
    @inbounds b = codeunit(s, i-1)
20,068,064✔
156
    between(b, 0b11000000, 0b11110111) && return i-1
20,068,064✔
157
    (b & 0xc0 == 0x80) & (i-2 > 0) || return i
15,660,209✔
158
    @inbounds b = codeunit(s, i-2)
7,171,013✔
159
    between(b, 0b11100000, 0b11110111) && return i-2
7,171,013✔
160
    (b & 0xc0 == 0x80) & (i-3 > 0) || return i
5,906,601✔
161
    @inbounds b = codeunit(s, i-3)
1,027,051✔
162
    between(b, 0b11110000, 0b11110111) && return i-3
1,027,051✔
163
    return i
241,004✔
164
end
165

166
@propagate_inbounds nextind(s::String, i::Int) = _nextind_str(s, i)
14,196,474✔
167

168
# s should be String or SubString{String}
169
@inline function _nextind_str(s, i::Int)
14,706,001✔
170
    i == 0 && return 1
14,706,001✔
171
    n = ncodeunits(s)
14,685,183✔
172
    @boundscheck between(i, 1, n) || throw(BoundsError(s, i))
14,685,195✔
173
    @inbounds l = codeunit(s, i)
14,685,171✔
174
    (l < 0x80) | (0xf8 ≤ l) && return i+1
14,685,171✔
175
    if l < 0xc0
132,137✔
176
        i′ = @inbounds thisind(s, i)
51,357✔
177
        return i′ < i ? @inbounds(nextind(s, i′)) : i+1
30,403✔
178
    end
179
    # first continuation byte
180
    (i += 1) > n && return i
101,734✔
181
    @inbounds b = codeunit(s, i)
101,096✔
182
    b & 0xc0 ≠ 0x80 && return i
101,096✔
183
    ((i += 1) > n) | (l < 0xe0) && return i
93,852✔
184
    # second continuation byte
185
    @inbounds b = codeunit(s, i)
76,341✔
186
    b & 0xc0 ≠ 0x80 && return i
76,341✔
187
    ((i += 1) > n) | (l < 0xf0) && return i
72,708✔
188
    # third continuation byte
189
    @inbounds b = codeunit(s, i)
20,796✔
190
    ifelse(b & 0xc0 ≠ 0x80, i, i+1)
20,796✔
191
end
192

193
## checking UTF-8 & ACSII validity ##
194

195
byte_string_classify(s::Union{String,Vector{UInt8},FastContiguousSubArray{UInt8,1,Vector{UInt8}}}) =
20,322✔
196
    ccall(:u8_isvalid, Int32, (Ptr{UInt8}, Int), s, sizeof(s))
197
    # 0: neither valid ASCII nor UTF-8
198
    # 1: valid ASCII
199
    # 2: valid UTF-8
200

201
isvalid(::Type{String}, s::Union{Vector{UInt8},FastContiguousSubArray{UInt8,1,Vector{UInt8}},String}) = byte_string_classify(s) ≠ 0
20,322✔
202
isvalid(s::String) = isvalid(String, s)
39✔
203

204
is_valid_continuation(c) = c & 0xc0 == 0x80
8✔
205

206
## required core functionality ##
207

208
@inline function iterate(s::String, i::Int=firstindex(s))
64,875✔
209
    (i % UInt) - 1 < ncodeunits(s) || return nothing
29,356,238✔
210
    b = @inbounds codeunit(s, i)
19,841,489✔
211
    u = UInt32(b) << 24
19,841,489✔
212
    between(b, 0x80, 0xf7) || return reinterpret(Char, u), i+1
38,763,660✔
213
    return iterate_continued(s, i, u)
919,318✔
214
end
215

216
function iterate_continued(s::String, i::Int, u::UInt32)
919,318✔
217
    u < 0xc0000000 && (i += 1; @goto ret)
919,419✔
218
    n = ncodeunits(s)
919,217✔
219
    # first continuation byte
220
    (i += 1) > n && @goto ret
919,217✔
221
    @inbounds b = codeunit(s, i)
919,197✔
222
    b & 0xc0 == 0x80 || @goto ret
919,197✔
223
    u |= UInt32(b) << 16
919,136✔
224
    # second continuation byte
225
    ((i += 1) > n) | (u < 0xe0000000) && @goto ret
919,136✔
226
    @inbounds b = codeunit(s, i)
854,270✔
227
    b & 0xc0 == 0x80 || @goto ret
854,272✔
228
    u |= UInt32(b) << 8
854,268✔
229
    # third continuation byte
230
    ((i += 1) > n) | (u < 0xf0000000) && @goto ret
854,268✔
231
    @inbounds b = codeunit(s, i)
273,688✔
232
    b & 0xc0 == 0x80 || @goto ret
273,689✔
233
    u |= UInt32(b); i += 1
547,374✔
234
@label ret
×
235
    return reinterpret(Char, u), i
919,318✔
236
end
237

238
@propagate_inbounds function getindex(s::String, i::Int)
156,407✔
239
    b = codeunit(s, i)
2,631,967✔
240
    u = UInt32(b) << 24
2,631,967✔
241
    between(b, 0x80, 0xf7) || return reinterpret(Char, u)
5,260,200✔
242
    return getindex_continued(s, i, u)
3,734✔
243
end
244

245
function getindex_continued(s::String, i::Int, u::UInt32)
3,734✔
246
    if u < 0xc0000000
3,734✔
247
        # called from `getindex` which checks bounds
248
        @inbounds isvalid(s, i) && @goto ret
16✔
249
        string_index_err(s, i)
1✔
250
    end
251
    n = ncodeunits(s)
3,718✔
252

253
    (i += 1) > n && @goto ret
3,718✔
254
    @inbounds b = codeunit(s, i) # cont byte 1
3,717✔
255
    b & 0xc0 == 0x80 || @goto ret
3,717✔
256
    u |= UInt32(b) << 16
3,716✔
257

258
    ((i += 1) > n) | (u < 0xe0000000) && @goto ret
3,716✔
259
    @inbounds b = codeunit(s, i) # cont byte 2
2,481✔
260
    b & 0xc0 == 0x80 || @goto ret
2,481✔
261
    u |= UInt32(b) << 8
2,481✔
262

263
    ((i += 1) > n) | (u < 0xf0000000) && @goto ret
2,481✔
264
    @inbounds b = codeunit(s, i) # cont byte 3
478✔
265
    b & 0xc0 == 0x80 || @goto ret
478✔
266
    u |= UInt32(b)
478✔
267
@label ret
×
268
    return reinterpret(Char, u)
3,733✔
269
end
270

271
getindex(s::String, r::AbstractUnitRange{<:Integer}) = s[Int(first(r)):Int(last(r))]
×
272

273
@inline function getindex(s::String, r::UnitRange{Int})
1,496,818✔
274
    isempty(r) && return ""
986,071✔
275
    i, j = first(r), last(r)
69,412✔
276
    @boundscheck begin
961,256✔
277
        checkbounds(s, r)
961,238✔
278
        @inbounds isvalid(s, i) || string_index_err(s, i)
961,226✔
279
        @inbounds isvalid(s, j) || string_index_err(s, j)
961,227✔
280
    end
281
    j = nextind(s, j) - 1
961,249✔
282
    n = j - i + 1
961,249✔
283
    ss = _string_n(n)
961,249✔
284
    GC.@preserve s ss unsafe_copyto!(pointer(ss), pointer(s, i), n)
961,249✔
285
    return ss
961,249✔
286
end
287

288
# nothrow because we know the start and end indices are valid
289
@assume_effects :nothrow length(s::String) = length_continued(s, 1, ncodeunits(s), ncodeunits(s))
793,340✔
290

291
# effects needed because @inbounds
292
@assume_effects :consistent :effect_free @inline function length(s::String, i::Int, j::Int)
68,251✔
293
    @boundscheck begin
229,478✔
294
        0 < i ≤ ncodeunits(s)+1 || throw(BoundsError(s, i))
229,478✔
295
        0 ≤ j < ncodeunits(s)+1 || throw(BoundsError(s, j))
229,482✔
296
    end
297
    j < i && return 0
229,474✔
298
    @inbounds i, k = thisind(s, i), i
352,748✔
299
    c = j - i + (i == k)
176,374✔
300
    @inbounds length_continued(s, i, j, c)
176,374✔
301
end
302

303
@assume_effects :terminates_locally @inline @propagate_inbounds function length_continued(s::String, i::Int, n::Int, c::Int)
896,947✔
304
    i < n || return c
1,194,579✔
305
    b = codeunit(s, i)
744,849✔
306
    while true
4,168,382✔
307
        while true
49,916,251✔
308
            (i += 1) ≤ n || return c
50,660,329✔
309
            0xc0 ≤ b ≤ 0xf7 && break
49,172,173✔
310
            b = codeunit(s, i)
45,747,869✔
311
        end
45,747,869✔
312
        l = b
3,424,304✔
313
        b = codeunit(s, i) # cont byte 1
3,424,304✔
314
        c -= (x = b & 0xc0 == 0x80)
3,424,304✔
315
        x & (l ≥ 0xe0) || continue
3,424,304✔
316

317
        (i += 1) ≤ n || return c
3,025,143✔
318
        b = codeunit(s, i) # cont byte 2
3,023,681✔
319
        c -= (x = b & 0xc0 == 0x80)
3,023,681✔
320
        x & (l ≥ 0xf0) || continue
5,150,375✔
321

322
        (i += 1) ≤ n || return c
897,027✔
323
        b = codeunit(s, i) # cont byte 3
896,947✔
324
        c -= (b & 0xc0 == 0x80)
896,947✔
325
    end
3,423,533✔
326
end
327

328
## overload methods for efficiency ##
329

330
isvalid(s::String, i::Int) = checkbounds(Bool, s, i) && thisind(s, i) == i
83,501,665✔
331

332
isascii(s::String) = isascii(codeunits(s))
25,782✔
333

334
# don't assume effects for general integers since we cannot know their implementation
335
@assume_effects :foldable repeat(c::Char, r::BitInteger) = @invoke repeat(c::Char, r::Integer)
14,269✔
336

337
"""
338
    repeat(c::AbstractChar, r::Integer) -> String
339

340
Repeat a character `r` times. This can equivalently be accomplished by calling
341
[`c^r`](@ref :^(::Union{AbstractString, AbstractChar}, ::Integer)).
342

343
# Examples
344
```jldoctest
345
julia> repeat('A', 3)
346
"AAA"
347
```
348
"""
349
function repeat(c::AbstractChar, r::Integer)
14,270✔
350
    c = Char(c)::Char
14,270✔
351
    r == 0 && return ""
14,270✔
352
    r < 0 && throw(ArgumentError("can't repeat a character $r times"))
10,165✔
353
    u = bswap(reinterpret(UInt32, c))
10,161✔
354
    n = 4 - (leading_zeros(u | 0xff) >> 3)
10,161✔
355
    s = _string_n(n*r)
10,161✔
356
    p = pointer(s)
10,159✔
357
    GC.@preserve s if n == 1
10,159✔
358
        ccall(:memset, Ptr{Cvoid}, (Ptr{UInt8}, Cint, Csize_t), p, u % UInt8, r)
10,133✔
359
    elseif n == 2
26✔
360
        p16 = reinterpret(Ptr{UInt16}, p)
6✔
361
        for i = 1:r
12✔
362
            unsafe_store!(p16, u % UInt16, i)
20✔
363
        end
20✔
364
    elseif n == 3
20✔
365
        b1 = (u >> 0) % UInt8
16✔
366
        b2 = (u >> 8) % UInt8
16✔
367
        b3 = (u >> 16) % UInt8
16✔
368
        for i = 0:r-1
32✔
369
            unsafe_store!(p, b1, 3i + 1)
45✔
370
            unsafe_store!(p, b2, 3i + 2)
45✔
371
            unsafe_store!(p, b3, 3i + 3)
45✔
372
        end
45✔
373
    elseif n == 4
4✔
374
        p32 = reinterpret(Ptr{UInt32}, p)
4✔
375
        for i = 1:r
8✔
376
            unsafe_store!(p32, u, i)
8✔
377
        end
10,167✔
378
    end
379
    return s
10,159✔
380
end
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

© 2025 Coveralls, Inc