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

JuliaLang / julia / #37662

25 Oct 2023 07:08AM UTC coverage: 87.999% (+1.5%) from 86.476%
#37662

push

local

web-flow
Improve efficiency of minimum/maximum(::Diagonal) (#30236)

```
julia> DM = Diagonal(rand(100));

julia> @btime minimum($DM);    # before
  27.987 μs (0 allocations: 0 bytes)

julia> @btime minimum($DM);    # after
  246.091 ns (0 allocations: 0 bytes)
```

8 of 8 new or added lines in 1 file covered. (100.0%)

74065 of 84166 relevant lines covered (88.0%)

12219725.89 hits per line

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

92.38
/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
50,827✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
3,222✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
5,336✔
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,598,970✔
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}
66,334,958✔
76
    @inline
66,334,954✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
66,368,484✔
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)
252,717,965✔
97
    @inline
106,359,534✔
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(A) = _any_tuple(x->Int(first(x))::Int != 1, false, axes(A)...)
543,760✔
111
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
133,049✔
112
# Use `_any_tuple` to avoid unneeded invoke.
113
# note: this could call `any` directly if the compiler can infer it
114
has_offset_axes(As...) = _any_tuple(has_offset_axes, false, As...)
338,226✔
115
has_offset_axes(::Colon) = false
1,094✔
116
has_offset_axes(::Array) = false
563,460✔
117

118
"""
119
    require_one_based_indexing(A::AbstractArray)
120
    require_one_based_indexing(A,B...)
121

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

125
!!! compat "Julia 1.2"
126
     This function requires at least Julia 1.2.
127
"""
128
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"))
1,345,595✔
129

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

137
"""
138
    keys(a::AbstractArray)
139

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

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

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

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

158
julia> keys([4 5; 6 7])
159
CartesianIndices((2, 2))
160
```
161
"""
162
keys(a::AbstractArray) = CartesianIndices(axes(a))
29,055✔
163
keys(a::AbstractVector) = LinearIndices(a)
62,472,047✔
164

165
"""
166
    keytype(T::Type{<:AbstractArray})
167
    keytype(A::AbstractArray)
168

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

173
# Examples
174
```jldoctest
175
julia> keytype([1, 2, 3]) == Int
176
true
177

178
julia> keytype([1 2; 3 4])
179
CartesianIndex{2}
180
```
181

182
!!! compat "Julia 1.2"
183
     For arrays, this function requires at least Julia 1.2.
184
"""
185
keytype(a::AbstractArray) = keytype(typeof(a))
21,555,815✔
186
keytype(::Type{Union{}}, slurp...) = eltype(Union{})
×
187

188
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
2✔
189
keytype(A::Type{<:AbstractVector}) = Int
21,555,815✔
190

191
valtype(a::AbstractArray) = valtype(typeof(a))
15✔
192
valtype(::Type{Union{}}, slurp...) = eltype(Union{})
×
193

194
"""
195
    valtype(T::Type{<:AbstractArray})
196
    valtype(A::AbstractArray)
197

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

201
# Examples
202
```jldoctest
203
julia> valtype(["one", "two", "three"])
204
String
205
```
206

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

212
prevind(::AbstractArray, i::Integer) = Int(i)-1
146,852✔
213
nextind(::AbstractArray, i::Integer) = Int(i)+1
253,887,217✔
214

215

216
"""
217
    eltype(type)
218

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

225
See also: [`keytype`](@ref), [`typeof`](@ref).
226

227
# Examples
228
```jldoctest
229
julia> eltype(fill(1f0, (2,2)))
230
Float32
231

232
julia> eltype(fill(0x1, (2,2)))
233
UInt8
234
```
235
"""
236
eltype(::Type) = Any
14,078✔
237
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
1✔
238
eltype(x) = eltype(typeof(x))
5,397,552✔
239
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
3,418,937✔
240

241
"""
242
    elsize(type)
243

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

248
# Examples
249
```jldoctest
250
julia> Base.elsize(rand(Float32, 10))
251
4
252
```
253
"""
254
elsize(A::AbstractArray) = elsize(typeof(A))
1,796,533✔
255

256
"""
257
    ndims(A::AbstractArray) -> Integer
258

259
Return the number of dimensions of `A`.
260

261
See also: [`size`](@ref), [`axes`](@ref).
262

263
# Examples
264
```jldoctest
265
julia> A = fill(1, (3,4,5));
266

267
julia> ndims(A)
268
3
269
```
270
"""
271
ndims(::AbstractArray{T,N}) where {T,N} = N
1,402,060✔
272
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N
61✔
273
ndims(::Type{Union{}}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
×
274

275
"""
276
    length(collection) -> Integer
277

278
Return the number of elements in the collection.
279

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

282
See also: [`size`](@ref), [`ndims`](@ref), [`eachindex`](@ref).
283

284
# Examples
285
```jldoctest
286
julia> length(1:5)
287
5
288

289
julia> length([1, 2, 3, 4])
290
4
291

292
julia> length([1 2; 3 4])
293
4
294
```
295
"""
296
length
297

298
"""
299
    length(A::AbstractArray)
300

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

303
# Examples
304
```jldoctest
305
julia> length([1, 2, 3, 4])
306
4
307

308
julia> length([1 2; 3 4])
309
4
310
```
311
"""
312
length(t::AbstractArray) = (@inline; prod(size(t)))
19,370,231✔
313

314
# `eachindex` is mostly an optimization of `keys`
315
eachindex(itrs...) = keys(itrs...)
276✔
316

317
# eachindex iterates over all indices. IndexCartesian definitions are later.
318
eachindex(A::AbstractVector) = (@inline(); axes1(A))
1,262,149,322✔
319

320

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

328
"""
329
    eachindex(A...)
330
    eachindex(::IndexStyle, A::AbstractArray...)
331

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

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

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

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

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

356
# Examples
357
```jldoctest
358
julia> A = [10 20; 30 40];
359

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

368
julia> for i in eachindex(view(A, 1:2, 1:1)) # Cartesian indexing
369
           println(i)
370
       end
371
CartesianIndex(1, 1)
372
CartesianIndex(2, 1)
373
```
374
"""
375
eachindex(A::AbstractArray) = (@inline(); eachindex(IndexStyle(A), A))
146,524✔
376

377
function eachindex(A::AbstractArray, B::AbstractArray)
37✔
378
    @inline
37✔
379
    eachindex(IndexStyle(A,B), A, B)
37✔
380
end
381
function eachindex(A::AbstractArray, B::AbstractArray...)
×
382
    @inline
×
383
    eachindex(IndexStyle(A,B...), A, B...)
×
384
end
385
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
18,667,654✔
386
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
2,147,483,647✔
387
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
34✔
388
    @inline
34✔
389
    indsA = eachindex(IndexLinear(), A)
34✔
390
    _all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
69✔
391
        throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
392
    indsA
33✔
393
end
394
function _all_match_first(f::F, inds, A, B...) where F<:Function
39✔
395
    @inline
39✔
396
    (inds == f(A)) & _all_match_first(f, inds, B...)
43✔
397
end
398
_all_match_first(f::F, inds) where F<:Function = true
39✔
399

400
# keys with an IndexStyle
401
keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...)
×
402

403
"""
404
    lastindex(collection) -> Integer
405
    lastindex(collection, d) -> Integer
406

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

409
The syntaxes `A[end]` and `A[end, end]` lower to `A[lastindex(A)]` and
410
`A[lastindex(A, 1), lastindex(A, 2)]`, respectively.
411

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

414
# Examples
415
```jldoctest
416
julia> lastindex([1,2,4])
417
3
418

419
julia> lastindex(rand(3,4,5), 2)
420
4
421
```
422
"""
423
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
1,982,679,687✔
424
lastindex(a, d) = (@inline; last(axes(a, d)))
4,704✔
425

426
"""
427
    firstindex(collection) -> Integer
428
    firstindex(collection, d) -> Integer
429

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

432
The syntaxes `A[begin]` and `A[1, begin]` lower to `A[firstindex(A)]` and
433
`A[1, firstindex(A, 2)]`, respectively.
434

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

437
# Examples
438
```jldoctest
439
julia> firstindex([1,2,4])
440
1
441

442
julia> firstindex(rand(3,4,5), 2)
443
1
444
```
445
"""
446
firstindex(a::AbstractArray) = (@inline; first(eachindex(IndexLinear(), a)))
23,479,086✔
447
firstindex(a, d) = (@inline; first(axes(a, d)))
2,701✔
448

449
first(a::AbstractArray) = a[first(eachindex(a))]
317,722✔
450

451
"""
452
    first(coll)
453

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

457
See also: [`only`](@ref), [`firstindex`](@ref), [`last`](@ref).
458

459
# Examples
460
```jldoctest
461
julia> first(2:2:10)
462
2
463

464
julia> first([1; 2; 3; 4])
465
1
466
```
467
"""
468
function first(itr)
59,027✔
469
    x = iterate(itr)
7,095,432✔
470
    x === nothing && throw(ArgumentError("collection must be non-empty"))
3,556,893✔
471
    x[1]
3,556,891✔
472
end
473

474
"""
475
    first(itr, n::Integer)
476

477
Get the first `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
478
long enough.
479

480
See also: [`startswith`](@ref), [`Iterators.take`](@ref).
481

482
!!! compat "Julia 1.6"
483
    This method requires at least Julia 1.6.
484

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

492
julia> first(1:6, 10)
493
1:6
494

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

506
"""
507
    last(coll)
508

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

513
See also [`first`](@ref), [`endswith`](@ref).
514

515
# Examples
516
```jldoctest
517
julia> last(1:2:10)
518
9
519

520
julia> last([1; 2; 3; 4])
521
4
522
```
523
"""
524
last(a) = a[end]
85,935,778✔
525

526
"""
527
    last(itr, n::Integer)
528

529
Get the last `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
530
long enough.
531

532
!!! compat "Julia 1.6"
533
    This method requires at least Julia 1.6.
534

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

542
julia> last(1:6, 10)
543
1:6
544

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

556
"""
557
    strides(A)
558

559
Return a tuple of the memory strides in each dimension.
560

561
See also: [`stride`](@ref).
562

563
# Examples
564
```jldoctest
565
julia> A = fill(1, (3,4,5));
566

567
julia> strides(A)
568
(1, 3, 12)
569
```
570
"""
571
function strides end
572

573
"""
574
    stride(A, k::Integer)
575

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

578
See also: [`strides`](@ref).
579

580
# Examples
581
```jldoctest
582
julia> A = fill(1, (3,4,5));
583

584
julia> stride(A,2)
585
3
586

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

603
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
412,134✔
604
size_to_strides(s, d) = (s,)
353,023✔
605
size_to_strides(s) = ()
×
606

607
function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
34✔
608
    @boundscheck checkbounds(A, I...)
37✔
609
    return true
31✔
610
end
611

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

633
## Bounds checking ##
634

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

649
"""
650
    checkbounds(Bool, A, I...)
651

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

657
See also [`checkindex`](@ref).
658

659
# Examples
660
```jldoctest
661
julia> A = rand(3, 3);
662

663
julia> checkbounds(Bool, A, 2)
664
true
665

666
julia> checkbounds(Bool, A, 3, 4)
667
false
668

669
julia> checkbounds(Bool, A, 1:3)
670
true
671

672
julia> checkbounds(Bool, A, 1:3, 2:4)
673
false
674
```
675
"""
676
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
109,603,265✔
677
    @inline
109,603,265✔
678
    checkbounds_indices(Bool, axes(A), I)
109,737,509✔
679
end
680

681
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index
682
function checkbounds(::Type{Bool}, A::AbstractArray, i)
397,809,089✔
683
    @inline
377,185,173✔
684
    checkindex(Bool, eachindex(IndexLinear(), A), i)
2,147,483,647✔
685
end
686
# As a special extension, allow using logical arrays that match the source array exactly
687
function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{Bool,N}) where N
88✔
688
    @inline
88✔
689
    axes(A) == axes(I)
143✔
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...)
1,200,788,061✔
698
    @inline
448,712,667✔
699
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
1,200,979,310✔
700
    nothing
1,200,977,537✔
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}, IA::Tuple, I::Tuple)
344,615,941✔
724
    @inline
165,906,177✔
725
    checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
345,070,267✔
726
end
727
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
15,801✔
728
    @inline
3,624✔
729
    checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
28,480✔
730
end
731
checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
577,883✔
732
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
×
733

734
throw_boundserror(A, I) = (@noinline; throw(BoundsError(A, I)))
751✔
735

736
# check along a single dimension
737
"""
738
    checkindex(Bool, inds::AbstractUnitRange, index)
739

740
Return `true` if the given `index` is within the bounds of
741
`inds`. Custom types that would like to behave as indices for all
742
arrays can extend this method in order to provide a specialized bounds
743
checking implementation.
744

745
See also [`checkbounds`](@ref).
746

