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

JuliaLang / julia / #38039

31 Mar 2025 08:00AM UTC coverage: 20.268% (-0.02%) from 20.292%
#38039

push

local

web-flow
`_precompilepkgs`: interactive progress display: fix unintended capture (#57932)

The variable `str` also exists in one of the enclosing closures. Use a
new variable, as was surely intended, instead of capturing and mutating
the `str`.

Improves the sysimage's resistance to invalidation.

9938 of 49034 relevant lines covered (20.27%)

98941.38 hits per line

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

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

3
import Core: Tuple
4

5
# Document NTuple here where we have everything needed for the doc system
6
"""
7
    NTuple{N, T}
8

9
A compact way of representing the type for a tuple of length `N` where all elements are of type `T`.
10

11
# Examples
12
```jldoctest
13
julia> isa((1, 2, 3, 4, 5, 6), NTuple{6, Int})
14
true
15
```
16

17
See also [`ntuple`](@ref).
18
"""
19
NTuple
20

21
# convenience function for extracting N from a Tuple (if defined)
22
# else return `nothing` for anything else given (such as Vararg or other non-sized Union)
23
_counttuple(::Type{<:NTuple{N,Any}}) where {N} = N
×
24
_counttuple(::Type) = nothing
×
25

26
## indexing ##
27

28
length(@nospecialize t::Tuple) = nfields(t)
332,753✔
29
firstindex(@nospecialize t::Tuple) = 1
×
30
lastindex(@nospecialize t::Tuple) = length(t)
×
31
size(@nospecialize(t::Tuple), d::Integer) = (d == 1) ? length(t) : throw(ArgumentError("invalid tuple dimension $d"))
×
32
axes(@nospecialize t::Tuple) = (OneTo(length(t)),)
×
33
getindex(@nospecialize(t::Tuple), i::Int) = getfield(t, i, @_boundscheck)
125,649,770✔
34
getindex(@nospecialize(t::Tuple), i::Integer) = getfield(t, convert(Int, i), @_boundscheck)
×
35
__safe_getindex(@nospecialize(t::Tuple), i::Int) = (@_nothrow_noub_meta; getfield(t, i, false))
13,817✔
36
getindex(t::Tuple, r::AbstractArray{<:Any,1}) = (eltype(t)[t[ri] for ri in r]...,)
×
37
getindex(t::Tuple, b::AbstractArray{Bool,1}) = length(b) == length(t) ? getindex(t, findall(b)) : throw(BoundsError(t, b))
×
38
getindex(t::Tuple, c::Colon) = t
×
39

40
get(t::Tuple, i::Integer, default) = i in 1:length(t) ? getindex(t, i) : default
×
41
get(f::Callable, t::Tuple, i::Integer) = i in 1:length(t) ? getindex(t, i) : f()
×
42

43
# returns new tuple; N.B.: becomes no-op if `i` is out-of-bounds
44

45
"""
46
    setindex(t::Tuple, v, i::Integer)
47

48
Creates a new tuple similar to `t` with the value at index `i` set to `v`.
49
Throws a `BoundsError` when out of bounds.
50

51
# Examples
52
```jldoctest
53
julia> Base.setindex((1, 2, 6), 2, 3) == (1, 2, 2)
54
true
55
```
56
"""
57
function setindex(x::Tuple, v, i::Integer)
×
58
    @boundscheck 1 <= i <= length(x) || throw(BoundsError(x, i))
×
59
    @inline
×
60
    _setindex(v, i, x...)
×
61
end
62

63
function _setindex(v, i::Integer, args::Vararg{Any,N}) where {N}
×
64
    @inline
×
65
    return ntuple(j -> ifelse(j == i, v, args[j]), Val{N}())::NTuple{N, Any}
×
66
end
67

68

69
## iterating ##
70

71
function iterate(@nospecialize(t::Tuple), i::Int=1)
17✔
72
    @inline
380,296✔
73
    @_nothrow_meta
380,296✔
74
    return (1 <= i <= length(t)) ? (t[i], i + 1) : nothing
11,729,809✔
75
end
76

77
keys(@nospecialize t::Tuple) = OneTo(length(t))
×
78

79
"""
80
    prevind(A, i)
81

82
Return the index before `i` in `A`. The returned index is often equivalent to
83
`i - 1` for an integer `i`. This function can be useful for generic code.
84

85
!!! warning
86
    The returned index might be out of bounds. Consider using
87
    [`checkbounds`](@ref).
88

89
See also: [`nextind`](@ref).
90

91
# Examples
92
```jldoctest
93
julia> x = [1 2; 3 4]
94
2×2 Matrix{Int64}:
95
 1  2
96
 3  4
97

98
julia> prevind(x, 4) # valid result
99
3
100

101
julia> prevind(x, 1) # invalid result
102
0
103

104
julia> prevind(x, CartesianIndex(2, 2)) # valid result
105
CartesianIndex(1, 2)
106

107
julia> prevind(x, CartesianIndex(1, 1)) # invalid result
108
CartesianIndex(2, 0)
109
```
110
"""
111
function prevind end
112

113
"""
114
    nextind(A, i)
115

116
Return the index after `i` in `A`. The returned index is often equivalent to
117
`i + 1` for an integer `i`. This function can be useful for generic code.
118

119
!!! warning
120
    The returned index might be out of bounds. Consider using
121
    [`checkbounds`](@ref).
122

123
See also: [`prevind`](@ref).
124

125
# Examples
126
```jldoctest
127
julia> x = [1 2; 3 4]
128
2×2 Matrix{Int64}:
129
 1  2
130
 3  4
131

132
julia> nextind(x, 1) # valid result
133
2
134

135
julia> nextind(x, 4) # invalid result
136
5
137

138
julia> nextind(x, CartesianIndex(1, 1)) # valid result
139
CartesianIndex(2, 1)
140

141
julia> nextind(x, CartesianIndex(2, 2)) # invalid result
142
CartesianIndex(1, 3)
143
```
144
"""
145
function nextind end
146

147
prevind(@nospecialize(t::Tuple), i::Integer) = Int(i)-1
×
148
nextind(@nospecialize(t::Tuple), i::Integer) = Int(i)+1
×
149

150
function keys(t::Tuple, t2::Tuple...)
×
151
    @inline
×
152
    OneTo(_maxlength(t, t2...))
×
153
end
154
_maxlength(t::Tuple) = length(t)
×
155
function _maxlength(t::Tuple, t2::Tuple, t3::Tuple...)
×
156
    @inline
×
157
    max(length(t), _maxlength(t2, t3...))
×
158
end
159

160
# this allows partial evaluation of bounded sequences of next() calls on tuples,
161
# while reducing to plain next() for arbitrary iterables.
162
indexed_iterate(t::Tuple, i::Int, state=1) = (@inline; (getfield(t, i), i+1))
32,939,158✔
163
indexed_iterate(a::Array, i::Int, state=1) = (@inline; (a[i], i+1))
1,481✔
164
function indexed_iterate(I, i)
2✔
165
    x = iterate(I)
42✔
166
    x === nothing && throw(BoundsError(I, i))
21✔
167
    x
1✔
168
end
169
function indexed_iterate(I, i, state)
2✔
170
    x = iterate(I, state)
44✔
171
    x === nothing && throw(BoundsError(I, i))
23✔
172
    x
3✔
173
end
174

175
"""
176
    Base.rest(collection[, itr_state])
177

178
Generic function for taking the tail of `collection`, starting from a specific iteration
179
state `itr_state`. Return a `Tuple`, if `collection` itself is a `Tuple`, a subtype of
180
`AbstractVector`, if `collection` is an `AbstractArray`, a subtype of `AbstractString`
181
if `collection` is an `AbstractString`, and an arbitrary iterator, falling back to
182
`Iterators.rest(collection[, itr_state])`, otherwise.
183

184
Can be overloaded for user-defined collection types to customize the behavior of [slurping
185
in assignments](@ref destructuring-assignment) in final position, like `a, b... = collection`.
186

187
!!! compat "Julia 1.6"
188
    `Base.rest` requires at least Julia 1.6.
189

190
See also: [`first`](@ref first), [`Iterators.rest`](@ref), [`Base.split_rest`](@ref).
191

192
# Examples
193
```jldoctest
194
julia> a = [1 2; 3 4]
195
2×2 Matrix{Int64}:
196
 1  2
197
 3  4
198

199
julia> first, state = iterate(a)
200
(1, 2)
201

202
julia> first, Base.rest(a, state)
203
(1, [3, 2, 4])
204
```
205
"""
206
function rest end
207
rest(t::Tuple) = t
×
208
rest(t::Tuple, i::Int) = ntuple(x -> getfield(t, x+i-1), length(t)-i+1)
×
209
rest(a::Array, i::Int=1) = a[i:end]
1✔
210
rest(a::Core.SimpleVector, i::Int=1) = a[i:end]
×
211
rest(itr, state...) = Iterators.rest(itr, state...)
×
212

213
"""
214
    Base.split_rest(collection, n::Int[, itr_state]) -> (rest_but_n, last_n)
215

216
Generic function for splitting the tail of `collection`, starting from a specific iteration
217
state `itr_state`. Returns a tuple of two new collections. The first one contains all
218
elements of the tail but the `n` last ones, which make up the second collection.
219

220
The type of the first collection generally follows that of [`Base.rest`](@ref), except that
221
the fallback case is not lazy, but is collected eagerly into a vector.
222

223
Can be overloaded for user-defined collection types to customize the behavior of [slurping
224
in assignments](@ref destructuring-assignment) in non-final position, like `a, b..., c = collection`.
225

226
!!! compat "Julia 1.9"
227
    `Base.split_rest` requires at least Julia 1.9.
228

229
See also: [`Base.rest`](@ref).
230

231
# Examples
232
```jldoctest
233
julia> a = [1 2; 3 4]
234
2×2 Matrix{Int64}:
235
 1  2
236
 3  4
237

238
julia> first, state = iterate(a)
239
(1, 2)
240

241
julia> first, Base.split_rest(a, 1, state)
242
(1, ([3, 2], [4]))
243
```
244
"""
245
function split_rest end
246
function split_rest(itr, n::Int, state...)
×
247
    if IteratorSize(itr) == IsInfinite()
×
248
        throw(ArgumentError("Cannot split an infinite iterator in the middle."))
×
249
    end
250
    return _split_rest(rest(itr, state...), n)
×
251
end
252
_split_rest(itr, n::Int) = _split_rest(collect(itr), n)
×
253
function _check_length_split_rest(len, n)
×
254
    len < n && throw(ArgumentError(
×
255
        "The iterator only contains $len elements, but at least $n were requested."
256
    ))
257
end
258
function _split_rest(a::Union{AbstractArray, Core.SimpleVector}, n::Int)
×
259
    _check_length_split_rest(length(a), n)
×
260
    return a[begin:end-n], a[end-n+1:end]
×
261
end
262

263
@eval split_rest(t::Tuple, n::Int, i=1) = ($(Expr(:meta, :aggressive_constprop)); (t[i:end-n], t[end-n+1:end]))
×
264

265
# Use dispatch to avoid a branch in first
266
first(::Tuple{}) = throw(ArgumentError("tuple must be non-empty"))
×
267
first(t::Tuple) = t[1]
142✔
268

269
# eltype
270

271
eltype(::Type{Tuple{}}) = Bottom
×
272
# the <: here makes the runtime a bit more complicated (needing to check isdefined), but really helps inference
273
eltype(t::Type{<:Tuple{Vararg{E}}}) where {E} = @isdefined(E) ? (E isa Type ? E : Union{}) : _compute_eltype(t)
11✔
274
eltype(t::Type{<:Tuple}) = _compute_eltype(t)
1✔
275
function _compute_eltype(@nospecialize t)
×
276
    @_total_meta
×
277
    has_free_typevars(t) && return Any
×
278
    t´ = unwrap_unionall(t)
×
279
    # Given t = Tuple{Vararg{S}} where S<:Real, the various
280
    # unwrapping/wrapping/va-handling here will return Real
281
    if t´ isa Union
×
282
        return promote_typejoin(_compute_eltype(rewrap_unionall(t´.a, t)),
×
283
                                _compute_eltype(rewrap_unionall(t´.b, t)))
284
    end
285
    p = (t´::DataType).parameters
×
286
    length(p) == 0 && return Union{}
×
287
    elt = rewrap_unionall(unwrapva(p[1]), t)
×
288
    elt isa Type || return Union{} # Tuple{2} is legal as a Type, but the eltype is Union{} since it is uninhabited
×
289
    r = elt
×
290
    for i in 2:length(p)
×
291
        r === Any && return r # if we've already reached Any, it can't widen any more
×
292
        elt = rewrap_unionall(unwrapva(p[i]), t)
×
293
        elt isa Type || return Union{} # Tuple{2} is legal as a Type, but the eltype is Union{} since it is uninhabited
×
294
        r = promote_typejoin(elt, r)
×
295
    end
×
296
    return r
×
297
end
298

299
# We'd like to be able to infer eltype(::Tuple), which needs to be able to
300
# look at these four methods:
301
#
302
# julia> methods(Base.eltype, Tuple{Type{<:Tuple}})
303
# 4 methods for generic function "eltype" from Base:
304
# [1] eltype(::Type{Union{}})
305
#  @ abstractarray.jl:234
306
# [2] eltype(::Type{Tuple{}})
307
#  @ tuple.jl:199
308
# [3] eltype(t::Type{<:Tuple{Vararg{E}}}) where E
309
#  @ tuple.jl:200
310
# [4] eltype(t::Type{<:Tuple})
311
#  @ tuple.jl:209
312
typeof(function eltype end).name.max_methods = UInt8(4)
313

314
# key/val types
315
keytype(@nospecialize t::Tuple) = keytype(typeof(t))
×
316
keytype(@nospecialize T::Type{<:Tuple}) = Int
×
317

318
valtype(@nospecialize t::Tuple) = valtype(typeof(t))
×
319
valtype(@nospecialize T::Type{<:Tuple}) = eltype(T)
×
320

321
# version of tail that doesn't throw on empty tuples (used in array indexing)
322
safe_tail(t::Tuple) = tail(t)
×
323
safe_tail(t::Tuple{}) = ()
×
324

325
# front (the converse of tail: it skips the last entry)
326

327
"""
328
    front(x::Tuple)::Tuple
329

330
Return a `Tuple` consisting of all but the last component of `x`.
331

332
See also: [`first`](@ref), [`tail`](@ref Base.tail).
333

334
# Examples
335
```jldoctest
336
julia> Base.front((1,2,3))
337
(1, 2)
338

339
julia> Base.front(())
340
ERROR: ArgumentError: Cannot call front on an empty tuple.
341
```
342
"""
343
function front(t::Tuple)
344
    @inline
×
345
    _front(t...)
×
346
end
347
_front() = throw(ArgumentError("Cannot call front on an empty tuple."))
×
348
_front(v) = ()
×
349
function _front(v, t...)
350
    @inline
×
351
    (v, _front(t...)...)
×
352
end
353

354
## mapping ##
355

356
# 1 argument function
357
map(f, t::Tuple{})              = ()
×
358
map(f, t::Tuple{Any,})          = (@inline; (f(t[1]),))
3,469,546✔
359
map(f, t::Tuple{Any, Any})      = (@inline; (f(t[1]), f(t[2])))
833,593✔
360
map(f, t::Tuple{Any, Any, Any}) = (@inline; (f(t[1]), f(t[2]), f(t[3])))
19✔
361
map(f, t::Tuple)                = (@inline; (f(t[1]), map(f,tail(t))...))
×
362
# stop inlining after some number of arguments to avoid code blowup
363
const Any32{N} = Tuple{Any,Any,Any,Any,Any,Any,Any,Any,
364
                       Any,Any,Any,Any,Any,Any,Any,Any,
365
                       Any,Any,Any,Any,Any,Any,Any,Any,
366
                       Any,Any,Any,Any,Any,Any,Any,Any,
367
                       Vararg{Any,N}}
368
const All32{T,N} = Tuple{T,T,T,T,T,T,T,T,
369
                         T,T,T,T,T,T,T,T,
370
                         T,T,T,T,T,T,T,T,
371
                         T,T,T,T,T,T,T,T,
372
                         Vararg{T,N}}
373
function map(f, t::Any32)
×
374
    n = length(t)
×
375
    A = Vector{Any}(undef, n)
×
376
    for i=1:n
×
377
        A[i] = f(t[i])
×
378
    end
×
379
    (A...,)
×
380
end
381
# 2 argument function
382
map(f, t::Tuple{},        s::Tuple{})        = ()
×
383
map(f, t::Tuple,          s::Tuple{})        = ()
×
384
map(f, t::Tuple{},        s::Tuple)          = ()
×
385
map(f, t::Tuple{Any,},    s::Tuple{Any,})    = (@inline; (f(t[1],s[1]),))
5,455✔
386
map(f, t::Tuple{Any,Any}, s::Tuple{Any,Any}) = (@inline; (f(t[1],s[1]), f(t[2],s[2])))
4✔
387
function map(f, t::Tuple, s::Tuple)
388
    @inline
2✔
389
    (f(t[1],s[1]), map(f, tail(t), tail(s))...)
4✔
390
end
391
function map(f, t::Any32, s::Any32)
×
392
    n = min(length(t), length(s))
×
393
    A = Vector{Any}(undef, n)
×
394
    for i = 1:n
×
395
        A[i] = f(t[i], s[i])
×
396
    end
×
397
    (A...,)
×
398
end
399
# n argument function
400
heads(ts::Tuple...) = map(t -> t[1], ts)
×
401
tails(ts::Tuple...) = map(tail, ts)
×
402
map(f, ::Tuple{}, ::Tuple{}...) = ()
×
403
anyempty(x::Tuple{}, xs...) = true
×
404
anyempty(x::Tuple, xs...) = anyempty(xs...)
×
405
anyempty() = false
×
406
function map(f, t1::Tuple, t2::Tuple, ts::Tuple...)
×
407
    @inline
×
408
    anyempty(t1, t2, ts...) && return ()
×
409
    (f(heads(t1, t2, ts...)...), map(f, tails(t1, t2, ts...)...)...)
×
410
end
411
function map(f, t1::Any32, t2::Any32, ts::Any32...)
×
412
    n = min(length(t1), length(t2), minimum(length, ts))
×
413
    A = Vector{Any}(undef, n)
×
414
    for i = 1:n
×
415
        A[i] = f(t1[i], t2[i], map(t -> t[i], ts)...)
×
416
    end
×
417
    (A...,)
×
418
end
419

420
# type-stable padding
421
fill_to_length(t::NTuple{N,Any}, val, ::Val{N}) where {N} = t
×
422
fill_to_length(t::Tuple{}, val, ::Val{1}) = (val,)
×
423
fill_to_length(t::Tuple{Any}, val, ::Val{2}) = (t..., val)
×
424
fill_to_length(t::Tuple{}, val, ::Val{2}) = (val, val)
×
425
#function fill_to_length(t::Tuple, val, ::Val{N}) where {N}
426
#    @inline
427
#    return (t..., ntuple(i -> val, N - length(t))...)
428
#end
429

430
# constructing from an iterator
431

432
function tuple_type_tail(T::Type)
×
433
    @_foldable_meta # TODO: this method is wrong (and not :foldable)
×
434
    if isa(T, UnionAll)
×
435
        return UnionAll(T.var, tuple_type_tail(T.body))
×
436
    elseif isa(T, Union)
×
437
        return Union{tuple_type_tail(T.a), tuple_type_tail(T.b)}
×
438
    else
439
        T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,)))
