StatProfilerHTML.jl report
Generated on Mon, 01 Apr 2024 21:01:18
File source code
Line Exclusive Inclusive Code
1 # This file is a part of Julia. License is MIT: https://julialang.org/license
2
3 # Document NTuple here where we have everything needed for the doc system
4 """
5 NTuple{N, T}
6
7 A compact way of representing the type for a tuple of length `N` where all elements are of type `T`.
8
9 # Examples
10 ```jldoctest
11 julia> isa((1, 2, 3, 4, 5, 6), NTuple{6, Int})
12 true
13 ```
14
15 See also [`ntuple`](@ref).
16 """
17 NTuple
18
19 # convenience function for extracting N from a Tuple (if defined)
20 # else return `nothing` for anything else given (such as Vararg or other non-sized Union)
21 _counttuple(::Type{<:NTuple{N,Any}}) where {N} = N
22 _counttuple(::Type) = nothing
23
24 ## indexing ##
25
26 length(@nospecialize t::Tuple) = nfields(t)
27 firstindex(@nospecialize t::Tuple) = 1
28 lastindex(@nospecialize t::Tuple) = length(t)
29 size(@nospecialize(t::Tuple), d::Integer) = (d == 1) ? length(t) : throw(ArgumentError("invalid tuple dimension $d"))
30 axes(@nospecialize t::Tuple) = (OneTo(length(t)),)
31 1 (2 %) 1 (2 %)
1 (2 %) samples spent in getindex
1 (100 %) (ex.), 1 (100 %) (incl.) when called from getindex line 62
@eval getindex(@nospecialize(t::Tuple), i::Int) = getfield(t, i, $(Expr(:boundscheck)))
32 @eval getindex(@nospecialize(t::Tuple), i::Integer) = getfield(t, convert(Int, i), $(Expr(:boundscheck)))
33 __inbounds_getindex(@nospecialize(t::Tuple), i::Int) = getfield(t, i, false)
34 __inbounds_getindex(@nospecialize(t::Tuple), i::Integer) = getfield(t, convert(Int, i), false)
35 getindex(t::Tuple, r::AbstractArray{<:Any,1}) = (eltype(t)[t[ri] for ri in r]...,)
36 getindex(t::Tuple, b::AbstractArray{Bool,1}) = length(b) == length(t) ? getindex(t, findall(b)) : throw(BoundsError(t, b))
37 getindex(t::Tuple, c::Colon) = t
38
39 get(t::Tuple, i::Integer, default) = i in 1:length(t) ? getindex(t, i) : default
40 get(f::Callable, t::Tuple, i::Integer) = i in 1:length(t) ? getindex(t, i) : f()
41
42 # returns new tuple; N.B.: becomes no-op if `i` is out-of-bounds
43
44 """
45 setindex(c::Tuple, v, i::Integer)
46
47 Creates a new tuple similar to `x` with the value at index `i` set to `v`.
48 Throws a `BoundsError` when out of bounds.
49
50 # Examples
51 ```jldoctest
52 julia> Base.setindex((1, 2, 6), 2, 3) == (1, 2, 2)
53 true
54 ```
55 """
56 function setindex(x::Tuple, v, i::Integer)
57 @boundscheck 1 <= i <= length(x) || throw(BoundsError(x, i))
58 @inline
59 _setindex(v, i, x...)
60 end
61
62 function _setindex(v, i::Integer, args::Vararg{Any,N}) where {N}
63 @inline
64 return ntuple(j -> ifelse(j == i, v, args[j]), Val{N}())
65 end
66
67
68 ## iterating ##
69
70 function iterate(@nospecialize(t::Tuple), i::Int=1)
71 @inline
72 return (1 <= i <= length(t)) ? (t[i], i + 1) : nothing
73 end
74
75 keys(@nospecialize t::Tuple) = OneTo(length(t))
76
77 prevind(@nospecialize(t::Tuple), i::Integer) = Int(i)-1
78 nextind(@nospecialize(t::Tuple), i::Integer) = Int(i)+1
79
80 function keys(t::Tuple, t2::Tuple...)
81 @inline
82 OneTo(_maxlength(t, t2...))
83 end
84 _maxlength(t::Tuple) = length(t)
85 function _maxlength(t::Tuple, t2::Tuple, t3::Tuple...)
86 @inline
87 max(length(t), _maxlength(t2, t3...))
88 end
89
90 # this allows partial evaluation of bounded sequences of next() calls on tuples,
91 # while reducing to plain next() for arbitrary iterables.
92 indexed_iterate(t::Tuple, i::Int, state=1) = (@inline; (getfield(t, i), i+1))
93 indexed_iterate(a::Array, i::Int, state=1) = (@inline; (a[i], i+1))
94 function indexed_iterate(I, i)
95 x = iterate(I)
96 x === nothing && throw(BoundsError(I, i))
97 x
98 end
99 function indexed_iterate(I, i, state)
100 x = iterate(I, state)
101 x === nothing && throw(BoundsError(I, i))
102 x
103 end
104
105 """
106 Base.rest(collection[, itr_state])
107
108 Generic function for taking the tail of `collection`, starting from a specific iteration
109 state `itr_state`. Return a `Tuple`, if `collection` itself is a `Tuple`, a subtype of
110 `AbstractVector`, if `collection` is an `AbstractArray`, a subtype of `AbstractString`
111 if `collection` is an `AbstractString`, and an arbitrary iterator, falling back to
112 `Iterators.rest(collection[, itr_state])`, otherwise.
113
114 Can be overloaded for user-defined collection types to customize the behavior of [slurping
115 in assignments](@ref destructuring-assignment) in final position, like `a, b... = collection`.
116
117 !!! compat "Julia 1.6"
118 `Base.rest` requires at least Julia 1.6.
119
120 See also: [`first`](@ref first), [`Iterators.rest`](@ref), [`Base.split_rest`](@ref).
121
122 # Examples
123 ```jldoctest
124 julia> a = [1 2; 3 4]
125 2×2 Matrix{Int64}:
126 1 2
127 3 4
128
129 julia> first, state = iterate(a)
130 (1, 2)
131
132 julia> first, Base.rest(a, state)
133 (1, [3, 2, 4])
134 ```
135 """
136 function rest end
137 rest(t::Tuple) = t
138 rest(t::Tuple, i::Int) = ntuple(x -> getfield(t, x+i-1), length(t)-i+1)
139 rest(a::Array, i::Int=1) = a[i:end]
140 rest(a::Core.SimpleVector, i::Int=1) = a[i:end]
141 rest(itr, state...) = Iterators.rest(itr, state...)
142
143 """
144 Base.split_rest(collection, n::Int[, itr_state]) -> (rest_but_n, last_n)
145
146 Generic function for splitting the tail of `collection`, starting from a specific iteration
147 state `itr_state`. Returns a tuple of two new collections. The first one contains all
148 elements of the tail but the `n` last ones, which make up the second collection.
149
150 The type of the first collection generally follows that of [`Base.rest`](@ref), except that
151 the fallback case is not lazy, but is collected eagerly into a vector.
152
153 Can be overloaded for user-defined collection types to customize the behavior of [slurping
154 in assignments](@ref destructuring-assignment) in non-final position, like `a, b..., c = collection`.
155
156 !!! compat "Julia 1.9"
157 `Base.split_rest` requires at least Julia 1.9.
158
159 See also: [`Base.rest`](@ref).
160
161 # Examples
162 ```jldoctest
163 julia> a = [1 2; 3 4]
164 2×2 Matrix{Int64}:
165 1 2
166 3 4
167
168 julia> first, state = iterate(a)
169 (1, 2)
170
171 julia> first, Base.split_rest(a, 1, state)
172 (1, ([3, 2], [4]))
173 ```
174 """
175 function split_rest end
176 function split_rest(itr, n::Int, state...)
177 if IteratorSize(itr) == IsInfinite()
178 throw(ArgumentError("Cannot split an infinite iterator in the middle."))
179 end
180 return _split_rest(rest(itr, state...), n)
181 end
182 _split_rest(itr, n::Int) = _split_rest(collect(itr), n)
183 function _check_length_split_rest(len, n)
184 len < n && throw(ArgumentError(
185 "The iterator only contains $len elements, but at least $n were requested."
186 ))
187 end
188 function _split_rest(a::Union{AbstractArray, Core.SimpleVector}, n::Int)
189 _check_length_split_rest(length(a), n)
190 return a[begin:end-n], a[end-n+1:end]
191 end
192
193 @eval split_rest(t::Tuple, n::Int, i=1) = ($(Expr(:meta, :aggressive_constprop)); (t[i:end-n], t[end-n+1:end]))
194
195 # Use dispatch to avoid a branch in first
196 first(::Tuple{}) = throw(ArgumentError("tuple must be non-empty"))
197 first(t::Tuple) = t[1]
198
199 # eltype
200
201 eltype(::Type{Tuple{}}) = Bottom
202 function eltype(t::Type{<:Tuple{Vararg{E}}}) where {E}
203 if @isdefined(E)
204 return E
205 else
206 # TODO: need to guard against E being miscomputed by subtyping (ref #23017)
207 # and compute the result manually in this case
208 return _compute_eltype(t)
209 end
210 end
211 eltype(t::Type{<:Tuple}) = _compute_eltype(t)
212 function _tuple_unique_fieldtypes(@nospecialize t)
213 @_total_meta
214 types = IdSet()
215 t´ = unwrap_unionall(t)
216 # Given t = Tuple{Vararg{S}} where S<:Real, the various
217 # unwrapping/wrapping/va-handling here will return Real
218 if t´ isa Union
219 union!(types, _tuple_unique_fieldtypes(rewrap_unionall(t´.a, t)))
220 union!(types, _tuple_unique_fieldtypes(rewrap_unionall(t´.b, t)))
221 else
222 for ti in (t´::DataType).parameters
223 push!(types, rewrap_unionall(unwrapva(ti), t))
224 end
225 end
226 return Core.svec(types...)
227 end
228 function _compute_eltype(@nospecialize t)
229 @_total_meta # TODO: the compiler shouldn't need this
230 types = _tuple_unique_fieldtypes(t)
231 return afoldl(types...) do a, b
232 # if we've already reached Any, it can't widen any more
233 a === Any && return Any
234 b === Any && return Any
235 return promote_typejoin(a, b)
236 end
237 end
238
239 # We'd like to be able to infer eltype(::Tuple), which needs to be able to
240 # look at these four methods:
241 #
242 # julia> methods(Base.eltype, Tuple{Type{<:Tuple}})
243 # 4 methods for generic function "eltype" from Base:
244 # [1] eltype(::Type{Union{}})
245 # @ abstractarray.jl:234
246 # [2] eltype(::Type{Tuple{}})
247 # @ tuple.jl:199
248 # [3] eltype(t::Type{<:Tuple{Vararg{E}}}) where E
249 # @ tuple.jl:200
250 # [4] eltype(t::Type{<:Tuple})
251 # @ tuple.jl:209
252 typeof(function eltype end).name.max_methods = UInt8(4)
253
254 # version of tail that doesn't throw on empty tuples (used in array indexing)
255 safe_tail(t::Tuple) = tail(t)
256 safe_tail(t::Tuple{}) = ()
257
258 # front (the converse of tail: it skips the last entry)
259
260 """
261 front(x::Tuple)::Tuple
262
263 Return a `Tuple` consisting of all but the last component of `x`.
264
265 See also: [`first`](@ref), [`tail`](@ref Base.tail).
266
267 # Examples
268 ```jldoctest
269 julia> Base.front((1,2,3))
270 (1, 2)
271
272 julia> Base.front(())
273 ERROR: ArgumentError: Cannot call front on an empty tuple.
274 ```
275 """
276 function front(t::Tuple)
277 @inline
278 _front(t...)
279 end
280 _front() = throw(ArgumentError("Cannot call front on an empty tuple."))
281 _front(v) = ()
282 function _front(v, t...)
283 @inline
284 (v, _front(t...)...)
285 end
286
287 ## mapping ##
288
289 # 1 argument function
290 map(f, t::Tuple{}) = ()
291 map(f, t::Tuple{Any,}) = (@inline; (f(t[1]),))
292 map(f, t::Tuple{Any, Any}) = (@inline; (f(t[1]), f(t[2])))
293 map(f, t::Tuple{Any, Any, Any}) = (@inline; (f(t[1]), f(t[2]), f(t[3])))
294 map(f, t::Tuple) = (@inline; (f(t[1]), map(f,tail(t))...))
295 # stop inlining after some number of arguments to avoid code blowup
296 const Any32{N} = Tuple{Any,Any,Any,Any,Any,Any,Any,Any,
297 Any,Any,Any,Any,Any,Any,Any,Any,
298 Any,Any,Any,Any,Any,Any,Any,Any,
299 Any,Any,Any,Any,Any,Any,Any,Any,
300 Vararg{Any,N}}
301 const All32{T,N} = Tuple{T,T,T,T,T,T,T,T,
302 T,T,T,T,T,T,T,T,
303 T,T,T,T,T,T,T,T,
304 T,T,T,T,T,T,T,T,
305 Vararg{T,N}}
306 function map(f, t::Any32)
307 n = length(t)
308 A = Vector{Any}(undef, n)
309 for i=1:n
310 A[i] = f(t[i])
311 end
312 (A...,)
313 end
314 # 2 argument function
315 map(f, t::Tuple{}, s::Tuple{}) = ()
316 map(f, t::Tuple, s::Tuple{}) = ()
317 map(f, t::Tuple{}, s::Tuple) = ()
318 map(f, t::Tuple{Any,}, s::Tuple{Any,}) = (@inline; (f(t[1],s[1]),))
319 map(f, t::Tuple{Any,Any}, s::Tuple{Any,Any}) = (@inline; (f(t[1],s[1]), f(t[2],s[2])))
320 function map(f, t::Tuple, s::Tuple)
321 @inline
322 (f(t[1],s[1]), map(f, tail(t), tail(s))...)
323 end
324 function map(f, t::Any32, s::Any32)
325 n = min(length(t), length(s))
326 A = Vector{Any}(undef, n)
327 for i = 1:n
328 A[i] = f(t[i], s[i])
329 end
330 (A...,)
331 end
332 # n argument function
333 heads(ts::Tuple...) = map(t -> t[1], ts)
334 tails(ts::Tuple...) = map(tail, ts)
335 map(f, ::Tuple{}...) = ()
336 anyempty(x::Tuple{}, xs...) = true
337 anyempty(x::Tuple, xs...) = anyempty(xs...)
338 anyempty() = false
339 function map(f, t1::Tuple, t2::Tuple, ts::Tuple...)
340 @inline
341 anyempty(t1, t2, ts...) && return ()
342 (f(heads(t1, t2, ts...)...), map(f, tails(t1, t2, ts...)...)...)
343 end
344 function map(f, t1::Any32, t2::Any32, ts::Any32...)
345 n = min(length(t1), length(t2), minimum(length, ts))
346 A = Vector{Any}(undef, n)
347 for i = 1:n
348 A[i] = f(t1[i], t2[i], map(t -> t[i], ts)...)
349 end
350 (A...,)
351 end
352
353 # type-stable padding
354 fill_to_length(t::NTuple{N,Any}, val, ::Val{N}) where {N} = t
355 fill_to_length(t::Tuple{}, val, ::Val{1}) = (val,)
356 fill_to_length(t::Tuple{Any}, val, ::Val{2}) = (t..., val)
357 fill_to_length(t::Tuple{}, val, ::Val{2}) = (val, val)
358 #function fill_to_length(t::Tuple, val, ::Val{N}) where {N}
359 # @inline
360 # return (t..., ntuple(i -> val, N - length(t))...)
361 #end
362
363 # constructing from an iterator
364
365 # only define these in Base, to avoid overwriting the constructors
366 # NOTE: this means this constructor must be avoided in Core.Compiler!
367 if nameof(@__MODULE__) === :Base
368
369 function tuple_type_tail(T::Type)
370 @_foldable_meta # TODO: this method is wrong (and not :foldable)
371 if isa(T, UnionAll)
372 return UnionAll(T.var, tuple_type_tail(T.body))
373 elseif isa(T, Union)
374 return Union{tuple_type_tail(T.a), tuple_type_tail(T.b)}
375 else
376 T.name === Tuple.name || throw(MethodError(tuple_type_tail, (T,)))
377 if isvatuple(T) && length(T.parameters) == 1
378 va = unwrap_unionall(T.parameters[1])::Core.TypeofVararg
379 (isdefined(va, :N) && isa(va.N, Int)) || return T
380 return Tuple{Vararg{va.T, va.N-1}}
381 end
382 return Tuple{argtail(T.parameters...)...}
383 end
384 end
385
386 (::Type{T})(x::Tuple) where {T<:Tuple} = x isa T ? x : convert(T, x) # still use `convert` for tuples
387
388 Tuple(x::Ref) = tuple(getindex(x)) # faster than iterator for one element
389 Tuple(x::Array{T,0}) where {T} = tuple(getindex(x))
390
391 (::Type{T})(itr) where {T<:Tuple} = _totuple(T, itr)
392
393 _totuple(::Type{Tuple{}}, itr, s...) = ()
394
395 function _totuple_err(@nospecialize T)
396 @noinline
397 throw(ArgumentError("too few elements for tuple type $T"))
398 end
399
400 function _totuple(::Type{T}, itr, s::Vararg{Any,N}) where {T,N}
401 @inline
402 y = iterate(itr, s...)
403 y === nothing && _totuple_err(T)
404 T1 = fieldtype(T, 1)
405 y1 = y[1]
406 t1 = y1 isa T1 ? y1 : convert(T1, y1)::T1
407 # inference may give up in recursive calls, so annotate here to force accurate return type to be propagated
408 rT = tuple_type_tail(T)
409 ts = _totuple(rT, itr, y[2])::rT
410 return (t1, ts...)::T
411 end
412
413 # use iterative algorithm for long tuples
414 function _totuple(T::Type{All32{E,N}}, itr) where {E,N}
415 len = N+32
416 elts = collect(E, Iterators.take(itr,len))
417 if length(elts) != len
418 _totuple_err(T)
419 end
420 (elts...,)
421 end
422
423 _totuple(::Type{Tuple{Vararg{E}}}, itr, s...) where {E} = (collect(E, Iterators.rest(itr,s...))...,)
424
425 _totuple(::Type{Tuple}, itr, s...) = (collect(Iterators.rest(itr,s...))...,)
426
427 # for types that `apply` knows about, just splatting is faster than collecting first
428 _totuple(::Type{Tuple}, itr::Array) = (itr...,)
429 _totuple(::Type{Tuple}, itr::SimpleVector) = (itr...,)
430 _totuple(::Type{Tuple}, itr::NamedTuple) = (itr...,)
431 _totuple(::Type{Tuple}, x::Number) = (x,) # to make Tuple(x) inferable
432
433 end
434
435 ## find ##
436
437 _findfirst_rec(f, i::Int, ::Tuple{}) = nothing
438 _findfirst_rec(f, i::Int, t::Tuple) = (@inline; f(first(t)) ? i : _findfirst_rec(f, i+1, tail(t)))
439 function _findfirst_loop(f::Function, t)
440 for i in 1:length(t)
441 f(t[i]) && return i
442 end
443 return nothing
444 end
445 findfirst(f::Function, t::Tuple) = length(t) < 32 ? _findfirst_rec(f, 1, t) : _findfirst_loop(f, t)
446
447 findlast(f::Function, t::Tuple) = length(t) < 32 ? _findlast_rec(f, t) : _findlast_loop(f, t)
448 function _findlast_rec(f::Function, x::Tuple)
449 r = findfirst(f, reverse(x))
450 return isnothing(r) ? r : length(x) - r + 1
451 end
452 function _findlast_loop(f::Function, t)
453 for i in reverse(1:length(t))
454 f(t[i]) && return i
455 end
456 return nothing
457 end
458
459 ## filter ##
460
461 filter_rec(f, xs::Tuple) = afoldl((ys, x) -> f(x) ? (ys..., x) : ys, (), xs...)
462
463 # use Array for long tuples
464 filter(f, t::Tuple) = length(t) < 32 ? filter_rec(f, t) : Tuple(filter(f, collect(t)))
465
466 ## comparison ##
467
468 isequal(t1::Tuple, t2::Tuple) = length(t1) == length(t2) && _isequal(t1, t2)
469 _isequal(::Tuple{}, ::Tuple{}) = true
470 function _isequal(t1::Tuple{Any,Vararg{Any}}, t2::Tuple{Any,Vararg{Any}})
471 return isequal(t1[1], t2[1]) && _isequal(tail(t1), tail(t2))
472 end
473 function _isequal(t1::Any32, t2::Any32)
474 for i = 1:length(t1)
475 if !isequal(t1[i], t2[i])
476 return false
477 end
478 end
479 return true
480 end
481
482 ==(t1::Tuple, t2::Tuple) = (length(t1) == length(t2)) && _eq(t1, t2)
483 _eq(t1::Tuple{}, t2::Tuple{}) = true
484 _eq_missing(t1::Tuple{}, t2::Tuple{}) = missing
485 function _eq(t1::Tuple, t2::Tuple)
486 eq = t1[1] == t2[1]
487 if eq === false
488 return false
489 elseif ismissing(eq)
490 return _eq_missing(tail(t1), tail(t2))
491 else
492 return _eq(tail(t1), tail(t2))
493 end
494 end
495 function _eq_missing(t1::Tuple, t2::Tuple)
496 eq = t1[1] == t2[1]
497 if eq === false
498 return false
499 else
500 return _eq_missing(tail(t1), tail(t2))
501 end
502 end
503 function _eq(t1::Any32, t2::Any32)
504 anymissing = false
505 for i = 1:length(t1)
506 eq = (t1[i] == t2[i])
507 if ismissing(eq)
508 anymissing = true
509 elseif !eq
510 return false
511 end
512 end
513 return anymissing ? missing : true
514 end
515
516 const tuplehash_seed = UInt === UInt64 ? 0x77cfa1eef01bca90 : 0xf01bca90
517 hash(::Tuple{}, h::UInt) = h + tuplehash_seed
518 hash(t::Tuple, h::UInt) = hash(t[1], hash(tail(t), h))
519 function hash(t::Any32, h::UInt)
520 out = h + tuplehash_seed
521 for i = length(t):-1:1
522 out = hash(t[i], out)
523 end
524 return out
525 end
526
527 <(::Tuple{}, ::Tuple{}) = false
528 <(::Tuple{}, ::Tuple) = true
529 <(::Tuple, ::Tuple{}) = false
530 function <(t1::Tuple, t2::Tuple)
531 a, b = t1[1], t2[1]
532 eq = (a == b)
533 if ismissing(eq)
534 return missing
535 elseif !eq
536 return a < b
537 end
538 return tail(t1) < tail(t2)
539 end
540 function <(t1::Any32, t2::Any32)
541 n1, n2 = length(t1), length(t2)
542 for i = 1:min(n1, n2)
543 a, b = t1[i], t2[i]
544 eq = (a == b)
545 if ismissing(eq)
546 return missing
547 elseif !eq
548 return a < b
549 end
550 end
551 return n1 < n2
552 end
553
554 isless(::Tuple{}, ::Tuple{}) = false
555 isless(::Tuple{}, ::Tuple) = true
556 isless(::Tuple, ::Tuple{}) = false
557
558 """
559 isless(t1::Tuple, t2::Tuple)
560
561 Return `true` when `t1` is less than `t2` in lexicographic order.
562 """
563 function isless(t1::Tuple, t2::Tuple)
564 a, b = t1[1], t2[1]
565 isless(a, b) || (isequal(a, b) && isless(tail(t1), tail(t2)))
566 end
567 function isless(t1::Any32, t2::Any32)
568 n1, n2 = length(t1), length(t2)
569 for i = 1:min(n1, n2)
570 a, b = t1[i], t2[i]
571 if !isequal(a, b)
572 return isless(a, b)
573 end
574 end
575 return n1 < n2
576 end
577
578 ## functions ##
579
580 isempty(x::Tuple{}) = true
581 isempty(@nospecialize x::Tuple) = false
582
583 revargs() = ()
584 revargs(x, r...) = (revargs(r...)..., x)
585
586 reverse(t::Tuple) = revargs(t...)
587
588 ## specialized reduction ##
589
590 prod(x::Tuple{}) = 1
591 # This is consistent with the regular prod because there is no need for size promotion
592 # if all elements in the tuple are of system size.
593 # It is defined here separately in order to support bootstrap, because it's needed earlier
594 # than the general prod definition is available.
595 prod(x::Tuple{Int, Vararg{Int}}) = *(x...)
596
597 all(x::Tuple{}) = true
598 all(x::Tuple{Bool}) = x[1]
599 all(x::Tuple{Bool, Bool}) = x[1]&x[2]
600 all(x::Tuple{Bool, Bool, Bool}) = x[1]&x[2]&x[3]
601 # use generic reductions for the rest
602
603 any(x::Tuple{}) = false
604 any(x::Tuple{Bool}) = x[1]
605 any(x::Tuple{Bool, Bool}) = x[1]|x[2]
606 any(x::Tuple{Bool, Bool, Bool}) = x[1]|x[2]|x[3]
607
608 # a version of `in` esp. for NamedTuple, to make it pure, and not compiled for each tuple length
609 function sym_in(x::Symbol, itr::Tuple{Vararg{Symbol}})
610 @noinline
611 @_total_meta
612 for y in itr
613 y === x && return true
614 end
615 return false
616 end
617 in(x::Symbol, itr::Tuple{Vararg{Symbol}}) = sym_in(x, itr)
618
619
620 """
621 empty(x::Tuple)
622
623 Return an empty tuple, `()`.
624 """
625 empty(@nospecialize x::Tuple) = ()
626
627 foreach(f, itr::Tuple) = foldl((_, x) -> (f(x); nothing), itr, init=nothing)
628 foreach(f, itrs::Tuple...) = foldl((_, xs) -> (f(xs...); nothing), zip(itrs...), init=nothing)