747
# Examples
748
```jldoctest
749
julia> checkindex(Bool, 1:20, 8)
750
true
751

752
julia> checkindex(Bool, 1:20, 21)
753
false
754
```
755
"""
756
checkindex(::Type{Bool}, inds::AbstractUnitRange, i) =
×
757
    throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
758
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
55,968,891✔
759
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
9,618,163✔
760
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
2,147,483,647✔
761
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
231✔
762
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
89,910✔
763
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
9,151,646✔
764
    @_propagate_inbounds_meta
2,220,812✔
765
    isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
480,491,805✔
766
end
767
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractVector{Bool}) = indx == axes1(I)
2✔
768
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool}) = false
1✔
769
function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray)
12,955✔
770
    @inline
5,016✔
771
    b = true
5,016✔
772
    for i in I
20,836✔
773
        b &= checkindex(Bool, inds, i)
6,488,817✔
774
    end
6,534,071✔
775
    b
18,395✔
776
end
777

778
# See also specializations in multidimensional
779

780
## Constructors ##
781

782
# default arguments to similar()
783
"""
784
    similar(array, [element_type=eltype(array)], [dims=size(array)])
785

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

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

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

798
```julia-repl
799
julia> similar(1:10, 1, 4)
800
1×4 Matrix{Int64}:
801
 4419743872  4374413872  4419743888  0
802
```
803

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

807
```julia-repl
808
julia> similar(trues(10,10), 2)
809
2-element BitVector:
810
 0
811
 0
812
```
813

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

817
```julia-repl
818
julia> similar(falses(10), Float64, 2, 4)
819
2×4 Matrix{Float64}:
820
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
821
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
822
```
823

824
See also: [`undef`](@ref), [`isassigned`](@ref).
825
"""
826
similar(a::AbstractArray{T}) where {T}                             = similar(a, T)
4,854✔
827
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
4,485✔
828
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
67,564,333✔
829
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
822✔
830
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
6,157,653✔
831
# Similar supports specifying dims as either Integers or AbstractUnitRanges or any mixed combination
832
# thereof. Ideally, we'd just convert Integers to OneTos and then call a canonical method with the axes,
833
# but we don't want to require all AbstractArray subtypes to dispatch on Base.OneTo. So instead we
834
# define this method to convert supported axes to Ints, with the expectation that an offset array
835
# package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}}
836
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims))
138,662✔
837
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims))
5✔
838
# similar creates an Array by default
839
similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N}    = Array{T,N}(undef, dims)
6,140,532✔
840

841
to_shape(::Tuple{}) = ()
400✔
842
to_shape(dims::Dims) = dims
6,620✔
843
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
6,968,638✔
844
# each dimension
845
to_shape(i::Int) = i
139✔
846
to_shape(i::Integer) = Int(i)
86✔
847
to_shape(r::OneTo) = Int(last(r))
364,427✔
848
to_shape(r::AbstractUnitRange) = r
196✔
849

850
"""
851
    similar(storagetype, axes)
852

853
Create an uninitialized mutable array analogous to that specified by
854
`storagetype`, but with `axes` specified by the last
855
argument.
856

857
**Examples**:
858

859
    similar(Array{Int}, axes(A))
860

861
creates an array that "acts like" an `Array{Int}` (and might indeed be
862
backed by one), but which is indexed identically to `A`. If `A` has
863
conventional indexing, this will be identical to
864
`Array{Int}(undef, size(A))`, but if `A` has unconventional indexing then the
865
indices of the result will match `A`.
866

867
    similar(BitArray, (axes(A, 2),))
868

869
would create a 1-dimensional logical array whose indices match those
870
of the columns of `A`.
871
"""
872
similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
49✔
873
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
480,313,302✔
874
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
480,313,395✔
875

876
"""
877
    empty(v::AbstractVector, [eltype])
878

879
Create an empty vector similar to `v`, optionally changing the `eltype`.
880

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

883
# Examples
884

885
```jldoctest
886
julia> empty([1.0, 2.0, 3.0])
887
Float64[]
888

889
julia> empty([1.0, 2.0, 3.0], String)
890
String[]
891
```
892
"""
893
empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
336✔
894

895
# like empty, but should return a mutable collection, a Vector by default
896
emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
214✔
897
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
54✔
898

899
"""
900
    copy!(dst, src) -> dst
901

902
In-place [`copy`](@ref) of `src` into `dst`, discarding any pre-existing
903
elements in `dst`.
904
If `dst` and `src` are of the same type, `dst == src` should hold after
905
the call. If `dst` and `src` are multidimensional arrays, they must have
906
equal [`axes`](@ref).
907

908
See also [`copyto!`](@ref).
909

910
!!! compat "Julia 1.1"
911
    This method requires at least Julia 1.1. In Julia 1.0 this method
912
    is available from the `Future` standard library as `Future.copy!`.
913
"""
914
function copy!(dst::AbstractVector, src::AbstractVector)
73,783,744✔
915
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
47✔
916
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
917
    if length(dst) != length(src)
73,783,744✔
918
        resize!(dst, length(src))
73,783,691✔
919
    end
920
    copyto!(dst, src)
73,783,775✔
921
end
922

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

929
## from general iterable to any array
930

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

935
function copyto!(dest::AbstractArray, src)
4,190,844✔
936
    destiter = eachindex(dest)
4,203,420✔
937
    y = iterate(destiter)
5,528,200✔
938
    for x in src
6,796,111✔
939
        y === nothing &&
4,356,489✔
940
            throw(ArgumentError("destination has fewer elements than required"))
941
        dest[y[1]] = x
4,356,608✔
942
        y = iterate(destiter, y[2])
7,387,977✔
943
    end
6,867,728✔
944
    return dest
4,203,418✔
945
end
946

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

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

993
# this method must be separate from the above since src might not have a length
994
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
104,669✔
995
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
104,669✔
996
        ", elements, but n should be non-negative")))
997
    n == 0 && return dest
104,668✔
998
    dmax = dstart + n - 1
104,667✔
999
    inds = LinearIndices(dest)
104,667✔
1000
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
209,332✔
1001
        sstart < 1 && throw(ArgumentError(LazyString("source start offset (",
4✔
1002
            sstart,") is < 1")))
1003
        throw(BoundsError(dest, dstart:dmax))
3✔
1004
    end
1005
    y = iterate(src)
104,663✔
1006
    for j = 1:(sstart-1)
204,961✔
1007
        if y === nothing
2,147,483,647✔
1008
            throw(ArgumentError(LazyString(
1✔
1009
                "source has fewer elements than required, ",
1010
                "expected at least ",sstart,", got ",j-1)))
1011
        end
1012
        y = iterate(src, y[2])
2,147,483,647✔
1013
    end
2,147,483,647✔
1014
    i = Int(dstart)
104,662✔
1015
    while i <= dmax && y !== nothing
9,120,538✔
1016
        val, st = y
9,015,876✔
1017
        @inbounds dest[i] = val
9,015,876✔
1018
        y = iterate(src, st)
9,020,240✔
1019
        i += 1
9,015,876✔
1020
    end
9,015,876✔
1021
    i <= dmax && throw(BoundsError(dest, i))
104,662✔
1022
    return dest
104,661✔
1023
end
1024

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

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

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

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

1037
# Examples
1038
```jldoctest
1039
julia> x = [1., 0., 3., 0., 5.];
1040

1041
julia> y = zeros(7);
1042

1043
julia> copyto!(y, x);
1044

1045
julia> y
1046
7-element Vector{Float64}:
1047
 1.0
1048
 0.0
1049
 3.0
1050
 0.0
1051
 5.0
1052
 0.0
1053
 0.0
1054
```
1055
"""
1056
function copyto!(dest::AbstractArray, src::AbstractArray)
2,738,930✔
1057
    isempty(src) && return dest
2,935,284✔
1058
    if dest isa BitArray
2,600,848✔
1059
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1060
        return _copyto_bitarray!(dest, src)
1✔
1061
    end
1062
    src′ = unalias(dest, src)
2,954,863✔
1063
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,934,840✔
1064
end
1065

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

1072
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
2,930,225✔
1073
    isempty(src) && return dest
2,930,451✔
1074
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,930,452✔
1075
    idf, isf = first(destinds), first(srcinds)
2,596,308✔
1076
    Δi = idf - isf
2,596,308✔
1077
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,930,452✔
1078
        throw(BoundsError(dest, srcinds))
1079
    if deststyle isa IndexLinear
2,596,307✔
1080
        if srcstyle isa IndexLinear
2,593,091✔
1081
            # Single-index implementation
1082
            @inbounds for i in srcinds
5,317,504✔
1083
                if isassigned(src, i)
36,807,992✔
1084
                    dest[i + Δi] = src[i]
36,812,974✔
1085
                else
1086
                    _unsetindex!(dest, i + Δi)
×
1087
                end
1088
            end
70,957,230✔
1089
        else
1090
            # Dual-index implementation
1091
            i = idf - 1
106,619✔
1092
            @inbounds for a in eachindex(src)
536,915✔
1093
                i += 1
3,193,548✔
1094
                if isassigned(src, a)
3,197,916✔
1095
                    dest[i] = src[a]
3,500,155✔
1096
                else
1097
                    _unsetindex!(dest, i)
×
1098
                end
1099
            end
3,721,230✔
1100
        end
1101
    else
1102
        iterdest, itersrc = eachindex(dest), eachindex(src)
3,216✔
1103
        if iterdest == itersrc
3,216✔
1104
            # Shared-iterator implementation
1105
            for I in iterdest
630✔
1106
                if isassigned(src, I)
6,015,618✔
1107
                    @inbounds dest[I] = src[I]
6,015,832✔
1108
                else
1109
                    _unsetindex!(dest, I)
×
1110
                end
1111
            end
12,017,257✔
1112
        else
1113
            # Dual-iterator implementation
1114
            ret = iterate(iterdest)
5,802✔
1115
            @inbounds for a in itersrc
5,802✔
1116
                idx, state = ret::NTuple{2,Any}
2,032,795✔
1117
                if isassigned(src, a)
2,032,795✔
1118
                    dest[idx] = src[a]
2,032,795✔
1119
                else
1120
                    _unsetindex!(dest, idx)
×
1121
                end
1122
                ret = iterate(iterdest, state)
2,035,697✔
1123
            end
4,062,686✔
1124
        end
1125
    end
1126
    return dest
2,930,450✔
1127
end
1128

1129
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
20,498✔
1130
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
21,610✔
1131
end
1132

1133
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray, sstart::Integer)
22✔
1134
    srcinds = LinearIndices(src)
22✔
1135
    checkbounds(Bool, srcinds, sstart) || throw(BoundsError(src, sstart))
31✔
1136
    copyto!(dest, dstart, src, sstart, last(srcinds)-sstart+1)
13✔
1137
end
1138

1139
function copyto!(dest::AbstractArray, dstart::Integer,
785,970✔
1140
                 src::AbstractArray, sstart::Integer,
1141
                 n::Integer)
1142
    n == 0 && return dest
785,970✔
1143
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
785,968✔
1144
        n," elements, but n should be non-negative")))
1145
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
785,967✔
1146
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
785,979✔
1147
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
785,958✔
1148
    src′ = unalias(dest, src)
786,827✔
1149
    @inbounds for i = 0:n-1
1,571,904✔
1150
        if isassigned(src′, sstart+i)
40,033,999✔
1151
            dest[dstart+i] = src′[sstart+i]
40,033,999✔
1152
        else
1153
            _unsetindex!(dest, dstart+i)
×
1154
        end
1155
    end
79,282,046✔
1156
    return dest
785,952✔
1157
end
1158

1159
function copy(a::AbstractArray)
146,957✔
1160
    @_propagate_inbounds_meta
613✔
1161
    copymutable(a)
149,725✔
1162
end
1163

1164
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
3,185✔
1165
                 A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1166
    if length(ir_dest) != length(ir_src)
3,185✔
1167
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1168
            length(ir_src)," and ",length(ir_dest),")")))
1169
    end
1170
    if length(jr_dest) != length(jr_src)
3,184✔
1171
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1172
            length(jr_src)," and ",length(jr_dest),")")))
1173
    end
1174
    @boundscheck checkbounds(B, ir_dest, jr_dest)
3,184✔
1175
    @boundscheck checkbounds(A, ir_src, jr_src)
3,184✔
1176
    A′ = unalias(B, A)
6,127✔
1177
    jdest = first(jr_dest)
3,184✔
1178
    for jsrc in jr_src
6,368✔
1179
        idest = first(ir_dest)
19,478✔
1180
        for isrc in ir_src
38,956✔
1181
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
144,946✔
1182
            idest += step(ir_dest)
141,762✔
1183
        end
264,046✔
1184
        jdest += step(jr_dest)
19,478✔
1185
    end
35,772✔
1186
    return B
3,184✔
1187
end
1188

