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

JuliaLang / julia / #37801

08 Jun 2024 05:10AM UTC coverage: 87.504% (+0.03%) from 87.474%
#37801

push

local

web-flow
Don't let setglobal! implicitly create bindings (#54678)

PR #44231 (part of Julia 1.9) introduced the ability to modify globals
with `Mod.sym = val` syntax. However, the intention of this syntax was
always to modify *existing* globals in other modules. Unfortunately, as
implemented, it also implicitly creates new bindings in the other
module, even if the binding was not previously declared. This was not
intended, but it's a bit of a syntax corner case, so nobody caught it at
the time.

After some extensive discussions and taking into account the near future
direction we want to go with bindings (#54654 for both), the consensus
was reached that we should try to undo the implicit creation of bindings
(but not the ability to assign the *value* of globals in other modules).
Note that this was always an error until Julia 1.9, so hopefully it
hasn't crept into too many packages yet. We'll see what pkgeval says. If
use is extensive, we may want to consider a softer removal strategy.

Across base and stdlib, there's two cases affected by this change:
1. A left over debug statement in `precompile` that wanted to assign a
new variable in Base for debugging. Removed in this PR.
2. Distributed wanting to create new bindings. This is a legimitate use
case for wanting to create bindings in other modules. This is fixed in
https://github.com/JuliaLang/Distributed.jl/pull/102.

As noted in that PR, the recommended replacement where implicit binding
creation is desired is:
```
Core.eval(mod, Expr(:global, sym))
invokelatest(setglobal!, mod, sym, val)
```

The `invokelatest` is not presently required, but may be needed by
#54654, so it's included in the recommendation now.

Fixes #54607

77035 of 88036 relevant lines covered (87.5%)

16049112.75 hits per line

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

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

3
## Basic functions ##
4

5
"""
6
    AbstractArray{T,N}
7

8
Supertype for `N`-dimensional arrays (or array-like types) with elements of type `T`.
9
[`Array`](@ref) and other types are subtypes of this. See the manual section on the
10
[`AbstractArray` interface](@ref man-interface-array).
11

12
See also: [`AbstractVector`](@ref), [`AbstractMatrix`](@ref), [`eltype`](@ref), [`ndims`](@ref).
13
"""
14
AbstractArray
15

16
convert(::Type{T}, a::T) where {T<:AbstractArray} = a
59,804✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
5,773✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
8,329✔
19

20
"""
21
    size(A::AbstractArray, [dim])
22

23
Return a tuple containing the dimensions of `A`. Optionally you can specify a
24
dimension to just get the length of that dimension.
25

26
Note that `size` may not be defined for arrays with non-standard indices, in which case [`axes`](@ref)
27
may be useful. See the manual chapter on [arrays with custom indices](@ref man-custom-indices).
28

29
See also: [`length`](@ref), [`ndims`](@ref), [`eachindex`](@ref), [`sizeof`](@ref).
30

31
# Examples
32
```jldoctest
33
julia> A = fill(1, (2,3,4));
34

35
julia> size(A)
36
(2, 3, 4)
37

38
julia> size(A, 2)
39
3
40
```
41
"""
42
size(t::AbstractArray{T,N}, d) where {T,N} = d::Integer <= N ? size(t)[d] : 1
1,464,334✔
43

44
"""
45
    axes(A, d)
46

47
Return the valid range of indices for array `A` along dimension `d`.
48

49
See also [`size`](@ref), and the manual chapter on [arrays with custom indices](@ref man-custom-indices).
50

51
# Examples
52

53
```jldoctest
54
julia> A = fill(1, (5,6,7));
55

56
julia> axes(A, 2)
57
Base.OneTo(6)
58

59
julia> axes(A, 4) == 1:1  # all dimensions d > ndims(A) have size 1
60
true
61
```
62

63
# Usage note
64

65
Each of the indices has to be an `AbstractUnitRange{<:Integer}`, but at the same time can be
66
a type that uses custom indices. So, for example, if you need a subset, use generalized
67
indexing constructs like `begin`/`end` or [`firstindex`](@ref)/[`lastindex`](@ref):
68

69
```julia
70
ix = axes(v, 1)
71
ix[2:end]          # will work for eg Vector, but may fail in general
72
ix[(begin+1):end]  # works for generalized indexes
73
```
74
"""
75
function axes(A::AbstractArray{T,N}, d) where {T,N}
272✔
76
    @inline
71,702,770✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
71,763,524✔
78
end
79

80
"""
81
    axes(A)
82

83
Return the tuple of valid indices for array `A`.
84

85
See also: [`size`](@ref), [`keys`](@ref), [`eachindex`](@ref).
86

87
# Examples
88

89
```jldoctest
90
julia> A = fill(1, (5,6,7));
91

92
julia> axes(A)
93
(Base.OneTo(5), Base.OneTo(6), Base.OneTo(7))
94
```
95
"""
96
function axes(A)
1,215✔
97
    @inline
659,294,664✔
98
    map(unchecked_oneto, size(A))
2,147,483,647✔
99
end
100

101
"""
102
    has_offset_axes(A)
103
    has_offset_axes(A, B, ...)
104

105
Return `true` if the indices of `A` start with something other than 1 along any axis.
106
If multiple arguments are passed, equivalent to `has_offset_axes(A) || has_offset_axes(B) || ...`.
107

108
See also [`require_one_based_indexing`](@ref).
109
"""
110
has_offset_axes() = false
×
111
has_offset_axes(A) = _any_tuple(x->Int(first(x))::Int != 1, false, axes(A)...)
857,252✔
112
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
477,725✔
113
has_offset_axes(::Colon) = false
×
114
has_offset_axes(::Array) = false
×
115
# note: this could call `any` directly if the compiler can infer it. We don't use _any_tuple
116
# here because it stops full elision in some cases (#49332) and we don't need handling of
117
# `missing` (has_offset_axes(A) always returns a Bool)
118
has_offset_axes(A, As...) = has_offset_axes(A) || has_offset_axes(As...)
9,580,785✔
119

120

121
"""
122
    require_one_based_indexing(A::AbstractArray)
123
    require_one_based_indexing(A,B...)
124

125
Throw an `ArgumentError` if the indices of any argument start with something other than `1` along any axis.
126
See also [`has_offset_axes`](@ref).
127

128
!!! compat "Julia 1.2"
129
     This function requires at least Julia 1.2.
130
"""
131
require_one_based_indexing(A...) = !has_offset_axes(A...) || throw(ArgumentError("offset arrays are not supported but got an array with index other than 1"))
5,792,513✔
132

133
# Performance optimization: get rid of a branch on `d` in `axes(A, d)`
134
# for d=1. 1d arrays are heavily used, and the first dimension comes up
135
# in other applications.
136
axes1(A::AbstractArray{<:Any,0}) = OneTo(1)
×
137
axes1(A::AbstractArray) = (@inline; axes(A)[1])
2,147,483,647✔
138
axes1(iter) = oneto(length(iter))
1✔
139

140
"""
141
    keys(a::AbstractArray)
142

143
Return an efficient array describing all valid indices for `a` arranged in the shape of `a` itself.
144

145
The keys of 1-dimensional arrays (vectors) are integers, whereas all other N-dimensional
146
arrays use [`CartesianIndex`](@ref) to describe their locations.  Often the special array
147
types [`LinearIndices`](@ref) and [`CartesianIndices`](@ref) are used to efficiently
148
represent these arrays of integers and `CartesianIndex`es, respectively.
149

150
Note that the `keys` of an array might not be the most efficient index type; for maximum
151
performance use  [`eachindex`](@ref) instead.
152

153
# Examples
154
```jldoctest
155
julia> keys([4, 5, 6])
156
3-element LinearIndices{1, Tuple{Base.OneTo{Int64}}}:
157
 1
158
 2
159
 3
160

161
julia> keys([4 5; 6 7])
162
CartesianIndices((2, 2))
163
```
164
"""
165
keys(a::AbstractArray) = CartesianIndices(axes(a))
29,073✔
166
keys(a::AbstractVector) = LinearIndices(a)
86,259,610✔
167

168
"""
169
    keytype(T::Type{<:AbstractArray})
170
    keytype(A::AbstractArray)
171

172
Return the key type of an array. This is equal to the
173
[`eltype`](@ref) of the result of `keys(...)`, and is provided
174
mainly for compatibility with the dictionary interface.
175

176
# Examples
177
```jldoctest
178
julia> keytype([1, 2, 3]) == Int
179
true
180

181
julia> keytype([1 2; 3 4])
182
CartesianIndex{2}
183
```
184

185
!!! compat "Julia 1.2"
186
     For arrays, this function requires at least Julia 1.2.
187
"""
188
keytype(a::AbstractArray) = keytype(typeof(a))
28,663,528✔
189
keytype(::Type{Union{}}, slurp...) = eltype(Union{})
×
190

191
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
2✔
192
keytype(A::Type{<:AbstractVector}) = Int
×
193

194
valtype(a::AbstractArray) = valtype(typeof(a))
15✔
195
valtype(::Type{Union{}}, slurp...) = eltype(Union{})
×
196

197
"""
198
    valtype(T::Type{<:AbstractArray})
199
    valtype(A::AbstractArray)
200

201
Return the value type of an array. This is identical to [`eltype`](@ref) and is
202
provided mainly for compatibility with the dictionary interface.
203

204
# Examples
205
```jldoctest
206
julia> valtype(["one", "two", "three"])
207
String
208
```
209

210
!!! compat "Julia 1.2"
211
     For arrays, this function requires at least Julia 1.2.
212
"""
213
valtype(A::Type{<:AbstractArray}) = eltype(A)
17✔
214

215
prevind(::AbstractArray, i::Integer) = Int(i)-1
142,866✔
216
nextind(::AbstractArray, i::Integer) = Int(i)+1
314,109,704✔
217

218

219
"""
220
    eltype(type)
221

222
Determine the type of the elements generated by iterating a collection of the given `type`.
223
For dictionary types, this will be a `Pair{KeyType,ValType}`. The definition
224
`eltype(x) = eltype(typeof(x))` is provided for convenience so that instances can be passed
225
instead of types. However the form that accepts a type argument should be defined for new
226
types.
227

228
See also: [`keytype`](@ref), [`typeof`](@ref).
229

230
# Examples
231
```jldoctest
232
julia> eltype(fill(1f0, (2,2)))
233
Float32
234

235
julia> eltype(fill(0x1, (2,2)))
236
UInt8
237
```
238
"""
239
eltype(::Type) = Any
×
240
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
1✔
241
eltype(x) = eltype(typeof(x))
31,669,036✔
242
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
30,615,192✔
243

244
"""
245
    elsize(type)
246

247
Compute the memory stride in bytes between consecutive elements of [`eltype`](@ref)
248
stored inside the given `type`, if the array elements are stored densely with a
249
uniform linear stride.
250

251
# Examples
252
```jldoctest
253
julia> Base.elsize(rand(Float32, 10))
254
4
255
```
256
"""
257
elsize(A::AbstractArray) = elsize(typeof(A))
97,089,866✔
258

259
"""
260
    ndims(A::AbstractArray) -> Integer
261

262
Return the number of dimensions of `A`.
263

264
See also: [`size`](@ref), [`axes`](@ref).
265

266
# Examples
267
```jldoctest
268
julia> A = fill(1, (3,4,5));
269

270
julia> ndims(A)
271
3
272
```
273
"""
274
ndims(::AbstractArray{T,N}) where {T,N} = N::Int
25,875,682✔
275
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N::Int
59✔
276
ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
×
277

278
"""
279
    length(collection) -> Integer
280

281
Return the number of elements in the collection.
282

283
Use [`lastindex`](@ref) to get the last valid index of an indexable collection.
284

285
See also: [`size`](@ref), [`ndims`](@ref), [`eachindex`](@ref).
286

287
# Examples
288
```jldoctest
289
julia> length(1:5)
290
5
291

292
julia> length([1, 2, 3, 4])
293
4
294

295
julia> length([1 2; 3 4])
296
4
297
```
298
"""
299
length
300

301
"""
302
    length(A::AbstractArray)
303

304
Return the number of elements in the array, defaults to `prod(size(A))`.
305

306
# Examples
307
```jldoctest
308
julia> length([1, 2, 3, 4])
309
4
310

311
julia> length([1 2; 3 4])
312
4
313
```
314
"""
315
length(t::AbstractArray) = (@inline; prod(size(t)))
38,204,164✔
316

317
# `eachindex` is mostly an optimization of `keys`
318
eachindex(itrs...) = keys(itrs...)
263✔
319

320
# eachindex iterates over all indices. IndexCartesian definitions are later.
321
eachindex(A::AbstractVector) = (@inline(); axes1(A))
1,335,993,757✔
322

323

324
@noinline function throw_eachindex_mismatch_indices(::IndexLinear, inds...)
1✔
325
    throw(DimensionMismatch("all inputs to eachindex must have the same indices, got $(join(inds, ", ", " and "))"))
1✔
326
end
327
@noinline function throw_eachindex_mismatch_indices(::IndexCartesian, inds...)
1✔
328
    throw(DimensionMismatch("all inputs to eachindex must have the same axes, got $(join(inds, ", ", " and "))"))
1✔
329
end
330

331
"""
332
    eachindex(A...)
333
    eachindex(::IndexStyle, A::AbstractArray...)
334

335
Create an iterable object for visiting each index of an `AbstractArray` `A` in an efficient
336
manner. For array types that have opted into fast linear indexing (like `Array`), this is
337
simply the range `1:length(A)` if they use 1-based indexing.
338
For array types that have not opted into fast linear indexing, a specialized Cartesian
339
range is typically returned to efficiently index into the array with indices specified
340
for every dimension.
341

342
In general `eachindex` accepts arbitrary iterables, including strings and dictionaries, and returns
343
an iterator object supporting arbitrary index types (e.g. unevenly spaced or non-integer indices).
344

345
If `A` is `AbstractArray` it is possible to explicitly specify the style of the indices that
346
should be returned by `eachindex` by passing a value having `IndexStyle` type as its first argument
347
(typically `IndexLinear()` if linear indices are required or `IndexCartesian()` if Cartesian
348
range is wanted).
349

350
If you supply more than one `AbstractArray` argument, `eachindex` will create an
351
iterable object that is fast for all arguments (typically a [`UnitRange`](@ref)
352
if all inputs have fast linear indexing, a [`CartesianIndices`](@ref) otherwise).
353
If the arrays have different sizes and/or dimensionalities, a `DimensionMismatch` exception
354
will be thrown.
355

356
See also [`pairs`](@ref)`(A)` to iterate over indices and values together,
357
and [`axes`](@ref)`(A, 2)` for valid indices along one dimension.
358

359
# Examples
360
```jldoctest
361
julia> A = [10 20; 30 40];
362

363
julia> for i in eachindex(A) # linear indexing
364
           println("A[", i, "] == ", A[i])
365
       end
366
A[1] == 10
367
A[2] == 30
368
A[3] == 20
369
A[4] == 40
370

371
julia> for i in eachindex(view(A, 1:2, 1:1)) # Cartesian indexing
372
           println(i)
373
       end
374
CartesianIndex(1, 1)
375
CartesianIndex(2, 1)
376
```
377
"""
378
eachindex(A::AbstractArray) = (@inline(); eachindex(IndexStyle(A), A))
345,020✔
379

380
function eachindex(A::AbstractArray, B::AbstractArray)
7✔
381
    @inline
38✔
382
    eachindex(IndexStyle(A,B), A, B)
38✔
383
end
384
function eachindex(A::AbstractArray, B::AbstractArray...)
2✔
385
    @inline
2✔
386
    eachindex(IndexStyle(A,B...), A, B...)
2✔
387
end
388
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
12,819,592✔
389
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
2,147,483,647✔
390
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
1✔
391
    @inline
35✔
392
    indsA = eachindex(IndexLinear(), A)
35✔
393
    _all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
72✔
394
        throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
395
    indsA
34✔
396
end
397
function _all_match_first(f::F, inds, A, B...) where F<:Function
398
    @inline
44✔
399
    (inds == f(A)) & _all_match_first(f, inds, B...)
51✔
400
end
401
_all_match_first(f::F, inds) where F<:Function = true
×
402

403
# keys with an IndexStyle
404
keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...)
×
405

406
"""
407
    lastindex(collection) -> Integer
408
    lastindex(collection, d) -> Integer
409

410
Return the last index of `collection`. If `d` is given, return the last index of `collection` along dimension `d`.
411

412
The syntaxes `A[end]` and `A[end, end]` lower to `A[lastindex(A)]` and
413
`A[lastindex(A, 1), lastindex(A, 2)]`, respectively.
414

415
See also: [`axes`](@ref), [`firstindex`](@ref), [`eachindex`](@ref), [`prevind`](@ref).
416

417
# Examples
418
```jldoctest
419
julia> lastindex([1,2,4])
420
3
421

422
julia> lastindex(rand(3,4,5), 2)
423
4
424
```
425
"""
426
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
2,147,483,647✔
427
lastindex(a, d) = (@inline; last(axes(a, d)))
5,153✔
428

