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

JuliaLang / julia / #37639

03 Oct 2023 12:30AM UTC coverage: 86.356% (-1.1%) from 87.461%
#37639

push

local

web-flow
Bump libunwind. (#51545)

Fixes https://github.com/JuliaLang/julia/issues/51465, caused by
https://github.com/libunwind/libunwind/pull/203.
Ref https://github.com/JuliaPackaging/Yggdrasil/pull/7466

72846 of 84355 relevant lines covered (86.36%)

11563052.54 hits per line

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

92.17
/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
52,842✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
5,293✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
6,699✔
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,693,683✔
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,331,601✔
76
    @inline
66,331,381✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
66,336,984✔
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)
155,605,075✔
97
    @inline
98,561,164✔
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)...)
461,829✔
111
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
176,122✔
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...)
413,899✔
115
has_offset_axes(::Colon) = false
1,171✔
116
has_offset_axes(::Array) = false
623,159✔
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,351,157✔
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))
28,949✔
163
keys(a::AbstractVector) = LinearIndices(a)
58,031,995✔
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))
14,141✔
186
keytype(::Type{Union{}}, slurp...) = eltype(Union{})
×
187

188
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
2✔
189
keytype(A::Type{<:AbstractVector}) = Int
14,141✔
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
137,613✔
213
nextind(::AbstractArray, i::Integer) = Int(i)+1
247,356,031✔
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
13,928✔
237
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
3✔
238
eltype(x) = eltype(typeof(x))
5,373,918✔
239
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
3,377,039✔
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,753,191✔
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
827,612✔
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)))
14,370,945✔
313

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

317
# eachindex iterates over all indices. IndexCartesian definitions are later.
318
eachindex(A::AbstractVector) = (@inline(); axes1(A))
1,168,203,642✔
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))
141,801✔
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)))
7,742,646✔
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,815,375,917✔
424
lastindex(a, d) = (@inline; last(axes(a, d)))
3,430✔
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)))
1,844,048✔
447
firstindex(a, d) = (@inline; first(axes(a, d)))
2,677✔
448

449
first(a::AbstractArray) = a[first(eachindex(a))]
395,035✔
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)
3,164,711✔
469
    x = iterate(itr)
6,311,160✔
470
    x === nothing && throw(ArgumentError("collection must be non-empty"))
3,164,712✔
471
    x[1]
3,164,710✔
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))
34✔
500
# Faster method for vectors
501
function first(v::AbstractVector, n::Integer)
1,476✔
502
    n < 0 && throw(ArgumentError("Number of elements must be non-negative"))
1,476✔
503
    v[range(begin, length=min(n, checked_length(v)))]
1,474✔
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]
82,191,417✔
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)))
57✔
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...)...)
297,159✔
604
size_to_strides(s, d) = (s,)
292,829✔
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)
×
614
    s = 1
×
615
    for i=n:ndims(A)
×
616
        s *= size(A,i)
×
617
    end
×
618
    return s
×
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...)
97,309,721✔
677
    @inline
97,309,721✔
678
    checkbounds_indices(Bool, axes(A), I)
97,340,066✔
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)
88,243,705✔
683
    @inline
79,700,956✔
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...)
841,175,952✔
698
    @inline
172,814,406✔
699
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
841,314,761✔
700
    nothing
841,315,084✔
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)
304,655,265✔
724
    @inline
139,029,945✔
725
    checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
304,901,505✔
726
end
727
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
21,502✔
728
    @inline
3,667✔
729
    checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
257,512✔
730
end
731
checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
577,847✔
732
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
×
733

734
throw_boundserror(A, I) = (@noinline; throw(BoundsError(A, I)))
589✔
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))
6,068,678✔
759
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
3,049,766✔
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
464✔
762
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
103,651✔
763
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
9,095,357✔
764
    @_propagate_inbounds_meta
1,211,200✔
765
    isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
405,384,605✔
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)
5,762✔
770
    @inline
483✔
771
    b = true
483✔
772
    for i in I
7,927✔
773
        b &= checkindex(Bool, inds, i)
6,247,211✔
774
    end
6,254,492✔
775
    b
7,541✔
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,083✔
827
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
4,182✔
828
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
62,021,686✔
829
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
803✔
830
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
5,635,531✔
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))
141,918✔
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)
5,616,046✔
840

841
to_shape(::Tuple{}) = ()
18✔
842
to_shape(dims::Dims) = dims
6,576✔
843
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
6,842,400✔
844
# each dimension
845
to_shape(i::Int) = i
33✔
846
to_shape(i::Integer) = Int(i)
41✔
847
to_shape(r::OneTo) = Int(last(r))
227,388✔
848
to_shape(r::AbstractUnitRange) = r
188✔
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)
14✔
873
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
439,933,204✔
874
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
439,933,240✔
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}()
332✔
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}()
212✔
897
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
56✔
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)
11,466,885✔
915
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
79✔
916
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
917
    if length(dst) != length(src)
68,800,895✔
918
        resize!(dst, length(src))
68,800,815✔
919
    end
920
    copyto!(dst, src)
68,800,895✔
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)
14✔
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)
3,750,457✔
936
    destiter = eachindex(dest)
3,761,794✔
937
    y = iterate(destiter)
4,956,088✔
938
    for x in src
6,099,876✔
939
        y === nothing &&
4,034,848✔
940
            throw(ArgumentError("destination has fewer elements than required"))
941
        dest[y[1]] = x
4,034,967✔
942
        y = iterate(destiter, y[2])
6,875,181✔
943
    end
6,484,757✔
944
    return dest
3,761,792✔
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)
128,882✔
995
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
128,882✔
996
        ", elements, but n should be non-negative")))
997
    n == 0 && return dest
128,881✔
998
    dmax = dstart + n - 1
128,880✔
999
    inds = LinearIndices(dest)
128,880✔
1000
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
257,758✔
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)
128,876✔
1006
    for j = 1:(sstart-1)
229,174✔
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)
128,875✔
1015
    while i <= dmax && y !== nothing
9,243,151✔
1016
        val, st = y
9,000,004✔
1017
        @inbounds dest[i] = val
9,114,276✔
1018
        y = iterate(src, st)
9,142,853✔
1019
        i += 1
9,114,276✔
1020
    end
9,114,276✔
1021
    i <= dmax && throw(BoundsError(dest, i))
128,875✔
1022
    return dest
128,874✔
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,746,266✔
1057
    isempty(src) && return dest
2,920,510✔
1058
    if dest isa BitArray
2,608,241✔
1059
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1060
        return _copyto_bitarray!(dest, src)
1✔
1061
    end
1062
    src′ = unalias(dest, src)
2,944,320✔
1063
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,920,101✔
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,779,930✔
1073
    isempty(src) && return dest
2,920,101✔
1074
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,920,102✔
1075
    idf, isf = first(destinds), first(srcinds)
2,608,083✔
1076
    Δi = idf - isf
2,608,083✔
1077
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,920,102✔
1078
        throw(BoundsError(dest, srcinds))
1079
    if deststyle isa IndexLinear
2,608,082✔
1080
        if srcstyle isa IndexLinear
2,603,989✔
1081
            # Single-index implementation
1082
            @inbounds for i in srcinds
5,272,004✔
1083
                dest[i + Δi] = src[i]
35,610,855✔
1084
            end
68,578,895✔
1085
        else
1086
            # Dual-index implementation
1087
            i = idf - 1
118,569✔
1088
            @inbounds for a in src
559,965✔
1089
                dest[i+=1] = a
2,187,740✔
1090
            end
4,088,106✔
1091
        end
1092
    else
1093
        iterdest, itersrc = eachindex(dest), eachindex(src)
4,093✔
1094
        if iterdest == itersrc
4,093✔
1095
            # Shared-iterator implementation
1096
            for I in iterdest
2,308✔
1097
                @inbounds dest[I] = src[I]
6,190,748✔
1098
            end
12,101,933✔
1099
        else
1100
            # Dual-iterator implementation
1101
            ret = iterate(iterdest)
5,878✔
1102
            @inbounds for a in src
4,984✔
1103
                idx, state = ret::NTuple{2,Any}
2,033,771✔
1104
                dest[idx] = a
2,033,771✔
1105
                ret = iterate(iterdest, state)
2,036,711✔
1106
            end
4,032,997✔
1107
        end
1108
    end
1109
    return dest
2,920,100✔
1110
end
1111

1112
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
20,761✔
1113
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
20,769✔
1114
end
1115

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

1122
function copyto!(dest::AbstractArray, dstart::Integer,
408,237✔
1123
               src::AbstractArray, sstart::Integer,
1124
               n::Integer)
1125
    n == 0 && return dest
408,237✔
1126
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
408,235✔
1127
        n," elements, but n should be non-negative")))
1128
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
408,234✔
1129
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
408,246✔
1130
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
408,225✔
1131
    src′ = unalias(dest, src)
408,264✔
1132
    @inbounds for i = 0:n-1
816,438✔
1133
        dest[dstart+i] = src′[sstart+i]
20,939,680✔
1134
    end
41,471,141✔
1135
    return dest
408,219✔
1136
end
1137

1138
function copy(a::AbstractArray)
146,932✔
1139
    @_propagate_inbounds_meta
146,932✔
1140
    copymutable(a)
147,654✔
1141
end
1142

1143
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
3,594✔
1144
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1145
    if length(ir_dest) != length(ir_src)
3,594✔
1146
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1147
            length(ir_src)," and ",length(ir_dest),")")))
1148
    end
1149
    if length(jr_dest) != length(jr_src)
3,593✔
1150
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1151
            length(jr_src)," and ",length(jr_dest),")")))
1152
    end
1153
    @boundscheck checkbounds(B, ir_dest, jr_dest)
3,593✔
1154
    @boundscheck checkbounds(A, ir_src, jr_src)
3,593✔
1155
    A′ = unalias(B, A)
7,184✔
1156
    jdest = first(jr_dest)
3,593✔
1157
    for jsrc in jr_src
7,186✔
1158
        idest = first(ir_dest)
20,420✔
1159
        for isrc in ir_src
40,840✔
1160
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
198,852✔
1161
            idest += step(ir_dest)
198,692✔
1162
        end
376,964✔
1163
        jdest += step(jr_dest)
20,420✔
1164
    end
37,247✔
1165
    return B
3,593✔
1166
end
1167

1168
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
215,223✔
1169

1170
function copyto_axcheck!(dest, src)
32,687✔
1171
    _checkaxs(axes(dest), axes(src))
194,428✔
1172
    copyto!(dest, src)
371,387✔
1173
end
1174

1175
"""
1176
    copymutable(a)
1177

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

1183
# Examples
1184
```jldoctest
1185
julia> tup = (1, 2, 3)
1186
(1, 2, 3)
1187

1188
julia> Base.copymutable(tup)
1189
3-element Vector{Int64}:
1190
 1
1191
 2
1192
 3
1193
```
1194
"""
1195
function copymutable(a::AbstractArray)
148,255✔
1196
    @_propagate_inbounds_meta