1189
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
207,808✔
1190

1191
function copyto_axcheck!(dest, src)
23,310✔
1192
    _checkaxs(axes(dest), axes(src))
186,356✔
1193
    copyto!(dest, src)
359,615✔
1194
end
1195

1196
"""
1197
    copymutable(a)
1198

1199
Make a mutable copy of an array or iterable `a`.  For `a::Array`,
1200
this is equivalent to `copy(a)`, but for other array types it may
1201
differ depending on the type of `similar(a)`.  For generic iterables
1202
this is equivalent to `collect(a)`.
1203

1204
# Examples
1205
```jldoctest
1206
julia> tup = (1, 2, 3)
1207
(1, 2, 3)
1208

1209
julia> Base.copymutable(tup)
1210
3-element Vector{Int64}:
1211
 1
1212
 2
1213
 3
1214
```
1215
"""
1216
function copymutable(a::AbstractArray)
4,304✔
1217
    @_propagate_inbounds_meta
3,377✔
1218
    copyto!(similar(a), a)
163,610✔
1219
end
1220
copymutable(itr) = collect(itr)
74✔
1221

1222
zero(x::AbstractArray{T}) where {T} = fill!(similar(x, typeof(zero(T))), zero(T))
16,650✔
1223

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

1227
# While the definitions for IndexLinear are all simple enough to inline on their
1228
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1229
# inlining.
1230
function iterate(A::AbstractArray, state=(eachindex(A),))
105,891,602✔
1231
    y = iterate(state...)
129,175,866✔
1232
    y === nothing && return nothing
108,002,925✔
1233
    A[y[1]], (state[1], tail(y)...)
107,509,477✔
1234
end
1235

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

1238

1239
## range conversions ##
1240

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

1248
## unsafe/pointer conversions ##
1249

1250
# note: the following type definitions don't mean any AbstractArray is convertible to
1251
# a data Ref. they just map the array element type to the pointer type for
1252
# convenience in cases that work.
1253
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, cconvert(Ptr{T}, x))
514,647,148✔
1254
function pointer(x::AbstractArray{T}, i::Integer) where T
9,315,960✔
1255
    @inline
5,453,951✔
1256
    pointer(x) + Int(_memory_offset(x, i))::Int
457,753,774✔
1257
end
1258

1259
# The distance from pointer(x) to the element at x[I...] in bytes
1260
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
181,021,557✔
1261
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
100,104✔
1262
    J = _to_subscript_indices(x, I...)
100,104✔
1263
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
375,985✔
1264
end
1265

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

1278
Return a subset of array `A` as specified by `inds`, where each `ind` may be,
1279
for example, an `Int`, an [`AbstractRange`](@ref), or a [`Vector`](@ref).
1280

1281
When `inds` selects multiple elements, this function returns a newly
1282
allocated array. To index multiple elements without making a copy,
1283
use [`view`](@ref) instead.
1284

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

1287
# Examples
1288
```jldoctest
1289
julia> A = [1 2; 3 4]
1290
2×2 Matrix{Int64}:
1291
 1  2
1292
 3  4
1293

1294
julia> getindex(A, 1)
1295
1
1296

1297
julia> getindex(A, [2, 1])
1298
2-element Vector{Int64}:
1299
 3
1300
 1
1301

1302
julia> getindex(A, 2:4)
1303
3-element Vector{Int64}:
1304
 3
1305
 2
1306
 4
1307
```
1308
"""
1309
function getindex(A::AbstractArray, I...)
135,182,990✔
1310
    @_propagate_inbounds_meta
129,890,837✔
1311
    error_if_canonical_getindex(IndexStyle(A), A, I...)
129,890,837✔
1312
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
263,336,045✔
1313
end
1314
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1315
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
263,321,290✔
1316

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

1319
struct CanonicalIndexError <: Exception
1320
    func::String
1321
    type::Any
1322
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
14✔
1323
end
1324

1325
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
2✔
1326
    throw(CanonicalIndexError("getindex", typeof(A)))
1327
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
3✔
1328
    throw(CanonicalIndexError("getindex", typeof(A)))
1329
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
129,890,832✔
1330

1331
## Internal definitions
1332
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1333
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1334

1335
## IndexLinear Scalar indexing: canonical method is one Int
1336
_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)
39,688,189✔
1337
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
51✔
1338
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
2,257,896✔
1339
    @inline
2,257,896✔
1340
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
42,461,914✔
1341
    @inbounds r = getindex(A, _to_linear_index(A, I...))
42,461,853✔
1342
    r
42,461,828✔
1343
end
1344
_to_linear_index(A::AbstractArray, i::Integer) = i
187,880✔
1345
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
1,768,081✔
1346
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
324,779✔
1347
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
2,549,720✔
1348

1349
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1350
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
310,164✔
1351
    @inline
310,164✔
1352
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
310,237✔
1353
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
319,247✔
1354
    r
310,090✔
1355
end
1356
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
93,087,886✔
1357
    @_propagate_inbounds_meta
93,087,886✔
1358
    getindex(A, I...)
180,345,660✔
1359
end
1360
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
382,602✔
1361
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1362
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1363
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
417✔
1364
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1365
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1,843✔
1366
    @inline
1,843✔
1367
    J, Jrem = IteratorsMD.split(I, Val(N))
1,843✔
1368
    _to_subscript_indices(A, J, Jrem)
1,843✔
1369
end
1370
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1371
    __to_subscript_indices(A, axes(A), J, Jrem)
1372
function __to_subscript_indices(A::AbstractArray,
2✔
1373
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1374
    @inline
2✔
1375
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1376
end
1377
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
1,841✔
1378
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
29,012✔
1379
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1380
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1381
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1382
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
382,602✔
1383

1384
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1385
# function that allows dispatch on array storage
1386

1387
"""
1388
    setindex!(A, X, inds...)
1389
    A[inds...] = X
1390

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

1394
# Examples
1395
```jldoctest
1396
julia> A = zeros(2,2);
1397

1398
julia> setindex!(A, [10, 20], [1, 2]);
1399

1400
julia> A[[3, 4]] = [30, 40];
1401

1402
julia> A
1403
2×2 Matrix{Float64}:
1404
 10.0  30.0
1405
 20.0  40.0
1406
```
1407
"""
1408
function setindex!(A::AbstractArray, v, I...)
2,778,202✔
1409
    @_propagate_inbounds_meta
2,778,202✔
1410
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,778,202✔
1411
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
3,359,325✔
1412
end
1413
function unsafe_setindex!(A::AbstractArray, v, I...)
732✔
1414
    @inline
732✔
1415
    @inbounds r = setindex!(A, v, I...)
732✔
1416
    r
730✔
1417
end
1418

1419
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
7✔
1420
    throw(CanonicalIndexError("setindex!", typeof(A)))
1421
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
2✔
1422
    throw(CanonicalIndexError("setindex!", typeof(A)))
1423
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
2,778,193✔
1424

1425
## Internal definitions
1426
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1427
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1428

1429
## IndexLinear Scalar indexing
1430
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
661,181✔
1431
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
164,107✔
1432
    @inline
164,107✔
1433
    @boundscheck checkbounds(A, I...)
261,590✔
1434
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
261,553✔
1435
    r
261,552✔
1436
end
1437

1438
# IndexCartesian Scalar indexing
1439
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
2,222,793✔
1440
    @_propagate_inbounds_meta
2,222,793✔
1441
    setindex!(A, v, I...)
2,222,892✔
1442
end
1443
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
918✔
1444
    @inline
918✔
1445
    @boundscheck checkbounds(A, I...)
923✔
1446
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
913✔
1447
    r
913✔
1448
end
1449

1450
"""
1451
    parent(A)
1452

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

1458
# Examples
1459
```jldoctest
1460
julia> A = [1 2; 3 4]
1461
2×2 Matrix{Int64}:
1462
 1  2
1463
 3  4
1464

1465
julia> V = view(A, 1:2, :)
1466
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1467
 1  2
1468
 3  4
1469

1470
julia> parent(V)
1471
2×2 Matrix{Int64}:
1472
 1  2
1473
 3  4
1474
```
1475
"""
1476
function parent end
1477

1478
parent(a::AbstractArray) = a
1,791✔
1479

1480
## rudimentary aliasing detection ##
1481
"""
1482
    Base.unalias(dest, A)
1483

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

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

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

1494
See also [`Base.mightalias`](@ref).
1495
"""
1496
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
9,162,350✔
1497
unalias(dest, A::AbstractRange) = A
24,324,943✔
1498
unalias(dest, A) = A
2,599,537✔
1499

1500
"""
1501
    Base.unaliascopy(A)
1502

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

1506
This must return an object of the same type as `A` to preserve optimal performance in the
1507
much more common case where aliasing does not occur. By default,
1508
`unaliascopy(A::AbstractArray)` will attempt to use [`copy(A)`](@ref), but in cases where
1509
`copy(A)` is not a `typeof(A)`, then the array should provide a custom implementation of
1510
`Base.unaliascopy(A)`.
1511
"""
1512
unaliascopy(A::Array) = copy(A)
446✔
1513
unaliascopy(A::AbstractArray)::typeof(A) = (@noinline; _unaliascopy(A, copy(A)))
4✔
1514
_unaliascopy(A::T, C::T) where {T} = C
4✔
1515
_unaliascopy(A, C) = throw(ArgumentError("""
×
1516
    an array of type `$(typename(typeof(A)).wrapper)` shares memory with another argument
1517
    and must make a preventative copy of itself in order to maintain consistent semantics,
1518
    but `copy(::$(typeof(A)))` returns a new array of type `$(typeof(C))`.
1519
    To fix, implement:
1520
        `Base.unaliascopy(A::$(typename(typeof(A)).wrapper))::typeof(A)`"""))
1521
unaliascopy(A) = A
×
1522

1523
"""
1524
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1525

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

1528
By default, this simply checks if either of the arrays reference the same memory
1529
regions, as identified by their [`Base.dataids`](@ref).
1530
"""
1531
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !isempty(A) && !isempty(B) && !_isdisjoint(dataids(A), dataids(B))
6,421,730✔
1532
mightalias(x, y) = false
×
1533

1534
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1535
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1536
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1537
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
11✔
1538
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
6,218,587✔
1539
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
62,381✔
1540
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1541
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
5,449✔
1542
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
72,895✔
1543

1544
"""
1545
    Base.dataids(A::AbstractArray)
1546

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