429
"""
430
    firstindex(collection) -> Integer
431
    firstindex(collection, d) -> Integer
432

433
Return the first index of `collection`. If `d` is given, return the first index of `collection` along dimension `d`.
434

435
The syntaxes `A[begin]` and `A[1, begin]` lower to `A[firstindex(A)]` and
436
`A[1, firstindex(A, 2)]`, respectively.
437

438
See also: [`first`](@ref), [`axes`](@ref), [`lastindex`](@ref), [`nextind`](@ref).
439

440
# Examples
441
```jldoctest
442
julia> firstindex([1,2,4])
443
1
444

445
julia> firstindex(rand(3,4,5), 2)
446
1
447
```
448
"""
449
firstindex(a::AbstractArray) = (@inline; first(eachindex(IndexLinear(), a)))
34,554,922✔
450
firstindex(a, d) = (@inline; first(axes(a, d)))
3,532✔
451

452
@propagate_inbounds first(a::AbstractArray) = a[first(eachindex(a))]
494,079✔
453

454
"""
455
    first(coll)
456

457
Get the first element of an iterable collection. Return the start point of an
458
[`AbstractRange`](@ref) even if it is empty.
459

460
See also: [`only`](@ref), [`firstindex`](@ref), [`last`](@ref).
461

462
# Examples
463
```jldoctest
464
julia> first(2:2:10)
465
2
466

467
julia> first([1; 2; 3; 4])
468
1
469
```
470
"""
471
function first(itr)
1,084✔
472
    x = iterate(itr)
2,156✔
473
    x === nothing && throw(ArgumentError("collection must be non-empty"))
1,129✔
474
    x[1]
1,127✔
475
end
476

477
"""
478
    first(itr, n::Integer)
479

480
Get the first `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
481
long enough.
482

483
See also: [`startswith`](@ref), [`Iterators.take`](@ref).
484

485
!!! compat "Julia 1.6"
486
    This method requires at least Julia 1.6.
487

488
# Examples
489
```jldoctest
490
julia> first(["foo", "bar", "qux"], 2)
491
2-element Vector{String}:
492
 "foo"
493
 "bar"
494

495
julia> first(1:6, 10)
496
1:6
497

498
julia> first(Bool[], 1)
499
Bool[]
500
```
501
"""
502
first(itr, n::Integer) = collect(Iterators.take(itr, n))
10✔
503
# Faster method for vectors
504
function first(v::AbstractVector, n::Integer)
1,467✔
505
    n < 0 && throw(ArgumentError("Number of elements must be non-negative"))
1,482✔
506
    v[range(begin, length=min(n, checked_length(v)))]
1,492✔
507
end
508

509
"""
510
    last(coll)
511

512
Get the last element of an ordered collection, if it can be computed in O(1) time. This is
513
accomplished by calling [`lastindex`](@ref) to get the last index. Return the end
514
point of an [`AbstractRange`](@ref) even if it is empty.
515

516
See also [`first`](@ref), [`endswith`](@ref).
517

518
# Examples
519
```jldoctest
520
julia> last(1:2:10)
521
9
522

523
julia> last([1; 2; 3; 4])
524
4
525
```
526
"""
527
last(a) = a[end]
338,513,583✔
528

529
"""
530
    last(itr, n::Integer)
531

532
Get the last `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
533
long enough.
534

535
!!! compat "Julia 1.6"
536
    This method requires at least Julia 1.6.
537

538
# Examples
539
```jldoctest
540
julia> last(["foo", "bar", "qux"], 2)
541
2-element Vector{String}:
542
 "bar"
543
 "qux"
544

545
julia> last(1:6, 10)
546
1:6
547

548
julia> last(Float64[], 1)
549
Float64[]
550
```
551
"""
552
last(itr, n::Integer) = reverse!(collect(Iterators.take(Iterators.reverse(itr), n)))
60✔
553
# Faster method for arrays
554
function last(v::AbstractVector, n::Integer)
1,828✔
555
    n < 0 && throw(ArgumentError("Number of elements must be non-negative"))
1,873✔
556
    v[range(stop=lastindex(v), length=min(n, checked_length(v)))]
1,913✔
557
end
558

559
"""
560
    strides(A)
561

562
Return a tuple of the memory strides in each dimension.
563

564
See also: [`stride`](@ref).
565

566
# Examples
567
```jldoctest
568
julia> A = fill(1, (3,4,5));
569

570
julia> strides(A)
571
(1, 3, 12)
572
```
573
"""
574
function strides end
575

576
"""
577
    stride(A, k::Integer)
578

579
Return the distance in memory (in number of elements) between adjacent elements in dimension `k`.
580

581
See also: [`strides`](@ref).
582

583
# Examples
584
```jldoctest
585
julia> A = fill(1, (3,4,5));
586

587
julia> stride(A,2)
588
3
589

590
julia> stride(A,3)
591
12
592
```
593
"""
594
function stride(A::AbstractArray, k::Integer)
42✔
595
    st = strides(A)
489✔
596
    k ≤ ndims(A) && return st[k]
477✔
597
    ndims(A) == 0 && return 1
7✔
598
    sz = size(A)
7✔
599
    s = st[1] * sz[1]
7✔
600
    for i in 2:ndims(A)
7✔
601
        s += st[i] * sz[i]
2✔
602
    end
2✔
603
    return s
7✔
604
end
605

606
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
24,455,706✔
607
size_to_strides(s, d) = (s,)
24,386,103✔
608
size_to_strides(s) = ()
1✔
609

610
function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
4✔
611
    @boundscheck checkbounds(A, I...)
37✔
612
    return true
31✔
613
end
614

615
# used to compute "end" for last index
616
function trailingsize(A, n)
×
617
    s = 1
×
618
    for i=n:ndims(A)
×
619
        s *= size(A,i)
×
620
    end
×
621
    return s
×
622
end
623
function trailingsize(inds::Indices, n)
×
624
    s = 1
×
625
    for i=n:length(inds)
×
626
        s *= length(inds[i])
×
627
    end
×
628
    return s
×
629
end
630
# This version is type-stable even if inds is heterogeneous
631
function trailingsize(inds::Indices)
×
632
    @inline
×
633
    prod(map(length, inds))
×
634
end
635

636
## Bounds checking ##
637

638
# The overall hierarchy is
639
#     `checkbounds(A, I...)` ->
640
#         `checkbounds(Bool, A, I...)` ->
641
#             `checkbounds_indices(Bool, IA, I)`, which recursively calls
642
#                 `checkindex` for each dimension
643
#
644
# See the "boundscheck" devdocs for more information.
645
#
646
# Note this hierarchy has been designed to reduce the likelihood of
647
# method ambiguities.  We try to make `checkbounds` the place to
648
# specialize on array type, and try to avoid specializations on index
649
# types; conversely, `checkindex` is intended to be specialized only
650
# on index type (especially, its last argument).
651

652
"""
653
    checkbounds(Bool, A, I...)
654

655
Return `true` if the specified indices `I` are in bounds for the given
656
array `A`. Subtypes of `AbstractArray` should specialize this method
657
if they need to provide custom bounds checking behaviors; however, in
658
many cases one can rely on `A`'s indices and [`checkindex`](@ref).
659

660
See also [`checkindex`](@ref).
661

662
# Examples
663
```jldoctest
664
julia> A = rand(3, 3);
665

666
julia> checkbounds(Bool, A, 2)
667
true
668

669
julia> checkbounds(Bool, A, 3, 4)
670
false
671

672
julia> checkbounds(Bool, A, 1:3)
673
true
674

675
julia> checkbounds(Bool, A, 1:3, 2:4)
676
false
677
```
678
"""
679
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
3,958✔
680
    @inline
398,170,450✔
681
    checkbounds_indices(Bool, axes(A), I)
413,676,692✔
682
end
683

684
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index;
685
# indices that do not allow linear indexing (e.g., logical arrays, cartesian indices, etc)
686
# must add specialized methods to implement their restrictions
687
function checkbounds(::Type{Bool}, A::AbstractArray, i)
166✔
688
    @inline
879,031,430✔
689
    return checkindex(Bool, eachindex(IndexLinear(), A), i)
2,147,483,647✔
690
end
691

692
"""
693
    checkbounds(A, I...)
694

695
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
696
"""
697
function checkbounds(A::AbstractArray, I...)
4,054✔
698
    @inline
1,267,208,444✔
699
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
2,147,483,647✔
700
    nothing
701
end
702

703
"""
704
    checkbounds_indices(Bool, IA, I)
705

706
Return `true` if the "requested" indices in the tuple `I` fall within
707
the bounds of the "permitted" indices specified by the tuple
708
`IA`. This function recursively consumes elements of these tuples,
709
usually in a 1-for-1 fashion,
710

711
    checkbounds_indices(Bool, (IA1, IA...), (I1, I...)) = checkindex(Bool, IA1, I1) &
712
                                                          checkbounds_indices(Bool, IA, I)
713

714
Note that [`checkindex`](@ref) is being used to perform the actual
715
bounds-check for a single dimension of the array.
716

717
There are two important exceptions to the 1-1 rule: linear indexing and
718
CartesianIndex{N}, both of which may "consume" more than one element
719
of `IA`.
720

721
See also [`checkbounds`](@ref).
722
"""
723
function checkbounds_indices(::Type{Bool}, inds::Tuple, I::Tuple{Any, Vararg})
4,780✔
724
    @inline
26,249,231✔
725
    return checkindex(Bool, get(inds, 1, OneTo(1)), I[1])::Bool &
969,684,801✔
726
        checkbounds_indices(Bool, safe_tail(inds), tail(I))
727
end
728

729
checkbounds_indices(::Type{Bool}, inds::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, inds))
577,988✔
730

731
# check along a single dimension
732
"""
733
    checkindex(Bool, inds::AbstractUnitRange, index)
734

735
Return `true` if the given `index` is within the bounds of
736
`inds`. Custom types that would like to behave as indices for all
737
arrays can extend this method in order to provide a specialized bounds
738
checking implementation.
739

740
See also [`checkbounds`](@ref).
741

742
# Examples
743
```jldoctest
744
julia> checkindex(Bool, 1:20, 8)
745
true
746

747
julia> checkindex(Bool, 1:20, 21)
748
false
749
```
750
"""
751
checkindex(::Type{Bool}, inds, i) = throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
2✔
752
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
68,268,664✔
753
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
3,067,684✔
754
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
2,147,483,647✔
755
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
×
756
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
×
757
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::AbstractRange) =
397,180,467✔
758
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
759
# range like indices with cheap `extrema`
760
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::LinearIndices) =
145✔
761
    isempty(i) | (checkindex(Bool, inds, first(i)) & checkindex(Bool, inds, last(i)))
762

763
function checkindex(::Type{Bool}, inds, I::AbstractArray)
764
    @inline
7,062✔
765
    b = true
7,062✔
766
    for i in I
23,648✔
767
        b &= checkindex(Bool, inds, i)
6,574,207✔
768
    end
6,583,342✔
769
    b
21,308✔
770
end
771

772
# See also specializations in multidimensional
773

774
## Constructors ##
775

776
# default arguments to similar()
777
"""
778
    similar(array, [element_type=eltype(array)], [dims=size(array)])
779

780
Create an uninitialized mutable array with the given element type and size, based upon the
781
given source array. The second and third arguments are both optional, defaulting to the
782
given array's `eltype` and `size`. The dimensions may be specified either as a single tuple
783
argument or as a series of integer arguments.
784

785
Custom AbstractArray subtypes may choose which specific array type is best-suited to return
786
for the given element type and dimensionality. If they do not specialize this method, the
787
default is an `Array{element_type}(undef, dims...)`.
788

789
For example, `similar(1:10, 1, 4)` returns an uninitialized `Array{Int,2}` since ranges are
790
neither mutable nor support 2 dimensions:
791

792
```julia-repl
793
julia> similar(1:10, 1, 4)
794
1×4 Matrix{Int64}:
795
 4419743872  4374413872  4419743888  0
796
```
797

798
Conversely, `similar(trues(10,10), 2)` returns an uninitialized `BitVector` with two
799
elements since `BitArray`s are both mutable and can support 1-dimensional arrays:
800

801
```julia-repl
802
julia> similar(trues(10,10), 2)
803
2-element BitVector:
804
 0
805
 0
806
```
807

808
Since `BitArray`s can only store elements of type [`Bool`](@ref), however, if you request a
809
different element type it will create a regular `Array` instead:
810

811
```julia-repl
812
julia> similar(falses(10), Float64, 2, 4)
813
2×4 Matrix{Float64}:
814
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
815
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
816
```
817

818
See also: [`undef`](@ref), [`isassigned`](@ref).
819
"""
820
similar(a::AbstractArray{T}) where {T}                             = similar(a, T)
19,058✔
821
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
15,523✔
822
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
108,421,402✔
823
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
3,599✔
824
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
17,394,846✔
825
# Similar supports specifying dims as either Integers or AbstractUnitRanges or any mixed combination
826
# thereof. Ideally, we'd just convert Integers to OneTos and then call a canonical method with the axes,
827
# but we don't want to require all AbstractArray subtypes to dispatch on Base.OneTo. So instead we
828
# define this method to convert supported axes to Ints, with the expectation that an offset array
829
# package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}}
830
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims))
314,652✔
831
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims))
5✔
832
# similar creates an Array by default
833
similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N}    = Array{T,N}(undef, dims)
17,348,948✔
834

835
to_shape(::Tuple{}) = ()
34✔
836
to_shape(dims::Dims) = dims
5,814✔
837
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
12,874,111✔
838
# each dimension
839
to_shape(i::Int) = i
111✔
840
to_shape(i::Integer) = Int(i)
173✔
841
to_shape(r::OneTo) = Int(last(r))
8,601,046✔
842
to_shape(r::AbstractUnitRange) = r
289✔
843

844
"""
845
    similar(storagetype, axes)
846

847
Create an uninitialized mutable array analogous to that specified by
848
`storagetype`, but with `axes` specified by the last
849
argument.
850

851
**Examples**:
852

853
    similar(Array{Int}, axes(A))
854

855
creates an array that "acts like" an `Array{Int}` (and might indeed be
856
backed by one), but which is indexed identically to `A`. If `A` has
857
conventional indexing, this will be identical to
858
`Array{Int}(undef, size(A))`, but if `A` has unconventional indexing then the
859
indices of the result will match `A`.
860

861
    similar(BitArray, (axes(A, 2),))
862

863
would create a 1-dimensional logical array whose indices match those
864
of the columns of `A`.
865
"""
866
similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
93✔
867
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
1,121,279,810✔
868
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
1,121,280,358✔
869

870
"""
871
    empty(v::AbstractVector, [eltype])
872

873
Create an empty vector similar to `v`, optionally changing the `eltype`.
874

875
See also: [`empty!`](@ref), [`isempty`](@ref), [`isassigned`](@ref).
876

877
# Examples
878

879
```jldoctest
880
julia> empty([1.0, 2.0, 3.0])
881
Float64[]
882

883
julia> empty([1.0, 2.0, 3.0], String)
884
String[]
885
```
886
"""
887
empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = similar(a, U, 0)
336✔
888

889
# like empty, but should return a mutable collection, a Vector by default
890
emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
231✔
891
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
60✔
892

893
"""
894
    copy!(dst, src) -> dst
895

896
In-place [`copy`](@ref) of `src` into `dst`, discarding any pre-existing
897
elements in `dst`.
898
If `dst` and `src` are of the same type, `dst == src` should hold after
899
the call. If `dst` and `src` are vector types, they must have equal
900
offset. If `dst` and `src` are multidimensional arrays, they must have
901
equal [`axes`](@ref).
902

903
$(_DOCS_ALIASING_WARNING)
904

905
See also [`copyto!`](@ref).
906

907
!!! note
908
    When operating on vector types, if `dst` and `src` are not of the
909
    same length, `dst` is resized to `length(src)` prior to the `copy`.
910

911
!!! compat "Julia 1.1"
912
    This method requires at least Julia 1.1. In Julia 1.0 this method
913
    is available from the `Future` standard library as `Future.copy!`.
914
"""
915
function copy!(dst::AbstractVector, src::AbstractVector)
24,532,167✔
916
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
97✔
917
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
918
    if length(dst) != length(src)
24,532,260✔
919
        resize!(dst, length(src))
24,287,509✔
920
    end
921
    copyto!(dst, src)
24,532,355✔
922
end
923

924
function copy!(dst::AbstractArray, src::AbstractArray)
925
    axes(dst) == axes(src) || throw(ArgumentError(
16✔
926
        "arrays must have the same axes for copy! (consider using `copyto!`)"))
927
    copyto!(dst, src)
16✔
928
end
929

930
## from general iterable to any array
931

932
# This is `Experimental.@max_methods 1 function copyto! end`, which is not
933
# defined at this point in bootstrap.
934
typeof(function copyto! end).name.max_methods = UInt8(1)
935

936
function copyto!(dest::AbstractArray, src)
12,356,404✔
937
    destiter = eachindex(dest)
12,370,123✔
938
    y = iterate(destiter)