×
440
        if isvatuple(T) && length(T.parameters) == 1
×
441
            va = unwrap_unionall(T.parameters[1])::Core.TypeofVararg
×
442
            (isdefined(va, :N) && isa(va.N, Int)) || return T
×
443
            return Tuple{Vararg{va.T, va.N-1}}
×
444
        end
445
        return Tuple{argtail(T.parameters...)...}
×
446
    end
447
end
448

449
(::Type{T})(x::Tuple) where {T<:Tuple} = x isa T ? x : convert(T, x)  # still use `convert` for tuples
×
450

451
Tuple(x::Ref) = tuple(getindex(x))  # faster than iterator for one element
×
452
Tuple(x::Array{T,0}) where {T} = tuple(getindex(x))
×
453

454
(::Type{T})(itr) where {T<:Tuple} = _totuple(T, itr)
5✔
455

456
_totuple(::Type{Tuple{}}, itr, s...) = ()
×
457

458
function _totuple_err(@nospecialize T)
×
459
    @noinline
×
460
    throw(ArgumentError(LazyString("too few elements for tuple type ", T)))
×
461
end
462

463
function _totuple(::Type{T}, itr, s::Vararg{Any,N}) where {T,N}
×
464
    @inline
×
465
    y = iterate(itr, s...)