147,790✔
1197
    copyto!(similar(a), a)
154,060✔
1198
end
1199
copymutable(itr) = collect(itr)
7✔
1200

1201
zero(x::AbstractArray{T}) where {T} = fill!(similar(x, typeof(zero(T))), zero(T))
15,612✔
1202

1203
## iteration support for arrays by iterating over `eachindex` in the array ##
1204
# Allows fast iteration by default for both IndexLinear and IndexCartesian arrays
1205

1206
# While the definitions for IndexLinear are all simple enough to inline on their
1207
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1208
# inlining.
1209
function iterate(A::AbstractArray, state=(eachindex(A),))
109,640,598✔
1210
    y = iterate(state...)
135,738,857✔
1211
    y === nothing && return nothing
111,956,232✔
1212
    A[y[1]], (state[1], tail(y)...)
111,300,667✔
1213
end
1214

1215
isempty(a::AbstractArray) = (length(a) == 0)
2,147,483,647✔
1216

1217

1218
## range conversions ##
1219

1220
map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
2✔
1221
map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
40✔
1222
map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
6✔
1223
function map(::Type{T}, r::LinRange) where T<:AbstractFloat
1✔
1224
    LinRange(T(r.start), T(r.stop), length(r))
1✔
1225
end
1226

1227
## unsafe/pointer conversions ##
1228

1229
# note: the following type definitions don't mean any AbstractArray is convertible to
1230
# a data Ref. they just map the array element type to the pointer type for
1231
# convenience in cases that work.
1232
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, x)
45,372,825✔
1233
function pointer(x::AbstractArray{T}, i::Integer) where T
9,068,199✔
1234
    @inline
5,240,466✔
1235
    unsafe_convert(Ptr{T}, x) + Int(_memory_offset(x, i))::Int
404,140,987✔
1236
end
1237

1238
# The distance from pointer(x) to the element at x[I...] in bytes
1239
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
343,935,958✔
1240
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
70,193✔
1241
    J = _to_subscript_indices(x, I...)
70,193✔
1242
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
271,283✔
1243
end
1244

1245
## Approach:
1246
# We only define one fallback method on getindex for all argument types.
1247
# That dispatches to an (inlined) internal _getindex function, where the goal is
1248
# to transform the indices such that we can call the only getindex method that
1249
# we require the type A{T,N} <: AbstractArray{T,N} to define; either:
1250
#       getindex(::A, ::Int) # if IndexStyle(A) == IndexLinear() OR
1251
#       getindex(::A{T,N}, ::Vararg{Int, N}) where {T,N} # if IndexCartesian()
1252
# If the subtype hasn't defined the required method, it falls back to the
1253
# _getindex function again where an error is thrown to prevent stack overflows.
1254
"""
1255
    getindex(A, inds...)
1256

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

1260
When `inds` selects multiple elements, this function returns a newly
1261
allocated array. To index multiple elements without making a copy,
1262
use [`view`](@ref) instead.
1263

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

1266
# Examples
1267
```jldoctest
1268
julia> A = [1 2; 3 4]
1269
2×2 Matrix{Int64}:
1270
 1  2
1271
 3  4
1272

1273
julia> getindex(A, 1)
1274
1
1275

1276
julia> getindex(A, [2, 1])
1277
2-element Vector{Int64}:
1278
 3
1279
 1
1280

1281
julia> getindex(A, 2:4)
1282
3-element Vector{Int64}:
1283
 3
1284
 2
1285
 4
1286
```
1287
"""
1288
function getindex(A::AbstractArray, I...)
94,090,660✔
1289
    @_propagate_inbounds_meta
94,086,118✔
1290
    error_if_canonical_getindex(IndexStyle(A), A, I...)
94,086,118✔
1291
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
238,647,044✔
1292
end
1293
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1294
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
207,048,375✔
1295

1296
@inline unsafe_getindex(A::AbstractArray, I...) = @inbounds getindex(A, I...)
387✔
1297

1298
struct CanonicalIndexError <: Exception
1299
    func::String
1300
    type::Any
1301
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
14✔
1302
end
1303

1304
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
2✔
1305
    throw(CanonicalIndexError("getindex", typeof(A)))
1306
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
3✔
1307
    throw(CanonicalIndexError("getindex", typeof(A)))
1308
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
94,086,064✔
1309

1310
## Internal definitions
1311
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1312
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1313

1314
## IndexLinear Scalar indexing: canonical method is one Int
1315
_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)
20,404,841✔
1316
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
×
1317
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
1,291,268✔
1318
    @inline
1,291,268✔
1319
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
38,471,936✔
1320
    @inbounds r = getindex(A, _to_linear_index(A, I...))
38,471,883✔
1321
    r
38,471,874✔
1322
end
1323
_to_linear_index(A::AbstractArray, i::Integer) = i
143,703✔
1324
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
1,973,309✔
1325
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
289,004✔
1326
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
1,112,015✔
1327

1328
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1329
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
260,527✔
1330
    @inline
260,527✔
1331
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
260,540✔
1332
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
280,362✔
1333
    r
260,513✔
1334
end
1335
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
91,798,400✔
1336
    @_propagate_inbounds_meta
91,798,400✔
1337
    getindex(A, I...)
179,046,706✔
1338
end
1339
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
251,640✔
1340
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1341
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1342
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
5✔
1343
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1344
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
80,112✔
1345
    @inline
80,112✔
1346
    J, Jrem = IteratorsMD.split(I, Val(N))
80,112✔
1347
    _to_subscript_indices(A, J, Jrem)
80,112✔
1348
end
1349
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1350
    __to_subscript_indices(A, axes(A), J, Jrem)