1549
Custom arrays that would like to opt-in to aliasing detection of their component
1550
parts can specialize this method to return the concatenation of the `dataids` of
1551
their component parts.  A typical definition for an array that wraps a parent is
1552
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1553
"""
1554
dataids(A::AbstractArray) = (UInt(objectid(A)),)
474,810✔
1555
dataids(A::Array) = (UInt(pointer(A)),)
12,061,295✔
1556
dataids(::AbstractRange) = ()
2,514,430✔
1557
dataids(x) = ()
6,855✔
1558

1559
## get (getindex with a default value) ##
1560

1561
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1562
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1563

1564
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
11✔
1565
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
8✔
1566
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
16✔
1567
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
4✔
1568
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
7✔
1569
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
9✔
1570

1571
function get!(X::AbstractVector{T}, A::AbstractVector, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
×
1572
    # 1d is not linear indexing
1573
    ind = findall(in(axes1(A)), I)
×
1574
    X[ind] = A[I[ind]]
×
1575
    Xind = axes1(X)
×
1576
    X[first(Xind):first(ind)-1] = default
×
1577
    X[last(ind)+1:last(Xind)] = default
×
1578
    X
×
1579
end
1580
function get!(X::AbstractArray{T}, A::AbstractArray, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
1✔
1581
    # Linear indexing
1582
    ind = findall(in(1:length(A)), I)
1✔
1583
    X[ind] = A[I[ind]]
5✔
1584
    fill!(view(X, 1:first(ind)-1), default)
6✔
1585
    fill!(view(X, last(ind)+1:length(X)), default)
1✔
1586
    X
1✔
1587
end
1588

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

1591
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
2✔
1592
    fill!(X, default)
72✔
1593
    dst, src = indcopy(size(A), I)
2✔
1594
    X[dst...] = A[src...]
2✔
1595
    X
2✔
1596
end
1597

1598
get(A::AbstractArray, I::RangeVecIntList, default) =
2✔
1599
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1600

1601
## structured matrix methods ##
1602
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
23,924✔
1603
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
5,658✔
1604

1605
## Concatenation ##
1606
eltypeof(x) = typeof(x)
21,332✔
1607
eltypeof(x::AbstractArray) = eltype(x)
1,264✔
1608

1609
promote_eltypeof() = error()
×
1610
promote_eltypeof(v1) = eltypeof(v1)
583✔
1611
promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...))
21,912✔
1612
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
136✔
1613
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
7,540✔
1614

1615
promote_eltype() = error()
×
1616
promote_eltype(v1) = eltype(v1)
129✔
1617
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
2,015✔
1618
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
11,693✔
1619
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
3,008✔
1620

1621
#TODO: ERROR CHECK
1622
_cat(catdim::Int) = Vector{Any}()
1✔
1623

1624
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1625
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1626

1627
## cat: special cases
1628
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
289✔
1629
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
175✔
1630
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
96✔
1631
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
442✔
1632

1633
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
31✔
1634
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
57✔
1635
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
10✔
1636
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
61✔
1637

1638
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
4✔
1639
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
6✔
1640

1641
# FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1642
# and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1643
# but that solution currently fails (see #27188 and #27224)
1644
AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1645

1646
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
793,195✔
1647
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
823,487✔
1648
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1649

1650
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
793,195✔
1651
    pos = 1
793,193✔
1652
    for k=1:Int(length(V))::Int
793,207✔
1653
        Vk = V[k]
795,207✔
1654
        p1 = pos + Int(length(Vk))::Int - 1
795,716✔
1655
        a[pos:p1] = Vk
5,721,235✔
1656
        pos = p1+1
795,207✔
1657
    end
797,219✔
1658
    a
793,195✔
1659
end
1660

1661
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
1,014✔
1662

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

1670

1671
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
299✔
1672
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
272✔
1673

1674
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
1,020✔
1675
    nargs = length(A)
1,020✔
1676
    nrows = size(A[1], 1)
1,021✔
1677
    ncols = 0
1,020✔
1678
    dense = true
1,020✔
1679
    for j = 1:nargs
1,026✔
1680
        Aj = A[j]
2,090✔
1681
        if size(Aj, 1) != nrows
2,858✔
1682
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1683
        end
1684
        dense &= isa(Aj,Array)
2,089✔
1685
        nd = ndims(Aj)
2,854✔
1686
        ncols += (nd==2 ? size(Aj,2) : 1)
2,570✔
1687
    end
3,159✔
1688
    B = similar(A[1], T, nrows, ncols)
1,019✔
1689
    pos = 1
1,019✔
1690
    if dense
1,019✔
1691
        for k=1:nargs
408✔
1692
            Ak = A[k]
836✔
1693
            n = length(Ak)
1,060✔
1694
            copyto!(B, pos, Ak, 1, n)
1,416✔
1695
            pos += n
836✔
1696
        end
1,266✔
1697
    else
1698
        for k=1:nargs
617✔
1699
            Ak = A[k]
1,252✔
1700
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
1,525✔
1701
            B[:, pos:p1] = Ak
1,630✔
1702
            pos = p1+1
1,252✔
1703
        end
1,755✔
1704
    end
1705
    return B
1,019✔
1706
end
1707

1708
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
67✔
1709
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
206✔
1710

1711
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
493✔
1712
    nargs = length(A)
493✔
1713
    nrows = sum(a->size(a, 1), A)::Int
1,605✔
1714
    ncols = size(A[1], 2)
493✔
1715
    for j = 2:nargs
494✔
1716
        if size(A[j], 2) != ncols
587✔
1717
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1718
        end
1719
    end
660✔
1720
    B = similar(A[1], T, nrows, ncols)
492✔
1721
    pos = 1
492✔
1722
    for k=1:nargs
493✔
1723
        Ak = A[k]
1,060✔
1724
        p1 = pos+size(Ak,1)::Int-1
1,233✔
1725
        B[pos:p1, :] = Ak
1,106✔
1726
        pos = p1+1
1,060✔
1727
    end
1,628✔
1728
    return B
492✔
1729
end
1730

1731
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
815,877✔
1732

1733
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1734
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1735

1736
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1737
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1738

1739
## cat: general case
1740

1741
# helper functions
1742
cat_size(A) = (1,)
22,372✔
1743
cat_size(A::AbstractArray) = size(A)
15,746✔
1744
cat_size(A, d) = 1
22,785✔
1745
cat_size(A::AbstractArray, d) = size(A, d)
23,814✔
1746

1747
cat_length(::Any) = 1
100✔
1748
cat_length(a::AbstractArray) = length(a)
472✔
1749

1750
cat_ndims(a) = 0
183✔
1751
cat_ndims(a::AbstractArray) = ndims(a)
684✔
1752

1753
cat_indices(A, d) = OneTo(1)
22,373✔
1754
cat_indices(A::AbstractArray, d) = axes(A, d)
17,217✔
1755

1756
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
7,361✔
1757
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1758
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,179✔
1759
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1760
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
471✔
1761
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
2✔
1762

1763
# These are for backwards compatibility (even though internal)
1764
cat_shape(dims, shape::Tuple{Vararg{Int}}) = shape
×
1765
function cat_shape(dims, shapes::Tuple)
4✔
1766
    out_shape = ()
4✔
1767
    for s in shapes
4✔
1768
        out_shape = _cshp(1, dims, out_shape, s)
18✔
1769
    end
15✔
1770
    return out_shape
4✔
1771
end
1772
# The new way to compute the shape (more inferable than combining cat_size & cat_shape, due to Varargs + issue#36454)
1773
cat_size_shape(dims) = ntuple(zero, Val(length(dims)))
×
1774
@inline cat_size_shape(dims, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, (), cat_size(X)), tail...)
9,090✔
1775
_cat_size_shape(dims, shape) = shape
1,434✔
1776
@inline _cat_size_shape(dims, shape, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, shape, cat_size(X)), tail...)
29,193✔
1777

1778
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1779
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
20✔
1780
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
497✔
1781
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
760✔
1782
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1783
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
3,024✔
1784
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1785
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
21✔
1786
    _cs(ndim, shape[1], 1)
23✔
1787
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
19✔
1788
end
1789
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
158✔
1790
    next = _cs(ndim, shape[1], nshape[1])
158✔
1791
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
158✔
1792
end
1793
@inline function _cshp(ndim::Int, dims, shape, nshape)
30,050✔
1794
    a = shape[1]
29,991✔
1795
    b = nshape[1]
29,991✔
1796
    next = dims[1] ? a + b : _cs(ndim, a, b)
30,434✔
1797
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
30,080✔
1798
end
1799

1800
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,061✔
1801
    "mismatch in dimension $d (expected $a got $b)")))
1802

1803
dims2cat(::Val{dims}) where dims = dims2cat(dims)
8,183✔
1804
function dims2cat(dims)
8,982✔
1805
    if any(≤(0), dims)
10,537✔
1806
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1807
    end
1808
    ntuple(in(dims), maximum(dims))
9,022✔
1809
end
1810

1811
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
8,052✔
1812

1813
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
8,987✔
1814
    catdims = dims2cat(dims)
9,025✔
1815
    shape = cat_size_shape(catdims, X...)
9,090✔
1816
    A = cat_similar(X[1], T, shape)
8,981✔
1817
    if count(!iszero, catdims)::Int > 1
8,981✔
1818
        fill!(A, zero(T))
771✔
1819
    end
1820
    return __cat(A, shape, catdims, X...)
9,511✔
1821
end
1822
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1823
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1824
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1825

1826
# Why isn't this called `__cat!`?
1827
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
9,515✔
1828

1829
function __cat_offset!(A, shape, catdims, offsets, x, X...)
38,143✔
1830
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1831
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
38,675✔
1832
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
38,143✔
1833
end
1834
__cat_offset!(A, shape, catdims, offsets) = A
8,983✔
1835

1836
function __cat_offset1!(A, shape, catdims, offsets, x)
38,143✔
1837
    inds = ntuple(length(offsets)) do i
38,294✔
1838
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
41,732✔
1839
    end
1840
    _copy_or_fill!(A, inds, x)
130,507✔
1841
    newoffsets = ntuple(length(offsets)) do i
38,142✔
1842
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
42,764✔
1843
    end
1844
    return newoffsets
38,142✔
1845
end
1846

1847
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
23,248✔
1848
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
107,223✔
1849

1850
"""
1851
    vcat(A...)
1852

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

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

1859
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1860

1861
# Examples
1862
```jldoctest
1863
julia> v = vcat([1,2], [3,4])
1864
4-element Vector{Int64}:
1865
 1
1866
 2
1867
 3
1868
 4
1869

1870
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1871
true
1872

1873
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1874
true
1875

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

1879
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1880
3-element Vector{Float64}:
1881
 1.0
1882
 1.5
1883
 2.0
1884

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

1888
julia> vcat(two...)
1889
3×3 Matrix{Float64}:
1890
 10.0  20.0  30.0
1891
  4.0   5.0   6.0
1892
  7.0   8.0   9.0
1893

1894
julia> vs = [[1, 2], [3, 4], [5, 6]];
1895

1896
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1897
6-element Vector{Int64}:
1898
 1
1899
 2
1900
 3
1901
 4
1902
 5
1903
 6
1904

1905
julia> ans == collect(Iterators.flatten(vs))
1906
true
1907
```
1908
"""
1909
vcat(X...) = cat(X...; dims=Val(1))
380✔
1910
"""
1911
    hcat(A...)
1912

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

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

1920
See also [`vcat`](@ref), [`hvcat`](@ref).
1921

1922
# Examples
1923
```jldoctest
1924
julia> hcat([1,2], [3,4], [5,6])
1925
2×3 Matrix{Int64}:
1926
 1  3  5
1927
 2  4  6
1928

1929
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1930
1×7 Matrix{Int64}:
1931
 1  2  30  40  5  6  7
1932

1933
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1934
true
1935

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

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

1942
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
1943
2×6 Matrix{Float64}:
1944
 0.0  0.0  1.0  2.0  50.0  60.0
1945
 0.0  0.0  3.0  4.0  70.0  80.0
1946

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

1950
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
1951
0×3 Matrix{Int64}
1952

1953
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
1954
2×1 Matrix{Any}:
1955
 1.1
1956
 9.9
1957
```
1958
"""
1959
hcat(X...) = cat(X...; dims=Val(2))
9✔
1960

1961
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
186✔
1962
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
326✔
1963

1964
"""
1965
    cat(A...; dims)
1966

1967
Concatenate the input arrays along the dimensions specified in `dims`.
1968

1969
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
1970
a in A)`.
1971
Along other dimensions, all input arrays should have the same size,
1972
which will also be the size of the output array along those dimensions.
1973

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

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

1983
The keyword also accepts `Val(dims)`.
1984

1985
!!! compat "Julia 1.8"
1986
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
1987

1988
# Examples
1989
```jldoctest
1990
julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2)  # same as hcat
1991
2×6×1 Array{Float64, 3}:
1992
[:, :, 1] =
1993
 1.0  2.0  3.14159  10.0  10.0  10.0
1994
 3.0  4.0  3.14159  10.0  10.0  10.0
1995

1996
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
1997
4×7 Matrix{Bool}:
1998
 1  0  0  0  0  0  0
1999
 0  1  1  0  0  0  0
2000
 0  1  1  0  0  0  0
2001
 0  0  0  1  1  1  1
2002

2003
julia> cat(1, [2], [3;;]; dims=Val(2))
2004
1×3 Matrix{Int64}:
2005
 1  2  3
2006
```
2007
"""
2008
@inline cat(A...; dims) = _cat(dims, A...)
16,986✔
2009
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
2010
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
218✔
2011

2012
# The specializations for 1 and 2 inputs are important
2013
# especially when running with --inline=no, see #11158
2014
vcat(A::AbstractArray) = cat(A; dims=Val(1))
1✔
2015
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
5✔
2016
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
2017
vcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(1))
6,991✔
2018
hcat(A::AbstractArray) = cat(A; dims=Val(2))
1✔
2019
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
1✔
2020
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
1✔
2021
hcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(2))
6✔
2022

2023
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
2024
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
2025
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
2026
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
2027
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
2028
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
2029

2030
# 2d horizontal and vertical concatenation
2031

2032
# these are produced in lowering if splatting occurs inside hvcat
2033
hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
3✔
2034
typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
3✔
2035

2036
function hvcat(nbc::Int, as...)
10✔
2037
    # nbc = # of block columns
2038
    n = length(as)
10✔
2039
    mod(n,nbc) != 0 &&
20✔
2040
        throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc"))
2041
    nbr = div(n,nbc)
9✔
2042
    hvcat(ntuple(Returns(nbc), nbr), as...)
9✔
2043
end
2044

2045
"""
2046
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2047

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

2053
# Examples
2054
```jldoctest
2055
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2056
(1, 2, 3, 4, 5, 6)
2057

2058
julia> [a b c; d e f]
2059
2×3 Matrix{Int64}:
2060
 1  2  3
2061
 4  5  6
2062

2063
julia> hvcat((3,3), a,b,c,d,e,f)
2064
2×3 Matrix{Int64}:
2065
 1  2  3
2066
 4  5  6
2067

2068
julia> [a b; c d; e f]
2069
3×2 Matrix{Int64}:
2070
 1  2
2071
 3  4
2072
 5  6
2073

2074
julia> hvcat((2,2,2), a,b,c,d,e,f)
2075
3×2 Matrix{Int64}:
2076
 1  2