×
466
    y === nothing && _totuple_err(T)
×
467
    T1 = fieldtype(T, 1)
×
468
    y1 = y[1]
×
469
    t1 = y1 isa T1 ? y1 : convert(T1, y1)::T1
×
470
    # inference may give up in recursive calls, so annotate here to force accurate return type to be propagated
471
    rT = tuple_type_tail(T)
×
472
    ts = _totuple(rT, itr, y[2])::rT
×
473
    return (t1, ts...)::T
×
474
end
475

476
# use iterative algorithm for long tuples
477
function _totuple(T::Type{All32{E,N}}, itr) where {E,N}
×
478
    len = N+32
×
479
    elts = collect(E, Iterators.take(itr,len))
×
480
    if length(elts) != len
×
481
        _totuple_err(T)
×
482
    end
483
    (elts...,)
×
484
end
485

486
_totuple(::Type{Tuple{Vararg{E}}}, itr, s...) where {E} = (collect(E, Iterators.rest(itr,s...))...,)
×
487

488
_totuple(::Type{Tuple}, itr, s...) = (collect(Iterators.rest(itr,s...))...,)
×
489

490
# for types that `apply` knows about, just splatting is faster than collecting first
491
_totuple(::Type{Tuple}, itr::Array) = (itr...,)
5✔
492
_totuple(::Type{Tuple}, itr::SimpleVector) = (itr...,)
×
493
_totuple(::Type{Tuple}, itr::NamedTuple) = (itr...,)
×
494
_totuple(::Type{Tuple}, p::Pair) = (p.first, p.second)
×
495
_totuple(::Type{Tuple}, x::Number) = (x,) # to make Tuple(x) inferable
×
496