12,370,133✔
939
    for x in src
16,707,267✔
940
        y === nothing &&
5,924,320✔
941
            throw(ArgumentError("destination has fewer elements than required"))
942
        dest[y[1]] = x
5,924,319✔
943
        y = iterate(destiter, y[2])
9,618,138✔
944
    end
9,424,207✔
945
    return dest
12,370,121✔
946
end
947

948
function copyto!(dest::AbstractArray, dstart::Integer, src)
253✔
949
    i = Int(dstart)
276✔
950
    if haslength(src) && length(dest) > 0
276✔
951
        @boundscheck checkbounds(dest, i:(i + length(src) - 1))
271✔
952
        for x in src
281✔
953
            @inbounds dest[i] = x
2,335✔
954
            i += 1
2,335✔
955
        end
2,802✔
956
    else
957
        for x in src
6✔
958
            dest[i] = x
6✔
959
            i += 1
3✔
960
        end
3✔
961
    end
962
    return dest
272✔
963
end
964

965
# copy from an some iterable object into an AbstractArray
966
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer)
9✔
967
    if (sstart < 1)
9✔
968
        throw(ArgumentError(LazyString("source start offset (",sstart,") is < 1")))
1✔
969
    end
970
    y = iterate(src)
8✔
971
    for j = 1:(sstart-1)
8✔
972
        if y === nothing
5✔
973
            throw(ArgumentError(LazyString(
1✔
974
                "source has fewer elements than required, ",
975
                "expected at least ", sstart,", got ", j-1)))
976
        end
977
        y = iterate(src, y[2])
4✔
978
    end
6✔
979
    if y === nothing
7✔
980
        throw(ArgumentError(LazyString(
1✔
981
            "source has fewer elements than required, ",
982
            "expected at least ",sstart," got ", sstart-1)))
983
    end
984
    i = Int(dstart)
6✔
985
    while y !== nothing
12✔
986
        val, st = y
10✔
987
        dest[i] = val
10✔
988
        i += 1
6✔
989
        y = iterate(src, st)
7✔
990
    end
6✔
991
    return dest
2✔
992
end
993

994
# this method must be separate from the above since src might not have a length
995
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
1,367,057✔
996
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
1,367,057✔
997
        ", elements, but n should be non-negative")))
998
    n == 0 && return dest
1,367,056✔
999
    dmax = dstart + n - 1
1,367,051✔
1000
    inds = LinearIndices(dest)
1,367,051✔
1001
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
2,734,100✔
1002
        sstart < 1 && throw(ArgumentError(LazyString("source start offset (",
4✔
1003
            sstart,") is < 1")))
1004
        throw(BoundsError(dest, dstart:dmax))
3✔
1005
    end
1006
    y = iterate(src)
1,367,047✔
1007
    for j = 1:(sstart-1)
1,420,470✔
1008
        if y === nothing
2,147,483,647✔
1009
            throw(ArgumentError(LazyString(
1✔
1010
                "source has fewer elements than required, ",
1011
                "expected at least ",sstart,", got ",j-1)))
1012
        end
1013
        y = iterate(src, y[2])
2,147,483,647✔
1014
    end
2,147,483,647✔
1015
    i = Int(dstart)
1,367,046✔
1016
    while i <= dmax && y !== nothing
13,434,160✔
1017
        val, st = y
10,497,583✔
1018
        @inbounds dest[i] = val
12,067,114✔
1019
        y = iterate(src, st)
13,333,862✔
1020
        i += 1
12,067,114✔
1021
    end
12,067,114✔
1022
    i <= dmax && throw(BoundsError(dest, i))
1,367,046✔
1023
    return dest
1,367,045✔
1024
end
1025

1026
## copy between abstract arrays - generally more efficient
1027
## since a single index variable can be used.
1028

1029
"""
1030
    copyto!(dest::AbstractArray, src) -> dest
1031

1032
Copy all elements from collection `src` to array `dest`, whose length must be greater than
1033
or equal to the length `n` of `src`. The first `n` elements of `dest` are overwritten,
1034
the other elements are left untouched.
1035

1036
See also [`copy!`](@ref Base.copy!), [`copy`](@ref).
1037

1038
$(_DOCS_ALIASING_WARNING)
1039

1040
# Examples
1041
```jldoctest
1042
julia> x = [1., 0., 3., 0., 5.];
1043

1044
julia> y = zeros(7);
1045

1046
julia> copyto!(y, x);
1047

1048
julia> y
1049
7-element Vector{Float64}:
1050
 1.0
1051
 0.0
1052
 3.0
1053
 0.0
1054
 5.0
1055
 0.0
1056
 0.0
1057
```
1058
"""
1059
function copyto!(dest::AbstractArray, src::AbstractArray)
2,645,800✔
1060
    isempty(src) && return dest
2,973,171✔
1061
    if dest isa BitArray
2,759,618✔
1062
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1063
        return _copyto_bitarray!(dest, src)
1✔
1064
    end
1065
    src′ = unalias(dest, src)
2,967,505✔
1066
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,972,681✔
1067
end
1068

1069
function copyto!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
×
1070
    isempty(src) && return dest
×
1071
    src′ = unalias(dest, src)
×
1072
    copyto_unaliased!(deststyle, dest, srcstyle, src′)
×
1073
end
1074

1075
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
148,854✔
1076
    isempty(src) && return dest
2,966,415✔
1077
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,966,416✔
1078
    idf, isf = first(destinds), first(srcinds)
2,753,445✔
1079
    Δi = idf - isf
2,753,445✔
1080
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,966,420✔
1081
        throw(BoundsError(dest, srcinds))
1082
    if deststyle isa IndexLinear
2,753,440✔
1083
        if srcstyle isa IndexLinear
2,750,303✔
1084
            # Single-index implementation
1085
            @inbounds for i in srcinds
2,676,363✔
1086
                dest[i + Δi] = src[i]
37,413,379✔
1087
            end
72,148,192✔
1088
        else
1089
            # Dual-index implementation
1090
            i = idf - 1
104,237✔
1091
            @inbounds for a in src
573,778✔
1092
                dest[i+=1] = a
3,091,718✔
1093
            end
5,889,329✔
1094
        end
1095
    else
1096
        iterdest, itersrc = eachindex(dest), eachindex(src)
3,137✔
1097
        if iterdest == itersrc
3,138✔
1098
            # Shared-iterator implementation
1099
            for I in iterdest
301✔
1100
                @inbounds dest[I] = src[I]
6,011,446✔
1101
            end
12,012,525✔
1102
        else
1103
            # Dual-iterator implementation
1104
            ret = iterate(iterdest)
5,944✔
1105
            @inbounds for a in src
5,048✔
1106
                idx, state = ret::NTuple{2,Any}
2,033,835✔
1107
                dest[idx] = a
2,033,841✔
1108
                ret = iterate(iterdest, state)
2,036,774✔
1109
            end
4,032,161✔
1110
        end
1111
    end
1112
    return dest
2,966,404✔
1113
end
1114

1115
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
72✔
1116
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
22,218✔
1117
end
1118

1119
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray, sstart::Integer)
22✔
1120
    srcinds = LinearIndices(src)
22✔
1121
    checkbounds(Bool, srcinds, sstart) || throw(BoundsError(src, sstart))
31✔
1122
    copyto!(dest, dstart, src, sstart, last(srcinds)-sstart+1)
13✔
1123
end
1124

1125
function copyto!(dest::AbstractArray, dstart::Integer,
878,606✔
1126
                 src::AbstractArray, sstart::Integer,
1127
                 n::Integer)
1128
    n == 0 && return dest
878,606✔
1129
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
878,555✔
1130
        n," elements, but n should be non-negative")))
1131
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
878,554✔
1132
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
878,566✔
1133
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
878,545✔
1134
    src′ = unalias(dest, src)
878,539✔
1135
    @inbounds for i = 0:n-1
878,616✔
1136
        dest[dstart+i] = src′[sstart+i]
55,953,968✔
1137
    end
111,029,397✔
1138
    return dest
878,539✔
1139
end
1140

1141
function copy(a::AbstractArray)
142,415✔
1142
    @_propagate_inbounds_meta
146,805✔
1143
    copymutable(a)
152,924✔
1144
end
1145

1146
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
757✔
1147
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1148
    if length(ir_dest) != length(ir_src)
757✔
1149
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1150
            length(ir_src)," and ",length(ir_dest),")")))
1151
    end
1152
    if length(jr_dest) != length(jr_src)
756✔
1153
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1154
            length(jr_src)," and ",length(jr_dest),")")))
1155
    end
1156
    @boundscheck checkbounds(B, ir_dest, jr_dest)
756✔
1157
    @boundscheck checkbounds(A, ir_src, jr_src)
756✔
1158
    A′ = unalias(B, A)
756✔
1159
    jdest = first(jr_dest)
756✔
1160
    for jsrc in jr_src
1,511✔
1161
        idest = first(ir_dest)
11,508✔
1162
        for isrc in ir_src
23,013✔
1163
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
179,256✔
1164
            idest += step(ir_dest)
179,256✔
1165
        end
347,004✔
1166
        jdest += step(jr_dest)
11,508✔
1167
    end
22,260✔
1168
    return B
756✔
1169
end
1170

1171
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
246,277✔
1172

1173
function copyto_axcheck!(dest, src)
187,379✔
1174
    _checkaxs(axes(dest), axes(src))
225,428✔
1175
    copyto!(dest, src)
239,758✔
1176
end
1177

1178
"""
1179
    copymutable(a)
1180

1181
Make a mutable copy of an array or iterable `a`.  For `a::Array`,
1182
this is equivalent to `copy(a)`, but for other array types it may
1183
differ depending on the type of `similar(a)`.  For generic iterables
1184
this is equivalent to `collect(a)`.
1185

1186
# Examples
1187
```jldoctest
1188
julia> tup = (1, 2, 3)
1189
(1, 2, 3)
1190

1191
julia> Base.copymutable(tup)
1192
3-element Vector{Int64}:
1193
 1
1194
 2
1195
 3
1196
```
1197
"""
1198
function copymutable(a::AbstractArray)
44✔
1199
    @_propagate_inbounds_meta
149,589✔
1200
    copyto!(similar(a), a)
175,033✔
1201
end
1202
copymutable(itr) = collect(itr)
1✔
1203

1204
zero(x::AbstractArray{T}) where {T<:Number} = fill!(similar(x, typeof(zero(T))), zero(T))
3,557✔
1205
zero(x::AbstractArray{S}) where {S<:Union{Missing, Number}} = fill!(similar(x, typeof(zero(S))), zero(S))
3✔
1206
zero(x::AbstractArray) = map(zero, x)
11✔
1207

1208
function _one(unit::T, mat::AbstractMatrix) where {T}
164✔
1209
    (rows, cols) = axes(mat)
164✔
1210
    (length(rows) == length(cols)) ||
164✔
1211
      throw(DimensionMismatch("multiplicative identity defined only for square matrices"))
1212
    zer = zero(unit)::T
164✔
1213
    require_one_based_indexing(mat)
164✔
1214
    I = similar(mat, T)
328✔
1215
    fill!(I, zer)
3,792✔
1216
    for i ∈ rows
164✔
1217
        I[i, i] = unit
661✔
1218
    end
1,158✔
1219
    I
164✔
1220
end
1221

1222
one(x::AbstractMatrix{T}) where {T} = _one(one(T), x)
139✔
1223
oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
31✔
1224

1225
## iteration support for arrays by iterating over `eachindex` in the array ##
1226
# Allows fast iteration by default for both IndexLinear and IndexCartesian arrays
1227

1228
# While the definitions for IndexLinear are all simple enough to inline on their
1229
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1230
# inlining.
1231
function iterate(A::AbstractArray, state=(eachindex(A),))
19,620✔
1232
    y = iterate(state...)
146,553,317✔
1233
    y === nothing && return nothing
123,296,117✔
1234
    A[y[1]], (state[1], tail(y)...)
122,741,290✔
1235
end
1236

1237
isempty(a::AbstractArray) = (length(a) == 0)
2,147,483,647✔
1238

1239

1240
## range conversions ##
1241

1242
map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
2✔
1243
map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
165✔
1244
map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
6✔
1245
function map(::Type{T}, r::LinRange) where T<:AbstractFloat
1246
    LinRange(T(r.start), T(r.stop), length(r))
1✔
1247
end
1248

1249
## unsafe/pointer conversions ##
1250

1251
# note: the following type definitions don't mean any AbstractArray is convertible to
1252
# a data Ref. they just map the array element type to the pointer type for
1253
# convenience in cases that work.
1254
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, cconvert(Ptr{T}, x))
56,912,223✔
1255
function pointer(x::AbstractArray{T}, i::Integer) where T
102,749✔
1256
    @inline
409,556✔
1257
    pointer(x) + Int(_memory_offset(x, i))::Int
3,542,553✔
1258
end
1259

1260
# The distance from pointer(x) to the element at x[I...] in bytes
1261
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
3,209,638✔
1262
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
48,708✔
1263
    J = _to_subscript_indices(x, I...)
102,054✔
1264
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
383,661✔
1265
end
1266

1267
## Approach:
1268
# We only define one fallback method on getindex for all argument types.
1269
# That dispatches to an (inlined) internal _getindex function, where the goal is
1270
# to transform the indices such that we can call the only getindex method that
1271
# we require the type A{T,N} <: AbstractArray{T,N} to define; either:
1272
#       getindex(::A, ::Int) # if IndexStyle(A) == IndexLinear() OR
1273
#       getindex(::A{T,N}, ::Vararg{Int, N}) where {T,N} # if IndexCartesian()
1274
# If the subtype hasn't defined the required method, it falls back to the
1275
# _getindex function again where an error is thrown to prevent stack overflows.
1276
"""
1277
    getindex(A, inds...)
1278

1279
Return a subset of array `A` as selected by the indices `inds`.
1280

1281
Each index may be any [supported index type](@ref man-supported-index-types), such
1282
as an [`Integer`](@ref), [`CartesianIndex`](@ref), [range](@ref Base.AbstractRange), or [array](@ref man-multi-dim-arrays) of supported indices.
1283
A [:](@ref Base.Colon) may be used to select all elements along a specific dimension, and a boolean array (e.g. an `Array{Bool}` or a [`BitArray`](@ref)) may be used to filter for elements where the corresponding index is `true`.
1284

1285
When `inds` selects multiple elements, this function returns a newly
1286
allocated array. To index multiple elements without making a copy,
1287
use [`view`](@ref) instead.
1288

1289
See the manual section on [array indexing](@ref man-array-indexing) for details.
1290

1291
# Examples
1292
```jldoctest
1293
julia> A = [1 2; 3 4]
1294
2×2 Matrix{Int64}:
1295
 1  2
1296
 3  4
1297

1298
julia> getindex(A, 1)
1299
1
1300

1301
julia> getindex(A, [2, 1])
1302
2-element Vector{Int64}:
1303
 3
1304
 1
1305

1306
julia> getindex(A, 2:4)
1307
3-element Vector{Int64}:
1308
 3
1309
 2
1310
 4
1311

1312
julia> getindex(A, 2, 1)
1313
3
1314

1315
julia> getindex(A, CartesianIndex(2, 1))
1316
3
1317

1318
julia> getindex(A, :, 2)
1319
2-element Vector{Int64}:
1320
 2
1321
 4
1322

1323
julia> getindex(A, 2, :)
1324
2-element Vector{Int64}:
1325
 3
1326
 4
1327

1328
julia> getindex(A, A .> 2)
1329
2-element Vector{Int64}:
1330
 3
1331
 4
1332
```
1333
"""
1334
function getindex(A::AbstractArray, I...)
534,001✔
1335
    @_propagate_inbounds_meta
111,272,555✔
1336
    error_if_canonical_getindex(IndexStyle(A), A, I...)
111,272,555✔
1337
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
225,471,683✔
1338
end
1339
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1340
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
157,135,547✔
1341

1342
@inline unsafe_getindex(A::AbstractArray, I...) = @inbounds getindex(A, I...)
389✔
1343

1344
struct CanonicalIndexError <: Exception
1345
    func::String
1346
    type::Any
1347
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
14✔
1348
end
1349

1350
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
2✔
1351
    throw(CanonicalIndexError("getindex", typeof(A)))
1352
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
3✔
1353
    throw(CanonicalIndexError("getindex", typeof(A)))
1354
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
×
1355

1356
## Internal definitions
1357
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1358
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1359

1360
## IndexLinear Scalar indexing: canonical method is one Int
1361
_getindex(::IndexLinear, A::AbstractVector, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))  # ambiguity resolution in case packages specialize this (to be avoided if at all possible, but see Interpolations.jl)
44,637,166✔
1362
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
51✔
1363
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
342✔
1364
    @inline
2,377,445✔
1365
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
48,713,026✔
1366
    @inbounds r = getindex(A, _to_linear_index(A, I...))
48,712,958✔
1367
    r
2,377,394✔
1368
end
1369
_to_linear_index(A::AbstractArray, i::Integer) = i
52,071✔
1370
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
84,738,452✔
1371
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
329,290✔
1372
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
281,695,625✔
1373