1351
function __to_subscript_indices(A::AbstractArray,
2✔
1352
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1353
    @inline
2✔
1354
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1355
end
1356
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
80,110✔
1357
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
24,502✔
1358
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1359
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1360
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1361
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
251,640✔
1362

1363
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1364
# function that allows dispatch on array storage
1365

1366
"""
1367
    setindex!(A, X, inds...)
1368
    A[inds...] = X
1369

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

1373
# Examples
1374
```jldoctest
1375
julia> A = zeros(2,2);
1376

1377
julia> setindex!(A, [10, 20], [1, 2]);
1378

1379
julia> A[[3, 4]] = [30, 40];
1380

1381
julia> A
1382
2×2 Matrix{Float64}:
1383
 10.0  30.0
1384
 20.0  40.0
1385
```
1386
"""
1387
function setindex!(A::AbstractArray, v, I...)
2,991,918✔
1388
    @_propagate_inbounds_meta
2,991,918✔
1389
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,991,918✔
1390
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
3,195,343✔
1391
end
1392
function unsafe_setindex!(A::AbstractArray, v, I...)
732✔
1393
    @inline
732✔
1394
    @inbounds r = setindex!(A, v, I...)
732✔
1395
    r
730✔
1396
end
1397

1398
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
7✔
1399
    throw(CanonicalIndexError("setindex!", typeof(A)))
1400
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
2✔
1401
    throw(CanonicalIndexError("setindex!", typeof(A)))
1402
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
2,991,909✔
1403

1404
## Internal definitions
1405
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1406
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1407

1408
## IndexLinear Scalar indexing
1409
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
412,870✔
1410
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
213,840✔
1411
    @inline
207,834✔
1412
    @boundscheck checkbounds(A, I...)
218,675✔
1413
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
218,638✔
1414
    r
218,637✔
1415
end
1416

1417
# IndexCartesian Scalar indexing
1418
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
2,324,094✔
1419
    @_propagate_inbounds_meta
2,324,094✔
1420
    setindex!(A, v, I...)
2,324,193✔
1421
end
1422
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
22,805✔
1423
    @inline
22,805✔
1424
    @boundscheck checkbounds(A, I...)
22,810✔
1425
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
28,374✔
1426
    r
22,800✔
1427
end
1428

1429
"""
1430
    parent(A)
1431

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

1437
# Examples
1438
```jldoctest
1439
julia> A = [1 2; 3 4]
1440
2×2 Matrix{Int64}:
1441
 1  2
1442
 3  4
1443

1444
julia> V = view(A, 1:2, :)
1445
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1446
 1  2
1447
 3  4
1448

1449
julia> parent(V)
1450
2×2 Matrix{Int64}:
1451
 1  2
1452
 3  4
1453
```
1454
"""
1455
function parent end
1456

1457
parent(a::AbstractArray) = a
1,925✔
1458

1459
## rudimentary aliasing detection ##
1460
"""
1461
    Base.unalias(dest, A)
1462

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

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

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

1473
See also [`Base.mightalias`](@ref).
1474
"""
1475
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
8,557,139✔
1476
unalias(dest, A::AbstractRange) = A
2,330,950✔
1477
unalias(dest, A) = A
2,607,989✔
1478

1479
"""
1480
    Base.unaliascopy(A)
1481

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

1485
This must return an object of the same type as `A` to preserve optimal performance in the
1486
much more common case where aliasing does not occur. By default,
1487
`unaliascopy(A::AbstractArray)` will attempt to use [`copy(A)`](@ref), but in cases where
1488
`copy(A)` is not a `typeof(A)`, then the array should provide a custom implementation of
1489
`Base.unaliascopy(A)`.
1490
"""
1491
unaliascopy(A::Array) = copy(A)
189✔
1492
unaliascopy(A::AbstractArray)::typeof(A) = (@noinline; _unaliascopy(A, copy(A)))
4✔
1493
_unaliascopy(A::T, C::T) where {T} = C
4✔
1494
_unaliascopy(A, C) = throw(ArgumentError("""
×
1495
    an array of type `$(typename(typeof(A)).wrapper)` shares memory with another argument
1496
    and must make a preventative copy of itself in order to maintain consistent semantics,
1497
    but `copy(::$(typeof(A)))` returns a new array of type `$(typeof(C))`.
1498
    To fix, implement:
1499
        `Base.unaliascopy(A::$(typename(typeof(A)).wrapper))::typeof(A)`"""))
1500
unaliascopy(A) = A
×
1501

1502
"""
1503
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1504

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

1507
By default, this simply checks if either of the arrays reference the same memory
1508
regions, as identified by their [`Base.dataids`](@ref).
1509
"""
1510
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !_isdisjoint(dataids(A), dataids(B))
5,921,261✔
1511
mightalias(x, y) = false
×
1512

1513
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1514
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1515
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1516
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
9✔
1517
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
5,809,687✔
1518
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
78,444✔
1519
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1520
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
2,076✔
1521
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
78,786✔
1522

1523
"""
1524
    Base.dataids(A::AbstractArray)
1525

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

1528
Custom arrays that would like to opt-in to aliasing detection of their component
1529
parts can specialize this method to return the concatenation of the `dataids` of
1530
their component parts.  A typical definition for an array that wraps a parent is
1531
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1532
"""
1533
dataids(A::AbstractArray) = (UInt(objectid(A)),)
307,728✔
1534
dataids(A::Array) = (UInt(pointer(A)),)
11,425,545✔
1535
dataids(::AbstractRange) = ()
2,496,995✔
1536
dataids(x) = ()
2,662✔
1537

1538
## get (getindex with a default value) ##
1539

1540
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1541
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1542

1543
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
11✔
1544
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
8✔
1545
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
16✔
1546
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
4✔
1547
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
8✔
1548
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
9✔
1549

1550
function get!(X::AbstractVector{T}, A::AbstractVector, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
×
1551
    # 1d is not linear indexing
1552
    ind = findall(in(axes1(A)), I)
×
1553
    X[ind] = A[I[ind]]
×
1554
    Xind = axes1(X)
×
1555
    X[first(Xind):first(ind)-1] = default
×
1556
    X[last(ind)+1:last(Xind)] = default
×
1557
    X
×
1558
end
1559
function get!(X::AbstractArray{T}, A::AbstractArray, I::Union{AbstractRange,AbstractVector{Int}}, default::T) where T
1✔
1560
    # Linear indexing
1561
    ind = findall(in(1:length(A)), I)
1✔
1562
    X[ind] = A[I[ind]]
5✔
1563
    fill!(view(X, 1:first(ind)-1), default)
6✔
1564
    fill!(view(X, last(ind)+1:length(X)), default)
1✔
1565
    X
1✔
1566
end
1567

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

1570
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
2✔
1571
    fill!(X, default)
72✔
1572
    dst, src = indcopy(size(A), I)
2✔
1573
    X[dst...] = A[src...]
2✔
1574
    X
2✔
1575
end
1576

1577
get(A::AbstractArray, I::RangeVecIntList, default) =
2✔
1578
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1579

1580
## structured matrix methods ##
1581
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
23,884✔
1582
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
5,648✔
1583

1584
## Concatenation ##
1585
eltypeof(x) = typeof(x)
21,305✔
1586
eltypeof(x::AbstractArray) = eltype(x)
1,251✔
1587

1588
promote_eltypeof() = error()
×
1589
promote_eltypeof(v1) = eltypeof(v1)
581✔
1590
promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...))
21,898✔
1591
promote_eltypeof(v1::T, vs::T...) where {T} = eltypeof(v1)
112✔
1592
promote_eltypeof(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
7,530✔
1593

1594
promote_eltype() = error()
×
1595
promote_eltype(v1) = eltype(v1)
124✔
1596
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
2,206✔
1597
promote_eltype(v1::T, vs::T...) where {T} = eltype(T)
11,492✔
1598
promote_eltype(v1::AbstractArray{T}, vs::AbstractArray{T}...) where {T} = T
3,091✔
1599

1600
#TODO: ERROR CHECK
1601
_cat(catdim::Int) = Vector{Any}()
1✔
1602

1603
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1604
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1605

1606
## cat: special cases
1607
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
277✔
1608
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
174✔
1609
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
70✔
1610
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
449✔
1611

1612
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
34✔
1613
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
44✔
1614
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
10✔
1615
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
60✔
1616

1617
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
4✔
1618
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
4✔
1619

1620
# FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1621
# and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1622
# but that solution currently fails (see #27188 and #27224)
1623
AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1624

1625
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
791,869✔
1626
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
811,907✔
1627
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1628

1629
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
791,869✔
1630
    pos = 1
791,868✔
1631
    for k=1:Int(length(V))::Int
791,879✔
1632
        Vk = V[k]
792,809✔
1633
        p1 = pos + Int(length(Vk))::Int - 1
792,836✔
1634
        a[pos:p1] = Vk
5,701,980✔
1635
        pos = p1+1
792,809✔
1636
    end
793,749✔
1637
    a
791,869✔
1638
end
1639

1640
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
1,030✔
1641

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

1649

1650
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
296✔
1651
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
270✔
1652

1653
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
1,036✔
1654
    nargs = length(A)
1,036✔
1655
    nrows = size(A[1], 1)
1,036✔
1656
    ncols = 0
1,036✔
1657
    dense = true
1,036✔
1658
    for j = 1:nargs
1,042✔
1659
        Aj = A[j]
2,124✔
1660
        if size(Aj, 1) != nrows
2,910✔
1661
            throw(DimensionMismatch("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1662
        end
1663
        dense &= isa(Aj,Array)
2,123✔
1664
        nd = ndims(Aj)
2,908✔
1665
        ncols += (nd==2 ? size(Aj,2) : 1)
2,604✔
1666
    end
3,211✔
1667
    B = similar(A[1], T, nrows, ncols)
1,035✔
1668
    pos = 1
1,035✔
1669
    if dense
1,035✔
1670
        for k=1:nargs
405✔
1671
            Ak = A[k]
828✔
1672
            n = length(Ak)
1,048✔
1673
            copyto!(B, pos, Ak, 1, n)
1,046✔
1674
            pos += n
828✔
1675
        end
1,253✔
1676
    else
1677
        for k=1:nargs
636✔
1678
            Ak = A[k]
1,294✔
1679
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
1,567✔
1680
            B[:, pos:p1] = Ak
1,696✔
1681
            pos = p1+1
1,294✔
1682
        end
1,820✔
1683
    end
1684
    return B
1,035✔
1685
end
1686

1687
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
65✔
1688
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
206✔
1689

1690
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
476✔
1691
    nargs = length(A)
476✔
1692
    nrows = sum(a->size(a, 1), A)::Int
1,556✔
1693
    ncols = size(A[1], 2)
476✔
1694
    for j = 2:nargs
477✔
1695
        if size(A[j], 2) != ncols
572✔
1696
            throw(DimensionMismatch("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1697
        end
1698
    end
647✔
1699
    B = similar(A[1], T, nrows, ncols)
475✔
1700
    pos = 1
475✔
1701
    for k=1:nargs
476✔
1702
        Ak = A[k]
1,028✔
1703
        p1 = pos+size(Ak,1)::Int-1
1,209✔
1704
        B[pos:p1, :] = Ak
1,084✔
1705
        pos = p1+1
1,028✔
1706
    end
1,581✔
1707
    return B
475✔
1708
end
1709

1710
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
812,234✔
1711

1712
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1713
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1714

1715
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1716
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1717

1718
## cat: general case
1719

1720
# helper functions
1721
cat_size(A) = (1,)
22,233✔
1722
cat_size(A::AbstractArray) = size(A)
16,222✔
1723
cat_size(A, d) = 1
22,646✔
1724
cat_size(A::AbstractArray, d) = size(A, d)
24,342✔
1725

1726
cat_length(::Any) = 1
100✔
1727
cat_length(a::AbstractArray) = length(a)
472✔
1728

1729
cat_ndims(a) = 0
183✔
1730
cat_ndims(a::AbstractArray) = ndims(a)
684✔
1731

1732
cat_indices(A, d) = OneTo(1)
22,234✔
1733
cat_indices(A::AbstractArray, d) = axes(A, d)
17,745✔
1734

1735
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
7,317✔
1736
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1737
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,321✔
1738
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1739
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
501✔
1740
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
2✔
1741

1742
# These are for backwards compatibility (even though internal)
1743
cat_shape(dims, shape::Tuple{Vararg{Int}}) = shape
×
1744
function cat_shape(dims, shapes::Tuple)
4✔
1745
    out_shape = ()
4✔
1746
    for s in shapes
4✔
1747
        out_shape = _cshp(1, dims, out_shape, s)
18✔
1748
    end
15✔
1749
    return out_shape
4✔
1750
end
1751
# The new way to compute the shape (more inferable than combining cat_size & cat_shape, due to Varargs + issue#36454)
1752
cat_size_shape(dims) = ntuple(zero, Val(length(dims)))
×
1753
@inline cat_size_shape(dims, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, (), cat_size(X)), tail...)
9,231✔
1754
_cat_size_shape(dims, shape) = shape
1,408✔
1755
@inline _cat_size_shape(dims, shape, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, shape, cat_size(X)), tail...)
29,556✔
1756

1757
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1758
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
18✔
1759
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
465✔
1760
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
684✔
1761
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1762
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
3,018✔
1763
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1764
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
21✔
1765
    _cs(ndim, shape[1], 1)
23✔
1766
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
19✔
1767
end
1768
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
154✔
1769
    next = _cs(ndim, shape[1], nshape[1])
154✔
1770
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
154✔
1771
end
1772
@inline function _cshp(ndim::Int, dims, shape, nshape)
30,277✔
1773
    a = shape[1]
30,218✔
1774
    b = nshape[1]
30,218✔
1775
    next = dims[1] ? a + b : _cs(ndim, a, b)
30,812✔
1776
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
30,462✔
1777
end
1778

1779
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
967✔
1780
    "mismatch in dimension $d (expected $a got $b)")))
1781

1782
dims2cat(::Val{dims}) where dims = dims2cat(dims)
7,796✔
1783
function dims2cat(dims)
8,614✔
1784
    if any(≤(0), dims)
10,208✔
1785
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1786
    end
1787
    ntuple(in(dims), maximum(dims))
8,653✔
1788
end
1789

1790
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
8,191✔
1791

1792
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
8,958✔
1793
    catdims = dims2cat(dims)
8,995✔
1794
    shape = cat_size_shape(catdims, X...)
9,231✔
1795
    A = cat_similar(X[1], T, shape)
9,107✔
1796
    if count(!iszero, catdims)::Int > 1
8,952✔
1797
        fill!(A, zero(T))
791✔
1798
    end
1799
    return __cat(A, shape, catdims, X...)
9,635✔
1800
end
1801
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1802
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1803
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1804

1805
# Why isn't this called `__cat!`?
1806
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
9,639✔
1807

1808
function __cat_offset!(A, shape, catdims, offsets, x, X...)
38,480✔
1809
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1810
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
39,165✔
1811
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
38,636✔
1812
end
1813
__cat_offset!(A, shape, catdims, offsets) = A
8,954✔
1814

1815
function __cat_offset1!(A, shape, catdims, offsets, x)
38,325✔
1816
    inds = ntuple(length(offsets)) do i
38,786✔
1817
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
42,131✔
1818
    end
1819
    _copy_or_fill!(A, inds, x)
127,116✔
1820
    newoffsets = ntuple(length(offsets)) do i
38,634✔
1821
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
42,514✔
1822
    end
1823
    return newoffsets
38,634✔
1824
end
1825

1826
_copy_or_fill!(A, inds, x) = fill!(view(A, inds...), x)
22,384✔
1827
_copy_or_fill!(A, inds, x::AbstractArray) = (A[inds...] = x)
104,696✔
1828