497
## find ##
498

499
_findfirst_rec(f, i::Int, ::Tuple{}) = nothing
×
500
_findfirst_rec(f, i::Int, t::Tuple) = (@inline; f(first(t)) ? i : _findfirst_rec(f, i+1, tail(t)))
×
501
function _findfirst_loop(f::Function, t)
×
502
    for i in eachindex(t)
×
503
        f(t[i]) && return i
×
504
    end
×
505
    return nothing
×
506
end
507
findfirst(f::Function, t::Tuple) = length(t) < 32 ? _findfirst_rec(f, 1, t) : _findfirst_loop(f, t)
×
508

509
findlast(f::Function, t::Tuple) = length(t) < 32 ? _findlast_rec(f, t) : _findlast_loop(f, t)
×
510
function _findlast_rec(f::Function, x::Tuple)
×
511
    r = findfirst(f, reverse(x))
×
512
    return isnothing(r) ? r : length(x) - r + 1
×
513
end
514
function _findlast_loop(f::Function, t)
×
515
    for i in reverse(1:length(t))
×
516
        f(t[i]) && return i
×
517
    end
×
518
    return nothing
×
519
end
520

521
## filter ##
522

523
filter_rec(f, xs::Tuple) = afoldl((ys, x) -> f(x) ? (ys..., x) : ys, (), xs...)
311✔
524