2077
 3  4
2078
 5  6
2079
julia> hvcat((2,2,2), a,b,c,d,e,f) == hvcat(2, a,b,c,d,e,f)
2080
true
2081
```
2082
"""
2083
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
323✔
2084
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray{T}...) where {T} = typed_hvcat(T, rows, xs...)
517✔
2085

2086
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T
881✔
2087
    nbr = length(rows)  # number of block rows
881✔
2088

2089
    nc = 0
881✔
2090
    for i=1:rows[1]
1,762✔
2091
        nc += size(as[i],2)
2,705✔
2092
    end
2,509✔
2093

2094
    nr = 0
881✔
2095
    a = 1
881✔
2096
    for i = 1:nbr
881✔
2097
        nr += size(as[a],1)
1,781✔
2098
        a += rows[i]
1,425✔
2099
    end
1,969✔
2100

2101
    out = similar(as[1], T, nr, nc)
881✔
2102

2103
    a = 1
881✔
2104
    r = 1
881✔
2105
    for i = 1:nbr
881✔
2106
        c = 1
1,425✔
2107
        szi = size(as[a],1)
1,781✔
2108
        for j = 1:rows[i]
2,850✔
2109
            Aj = as[a+j-1]
2,627✔
2110
            szj = size(Aj,2)
3,912✔
2111
            if size(Aj,1) != szi
3,912✔
2112
                throw(DimensionMismatch("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
1✔
2113
            end
2114
            if c-1+szj > nc
3,923✔
2115
                throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
1✔
2116
            end
2117
            out[r:r-1+szi, c:c-1+szj] = Aj
3,841✔
2118
            c += szj
2,625✔
2119
        end
3,827✔
2120
        if c != nc+1
1,423✔
2121
            throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
1✔
2122
        end
2123
        r += szi
1,422✔
2124
        a += rows[i]
1,422✔
2125
    end
1,966✔
2126
    out
878✔
2127
end
2128

2129
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
2130
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2131

2132
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,192✔
2133
    nr = length(rows)
1,192✔
2134
    nc = rows[1]
1,192✔
2135

2136
    a = Matrix{T}(undef, nr, nc)
1,192✔
2137
    if length(a) != length(xs)
1,192✔
2138
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2139
    end
2140
    k = 1
1,190✔
2141
    @inbounds for i=1:nr
1,190✔
2142
        if nc != rows[i]
3,271✔
2143
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2144
        end
2145
        for j=1:nc
6,540✔
2146
            a[i,j] = xs[k]
9,090✔
2147
            k += 1
9,090✔
2148
        end
14,910✔
2149
    end
5,351✔
2150
    a
1,189✔
2151
end
2152

2153
function hvcat_fill!(a::Array, xs::Tuple)
532✔
2154
    nr, nc = size(a,1), size(a,2)
532✔
2155
    len = length(xs)
532✔
2156
    if nr*nc != len
532✔
2157
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2158
    end
2159
    k = 1
531✔
2160
    for i=1:nr
1,062✔
2161
        @inbounds for j=1:nc
2,792✔
2162
            a[i,j] = xs[k]
9,458✔
2163
            k += 1
8,798✔
2164
        end
16,200✔
2165
    end
2,261✔
2166
    a
531✔
2167
end
2168

2169
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
150✔
2170
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
137✔
2171
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2172
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
3✔
2173

2174
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
375✔
2175
    nr = length(rows)
375✔
2176
    nc = rows[1]
375✔
2177
    for i = 2:nr
375✔
2178
        if nc != rows[i]
745✔
2179
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2✔
2180
        end
2181
    end
1,113✔
2182
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
373✔
2183
end
2184

2185
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T
147✔
2186
    nbr = length(rows)  # number of block rows
147✔
2187
    rs = Vector{Any}(undef, nbr)
147✔
2188
    a = 1
147✔
2189
    for i = 1:nbr
147✔
2190
        rs[i] = typed_hcat(T, as[a:a-1+rows[i]]...)
531✔
2191
        a += rows[i]
364✔
2192
    end
581✔
2193
    T[rs...;]
147✔
2194
end
2195

2196
## N-dimensional concatenation ##
2197

2198
"""
2199
    hvncat(dim::Int, row_first, values...)
2200
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2201
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2202

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

2205
This function is called for block matrix syntax. The first argument either specifies the
2206
shape of the concatenation, similar to `hvcat`, as a tuple of tuples, or the dimensions that
2207
specify the key number of elements along each axis, and is used to determine the output
2208
dimensions. The `dims` form is more performant, and is used by default when the concatenation
2209
operation has the same number of elements along each axis (e.g., [a b; c d;;; e f ; g h]).
2210
The `shape` form is used when the number of elements along each axis is unbalanced
2211
(e.g., [a b ; c]). Unbalanced syntax needs additional validation overhead. The `dim` form
2212
is an optimization for concatenation along just one dimension. `row_first` indicates how
2213
`values` are ordered. The meaning of the first and second elements of `shape` are also
2214
swapped based on `row_first`.
2215

2216
# Examples
2217
```jldoctest
2218
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2219
(1, 2, 3, 4, 5, 6)
2220

2221
julia> [a b c;;; d e f]
2222
1×3×2 Array{Int64, 3}:
2223
[:, :, 1] =
2224
 1  2  3
2225

2226
[:, :, 2] =
2227
 4  5  6
2228

2229
julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2230
2×1×3 Array{Int64, 3}:
2231
[:, :, 1] =
2232
 1
2233
 2
2234

2235
[:, :, 2] =
2236
 3
2237
 4
2238

2239
[:, :, 3] =
2240
 5
2241
 6
2242

2243
julia> [a b;;; c d;;; e f]
2244
1×2×3 Array{Int64, 3}:
2245
[:, :, 1] =
2246
 1  2
2247

2248
[:, :, 2] =
2249
 3  4
2250

2251
[:, :, 3] =
2252
 5  6
2253

2254
julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f)
2255
1×3×2 Array{Int64, 3}:
2256
[:, :, 1] =
2257
 1  2  3
2258

2259
[:, :, 2] =
2260
 4  5  6
2261
```
2262

2263
# Examples for construction of the arguments
2264
```
2265
[a b c ; d e f ;;;
2266
 g h i ; j k l ;;;
2267
 m n o ; p q r ;;;
2268
 s t u ; v w x]
2269
⇒ dims = (2, 3, 4)
2270

2271
[a b ; c ;;; d ;;;;]
2272
 ___   _     _
2273
 2     1     1 = elements in each row (2, 1, 1)
2274
 _______     _
2275
 3           1 = elements in each column (3, 1)
2276
 _____________
2277
 4             = elements in each 3d slice (4,)
2278
 _____________
2279
 4             = elements in each 4d slice (4,)