1374
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1375
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
1376
    @inline
431,085✔
1377
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
431,158✔
1378
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
434,218✔
1379
    r
431,010✔
1380
end
1381
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
1382
    @_propagate_inbounds_meta
106,970,461✔
1383
    getindex(A, I...)
131,114,726✔
1384
end
1385
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
447,319✔
1386
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1387
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1388
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
418✔
1389
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1390
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1391
    @inline
80,880✔
1392
    J, Jrem = IteratorsMD.split(I, Val(N))
80,880✔
1393
    _to_subscript_indices(A, J, Jrem)
80,880✔
1394
end
1395
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1396
    __to_subscript_indices(A, axes(A), J, Jrem)
1397
function __to_subscript_indices(A::AbstractArray,
1398
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1399
    @inline
2✔
1400
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1401
end
1402
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
80,878✔
1403
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
30,862✔
1404
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1405
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1406
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1407
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
447,319✔
1408

1409
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1410
# function that allows dispatch on array storage
1411

1412
"""
1413
    setindex!(A, X, inds...)
1414
    A[inds...] = X
1415

1416
Store values from array `X` within some subset of `A` as specified by `inds`.
1417
The syntax `A[inds...] = X` is equivalent to `(setindex!(A, X, inds...); X)`.
1418

1419
$(_DOCS_ALIASING_WARNING)
1420

1421
# Examples
1422
```jldoctest
1423
julia> A = zeros(2,2);
1424

1425
julia> setindex!(A, [10, 20], [1, 2]);
1426

1427
julia> A[[3, 4]] = [30, 40];
1428

1429
julia> A
1430
2×2 Matrix{Float64}:
1431
 10.0  30.0
1432
 20.0  40.0
1433
```
1434
"""
1435
function setindex!(A::AbstractArray, v, I...)
1,518✔
1436
    @_propagate_inbounds_meta
2,990,140✔
1437
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,990,140✔
1438
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
8,767,783✔
1439
end
1440
function unsafe_setindex!(A::AbstractArray, v, I...)
1441
    @inline
732✔
1442
    @inbounds r = setindex!(A, v, I...)
732✔
1443
    r
730✔
1444
end
1445

1446
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
7✔
1447
    throw(CanonicalIndexError("setindex!", typeof(A)))
1448
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
2✔
1449
    throw(CanonicalIndexError("setindex!", typeof(A)))
1450
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
×
1451

1452
## Internal definitions
1453
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1454
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1455

1456
## IndexLinear Scalar indexing
1457
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
5,845,966✔
1458
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
696✔
1459
    @inline
161,443✔
1460
    @boundscheck checkbounds(A, I...)
264,534✔
1461
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
264,505✔
1462
    r
161,422✔
1463
end
1464

1465
# IndexCartesian Scalar indexing
1466
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
1467
    @_propagate_inbounds_meta
2,404,056✔
1468
    setindex!(A, v, I...)
2,404,069✔
1469
end
1470
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
1471
    @inline
23,631✔
1472
    @boundscheck checkbounds(A, I...)
23,636✔
1473
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
23,626✔
1474
    r
23,626✔
1475
end
1476

1477
_unsetindex!(A::AbstractArray, i::Integer) = _unsetindex!(A, to_index(i))
×
1478

1479
"""
1480
    parent(A)
1481

1482
Return the underlying parent object of the view. This parent of objects of types `SubArray`, `SubString`, `ReshapedArray`
1483
or `LinearAlgebra.Transpose` is what was passed as an argument to `view`, `reshape`, `transpose`, etc.
1484
during object creation. If the input is not a wrapped object, return the input itself. If the input is
1485
wrapped multiple times, only the outermost wrapper will be removed.
1486

1487
# Examples
1488
```jldoctest
1489
julia> A = [1 2; 3 4]
1490
2×2 Matrix{Int64}:
1491
 1  2
1492
 3  4
1493

1494
julia> V = view(A, 1:2, :)
1495
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1496
 1  2
1497
 3  4
1498

1499
julia> parent(V)
1500
2×2 Matrix{Int64}:
1501
 1  2
1502
 3  4
1503
```
1504
"""
1505
function parent end
1506

1507
parent(a::AbstractArray) = a
1,594✔
1508

1509
## rudimentary aliasing detection ##
1510
"""
1511
    Base.unalias(dest, A)
1512

1513
Return either `A` or a copy of `A` in a rough effort to prevent modifications to `dest` from
1514
affecting the returned object. No guarantees are provided.
1515

1516
Custom arrays that wrap or use fields containing arrays that might alias against other
1517
external objects should provide a [`Base.dataids`](@ref) implementation.
1518

1519
This function must return an object of exactly the same type as `A` for performance and type
1520
stability. Mutable custom arrays for which [`copy(A)`](@ref) is not `typeof(A)` should
1521
provide a [`Base.unaliascopy`](@ref) implementation.
1522

1523
See also [`Base.mightalias`](@ref).
1524
"""
1525
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
6,620,431✔
1526
unalias(dest, A::AbstractRange) = A
32,803,309✔
1527
unalias(dest, A) = A
3,189,207✔
1528

1529
"""
1530
    Base.unaliascopy(A)
1531

1532
Make a preventative copy of `A` in an operation where `A` [`Base.mightalias`](@ref) against
1533
another array in order to preserve consistent semantics as that other array is mutated.
1534

1535
This must return an object of the same type as `A` to preserve optimal performance in the
1536
much more common case where aliasing does not occur. By default,
1537
`unaliascopy(A::AbstractArray)` will attempt to use [`copy(A)`](@ref), but in cases where
1538
`copy(A)` is not a `typeof(A)`, then the array should provide a custom implementation of
1539
`Base.unaliascopy(A)`.
1540
"""
1541
unaliascopy(A::Array) = copy(A)
7,350✔
1542
unaliascopy(A::AbstractArray)::typeof(A) = (@noinline; _unaliascopy(A, copy(A)))
14✔
1543
_unaliascopy(A::T, C::T) where {T} = C
14✔
1544
_unaliascopy(A, C) = throw(ArgumentError("""
×
1545
    an array of type `$(typename(typeof(A)).wrapper)` shares memory with another argument
1546
    and must make a preventative copy of itself in order to maintain consistent semantics,
1547
    but `copy(::$(typeof(A)))` returns a new array of type `$(typeof(C))`.
1548
    To fix, implement:
1549
        `Base.unaliascopy(A::$(typename(typeof(A)).wrapper))::typeof(A)`"""))
1550
unaliascopy(A) = A
×
1551

1552
"""
1553
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1554

1555
Perform a conservative test to check if arrays `A` and `B` might share the same memory.
1556

1557
By default, this simply checks if either of the arrays reference the same memory
1558
regions, as identified by their [`Base.dataids`](@ref).
1559
"""
1560
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !isempty(A) && !isempty(B) && !_isdisjoint(dataids(A), dataids(B))
6,624,533✔
1561
mightalias(x, y) = false
×
1562

1563
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1564
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1565
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1566
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1567
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
6,406,670✔
1568
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
46,334✔
1569
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1570
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
3,262✔
1571
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
64,459✔
1572

1573
"""
1574
    Base.dataids(A::AbstractArray)
1575

1576
Return a tuple of `UInt`s that represent the mutable data segments of an array.
1577

1578
Custom arrays that would like to opt-in to aliasing detection of their component
1579
parts can specialize this method to return the concatenation of the `dataids` of
1580
their component parts.  A typical definition for an array that wraps a parent is
1581
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1582
"""
1583
dataids(A::AbstractArray) = (UInt(objectid(A)),)
476,849✔
1584
dataids(A::Memory) = (B = ccall(:jl_genericmemory_owner, Any, (Any,), A); (UInt(pointer(B isa typeof(A) ? B : A)),))
12,452,305✔
1585
dataids(A::Array) = dataids(A.ref.mem)
8,907,160✔
1586
dataids(::AbstractRange) = ()
2,723,013✔
1587
dataids(x) = ()
19,781✔
1588

1589
## get (getindex with a default value) ##
1590

1591
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1592
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1593

1594
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
373✔
1595
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
8✔
1596
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
15✔
1597
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
4✔
1598
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
7✔
1599
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
9✔
1600

1601
function get!(X::AbstractVector{T}, A::AbstractVector, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
×
1602
    # 1d is not linear indexing
1603
    ind = findall(in(axes1(A)), I)
×
1604
    X[ind] = A[I[ind]]
×
1605
    Xind = axes1(X)
×
1606
    X[first(Xind):first(ind)-1] = default
×
1607
    X[last(ind)+1:last(Xind)] = default
×
1608
    X
×
1609
end
1610
function get!(X::AbstractArray{T}, A::AbstractArray, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
1✔
1611
    # Linear indexing
1612
    ind = findall(in(1:length(A)), I)
1✔
1613
    X[ind] = A[I[ind]]
5✔
1614
    fill!(view(X, 1:first(ind)-1), default)
6✔
1615
    fill!(view(X, last(ind)+1:length(X)), default)
1✔
1616
    X
1✔
1617
end
1618

1619
get(A::AbstractArray, I::AbstractRange, default) = get!(similar(A, typeof(default), index_shape(I)), A, I, default)
1✔
1620

1621
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
2✔
1622
    fill!(X, default)
72✔
1623
    dst, src = indcopy(size(A), I)
2✔
1624
    X[dst...] = A[src...]
2✔
1625
    X
2✔
1626
end
1627

1628
get(A::AbstractArray, I::RangeVecIntList, default) =
2✔
1629
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1630

1631
## structured matrix methods ##
1632
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
23,981✔
1633
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
33,019✔
1634

1635
## Concatenation ##
1636
eltypeof(x) = typeof(x)
14,702✔
1637
eltypeof(x::AbstractArray) = eltype(x)
14,645✔
1638

1639
promote_eltypeof() = error()
×
1640
promote_eltypeof(v1) = eltypeof(v1)
×
1641
promote_eltypeof(v1, v2) = promote_type(eltypeof(v1), eltypeof(v2))
1,384✔
1642
promote_eltypeof(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltypeof(y)), promote_eltypeof(v1, v2), vs...))
26,680✔
1643
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
6,870✔
1644
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
20✔
1645

1646
promote_eltype() = error()
×
1647
promote_eltype(v1) = eltype(v1)
×
1648
promote_eltype(v1, v2) = promote_type(eltype(v1), eltype(v2))
1,813✔
1649
promote_eltype(v1, v2, vs...) = (@inline; afoldl(((::Type{T}, y) where {T}) -> promote_type(T, eltype(y)), promote_eltype(v1, v2), vs...))
515✔
1650
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
178✔
1651
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
4,544✔
1652

1653
#TODO: ERROR CHECK
1654
_cat(catdim::Int) = Vector{Any}()
1✔
1655

1656
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1657
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1658

1659
## cat: special cases
1660
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
314✔
1661
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
235✔
1662
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
97✔
1663
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
8,000,549✔
1664

1665
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
1✔
1666
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
2✔
1667
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
10✔
1668
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
61✔
1669

1670
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
5✔
1671
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
13✔
1672

1673
# FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1674
# and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1675
# but that solution currently fails (see #27188 and #27224)
1676
AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1677

1678
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
1,500,011✔
1679
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
1,545,787✔
1680
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1681

1682
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
791,077✔
1683
    pos = 1
796,521✔
1684
    for k=1:Int(length(V))::Int
796,521✔
1685
        Vk = V[k]
797,936✔
1686
        p1 = pos + Int(length(Vk))::Int - 1
798,447✔
1687
        a[pos:p1] = Vk
5,806,163✔
1688
        pos = p1+1
797,936✔
1689
    end
799,351✔
1690
    a
796,521✔
1691
end
1692

1693
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
1,036✔
1694

1695
# Catch indexing errors like v[i +1] (instead of v[i+1] or v[i + 1]), where indexing is
1696
# interpreted as a typed concatenation. (issue #49676)
1697
typed_hcat(::AbstractArray, other...) = throw(ArgumentError("It is unclear whether you \
3✔
1698
    intend to perform an indexing operation or typed concatenation. If you intend to \
1699
    perform indexing (v[1 + 2]), adjust spacing or insert missing operator to clarify. \
1700
    If you intend to perform typed concatenation (T[1 2]), ensure that T is a type."))
1701

1702

1703
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
299✔
1704
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
272✔
1705

1706
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
1,042✔
1707
    nargs = length(A)
1,042✔
1708
    nrows = size(A[1], 1)
1,042✔
1709
    ncols = 0
1,042✔
1710
    dense = true
1,042✔
1711
    for j = 1:nargs
1,042✔
1712
        Aj = A[j]
2,147✔
1713
        if size(Aj, 1) != nrows
2,937✔
1714
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1715
        end
1716
        dense &= isa(Aj,Array)
2,146✔
1717
        nd = ndims(Aj)
2,935✔
1718
        ncols += (nd==2 ? size(Aj,2) : 1)
2,627✔
1719
    end
3,251✔
1720
    B = similar(A[1], T, nrows, ncols)
1,628✔
1721
    pos = 1
1,041✔
1722
    if dense
1,041✔
1723
        for k=1:nargs
406✔
1724
            Ak = A[k]
836✔
1725
            n = length(Ak)
1,060✔
1726
            copyto!(B, pos, Ak, 1, n)
1,416✔
1727
            pos += n
836✔
1728
        end
1,266✔
1729
    else
1730
        for k=1:nargs
635✔
1731
            Ak = A[k]
1,309✔
1732
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
1,582✔
1733
            B[:, pos:p1] = Ak
1,711✔
1734
            pos = p1+1
1,309✔
1735
        end
1,847✔
1736
    end
1737
    return B
1,041✔
1738
end
1739

1740
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
67✔
1741
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
202✔
1742

1743
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
491✔
1744
    nargs = length(A)
503✔
1745
    nrows = sum(a->size(a, 1), A)::Int
1,642✔
1746
    ncols = size(A[1], 2)
503✔
1747
    for j = 2:nargs
503✔
1748
        if size(A[j], 2) != ncols
607✔
1749
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1750
        end
1751
    end
682✔
1752
    B = similar(A[1], T, nrows, ncols)
903✔
1753
    pos = 1
502✔
1754
    for k=1:nargs
502✔
1755
        Ak = A[k]
1,088✔
1756
        p1 = pos+size(Ak,1)::Int-1
1,271✔
1757
        B[pos:p1, :] = Ak
1,144✔
1758
        pos = p1+1
1,088✔
1759
    end
1,674✔
1760
    return B
502✔
1761
end
1762

1763
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
1,546,284✔
1764

1765
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1766
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1767

1768
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1769
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1770

1771
## cat: general case
1772

1773
# helper functions
1774
cat_size(A) = (1,)
22,632✔
1775
cat_size(A::AbstractArray) = size(A)
16,364✔
1776
cat_size(A, d) = 1
×
1777
cat_size(A::AbstractArray, d) = size(A, d)
29,780✔
1778

1779
cat_length(::Any) = 1
×
1780
cat_length(a::AbstractArray) = length(a)
472✔
1781

1782
cat_ndims(a) = 0
×
1783
cat_ndims(a::AbstractArray) = ndims(a)
684✔
1784

1785
cat_indices(A, d) = OneTo(1)
22,633✔
1786
cat_indices(A::AbstractArray, d) = axes(A, d)
17,887✔
1787

1788
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
7,607✔
1789
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1790
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,332✔
1791
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1792
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
853✔
1793
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
2✔
1794

1795
# These are for backwards compatibility (even though internal)
1796
cat_shape(dims, shape::Tuple{Vararg{Int}}) = shape
×
1797
function cat_shape(dims, shapes::Tuple)
4✔
1798
    out_shape = ()
4✔
1799
    for s in shapes
4✔
1800
        out_shape = _cshp(1, dims, out_shape, s)
18✔
1801
    end
15✔
1802
    return out_shape
4✔
1803
end
1804
# The new way to compute the shape (more inferable than combining cat_size & cat_shape, due to Varargs + issue#36454)
1805
cat_size_shape(dims) = ntuple(zero, Val(length(dims)))
×
1806
@inline cat_size_shape(dims, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, (), cat_size(X)), tail...)
9,390✔
1807
_cat_size_shape(dims, shape) = shape
1,471✔
1808
@inline _cat_size_shape(dims, shape, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, shape, cat_size(X)), tail...)
29,799✔
1809

1810
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1811
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
20✔
1812
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
527✔
1813
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
499✔
1814
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1815
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
2,344✔
1816
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1817
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
1818
    _cs(ndim, shape[1], 1)
23✔
1819
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
19✔
1820
end
1821
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
1822
    next = _cs(ndim, shape[1], nshape[1])
158✔
1823
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
158✔
1824
end
1825
@inline function _cshp(ndim::Int, dims, shape, nshape)
86✔
1826
    a = shape[1]
30,599✔
1827
    b = nshape[1]
30,599✔
1828
    next = dims[1] ? a + b : _cs(ndim, a, b)
31,102✔
1829
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
30,676✔
1830
end
1831

1832
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,085✔
1833
    "mismatch in dimension $d (expected $a got $b)")))