525
# use Array for long tuples
526
filter(f, t::Tuple) = length(t) < 32 ? filter_rec(f, t) : Tuple(filter(f, collect(t)))
311✔
527

528
## comparison ##
529

530
isequal(t1::Tuple, t2::Tuple) = length(t1) == length(t2) && _isequal(t1, t2)
×
531
_isequal(::Tuple{}, ::Tuple{}) = true
×
532
function _isequal(t1::Tuple{Any,Vararg{Any}}, t2::Tuple{Any,Vararg{Any}})
533
    return isequal(t1[1], t2[1]) && _isequal(tail(t1), tail(t2))
×
534
end
535
function _isequal(t1::Any32, t2::Any32)
×
536
    for i in eachindex(t1, t2)
×
537
        if !isequal(t1[i], t2[i])
×
538
            return false
×
539
        end
540
    end
×
541
    return true
×
542
end
543

544
==(t1::Tuple, t2::Tuple) = (length(t1) == length(t2)) && _eq(t1, t2)
359,178✔
545
_eq(t1::Tuple{}, t2::Tuple{}) = true
×
546
_eq_missing(t1::Tuple{}, t2::Tuple{}) = missing
×
547
function _eq(t1::Tuple, t2::Tuple)
548
    eq = t1[1] == t2[1]