2280
⇒ shape = ((2, 1, 1), (3, 1), (4,), (4,)) with `row_first` = true
2281
```
2282
"""
2283
hvncat(dimsshape::Tuple, row_first::Bool, xs...) = _hvncat(dimsshape, row_first, xs...)
262✔
2284
hvncat(dim::Int, xs...) = _hvncat(dim, true, xs...)
75✔
2285

2286
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
29✔
2287
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
91✔
2288
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
86✔
2289
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
2290
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2291
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
132✔
2292

2293

2294
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
17✔
2295
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2296

2297
# 1-dimensional hvncat methods
2298

2299
_typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
4✔
2300
_typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
×
2301
_typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
4✔
2302
_typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
4✔
2303
_typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
×
2304
_typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
4✔
2305
_typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
×
2306

2307
_typed_hvncat_0d_only_one() =
8✔
2308
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2309

2310
# `@constprop :aggressive` here to form constant `Val(dim)` type to get type stability
2311
@constprop :aggressive _typed_hvncat(T::Type, dim::Int, ::Bool, xs...) = _typed_hvncat(T, Val(dim), xs...) # catches from _hvncat type promoters
75✔
2312

2313
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
15✔
2314
    N < 0 &&
15✔
2315
        throw(ArgumentError("concatenation dimension must be non-negative"))
2316
    return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
40✔
2317
end
2318

2319
function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
36✔
2320
    N < 0 &&
36✔
2321
        throw(ArgumentError("concatenation dimension must be non-negative"))
2322
    A = cat_similar(xs[1], T, (ntuple(x -> 1, Val(N - 1))..., length(xs)))
79✔
2323
    hvncat_fill!(A, false, xs)
35✔
2324
    return A
35✔
2325
end
2326

2327
function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N}
25✔
2328
    # optimization for arrays that can be concatenated by copying them linearly into the destination
2329
    # conditions: the elements must all have 1-length dimensions above N
2330
    length(as) > 0 ||
25✔
2331
        throw(ArgumentError("must have at least one element"))
2332
    N < 0 &&
25✔
2333
        throw(ArgumentError("concatenation dimension must be non-negative"))
2334
    for a ∈ as
23✔
2335
        ndims(a) <= N || all(x -> size(a, x) == 1, (N + 1):ndims(a)) ||
54✔
2336
            return _typed_hvncat(T, (ntuple(x -> 1, Val(N - 1))..., length(as), 1), false, as...)
9✔
2337
            # the extra 1 is to avoid an infinite cycle
2338
    end
46✔
2339

2340
    nd = N
17✔
2341

2342
    Ndim = 0
17✔
2343
    for i ∈ eachindex(as)
18✔
2344
        Ndim += cat_size(as[i], N)
38✔
2345
        nd = max(nd, cat_ndims(as[i]))
38✔
2346
        for d ∈ 1:N - 1
32✔
2347
            cat_size(as[1], d) == cat_size(as[i], d) || throw(DimensionMismatch("mismatched size along axis $d in element $i"))
39✔
2348
        end
44✔
2349
    end
43✔
2350

2351
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
28✔
2352
    k = 1
13✔
2353
    for a ∈ as
13✔
2354
        for i ∈ eachindex(a)
44✔
2355
            A[k] = a[i]
38✔
2356
            k += 1
34✔
2357
        end
47✔
2358
    end
34✔
2359
    return A
13✔
2360
end
2361

2362
function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N}
14✔
2363
    length(as) > 0 ||
14✔
2364
        throw(ArgumentError("must have at least one element"))
2365
    N < 0 &&
14✔
2366
        throw(ArgumentError("concatenation dimension must be non-negative"))
2367
    nd = N
12✔
2368
    Ndim = 0
12✔
2369
    for i ∈ eachindex(as)
14✔
2370
        Ndim += cat_size(as[i], N)
30✔
2371
        nd = max(nd, cat_ndims(as[i]))
30✔
2372
        for d ∈ 1:N-1
20✔
2373
            cat_size(as[i], d) == 1 ||
36✔
2374
                throw(DimensionMismatch("all dimensions of element $i other than $N must be of length 1"))
2375
        end
28✔
2376
    end
20✔
2377

2378
    A = Array{T, nd}(undef, ntuple(x -> 1, Val(N - 1))..., Ndim, ntuple(x -> 1, nd - N)...)
15✔
2379

2380
    k = 1
4✔
2381
    for a ∈ as
4✔
2382
        if a isa AbstractArray
12✔
2383
            lena = length(a)
2✔
2384
            copyto!(A, k, a, 1, lena)
2✔
2385
            k += lena
2✔
2386
        else
2387
            A[k] = a
10✔
2388
            k += 1
10✔
2389
        end
2390
    end
16✔
2391
    return A
4✔
2392
end
2393

2394
# 0-dimensional cases for balanced and unbalanced hvncat method
2395

2396
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2397
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2398

2399

2400
# balanced dimensions hvncat methods
2401

2402
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
2✔
2403
_typed_hvncat(T::Type, dims::Tuple{Int}, ::Bool, as::Number...) = _typed_hvncat_1d(T, dims[1], Val(false), as...)
8✔
2404

2405
function _typed_hvncat_1d(::Type{T}, ds::Int, ::Val{row_first}, as...) where {T, row_first}
22✔
2406
    lengthas = length(as)
22✔
2407
    ds > 0 ||
22✔
2408
        throw(ArgumentError("`dimsshape` argument must consist of positive integers"))
2409
    lengthas == ds ||
30✔
2410
        throw(ArgumentError("number of elements does not match `dimshape` argument; expected $ds, got $lengthas"))
2411
    if row_first
14✔
2412
        return _typed_hvncat(T, Val(2), as...)
4✔
2413
    else
2414
        return _typed_hvncat(T, Val(1), as...)
10✔
2415
    end
2416
end
2417

2418
function _typed_hvncat(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, xs::Number...) where {T, N}
44✔
2419
    all(>(0), dims) ||
60✔
2420
        throw(ArgumentError("`dims` argument must contain positive integers"))
2421
    A = Array{T, N}(undef, dims...)
28✔
2422
    lengtha = length(A)  # Necessary to store result because throw blocks are being deoptimized right now, which leads to excessive allocations
28✔
2423
    lengthx = length(xs) # Cuts from 3 allocations to 1.
28✔
2424
    if lengtha != lengthx
28✔
2425
       throw(ArgumentError("argument count does not match specified shape (expected $lengtha, got $lengthx)"))
×
2426
    end
2427
    hvncat_fill!(A, row_first, xs)
28✔
2428
    return A
28✔
2429
end
2430

2431
function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
63✔
2432
    nr, nc = size(A, 1), size(A, 2)
63✔
2433
    na = prod(size(A)[3:end])
63✔
2434
    len = length(xs)
63✔
2435
    nrc = nr * nc
63✔
2436
    if nrc * na != len
63✔
2437
        throw(ArgumentError("argument count $(len) does not match specified shape $(size(A))"))
×
2438
    end
2439
    # putting these in separate functions leads to unnecessary allocations
2440
    if row_first
63✔
2441
        k = 1
17✔
2442
        for d ∈ 1:na
34✔
2443
            dd = nrc * (d - 1)
31✔
2444
            for i ∈ 1:nr
62✔
2445
                Ai = dd + i
42✔
2446
                for j ∈ 1:nc
84✔
2447
                    @inbounds A[Ai] = xs[k]
95✔
2448
                    k += 1
95✔
2449
                    Ai += nr
95✔
2450
                end
148✔
2451
            end
53✔
2452
        end
31✔
2453
    else
2454
        for k ∈ eachindex(xs)
46✔
2455
            @inbounds A[k] = xs[k]
93✔
2456
        end
93✔
2457
    end
2458
end
2459

2460
function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
90✔
2461
    # function barrier after calculating the max is necessary for high performance
2462
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
90✔
2463
    return _typed_hvncat_dims(T, (dims..., ntuple(x -> 1, nd - N)...), row_first, as)
124✔
2464
end
2465

2466
function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
90✔
2467
    length(as) > 0 ||
90✔
2468
        throw(ArgumentError("must have at least one element"))
2469
    all(>(0), dims) ||
122✔
2470
        throw(ArgumentError("`dims` argument must contain positive integers"))
2471

2472
    d1 = row_first ? 2 : 1
58✔
2473
    d2 = row_first ? 1 : 2
58✔
2474

2475
    outdims = zeros(Int, N)
203✔
2476

2477
    # validate shapes for lowest level of concatenation
2478
    d = findfirst(>(1), dims)
86✔
2479
    if d !== nothing # all dims are 1
58✔
2480
        if row_first && d < 3
57✔
2481
            d = d == 1 ? 2 : 1
32✔
2482
        end
2483
        nblocks = length(as) ÷ dims[d]
57✔
2484
        for b ∈ 1:nblocks
114✔
2485
            offset = ((b - 1) * dims[d])
175✔
2486
            startelementi = offset + 1
175✔
2487
            for i ∈ offset .+ (2:dims[d])
262✔
2488
                for dd ∈ 1:N
111✔
2489
                    dd == d && continue
316✔
2490
                    if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
217✔
2491
                        throw(DimensionMismatch("incompatible shape in element $i"))
6✔
2492
                    end
2493
                end
515✔
2494
            end
129✔
2495
        end
287✔
2496
    end
2497

2498
    # discover number of rows or columns
2499
    for i ∈ 1:dims[d1]
104✔
2500
        outdims[d1] += cat_size(as[i], d1)
140✔
2501
    end
164✔
2502

2503
    currentdims = zeros(Int, N)
176✔
2504
    blockcount = 0
52✔
2505
    elementcount = 0
52✔
2506
    for i ∈ eachindex(as)
52✔
2507
        elementcount += cat_length(as[i])
309✔
2508
        currentdims[d1] += cat_size(as[i], d1)
309✔
2509
        if currentdims[d1] == outdims[d1]
259✔
2510
            currentdims[d1] = 0
129✔
2511
            for d ∈ (d2, 3:N...)
129✔
2512
                currentdims[d] += cat_size(as[i], d)
258✔
2513
                if outdims[d] == 0 # unfixed dimension
203✔
2514
                    blockcount += 1
167✔
2515
                    if blockcount == dims[d]
167✔
2516
                        outdims[d] = currentdims[d]
88✔
2517
                        currentdims[d] = 0
88✔
2518
                        blockcount = 0
88✔
2519
                    else
2520
                        break
167✔
2521
                    end
2522
                else # fixed dimension
2523
                    if currentdims[d] == outdims[d] # end of dimension
36✔
2524
                        currentdims[d] = 0
23✔
2525
                    elseif currentdims[d] < outdims[d] # dimension in progress
13✔
2526
                        break
13✔
2527
                    else # exceeded dimension
2528
                        throw(DimensionMismatch("argument $i has too many elements along axis $d"))
×
2529
                    end
2530
                end
2531
            end
142✔
2532
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
130✔
2533
            throw(DimensionMismatch("argument $i has too many elements along axis $d1"))
16✔
2534
        end
2535
    end
450✔
2536

2537
    outlen = prod(outdims)
72✔
2538
    elementcount == outlen ||
36✔
2539
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2540

2541
    # copy into final array
2542
    A = cat_similar(as[1], T, outdims)
36✔
2543
    # @assert all(==(0), currentdims)
2544
    outdims .= 0
108✔
2545
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
36✔
2546
    return A
36✔
2547
end
2548

2549

2550
# unbalanced dimensions hvncat methods
2551

2552
function _typed_hvncat(T::Type, shape::Tuple{Tuple}, row_first::Bool, xs...)
19✔
2553
    length(shape[1]) > 0 ||
19✔
2554
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2555
    return _typed_hvncat_1d(T, shape[1][1], Val(row_first), xs...)
13✔
2556
end
2557

2558
function _typed_hvncat(T::Type, shape::NTuple{N, Tuple}, row_first::Bool, as...) where {N}
115✔
2559
    # function barrier after calculating the max is necessary for high performance
2560
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
115✔
2561
    return _typed_hvncat_shape(T, (shape..., ntuple(x -> shape[end], nd - N)...), row_first, as)
134✔
2562
end
2563

2564
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
107✔
2565
    length(as) > 0 ||
107✔
2566
        throw(ArgumentError("must have at least one element"))
2567
    all(>(0), tuple((shape...)...)) ||
147✔
2568
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2569

2570
    d1 = row_first ? 2 : 1
67✔
2571
    d2 = row_first ? 1 : 2
67✔
2572

2573
    shapev = collect(shape) # saves allocations later
67✔
2574
    all(!isempty, shapev) ||
134✔
2575
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2576
    length(shapev[end]) == 1 ||
70✔
2577
        throw(ArgumentError("last level of shape must contain only one integer"))
2578
    shapelength = shapev[end][1]
64✔
2579
    lengthas = length(as)
64✔
2580
    shapelength == lengthas || throw(ArgumentError("number of elements does not match shape; expected $(shapelength), got $lengthas)"))
64✔
2581
    # discover dimensions
2582
    nd = max(N, cat_ndims(as[1]))
64✔
2583
    outdims = fill(-1, nd)
210✔
2584
    currentdims = zeros(Int, nd)
210✔
2585
    blockcounts = zeros(Int, nd)
210✔
2586
    shapepos = ones(Int, nd)
210✔
2587

2588
    elementcount = 0
64✔
2589
    for i ∈ eachindex(as)
64✔
2590
        elementcount += cat_length(as[i])
355✔
2591
        wasstartblock = false
313✔
2592
        for d ∈ 1:N
313✔
2593
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
907✔
2594
            dsize = cat_size(as[i], ad)
1,048✔
2595
            blockcounts[d] += 1
907✔
2596

2597
            if d == 1 || i == 1 || wasstartblock
1,501✔
2598
                currentdims[d] += dsize
623✔
2599
            elseif dsize != cat_size(as[i - 1], ad)
302✔
2600
                throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
8✔
2601
                                         expected $(cat_size(as[i - 1], ad)), got $dsize"))
2602
            end
2603

2604
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
899✔
2605

2606
            isendblock = blockcounts[d] == shapev[d][shapepos[d]]
899✔
2607
            if isendblock
899✔
2608
                if outdims[d] == -1
269✔
2609
                    outdims[d] = currentdims[d]
138✔
2610
                elseif outdims[d] != currentdims[d]
131✔
2611
                    throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
40✔
2612
                                             expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2613
                end
2614
                currentdims[d] = 0
229✔
2615
                blockcounts[d] = 0
229✔
2616
                shapepos[d] += 1
229✔
2617
                d > 1 && (blockcounts[d - 1] == 0 ||
230✔
2618
                    throw(DimensionMismatch("shape in level $d is inconsistent; level counts must nest \
2619
                                             evenly into each other")))
2620
            end
2621
        end
1,452✔
2622
    end
513✔
2623

2624
    outlen = prod(outdims)
30✔
2625
    elementcount == outlen ||
15✔
2626
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2627

2628
    if row_first
15✔
2629
        outdims[1], outdims[2] = outdims[2], outdims[1]
11✔
2630
    end
2631

2632
    # @assert all(==(0), currentdims)
2633
    # @assert all(==(0), blockcounts)
2634

2635
    # copy into final array
2636
    A = cat_similar(as[1], T, outdims)
15✔
2637
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
15✔
2638
    return A
15✔
2639
end
2640

2641
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int},
51✔
2642
                              d1::Int, d2::Int, as::Tuple) where {T, N}
2643
    N > 1 || throw(ArgumentError("dimensions of the destination array must be at least 2"))
51✔
2644
    length(scratch1) == length(scratch2) == N ||
51✔
2645
        throw(ArgumentError("scratch vectors must have as many elements as the destination array has dimensions"))
2646
    0 < d1 < 3 &&
51✔
2647
    0 < d2 < 3 &&
2648
    d1 != d2 ||
2649
        throw(ArgumentError("d1 and d2 must be either 1 or 2, exclusive."))
2650
    outdims = size(A)
51✔
2651
    offsets = scratch1
51✔
2652
    inneroffsets = scratch2
51✔
2653
    for a ∈ as
51✔
2654
        if isa(a, AbstractArray)
270✔
2655
            for ai ∈ a
266✔
2656
                @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
7,046✔
2657
                A[Ai] = ai
1,888✔
2658

2659
                @inbounds for j ∈ 1:N
1,888✔
2660
                    inneroffsets[j] += 1
4,152✔
2661
                    inneroffsets[j] < cat_size(a, j) && break
4,221✔
2662
                    inneroffsets[j] = 0
2,490✔
2663
                end
2,490✔
2664
            end
2,118✔
2665
        else
2666
            @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
52✔
2667
            A[Ai] = a
30✔
2668
        end
2669

2670
        @inbounds for j ∈ (d1, d2, 3:N...)
270✔
2671
            offsets[j] += cat_size(a, j)
599✔
2672
            offsets[j] < outdims[j] && break
518✔
2673
            offsets[j] = 0
304✔
2674
        end
304✔
2675
    end
270✔
2676
end
2677

2678
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
1,915✔
2679
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2680
    Ai = inneroffsets[1] + offsets[1] + 1
1,915✔
2681
    for j ∈ 2:nd
1,915✔
2682
        increment = inneroffsets[j] + offsets[j]
7,098✔
2683
        for k ∈ 1:j-1
14,168✔
2684
            increment *= outdims[k]
17,209✔
2685
        end
27,320✔
2686
        Ai += increment
7,098✔
2687
    end
12,281✔
2688
    Ai
1,915✔
2689
end
2690

2691
"""
2692
    stack(iter; [dims])
2693

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

2697
By default the axes of the elements are placed first,
2698
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2699
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2700

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

2705
The various [`cat`](@ref) functions also combine arrays. However, these all
2706
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2707
the arrays along new dimensions.
2708
They also accept arrays as separate arguments, rather than a single collection.
2709

2710
!!! compat "Julia 1.9"
2711
    This function requires at least Julia 1.9.
2712

2713
# Examples
2714
```jldoctest
2715
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2716

2717
julia> mat = stack(vecs)
2718
2×3 Matrix{Float32}:
2719
 1.0  30.0  500.0
2720
 2.0  40.0  600.0
2721

2722
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2723
true
2724

2725
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2726
true
2727

2728
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2729
2×4 Matrix{Int64}:
2730
  1   2   3   4
2731
 10  11  12  13
2732

2733
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2734
true
2735

2736
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2737
3×2 Matrix{Float32}:
2738
   1.0    2.0
2739
  30.0   40.0
2740
 500.0  600.0
2741

2742
julia> x = rand(3,4);
2743

2744
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2745
true
2746
```
2747

2748
Higher-dimensional examples:
2749

2750
```jldoctest
2751
julia> A = rand(5, 7, 11);
2752

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

2755
julia> (element = size(first(E)), container = size(E))
2756
(element = (5, 11), container = (7,))
2757

2758
julia> stack(E) |> size
2759
(5, 11, 7)
2760