1834

1835
dims2cat(::Val{dims}) where dims = dims2cat(dims)
544✔
1836
function dims2cat(dims)
5✔
1837
    if any(≤(0), dims)
2,956✔
1838
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1839
    end
1840
    ntuple(in(dims), maximum(dims))
2,172✔
1841
end
1842

1843
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
8,251✔
1844

1845
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
8,286✔
1846
    catdims = dims2cat(dims)
10,037✔
1847
    shape = cat_size_shape(catdims, X...)
9,390✔
1848
    A = cat_similar(X[1], T, shape)
9,751✔
1849
    if count(!iszero, catdims)::Int > 1
9,220✔
1850
        fill!(A, zero(T))
791✔
1851
    end
1852
    return __cat(A, shape, catdims, X...)
9,324✔
1853
end
1854
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1855
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1856
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1857

1858
# Why isn't this called `__cat!`?
1859
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
9,836✔
1860

1861
function __cat_offset!(A, shape, catdims, offsets, x, X...)
36,433✔
1862
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1863
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
83,993✔
1864
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
39,107✔
1865
end
1866
__cat_offset!(A, shape, catdims, offsets) = A
9,222✔
1867

1868
function __cat_offset1!(A, shape, catdims, offsets, x)
5✔
1869
    inds = ntuple(length(offsets)) do i
39,264✔
1870
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
42,734✔
1871
    end
1872
    _copy_or_fill!(A, inds, x)
131,433✔
1873
    newoffsets = ntuple(length(offsets)) do i
39,067✔
1874
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
41,442✔
1875
    end
1876
    return newoffsets
39,067✔
1877
end
1878

1879
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
23,584✔
1880
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
107,813✔
1881

1882
"""
1883
    vcat(A...)
1884

1885
Concatenate arrays or numbers vertically. Equivalent to [`cat`](@ref)`(A...; dims=1)`,
1886
and to the syntax `[a; b; c]`.
1887

1888
To concatenate a large vector of arrays, `reduce(vcat, A)` calls an efficient method
1889
when `A isa AbstractVector{<:AbstractVecOrMat}`, rather than working pairwise.
1890

1891
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1892

1893
# Examples
1894
```jldoctest
1895
julia> v = vcat([1,2], [3,4])
1896
4-element Vector{Int64}:
1897
 1
1898
 2
1899
 3
1900
 4
1901

1902
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1903
true
1904

1905
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1906
true
1907

1908
julia> summary(ComplexF64[1; 2; [3,4]])  # syntax for supplying the element type
1909
"4-element Vector{ComplexF64}"
1910

1911
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1912
3-element Vector{Float64}:
1913
 1.0
1914
 1.5
1915
 2.0
1916

1917
julia> two = ([10, 20, 30]', Float64[4 5 6; 7 8 9])  # row vector and a matrix
1918
([10 20 30], [4.0 5.0 6.0; 7.0 8.0 9.0])
1919

1920
julia> vcat(two...)
1921
3×3 Matrix{Float64}:
1922
 10.0  20.0  30.0
1923
  4.0   5.0   6.0
1924
  7.0   8.0   9.0
1925

1926
julia> vs = [[1, 2], [3, 4], [5, 6]];
1927

1928
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1929
6-element Vector{Int64}:
1930
 1
1931
 2
1932
 3
1933
 4
1934
 5
1935
 6
1936

1937
julia> ans == collect(Iterators.flatten(vs))
1938
true
1939
```
1940
"""
1941
vcat(X...) = cat(X...; dims=Val(1))
433✔
1942
"""
1943
    hcat(A...)
1944

1945
Concatenate arrays or numbers horizontally. Equivalent to [`cat`](@ref)`(A...; dims=2)`,
1946
and to the syntax `[a b c]` or `[a;; b;; c]`.
1947

1948
For a large vector of arrays, `reduce(hcat, A)` calls an efficient method
1949
when `A isa AbstractVector{<:AbstractVecOrMat}`.
1950
For a vector of vectors, this can also be written [`stack`](@ref)`(A)`.
1951

1952
See also [`vcat`](@ref), [`hvcat`](@ref).
1953

1954
# Examples
1955
```jldoctest
1956
julia> hcat([1,2], [3,4], [5,6])
1957
2×3 Matrix{Int64}:
1958
 1  3  5
1959
 2  4  6
1960

1961
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1962
1×7 Matrix{Int64}:
1963
 1  2  30  40  5  6  7
1964

1965
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1966
true
1967

1968
julia> Float32[1 2 [30 40] [5, 6, 7]']  # syntax for supplying the eltype
1969
1×7 Matrix{Float32}:
1970
 1.0  2.0  30.0  40.0  5.0  6.0  7.0
1971

1972
julia> ms = [zeros(2,2), [1 2; 3 4], [50 60; 70 80]];
1973

1974
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
1975
2×6 Matrix{Float64}:
1976
 0.0  0.0  1.0  2.0  50.0  60.0
1977
 0.0  0.0  3.0  4.0  70.0  80.0
1978

1979
julia> stack(ms) |> summary  # disagrees on a vector of matrices
1980
"2×2×3 Array{Float64, 3}"
1981

1982
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
1983
0×3 Matrix{Int64}
1984

1985
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
1986
2×1 Matrix{Any}:
1987
 1.1
1988
 9.9
1989
```
1990
"""
1991
hcat(X...) = cat(X...; dims=Val(2))
10✔
1992

1993
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
394✔
1994
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
338✔
1995

1996
"""
1997
    cat(A...; dims)
1998

1999
Concatenate the input arrays along the dimensions specified in `dims`.
2000

2001
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
2002
a in A)`.
2003
Along other dimensions, all input arrays should have the same size,
2004
which will also be the size of the output array along those dimensions.
2005

2006
If `dims` is a single number, the different arrays are tightly packed along that dimension.
2007
If `dims` is an iterable containing several dimensions, the positions along these dimensions
2008
are increased simultaneously for each input array, filling with zero elsewhere.
2009
This allows one to construct block-diagonal matrices as `cat(matrices...; dims=(1,2))`,
2010
and their higher-dimensional analogues.
2011

2012
The special case `dims=1` is [`vcat`](@ref), and `dims=2` is [`hcat`](@ref).
2013
See also [`hvcat`](@ref), [`hvncat`](@ref), [`stack`](@ref), [`repeat`](@ref).
2014

2015
The keyword also accepts `Val(dims)`.
2016

2017
!!! compat "Julia 1.8"
2018
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
2019

2020
# Examples
2021

2022
Concatenate two arrays in different dimensions:
2023
```jldoctest
2024
julia> a = [1 2 3]
2025
1×3 Matrix{Int64}:
2026
 1  2  3
2027

2028
julia> b = [4 5 6]
2029
1×3 Matrix{Int64}:
2030
 4  5  6
2031

2032
julia> cat(a, b; dims=1)
2033
2×3 Matrix{Int64}:
2034
 1  2  3
2035
 4  5  6
2036

2037
julia> cat(a, b; dims=2)
2038
1×6 Matrix{Int64}:
2039
 1  2  3  4  5  6
2040

2041
julia> cat(a, b; dims=(1, 2))
2042
2×6 Matrix{Int64}:
2043
 1  2  3  0  0  0
2044
 0  0  0  4  5  6
2045
```
2046

2047
# Extended Help
2048

2049
Concatenate 3D arrays:
2050
```jldoctest
2051
julia> a = ones(2, 2, 3);
2052

2053
julia> b = ones(2, 2, 4);
2054

2055
julia> c = cat(a, b; dims=3);
2056

2057
julia> size(c) == (2, 2, 7)
2058
true
2059
```
2060

2061
Concatenate arrays of different sizes:
2062
```jldoctest
2063
julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2)  # same as hcat
2064
2×6×1 Array{Float64, 3}:
2065
[:, :, 1] =
2066
 1.0  2.0  3.14159  10.0  10.0  10.0
2067
 3.0  4.0  3.14159  10.0  10.0  10.0
2068
```
2069

2070
Construct a block diagonal matrix:
2071
```
2072
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
2073
4×7 Matrix{Bool}:
2074
 1  0  0  0  0  0  0
2075
 0  1  1  0  0  0  0
2076
 0  1  1  0  0  0  0
2077
 0  0  0  1  1  1  1
2078
```
2079

2080
```
2081
julia> cat(1, [2], [3;;]; dims=Val(2))
2082
1×3 Matrix{Int64}:
2083
 1  2  3
2084
```
2085

2086
!!! note
2087
    `cat` does not join two strings, you may want to use `*`.
2088

2089
```jldoctest
2090
julia> a = "aaa";
2091

2092
julia> b = "bbb";
2093

2094
julia> cat(a, b; dims=1)
2095
2-element Vector{String}:
2096
 "aaa"
2097
 "bbb"
2098

2099
julia> cat(a, b; dims=2)
2100
1×2 Matrix{String}:
2101
 "aaa"  "bbb"
2102

2103
julia> a * b
2104
"aaabbb"
2105
```
2106
"""
2107
@inline cat(A...; dims) = _cat(dims, A...)
17,379✔
2108
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
2109
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
219✔
2110

2111
# The specializations for 1 and 2 inputs are important
2112
# especially when running with --inline=no, see #11158
2113
vcat(A::AbstractArray) = cat(A; dims=Val(1))
1✔
2114
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
5✔
2115
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
2116
vcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(1))
7,075✔
2117
hcat(A::AbstractArray) = cat(A; dims=Val(2))
1✔
2118
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
1✔
2119
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
1✔
2120
hcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(2))
6✔
2121

2122
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
2123
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
2124
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
2125
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
2126
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
2127
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
2128

2129
# 2d horizontal and vertical concatenation
2130

2131
# these are produced in lowering if splatting occurs inside hvcat
2132
hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
3✔
2133
typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
3✔
2134

2135
function hvcat(nbc::Int, as...)
10✔
2136
    # nbc = # of block columns
2137
    n = length(as)
10✔
2138
    mod(n,nbc) != 0 &&
20✔
2139
        throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc"))
2140
    nbr = div(n,nbc)
9✔
2141
    hvcat(ntuple(Returns(nbc), nbr), as...)
9✔
2142
end
2143

2144
"""
2145
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2146

2147
Horizontal and vertical concatenation in one call. This function is called for block matrix
2148
syntax. The first argument specifies the number of arguments to concatenate in each block
2149
row. If the first argument is a single integer `n`, then all block rows are assumed to have `n`
2150
block columns.
2151

2152
# Examples
2153
```jldoctest
2154
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2155
(1, 2, 3, 4, 5, 6)
2156

2157
julia> [a b c; d e f]
2158
2×3 Matrix{Int64}:
2159
 1  2  3
2160
 4  5  6
2161

2162
julia> hvcat((3,3), a,b,c,d,e,f)
2163
2×3 Matrix{Int64}:
2164
 1  2  3
2165
 4  5  6
2166

2167
julia> [a b; c d; e f]
2168
3×2 Matrix{Int64}:
2169
 1  2
2170
 3  4
2171
 5  6
2172

2173
julia> hvcat((2,2,2), a,b,c,d,e,f)
2174
3×2 Matrix{Int64}:
2175
 1  2
2176
 3  4
2177
 5  6
2178
julia> hvcat((2,2,2), a,b,c,d,e,f) == hvcat(2, a,b,c,d,e,f)
2179
true
2180
```
2181
"""
2182
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
323✔
2183
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray{T}...) where {T} = typed_hvcat(T, rows, xs...)
518✔
2184

2185
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T
882✔
2186
    nbr = length(rows)  # number of block rows
882✔
2187

2188
    nc = 0
882✔
2189
    for i=1:rows[1]
882✔
2190
        nc += size(as[i],2)
1,697✔
2191
    end
2,512✔
2192

2193
    nr = 0
882✔
2194
    a = 1
882✔
2195
    for i = 1:nbr
882✔
2196
        nr += size(as[a],1)
1,427✔
2197
        a += rows[i]
1,427✔
2198
    end
1,972✔
2199

2200
    out = similar(as[1], T, nr, nc)
924✔
2201

2202
    a = 1
882✔
2203
    r = 1
882✔
2204
    for i = 1:nbr
882✔
2205
        c = 1
1,427✔
2206
        szi = size(as[a],1)
1,427✔
2207
        for j = 1:rows[i]
1,427✔
2208
            Aj = as[a+j-1]
2,631✔
2209
            szj = size(Aj,2)
2,631✔
2210
            if size(Aj,1) != szi
2,631✔
2211
                throw(DimensionMismatch("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
1✔
2212
            end
2213
            if c-1+szj > nc
3,927✔
2214
                throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
1✔
2215
            end
2216
            out[r:r-1+szi, c:c-1+szj] = Aj
3,845✔
2217
            c += szj
2,629✔
2218
        end
3,833✔
2219
        if c != nc+1
1,425✔
2220
            throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
1✔
2221
        end
2222
        r += szi
1,424✔
2223
        a += rows[i]
1,424✔
2224
    end
1,969✔
2225
    out
879✔
2226
end
2227

2228
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
2229
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2230

2231
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,312✔
2232
    nr = length(rows)
1,311✔
2233
    nc = rows[1]
1,312✔
2234

2235
    a = Matrix{T}(undef, nr, nc)
2,624✔
2236
    if length(a) != length(xs)
1,312✔
2237
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2238
    end
2239
    k = 1
1,309✔
2240
    @inbounds for i=1:nr
1,311✔
2241
        if nc != rows[i]
3,550✔
2242
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2243
        end
2244
        for j=1:nc
3,549✔
2245
            a[i,j] = xs[k]
9,778✔
2246
            k += 1
9,778✔
2247
        end
16,007✔
2248
    end
5,788✔
2249
    a
1,308✔
2250
end
2251

2252
function hvcat_fill!(a::Array, xs::Tuple)
494✔
2253
    nr, nc = size(a,1), size(a,2)
502✔
2254
    len = length(xs)
502✔
2255
    if nr*nc != len
502✔
2256
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2257
    end
2258
    k = 1
501✔
2259
    for i=1:nr
501✔
2260
        @inbounds for j=1:nc
1,336✔
2261
            a[i,j] = xs[k]
8,820✔
2262
            k += 1
8,820✔
2263
        end
16,304✔
2264
    end
2,171✔
2265
    a
501✔
2266
end
2267

2268
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
178✔
2269
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
138✔
2270
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2271
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
3✔
2272

2273
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
354✔
2274
    nr = length(rows)
430✔
2275
    nc = rows[1]
430✔
2276
    for i = 2:nr
430✔
2277
        if nc != rows[i]
824✔
2278
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2✔
2279
        end
2280
    end
1,216✔
2281
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
428✔
2282
end
2283

2284
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T
153✔
2285
    nbr = length(rows)  # number of block rows
153✔
2286
    rs = Vector{Any}(undef, nbr)
153✔
2287
    a = 1
153✔
2288
    for i = 1:nbr
153✔
2289
        rs[i] = typed_hcat(T, as[a:a-1+rows[i]]...)
376✔
2290
        a += rows[i]
376✔
2291
    end
599✔
2292
    T[rs...;]
153✔
2293
end
2294

2295
## N-dimensional concatenation ##
2296

2297
"""
2298
    hvncat(dim::Int, row_first, values...)
2299
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2300
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2301

2302
Horizontal, vertical, and n-dimensional concatenation of many `values` in one call.
2303

2304
This function is called for block matrix syntax. The first argument either specifies the
2305
shape of the concatenation, similar to `hvcat`, as a tuple of tuples, or the dimensions that
2306
specify the key number of elements along each axis, and is used to determine the output
2307
dimensions. The `dims` form is more performant, and is used by default when the concatenation
2308
operation has the same number of elements along each axis (e.g., [a b; c d;;; e f ; g h]).
2309
The `shape` form is used when the number of elements along each axis is unbalanced
2310
(e.g., [a b ; c]). Unbalanced syntax needs additional validation overhead. The `dim` form
2311
is an optimization for concatenation along just one dimension. `row_first` indicates how
2312
`values` are ordered. The meaning of the first and second elements of `shape` are also
2313
swapped based on `row_first`.
2314

2315
# Examples
2316
```jldoctest
2317
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2318
(1, 2, 3, 4, 5, 6)
2319

2320
julia> [a b c;;; d e f]
2321
1×3×2 Array{Int64, 3}:
2322
[:, :, 1] =
2323
 1  2  3
2324

2325
[:, :, 2] =
2326
 4  5  6
2327

2328
julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2329
2×1×3 Array{Int64, 3}:
2330
[:, :, 1] =
2331
 1
2332
 2
2333

2334
[:, :, 2] =
2335
 3
2336
 4
2337

2338
[:, :, 3] =
2339
 5
2340
 6
2341

2342
julia> [a b;;; c d;;; e f]
2343
1×2×3 Array{Int64, 3}:
2344
[:, :, 1] =
2345
 1  2
2346

2347
[:, :, 2] =
2348
 3  4
2349

2350
[:, :, 3] =
2351
 5  6
2352

2353
julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f)
2354
1×3×2 Array{Int64, 3}:
2355
[:, :, 1] =
2356
 1  2  3
2357

2358
[:, :, 2] =
2359
 4  5  6
2360
```
2361

2362
# Examples for construction of the arguments
2363
```
2364
[a b c ; d e f ;;;
2365
 g h i ; j k l ;;;
2366
 m n o ; p q r ;;;
2367
 s t u ; v w x]
2368
⇒ dims = (2, 3, 4)
2369

2370
[a b ; c ;;; d ;;;;]
2371
 ___   _     _
2372
 2     1     1 = elements in each row (2, 1, 1)
2373
 _______     _
2374
 3           1 = elements in each column (3, 1)
2375
 _____________
2376
 4             = elements in each 3d slice (4,)
2377
 _____________
2378
 4             = elements in each 4d slice (4,)
2379
⇒ shape = ((2, 1, 1), (3, 1), (4,), (4,)) with `row_first` = true
2380
```
2381
"""
2382
hvncat(dimsshape::Tuple, row_first::Bool, xs...) = _hvncat(dimsshape, row_first, xs...)
262✔
2383
hvncat(dim::Int, xs...) = _hvncat(dim, true, xs...)
78✔
2384

2385
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
28✔
2386
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
91✔
2387
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
89✔
2388
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
2389
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2390
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
132✔
2391

2392

2393
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
17✔
2394
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2395

2396
# 1-dimensional hvncat methods
2397

2398
_typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
4✔
2399
_typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
×
2400
_typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
4✔
2401
_typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
4✔
2402
_typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
×
2403
_typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
4✔
2404
_typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
×
2405

2406
_typed_hvncat_0d_only_one() =
8✔
2407
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2408

2409
# `@constprop :aggressive` here to form constant `Val(dim)` type to get type stability
2410
@constprop :aggressive _typed_hvncat(T::Type, dim::Int, ::Bool, xs...) = _typed_hvncat(T, Val(dim), xs...) # catches from _hvncat type promoters
78✔
2411

2412
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
15✔
2413
    N < 0 &&
15✔
2414
        throw(ArgumentError("concatenation dimension must be non-negative"))
2415
    return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
14✔
2416
end
2417

2418
function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
26✔
2419
    N < 0 &&
39✔
2420
        throw(ArgumentError("concatenation dimension must be non-negative"))
2421
    A = cat_similar(xs[1], T, (ntuple(x -> 1, Val(N - 1))..., length(xs)))
38✔
2422
    hvncat_fill!(A, false, xs)
38✔
2423
    return A
38✔
2424
end
2425

2426
function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N}
24✔
2427
    # optimization for arrays that can be concatenated by copying them linearly into the destination
2428
    # conditions: the elements must all have 1-length dimensions above N
2429
    length(as) > 0 ||
25✔
2430
        throw(ArgumentError("must have at least one element"))
2431
    N < 0 &&
25✔
2432
        throw(ArgumentError("concatenation dimension must be non-negative"))
2433
    for a ∈ as
23✔
2434
        ndims(a) <= N || all(x -> size(a, x) == 1, (N + 1):ndims(a)) ||
61✔
2435
            return _typed_hvncat(T, (ntuple(x -> 1, Val(N - 1))..., length(as), 1), false, as...)
2436
            # the extra 1 is to avoid an infinite cycle
2437
    end
46✔
2438

2439
    nd = N
17✔
2440

2441
    Ndim = 0
17✔
2442
    for i ∈ eachindex(as)
17✔
2443
        Ndim += cat_size(as[i], N)
38✔
2444
        nd = max(nd, cat_ndims(as[i]))
38✔
2445
        for d ∈ 1:N - 1
32✔
2446
            cat_size(as[1], d) == cat_size(as[i], d) || throw(DimensionMismatch("mismatched size along axis $d in element $i"))
39✔
2447
        end
44✔
2448
    end
43✔
2449

2450
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
32✔
2451
    k = 1
13✔
2452
    for a ∈ as
13✔
2453
        for i ∈ eachindex(a)
26✔
2454
            A[k] = a[i]
34✔
2455
            k += 1
34✔
2456
        end
47✔
2457
    end
34✔
2458
    return A
13✔
2459
end
2460

2461
function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N}
14✔
2462
    length(as) > 0 ||