326,856✔
549
    if eq === false
326,856✔
550
        return false
124,799✔
551
    elseif ismissing(eq)
54✔
552
        return _eq_missing(tail(t1), tail(t2))
×
553
    else
554
        return _eq(tail(t1), tail(t2))
202,057✔
555
    end
556
end
557
function _eq_missing(t1::Tuple, t2::Tuple)
×
558
    eq = t1[1] == t2[1]
×
559
    if eq === false
×
560
        return false
×
561
    else
562
        return _eq_missing(tail(t1), tail(t2))
×
563
    end
564
end
565
function _eq(t1::Any32, t2::Any32)
×
566
    anymissing = false
×
567
    for i in eachindex(t1, t2)
×
568
        eq = (t1[i] == t2[i])
×
569
        if ismissing(eq)
×
570
            anymissing = true
×
571
        elseif !eq
×
572
           return false
×
573
       end
574
    end
×
575
    return anymissing ? missing : true
×
576
end
577

578
const tuplehash_seed = UInt === UInt64 ? 0x77cfa1eef01bca90 : 0xf01bca90
579
hash(::Tuple{}, h::UInt) = h + tuplehash_seed
14,922✔
580
hash(t::Tuple, h::UInt) = hash(t[1], hash(tail(t), h))
206,159✔
581
function hash(t::Any32, h::UInt)
×
582
    out = h + tuplehash_seed