1829
"""
1830
    vcat(A...)
1831

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

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

1838
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1839

1840
# Examples
1841
```jldoctest
1842
julia> v = vcat([1,2], [3,4])
1843
4-element Vector{Int64}:
1844
 1
1845
 2
1846
 3
1847
 4
1848

1849
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1850
true
1851

1852
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1853
true
1854

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

1858
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1859
3-element Vector{Float64}:
1860
 1.0
1861
 1.5
1862
 2.0
1863

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

1867
julia> vcat(two...)
1868
3×3 Matrix{Float64}:
1869
 10.0  20.0  30.0
1870
  4.0   5.0   6.0
1871
  7.0   8.0   9.0
1872

1873
julia> vs = [[1, 2], [3, 4], [5, 6]];
1874

1875
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1876
6-element Vector{Int64}:
1877
 1
1878
 2
1879
 3
1880
 4
1881
 5
1882
 6
1883

1884
julia> ans == collect(Iterators.flatten(vs))
1885
true
1886
```
1887
"""
1888
vcat(X...) = cat(X...; dims=Val(1))
535✔
1889
"""
1890
    hcat(A...)
1891

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

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

1899
See also [`vcat`](@ref), [`hvcat`](@ref).
1900

1901
# Examples
1902
```jldoctest
1903
julia> hcat([1,2], [3,4], [5,6])
1904
2×3 Matrix{Int64}:
1905
 1  3  5
1906
 2  4  6
1907

1908
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1909
1×7 Matrix{Int64}:
1910
 1  2  30  40  5  6  7
1911

1912
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1913
true
1914

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

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

1921
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
1922
2×6 Matrix{Float64}:
1923
 0.0  0.0  1.0  2.0  50.0  60.0
1924
 0.0  0.0  3.0  4.0  70.0  80.0
1925

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

1929
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
1930
0×3 Matrix{Int64}
1931

1932
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
1933
2×1 Matrix{Any}:
1934
 1.1
1935
 9.9
1936
```
1937
"""
1938
hcat(X...) = cat(X...; dims=Val(2))
9✔
1939

1940
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
189✔
1941
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
280✔
1942

1943
"""
1944
    cat(A...; dims)
1945

1946
Concatenate the input arrays along the dimensions specified in `dims`.
1947

1948
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
1949
a in A)`.
1950
Along other dimensions, all input arrays should have the same size,
1951
which will also be the size of the output array along those dimensions.
1952

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

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

1962
The keyword also accepts `Val(dims)`.
1963

1964
!!! compat "Julia 1.8"
1965
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
1966

1967
# Examples
1968
```jldoctest
1969
julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2)  # same as hcat
1970
2×6×1 Array{Float64, 3}:
1971
[:, :, 1] =
1972
 1.0  2.0  3.14159  10.0  10.0  10.0
1973
 3.0  4.0  3.14159  10.0  10.0  10.0
1974

1975
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
1976
4×7 Matrix{Bool}:
1977
 1  0  0  0  0  0  0
1978
 0  1  1  0  0  0  0
1979
 0  1  1  0  0  0  0
1980
 0  0  0  1  1  1  1
1981

1982
julia> cat(1, [2], [3;;]; dims=Val(2))
1983
1×3 Matrix{Int64}:
1984
 1  2  3
1985
```
1986
"""
1987
@inline cat(A...; dims) = _cat(dims, A...)
17,318✔
1988
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
1989
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
215✔
1990

1991
# The specializations for 1 and 2 inputs are important
1992
# especially when running with --inline=no, see #11158
1993
vcat(A::AbstractArray) = cat(A; dims=Val(1))
1✔
1994
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
3✔
1995
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
1996
vcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(1))
6,988✔
1997
hcat(A::AbstractArray) = cat(A; dims=Val(2))
1✔
1998
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
1✔
1999
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
1✔
2000
hcat(A::Union{AbstractArray,Number}...) = cat(A...; dims=Val(2))
6✔
2001

2002
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
2003
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
2004
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
2005
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
2006
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
2007
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
2008

2009
# 2d horizontal and vertical concatenation
2010

2011
# these are produced in lowering if splatting occurs inside hvcat
2012
hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
3✔
2013
typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
3✔
2014

2015
function hvcat(nbc::Int, as...)
10✔
2016
    # nbc = # of block columns
2017
    n = length(as)
10✔
2018
    mod(n,nbc) != 0 &&
20✔
2019
        throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc"))
2020
    nbr = div(n,nbc)
9✔
2021
    hvcat(ntuple(Returns(nbc), nbr), as...)
9✔
2022
end
2023

2024
"""
2025
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2026

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

2032
# Examples
2033
```jldoctest
2034
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2035
(1, 2, 3, 4, 5, 6)
2036

2037
julia> [a b c; d e f]
2038
2×3 Matrix{Int64}:
2039
 1  2  3
2040
 4  5  6
2041

2042
julia> hvcat((3,3), a,b,c,d,e,f)
2043
2×3 Matrix{Int64}:
2044
 1  2  3
2045
 4  5  6
2046

2047
julia> [a b; c d; e f]
2048
3×2 Matrix{Int64}:
2049
 1  2
2050
 3  4
2051
 5  6
2052

2053
julia> hvcat((2,2,2), a,b,c,d,e,f)
2054
3×2 Matrix{Int64}:
2055
 1  2
2056
 3  4
2057
 5  6
2058
julia> hvcat((2,2,2), a,b,c,d,e,f) == hvcat(2, a,b,c,d,e,f)
2059
true
2060
```
2061
"""
2062
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
322✔
2063
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractArray{T}...) where {T} = typed_hvcat(T, rows, xs...)
516✔
2064

2065
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T
879✔
2066
    nbr = length(rows)  # number of block rows
879✔
2067

2068
    nc = 0
879✔
2069
    for i=1:rows[1]
1,758✔
2070
        nc += size(as[i],2)
2,699✔
2071
    end
2,493✔
2072

2073
    nr = 0
879✔
2074
    a = 1
879✔
2075
    for i = 1:nbr
879✔
2076
        nr += size(as[a],1)
1,783✔
2077
        a += rows[i]
1,421✔
2078
    end
1,963✔
2079

2080
    out = similar(as[1], T, nr, nc)
879✔
2081

2082
    a = 1
879✔
2083
    r = 1
879✔
2084
    for i = 1:nbr
879✔
2085
        c = 1
1,421✔
2086
        szi = size(as[a],1)
1,783✔
2087
        for j = 1:rows[i]
2,842✔
2088
            Aj = as[a+j-1]
2,609✔
2089
            szj = size(Aj,2)
3,896✔
2090
            if size(Aj,1) != szi