14✔
2463
        throw(ArgumentError("must have at least one element"))
2464
    N < 0 &&
14✔
2465
        throw(ArgumentError("concatenation dimension must be non-negative"))
2466
    nd = N
12✔
2467
    Ndim = 0
12✔
2468
    for i ∈ eachindex(as)
12✔
2469
        Ndim += cat_size(as[i], N)
30✔
2470
        nd = max(nd, cat_ndims(as[i]))
34✔
2471
        for d ∈ 1:N-1
20✔
2472
            cat_size(as[i], d) == 1 ||
36✔
2473
                throw(DimensionMismatch("all dimensions of element $i other than $N must be of length 1"))
2474
        end
28✔
2475
    end
20✔
2476

2477
    A = Array{T, nd}(undef, ntuple(x -> 1, Val(N - 1))..., Ndim, ntuple(x -> 1, nd - N)...)
7✔
2478

2479
    k = 1
4✔
2480
    for a ∈ as
4✔
2481
        if a isa AbstractArray
12✔
2482
            lena = length(a)
2✔
2483
            copyto!(A, k, a, 1, lena)
2✔
2484
            k += lena
2✔
2485
        else
2486
            A[k] = a
10✔
2487
            k += 1
10✔
2488
        end
2489
    end
16✔
2490
    return A
4✔
2491
end
2492

2493
# 0-dimensional cases for balanced and unbalanced hvncat method
2494

2495
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2496
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2497

2498

2499
# balanced dimensions hvncat methods
2500

2501
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
2✔
2502
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as::Number...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
7✔
2503

2504
function _typed_hvncat_1d(::Type{T}, ds::Int, ::Val{row_first}, as...) where {T, row_first}
21✔
2505
    lengthas = length(as)
22✔
2506
    ds > 0 ||
22✔
2507
        throw(ArgumentError("`dimsshape` argument must consist of positive integers"))
2508
    lengthas == ds ||
30✔
2509
        throw(ArgumentError("number of elements does not match `dimshape` argument; expected $ds, got $lengthas"))
2510
    if row_first
14✔
2511
        return _typed_hvncat(T, Val(2), as...)
4✔
2512
    else
2513
        return _typed_hvncat(T, Val(1), as...)
10✔
2514
    end
2515
end
2516

2517
function _typed_hvncat(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, xs::Number...) where {T, N}
44✔
2518
    all(>(0), dims) ||
60✔
2519
        throw(ArgumentError("`dims` argument must contain positive integers"))
2520
    A = Array{T, N}(undef, dims...)
56✔
2521
    lengtha = length(A)  # Necessary to store result because throw blocks are being deoptimized right now, which leads to excessive allocations
28✔
2522
    lengthx = length(xs) # Cuts from 3 allocations to 1.
28✔
2523
    if lengtha != lengthx
28✔
2524
       throw(ArgumentError("argument count does not match specified shape (expected $lengtha, got $lengthx)"))
×
2525
    end
2526
    hvncat_fill!(A, row_first, xs)
28✔
2527
    return A
28✔
2528
end
2529

2530
function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
66✔
2531
    nr, nc = size(A, 1), size(A, 2)
66✔
2532
    na = prod(size(A)[3:end])
66✔
2533
    len = length(xs)
66✔
2534
    nrc = nr * nc
66✔
2535
    if nrc * na != len
66✔
2536
        throw(ArgumentError("argument count $(len) does not match specified shape $(size(A))"))
×
2537
    end
2538
    # putting these in separate functions leads to unnecessary allocations
2539
    if row_first
66✔
2540
        k = 1
17✔
2541
        for d ∈ 1:na
17✔
2542
            dd = nrc * (d - 1)
31✔
2543
            for i ∈ 1:nr
31✔
2544
                Ai = dd + i
42✔
2545
                for j ∈ 1:nc
42✔
2546
                    @inbounds A[Ai] = xs[k]
95✔
2547
                    k += 1
95✔
2548
                    Ai += nr
95✔
2549
                end
148✔
2550
            end
53✔
2551
        end
31✔
2552
    else
2553
        for k ∈ eachindex(xs)
49✔
2554
            @inbounds A[k] = xs[k]
96✔
2555
        end
96✔
2556
    end
2557
end
2558

2559
function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
76✔
2560
    # function barrier after calculating the max is necessary for high performance
2561
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
90✔
2562
    return _typed_hvncat_dims(T, (dims..., ntuple(x -> 1, nd - N)...), row_first, as)
90✔
2563
end
2564

2565
function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
90✔
2566
    length(as) > 0 ||
90✔
2567
        throw(ArgumentError("must have at least one element"))
2568
    all(>(0), dims) ||
122✔
2569
        throw(ArgumentError("`dims` argument must contain positive integers"))
2570

2571
    d1 = row_first ? 2 : 1
58✔
2572
    d2 = row_first ? 1 : 2
58✔
2573

2574
    outdims = zeros(Int, N)
203✔
2575

2576
    # validate shapes for lowest level of concatenation
2577
    d = findfirst(>(1), dims)
86✔
2578
    if d !== nothing # all dims are 1
58✔
2579
        if row_first && d < 3
57✔
2580
            d = d == 1 ? 2 : 1
32✔
2581
        end
2582
        nblocks = length(as) ÷ dims[d]
57✔
2583
        for b ∈ 1:nblocks
57✔
2584
            offset = ((b - 1) * dims[d])
175✔
2585
            startelementi = offset + 1
175✔
2586
            for i ∈ offset .+ (2:dims[d])
263✔
2587
                for dd ∈ 1:N
111✔
2588
                    dd == d && continue
316✔
2589
                    if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
313✔
2590
                        throw(DimensionMismatch("incompatible shape in element $i"))
6✔
2591
                    end
2592
                end
515✔
2593
            end
129✔
2594
        end
287✔
2595
    end
2596

2597
    # discover number of rows or columns
2598
    for i ∈ 1:dims[d1]
52✔
2599
        outdims[d1] += cat_size(as[i], d1)
108✔
2600
    end
164✔
2601

2602
    currentdims = zeros(Int, N)
176✔
2603
    blockcount = 0
52✔
2604
    elementcount = 0
52✔
2605
    for i ∈ eachindex(as)
52✔
2606
        elementcount += cat_length(as[i])
306✔
2607
        currentdims[d1] += cat_size(as[i], d1)
259✔
2608
        if currentdims[d1] == outdims[d1]
259✔
2609
            currentdims[d1] = 0
129✔
2610
            for d ∈ (d2, 3:N...)
129✔
2611
                currentdims[d] += cat_size(as[i], d)
203✔
2612
                if outdims[d] == 0 # unfixed dimension
203✔
2613
                    blockcount += 1
167✔
2614
                    if blockcount == dims[d]
167✔
2615
                        outdims[d] = currentdims[d]
88✔
2616
                        currentdims[d] = 0
88✔
2617
                        blockcount = 0
88✔
2618
                    else
2619
                        break
79✔
2620
                    end
2621
                else # fixed dimension
2622
                    if currentdims[d] == outdims[d] # end of dimension
36✔
2623
                        currentdims[d] = 0
23✔
2624
                    elseif currentdims[d] < outdims[d] # dimension in progress
13✔
2625
                        break
13✔
2626
                    else # exceeded dimension
2627
                        throw(DimensionMismatch("argument $i has too many elements along axis $d"))
×
2628
                    end
2629
                end
2630
            end
142✔
2631
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
130✔
2632
            throw(DimensionMismatch("argument $i has too many elements along axis $d1"))
16✔
2633
        end
2634
    end
450✔
2635

2636
    outlen = prod(outdims)
72✔
2637
    elementcount == outlen ||
36✔
2638
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2639

2640
    # copy into final array
2641
    A = cat_similar(as[1], T, outdims)
36✔
2642
    # @assert all(==(0), currentdims)
2643
    outdims .= 0
108✔
2644
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
36✔
2645
    return A
36✔
2646
end
2647

2648

2649
# unbalanced dimensions hvncat methods
2650

2651
function _typed_hvncat(T::Type, shape::Tuple{Tuple}, row_first::Bool, xs...)
19✔
2652
    length(shape[1]) > 0 ||
19✔
2653
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2654
    return _typed_hvncat_1d(T, shape[1][1], Val(row_first), xs...)
13✔
2655
end
2656

2657
function _typed_hvncat(T::Type, shape::NTuple{N, Tuple}, row_first::Bool, as...) where {N}
99✔
2658
    # function barrier after calculating the max is necessary for high performance
2659
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
115✔
2660
    return _typed_hvncat_shape(T, (shape..., ntuple(x -> shape[end], nd - N)...), row_first, as)
122✔
2661
end
2662

2663
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
107✔
2664
    length(as) > 0 ||
107✔
2665
        throw(ArgumentError("must have at least one element"))
2666
    all(>(0), tuple((shape...)...)) ||
147✔
2667
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2668

2669
    d1 = row_first ? 2 : 1
67✔
2670
    d2 = row_first ? 1 : 2
67✔
2671

2672
    shapev = collect(shape) # saves allocations later
110✔
2673
    all(!isempty, shapev) ||
67✔
2674
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2675
    length(shapev[end]) == 1 ||
70✔
2676
        throw(ArgumentError("last level of shape must contain only one integer"))
2677
    shapelength = shapev[end][1]
64✔
2678
    lengthas = length(as)
64✔
2679
    shapelength == lengthas || throw(ArgumentError("number of elements does not match shape; expected $(shapelength), got $lengthas)"))
64✔
2680
    # discover dimensions
2681
    nd = max(N, cat_ndims(as[1]))
64✔
2682
    outdims = fill(-1, nd)
210✔
2683
    currentdims = zeros(Int, nd)
210✔
2684
    blockcounts = zeros(Int, nd)
210✔
2685
    shapepos = ones(Int, nd)
210✔
2686

2687
    elementcount = 0
64✔
2688
    for i ∈ eachindex(as)
64✔
2689
        elementcount += cat_length(as[i])
355✔
2690
        wasstartblock = false
313✔
2691
        for d ∈ 1:N
313✔
2692
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
907✔
2693
            dsize = cat_size(as[i], ad)
1,386✔
2694
            blockcounts[d] += 1
907✔
2695

2696
            if d == 1 || i == 1 || wasstartblock
1,501✔
2697
                currentdims[d] += dsize
623✔
2698
            elseif dsize != cat_size(as[i - 1], ad)
422✔
2699
                throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
8✔
2700
                                         expected $(cat_size(as[i - 1], ad)), got $dsize"))
2701
            end
2702

2703
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
899✔
2704

2705
            isendblock = blockcounts[d] == shapev[d][shapepos[d]]
899✔
2706
            if isendblock
899✔
2707
                if outdims[d] == -1
269✔
2708
                    outdims[d] = currentdims[d]
138✔
2709
                elseif outdims[d] != currentdims[d]
131✔
2710
                    throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
40✔
2711
                                             expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2712
                end
2713
                currentdims[d] = 0
229✔
2714
                blockcounts[d] = 0
229✔
2715
                shapepos[d] += 1