×
583
    for i = length(t):-1:1
×
584
        out = hash(t[i], out)
×
585
    end
×
586
    return out
×
587
end
588

589
<(::Tuple{}, ::Tuple{}) = false
×
590
<(::Tuple{}, ::Tuple) = true
×
591
<(::Tuple, ::Tuple{}) = false
×
592
function <(t1::Tuple, t2::Tuple)
593
    a, b = t1[1], t2[1]
2✔
594
    eq = (a == b)
285,198✔
595
    if ismissing(eq)
×
596
        return missing
×
597
    elseif !eq
285,198✔
598
        return a < b
167,889✔
599
    end
600
    return tail(t1) < tail(t2)
117,309✔
601
end
602
function <(t1::Any32, t2::Any32)
×
603
    n1, n2 = length(t1), length(t2)
×
604
    for i = 1:min(n1, n2)
×
605
        a, b = t1[i], t2[i]
×
606
        eq = (a == b)
×
607
        if ismissing(eq)
×
608
            return missing
×
609
        elseif !eq
×
610
           return a < b
×
611
        end
612
    end
×
613
    return n1 < n2
×
614
end
615

616
isless(::Tuple{}, ::Tuple{}) = false
×
617
isless(::Tuple{}, ::Tuple) = true
×
618
isless(::Tuple, ::Tuple{}) = false
×
619