2761
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2762
true
2763

2764
julia> A == stack(E; dims=2)
2765
true
2766

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

2769
julia> (element = size(first(M)), container = size(M))
2770
(element = (2, 3), container = (5, 7))
2771

2772
julia> stack(M) |> size  # keeps all dimensions
2773
(2, 3, 5, 7)
2774

2775
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2776
(35, 2, 3)
2777

2778
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2779
(14, 15)
2780
```
2781
"""
2782
stack(iter; dims=:) = _stack(dims, iter)
248✔
2783

2784
"""
2785
    stack(f, args...; [dims])
2786

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

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

2794
See also [`mapslices`](@ref), [`eachcol`](@ref).
2795

2796
# Examples
2797
```jldoctest
2798
julia> stack(c -> (c, c-32), "julia")
2799
2×5 Matrix{Char}:
2800
 'j'  'u'  'l'  'i'  'a'
2801
 'J'  'U'  'L'  'I'  'A'
2802

2803
julia> stack(eachrow([1 2 3; 4 5 6]), (10, 100); dims=1) do row, n
2804
         vcat(row, row .* n, row ./ n)
2805
       end
2806
2×9 Matrix{Float64}:
2807
 1.0  2.0  3.0   10.0   20.0   30.0  0.1   0.2   0.3
2808
 4.0  5.0  6.0  400.0  500.0  600.0  0.04  0.05  0.06
2809
```
2810
"""
2811
stack(f, iter; dims=:) = _stack(dims, f(x) for x in iter)
12✔
2812
stack(f, xs, yzs...; dims=:) = _stack(dims, f(xy...) for xy in zip(xs, yzs...))
2✔
2813

2814
_stack(dims::Union{Integer, Colon}, iter) = _stack(dims, IteratorSize(iter), iter)
163✔
2815

2816
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2817

2818
function _stack(dims, ::Union{HasShape, HasLength}, iter)
122✔
2819
    S = @default_eltype iter
122✔
2820
    T = S != Union{} ? eltype(S) : Any  # Union{} occurs for e.g. stack(1,2), postpone the error
126✔
2821
    if isconcretetype(T)
122✔
2822
        _typed_stack(dims, T, S, iter)
101✔
2823
    else  # Need to look inside, but shouldn't run an expensive iterator twice:
2824
        array = iter isa Union{Tuple, AbstractArray} ? iter : collect(iter)
42✔
2825
        isempty(array) && return _empty_stack(dims, T, S, iter)
38✔
2826
        T2 = mapreduce(eltype, promote_type, array)
42✔
2827
        _typed_stack(dims, T2, eltype(array), array)
36✔
2828
    end
2829
end
2830

2831
function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
184✔
2832
    xit = iterate(A)
211✔
2833
    nothing === xit && return _empty_stack(:, T, S, A)
94✔
2834
    x1, _ = xit
94✔
2835
    ax1 = _iterator_axes(x1)
98✔
2836
    B = similar(_ensure_array(x1), T, ax1..., Aax...)
106✔
2837
    off = firstindex(B)
93✔
2838
    len = length(x1)
97✔
2839
    while xit !== nothing
2,563✔
2840
        x, state = xit
2,476✔
2841
        _stack_size_check(x, ax1)
4,654✔
2842
        copyto!(B, off, x)
3,574✔
2843
        off += len
2,470✔
2844
        xit = iterate(A, state)
3,798✔
2845
    end
2,470✔
2846
    B
87✔
2847
end
2848

2849
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2850
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2851
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2852

2853
# For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2854
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
48✔
2855
    _typed_stack(dims, T, S, IteratorSize(S), A)
2856
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasLength, A) where {T,S} =
11✔
2857
    _typed_stack(dims, T, S, HasShape{1}(), A)
2858
function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
27✔
2859
    if dims == N+1
27✔
2860
        _typed_stack(:, T, S, A, (_vec_axis(A),))
4✔
2861
    else
2862
        _dim_stack(dims, T, S, A)
23✔
2863
    end
2864
end
2865
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
2✔
2866
    _dim_stack(dims, T, S, A)
2867

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

2870
@constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
25✔
2871
    xit = Iterators.peel(A)
48✔
2872
    nothing === xit && return _empty_stack(dims, T, S, A)
25✔
2873
    x1, xrest = xit
25✔
2874
    ax1 = _iterator_axes(x1)
25✔
2875
    N1 = length(ax1)+1
24✔
2876
    dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
27✔
2877

2878
    newaxis = _vec_axis(A)
21✔
2879
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
141✔
2880
    B = similar(_ensure_array(x1), T, outax...)
23✔
2881

2882
    if dims == 1
21✔
2883
        _dim_stack!(Val(1), B, x1, xrest)
13✔
2884
    elseif dims == 2
8✔
2885
        _dim_stack!(Val(2), B, x1, xrest)
4✔
2886
    else
2887
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
2888
    end
2889
    B
18✔
2890
end
2891

2892
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
21✔
2893
    before = ntuple(d -> Colon(), dims - 1)
33✔
2894
    after = ntuple(d -> Colon(), ndims(B) - dims)
49✔
2895

2896
    i = firstindex(B, dims)
21✔
2897
    copyto!(view(B, before..., i, after...), x1)
41✔
2898

2899
    for x in xrest
29✔
2900
        _stack_size_check(x, _iterator_axes(x1))
6,422✔
2901
        i += 1
3,261✔
2902
        @inbounds copyto!(view(B, before..., i, after...), x)
6,514✔
2903
    end
3,261✔
2904
end
2905

2906
@inline function _stack_size_check(x, ax1::Tuple)
5,740✔
2907
    if _iterator_axes(x) != ax1
11,107✔
2908
        uax1 = map(UnitRange, ax1)
9✔
2909
        uaxN = map(UnitRange, axes(x))
9✔
2910
        throw(DimensionMismatch(
9✔
2911
            LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
2912
    end
2913
end
2914

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

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

2920

2921
## Reductions and accumulates ##
2922

2923
function isequal(A::AbstractArray, B::AbstractArray)
247,603✔
2924
    if A === B return true end
249,068✔
2925
    if axes(A) != axes(B)
494,037✔
2926
        return false
2,917✔
2927
    end
2928
    for (a, b) in zip(A, B)
490,546✔
2929
        if !isequal(a, b)
92,020,867✔
2930
            return false
612✔
2931
        end
2932
    end
183,592,121✔
2933
    return true
244,957✔
2934
end
2935

2936
function cmp(A::AbstractVector, B::AbstractVector)
297✔
2937
    for (a, b) in zip(A, B)
604✔
2938
        if !isequal(a, b)
829✔
2939
            return isless(a, b) ? -1 : 1
383✔
2940
        end
2941
    end
1,071✔
2942
    return cmp(length(A), length(B))
17✔
2943
end
2944

2945
"""
2946
    isless(A::AbstractVector, B::AbstractVector)
2947

2948
Return `true` when `A` is less than `B` in lexicographic order.
2949
"""
2950
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
391✔
2951

2952
function (==)(A::AbstractArray, B::AbstractArray)
6,567,456✔
2953
    if axes(A) != axes(B)
13,139,123✔
2954
        return false
3,541✔
2955
    end
2956
    anymissing = false
6,563,815✔
2957
    for (a, b) in zip(A, B)
12,248,782✔
2958
        eq = (a == b)
136,116,027✔
2959
        if ismissing(eq)
104,046,990✔
2960
            anymissing = true
21✔
2961
        elseif !eq
135,227,199✔
2962
            return false
2,766✔
2963
        end
2964
    end
264,770,673✔
2965
    return anymissing ? missing : true
6,565,065✔
2966
end
2967

2968
# _sub2ind and _ind2sub
2969
# fallbacks
2970
function _sub2ind(A::AbstractArray, I...)
2,148,769✔
2971
    @inline
2,148,769✔
2972
    _sub2ind(axes(A), I...)
2,549,720✔
2973
end
2974

2975
function _ind2sub(A::AbstractArray, ind)
382,603✔
2976
    @inline
382,603✔
2977
    _ind2sub(axes(A), ind)
382,603✔
2978
end
2979

2980
# 0-dimensional arrays and indexing with []
2981
_sub2ind(::Tuple{}) = 1
18✔
2982
_sub2ind(::DimsInteger) = 1
2✔
2983
_sub2ind(::Indices) = 1
×
2984
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
6✔
2985

2986
# Generic cases
2987
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
2,147,483,647✔
2988
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
2,667,869✔
2989
# In 1d, there's a question of whether we're doing cartesian indexing
2990
# or linear indexing. Support only the former.
2991
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
2992
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2993
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
2994
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
2995

2996
_sub2ind_recurse(::Any, L, ind) = ind
1,967,062✔
2997
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,800✔
2998
    @inline
867✔
2999
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
12,153✔
3000
end
3001
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
13,167,883✔
3002
    @inline
10,873,416✔
3003
    r1 = inds[1]
10,873,418✔
3004
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
2,147,483,647✔
3005
end
3006

3007
nextL(L, l::Integer) = L*l
5,785,841✔
3008
nextL(L, r::AbstractUnitRange) = L*length(r)
5,498,889✔
3009
nextL(L, r::Slice) = L*length(r.indices)
×
3010
offsetin(i, l::Integer) = i-1
2,147,483,647✔
3011
offsetin(i, r::AbstractUnitRange) = i-first(r)
5,899,864✔
3012

3013
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
3014
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
1,231✔
3015
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
382,588✔
3016
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
3017
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
3018
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
39✔
3019

3020
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3021
function _ind2sub_recurse(indslast::NTuple{1}, ind)
383,819✔
3022
    @inline
383,819✔
3023
    (_lookup(ind, indslast[1]),)
383,819✔
3024
end
3025
function _ind2sub_recurse(inds, ind)
729,732✔
3026
    @inline
729,732✔
3027
    r1 = inds[1]
729,732✔
3028
    indnext, f, l = _div(ind, r1)
729,732✔
3029
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
729,732✔
3030
end
3031

3032
_lookup(ind, d::Integer) = ind+1
1,231✔
3033
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
382,588✔
3034
_div(ind, d::Integer) = div(ind, d), 1, d
1,231✔
3035
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
1,457,002✔
3036

3037
# Vectorized forms
3038
function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
×
3039
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
×
3040
end
3041
_sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3042
    _sub2ind_vecs(inds, I1, I...)
3043
_sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3044
    _sub2ind_vecs(inds, I1, I...)
3045
function _sub2ind_vecs(inds, I::AbstractVector...)
×
3046
    I1 = I[1]
×
3047
    Iinds = axes1(I1)
×
3048
    for j = 2:length(I)
×
3049
        axes1(I[j]) == Iinds || throw(DimensionMismatch("indices of I[1] ($(Iinds)) does not match indices of I[$j] ($(axes1(I[j])))"))
×
3050
    end
×
3051
    Iout = similar(I1)
×
3052
    _sub2ind!(Iout, inds, Iinds, I)
×
3053
    Iout
×
3054
end
3055

3056
function _sub2ind!(Iout, inds, Iinds, I)
×
3057
    @noinline
×
3058
    for i in Iinds
×
3059
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3060
        Iout[i] = sub2ind_vec(inds, i, I)
×
3061
    end
×
3062
    Iout
×
3063
end
3064

3065
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3066
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3067
_sub2ind_vec(i) = ()
×
3068

3069
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
×
3070
    M = length(ind)
×
3071
    t = ntuple(n->similar(ind),Val(N))
×
3072
    for (i,idx) in pairs(IndexLinear(), ind)
×
3073
        sub = _ind2sub(inds, idx)
×
3074
        for j = 1:N
×
3075
            t[j][i] = sub[j]
×
3076
        end
×
3077
    end
×
3078
    t
×
3079
end
3080

3081
## iteration utilities ##
3082

3083
"""
3084
    foreach(f, c...) -> Nothing
3085

3086
Call function `f` on each element of iterable `c`.
3087
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3088
any iterator is finished.
3089

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

3093
# Examples
3094
```jldoctest
3095
julia> tri = 1:3:7; res = Int[];
3096

3097
julia> foreach(x -> push!(res, x^2), tri)
3098

3099
julia> res
3100
3-element Vector{$(Int)}:
3101
  1
3102
 16
3103
 49
3104

3105
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3106
1 with a
3107
4 with b
3108
7 with c
3109
```
3110
"""
3111
foreach(f) = (f(); nothing)
2✔
3112
foreach(f, itr) = (for x in itr; f(x); end; nothing)
573,747,315✔
3113
foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing)
11✔
3114

3115
## map over arrays ##
3116

3117
## transform any set of dimensions
3118
## dims specifies which dimensions will be transformed. for example
3119
## dims==1:2 will call f on all slices A[:,:,...]
3120
"""
3121
    mapslices(f, A; dims)
3122

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

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

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

3132
# Examples
3133
```jldoctest
3134
julia> A = reshape(1:30,(2,5,3))
3135
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3136
[:, :, 1] =
3137
 1  3  5  7   9