229✔
2716
                d > 1 && (blockcounts[d - 1] == 0 ||
230✔
2717
                    throw(DimensionMismatch("shape in level $d is inconsistent; level counts must nest \
2718
                                             evenly into each other")))
2719
            end
2720
        end
1,452✔
2721
    end
513✔
2722

2723
    outlen = prod(outdims)
30✔
2724
    elementcount == outlen ||
15✔
2725
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2726

2727
    if row_first
15✔
2728
        outdims[1], outdims[2] = outdims[2], outdims[1]
11✔
2729
    end
2730

2731
    # @assert all(==(0), currentdims)
2732
    # @assert all(==(0), blockcounts)
2733

2734
    # copy into final array
2735
    A = cat_similar(as[1], T, outdims)
15✔
2736
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
15✔
2737
    return A
15✔
2738
end
2739

2740
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int},
51✔
2741
                              d1::Int, d2::Int, as::Tuple) where {T, N}
2742
    N > 1 || throw(ArgumentError("dimensions of the destination array must be at least 2"))
51✔
2743
    length(scratch1) == length(scratch2) == N ||
51✔
2744
        throw(ArgumentError("scratch vectors must have as many elements as the destination array has dimensions"))
2745
    0 < d1 < 3 &&
51✔
2746
    0 < d2 < 3 &&
2747
    d1 != d2 ||
2748
        throw(ArgumentError("d1 and d2 must be either 1 or 2, exclusive."))
2749
    outdims = size(A)
51✔
2750
    offsets = scratch1
51✔
2751
    inneroffsets = scratch2
51✔
2752
    for a ∈ as
51✔
2753
        if isa(a, AbstractArray)
270✔
2754
            for ai ∈ a
249✔
2755
                @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
7,046✔
2756
                A[Ai] = ai
1,888✔
2757

2758
                @inbounds for j ∈ 1:N
1,888✔
2759
                    inneroffsets[j] += 1
4,152✔
2760
                    inneroffsets[j] < cat_size(a, j) && break
7,976✔
2761
                    inneroffsets[j] = 0
2,490✔
2762
                end
2,490✔
2763
            end
1,912✔
2764
        else
2765
            @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
52✔
2766
            A[Ai] = a
27✔
2767
        end
2768

2769
        @inbounds for j ∈ (d1, d2, 3:N...)
270✔
2770
            offsets[j] += cat_size(a, j)
518✔
2771
            offsets[j] < outdims[j] && break
518✔
2772
            offsets[j] = 0
304✔
2773
        end
304✔
2774
    end
270✔
2775
end
2776

2777
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
2778
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2779
    Ai = inneroffsets[1] + offsets[1] + 1
1,915✔
2780
    for j ∈ 2:nd
1,915✔
2781
        increment = inneroffsets[j] + offsets[j]
7,098✔
2782
        for k ∈ 1:j-1
7,098✔
2783
            increment *= outdims[k]
17,209✔
2784
        end
27,320✔
2785
        Ai += increment
7,098✔
2786
    end
12,281✔
2787
    Ai
1,915✔
2788
end
2789

2790
"""
2791
    stack(iter; [dims])
2792

2793
Combine a collection of arrays (or other iterable objects) of equal size
2794
into one larger array, by arranging them along one or more new dimensions.
2795

2796
By default the axes of the elements are placed first,
2797
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2798
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2799

2800
With keyword `dims::Integer`, instead the `i`th element of `iter` becomes the slice
2801
[`selectdim`](@ref)`(result, dims, i)`, so that `size(result, dims) == length(iter)`.
2802
In this case `stack` reverses the action of [`eachslice`](@ref) with the same `dims`.
2803

2804
The various [`cat`](@ref) functions also combine arrays. However, these all
2805
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2806
the arrays along new dimensions.
2807
They also accept arrays as separate arguments, rather than a single collection.
2808

2809
!!! compat "Julia 1.9"
2810
    This function requires at least Julia 1.9.
2811

2812
# Examples
2813
```jldoctest
2814
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2815

2816
julia> mat = stack(vecs)
2817
2×3 Matrix{Float32}:
2818
 1.0  30.0  500.0
2819
 2.0  40.0  600.0
2820

2821
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2822
true
2823

2824
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2825
true
2826

2827
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2828
2×4 Matrix{Int64}:
2829
  1   2   3   4
2830
 10  11  12  13
2831

2832
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2833
true
2834

2835
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2836
3×2 Matrix{Float32}:
2837
   1.0    2.0
2838
  30.0   40.0
2839
 500.0  600.0
2840

2841
julia> x = rand(3,4);
2842

2843
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2844
true
2845
```
2846

2847
Higher-dimensional examples:
2848

2849
```jldoctest
2850
julia> A = rand(5, 7, 11);
2851

2852
julia> E = eachslice(A, dims=2);  # a vector of matrices
2853

2854
julia> (element = size(first(E)), container = size(E))
2855
(element = (5, 11), container = (7,))
2856

2857
julia> stack(E) |> size
2858
(5, 11, 7)
2859

2860
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2861
true
2862

2863
julia> A == stack(E; dims=2)
2864
true
2865

2866
julia> M = (fill(10i+j, 2, 3) for i in 1:5, j in 1:7);
2867

2868
julia> (element = size(first(M)), container = size(M))
2869
(element = (2, 3), container = (5, 7))
2870

2871
julia> stack(M) |> size  # keeps all dimensions
2872
(2, 3, 5, 7)
2873

2874
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2875
(35, 2, 3)
2876

2877
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2878
(14, 15)
2879
```
2880
"""
2881
stack(iter; dims=:) = _stack(dims, iter)
254✔
2882

2883
"""
2884
    stack(f, args...; [dims])
2885

2886
Apply a function to each element of a collection, and `stack` the result.
2887
Or to several collections, [`zip`](@ref)ped together.
2888

2889
The function should return arrays (or tuples, or other iterators) all of the same size.
2890
These become slices of the result, each separated along `dims` (if given) or by default
2891
along the last dimensions.
2892

2893
See also [`mapslices`](@ref), [`eachcol`](@ref).
2894

2895
# Examples
2896
```jldoctest
2897
julia> stack(c -> (c, c-32), "julia")
2898
2×5 Matrix{Char}:
2899
 'j'  'u'  'l'  'i'  'a'
2900
 'J'  'U'  'L'  'I'  'A'
2901

2902
julia> stack(eachrow([1 2 3; 4 5 6]), (10, 100); dims=1) do row, n
2903
         vcat(row, row .* n, row ./ n)
2904
       end
2905
2×9 Matrix{Float64}:
2906
 1.0  2.0  3.0   10.0   20.0   30.0  0.1   0.2   0.3
2907
 4.0  5.0  6.0  400.0  500.0  600.0  0.04  0.05  0.06
2908
```
2909
"""
2910
stack(f, iter; dims=:) = _stack(dims, f(x) for x in iter)
12✔
2911
stack(f, xs, yzs...; dims=:) = _stack(dims, f(xy...) for xy in zip(xs, yzs...))
2✔
2912

2913
_stack(dims::Union{Integer, Colon}, iter) = _stack(dims, IteratorSize(iter), iter)
169✔
2914

2915
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2916

2917
function _stack(dims, ::Union{HasShape, HasLength}, iter)
33✔
2918
    S = @default_eltype iter
122✔
2919
    T = S != Union{} ? eltype(S) : Any  # Union{} occurs for e.g. stack(1,2), postpone the error
122✔
2920
    if isconcretetype(T)
122✔
2921
        _typed_stack(dims, T, S, iter)
109✔
2922
    else  # Need to look inside, but shouldn't run an expensive iterator twice:
2923
        array = iter isa Union{Tuple, AbstractArray} ? iter : collect(iter)
38✔
2924
        isempty(array) && return _empty_stack(dims, T, S, iter)
38✔
2925
        T2 = mapreduce(eltype, promote_type, array)
35✔
2926
        _typed_stack(dims, T2, eltype(array), array)
36✔
2927
    end
2928
end
2929

2930
function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
112✔
2931
    xit = iterate(A)
217✔
2932
    nothing === xit && return _empty_stack(:, T, S, A)
94✔
2933
    x1, _ = xit
94✔
2934
    ax1 = _iterator_axes(x1)
98✔
2935
    B = similar(_ensure_array(x1), T, ax1..., Aax...)
173✔
2936
    off = firstindex(B)
93✔
2937
    len = length(x1)
99✔
2938
    while xit !== nothing
2,563✔
2939
        x, state = xit
2,476✔
2940
        _stack_size_check(x, ax1)
4,654✔
2941
        copyto!(B, off, x)
3,564✔
2942
        off += len
2,470✔
2943
        xit = iterate(A, state)
3,737✔
2944
    end
2,470✔
2945
    B
87✔
2946
end
2947

2948
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2949
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2950
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2951

2952
# For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2953
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
48✔
2954
    _typed_stack(dims, T, S, IteratorSize(S), A)
2955
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasLength, A) where {T,S} =
13✔
2956
    _typed_stack(dims, T, S, HasShape{1}(), A)
2957
function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
1✔
2958
    if dims == N+1
27✔
2959
        _typed_stack(:, T, S, A, (_vec_axis(A),))
4✔
2960
    else
2961
        _dim_stack(dims, T, S, A)
23✔
2962
    end
2963
end
2964
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
2✔
2965
    _dim_stack(dims, T, S, A)
2966

2967
_vec_axis(A, ax=_iterator_axes(A)) = length(ax) == 1 ? only(ax) : OneTo(prod(length, ax; init=1))
50✔
2968

2969
@constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
25✔
2970
    xit = Iterators.peel(A)
48✔
2971
    nothing === xit && return _empty_stack(dims, T, S, A)
25✔
2972
    x1, xrest = xit
25✔
2973
    ax1 = _iterator_axes(x1)
25✔
2974
    N1 = length(ax1)+1
24✔
2975
    dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
27✔
2976

2977
    newaxis = _vec_axis(A)
21✔
2978
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
122✔
2979
    B = similar(_ensure_array(x1), T, outax...)
41✔
2980

2981
    if dims == 1
21✔
2982
        _dim_stack!(Val(1), B, x1, xrest)
13✔
2983
    elseif dims == 2
8✔
2984
        _dim_stack!(Val(2), B, x1, xrest)
4✔
2985
    else
2986
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
2987
    end
2988
    B
18✔
2989
end
2990

2991
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
21✔
2992
    before = ntuple(d -> Colon(), dims - 1)
29✔
2993
    after = ntuple(d -> Colon(), ndims(B) - dims)
42✔
2994

2995
    i = firstindex(B, dims)
21✔
2996
    copyto!(view(B, before..., i, after...), x1)
37✔
2997

2998
    for x in xrest
29✔
2999
        _stack_size_check(x, _iterator_axes(x1))
6,422✔
3000
        i += 1
3,261✔
3001
        @inbounds copyto!(view(B, before..., i, after...), x)
6,393✔
3002
    end
3,261✔
3003
end
3004

3005
@inline function _stack_size_check(x, ax1::Tuple)
26✔
3006
    if _iterator_axes(x) != ax1
11,107✔
3007
        uax1 = map(UnitRange, ax1)
9✔
3008
        uaxN = map(UnitRange, axes(x))