620
"""
621
    isless(t1::Tuple, t2::Tuple)
622

623
Return `true` when `t1` is less than `t2` in lexicographic order.
624
"""
625
function isless(t1::Tuple, t2::Tuple)
×
626
    a, b = t1[1], t2[1]
×
627
    isless(a, b) || (isequal(a, b) && isless(tail(t1), tail(t2)))
2,329✔
628
end
629
function isless(t1::Any32, t2::Any32)
×
630
    n1, n2 = length(t1), length(t2)
×
631
    for i = 1:min(n1, n2)
×
632
        a, b = t1[i], t2[i]
×
633
        if !isequal(a, b)
×
634
            return isless(a, b)
×
635
        end
636
    end
×
637
    return n1 < n2
×
638
end
639

640
## functions ##
641

642
isempty(x::Tuple{}) = true
×
643
isempty(@nospecialize x::Tuple) = false
386✔
644

645
revargs() = ()
×
646
revargs(x, r...) = (revargs(r...)..., x)
×
647

648
reverse(t::Tuple) = revargs(t...)
×
649

650
## specialized reduction ##
651

652
prod(x::Tuple{}) = 1
×
653
# This is consistent with the regular prod because there is no need for size promotion
654
# if all elements in the tuple are of system size.
655
# It is defined here separately in order to support bootstrap, because it's needed earlier
656
# than the general prod definition is available.
657
prod(x::Tuple{Int, Vararg{Int}}) = *(x...)
256✔
658

659
# a version of `in` esp. for NamedTuple, to make it pure, and not compiled for each tuple length
660
function sym_in(x::Symbol, itr::Tuple{Vararg{Symbol}})
318,132✔
661
    @noinline
×
662
    @_total_meta
×
663
    for y in itr
318,132✔
664
        y === x && return true
2,578,295✔
665
    end
2,482,795✔
666
    return false
111,316✔
667
end
668
in(x::Symbol, itr::Tuple{Vararg{Symbol}}) = sym_in(x, itr)
964,023✔
669

670

671
"""
672
    empty(x::Tuple)
673

674
Return an empty tuple, `()`.
675
"""
676
empty(@nospecialize x::Tuple) = ()
×
677

678
foreach(f, itr::Tuple) = foldl((_, x) -> (f(x); nothing), itr, init=nothing)
3✔
679
foreach(f, itr::Tuple, itrs::Tuple...) = foldl((_, xs) -> (f(xs...); nothing), zip(itr, itrs...), init=nothing)
×
680

681
circshift((@nospecialize t::Union{Tuple{},Tuple{Any}}), @nospecialize _::Integer) = t
×
682
circshift(t::Tuple{Any,Any}, shift::Integer) = iseven(shift) ? t : reverse(t)
×
683
function circshift(x::Tuple{Any,Any,Any,Vararg{Any,N}}, shift::Integer) where {N}
×
684
    @inline
×
685
    len = N + 3
×
686
    j = mod1(shift, len)
×
687
    ntuple(k -> getindex(x, k-j+ifelse(k>j,0,len)), Val(len))::Tuple
×
688
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

© 2026 Coveralls, Inc