3,896✔
2091
                throw(DimensionMismatch("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
1✔
2092
            end
2093
            if c-1+szj > nc
3,895✔
2094
                throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
1✔
2095
            end
2096
            out[r:r-1+szi, c:c-1+szj] = Aj
3,823✔
2097
            c += szj
2,607✔
2098
        end
3,795✔
2099
        if c != nc+1
1,419✔
2100
            throw(DimensionMismatch("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
1✔
2101
        end
2102
        r += szi
1,418✔
2103
        a += rows[i]
1,418✔
2104
    end
1,960✔
2105
    out
876✔
2106
end
2107

2108
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
2109
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2110

2111
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,273✔
2112
    nr = length(rows)
1,248✔
2113
    nc = rows[1]
1,273✔
2114

2115
    a = Matrix{T}(undef, nr, nc)
1,273✔
2116
    if length(a) != length(xs)
1,273✔
2117
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2118
    end
2119
    k = 1
1,246✔
2120
    @inbounds for i=1:nr
1,296✔
2121
        if nc != rows[i]
3,446✔
2122
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2123
        end
2124
        for j=1:nc
6,890✔
2125
            a[i,j] = xs[k]
9,426✔
2126
            k += 1
9,426✔
2127
        end
15,407✔
2128
    end
5,620✔
2129
    a
1,270✔
2130
end
2131

2132
function hvcat_fill!(a::Array, xs::Tuple)
541✔
2133
    nr, nc = size(a,1), size(a,2)
541✔
2134
    len = length(xs)
541✔
2135
    if nr*nc != len
541✔
2136
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2137
    end
2138
    k = 1
540✔
2139
    for i=1:nr
1,080✔
2140
        @inbounds for j=1:nc
2,876✔
2141
            a[i,j] = xs[k]
9,567✔
2142
            k += 1
8,890✔
2143
        end
16,342✔
2144
    end
2,336✔
2145
    a
540✔
2146
end
2147

2148
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
172✔
2149
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
114✔
2150
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2151
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractArray,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
3✔
2152

2153
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
395✔
2154
    nr = length(rows)
395✔
2155
    nc = rows[1]
395✔
2156
    for i = 2:nr
395✔
2157
        if nc != rows[i]
775✔
2158
            throw(DimensionMismatch("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2✔
2159
        end
2160
    end
1,153✔
2161
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
393✔
2162
end
2163

2164
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T
124✔
2165
    nbr = length(rows)  # number of block rows
124✔
2166
    rs = Vector{Any}(undef, nbr)
124✔
2167
    a = 1
124✔
2168
    for i = 1:nbr
124✔
2169
        rs[i] = typed_hcat(T, as[a:a-1+rows[i]]...)
439✔
2170
        a += rows[i]
318✔
2171
    end
512✔
2172
    T[rs...;]
124✔
2173
end
2174

2175
## N-dimensional concatenation ##
2176

2177
"""
2178
    hvncat(dim::Int, row_first, values...)
2179
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2180
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2181

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

2184
This function is called for block matrix syntax. The first argument either specifies the
2185
shape of the concatenation, similar to `hvcat`, as a tuple of tuples, or the dimensions that
2186
specify the key number of elements along each axis, and is used to determine the output
2187
dimensions. The `dims` form is more performant, and is used by default when the concatenation
2188
operation has the same number of elements along each axis (e.g., [a b; c d;;; e f ; g h]).
2189
The `shape` form is used when the number of elements along each axis is unbalanced
2190
(e.g., [a b ; c]). Unbalanced syntax needs additional validation overhead. The `dim` form
2191
is an optimization for concatenation along just one dimension. `row_first` indicates how
2192
`values` are ordered. The meaning of the first and second elements of `shape` are also
2193
swapped based on `row_first`.
2194

2195
# Examples
2196
```jldoctest
2197
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2198
(1, 2, 3, 4, 5, 6)
2199

2200
julia> [a b c;;; d e f]
2201
1×3×2 Array{Int64, 3}:
2202
[:, :, 1] =
2203
 1  2  3
2204

2205
[:, :, 2] =
2206
 4  5  6
2207

2208
julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2209
2×1×3 Array{Int64, 3}:
2210
[:, :, 1] =
2211
 1
2212
 2
2213

2214
[:, :, 2] =
2215
 3
2216
 4
2217

2218
[:, :, 3] =
2219
 5
2220
 6
2221

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

2227
[:, :, 2] =
2228
 3  4
2229

2230
[:, :, 3] =
2231
 5  6
2232

2233
julia> hvncat(((3, 3), (3, 3), (6,)), true, a, b, c, d, e, f)
2234
1×3×2 Array{Int64, 3}:
2235
[:, :, 1] =
2236
 1  2  3
2237

2238
[:, :, 2] =
2239
 4  5  6
2240
```
2241

2242
# Examples for construction of the arguments
2243
```
2244
[a b c ; d e f ;;;
2245
 g h i ; j k l ;;;
2246
 m n o ; p q r ;;;
2247
 s t u ; v w x]
2248
⇒ dims = (2, 3, 4)
2249

2250
[a b ; c ;;; d ;;;;]
2251
 ___   _     _
2252
 2     1     1 = elements in each row (2, 1, 1)
2253
 _______     _
2254
 3           1 = elements in each column (3, 1)
2255
 _____________
2256
 4             = elements in each 3d slice (4,)
2257
 _____________
2258
 4             = elements in each 4d slice (4,)
2259
⇒ shape = ((2, 1, 1), (3, 1), (4,), (4,)) with `row_first` = true
2260
```
2261
"""
2262
hvncat(dimsshape::Tuple, row_first::Bool, xs...) = _hvncat(dimsshape, row_first, xs...)
262✔
2263
hvncat(dim::Int, xs...) = _hvncat(dim, true, xs...)
77✔
2264

2265
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
29✔
2266
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
91✔
2267
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
88✔
2268
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
2269
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2270
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
132✔
2271

2272

2273
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
17✔
2274
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2275

2276
# 1-dimensional hvncat methods
2277

2278
_typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
4✔
2279
_typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
×
2280
_typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
4✔
2281
_typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
4✔
2282
_typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
×
2283
_typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
4✔
2284
_typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
×
2285

2286
_typed_hvncat_0d_only_one() =
8✔
2287
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2288

2289
# `@constprop :aggressive` here to form constant `Val(dim)` type to get type stability
2290
@constprop :aggressive _typed_hvncat(T::Type, dim::Int, ::Bool, xs...) = _typed_hvncat(T, Val(dim), xs...) # catches from _hvncat type promoters
77✔
2291

2292
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
15✔
2293
    N < 0 &&
15✔
2294
        throw(ArgumentError("concatenation dimension must be non-negative"))
2295
    return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
40✔
2296
end
2297

2298
function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
38✔
2299
    N < 0 &&
38✔
2300
        throw(ArgumentError("concatenation dimension must be non-negative"))
2301
    A = cat_similar(xs[1], T, (ntuple(x -> 1, Val(N - 1))..., length(xs)))
83✔
2302
    hvncat_fill!(A, false, xs)
37✔
2303
    return A
37✔
2304
end
2305

2306
function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N}
25✔
2307
    # optimization for arrays that can be concatenated by copying them linearly into the destination
2308
    # conditions: the elements must all have 1-length dimensions above N
2309
    length(as) > 0 ||
25✔
2310
        throw(ArgumentError("must have at least one element"))
2311
    N < 0 &&
25✔
2312
        throw(ArgumentError("concatenation dimension must be non-negative"))
2313
    for a ∈ as
23✔
2314
        ndims(a) <= N || all(x -> size(a, x) == 1, (N + 1):ndims(a)) ||
54✔
2315
            return _typed_hvncat(T, (ntuple(x -> 1, Val(N - 1))..., length(as), 1), false, as...)
9✔
2316
            # the extra 1 is to avoid an infinite cycle
2317
    end
46✔
2318

2319
    nd = N
17✔
2320

2321
    Ndim = 0
17✔
2322
    for i ∈ eachindex(as)
18✔
2323
        Ndim += cat_size(as[i], N)
38✔
2324
        nd = max(nd, cat_ndims(as[i]))
38✔
2325
        for d ∈ 1:N - 1
32✔
2326
            cat_size(as[1], d) == cat_size(as[i], d) || throw(DimensionMismatch("mismatched size along axis $d in element $i"))
39✔
2327
        end
44✔
2328
    end
43✔
2329

2330
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
28✔
2331
    k = 1
13✔
2332
    for a ∈ as
13✔
2333
        for i ∈ eachindex(a)
44✔
2334
            A[k] = a[i]
36✔
2335
            k += 1
34✔
2336
        end
47✔
2337
    end
34✔
2338
    return A
13✔
2339
end
2340

2341
function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N}
14✔
2342
    length(as) > 0 ||
14✔
2343
        throw(ArgumentError("must have at least one element"))
2344
    N < 0 &&
14✔
2345
        throw(ArgumentError("concatenation dimension must be non-negative"))
2346
    nd = N
12✔
2347
    Ndim = 0
12✔
2348
    for i ∈ eachindex(as)
14✔
2349
        Ndim += cat_size(as[i], N)
30✔
2350
        nd = max(nd, cat_ndims(as[i]))
30✔
2351
        for d ∈ 1:N-1
20✔
2352
            cat_size(as[i], d) == 1 ||
36✔
2353
                throw(DimensionMismatch("all dimensions of element $i other than $N must be of length 1"))
2354
        end
28✔
2355
    end
20✔
2356

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

2359
    k = 1
4✔
2360
    for a ∈ as
4✔
2361
        if a isa AbstractArray
12✔
2362
            lena = length(a)
2✔
2363
            copyto!(A, k, a, 1, lena)
2✔
2364
            k += lena
2✔
2365
        else
2366
            A[k] = a
10✔
2367
            k += 1
10✔
2368
        end
2369
    end
16✔
2370
    return A
4✔
2371
end
2372

2373
# 0-dimensional cases for balanced and unbalanced hvncat method
2374

2375
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2376
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2377

2378

2379
# balanced dimensions hvncat methods
2380

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

2384
function _typed_hvncat_1d(::Type{T}, ds::Int, ::Val{row_first}, as...) where {T, row_first}
22✔
2385
    lengthas = length(as)
22✔
2386
    ds > 0 ||
22✔
2387
        throw(ArgumentError("`dimsshape` argument must consist of positive integers"))
2388
    lengthas == ds ||
30✔
2389
        throw(ArgumentError("number of elements does not match `dimshape` argument; expected $ds, got $lengthas"))
2390
    if row_first
14✔
2391
        return _typed_hvncat(T, Val(2), as...)
4✔
2392
    else
2393
        return _typed_hvncat(T, Val(1), as...)
10✔
2394
    end
2395
end
2396

2397
function _typed_hvncat(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, xs::Number...) where {T, N}
44✔
2398
    all(>(0), dims) ||
60✔
2399
        throw(ArgumentError("`dims` argument must contain positive integers"))
2400
    A = Array{T, N}(undef, dims...)
28✔
2401
    lengtha = length(A)  # Necessary to store result because throw blocks are being deoptimized right now, which leads to excessive allocations
28✔
2402
    lengthx = length(xs) # Cuts from 3 allocations to 1.
28✔
2403
    if lengtha != lengthx
28✔
2404
       throw(ArgumentError("argument count does not match specified shape (expected $lengtha, got $lengthx)"))
×
2405
    end
2406
    hvncat_fill!(A, row_first, xs)
28✔
2407
    return A
28✔
2408
end
2409

2410
function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
65✔
2411
    nr, nc = size(A, 1), size(A, 2)
65✔
2412
    na = prod(size(A)[3:end])
65✔
2413
    len = length(xs)
65✔
2414
    nrc = nr * nc
65✔
2415
    if nrc * na != len
65✔
2416
        throw(ArgumentError("argument count $(len) does not match specified shape $(size(A))"))
×
2417
    end
2418
    # putting these in separate functions leads to unnecessary allocations
2419
    if row_first
65✔
2420
        k = 1
17✔
2421
        for d ∈ 1:na
34✔
2422
            dd = nrc * (d - 1)
31✔
2423
            for i ∈ 1:nr
62✔
2424
                Ai = dd + i
42✔
2425
                for j ∈ 1:nc
84✔
2426
                    @inbounds A[Ai] = xs[k]
95✔
2427
                    k += 1
95✔
2428
                    Ai += nr
95✔
2429
                end
148✔
2430
            end
53✔
2431
        end
31✔
2432
    else
2433
        for k ∈ eachindex(xs)
48✔
2434
            @inbounds A[k] = xs[k]
95✔
2435
        end
95✔
2436
    end
2437
end
2438

2439
function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
90✔
2440
    # function barrier after calculating the max is necessary for high performance
2441
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
90✔
2442
    return _typed_hvncat_dims(T, (dims..., ntuple(x -> 1, nd - N)...), row_first, as)
124✔
2443
end
2444

2445
function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
90✔
2446
    length(as) > 0 ||
90✔
2447
        throw(ArgumentError("must have at least one element"))
2448
    all(>(0), dims) ||
122✔
2449
        throw(ArgumentError("`dims` argument must contain positive integers"))
2450

2451
    d1 = row_first ? 2 : 1
58✔
2452
    d2 = row_first ? 1 : 2
58✔
2453

2454
    outdims = zeros(Int, N)
203✔
2455

2456
    # validate shapes for lowest level of concatenation
2457
    d = findfirst(>(1), dims)
86✔
2458
    if d !== nothing # all dims are 1
58✔
2459
        if row_first && d < 3
57✔
2460
            d = d == 1 ? 2 : 1
32✔
2461
        end
2462
        nblocks = length(as) ÷ dims[d]
57✔
2463
        for b ∈ 1:nblocks
114✔
2464
            offset = ((b - 1) * dims[d])
175✔
2465
            startelementi = offset + 1
175✔
2466
            for i ∈ offset .+ (2:dims[d])
262✔
2467
                for dd ∈ 1:N
111✔
2468
                    dd == d && continue
316✔
2469
                    if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
217✔
2470
                        throw(DimensionMismatch("incompatible shape in element $i"))
6✔
2471
                    end
2472
                end
515✔
2473
            end
129✔
2474
        end
287✔
2475
    end
2476

2477
    # discover number of rows or columns
2478
    for i ∈ 1:dims[d1]
104✔
2479
        outdims[d1] += cat_size(as[i], d1)
140✔
2480
    end
164✔
2481

2482
    currentdims = zeros(Int, N)
176✔
2483
    blockcount = 0
52✔
2484
    elementcount = 0
52✔
2485
    for i ∈ eachindex(as)
52✔
2486
        elementcount += cat_length(as[i])
309✔
2487
        currentdims[d1] += cat_size(as[i], d1)
309✔
2488
        if currentdims[d1] == outdims[d1]
259✔
2489
            currentdims[d1] = 0
129✔
2490
            for d ∈ (d2, 3:N...)
129✔
2491
                currentdims[d] += cat_size(as[i], d)
258✔
2492
                if outdims[d] == 0 # unfixed dimension
203✔
2493
                    blockcount += 1
167✔
2494
                    if blockcount == dims[d]
167✔
2495
                        outdims[d] = currentdims[d]
88✔
2496
                        currentdims[d] = 0
88✔
2497
                        blockcount = 0
88✔
2498
                    else
2499
                        break
167✔
2500
                    end
2501
                else # fixed dimension
2502
                    if currentdims[d] == outdims[d] # end of dimension
36✔
2503
                        currentdims[d] = 0
23✔
2504
                    elseif currentdims[d] < outdims[d] # dimension in progress
13✔
2505
                        break
13✔
2506
                    else # exceeded dimension
2507
                        throw(DimensionMismatch("argument $i has too many elements along axis $d"))
×
2508
                    end
2509
                end
2510
            end
142✔
2511
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
130✔
2512
            throw(DimensionMismatch("argument $i has too many elements along axis $d1"))
16✔
2513
        end
2514
    end
450✔
2515

2516
    outlen = prod(outdims)
72✔
2517
    elementcount == outlen ||
36✔
2518
        throw(DimensionMismatch("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2519

2520
    # copy into final array
2521
    A = cat_similar(as[1], T, outdims)
36✔
2522
    # @assert all(==(0), currentdims)
2523
    outdims .= 0
108✔
2524
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
36✔
2525
    return A
36✔
2526
end
2527

2528

2529
# unbalanced dimensions hvncat methods
2530

2531
function _typed_hvncat(T::Type, shape::Tuple{Tuple}, row_first::Bool, xs...)
19✔
2532
    length(shape[1]) > 0 ||
19✔
2533
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2534
    return _typed_hvncat_1d(T, shape[1][1], Val(row_first), xs...)
13✔
2535
end
2536

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

2543
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
107✔
2544
    length(as) > 0 ||
107✔
2545
        throw(ArgumentError("must have at least one element"))
2546
    all(>(0), tuple((shape...)...)) ||
147✔
2547
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2548

2549
    d1 = row_first ? 2 : 1
67✔
2550
    d2 = row_first ? 1 : 2
67✔
2551

2552
    shapev = collect(shape) # saves allocations later
110✔
2553
    all(!isempty, shapev) ||
134✔
2554
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2555
    length(shapev[end]) == 1 ||
70✔
2556
        throw(ArgumentError("last level of shape must contain only one integer"))
2557
    shapelength = shapev[end][1]
64✔
2558
    lengthas = length(as)
64✔
2559
    shapelength == lengthas || throw(ArgumentError("number of elements does not match shape; expected $(shapelength), got $lengthas)"))
64✔
2560
    # discover dimensions
2561
    nd = max(N, cat_ndims(as[1]))
64✔
2562
    outdims = fill(-1, nd)
210✔
2563
    currentdims = zeros(Int, nd)
210✔
2564
    blockcounts = zeros(Int, nd)
210✔
2565
    shapepos = ones(Int, nd)
210✔
2566

2567
    elementcount = 0
64✔
2568
    for i ∈ eachindex(as)
64✔
2569
        elementcount += cat_length(as[i])
355✔
2570
        wasstartblock = false
313✔
2571
        for d ∈ 1:N
313✔
2572
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
907✔
2573
            dsize = cat_size(as[i], ad)
1,048✔
2574
            blockcounts[d] += 1
907✔
2575

2576
            if d == 1 || i == 1 || wasstartblock
1,501✔
2577
                currentdims[d] += dsize
623✔
2578
            elseif dsize != cat_size(as[i - 1], ad)
302✔
2579
                throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
8✔
2580
                                         expected $(cat_size(as[i - 1], ad)), got $dsize"))
2581
            end
2582

2583
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
899✔
2584

2585
            isendblock = blockcounts[d] == shapev[d][shapepos[d]]
899✔
2586
            if isendblock
899✔
2587
                if outdims[d] == -1
269✔
2588
                    outdims[d] = currentdims[d]
138✔
2589
                elseif outdims[d] != currentdims[d]
131✔
2590
                    throw(DimensionMismatch("argument $i has a mismatched number of elements along axis $ad; \
40✔
2591
                                             expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2592
                end
2593
                currentdims[d] = 0
229✔
2594
                blockcounts[d] = 0
229✔
2595
                shapepos[d] += 1
229✔
2596
                d > 1 && (blockcounts[d - 1] == 0 ||
230✔
2597
                    throw(DimensionMismatch("shape in level $d is inconsistent; level counts must nest \
2598
                                             evenly into each other")))
2599
            end
2600
        end
1,452✔
2601
    end
513✔
2602

2603
    outlen = prod(outdims)
30✔
2604
    elementcount == outlen ||
15✔
2605
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2606

2607
    if row_first
15✔
2608
        outdims[1], outdims[2] = outdims[2], outdims[1]
11✔
2609
    end
2610

2611
    # @assert all(==(0), currentdims)
2612
    # @assert all(==(0), blockcounts)
2613

2614
    # copy into final array
2615
    A = cat_similar(as[1], T, outdims)
15✔
2616
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
15✔
2617
    return A
15✔
2618
end
2619

2620
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int},
51✔
2621
                              d1::Int, d2::Int, as::Tuple) where {T, N}
2622
    N > 1 || throw(ArgumentError("dimensions of the destination array must be at least 2"))
51✔
2623
    length(scratch1) == length(scratch2) == N ||
51✔
2624
        throw(ArgumentError("scratch vectors must have as many elements as the destination array has dimensions"))
2625
    0 < d1 < 3 &&
51✔
2626
    0 < d2 < 3 &&
2627
    d1 != d2 ||
2628
        throw(ArgumentError("d1 and d2 must be either 1 or 2, exclusive."))
2629
    outdims = size(A)
51✔
2630
    offsets = scratch1
51✔
2631
    inneroffsets = scratch2
51✔
2632
    for a ∈ as
51✔
2633
        if isa(a, AbstractArray)
270✔
2634
            for ai ∈ a
266✔
2635
                @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
7,046✔
2636
                A[Ai] = ai
1,888✔
2637

2638
                @inbounds for j ∈ 1:N
1,888✔
2639
                    inneroffsets[j] += 1
4,152✔
2640
                    inneroffsets[j] < cat_size(a, j) && break
4,221✔
2641
                    inneroffsets[j] = 0
2,490✔
2642
                end
2,490✔
2643
            end
2,118✔
2644
        else
2645
            @inbounds Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
52✔
2646
            A[Ai] = a
30✔
2647
        end
2648

2649
        @inbounds for j ∈ (d1, d2, 3:N...)
270✔
2650
            offsets[j] += cat_size(a, j)
599✔
2651
            offsets[j] < outdims[j] && break
518✔
2652
            offsets[j] = 0
304✔
2653
        end
304✔
2654
    end
270✔
2655
end
2656

2657
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
1,915✔
2658
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2659
    Ai = inneroffsets[1] + offsets[1] + 1
1,915✔
2660
    for j ∈ 2:nd
1,915✔
2661
        increment = inneroffsets[j] + offsets[j]
7,098✔
2662
        for k ∈ 1:j-1
14,168✔
2663
            increment *= outdims[k]
17,209✔
2664
        end
27,320✔
2665
        Ai += increment
7,098✔
2666
    end
12,281✔
2667
    Ai
1,915✔
2668
end
2669

2670
"""
2671
    stack(iter; [dims])
2672

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

2676
By default the axes of the elements are placed first,
2677
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2678
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2679

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

2684
The various [`cat`](@ref) functions also combine arrays. However, these all
2685
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2686
the arrays along new dimensions.
2687
They also accept arrays as separate arguments, rather than a single collection.
2688

2689
!!! compat "Julia 1.9"
2690
    This function requires at least Julia 1.9.
2691

2692
# Examples
2693
```jldoctest
2694
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2695

2696
julia> mat = stack(vecs)
2697
2×3 Matrix{Float32}:
2698
 1.0  30.0  500.0
2699
 2.0  40.0  600.0
2700

2701
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2702
true
2703

2704
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2705
true
2706

2707
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2708
2×4 Matrix{Int64}:
2709
  1   2   3   4
2710
 10  11  12  13
2711

2712
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2713
true
2714

2715
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2716
3×2 Matrix{Float32}:
2717
   1.0    2.0
2718
  30.0   40.0
2719
 500.0  600.0
2720

2721
julia> x = rand(3,4);
2722

2723
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2724
true
2725
```
2726

2727
Higher-dimensional examples:
2728

2729
```jldoctest
2730
julia> A = rand(5, 7, 11);
2731

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

2734
julia> (element = size(first(E)), container = size(E))
2735
(element = (5, 11), container = (7,))
2736

2737
julia> stack(E) |> size
2738
(5, 11, 7)
2739

2740
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2741
true
2742

2743
julia> A == stack(E; dims=2)
2744
true
2745

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

2748
julia> (element = size(first(M)), container = size(M))
2749
(element = (2, 3), container = (5, 7))
2750

2751
julia> stack(M) |> size  # keeps all dimensions
2752
(2, 3, 5, 7)
2753

2754
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2755
(35, 2, 3)
2756

2757
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2758
(14, 15)
2759
```
2760
"""
2761
stack(iter; dims=:) = _stack(dims, iter)
250✔
2762

2763
"""
2764
    stack(f, args...; [dims])
2765

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

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

2773
See also [`mapslices`](@ref), [`eachcol`](@ref).
2774

2775
# Examples
2776
```jldoctest
2777
julia> stack(c -> (c, c-32), "julia")
2778
2×5 Matrix{Char}:
2779
 'j'  'u'  'l'  'i'  'a'
2780
 'J'  'U'  'L'  'I'  'A'
2781

2782
julia> stack(eachrow([1 2 3; 4 5 6]), (10, 100); dims=1) do row, n
2783
         vcat(row, row .* n, row ./ n)
2784
       end
2785
2×9 Matrix{Float64}:
2786
 1.0  2.0  3.0   10.0   20.0   30.0  0.1   0.2   0.3
2787
 4.0  5.0  6.0  400.0  500.0  600.0  0.04  0.05  0.06
2788
```
2789
"""
2790
stack(f, iter; dims=:) = _stack(dims, f(x) for x in iter)
12✔
2791
stack(f, xs, yzs...; dims=:) = _stack(dims, f(xy...) for xy in zip(xs, yzs...))
2✔
2792

2793
_stack(dims::Union{Integer, Colon}, iter) = _stack(dims, IteratorSize(iter), iter)
165✔
2794

2795
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2796

2797
function _stack(dims, ::Union{HasShape, HasLength}, iter)
122✔
2798
    S = @default_eltype iter
122✔
2799
    T = S != Union{} ? eltype(S) : Any  # Union{} occurs for e.g. stack(1,2), postpone the error
126✔
2800
    if isconcretetype(T)
122✔
2801
        _typed_stack(dims, T, S, iter)
103✔
2802
    else  # Need to look inside, but shouldn't run an expensive iterator twice:
2803
        array = iter isa Union{Tuple, AbstractArray} ? iter : collect(iter)
42✔
2804
        isempty(array) && return _empty_stack(dims, T, S, iter)
38✔
2805
        T2 = mapreduce(eltype, promote_type, array)
42✔
2806
        _typed_stack(dims, T2, eltype(array), array)
36✔
2807
    end
2808
end
2809

2810
function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
184✔
2811
    xit = iterate(A)
210✔
2812
    nothing === xit && return _empty_stack(:, T, S, A)
94✔
2813
    x1, _ = xit
94✔
2814
    ax1 = _iterator_axes(x1)
98✔
2815
    B = similar(_ensure_array(x1), T, ax1..., Aax...)
106✔
2816
    off = firstindex(B)
93✔
2817
    len = length(x1)
97✔
2818
    while xit !== nothing
2,563✔
2819
        x, state = xit
2,476✔
2820
        _stack_size_check(x, ax1)
4,654✔
2821
        copyto!(B, off, x)
2,474✔
2822
        off += len
2,470✔
2823
        xit = iterate(A, state)
3,798✔
2824
    end
2,470✔
2825
    B
87✔
2826
end
2827

2828
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2829
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2830
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2831

2832
# For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2833
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
51✔
2834
    _typed_stack(dims, T, S, IteratorSize(S), A)
2835
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasLength, A) where {T,S} =
13✔
2836
    _typed_stack(dims, T, S, HasShape{1}(), A)
2837
function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
27✔
2838
    if dims == N+1
27✔
2839
        _typed_stack(:, T, S, A, (_vec_axis(A),))
4✔
2840
    else
2841
        _dim_stack(dims, T, S, A)
23✔
2842
    end
2843
end
2844
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
2✔
2845
    _dim_stack(dims, T, S, A)
2846

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

2849
@constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
25✔
2850
    xit = Iterators.peel(A)
48✔
2851
    nothing === xit && return _empty_stack(dims, T, S, A)
25✔
2852
    x1, xrest = xit
25✔
2853
    ax1 = _iterator_axes(x1)
25✔
2854
    N1 = length(ax1)+1
24✔
2855
    dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
27✔
2856

2857
    newaxis = _vec_axis(A)
21✔
2858
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
141✔
2859
    B = similar(_ensure_array(x1), T, outax...)
23✔
2860

2861
    if dims == 1
21✔
2862
        _dim_stack!(Val(1), B, x1, xrest)
13✔
2863
    elseif dims == 2
8✔
2864
        _dim_stack!(Val(2), B, x1, xrest)
4✔
2865
    else
2866
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
2867
    end
2868
    B
18✔
2869
end
2870

2871
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
21✔
2872
    before = ntuple(d -> Colon(), dims - 1)
33✔
2873
    after = ntuple(d -> Colon(), ndims(B) - dims)
49✔
2874

2875
    i = firstindex(B, dims)
21✔
2876
    copyto!(view(B, before..., i, after...), x1)
40✔
2877

2878
    for x in xrest
29✔
2879
        _stack_size_check(x, _iterator_axes(x1))
6,422✔
2880
        i += 1
3,261✔
2881
        @inbounds copyto!(view(B, before..., i, after...), x)
6,415✔
2882
    end
3,261✔
2883
end
2884

2885
@inline function _stack_size_check(x, ax1::Tuple)
5,740✔
2886
    if _iterator_axes(x) != ax1
11,107✔
2887
        uax1 = map(UnitRange, ax1)
9✔
2888
        uaxN = map(UnitRange, axes(x))
9✔
2889
        throw(DimensionMismatch(
9✔
2890
            LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
2891
    end
2892
end
2893

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

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

2899

2900
## Reductions and accumulates ##
2901

2902
function isequal(A::AbstractArray, B::AbstractArray)
246,550✔
2903
    if A === B return true end
246,803✔
2904
    if axes(A) != axes(B)
489,661✔
2905
        return false
2,915✔
2906
    end
2907
    for (a, b) in zip(A, B)
486,196✔
2908
        if !isequal(a, b)
91,312,809✔
2909
            return false
474✔
2910
        end
2911
    end
182,178,284✔
2912
    return true
242,908✔
2913
end
2914

2915
function cmp(A::AbstractVector, B::AbstractVector)
331✔
2916
    for (a, b) in zip(A, B)
662✔
2917
        if !isequal(a, b)
792✔
2918
            return isless(a, b) ? -1 : 1
316✔
2919
        end
2920
    end
937✔
2921
    return cmp(length(A), length(B))
15✔
2922
end
2923

2924
"""
2925
    isless(A::AbstractVector, B::AbstractVector)
2926

2927
Return `true` when `A` is less than `B` in lexicographic order.
2928
"""
2929
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
322✔
2930

2931
function (==)(A::AbstractArray, B::AbstractArray)
6,569,473✔
2932
    if axes(A) != axes(B)
13,135,760✔
2933
        return false
3,573✔
2934
    end
2935
    anymissing = false
6,563,342✔
2936
    for (a, b) in zip(A, B)
12,245,639✔
2937
        eq = (a == b)
335,931,069✔
2938
        if ismissing(eq)
304,015,977✔
2939
            anymissing = true
24✔
2940
        elseif !eq
335,043,009✔
2941
            return false
2,771✔
2942
        end
2943
    end
664,403,739✔
2944
    return anymissing ? missing : true
6,563,362✔
2945
end
2946

2947
# _sub2ind and _ind2sub
2948
# fallbacks
2949
function _sub2ind(A::AbstractArray, I...)
1,087,150✔
2950
    @inline
1,087,150✔
2951
    _sub2ind(axes(A), I...)
1,112,015✔
2952
end
2953

2954
function _ind2sub(A::AbstractArray, ind)
251,641✔
2955
    @inline
251,641✔
2956
    _ind2sub(axes(A), ind)
251,641✔
2957
end
2958

2959
# 0-dimensional arrays and indexing with []
2960
_sub2ind(::Tuple{}) = 1
18✔
2961
_sub2ind(::DimsInteger) = 1
2✔
2962
_sub2ind(::Indices) = 1
×
2963
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
5✔
2964

2965
# Generic cases
2966
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
2,147,483,647✔
2967
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
1,230,164✔
2968
# In 1d, there's a question of whether we're doing cartesian indexing
2969
# or linear indexing. Support only the former.
2970
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
2971
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2972
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
2973
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
2974

2975
_sub2ind_recurse(::Any, L, ind) = ind
1,262,087✔
2976
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,794✔
2977
    @inline
867✔
2978
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
12,147✔
2979
end
2980
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
4,472,543✔
2981
    @inline
4,339,314✔
2982
    r1 = inds[1]
4,339,316✔
2983
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
2,147,483,647✔
2984
end
2985

2986
nextL(L, l::Integer) = L*l
1,415,982✔
2987
nextL(L, r::AbstractUnitRange) = L*length(r)
2,958,560✔
2988
nextL(L, r::Slice) = L*length(r.indices)
×
2989
offsetin(i, l::Integer) = i-1
2,147,483,647✔
2990
offsetin(i, r::AbstractUnitRange) = i-first(r)
2,983,425✔
2991

2992
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
2993
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
2,065✔
2994
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
251,653✔
2995
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
2996
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2997
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
12✔
2998

2999
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
3000
function _ind2sub_recurse(indslast::NTuple{1}, ind)
253,718✔
3001
    @inline
253,718✔
3002
    (_lookup(ind, indslast[1]),)
253,718✔
3003
end
3004
function _ind2sub_recurse(inds, ind)
416,055✔
3005
    @inline
416,055✔
3006
    r1 = inds[1]
416,055✔
3007
    indnext, f, l = _div(ind, r1)
416,055✔
3008
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
416,055✔
3009
end
3010

3011
_lookup(ind, d::Integer) = ind+1
2,065✔
3012
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
251,653✔
3013
_div(ind, d::Integer) = div(ind, d), 1, d
2,065✔
3014
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
827,980✔
3015

3016
# Vectorized forms
3017
function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
×
3018
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
×
3019
end
3020
_sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3021
    _sub2ind_vecs(inds, I1, I...)
3022
_sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
3023
    _sub2ind_vecs(inds, I1, I...)
3024
function _sub2ind_vecs(inds, I::AbstractVector...)
×
3025
    I1 = I[1]
×
3026
    Iinds = axes1(I1)
×
3027
    for j = 2:length(I)
×
3028
        axes1(I[j]) == Iinds || throw(DimensionMismatch("indices of I[1] ($(Iinds)) does not match indices of I[$j] ($(axes1(I[j])))"))
×
3029
    end
×
3030
    Iout = similar(I1)
×
3031
    _sub2ind!(Iout, inds, Iinds, I)
×
3032
    Iout
×
3033
end
3034

3035
function _sub2ind!(Iout, inds, Iinds, I)
×
3036
    @noinline
×
3037
    for i in Iinds
×
3038
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3039
        Iout[i] = sub2ind_vec(inds, i, I)
×
3040
    end
×
3041
    Iout
×
3042
end
3043

3044
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3045
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3046
_sub2ind_vec(i) = ()
×
3047

3048
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
×
3049
    M = length(ind)
×
3050
    t = ntuple(n->similar(ind),Val(N))
×
3051
    for (i,idx) in pairs(IndexLinear(), ind)
×
3052
        sub = _ind2sub(inds, idx)
×
3053
        for j = 1:N
×
3054
            t[j][i] = sub[j]
×
3055
        end
×
3056
    end
×
3057
    t
×
3058
end
3059

3060
## iteration utilities ##
3061

3062
"""
3063
    foreach(f, c...) -> Nothing
3064

3065
Call function `f` on each element of iterable `c`.
3066
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3067
any iterator is finished.
3068

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

3072
# Examples
3073
```jldoctest
3074
julia> tri = 1:3:7; res = Int[];
3075

3076
julia> foreach(x -> push!(res, x^2), tri)
3077

3078
julia> res
3079
3-element Vector{$(Int)}:
3080
  1
3081
 16
3082
 49
3083

3084
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3085
1 with a
3086
4 with b
3087
7 with c
3088
```
3089
"""
3090
foreach(f) = (f(); nothing)
2✔
3091
foreach(f, itr) = (for x in itr; f(x); end; nothing)
533,054,445✔
3092
foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing)
11✔
3093

3094
## map over arrays ##
3095

3096
## transform any set of dimensions
3097
## dims specifies which dimensions will be transformed. for example
3098
## dims==1:2 will call f on all slices A[:,:,...]
3099
"""
3100
    mapslices(f, A; dims)
3101

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

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

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

3111
# Examples
3112
```jldoctest
3113
julia> A = reshape(1:30,(2,5,3))
3114
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3115
[:, :, 1] =
3116
 1  3  5  7   9
3117
 2  4  6  8  10
3118

3119
[:, :, 2] =
3120
 11  13  15  17  19
3121
 12  14  16  18  20
3122

3123
[:, :, 3] =
3124
 21  23  25  27  29
3125
 22  24  26  28  30
3126

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

3129
julia> B = mapslices(f, A, dims=(1,2))
3130
1×4×3 Array{$Int, 3}:
3131
[:, :, 1] =
3132
 1  1  1  1
3133

3134
[:, :, 2] =
3135
 11  11  11  11
3136

3137
[:, :, 3] =
3138
 21  21  21  21
3139

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

3142
julia> B == stack(f2, eachslice(A, dims=3))
3143
true
3144

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

3147
julia> mapslices(g, A, dims=[1,3])
3148
1×5×1 Array{Rational{$Int}, 3}:
3149
[:, :, 1] =
3150
 1//21  3//23  1//5  7//27  9//29
3151

3152
julia> map(g, eachslice(A, dims=2))
3153
5-element Vector{Rational{$Int}}:
3154
 1//21
3155
 3//23
3156
 1//5
3157
 7//27
3158
 9//29
3159

3160
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3161
true
3162
```
3163

3164
Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3165
one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3166
`mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3167
values in the slice without affecting `A`.
3168
"""
3169
function mapslices(f, A::AbstractArray; dims)
892✔
3170
    isempty(dims) && return map(f, A)
446✔
3171

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

3182
    # Apply the function to the first slice in order to determine the next steps
3183
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
3,156✔
3184
    Aslice = A[idx1...]
829✔
3185
    r1 = f(Aslice)
531✔
3186

3187
    res1 = if r1 isa AbstractArray && ndims(r1) > 0
447✔
3188
        n = sum(dim_mask)
29✔
3189
        if ndims(r1) > n && any(ntuple(d -> size(r1,d+n)>1, ndims(r1)-n))
33✔
3190
            s = size(r1)[1:n]
1✔
3191
            throw(DimensionMismatch("mapslices cannot assign slice f(x) of size $(size(r1)) into output of size $s"))
1✔
3192
        end
3193
        r1
28✔
3194
    else
3195
        # If the result of f on a single slice is a scalar then we add singleton
3196
        # dimensions. When adding the dimensions, we have to respect the
3197
        # index type of the input array (e.g. in the case of OffsetArrays)
3198
        _res1 = similar(Aslice, typeof(r1), reduced_indices(Aslice, 1:ndims(Aslice)))
432✔
3199
        _res1[begin] = r1
414✔
3200
        _res1
813✔
3201
    end
3202

3203
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3204
    din = Ref(0)
442✔
3205
    Rsize = ntuple(ndims(A)) do d
444✔
3206
        if d in dims
3,237✔
3207
            axes(res1, din[] += 1)
878✔
3208
        else
3209
            axes(A,d)
805✔
3210
        end
3211
    end
3212
    R = similar(res1, Rsize)
459✔
3213

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

3219
    # That skips the first element, which we already have:
3220
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
2,581✔
3221
    concatenate_setindex!(R, res1, ridx...)
455✔
3222

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

3230
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
468✔
3231
    return R
442✔
3232
end
3233

3234
@noinline function _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
442✔
3235
    must_extend = any(dim_mask .& size(R) .> 1)
2,010✔
3236
    if safe_for_reuse
442✔
3237
        # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
3238
        # so we can reuse Aslice
3239
        for I in indices
418✔
3240
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
11,173✔
3241
            _unsafe_getindex!(Aslice, A, idx...)
11,173✔
3242
            r = f(Aslice)
15,359✔
3243
            if r isa AbstractArray || must_extend
11,173✔
3244
                ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
65✔
3245
                R[ridx...] = r
104✔
3246
            else
3247
                ridx = ifelse.(dim_mask, first.(axes(R)), Tuple(I))
11,108✔
3248
                R[ridx...] = r
11,108✔
3249
            end
3250
        end
11,173✔
3251
    else
3252
        # we can't guarantee safety (#18524), so allocate new storage for each slice
3253
        for I in indices
74✔
3254
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
1,857✔
3255
            ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
1,857✔
3256
            concatenate_setindex!(R, f(A[idx...]), ridx...)
1,870✔
3257
        end
1,857✔
3258
    end
3259
end
3260

3261
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
3,702✔
3262
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
448✔
3263

3264
## 0 arguments
3265

3266
map(f) = f()
1✔
3267

3268
## 1 argument
3269

3270
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3,565✔
3271
    for (i,j) in zip(eachindex(dest),eachindex(A))
306,918,107✔
3272
        val = f(@inbounds A[j])
328,426,764✔
3273
        @inbounds dest[i] = val
191,823,757✔
3274
    end
241,073,139✔
3275
    return dest
164,545,940✔
3276
end
3277

3278
# map on collections
3279
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
136,273✔
3280

3281
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
2,801✔
3282
mapany(f, itr) = Any[f(x) for x in itr]
×
3283

3284
"""
3285
    map(f, c...) -> collection
3286

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

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

3292
# Examples
3293
```jldoctest
3294
julia> map(x -> x * 2, [1, 2, 3])
3295
3-element Vector{Int64}:
3296
 2
3297
 4
3298
 6
3299

3300
julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3301
3-element Vector{Int64}:
3302
 11
3303
 22
3304
 33
3305
```
3306
"""
3307
map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
403✔
3308

3309
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3310
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3311

3312
## 2 argument
3313
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
370✔
3314
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
727✔
3315
        @inbounds a, b = A[j], B[k]
387,556✔
3316
        val = f(a, b)
338,222✔
3317
        @inbounds dest[i] = val
338,222✔
3318
    end
676,087✔
3319
    return dest
370✔
3320
end
3321

3322
## N argument
3323

3324
@inline ith_all(i, ::Tuple{}) = ()
4,030✔
3325
function ith_all(i, as)
12,090✔
3326
    @_propagate_inbounds_meta
12,090✔
3327
    return (as[1][i], ith_all(i, tail(as))...)
18,930✔
3328
end
3329

3330
function map_n!(f::F, dest::AbstractArray, As) where F
46✔
3331
    idxs1 = LinearIndices(As[1])
46✔
3332
    @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
368✔
3333
    for i = idxs1
92✔
3334
        @inbounds I = ith_all(i, As)
6,550✔
3335
        val = f(I...)
4,030✔
3336
        @inbounds dest[i] = val
4,030✔
3337
    end
8,014✔
3338
    return dest
46✔
3339
end
3340

3341
"""
3342
    map!(function, destination, collection...)
3343

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

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

3349
# Examples
3350
```jldoctest
3351
julia> a = zeros(3);
3352

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

3355
julia> a
3356
3-element Vector{Float64}:
3357
 2.0
3358
 4.0
3359
 6.0
3360

3361
julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3362
5-element Vector{$(Int)}:
3363
 101
3364
 103
3365
 105
3366
   0
3367
   0
3368
```
3369
"""
3370
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
47✔
3371
    isempty(As) && throw(ArgumentError(
47✔
3372
        """map! requires at least one "source" argument"""))
3373
    map_n!(f, dest, As)
46✔
3374
end
3375

3376
"""
3377
    map(f, A::AbstractArray...) -> N-array
3378

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

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

3384
# Examples
3385
```
3386
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3387
2×2 Matrix{Rational{$Int}}:
3388
 1//4  2//3
3389
 3//2  4//1
3390

3391
julia> map(+, [1 2; 3 4], zeros(2,1))
3392
ERROR: DimensionMismatch
3393

3394
julia> map(+, [1 2; 3 4], [1,10,100,1000], zeros(3,1))  # iterates until 3rd is exhausted
3395
3-element Vector{Float64}:
3396
   2.0
3397
  13.0
3398
 102.0
3399
```
3400
"""
3401
map(f, iters...) = collect(Generator(f, iters...))
1,203✔
3402

3403
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3404
# (note: must not cause a dispatch loop when 1-item case is not defined)
3405
push!(A, a, b) = push!(push!(A, a), b)
3✔
3406
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
2✔
3407
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
3408
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
2✔
3409

3410
## hashing AbstractArray ##
3411

3412
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3413
function hash(A::AbstractArray, h::UInt)
10,912✔
3414
    h += hash_abstractarray_seed
10,912✔
3415
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3416
    # Instead hash the tuple of firsts and lasts along each dimension
3417
    h = hash(map(first, axes(A)), h)
11,149✔
3418
    h = hash(map(last, axes(A)), h)
11,149✔
3419

3420
    # For short arrays, it's not worth doing anything complicated
3421
    if length(A) < 8192
11,149✔
3422
        for x in A
14,733✔
3423
            h = hash(x, h)
243,518✔
3424
        end
378,200✔
3425
        return h
10,908✔
3426
    end
3427

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

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

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

3449
    # Start at the last index
3450
    keyidx = last(ks)
4✔
3451
    linidx = key_to_linear[keyidx]
4✔
3452
    fibskip = prevfibskip = oneunit(linidx)
4✔
3453
    first_linear = first(LinearIndices(linear_to_key))
4✔
3454
    n = 0
4✔
3455
    while true
28,192✔
3456
        n += 1
28,192✔
3457
        # Hash the element
3458
        elt = A[keyidx]
28,192✔
3459
        h = hash(keyidx=>elt, h)
56,384✔
3460

3461
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3462
        linidx = key_to_linear[keyidx]
28,192✔
3463
        linidx < fibskip + first_linear && break
28,192✔
3464
        linidx -= fibskip
28,188✔
3465
        keyidx = linear_to_key[linidx]
28,188✔
3466

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

3477
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3478
        keyidx = findprev(!isequal(elt), A, keyidx)
56,376✔
3479
        keyidx === nothing && break
28,188✔
3480
    end
28,188✔
3481

3482
    return h
4✔
3483
end
3484

3485
# The semantics of `collect` are weird. Better to write our own
3486
function rest(a::AbstractArray{T}, state...) where {T}
11✔
3487
    v = Vector{T}(undef, 0)
11✔
3488
    # assume only very few items are taken from the front
3489
    sizehint!(v, length(a))
11✔
3490
    return foldl(push!, Iterators.rest(a, state...), init=v)
11✔
3491
end
3492

3493

3494
## keepat! ##
3495

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

3498
function _keepat!(a::AbstractVector, inds)
11✔
3499
    local prev
11✔
3500
    i = firstindex(a)
11✔
3501
    for k in inds
19✔
3502
        if @isdefined(prev)
34✔
3503
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
27✔
3504
        end
3505
        ak = a[k] # must happen even when i==k for bounds checking
32✔
3506
        if i != k
29✔
3507
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
13✔
3508
        end
3509
        prev = k
29✔
3510
        i = nextind(a, i)
29✔
3511
    end
51✔
3512
    deleteat!(a, i:lastindex(a))
11✔
3513
    return a
6✔
3514
end
3515

3516
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
5✔
3517
    length(m) == length(a) || throw(BoundsError(a, m))
7✔
3518
    j = firstindex(a)
3✔
3519
    for i in eachindex(a, m)
5✔
3520
        @inbounds begin
20✔
3521
            if m[i]
20✔
3522
                i == j || (a[j] = a[i])
16✔
3523
                j = nextind(a, j)
8✔
3524
            end
3525
        end
3526
    end
38✔
3527
    deleteat!(a, j:lastindex(a))
3✔
3528
end
3529

3530
## 1-d circshift ##
3531
function circshift!(a::AbstractVector, shift::Integer)
1,137✔
3532
    n = length(a)
1,137✔
3533
    n == 0 && return
1,137✔
3534
    shift = mod(shift, n)
2,274✔
3535
    shift == 0 && return
1,137✔
3536
    l = lastindex(a)
701✔
3537
    reverse!(a, firstindex(a), l-shift)
701✔
3538
    reverse!(a, l-shift+1, lastindex(a))
701✔
3539
    reverse!(a)
701✔
3540
    return a
701✔
3541
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