9✔
3009
        throw(DimensionMismatch(
9✔
3010
            LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
3011
    end
3012
end
3013

3014
_ensure_array(x::AbstractArray) = x
85✔
3015
_ensure_array(x) = 1:0  # passed to similar, makes stack's output an Array
29✔
3016

3017
_empty_stack(_...) = throw(ArgumentError("`stack` on an empty collection is not allowed"))
3✔
3018

3019

3020
## Reductions and accumulates ##
3021

3022
function isequal(A::AbstractArray, B::AbstractArray)
246,391✔
3023
    if A === B return true end
289,013✔
3024
    if axes(A) != axes(B)
574,446✔
3025
        return false
2,924✔
3026
    end
3027
    for (a, b) in zip(A, B)
570,945✔
3028
        if !isequal(a, b)
92,086,118✔
3029
            return false
727✔
3030
        end
3031
    end
183,722,470✔
3032
    return true
285,043✔
3033
end
3034

3035
function cmp(A::AbstractVector, B::AbstractVector)
45✔
3036
    for (a, b) in zip(A, B)
780✔
3037
        if !isequal(a, b)
949✔
3038
            return isless(a, b) ? -1 : 1
530✔
3039
        end
3040
    end
1,142✔
3041
    return cmp(length(A), length(B))
24✔
3042
end
3043

3044
"""
3045
    isless(A::AbstractVector, B::AbstractVector)
3046

3047
Return `true` when `A` is less than `B` in lexicographic order.
3048
"""
3049
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
515✔
3050

3051
function (==)(A::AbstractArray, B::AbstractArray)
6,553,058✔
3052
    if axes(A) != axes(B)
13,149,393✔
3053
        return false
3,943✔
3054
    end
3055
    anymissing = false
6,564,090✔
3056
    for (a, b) in zip(A, B)
12,258,520✔
3057
        eq = (a == b)
321,397,529✔
3058
        if ismissing(eq)
286,794,401✔
3059
            anymissing = true
24✔
3060
        elseif !eq
320,507,962✔
3061
            return false
2,964✔
3062
        end
3063
    end
635,327,198✔
3064
    return anymissing ? missing : true
6,569,796✔
3065
end
3066

3067
# _sub2ind and _ind2sub
3068
# fallbacks
3069
function _sub2ind(A::AbstractArray, I...)
287✔
3070
    @inline
265,743,449✔
3071
    _sub2ind(axes(A), I...)
281,695,625✔
3072
end
3073

3074
function _ind2sub(A::AbstractArray, ind)
3075
    @inline
447,320✔
3076
    _ind2sub(axes(A), ind)
447,320✔
3077
end
3078

3079
# 0-dimensional arrays and indexing with []
3080
_sub2ind(::Tuple{}) = 1
×
3081
_sub2ind(::DimsInteger) = 1
×
3082
_sub2ind(::Indices) = 1
×
3083
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
3✔
3084

3085
# Generic cases
3086
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
1,111,912✔
3087
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
281,813,528✔
3088
# In 1d, there's a question of whether we're doing cartesian indexing
3089
# or linear indexing. Support only the former.
3090
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
3091
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3092
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
3093
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
3094

3095
_sub2ind_recurse(::Any, L, ind) = ind
44,482✔
3096
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
364✔
3097
    @inline
1,159✔
3098
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
68,111✔
3099
end
3100
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
914✔
3101
    @inline
13,030,720✔
3102
    r1 = inds[1]
13,095,845✔
3103
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
576,515,949✔
3104
end
3105

3106
nextL(L, l::Integer) = L*l
500,695✔
3107
nextL(L, r::AbstractUnitRange) = L*length(r)
293,091,718✔
3108
nextL(L, r::Slice) = L*length(r.indices)
×
3109
offsetin(i, l::Integer) = i-1
1,547,359✔
3110
offsetin(i, r::AbstractUnitRange) = i-first(r)
574,830,646✔
3111

3112
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
3113
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
1✔
3114
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
447,317✔
3115
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
3116
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3117
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
63✔
3118

3119
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3120
function _ind2sub_recurse(indslast::NTuple{1}, ind)
3121
    @inline
447,318✔
3122
    (_lookup(ind, indslast[1]),)
447,318✔
3123
end
3124
function _ind2sub_recurse(inds, ind)
3125
    @inline
793,307✔
3126
    r1 = inds[1]
793,307✔
3127
    indnext, f, l = _div(ind, r1)
793,307✔
3128
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
793,307✔
3129
end
3130

3131
_lookup(ind, d::Integer) = ind+1
1✔
3132
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
447,317✔
3133
_div(ind, d::Integer) = div(ind, d), 1, d
1✔
3134
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
793,306✔
3135

3136
# Vectorized forms
3137
function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
×
3138
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
×
3139
end
3140
_sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3141
    _sub2ind_vecs(inds, I1, I...)
3142
_sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3143
    _sub2ind_vecs(inds, I1, I...)
3144
function _sub2ind_vecs(inds, I::AbstractVector...)
×
3145
    I1 = I[1]
×
3146
    Iinds = axes1(I1)
×
3147
    for j = 2:length(I)
×
3148
        axes1(I[j]) == Iinds || throw(DimensionMismatch("indices of I[1] ($(Iinds)) does not match indices of I[$j] ($(axes1(I[j])))"))
×
3149
    end
×
3150
    Iout = similar(I1)
×
3151
    _sub2ind!(Iout, inds, Iinds, I)
×
3152
    Iout
×
3153
end
3154

3155
function _sub2ind!(Iout, inds, Iinds, I)
×
3156
    @noinline
×
3157
    for i in Iinds
×
3158
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3159
        Iout[i] = sub2ind_vec(inds, i, I)
×
3160
    end
×
3161
    Iout
×
3162
end
3163

3164
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3165
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3166
_sub2ind_vec(i) = ()
×
3167

3168
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
×
3169
    M = length(ind)
×
3170
    t = ntuple(n->similar(ind),Val(N))
×
3171
    for (i,idx) in pairs(IndexLinear(), ind)
×
3172
        sub = _ind2sub(inds, idx)
×
3173
        for j = 1:N
×
3174
            t[j][i] = sub[j]
×
3175
        end
×
3176
    end
×
3177
    t
×
3178
end
3179

3180
## iteration utilities ##
3181

3182
"""
3183
    foreach(f, c...) -> Nothing
3184

3185
Call function `f` on each element of iterable `c`.
3186
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3187
any iterator is finished.
3188

3189
`foreach` should be used instead of [`map`](@ref) when the results of `f` are not
3190
needed, for example in `foreach(println, array)`.
3191

3192
# Examples
3193
```jldoctest
3194
julia> tri = 1:3:7; res = Int[];
3195

3196
julia> foreach(x -> push!(res, x^2), tri)
3197

3198
julia> res
3199
3-element Vector{$(Int)}:
3200
  1
3201
 16
3202
 49
3203

3204
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3205
1 with a
3206
4 with b
3207
7 with c
3208
```
3209
"""
3210
foreach(f, itr) = (for x in itr; f(x); end; nothing)
397,673,940✔
3211
foreach(f, itr, itrs...) = (for z in zip(itr, itrs...); f(z...); end; nothing)
1✔
3212

3213
## map over arrays ##
3214

3215
## transform any set of dimensions
3216
## dims specifies which dimensions will be transformed. for example
3217
## dims==1:2 will call f on all slices A[:,:,...]
3218
"""
3219
    mapslices(f, A; dims)
3220

3221
Transform the given dimensions of array `A` by applying a function `f` on each slice
3222
of the form `A[..., :, ..., :, ...]`, with a colon at each `d` in `dims`. The results are
3223
concatenated along the remaining dimensions.
3224

3225
For example, if `dims = [1,2]` and `A` is 4-dimensional, then `f` is called on `x = A[:,:,i,j]`
3226
for all `i` and `j`, and `f(x)` becomes `R[:,:,i,j]` in the result `R`.
3227

3228
See also [`eachcol`](@ref) or [`eachslice`](@ref), used with [`map`](@ref) or [`stack`](@ref).
3229

3230
# Examples
3231
```jldoctest
3232
julia> A = reshape(1:30,(2,5,3))
3233
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3234
[:, :, 1] =
3235
 1  3  5  7   9
3236
 2  4  6  8  10
3237

3238
[:, :, 2] =
3239
 11  13  15  17  19
3240
 12  14  16  18  20
3241

3242
[:, :, 3] =
3243
 21  23  25  27  29
3244
 22  24  26  28  30
3245

3246
julia> f(x::Matrix) = fill(x[1,1], 1,4);  # returns a 1×4 matrix
3247

3248
julia> B = mapslices(f, A, dims=(1,2))
3249
1×4×3 Array{$Int, 3}:
3250
[:, :, 1] =
3251
 1  1  1  1
3252

3253
[:, :, 2] =
3254
 11  11  11  11
3255

3256
[:, :, 3] =
3257
 21  21  21  21
3258

3259
julia> f2(x::AbstractMatrix) = fill(x[1,1], 1,4);
3260

3261
julia> B == stack(f2, eachslice(A, dims=3))
3262
true
3263

3264
julia> g(x) = x[begin] // x[end-1];  # returns a number
3265

3266
julia> mapslices(g, A, dims=[1,3])
3267
1×5×1 Array{Rational{$Int}, 3}:
3268
[:, :, 1] =
3269
 1//21  3//23  1//5  7//27  9//29
3270

3271
julia> map(g, eachslice(A, dims=2))
3272
5-element Vector{Rational{$Int}}:
3273
 1//21
3274
 3//23
3275
 1//5
3276
 7//27
3277
 9//29
3278

3279
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3280
true
3281
```
3282

3283
Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3284
one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3285
`mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3286
values in the slice without affecting `A`.
3287
"""
3288
function mapslices(f, A::AbstractArray; dims)
892✔
3289
    isempty(dims) && return map(f, A)
446✔
3290

3291
    for d in dims
566✔
3292
        d isa Integer || throw(ArgumentError("mapslices: dimension must be an integer, got $d"))
881✔
3293
        d >= 1 || throw(ArgumentError("mapslices: dimension must be ≥ 1, got $d"))
882✔
3294
        # Indexing a matrix M[:,1,:] produces a 1-column matrix, but dims=(1,3) here
3295
        # would otherwise ignore 3, and slice M[:,i]. Previously this gave error:
3296
        # BoundsError: attempt to access 2-element Vector{Any} at index [3]
3297
        d > ndims(A) && throw(ArgumentError("mapslices does not accept dimensions > ndims(A) = $(ndims(A)), got $d"))
880✔
3298
    end
884✔
3299
    dim_mask = ntuple(d -> d in dims, ndims(A))
1,986✔
3300

3301
    # Apply the function to the first slice in order to determine the next steps
3302
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
3,156✔
3303
    Aslice = A[idx1...]
537✔
3304
    r1 = f(Aslice)
529✔
3305

3306
    res1 = if r1 isa AbstractArray && ndims(r1) > 0
447✔
3307
        n = sum(dim_mask)
29✔
3308
        if ndims(r1) > n && any(ntuple(d -> size(r1,d+n)>1, ndims(r1)-n))
35✔
3309
            s = size(r1)[1:n]
1✔
3310
            throw(DimensionMismatch("mapslices cannot assign slice f(x) of size $(size(r1)) into output of size $s"))
1✔
3311
        end
3312
        r1
28✔
3313
    else
3314
        # If the result of f on a single slice is a scalar then we add singleton
3315
        # dimensions. When adding the dimensions, we have to respect the
3316
        # index type of the input array (e.g. in the case of OffsetArrays)
3317
        _res1 = similar(Aslice, typeof(r1), reduced_indices(Aslice, 1:ndims(Aslice)))
414✔
3318
        _res1[begin] = r1
414✔
3319
        _res1
813✔
3320
    end
3321

3322
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3323
    din = Ref(0)
442✔
3324
    Rsize = ntuple(ndims(A)) do d
451✔
3325
        if d in dims
3,232✔
3326
            axes(res1, din[] += 1)
875✔
3327
        else
3328
            axes(A,d)
805✔
3329
        end
3330
    end
3331
    R = similar(res1, Rsize)
465✔
3332

3333
    # Determine iteration space. It will be convenient in the loop to mask N-dimensional
3334
    # CartesianIndices, with some trivial dimensions:
3335
    itershape = ntuple(d -> d in dims ? Base.OneTo(1) : axes(A,d), ndims(A))
3,151✔
3336
    indices = Iterators.drop(CartesianIndices(itershape), 1)
442✔
3337

3338
    # That skips the first element, which we already have:
3339
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
2,941✔
3340
    concatenate_setindex!(R, res1, ridx...)
479✔
3341

3342
    # In some cases, we can re-use the first slice for a dramatic performance
3343
    # increase. The slice itself must be mutable and the result cannot contain
3344
    # any mutable containers. The following errs on the side of being overly
3345
    # strict (#18570 & #21123).
3346
    safe_for_reuse = isa(Aslice, StridedArray) &&
448✔
3347
                     (isa(r1, Number) || (isa(r1, AbstractArray) && eltype(r1) <: Number))
3348

3349
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
468✔
3350
    return R
442✔
3351
end
3352

3353
@noinline function _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
442✔
3354
    must_extend = any(dim_mask .& size(R) .> 1)
2,010✔
3355
    if safe_for_reuse
442✔
3356
        # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
3357
        # so we can reuse Aslice
3358
        for I in indices
754✔
3359
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
11,173✔
3360
            _unsafe_getindex!(Aslice, A, idx...)
11,173✔
3361
            r = f(Aslice)
16,808✔
3362
            if r isa AbstractArray || must_extend
11,173✔
3363
                ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
65✔
3364
                R[ridx...] = r
130✔
3365
            else
3366
                ridx = ifelse.(dim_mask, first.(axes(R)), Tuple(I))
11,108✔
3367
                R[ridx...] = r
11,108✔
3368
            end
3369
        end
11,173✔
3370
    else
3371
        # we can't guarantee safety (#18524), so allocate new storage for each slice
3372
        for I in indices
130✔
3373
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
1,857✔
3374
            ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
1,857✔
3375
            concatenate_setindex!(R, f(A[idx...]), ridx...)
3,714✔
3376
        end
1,857✔
3377
    end
3378
end
3379

3380
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
1,851✔
3381
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
472✔
3382

3383
## 1 argument
3384

3385
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3,093✔
3386
    for (i,j) in zip(eachindex(dest),eachindex(A))
632,299,302✔
3387
        val = f(@inbounds A[j])
532,606,138✔
3388
        @inbounds dest[i] = val
386,140,473✔
3389
    end
476,677,486✔
3390
    return dest
336,695,842✔
3391
end
3392

3393
# map on collections
3394
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
192,229✔
3395

3396
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
3,554✔
3397
mapany(f, itr) = Any[f(x) for x in itr]
×
3398

3399
"""
3400
    map(f, c...) -> collection
3401

3402
Transform collection `c` by applying `f` to each element. For multiple collection arguments,
3403
apply `f` elementwise, and stop when any of them is exhausted.
3404

3405
See also [`map!`](@ref), [`foreach`](@ref), [`mapreduce`](@ref), [`mapslices`](@ref), [`zip`](@ref), [`Iterators.map`](@ref).
3406

3407
# Examples
3408
```jldoctest
3409
julia> map(x -> x * 2, [1, 2, 3])
3410
3-element Vector{Int64}:
3411
 2
3412
 4
3413
 6
3414

3415
julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3416
3-element Vector{Int64}:
3417
 11
3418
 22
3419
 33
3420
```
3421
"""
3422
map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
441✔
3423

3424
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3425
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3426

3427
## 2 argument
3428
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
304✔
3429
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
715✔
3430
        @inbounds a, b = A[j], B[k]
338,192✔
3431
        val = f(a, b)
338,192✔
3432
        @inbounds dest[i] = val
338,192✔
3433
    end
676,033✔
3434
    return dest
364✔
3435
end
3436

3437
## N argument
3438

3439
@inline ith_all(i, ::Tuple{}) = ()
4,020✔
3440
function ith_all(i, as)
3441
    @_propagate_inbounds_meta
12,060✔
3442
    return (as[1][i], ith_all(i, tail(as))...)
12,060✔
3443
end
3444

3445
function map_n!(f::F, dest::AbstractArray, As) where F
45✔
3446
    idxs1 = LinearIndices(As[1])
45✔
3447
    @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
360✔
3448
    for i = idxs1
45✔
3449
        @inbounds I = ith_all(i, As)
4,020✔
3450
        val = f(I...)
4,020✔
3451
        @inbounds dest[i] = val
4,020✔
3452
    end
7,995✔
3453
    return dest
45✔
3454
end
3455

3456
"""
3457
    map!(function, destination, collection...)
3458

3459
Like [`map`](@ref), but stores the result in `destination` rather than a new
3460
collection. `destination` must be at least as large as the smallest collection.
3461

3462
$(_DOCS_ALIASING_WARNING)
3463

3464
See also: [`map`](@ref), [`foreach`](@ref), [`zip`](@ref), [`copyto!`](@ref).
3465

3466
# Examples
3467
```jldoctest
3468
julia> a = zeros(3);
3469

3470
julia> map!(x -> x * 2, a, [1, 2, 3]);
3471

3472
julia> a
3473
3-element Vector{Float64}:
3474
 2.0
3475
 4.0
3476
 6.0
3477

3478
julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3479
5-element Vector{$(Int)}:
3480
 101
3481
 103
3482
 105
3483
   0
3484
   0
3485
```
3486
"""
3487
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
43✔
3488
    isempty(As) && throw(ArgumentError(
46✔
3489
        """map! requires at least one "source" argument"""))
3490
    map_n!(f, dest, As)
45✔
3491
end
3492

3493
"""
3494
    map(f, A::AbstractArray...) -> N-array
3495

3496
When acting on multi-dimensional arrays of the same [`ndims`](@ref),
3497
they must all have the same [`axes`](@ref), and the answer will too.
3498

3499
See also [`broadcast`](@ref), which allows mismatched sizes.
3500

3501
# Examples
3502
```
3503
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3504
2×2 Matrix{Rational{$Int}}:
3505
 1//4  2//3
3506
 3//2  4//1
3507

3508
julia> map(+, [1 2; 3 4], zeros(2,1))
3509
ERROR: DimensionMismatch
3510

3511
julia> map(+, [1 2; 3 4], [1,10,100,1000], zeros(3,1))  # iterates until 3rd is exhausted
3512
3-element Vector{Float64}:
3513
   2.0
3514
  13.0
3515
 102.0
3516
```
3517
"""
3518
map(f, it, iters...) = collect(Generator(f, it, iters...))
1,256✔
3519

3520
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3521
# (note: must not cause a dispatch loop when 1-item case is not defined)
3522
push!(A, a, b) = push!(push!(A, a), b)
995✔
3523
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
2✔
3524
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
3525
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
2✔
3526

3527
## hashing AbstractArray ##
3528

3529
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3530
function hash(A::AbstractArray, h::UInt)
17,041✔
3531
    h += hash_abstractarray_seed
17,041✔
3532
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3533
    # Instead hash the tuple of firsts and lasts along each dimension
3534
    h = hash(map(first, axes(A)), h)
17,278✔
3535
    h = hash(map(last, axes(A)), h)
17,278✔
3536

3537
    # For short arrays, it's not worth doing anything complicated
3538
    if length(A) < 8192
17,278✔
3539
        for x in A
22,047✔
3540
            h = hash(x, h)
2,354,553✔
3541
        end
2,233,857✔
3542
        return h
17,037✔
3543
    end
3544

3545
    # Goal: Hash approximately log(N) entries with a higher density of hashed elements
3546
    # weighted towards the end and special consideration for repeated values. Colliding
3547
    # hashes will often subsequently be compared by equality -- and equality between arrays
3548
    # works elementwise forwards and is short-circuiting. This means that a collision
3549
    # between arrays that differ by elements at the beginning is cheaper than one where the
3550
    # difference is towards the end. Furthermore, choosing `log(N)` arbitrary entries from a
3551
    # sparse array will likely only choose the same element repeatedly (zero in this case).
3552

3553
    # To achieve this, we work backwards, starting by hashing the last element of the
3554
    # array. After hashing each element, we skip `fibskip` elements, where `fibskip`
3555
    # is pulled from the Fibonacci sequence -- Fibonacci was chosen as a simple
3556
    # ~O(log(N)) algorithm that ensures we don't hit a common divisor of a dimension
3557
    # and only end up hashing one slice of the array (as might happen with powers of
3558
    # two). Finally, we find the next distinct value from the one we just hashed.
3559

3560
    # This is a little tricky since skipping an integer number of values inherently works
3561
    # with linear indices, but `findprev` uses `keys`. Hoist out the conversion "maps":
3562
    ks = keys(A)
4✔
3563
    key_to_linear = LinearIndices(ks) # Index into this map to compute the linear index
4✔
3564
    linear_to_key = vec(ks)           # And vice-versa
4✔
3565

3566
    # Start at the last index
3567
    keyidx = last(ks)
4✔
3568
    linidx = key_to_linear[keyidx]
4✔
3569
    fibskip = prevfibskip = oneunit(linidx)
4✔
3570
    first_linear = first(LinearIndices(linear_to_key))
4✔
3571
    n = 0
4✔
3572
    while true
28,192✔
3573
        n += 1
28,192✔
3574
        # Hash the element
3575
        elt = A[keyidx]
28,192✔
3576
        h = hash(keyidx=>elt, h)
28,192✔
3577

3578
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3579
        linidx = key_to_linear[keyidx]
28,192✔
3580
        linidx < fibskip + first_linear && break
28,192✔
3581
        linidx -= fibskip
28,188✔
3582
        keyidx = linear_to_key[linidx]
28,188✔
3583

3584
        # Only increase the Fibonacci skip once every N iterations. This was chosen
3585
        # to be big enough that all elements of small arrays get hashed while
3586
        # obscenely large arrays are still tractable. With a choice of N=4096, an
3587
        # entirely-distinct 8000-element array will have ~75% of its elements hashed,
3588
        # with every other element hashed in the first half of the array. At the same
3589
        # time, hashing a `typemax(Int64)`-length Float64 range takes about a second.
3590
        if rem(n, 4096) == 0
28,188✔
3591
            fibskip, prevfibskip = fibskip + prevfibskip, fibskip
4✔
3592
        end
3593

3594
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3595
        keyidx = findprev(!isequal(elt), A, keyidx)
56,376✔
3596
        keyidx === nothing && break
28,188✔
3597
    end
28,188✔
3598

3599
    return h
4✔
3600
end
3601

3602
# The semantics of `collect` are weird. Better to write our own
3603
function rest(a::AbstractArray{T}, state...) where {T}
5✔
3604
    v = Vector{T}(undef, 0)
11✔
3605
    # assume only very few items are taken from the front
3606
    sizehint!(v, length(a))
11✔
3607
    return foldl(push!, Iterators.rest(a, state...), init=v)
11✔
3608
end
3609

3610

3611
## keepat! ##
3612

3613
# NOTE: since these use `@inbounds`, they are actually only intended for Vector and BitVector
3614

3615
function _keepat!(a::AbstractVector, inds)
7✔
3616
    local prev
11✔
3617
    i = firstindex(a)
11✔
3618
    for k in inds
17✔
3619
        if @isdefined(prev)
34✔
3620
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
27✔
3621
        end
3622
        ak = a[k] # must happen even when i==k for bounds checking
35✔
3623
        if i != k
29✔
3624
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
13✔
3625
        end
3626
        prev = k
29✔
3627
        i = nextind(a, i)
29✔
3628
    end
50✔
3629
    deleteat!(a, i:lastindex(a))
11✔
3630
    return a
6✔
3631
end
3632

3633
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
4✔
3634
    length(m) == length(a) || throw(BoundsError(a, m))
7✔
3635
    j = firstindex(a)
3✔
3636
    for i in eachindex(a, m)
3✔
3637
        @inbounds begin
20✔
3638
            if m[i]
20✔
3639
                i == j || (a[j] = a[i])
12✔
3640
                j = nextind(a, j)
6✔
3641
            end
3642
        end
3643
    end
38✔
3644
    deleteat!(a, j:lastindex(a))
3✔
3645
end
3646

3647
## 1-d circshift ##
3648
function circshift!(a::AbstractVector, shift::Integer)
1,123✔
3649
    n = length(a)
1,141✔
3650
    n == 0 && return a
1,141✔
3651
    shift = mod(shift, n)
2,278✔
3652
    shift == 0 && return a
1,139✔
3653
    l = lastindex(a)
749✔
3654
    reverse!(a, firstindex(a), l-shift)
749✔
3655
    reverse!(a, l-shift+1, lastindex(a))
749✔
3656
    reverse!(a)
749✔
3657
    return a
749✔
3658
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