3138
 2  4  6  8  10
3139

3140
[:, :, 2] =
3141
 11  13  15  17  19
3142
 12  14  16  18  20
3143

3144
[:, :, 3] =
3145
 21  23  25  27  29
3146
 22  24  26  28  30
3147

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

3150
julia> B = mapslices(f, A, dims=(1,2))
3151
1×4×3 Array{$Int, 3}:
3152
[:, :, 1] =
3153
 1  1  1  1
3154

3155
[:, :, 2] =
3156
 11  11  11  11
3157

3158
[:, :, 3] =
3159
 21  21  21  21
3160

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

3163
julia> B == stack(f2, eachslice(A, dims=3))
3164
true
3165

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

3168
julia> mapslices(g, A, dims=[1,3])
3169
1×5×1 Array{Rational{$Int}, 3}:
3170
[:, :, 1] =
3171
 1//21  3//23  1//5  7//27  9//29
3172

3173
julia> map(g, eachslice(A, dims=2))
3174
5-element Vector{Rational{$Int}}:
3175
 1//21
3176
 3//23
3177
 1//5
3178
 7//27
3179
 9//29
3180

3181
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3182
true
3183
```
3184

3185
Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3186
one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3187
`mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3188
values in the slice without affecting `A`.
3189
"""
3190
function mapslices(f, A::AbstractArray; dims)
892✔
3191
    isempty(dims) && return map(f, A)
446✔
3192

3193
    for d in dims
566✔
3194
        d isa Integer || throw(ArgumentError("mapslices: dimension must be an integer, got $d"))
881✔
3195
        d >= 1 || throw(ArgumentError("mapslices: dimension must be ≥ 1, got $d"))
882✔
3196
        # Indexing a matrix M[:,1,:] produces a 1-column matrix, but dims=(1,3) here
3197
        # would otherwise ignore 3, and slice M[:,i]. Previously this gave error:
3198
        # BoundsError: attempt to access 2-element Vector{Any} at index [3]
3199
        d > ndims(A) && throw(ArgumentError("mapslices does not accept dimensions > ndims(A) = $(ndims(A)), got $d"))
880✔
3200
    end
1,176✔
3201
    dim_mask = ntuple(d -> d in dims, ndims(A))
4,233✔
3202

3203
    # Apply the function to the first slice in order to determine the next steps
3204
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
3,156✔
3205
    Aslice = A[idx1...]
829✔
3206
    r1 = f(Aslice)
531✔
3207

3208
    res1 = if r1 isa AbstractArray && ndims(r1) > 0
447✔
3209
        n = sum(dim_mask)
29✔
3210
        if ndims(r1) > n && any(ntuple(d -> size(r1,d+n)>1, ndims(r1)-n))
33✔
3211
            s = size(r1)[1:n]
1✔
3212
            throw(DimensionMismatch("mapslices cannot assign slice f(x) of size $(size(r1)) into output of size $s"))
1✔
3213
        end
3214
        r1
28✔
3215
    else
3216
        # If the result of f on a single slice is a scalar then we add singleton
3217
        # dimensions. When adding the dimensions, we have to respect the
3218
        # index type of the input array (e.g. in the case of OffsetArrays)
3219
        _res1 = similar(Aslice, typeof(r1), reduced_indices(Aslice, 1:ndims(Aslice)))
432✔
3220
        _res1[begin] = r1
416✔
3221
        _res1
813✔
3222
    end
3223

3224
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3225
    din = Ref(0)
442✔
3226
    Rsize = ntuple(ndims(A)) do d
444✔
3227
        if d in dims
3,237✔
3228
            axes(res1, din[] += 1)
878✔
3229
        else
3230
            axes(A,d)
805✔
3231
        end
3232
    end
3233
    R = similar(res1, Rsize)
459✔
3234

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

3240
    # That skips the first element, which we already have:
3241
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
2,941✔
3242
    concatenate_setindex!(R, res1, ridx...)
455✔
3243

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

3251
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
468✔
3252
    return R
442✔
3253
end
3254

3255
@noinline function _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
442✔
3256
    must_extend = any(dim_mask .& size(R) .> 1)
2,010✔
3257
    if safe_for_reuse
442✔
3258
        # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
3259
        # so we can reuse Aslice
3260
        for I in indices
754✔
3261
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
11,173✔
3262
            _unsafe_getindex!(Aslice, A, idx...)
11,173✔
3263
            r = f(Aslice)
16,379✔
3264
            if r isa AbstractArray || must_extend
11,173✔
3265
                ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
65✔
3266
                R[ridx...] = r
104✔
3267
            else
3268
                ridx = ifelse.(dim_mask, first.(axes(R)), Tuple(I))
11,108✔
3269
                R[ridx...] = r
11,108✔
3270
            end
3271
        end
11,173✔
3272
    else
3273
        # we can't guarantee safety (#18524), so allocate new storage for each slice
3274
        for I in indices
130✔
3275
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
1,857✔
3276
            ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
1,857✔
3277
            concatenate_setindex!(R, f(A[idx...]), ridx...)
1,870✔
3278
        end
1,857✔
3279
    end
3280
end
3281

3282
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
3,702✔
3283
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
448✔
3284

3285
## 0 arguments
3286

3287
map(f) = f()
1✔
3288

3289
## 1 argument
3290

3291
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
5,758✔
3292
    for (i,j) in zip(eachindex(dest),eachindex(A))
337,065,329✔
3293
        val = f(@inbounds A[j])
362,339,635✔
3294
        @inbounds dest[i] = val
211,376,349✔
3295
    end
266,033,285✔
3296
    return dest
180,548,096✔
3297
end
3298

3299
# map on collections
3300
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
134,706✔
3301

3302
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
2,967✔
3303
mapany(f, itr) = Any[f(x) for x in itr]
×
3304

3305
"""
3306
    map(f, c...) -> collection
3307

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

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

3313
# Examples
3314
```jldoctest
3315
julia> map(x -> x * 2, [1, 2, 3])
3316
3-element Vector{Int64}:
3317
 2
3318
 4
3319
 6
3320

3321
julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3322
3-element Vector{Int64}:
3323
 11
3324
 22
3325
 33
3326
```
3327
"""
3328
map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
440✔
3329

3330
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3331
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3332

3333
## 2 argument
3334
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
364✔
3335
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
715✔
3336
        @inbounds a, b = A[j], B[k]
387,240✔
3337
        val = f(a, b)
338,192✔
3338
        @inbounds dest[i] = val
338,192✔
3339
    end
676,033✔
3340
    return dest
364✔
3341
end
3342

3343
## N argument
3344

3345
@inline ith_all(i, ::Tuple{}) = ()
4,030✔
3346
function ith_all(i, as)
12,090✔
3347
    @_propagate_inbounds_meta
12,090✔
3348
    return (as[1][i], ith_all(i, tail(as))...)
18,930✔
3349
end
3350

3351
function map_n!(f::F, dest::AbstractArray, As) where F
46✔
3352
    idxs1 = LinearIndices(As[1])
46✔
3353
    @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
368✔
3354
    for i = idxs1
92✔
3355
        @inbounds I = ith_all(i, As)
6,550✔
3356
        val = f(I...)
4,030✔
3357
        @inbounds dest[i] = val
4,030✔
3358
    end
8,014✔
3359
    return dest
46✔
3360
end
3361

3362
"""
3363
    map!(function, destination, collection...)
3364

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

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

3370
# Examples
3371
```jldoctest
3372
julia> a = zeros(3);
3373

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

3376
julia> a
3377
3-element Vector{Float64}:
3378
 2.0
3379
 4.0
3380
 6.0
3381

3382
julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3383
5-element Vector{$(Int)}:
3384
 101
3385
 103
3386
 105
3387
   0
3388
   0
3389
```
3390
"""
3391
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
47✔
3392
    isempty(As) && throw(ArgumentError(
47✔
3393
        """map! requires at least one "source" argument"""))
3394
    map_n!(f, dest, As)
46✔
3395
end
3396

3397
"""
3398
    map(f, A::AbstractArray...) -> N-array
3399

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

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

3405
# Examples
3406
```
3407
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3408
2×2 Matrix{Rational{$Int}}:
3409
 1//4  2//3
3410
 3//2  4//1
3411

3412
julia> map(+, [1 2; 3 4], zeros(2,1))
3413
ERROR: DimensionMismatch
3414

3415
julia> map(+, [1 2; 3 4], [1,10,100,1000], zeros(3,1))  # iterates until 3rd is exhausted
3416
3-element Vector{Float64}:
3417
   2.0
3418
  13.0
3419
 102.0
3420
```
3421
"""
3422
map(f, iters...) = collect(Generator(f, iters...))
711✔
3423

3424
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3425
# (note: must not cause a dispatch loop when 1-item case is not defined)
3426
push!(A, a, b) = push!(push!(A, a), b)
995✔
3427
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
2✔
3428
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
3429
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
2✔
3430

3431
## hashing AbstractArray ##
3432

3433
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3434
function hash(A::AbstractArray, h::UInt)
16,753✔
3435
    h += hash_abstractarray_seed
16,753✔
3436
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3437
    # Instead hash the tuple of firsts and lasts along each dimension
3438
    h = hash(map(first, axes(A)), h)
16,990✔
3439
    h = hash(map(last, axes(A)), h)
16,990✔
3440

3441
    # For short arrays, it's not worth doing anything complicated
3442
    if length(A) < 8192
16,990✔
3443
        for x in A
22,088✔
3444
            h = hash(x, h)
2,296,479✔
3445
        end
2,112,593✔
3446
        return h
16,749✔
3447
    end
3448

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

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

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

3470
    # Start at the last index
3471
    keyidx = last(ks)
4✔
3472
    linidx = key_to_linear[keyidx]
4✔
3473
    fibskip = prevfibskip = oneunit(linidx)
4✔
3474
    first_linear = first(LinearIndices(linear_to_key))
4✔
3475
    n = 0
4✔
3476
    while true
28,192✔
3477
        n += 1
28,192✔
3478
        # Hash the element
3479
        elt = A[keyidx]
28,192✔
3480
        h = hash(keyidx=>elt, h)
28,192✔
3481

3482
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3483
        linidx = key_to_linear[keyidx]
28,192✔
3484
        linidx < fibskip + first_linear && break
28,192✔
3485
        linidx -= fibskip
28,188✔
3486
        keyidx = linear_to_key[linidx]
28,188✔
3487

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

3498
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3499
        keyidx = findprev(!isequal(elt), A, keyidx)
56,376✔
3500
        keyidx === nothing && break
28,188✔
3501
    end
28,188✔
3502

3503
    return h
4✔
3504
end
3505

3506
# The semantics of `collect` are weird. Better to write our own
3507
function rest(a::AbstractArray{T}, state...) where {T}
11✔
3508
    v = Vector{T}(undef, 0)
11✔
3509
    # assume only very few items are taken from the front
3510
    sizehint!(v, length(a))
11✔
3511
    return foldl(push!, Iterators.rest(a, state...), init=v)
11✔
3512
end
3513

3514

3515
## keepat! ##
3516

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

3519
function _keepat!(a::AbstractVector, inds)
11✔
3520
    local prev
11✔
3521
    i = firstindex(a)
11✔
3522
    for k in inds
19✔
3523
        if @isdefined(prev)
34✔
3524
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
27✔
3525
        end
3526
        ak = a[k] # must happen even when i==k for bounds checking
32✔
3527
        if i != k
29✔
3528
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
13✔
3529
        end
3530
        prev = k
29✔
3531
        i = nextind(a, i)
29✔
3532
    end
51✔
3533
    deleteat!(a, i:lastindex(a))
11✔
3534
    return a
6✔
3535
end
3536

3537
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
5✔
3538
    length(m) == length(a) || throw(BoundsError(a, m))
7✔
3539
    j = firstindex(a)
3✔
3540
    for i in eachindex(a, m)
5✔
3541
        @inbounds begin
20✔
3542
            if m[i]
20✔
3543
                i == j || (a[j] = a[i])
14✔
3544
                j = nextind(a, j)
7✔
3545
            end
3546
        end
3547
    end
38✔
3548
    deleteat!(a, j:lastindex(a))
3✔
3549
end
3550

3551
## 1-d circshift ##
3552
function circshift!(a::AbstractVector, shift::Integer)
1,101✔
3553
    n = length(a)
1,101✔
3554
    n == 0 && return
1,101✔
3555
    shift = mod(shift, n)
2,202✔
3556
    shift == 0 && return
1,101✔
3557
    l = lastindex(a)
677✔
3558
    reverse!(a, firstindex(a), l-shift)
677✔
3559
    reverse!(a, l-shift+1, lastindex(a))
677✔
3560
    reverse!(a)
677✔
3561
    return a
677✔
3562
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