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

JuliaLang / julia / #37550

pending completion
#37550

push

local

web-flow
Extend comparison lifting to `Core.ifelse` (#49882)

This change extends our existing transformation for:
   φ(a,b) === Const(c)   =>   φ(a === c, b === c)

to perform the analogous transformation for `Core.ifelse`:
   Core.ifelse(cond, a, b) === Const(c)
  =>
   Core.ifelse(cond, a === c, b === c)

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

72705 of 83986 relevant lines covered (86.57%)

20561515.97 hits per line

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

91.75
/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
66,363✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
15,626✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
17,465✔
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,454,593✔
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}
904,346✔
76
    @inline
902,849✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
910,629✔
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)
185,525,933✔
97
    @inline
96,567,953✔
98
    map(oneto, size(A))
4,829,930,162✔
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)...)
915,381✔
111
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
280,870✔
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...)
548,785✔
115
has_offset_axes(::Colon) = false
67✔
116
has_offset_axes(::Array) = false
584,290✔
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"))
667,321✔
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])
4,917,021,453✔
135
axes1(iter) = oneto(length(iter))
1✔
136

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

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

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

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

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

158
julia> keys([4 5; 6 7])
159
CartesianIndices((2, 2))
160
```
161
"""
162
keys(a::AbstractArray) = CartesianIndices(axes(a))
29,073✔
163
keys(a::AbstractVector) = LinearIndices(a)
45,579,024✔
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))
22,651,000✔
186
keytype(::Type{Union{}}, slurp...) = eltype(Union{})
×
187

188
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
2✔
189
keytype(A::Type{<:AbstractVector}) = Int
22,651,000✔
190

191
valtype(a::AbstractArray) = valtype(typeof(a))
2✔
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)
4✔
211

212
prevind(::AbstractArray, i::Integer) = Int(i)-1
137,544✔
213
nextind(::AbstractArray, i::Integer) = Int(i)+1
179,209,301✔
214

215

216
"""
217
    eltype(type)
218

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

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

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

232
julia> eltype(fill(0x1, (2,2)))
233
UInt8
234
```
235
"""
236
eltype(::Type) = Any
14,067✔
237
eltype(::Type{Bottom}, slurp...) = throw(ArgumentError("Union{} does not have elements"))
5✔
238
eltype(x) = eltype(typeof(x))
3,742,385✔
239
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
2,593,739✔
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))
401,868✔
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
903,609✔
272
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N
57✔
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)))
15,824,479✔
313

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

317
# eachindex iterates over all indices. IndexCartesian definitions are later.
318
eachindex(A::AbstractVector) = (@inline(); axes1(A))
899,189,401✔
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))
139,559✔
376

377
function eachindex(A::AbstractArray, B::AbstractArray)
35✔
378
    @inline
35✔
379
    eachindex(IndexStyle(A,B), A, B)
35✔
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)))
11,717,569✔
386
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
3,827,199,200✔
387
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
32✔
388
    @inline
32✔
389
    indsA = eachindex(IndexLinear(), A)
32✔
390
    _all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
65✔
391
        throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
392
    indsA
31✔
393
end
394
function _all_match_first(f::F, inds, A, B...) where F<:Function
37✔
395
    @inline
37✔
396
    (inds == f(A)) & _all_match_first(f, inds, B...)
41✔
397
end
398
_all_match_first(f::F, inds) where F<:Function = true
37✔
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,178,475,778✔
424
lastindex(a, d) = (@inline; last(axes(a, d)))
3,440✔
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)))
907,226✔
447
firstindex(a, d) = (@inline; first(axes(a, d)))
2,677✔
448

449
first(a::AbstractArray) = a[first(eachindex(a))]
1,155,654✔
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)
2,938,401✔
469
    x = iterate(itr)
5,873,501✔
470
    x === nothing && throw(ArgumentError("collection must be non-empty"))
2,938,402✔
471
    x[1]
2,938,400✔
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,490✔
502
    n < 0 && throw(ArgumentError("Number of elements must be nonnegative"))
1,490✔
503
    v[range(begin, length=min(n, checked_length(v)))]
1,488✔
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]
25,140,739✔
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 nonnegative"))
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)
483✔
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...)...)
312,745✔
604
size_to_strides(s, d) = (s,)
107✔
605
size_to_strides(s) = ()
×
606

607
function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
4✔
608
    @boundscheck checkbounds(A, I...)
7✔
609
    return true
1✔
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...)
96,170,491✔
677
    @inline
96,170,491✔
678
    checkbounds_indices(Bool, axes(A), I)
97,573,040✔
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)
118,294,103✔
683
    @inline
110,716,301✔
684
    checkindex(Bool, eachindex(IndexLinear(), A), i)
2,674,532,319✔
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
33✔
688
    @inline
33✔
689
    axes(A) == axes(I)
64✔
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...)
659,842,004✔
698
    @inline
204,653,572✔
699
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
659,842,296✔
700
    nothing
659,839,487✔
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)
171,895,452✔
724
    @inline
11,720,452✔
725
    checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
307,192,343✔
726
end
727
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
23,142✔
728
    @inline
3,567✔
729
    checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
40,342✔
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)))
516✔
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))
4,789,060✔
759
checkindex(::Type{Bool}, inds::IdentityUnitRange, i::Real) = checkindex(Bool, inds.indices, i)
3,049,869✔
760
checkindex(::Type{Bool}, inds::OneTo{T}, i::T) where {T<:BitInteger} = unsigned(i - one(i)) < unsigned(last(inds))
3,303,052,755✔
761
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
460✔
762
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
75✔
763
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
1,145,874✔
764
    @_propagate_inbounds_meta
589,724✔
765
    isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
320,059,739✔
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)
4,717✔
770
    @inline
631✔
771
    b = true
631✔
772
    for i in I
7,982✔
773
        b &= checkindex(Bool, inds, i)
6,403,998✔
774
    end
6,434,388✔
775
    b
7,411✔
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)
3,807✔
827
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
3,881✔
828
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
57,855,703✔
829
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
818✔
830
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
5,161,991✔
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))
152,973✔
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,140,831✔
840

841
to_shape(::Tuple{}) = ()
18✔
842
to_shape(dims::Dims) = dims
5,559✔
843
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
2,086,560✔
844
# each dimension
845
to_shape(i::Int) = i
33✔
846
to_shape(i::Integer) = Int(i)
32✔
847
to_shape(r::OneTo) = Int(last(r))
40,590✔
848
to_shape(r::AbstractUnitRange) = r
196✔
849

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

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

857
**Examples**:
858

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

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

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

869
would create a 1-dimensional logical array whose indices match those
870
of the columns of `A`.
871
"""
872
similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
49✔
873
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
427,006,687✔
874
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
427,006,723✔
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}()
286✔
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}()
192✔
897
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
49✔
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)
50✔
915
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
50✔
916
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
917
    if length(dst) != length(src)
37,071,461✔
918
        resize!(dst, length(src))
37,071,381✔
919
    end
920
    copyto!(dst, src)
37,071,461✔
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)
4,082,071✔
936
    destiter = eachindex(dest)
4,082,110✔
937
    y = iterate(destiter)
5,524,714✔
938
    for x in src
6,685,479✔
939
        y === nothing &&
4,905,323✔
940
            throw(ArgumentError("destination has fewer elements than required"))
941
        dest[y[1]] = x
4,905,442✔
942
        y = iterate(destiter, y[2])
8,367,786✔
943
    end
7,861,067✔
944
    return dest
4,082,108✔
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)
10✔
995
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
10✔
996
        ", elements, but n should be nonnegative")))
997
    n == 0 && return dest
9✔
998
    dmax = dstart + n - 1
8✔
999
    inds = LinearIndices(dest)
8✔
1000
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
14✔
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)
4✔
1006
    for j = 1:(sstart-1)
7✔
1007
        if y === nothing
5✔
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])
4✔
1013
    end
6✔
1014
    i = Int(dstart)
3✔
1015
    while i <= dmax && y !== nothing
7✔
1016
        val, st = y
4✔
1017
        @inbounds dest[i] = val
4✔
1018
        y = iterate(src, st)
4✔
1019
        i += 1
4✔
1020
    end
4✔
1021
    i <= dmax && throw(BoundsError(dest, i))
3✔
1022
    return dest
2✔
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,756,516✔
1057
    isempty(src) && return dest
2,770,625✔
1058
    if dest isa BitArray
143,601✔
1059
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1060
        return _copyto_bitarray!(dest, src)
1✔
1061
    end
1062
    src′ = unalias(dest, src)
2,804,857✔
1063
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,770,138✔
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,770,138✔
1073
    isempty(src) && return dest
2,770,138✔
1074
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,770,141✔
1075
    idf, isf = first(destinds), first(srcinds)
143,600✔
1076
    Δi = idf - isf
143,600✔
1077
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,770,139✔
1078
        throw(BoundsError(dest, srcinds))
1079
    if deststyle isa IndexLinear
143,599✔
1080
        if srcstyle isa IndexLinear
139,602✔
1081
            # Single-index implementation
1082
            @inbounds for i in srcinds
5,279,150✔
1083
                dest[i + Δi] = src[i]
35,766,625✔
1084
            end
68,884,940✔
1085
        else
1086
            # Dual-index implementation
1087
            i = idf - 1
126,020✔
1088
            @inbounds for a in src
253,085✔
1089
                dest[i+=1] = a
2,562,925✔
1090
            end
4,991,916✔
1091
        end
1092
    else
1093
        iterdest, itersrc = eachindex(dest), eachindex(src)
3,997✔
1094
        if iterdest == itersrc
3,997✔
1095
            # Shared-iterator implementation
1096
            for I in iterdest
3,268✔
1097
                @inbounds dest[I] = src[I]
6,285,260✔
1098
            end
12,151,652✔
1099
        else
1100
            # Dual-iterator implementation
1101
            ret = iterate(iterdest)
4,726✔
1102
            @inbounds for a in src
4,408✔
1103
                idx, state = ret::NTuple{2,Any}
2,009,483✔
1104
                dest[idx] = a
2,009,483✔
1105
                ret = iterate(iterdest, state)
2,011,847✔
1106
            end
4,008,133✔
1107
        end
1108
    end
1109
    return dest
2,770,137✔
1110
end
1111

1112
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
20,842✔
1113
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
20,850✔
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,
391,434✔
1123
               src::AbstractArray, sstart::Integer,
1124
               n::Integer)
1125
    n == 0 && return dest
391,434✔
1126
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
391,432✔
1127
        n," elements, but n should be nonnegative")))
1128
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
391,431✔
1129
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
391,443✔
1130
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
391,422✔
1131
    src′ = unalias(dest, src)
393,562✔
1132
    @inbounds for i = 0:n-1
782,832✔
1133
        dest[dstart+i] = src′[sstart+i]
19,581,632✔
1134
    end
38,771,848✔
1135
    return dest
391,416✔
1136
end
1137

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

1143
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
2,781✔
1144
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1145
    if length(ir_dest) != length(ir_src)
2,781✔
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)
2,780✔
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)
2,780✔
1154
    @boundscheck checkbounds(A, ir_src, jr_src)
2,780✔
1155
    A′ = unalias(B, A)
5,558✔
1156
    jdest = first(jr_dest)
2,780✔
1157
    for jsrc in jr_src
5,560✔
1158
        idest = first(ir_dest)
19,585✔
1159
        for isrc in ir_src
39,170✔
1160
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
196,702✔
1161
            idest += step(ir_dest)
196,542✔
1162
        end
373,499✔
1163
        jdest += step(jr_dest)
19,585✔
1164
    end
36,390✔
1165
    return B
2,780✔
1166
end
1167

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

1170
function copyto_axcheck!(dest, src)
37,696✔
1171
    _checkaxs(axes(dest), axes(src))
42,582✔
1172
    copyto!(dest, src)
53,374✔
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)
4,015✔
1196
    @_propagate_inbounds_meta
1,431✔
1197
    copyto!(similar(a), a)
155,143✔
1198
end
1199
copymutable(itr) = collect(itr)
1✔
1200

1201
zero(x::AbstractArray{T}) where {T} = fill!(similar(x, typeof(zero(T))), zero(T))
16,291✔
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),))
110,684,240✔
1210
    y = iterate(state...)
136,378,001✔
1211
    y === nothing && return nothing
112,532,295✔
1212
    A[y[1]], (state[1], tail(y)...)
112,044,978✔
1213
end
1214

1215
isempty(a::AbstractArray) = (length(a) == 0)
2,714,857,280✔
1216

1217

1218
## range conversions ##
1219

1220
map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
×
1221
map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
162✔
1222
map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
×
1223
function map(::Type{T}, r::LinRange) where T<:AbstractFloat
×
1224
    LinRange(T(r.start), T(r.stop), length(r))
×
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)
28,644,697✔
1233
function pointer(x::AbstractArray{T}, i::Integer) where T
5,005,463✔
1234
    @inline
2,573,750✔
1235
    unsafe_convert(Ptr{T}, x) + Int(_memory_offset(x, i))::Int
316,038,384✔
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)
270,880,567✔
1240
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
70,077✔
1241
    J = _to_subscript_indices(x, I...)
70,077✔
1242
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
270,935✔
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
See the manual section on [array indexing](@ref man-array-indexing) for details.
1260

1261
# Examples
1262
```jldoctest
1263
julia> A = [1 2; 3 4]
1264
2×2 Matrix{Int64}:
1265
 1  2
1266
 3  4
1267

1268
julia> getindex(A, 1)
1269
1
1270

1271
julia> getindex(A, [2, 1])
1272
2-element Vector{Int64}:
1273
 3
1274
 1
1275

1276
julia> getindex(A, 2:4)
1277
3-element Vector{Int64}:
1278
 3
1279
 2
1280
 4
1281
```
1282
"""
1283
function getindex(A::AbstractArray, I...)
113,228,407✔
1284
    @_propagate_inbounds_meta
110,252,547✔
1285
    error_if_canonical_getindex(IndexStyle(A), A, I...)
110,252,547✔
1286
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
238,618,536✔
1287
end
1288
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1289
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
211,646,810✔
1290

1291
function unsafe_getindex(A::AbstractArray, I...)
262✔
1292
    @inline
262✔
1293
    @inbounds r = getindex(A, I...)
387✔
1294
    r
260✔
1295
end
1296

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

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

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

1313
## IndexLinear Scalar indexing: canonical method is one Int
1314
_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)
18,669,942✔
1315
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
×
1316
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
1,985,367✔
1317
    @inline
901,509✔
1318
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
39,581,624✔
1319
    @inbounds r = getindex(A, _to_linear_index(A, I...))
39,581,590✔
1320
    r
39,581,562✔
1321
end
1322
_to_linear_index(A::AbstractArray, i::Integer) = i
163,913✔
1323
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
149,269✔
1324
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
289,003✔
1325
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
2,118,572✔
1326

1327
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1328
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
159,044✔
1329
    @inline
159,044✔
1330
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
159,057✔
1331
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
164,552✔
1332
    r
159,030✔
1333
end
1334
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
92,313,495✔
1335
    @_propagate_inbounds_meta
92,313,495✔
1336
    getindex(A, I...)
179,763,583✔
1337
end
1338
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
204,043✔
1339
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1340
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1341
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
5✔
1342
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1343
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
6,540✔
1344
    @inline
6,540✔
1345
    J, Jrem = IteratorsMD.split(I, Val(N))
6,540✔
1346
    _to_subscript_indices(A, J, Jrem)
6,540✔
1347
end
1348
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1349
    __to_subscript_indices(A, axes(A), J, Jrem)
1350
function __to_subscript_indices(A::AbstractArray,
2✔
1351
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1352
    @inline
2✔
1353
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1354
end
1355
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
6,538✔
1356
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
24,386✔
1357
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1358
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1359
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1360
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
204,043✔
1361

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

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

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

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

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

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

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

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

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

1407
## IndexLinear Scalar indexing
1408
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
231,951✔
1409
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
155,517✔
1410
    @inline
107,003✔
1411
    @boundscheck checkbounds(A, I...)
162,916✔
1412
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
162,879✔
1413
    r
162,878✔
1414
end
1415

1416
# IndexCartesian Scalar indexing
1417
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
2,334,542✔
1418
    @_propagate_inbounds_meta
2,334,542✔
1419
    setindex!(A, v, I...)
2,334,543✔
1420
end
1421
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
3,119✔
1422
    @inline
3,119✔
1423
    @boundscheck checkbounds(A, I...)
3,124✔
1424
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
3,114✔
1425
    r
3,114✔
1426
end
1427

1428
"""
1429
    parent(A)
1430

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

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

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

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

1456
parent(a::AbstractArray) = a
1,438✔
1457

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

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

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

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

1472
See also [`Base.mightalias`](@ref).
1473
"""
1474
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
7,081,818✔
1475
unalias(dest, A::AbstractRange) = A
1,309,807✔
1476
unalias(dest, A) = A
1,898,771✔
1477

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

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

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

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

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

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

1512
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1513
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1514
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1515
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1516
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
4,982,258✔
1517
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
80,465✔
1518
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1519
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
2,096✔
1520
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
81,358✔
1521

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

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

1527
Custom arrays that would like to opt-in to aliasing detection of their component
1528
parts can specialize this method to return the concatenation of the `dataids` of
1529
their component parts.  A typical definition for an array that wraps a parent is
1530
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1531
"""
1532
dataids(A::AbstractArray) = (UInt(objectid(A)),)
207,410✔
1533
dataids(A::Array) = (UInt(pointer(A)),)
9,874,076✔
1534
dataids(::AbstractRange) = ()
56,696✔
1535
dataids(x) = ()
54,180✔
1536

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

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

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

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

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

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

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

1579
## structured matrix methods ##
1580
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
24,364✔
1581
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
5,166✔
1582

1583
## Concatenation ##
1584
eltypeof(x) = typeof(x)
21,591✔
1585
eltypeof(x::AbstractArray) = eltype(x)
13,519✔
1586

1587
promote_eltypeof() = Bottom
×
1588
promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...))
35,110✔
1589

1590
promote_eltype() = Bottom
122✔
1591
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
7,898✔
1592

1593
#TODO: ERROR CHECK
1594
_cat(catdim::Int) = Vector{Any}()
1✔
1595

1596
typed_vcat(::Type{T}) where {T} = Vector{T}()
1✔
1597
typed_hcat(::Type{T}) where {T} = Vector{T}()
1✔
1598

1599
## cat: special cases
1600
vcat(X::T...) where {T}         = T[ X[i] for i=1:length(X) ]
308✔
1601
vcat(X::T...) where {T<:Number} = T[ X[i] for i=1:length(X) ]
300✔
1602
hcat(X::T...) where {T}         = T[ X[j] for i=1:1, j=1:length(X) ]
97✔
1603
hcat(X::T...) where {T<:Number} = T[ X[j] for i=1:1, j=1:length(X) ]
525✔
1604

1605
vcat(X::Number...) = hvcat_fill!(Vector{promote_typeof(X...)}(undef, length(X)), X)
1✔
1606
hcat(X::Number...) = hvcat_fill!(Matrix{promote_typeof(X...)}(undef, 1,length(X)), X)
2✔
1607
typed_vcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Vector{T}(undef, length(X)), X)
10✔
1608
typed_hcat(::Type{T}, X::Number...) where {T} = hvcat_fill!(Matrix{T}(undef, 1,length(X)), X)
61✔
1609

1610
vcat(V::AbstractVector...) = typed_vcat(promote_eltype(V...), V...)
5✔
1611
vcat(V::AbstractVector{T}...) where {T} = typed_vcat(T, V...)
13✔
1612

1613
# FIXME: this alias would better be Union{AbstractVector{T}, Tuple{Vararg{T}}}
1614
# and method signatures should do AbstractVecOrTuple{<:T} when they want covariance,
1615
# but that solution currently fails (see #27188 and #27224)
1616
AbstractVecOrTuple{T} = Union{AbstractVector{<:T}, Tuple{Vararg{T}}}
1617

1618
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
2,235✔
1619
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
15,630✔
1620
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1621

1622
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
2,235✔
1623
    pos = 1
2,235✔
1624
    for k=1:Int(length(V))::Int
2,240✔
1625
        Vk = V[k]
3,899✔
1626
        p1 = pos + Int(length(Vk))::Int - 1
4,396✔
1627
        a[pos:p1] = Vk
34,312✔
1628
        pos = p1+1
3,899✔
1629
    end
5,563✔
1630
    a
2,235✔
1631
end
1632

1633
typed_hcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_hcat(T, A)
442✔
1634

1635
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
17✔
1636
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
21✔
1637

1638
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
448✔
1639
    nargs = length(A)
448✔
1640
    nrows = size(A[1], 1)
449✔
1641
    ncols = 0
448✔
1642
    dense = true
448✔
1643
    for j = 1:nargs
454✔
1644
        Aj = A[j]
914✔
1645
        if size(Aj, 1) != nrows
1,180✔
1646
            throw(ArgumentError("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1647
        end
1648
        dense &= isa(Aj,Array)
913✔
1649
        nd = ndims(Aj)
1,178✔
1650
        ncols += (nd==2 ? size(Aj,2) : 1)
1,123✔
1651
    end
1,379✔
1652
    B = similar(A[1], T, nrows, ncols)
447✔
1653
    pos = 1
447✔
1654
    if dense
447✔
1655
        for k=1:nargs
185✔
1656
            Ak = A[k]
385✔
1657
            n = length(Ak)
405✔
1658
            copyto!(B, pos, Ak, 1, n)
405✔
1659
            pos += n
385✔
1660
        end
587✔
1661
    else
1662
        for k=1:nargs
268✔
1663
            Ak = A[k]
527✔
1664
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
722✔
1665
            B[:, pos:p1] = Ak
527✔
1666
            pos = p1+1
527✔
1667
        end
527✔
1668
    end
1669
    return B
447✔
1670
end
1671

1672
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
12✔
1673
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
16✔
1674

1675
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
768✔
1676
    nargs = length(A)
768✔
1677
    nrows = sum(a->size(a, 1), A)::Int
2,412✔
1678
    ncols = size(A[1], 2)
768✔
1679
    for j = 2:nargs
769✔
1680
        if size(A[j], 2) != ncols
826✔
1681
            throw(ArgumentError("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1682
        end
1683
    end
899✔
1684
    B = similar(A[1], T, nrows, ncols)
767✔
1685
    pos = 1
767✔
1686
    for k=1:nargs
768✔
1687
        Ak = A[k]
1,592✔
1688
        p1 = pos+size(Ak,1)::Int-1
1,668✔
1689
        B[pos:p1, :] = Ak
1,592✔
1690
        pos = p1+1
1,592✔
1691
    end
2,417✔
1692
    return B
767✔
1693
end
1694

1695
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
11,220✔
1696

1697
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1698
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1699

1700
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1701
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1702

1703
## cat: general case
1704

1705
# helper functions
1706
cat_size(A) = (1,)
22,238✔
1707
cat_size(A::AbstractArray) = size(A)
17,155✔
1708
cat_size(A, d) = 1
22,651✔
1709
cat_size(A::AbstractArray, d) = size(A, d)
24,911✔
1710

1711
cat_length(::Any) = 1
100✔
1712
cat_length(a::AbstractArray) = length(a)
472✔
1713

1714
cat_ndims(a) = 0
183✔
1715
cat_ndims(a::AbstractArray) = ndims(a)
684✔
1716

1717
cat_indices(A, d) = OneTo(1)
22,239✔
1718
cat_indices(A::AbstractArray, d) = axes(A, d)
18,314✔
1719

1720
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
7,317✔
1721
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1722
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
1,136✔
1723
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1724
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
991✔
1725
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
2✔
1726

1727
# These are for backwards compatibility (even though internal)
1728
cat_shape(dims, shape::Tuple{Vararg{Int}}) = shape
×
1729
function cat_shape(dims, shapes::Tuple)
4✔
1730
    out_shape = ()
4✔
1731
    for s in shapes
4✔
1732
        out_shape = _cshp(1, dims, out_shape, s)
18✔
1733
    end
15✔
1734
    return out_shape
4✔
1735
end
1736
# The new way to compute the shape (more inferable than combining cat_size & cat_shape, due to Varargs + issue#36454)
1737
cat_size_shape(dims) = ntuple(zero, Val(length(dims)))
×
1738
@inline cat_size_shape(dims, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, (), cat_size(X)), tail...)
9,399✔
1739
_cat_size_shape(dims, shape) = shape
1,803✔
1740
@inline _cat_size_shape(dims, shape, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, shape, cat_size(X)), tail...)
30,134✔
1741

1742
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1743
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
18✔
1744
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
546✔
1745
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
552✔
1746
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1747
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
10,442✔
1748
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1749
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
28✔
1750
    _cs(ndim, shape[1], 1)
30✔
1751
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
26✔
1752
end
1753
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
252✔
1754
    next = _cs(ndim, shape[1], nshape[1])
252✔
1755
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
252✔
1756
end
1757
@inline function _cshp(ndim::Int, dims, shape, nshape)
31,143✔
1758
    a = shape[1]
31,143✔
1759
    b = nshape[1]
31,143✔
1760
    next = dims[1] ? a + b : _cs(ndim, a, b)
32,063✔
1761
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
31,176✔
1762
end
1763

1764
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,608✔
1765
    "mismatch in dimension $d (expected $a got $b)")))
1766

1767
dims2cat(::Val{dims}) where dims = dims2cat(dims)
984✔
1768
function dims2cat(dims)
1,602✔
1769
    if any(≤(0), dims)
2,796✔
1770
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1771
    end
1772
    ntuple(in(dims), maximum(dims))
1,641✔
1773
end
1774

1775
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
7,332✔
1776

1777
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
9,397✔
1778
    catdims = dims2cat(dims)
9,434✔
1779
    shape = cat_size_shape(catdims, X...)
9,399✔
1780
    A = cat_similar(X[1], T, shape)
9,394✔
1781
    if count(!iszero, catdims)::Int > 1
9,391✔
1782
        fill!(A, zero(T))
591✔
1783
    end
1784
    return __cat(A, shape, catdims, X...)
9,919✔
1785
end
1786
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1787
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1788
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1789

1790
# Why isn't this called `__cat!`?
1791
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
9,923✔
1792

1793
function __cat_offset!(A, shape, catdims, offsets, x, X...)
39,382✔
1794
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1795
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
39,911✔
1796
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
39,384✔
1797
end
1798
__cat_offset!(A, shape, catdims, offsets) = A
9,393✔
1799

1800
function __cat_offset1!(A, shape, catdims, offsets, x)
39,382✔
1801
    inds = ntuple(length(offsets)) do i
39,537✔
1802
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
43,729✔
1803
    end
1804
    if x isa AbstractArray
39,379✔
1805
        A[inds...] = x
111,237✔
1806
    else
1807
        fill!(view(A, inds...), x)
22,982✔
1808
    end
1809
    newoffsets = ntuple(length(offsets)) do i
39,384✔
1810
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
45,837✔
1811
    end
1812
    return newoffsets
39,384✔
1813
end
1814

1815
"""
1816
    vcat(A...)
1817

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

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

1824
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1825

1826
# Examples
1827
```jldoctest
1828
julia> v = vcat([1,2], [3,4])
1829
4-element Vector{Int64}:
1830
 1
1831
 2
1832
 3
1833
 4
1834

1835
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1836
true
1837

1838
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1839
true
1840

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

1844
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1845
3-element Vector{Float64}:
1846
 1.0
1847
 1.5
1848
 2.0
1849

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

1853
julia> vcat(two...)
1854
3×3 Matrix{Float64}:
1855
 10.0  20.0  30.0
1856
  4.0   5.0   6.0
1857
  7.0   8.0   9.0
1858

1859
julia> vs = [[1, 2], [3, 4], [5, 6]];
1860

1861
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1862
6-element Vector{Int64}:
1863
 1
1864
 2
1865
 3
1866
 4
1867
 5
1868
 6
1869

1870
julia> ans == collect(Iterators.flatten(vs))
1871
true
1872
```
1873
"""
1874
vcat(X...) = cat(X...; dims=Val(1))
383✔
1875
"""
1876
    hcat(A...)
1877

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

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

1885
See also [`vcat`](@ref), [`hvcat`](@ref).
1886

1887
# Examples
1888
```jldoctest
1889
julia> hcat([1,2], [3,4], [5,6])
1890
2×3 Matrix{Int64}:
1891
 1  3  5
1892
 2  4  6
1893

1894
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1895
1×7 Matrix{Int64}:
1896
 1  2  30  40  5  6  7
1897

1898
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1899
true
1900

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

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

1907
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
1908
2×6 Matrix{Float64}:
1909
 0.0  0.0  1.0  2.0  50.0  60.0
1910
 0.0  0.0  3.0  4.0  70.0  80.0
1911

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

1915
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
1916
0×3 Matrix{Int64}
1917

1918
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
1919
2×1 Matrix{Any}:
1920
 1.1
1921
 9.9
1922
```
1923
"""
1924
hcat(X...) = cat(X...; dims=Val(2))
9✔
1925

1926
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
167✔
1927
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
275✔
1928

1929
"""
1930
    cat(A...; dims)
1931

1932
Concatenate the input arrays along the dimensions specified in `dims`.
1933

1934
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
1935
a in A)`.
1936
Along other dimensions, all input arrays should have the same size,
1937
which will also be the size of the output array along those dimensions.
1938

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

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

1948
The keyword also accepts `Val(dims)`.
1949

1950
!!! compat "Julia 1.8"
1951
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
1952

1953
# Examples
1954
```jldoctest
1955
julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2)  # same as hcat
1956
2×6×1 Array{Float64, 3}:
1957
[:, :, 1] =
1958
 1.0  2.0  3.14159  10.0  10.0  10.0
1959
 3.0  4.0  3.14159  10.0  10.0  10.0
1960

1961
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
1962
4×7 Matrix{Bool}:
1963
 1  0  0  0  0  0  0
1964
 0  1  1  0  0  0  0
1965
 0  1  1  0  0  0  0
1966
 0  0  0  1  1  1  1
1967

1968
julia> cat(1, [2], [3;;]; dims=Val(2))
1969
1×3 Matrix{Int64}:
1970
 1  2  3
1971
```
1972
"""
1973
@inline cat(A...; dims) = _cat(dims, A...)
17,942✔
1974
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
1975
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
30✔
1976

1977
# The specializations for 1 and 2 inputs are important
1978
# especially when running with --inline=no, see #11158
1979
# The specializations for Union{AbstractVecOrMat,Number} are necessary
1980
# to have more specialized methods here than in LinearAlgebra/uniformscaling.jl
1981
vcat(A::AbstractArray) = cat(A; dims=Val(1))
1✔
1982
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
3✔
1983
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
1984
vcat(A::Union{AbstractVecOrMat,Number}...) = cat(A...; dims=Val(1))
6,917✔
1985
hcat(A::AbstractArray) = cat(A; dims=Val(2))
1✔
1986
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
1✔
1987
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
1✔
1988
hcat(A::Union{AbstractVecOrMat,Number}...) = cat(A...; dims=Val(2))
×
1989

1990
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
1991
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
1992
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
1993
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
1994
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
1995
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
1996

1997
# 2d horizontal and vertical concatenation
1998

1999
# these are produced in lowering if splatting occurs inside hvcat
2000
hvcat_rows(rows::Tuple...) = hvcat(map(length, rows), (rows...)...)
3✔
2001
typed_hvcat_rows(T::Type, rows::Tuple...) = typed_hvcat(T, map(length, rows), (rows...)...)
3✔
2002

2003
function hvcat(nbc::Int, as...)
10✔
2004
    # nbc = # of block columns
2005
    n = length(as)
10✔
2006
    mod(n,nbc) != 0 &&
20✔
2007
        throw(ArgumentError("number of arrays $n is not a multiple of the requested number of block columns $nbc"))
2008
    nbr = div(n,nbc)
9✔
2009
    hvcat(ntuple(Returns(nbc), nbr), as...)
9✔
2010
end
2011

2012
"""
2013
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2014

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

2020
# Examples
2021
```jldoctest
2022
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2023
(1, 2, 3, 4, 5, 6)
2024

2025
julia> [a b c; d e f]
2026
2×3 Matrix{Int64}:
2027
 1  2  3
2028
 4  5  6
2029

2030
julia> hvcat((3,3), a,b,c,d,e,f)
2031
2×3 Matrix{Int64}:
2032
 1  2  3
2033
 4  5  6
2034

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

2041
julia> hvcat((2,2,2), a,b,c,d,e,f)
2042
3×2 Matrix{Int64}:
2043
 1  2
2044
 3  4
2045
 5  6
2046
julia> hvcat((2,2,2), a,b,c,d,e,f) == hvcat(2, a,b,c,d,e,f)
2047
true
2048
```
2049
"""
2050
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractVecOrMat...) = typed_hvcat(promote_eltype(xs...), rows, xs...)
16✔
2051
hvcat(rows::Tuple{Vararg{Int}}, xs::AbstractVecOrMat{T}...) where {T} = typed_hvcat(T, rows, xs...)
318✔
2052

2053
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T
679✔
2054
    nbr = length(rows)  # number of block rows
679✔
2055

2056
    nc = 0
679✔
2057
    for i=1:rows[1]
1,358✔
2058
        nc += size(as[i],2)
1,326✔
2059
    end
1,973✔
2060

2061
    nr = 0
679✔
2062
    a = 1
679✔
2063
    for i = 1:nbr
679✔
2064
        nr += size(as[a],1)
1,181✔
2065
        a += rows[i]
1,181✔
2066
    end
1,683✔
2067

2068
    out = similar(as[1], T, nr, nc)
679✔
2069

2070
    a = 1
679✔
2071
    r = 1
679✔
2072
    for i = 1:nbr
679✔
2073
        c = 1
1,181✔
2074
        szi = size(as[a],1)
1,181✔
2075
        for j = 1:rows[i]
2,362✔
2076
            Aj = as[a+j-1]
2,209✔
2077
            szj = size(Aj,2)
2,209✔
2078
            if size(Aj,1) != szi
2,209✔
2079
                throw(ArgumentError("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
1✔
2080
            end
2081
            if c-1+szj > nc
3,103✔
2082
                throw(ArgumentError("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
1✔
2083
            end
2084
            out[r:r-1+szi, c:c-1+szj] = Aj
3,423✔
2085
            c += szj
2,207✔
2086
        end
3,235✔
2087
        if c != nc+1
1,179✔
2088
            throw(ArgumentError("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
1✔
2089
        end
2090
        r += szi
1,178✔
2091
        a += rows[i]
1,178✔
2092
    end
1,680✔
2093
    out
676✔
2094
end
2095

2096
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
2097
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2098

2099
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,288✔
2100
    nr = length(rows)
493✔
2101
    nc = rows[1]
1,288✔
2102

2103
    a = Matrix{T}(undef, nr, nc)
1,288✔
2104
    if length(a) != length(xs)
1,288✔
2105
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2106
    end
2107
    k = 1
493✔
2108
    @inbounds for i=1:nr
1,286✔
2109
        if nc != rows[i]
3,484✔
2110
            throw(ArgumentError("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2111
        end
2112
        for j=1:nc
6,966✔
2113
            a[i,j] = xs[k]
9,522✔
2114
            k += 1
9,522✔
2115
        end
15,561✔
2116
    end
5,681✔
2117
    a
1,285✔
2118
end
2119

2120
function hvcat_fill!(a::Array, xs::Tuple)
463✔
2121
    nr, nc = size(a,1), size(a,2)
463✔
2122
    len = length(xs)
463✔
2123
    if nr*nc != len
463✔
2124
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2125
    end
2126
    k = 1
462✔
2127
    for i=1:nr
924✔
2128
        @inbounds for j=1:nc
2,474✔
2129
            a[i,j] = xs[k]
9,223✔
2130
            k += 1
8,541✔
2131
        end
15,845✔
2132
    end
2,012✔
2133
    a
462✔
2134
end
2135

2136
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
171✔
2137
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
116✔
2138
# the following method is needed to provide a more specific one compared to LinearAlgebra/uniformscaling.jl
2139
hvcat(rows::Tuple{Vararg{Int}}, xs::Union{AbstractVecOrMat,Number}...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
×
2140

2141
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, xs::Number...) where T
391✔
2142
    nr = length(rows)
391✔
2143
    nc = rows[1]
391✔
2144
    for i = 2:nr
391✔
2145
        if nc != rows[i]
764✔
2146
            throw(ArgumentError("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
2✔
2147
        end
2148
    end
1,135✔
2149
    hvcat_fill!(Matrix{T}(undef, nr, nc), xs)
389✔
2150
end
2151

2152
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as...) where T
124✔
2153
    nbr = length(rows)  # number of block rows
124✔
2154
    rs = Vector{Any}(undef, nbr)
124✔
2155
    a = 1
124✔
2156
    for i = 1:nbr
124✔
2157
        rs[i] = typed_hcat(T, as[a:a-1+rows[i]]...)
439✔
2158
        a += rows[i]
318✔
2159
    end
512✔
2160
    T[rs...;]
124✔
2161
end
2162

2163
## N-dimensional concatenation ##
2164

2165
"""
2166
    hvncat(dim::Int, row_first, values...)
2167
    hvncat(dims::Tuple{Vararg{Int}}, row_first, values...)
2168
    hvncat(shape::Tuple{Vararg{Tuple}}, row_first, values...)
2169

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

2172
This function is called for block matrix syntax. The first argument either specifies the
2173
shape of the concatenation, similar to `hvcat`, as a tuple of tuples, or the dimensions that
2174
specify the key number of elements along each axis, and is used to determine the output
2175
dimensions. The `dims` form is more performant, and is used by default when the concatenation
2176
operation has the same number of elements along each axis (e.g., [a b; c d;;; e f ; g h]).
2177
The `shape` form is used when the number of elements along each axis is unbalanced
2178
(e.g., [a b ; c]). Unbalanced syntax needs additional validation overhead. The `dim` form
2179
is an optimization for concatenation along just one dimension. `row_first` indicates how
2180
`values` are ordered. The meaning of the first and second elements of `shape` are also
2181
swapped based on `row_first`.
2182

2183
# Examples
2184
```jldoctest
2185
julia> a, b, c, d, e, f = 1, 2, 3, 4, 5, 6
2186
(1, 2, 3, 4, 5, 6)
2187

2188
julia> [a b c;;; d e f]
2189
1×3×2 Array{Int64, 3}:
2190
[:, :, 1] =
2191
 1  2  3
2192

2193
[:, :, 2] =
2194
 4  5  6
2195

2196
julia> hvncat((2,1,3), false, a,b,c,d,e,f)
2197
2×1×3 Array{Int64, 3}:
2198
[:, :, 1] =
2199
 1
2200
 2
2201

2202
[:, :, 2] =
2203
 3
2204
 4
2205

2206
[:, :, 3] =
2207
 5
2208
 6
2209

2210
julia> [a b;;; c d;;; e f]
2211
1×2×3 Array{Int64, 3}:
2212
[:, :, 1] =
2213
 1  2
2214

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

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

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

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

2230
# Examples for construction of the arguments
2231
```
2232
[a b c ; d e f ;;;
2233
 g h i ; j k l ;;;
2234
 m n o ; p q r ;;;
2235
 s t u ; v w x]
2236
⇒ dims = (2, 3, 4)
2237

2238
[a b ; c ;;; d ;;;;]
2239
 ___   _     _
2240
 2     1     1 = elements in each row (2, 1, 1)
2241
 _______     _
2242
 3           1 = elements in each column (3, 1)
2243
 _____________
2244
 4             = elements in each 3d slice (4,)
2245
 _____________
2246
 4             = elements in each 4d slice (4,)
2247
⇒ shape = ((2, 1, 1), (3, 1), (4,), (4,)) with `row_first` = true
2248
```
2249
"""
2250
hvncat(dimsshape::Tuple, row_first::Bool, xs...) = _hvncat(dimsshape, row_first, xs...)
262✔
2251
hvncat(dim::Int, xs...) = _hvncat(dim, true, xs...)
77✔
2252

2253
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool) = _typed_hvncat(Any, dimsshape, row_first)
29✔
2254
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs...) = _typed_hvncat(promote_eltypeof(xs...), dimsshape, row_first, xs...)
91✔
2255
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::T...) where T<:Number = _typed_hvncat(T, dimsshape, row_first, xs...)
88✔
2256
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::Number...) = _typed_hvncat(promote_typeof(xs...), dimsshape, row_first, xs...)
×
2257
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray...) = _typed_hvncat(promote_eltype(xs...), dimsshape, row_first, xs...)
×
2258
_hvncat(dimsshape::Union{Tuple, Int}, row_first::Bool, xs::AbstractArray{T}...) where T = _typed_hvncat(T, dimsshape, row_first, xs...)
132✔
2259

2260

2261
typed_hvncat(T::Type, dimsshape::Tuple, row_first::Bool, xs...) = _typed_hvncat(T, dimsshape, row_first, xs...)
17✔
2262
typed_hvncat(T::Type, dim::Int, xs...) = _typed_hvncat(T, Val(dim), xs...)
14✔
2263

2264
# 1-dimensional hvncat methods
2265

2266
_typed_hvncat(::Type, ::Val{0}) = _typed_hvncat_0d_only_one()
4✔
2267
_typed_hvncat(T::Type, ::Val{0}, x) = fill(convert(T, x))
×
2268
_typed_hvncat(T::Type, ::Val{0}, x::Number) = fill(convert(T, x))
4✔
2269
_typed_hvncat(T::Type, ::Val{0}, x::AbstractArray) = convert.(T, x)
4✔
2270
_typed_hvncat(::Type, ::Val{0}, ::Any...) = _typed_hvncat_0d_only_one()
×
2271
_typed_hvncat(::Type, ::Val{0}, ::Number...) = _typed_hvncat_0d_only_one()
4✔
2272
_typed_hvncat(::Type, ::Val{0}, ::AbstractArray...) = _typed_hvncat_0d_only_one()
×
2273

2274
_typed_hvncat_0d_only_one() =
8✔
2275
    throw(ArgumentError("a 0-dimensional array may only contain exactly one element"))
2276

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

2280
function _typed_hvncat(::Type{T}, ::Val{N}) where {T, N}
15✔
2281
    N < 0 &&
15✔
2282
        throw(ArgumentError("concatenation dimension must be nonnegative"))
2283
    return Array{T, N}(undef, ntuple(x -> 0, Val(N)))
40✔
2284
end
2285

2286
function _typed_hvncat(T::Type, ::Val{N}, xs::Number...) where N
38✔
2287
    N < 0 &&
38✔
2288
        throw(ArgumentError("concatenation dimension must be nonnegative"))
2289
    A = cat_similar(xs[1], T, (ntuple(x -> 1, Val(N - 1))..., length(xs)))
83✔
2290
    hvncat_fill!(A, false, xs)
37✔
2291
    return A
37✔
2292
end
2293

2294
function _typed_hvncat(::Type{T}, ::Val{N}, as::AbstractArray...) where {T, N}
25✔
2295
    # optimization for arrays that can be concatenated by copying them linearly into the destination
2296
    # conditions: the elements must all have 1-length dimensions above N
2297
    length(as) > 0 ||
25✔
2298
        throw(ArgumentError("must have at least one element"))
2299
    N < 0 &&
25✔
2300
        throw(ArgumentError("concatenation dimension must be nonnegative"))
2301
    for a ∈ as
23✔
2302
        ndims(a) <= N || all(x -> size(a, x) == 1, (N + 1):ndims(a)) ||
54✔
2303
            return _typed_hvncat(T, (ntuple(x -> 1, Val(N - 1))..., length(as), 1), false, as...)
9✔
2304
            # the extra 1 is to avoid an infinite cycle
2305
    end
46✔
2306

2307
    nd = N
17✔
2308

2309
    Ndim = 0
17✔
2310
    for i ∈ eachindex(as)
18✔
2311
        Ndim += cat_size(as[i], N)
38✔
2312
        nd = max(nd, cat_ndims(as[i]))
38✔
2313
        for d ∈ 1:N - 1
32✔
2314
            cat_size(as[1], d) == cat_size(as[i], d) || throw(ArgumentError("mismatched size along axis $d in element $i"))
39✔
2315
        end
44✔
2316
    end
43✔
2317

2318
    A = cat_similar(as[1], T, (ntuple(d -> size(as[1], d), N - 1)..., Ndim, ntuple(x -> 1, nd - N)...))
28✔
2319
    k = 1
13✔
2320
    for a ∈ as
13✔
2321
        for i ∈ eachindex(a)
44✔
2322
            A[k] = a[i]
36✔
2323
            k += 1
34✔
2324
        end
47✔
2325
    end
34✔
2326
    return A
13✔
2327
end
2328

2329
function _typed_hvncat(::Type{T}, ::Val{N}, as...) where {T, N}
14✔
2330
    length(as) > 0 ||
14✔
2331
        throw(ArgumentError("must have at least one element"))
2332
    N < 0 &&
14✔
2333
        throw(ArgumentError("concatenation dimension must be nonnegative"))
2334
    nd = N
12✔
2335
    Ndim = 0
12✔
2336
    for i ∈ eachindex(as)
14✔
2337
        Ndim += cat_size(as[i], N)
30✔
2338
        nd = max(nd, cat_ndims(as[i]))
30✔
2339
        for d ∈ 1:N-1
20✔
2340
            cat_size(as[i], d) == 1 ||
36✔
2341
                throw(ArgumentError("all dimensions of element $i other than $N must be of length 1"))
2342
        end
28✔
2343
    end
20✔
2344

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

2347
    k = 1
4✔
2348
    for a ∈ as
4✔
2349
        if a isa AbstractArray
12✔
2350
            lena = length(a)
2✔
2351
            copyto!(A, k, a, 1, lena)
2✔
2352
            k += lena
2✔
2353
        else
2354
            A[k] = a
10✔
2355
            k += 1
10✔
2356
        end
2357
    end
16✔
2358
    return A
4✔
2359
end
2360

2361
# 0-dimensional cases for balanced and unbalanced hvncat method
2362

2363
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x...) = _typed_hvncat(T, Val(0), x...)
2✔
2364
_typed_hvncat(T::Type, ::Tuple{}, ::Bool, x::Number...) = _typed_hvncat(T, Val(0), x...)
6✔
2365

2366

2367
# balanced dimensions hvncat methods
2368

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

2372
function _typed_hvncat_1d(::Type{T}, ds::Int, ::Val{row_first}, as...) where {T, row_first}
22✔
2373
    lengthas = length(as)
22✔
2374
    ds > 0 ||
22✔
2375
        throw(ArgumentError("`dimsshape` argument must consist of positive integers"))
2376
    lengthas == ds ||
30✔
2377
        throw(ArgumentError("number of elements does not match `dimshape` argument; expected $ds, got $lengthas"))
2378
    if row_first
14✔
2379
        return _typed_hvncat(T, Val(2), as...)
4✔
2380
    else
2381
        return _typed_hvncat(T, Val(1), as...)
10✔
2382
    end
2383
end
2384

2385
function _typed_hvncat(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, xs::Number...) where {T, N}
44✔
2386
    all(>(0), dims) ||
60✔
2387
        throw(ArgumentError("`dims` argument must contain positive integers"))
2388
    A = Array{T, N}(undef, dims...)
28✔
2389
    lengtha = length(A)  # Necessary to store result because throw blocks are being deoptimized right now, which leads to excessive allocations
28✔
2390
    lengthx = length(xs) # Cuts from 3 allocations to 1.
28✔
2391
    if lengtha != lengthx
28✔
2392
       throw(ArgumentError("argument count does not match specified shape (expected $lengtha, got $lengthx)"))
×
2393
    end
2394
    hvncat_fill!(A, row_first, xs)
28✔
2395
    return A
28✔
2396
end
2397

2398
function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
65✔
2399
    # putting these in separate functions leads to unnecessary allocations
2400
    if row_first
65✔
2401
        nr, nc = size(A, 1), size(A, 2)
17✔
2402
        nrc = nr * nc
17✔
2403
        na = prod(size(A)[3:end])
17✔
2404
        k = 1
17✔
2405
        for d ∈ 1:na
34✔
2406
            dd = nrc * (d - 1)
31✔
2407
            for i ∈ 1:nr
62✔
2408
                Ai = dd + i
42✔
2409
                for j ∈ 1:nc
84✔
2410
                    A[Ai] = xs[k]
95✔
2411
                    k += 1
95✔
2412
                    Ai += nr
95✔
2413
                end
148✔
2414
            end
53✔
2415
        end
31✔
2416
    else
2417
        for k ∈ eachindex(xs)
48✔
2418
            A[k] = xs[k]
95✔
2419
        end
95✔
2420
    end
2421
end
2422

2423
function _typed_hvncat(T::Type, dims::NTuple{N, Int}, row_first::Bool, as...) where {N}
90✔
2424
    # function barrier after calculating the max is necessary for high performance
2425
    nd = max(maximum(cat_ndims(a) for a ∈ as), N)
90✔
2426
    return _typed_hvncat_dims(T, (dims..., ntuple(x -> 1, nd - N)...), row_first, as)
124✔
2427
end
2428

2429
function _typed_hvncat_dims(::Type{T}, dims::NTuple{N, Int}, row_first::Bool, as::Tuple) where {T, N}
90✔
2430
    length(as) > 0 ||
90✔
2431
        throw(ArgumentError("must have at least one element"))
2432
    all(>(0), dims) ||
122✔
2433
        throw(ArgumentError("`dims` argument must contain positive integers"))
2434

2435
    d1 = row_first ? 2 : 1
58✔
2436
    d2 = row_first ? 1 : 2
58✔
2437

2438
    outdims = zeros(Int, N)
203✔
2439

2440
    # validate shapes for lowest level of concatenation
2441
    d = findfirst(>(1), dims)
86✔
2442
    if d !== nothing # all dims are 1
58✔
2443
        if row_first && d < 3
57✔
2444
            d = d == 1 ? 2 : 1
32✔
2445
        end
2446
        nblocks = length(as) ÷ dims[d]
57✔
2447
        for b ∈ 1:nblocks
114✔
2448
            offset = ((b - 1) * dims[d])
175✔
2449
            startelementi = offset + 1
175✔
2450
            for i ∈ offset .+ (2:dims[d])
262✔
2451
                for dd ∈ 1:N
111✔
2452
                    dd == d && continue
316✔
2453
                    if cat_size(as[startelementi], dd) != cat_size(as[i], dd)
217✔
2454
                        throw(ArgumentError("incompatible shape in element $i"))
6✔
2455
                    end
2456
                end
515✔
2457
            end
129✔
2458
        end
287✔
2459
    end
2460

2461
    # discover number of rows or columns
2462
    for i ∈ 1:dims[d1]
104✔
2463
        outdims[d1] += cat_size(as[i], d1)
140✔
2464
    end
164✔
2465

2466
    currentdims = zeros(Int, N)
176✔
2467
    blockcount = 0
52✔
2468
    elementcount = 0
52✔
2469
    for i ∈ eachindex(as)
52✔
2470
        elementcount += cat_length(as[i])
309✔
2471
        currentdims[d1] += cat_size(as[i], d1)
309✔
2472
        if currentdims[d1] == outdims[d1]
259✔
2473
            currentdims[d1] = 0
129✔
2474
            for d ∈ (d2, 3:N...)
129✔
2475
                currentdims[d] += cat_size(as[i], d)
258✔
2476
                if outdims[d] == 0 # unfixed dimension
203✔
2477
                    blockcount += 1
167✔
2478
                    if blockcount == dims[d]
167✔
2479
                        outdims[d] = currentdims[d]
88✔
2480
                        currentdims[d] = 0
88✔
2481
                        blockcount = 0
88✔
2482
                    else
2483
                        break
167✔
2484
                    end
2485
                else # fixed dimension
2486
                    if currentdims[d] == outdims[d] # end of dimension
36✔
2487
                        currentdims[d] = 0
23✔
2488
                    elseif currentdims[d] < outdims[d] # dimension in progress
13✔
2489
                        break
13✔
2490
                    else # exceeded dimension
2491
                        throw(ArgumentError("argument $i has too many elements along axis $d"))
×
2492
                    end
2493
                end
2494
            end
142✔
2495
        elseif currentdims[d1] > outdims[d1] # exceeded dimension
130✔
2496
            throw(ArgumentError("argument $i has too many elements along axis $d1"))
16✔
2497
        end
2498
    end
450✔
2499

2500
    outlen = prod(outdims)
72✔
2501
    elementcount == outlen ||
36✔
2502
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2503

2504
    # copy into final array
2505
    A = cat_similar(as[1], T, outdims)
36✔
2506
    # @assert all(==(0), currentdims)
2507
    outdims .= 0
108✔
2508
    hvncat_fill!(A, currentdims, outdims, d1, d2, as)
36✔
2509
    return A
36✔
2510
end
2511

2512

2513
# unbalanced dimensions hvncat methods
2514

2515
function _typed_hvncat(T::Type, shape::Tuple{Tuple}, row_first::Bool, xs...)
19✔
2516
    length(shape[1]) > 0 ||
19✔
2517
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2518
    return _typed_hvncat_1d(T, shape[1][1], Val(row_first), xs...)
13✔
2519
end
2520

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

2527
function _typed_hvncat_shape(::Type{T}, shape::NTuple{N, Tuple}, row_first, as::Tuple) where {T, N}
107✔
2528
    length(as) > 0 ||
107✔
2529
        throw(ArgumentError("must have at least one element"))
2530
    all(>(0), tuple((shape...)...)) ||
147✔
2531
        throw(ArgumentError("`shape` argument must consist of positive integers"))
2532

2533
    d1 = row_first ? 2 : 1
67✔
2534
    d2 = row_first ? 1 : 2
67✔
2535

2536
    shapev = collect(shape) # saves allocations later
67✔
2537
    all(!isempty, shapev) ||
134✔
2538
        throw(ArgumentError("each level of `shape` argument must have at least one value"))
2539
    length(shapev[end]) == 1 ||
70✔
2540
        throw(ArgumentError("last level of shape must contain only one integer"))
2541
    shapelength = shapev[end][1]
64✔
2542
    lengthas = length(as)
64✔
2543
    shapelength == lengthas || throw(ArgumentError("number of elements does not match shape; expected $(shapelength), got $lengthas)"))
64✔
2544
    # discover dimensions
2545
    nd = max(N, cat_ndims(as[1]))
64✔
2546
    outdims = fill(-1, nd)
210✔
2547
    currentdims = zeros(Int, nd)
210✔
2548
    blockcounts = zeros(Int, nd)
210✔
2549
    shapepos = ones(Int, nd)
210✔
2550

2551
    elementcount = 0
64✔
2552
    for i ∈ eachindex(as)
64✔
2553
        elementcount += cat_length(as[i])
355✔
2554
        wasstartblock = false
313✔
2555
        for d ∈ 1:N
313✔
2556
            ad = (d < 3 && row_first) ? (d == 1 ? 2 : 1) : d
907✔
2557
            dsize = cat_size(as[i], ad)
1,048✔
2558
            blockcounts[d] += 1
907✔
2559

2560
            if d == 1 || i == 1 || wasstartblock
1,501✔
2561
                currentdims[d] += dsize
623✔
2562
            elseif dsize != cat_size(as[i - 1], ad)
302✔
2563
                throw(ArgumentError("argument $i has a mismatched number of elements along axis $ad; \
8✔
2564
                                    expected $(cat_size(as[i - 1], ad)), got $dsize"))
2565
            end
2566

2567
            wasstartblock = blockcounts[d] == 1 # remember for next dimension
899✔
2568

2569
            isendblock = blockcounts[d] == shapev[d][shapepos[d]]
899✔
2570
            if isendblock
899✔
2571
                if outdims[d] == -1
269✔
2572
                    outdims[d] = currentdims[d]
138✔
2573
                elseif outdims[d] != currentdims[d]
131✔
2574
                    throw(ArgumentError("argument $i has a mismatched number of elements along axis $ad; \
40✔
2575
                                        expected $(abs(outdims[d] - (currentdims[d] - dsize))), got $dsize"))
2576
                end
2577
                currentdims[d] = 0
229✔
2578
                blockcounts[d] = 0
229✔
2579
                shapepos[d] += 1
229✔
2580
                d > 1 && (blockcounts[d - 1] == 0 ||
230✔
2581
                    throw(ArgumentError("shape in level $d is inconsistent; level counts must nest \
2582
                                        evenly into each other")))
2583
            end
2584
        end
1,452✔
2585
    end
513✔
2586

2587
    outlen = prod(outdims)
30✔
2588
    elementcount == outlen ||
15✔
2589
        throw(ArgumentError("mismatched number of elements; expected $(outlen), got $(elementcount)"))
2590

2591
    if row_first
15✔
2592
        outdims[1], outdims[2] = outdims[2], outdims[1]
11✔
2593
    end
2594

2595
    # @assert all(==(0), currentdims)
2596
    # @assert all(==(0), blockcounts)
2597

2598
    # copy into final array
2599
    A = cat_similar(as[1], T, outdims)
15✔
2600
    hvncat_fill!(A, currentdims, blockcounts, d1, d2, as)
15✔
2601
    return A
15✔
2602
end
2603

2604
function hvncat_fill!(A::AbstractArray{T, N}, scratch1::Vector{Int}, scratch2::Vector{Int}, d1::Int, d2::Int, as::Tuple{Vararg}) where {T, N}
51✔
2605
    outdims = size(A)
51✔
2606
    offsets = scratch1
51✔
2607
    inneroffsets = scratch2
51✔
2608
    for a ∈ as
51✔
2609
        if isa(a, AbstractArray)
270✔
2610
            for ai ∈ a
266✔
2611
                Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
7,046✔
2612
                A[Ai] = ai
1,888✔
2613

2614
                for j ∈ 1:N
1,888✔
2615
                    inneroffsets[j] += 1
4,152✔
2616
                    inneroffsets[j] < cat_size(a, j) && break
4,221✔
2617
                    inneroffsets[j] = 0
2,490✔
2618
                end
2,490✔
2619
            end
2,118✔
2620
        else
2621
            Ai = hvncat_calcindex(offsets, inneroffsets, outdims, N)
52✔
2622
            A[Ai] = a
30✔
2623
        end
2624

2625
        for j ∈ (d1, d2, 3:N...)
270✔
2626
            offsets[j] += cat_size(a, j)
599✔
2627
            offsets[j] < outdims[j] && break
518✔
2628
            offsets[j] = 0
304✔
2629
        end
304✔
2630
    end
270✔
2631
end
2632

2633
@propagate_inbounds function hvncat_calcindex(offsets::Vector{Int}, inneroffsets::Vector{Int},
1,915✔
2634
                                              outdims::Tuple{Vararg{Int}}, nd::Int)
2635
    Ai = inneroffsets[1] + offsets[1] + 1
1,915✔
2636
    for j ∈ 2:nd
1,915✔
2637
        increment = inneroffsets[j] + offsets[j]
7,098✔
2638
        for k ∈ 1:j-1
14,168✔
2639
            increment *= outdims[k]
17,209✔
2640
        end
27,320✔
2641
        Ai += increment
7,098✔
2642
    end
12,281✔
2643
    Ai
1,915✔
2644
end
2645

2646
"""
2647
    stack(iter; [dims])
2648

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

2652
By default the axes of the elements are placed first,
2653
giving `size(result) = (size(first(iter))..., size(iter)...)`.
2654
This has the same order of elements as [`Iterators.flatten`](@ref)`(iter)`.
2655

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

2660
The various [`cat`](@ref) functions also combine arrays. However, these all
2661
extend the arrays' existing (possibly trivial) dimensions, rather than placing
2662
the arrays along new dimensions.
2663
They also accept arrays as separate arguments, rather than a single collection.
2664

2665
!!! compat "Julia 1.9"
2666
    This function requires at least Julia 1.9.
2667

2668
# Examples
2669
```jldoctest
2670
julia> vecs = (1:2, [30, 40], Float32[500, 600]);
2671

2672
julia> mat = stack(vecs)
2673
2×3 Matrix{Float32}:
2674
 1.0  30.0  500.0
2675
 2.0  40.0  600.0
2676

2677
julia> mat == hcat(vecs...) == reduce(hcat, collect(vecs))
2678
true
2679

2680
julia> vec(mat) == vcat(vecs...) == reduce(vcat, collect(vecs))
2681
true
2682

2683
julia> stack(zip(1:4, 10:99))  # accepts any iterators of iterators
2684
2×4 Matrix{Int64}:
2685
  1   2   3   4
2686
 10  11  12  13
2687

2688
julia> vec(ans) == collect(Iterators.flatten(zip(1:4, 10:99)))
2689
true
2690

2691
julia> stack(vecs; dims=1)  # unlike any cat function, 1st axis of vecs[1] is 2nd axis of result
2692
3×2 Matrix{Float32}:
2693
   1.0    2.0
2694
  30.0   40.0
2695
 500.0  600.0
2696

2697
julia> x = rand(3,4);
2698

2699
julia> x == stack(eachcol(x)) == stack(eachrow(x), dims=1)  # inverse of eachslice
2700
true
2701
```
2702

2703
Higher-dimensional examples:
2704

2705
```jldoctest
2706
julia> A = rand(5, 7, 11);
2707

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

2710
julia> (element = size(first(E)), container = size(E))
2711
(element = (5, 11), container = (7,))
2712

2713
julia> stack(E) |> size
2714
(5, 11, 7)
2715

2716
julia> stack(E) == stack(E; dims=3) == cat(E...; dims=3)
2717
true
2718

2719
julia> A == stack(E; dims=2)
2720
true
2721

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

2724
julia> (element = size(first(M)), container = size(M))
2725
(element = (2, 3), container = (5, 7))
2726

2727
julia> stack(M) |> size  # keeps all dimensions
2728
(2, 3, 5, 7)
2729

2730
julia> stack(M; dims=1) |> size  # vec(container) along dims=1
2731
(35, 2, 3)
2732

2733
julia> hvcat(5, M...) |> size  # hvcat puts matrices next to each other
2734
(14, 15)
2735
```
2736
"""
2737
stack(iter; dims=:) = _stack(dims, iter)
250✔
2738

2739
"""
2740
    stack(f, args...; [dims])
2741

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

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

2749
See also [`mapslices`](@ref), [`eachcol`](@ref).
2750

2751
# Examples
2752
```jldoctest
2753
julia> stack(c -> (c, c-32), "julia")
2754
2×5 Matrix{Char}:
2755
 'j'  'u'  'l'  'i'  'a'
2756
 'J'  'U'  'L'  'I'  'A'
2757

2758
julia> stack(eachrow([1 2 3; 4 5 6]), (10, 100); dims=1) do row, n
2759
         vcat(row, row .* n, row ./ n)
2760
       end
2761
2×9 Matrix{Float64}:
2762
 1.0  2.0  3.0   10.0   20.0   30.0  0.1   0.2   0.3
2763
 4.0  5.0  6.0  400.0  500.0  600.0  0.04  0.05  0.06
2764
```
2765
"""
2766
stack(f, iter; dims=:) = _stack(dims, f(x) for x in iter)
12✔
2767
stack(f, xs, yzs...; dims=:) = _stack(dims, f(xy...) for xy in zip(xs, yzs...))
2✔
2768

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

2771
_stack(dims, ::IteratorSize, iter) = _stack(dims, collect(iter))
21✔
2772

2773
function _stack(dims, ::Union{HasShape, HasLength}, iter)
122✔
2774
    S = @default_eltype iter
122✔
2775
    T = S != Union{} ? eltype(S) : Any  # Union{} occurs for e.g. stack(1,2), postpone the error
126✔
2776
    if isconcretetype(T)
122✔
2777
        _typed_stack(dims, T, S, iter)
103✔
2778
    else  # Need to look inside, but shouldn't run an expensive iterator twice:
2779
        array = iter isa Union{Tuple, AbstractArray} ? iter : collect(iter)
42✔
2780
        isempty(array) && return _empty_stack(dims, T, S, iter)
38✔
2781
        T2 = mapreduce(eltype, promote_type, array)
42✔
2782
        _typed_stack(dims, T2, eltype(array), array)
36✔
2783
    end
2784
end
2785

2786
function _typed_stack(::Colon, ::Type{T}, ::Type{S}, A, Aax=_iterator_axes(A)) where {T, S}
184✔
2787
    xit = iterate(A)
210✔
2788
    nothing === xit && return _empty_stack(:, T, S, A)
94✔
2789
    x1, _ = xit
94✔
2790
    ax1 = _iterator_axes(x1)
98✔
2791
    B = similar(_ensure_array(x1), T, ax1..., Aax...)
106✔
2792
    off = firstindex(B)
93✔
2793
    len = length(x1)
97✔
2794
    while xit !== nothing
2,563✔
2795
        x, state = xit
2,476✔
2796
        _stack_size_check(x, ax1)
4,654✔
2797
        copyto!(B, off, x)
2,474✔
2798
        off += len
2,470✔
2799
        xit = iterate(A, state)
3,798✔
2800
    end
2,470✔
2801
    B
87✔
2802
end
2803

2804
_iterator_axes(x) = _iterator_axes(x, IteratorSize(x))
9,238✔
2805
_iterator_axes(x, ::HasLength) = (OneTo(length(x)),)
462✔
2806
_iterator_axes(x, ::IteratorSize) = axes(x)
8,776✔
2807

2808
# For some dims values, stack(A; dims) == stack(vec(A)), and the : path will be faster
2809
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S} =
51✔
2810
    _typed_stack(dims, T, S, IteratorSize(S), A)
2811
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasLength, A) where {T,S} =
13✔
2812
    _typed_stack(dims, T, S, HasShape{1}(), A)
2813
function _typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::HasShape{N}, A) where {T,S,N}
27✔
2814
    if dims == N+1
27✔
2815
        _typed_stack(:, T, S, A, (_vec_axis(A),))
4✔
2816
    else
2817
        _dim_stack(dims, T, S, A)
23✔
2818
    end
2819
end
2820
_typed_stack(dims::Integer, ::Type{T}, ::Type{S}, ::IteratorSize, A) where {T,S} =
2✔
2821
    _dim_stack(dims, T, S, A)
2822

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

2825
@constprop :aggressive function _dim_stack(dims::Integer, ::Type{T}, ::Type{S}, A) where {T,S}
25✔
2826
    xit = Iterators.peel(A)
48✔
2827
    nothing === xit && return _empty_stack(dims, T, S, A)
25✔
2828
    x1, xrest = xit
25✔
2829
    ax1 = _iterator_axes(x1)
25✔
2830
    N1 = length(ax1)+1
24✔
2831
    dims in 1:N1 || throw(ArgumentError(LazyString("cannot stack slices ndims(x) = ", N1-1, " along dims = ", dims)))
27✔
2832

2833
    newaxis = _vec_axis(A)
21✔
2834
    outax = ntuple(d -> d==dims ? newaxis : ax1[d - (d>dims)], N1)
141✔
2835
    B = similar(_ensure_array(x1), T, outax...)
23✔
2836

2837
    if dims == 1
21✔
2838
        _dim_stack!(Val(1), B, x1, xrest)
13✔
2839
    elseif dims == 2
8✔
2840
        _dim_stack!(Val(2), B, x1, xrest)
4✔
2841
    else
2842
        _dim_stack!(Val(dims), B, x1, xrest)
4✔
2843
    end
2844
    B
18✔
2845
end
2846

2847
function _dim_stack!(::Val{dims}, B::AbstractArray, x1, xrest) where {dims}
21✔
2848
    before = ntuple(d -> Colon(), dims - 1)
33✔
2849
    after = ntuple(d -> Colon(), ndims(B) - dims)
49✔
2850

2851
    i = firstindex(B, dims)
21✔
2852
    copyto!(view(B, before..., i, after...), x1)
39✔
2853

2854
    for x in xrest
29✔
2855
        _stack_size_check(x, _iterator_axes(x1))
6,422✔
2856
        i += 1
3,261✔
2857
        @inbounds copyto!(view(B, before..., i, after...), x)
6,512✔
2858
    end
3,261✔
2859
end
2860

2861
@inline function _stack_size_check(x, ax1::Tuple)
5,740✔
2862
    if _iterator_axes(x) != ax1
11,107✔
2863
        uax1 = map(UnitRange, ax1)
9✔
2864
        uaxN = map(UnitRange, axes(x))
9✔
2865
        throw(DimensionMismatch(
9✔
2866
            LazyString("stack expects uniform slices, got axes(x) == ", uaxN, " while first had ", uax1)))
2867
    end
2868
end
2869

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

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

2875

2876
## Reductions and accumulates ##
2877

2878
function isequal(A::AbstractArray, B::AbstractArray)
245,067✔
2879
    if A === B return true end
245,283✔
2880
    if axes(A) != axes(B)
486,843✔
2881
        return false
2,841✔
2882
    end
2883
    for (a, b) in zip(A, B)
483,467✔
2884
        if !isequal(a, b)
90,907,156✔
2885
            return false
541✔
2886
        end
2887
    end
181,368,290✔
2888
    return true
241,469✔
2889
end
2890

2891
function cmp(A::AbstractVector, B::AbstractVector)
325✔
2892
    for (a, b) in zip(A, B)
650✔
2893
        if !isequal(a, b)
822✔
2894
            return isless(a, b) ? -1 : 1
310✔
2895
        end
2896
    end
1,009✔
2897
    return cmp(length(A), length(B))
15✔
2898
end
2899

2900
"""
2901
    isless(A::AbstractVector, B::AbstractVector)
2902

2903
Return `true` when `A` is less than `B` in lexicographic order.
2904
"""
2905
isless(A::AbstractVector, B::AbstractVector) = cmp(A, B) < 0
316✔
2906

2907
function (==)(A::AbstractArray, B::AbstractArray)
232,978✔
2908
    if axes(A) != axes(B)
466,373✔
2909
        return false
2,478✔
2910
    end
2911
    anymissing = false
226,669✔
2912
    for (a, b) in zip(A, B)
460,969✔
2913
        eq = (a == b)
302,002,072✔
2914
        if ismissing(eq)
267,348,548✔
2915
            anymissing = true
24✔
2916
        elseif !eq
301,113,735✔
2917
            return false
2,400✔
2918
        end
2919
    end
601,996,086✔
2920
    return anymissing ? missing : true
229,587✔
2921
end
2922

2923
# _sub2ind and _ind2sub
2924
# fallbacks
2925
function _sub2ind(A::AbstractArray, I...)
739,812✔
2926
    @inline
739,812✔
2927
    _sub2ind(axes(A), I...)
2,118,572✔
2928
end
2929

2930
function _ind2sub(A::AbstractArray, ind)
204,044✔
2931
    @inline
204,044✔
2932
    _ind2sub(axes(A), ind)
204,044✔
2933
end
2934

2935
# 0-dimensional arrays and indexing with []
2936
_sub2ind(::Tuple{}) = 1
18✔
2937
_sub2ind(::DimsInteger) = 1
2✔
2938
_sub2ind(::Indices) = 1
×
2939
_sub2ind(::Tuple{}, I::Integer...) = (@inline; _sub2ind_recurse((), 1, 1, I...))
5✔
2940

2941
# Generic cases
2942
_sub2ind(dims::DimsInteger, I::Integer...) = (@inline; _sub2ind_recurse(dims, 1, 1, I...))
2,190,750,677✔
2943
_sub2ind(inds::Indices, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...))
2,236,728✔
2944
# In 1d, there's a question of whether we're doing cartesian indexing
2945
# or linear indexing. Support only the former.
2946
_sub2ind(inds::Indices{1}, I::Integer...) =
1✔
2947
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2948
_sub2ind(inds::Tuple{OneTo}, I::Integer...) = (@inline; _sub2ind_recurse(inds, 1, 1, I...)) # only OneTo is safe
×
2949
_sub2ind(inds::Tuple{OneTo}, i::Integer)    = i
×
2950

2951
_sub2ind_recurse(::Any, L, ind) = ind
1,814,868✔
2952
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,801✔
2953
    @inline
867✔
2954
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
12,134✔
2955
end
2956
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
3,073,354✔
2957
    @inline
2,550,663✔
2958
    r1 = inds[1]
2,584,294✔
2959
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
2,195,888,793✔
2960
end
2961

2962
nextL(L, l::Integer) = L*l
1,969,915✔
2963
nextL(L, r::AbstractUnitRange) = L*length(r)
2,704,730✔
2964
nextL(L, r::Slice) = L*length(r.indices)
×
2965
offsetin(i, l::Integer) = i-1
2,190,883,668✔
2966
offsetin(i, r::AbstractUnitRange) = i-first(r)
4,861,514✔
2967

2968
_ind2sub(::Tuple{}, ind::Integer) = (@inline; ind == 1 ? () : throw(BoundsError()))
×
2969
_ind2sub(dims::DimsInteger, ind::Integer) = (@inline; _ind2sub_recurse(dims, ind-1))
2,065✔
2970
_ind2sub(inds::Indices, ind::Integer)     = (@inline; _ind2sub_recurse(inds, ind-1))
204,056✔
2971
_ind2sub(inds::Indices{1}, ind::Integer) =
1✔
2972
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
2973
_ind2sub(inds::Tuple{OneTo}, ind::Integer) = (ind,)
12✔
2974

2975
_ind2sub_recurse(::Tuple{}, ind) = (ind+1,)
×
2976
function _ind2sub_recurse(indslast::NTuple{1}, ind)
206,121✔
2977
    @inline
206,121✔
2978
    (_lookup(ind, indslast[1]),)
206,121✔
2979
end
2980
function _ind2sub_recurse(inds, ind)
367,858✔
2981
    @inline
367,858✔
2982
    r1 = inds[1]
367,858✔
2983
    indnext, f, l = _div(ind, r1)
367,858✔
2984
    (ind-l*indnext+f, _ind2sub_recurse(tail(inds), indnext)...)
367,858✔
2985
end
2986

2987
_lookup(ind, d::Integer) = ind+1
2,065✔
2988
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
204,056✔
2989
_div(ind, d::Integer) = div(ind, d), 1, d
2,065✔
2990
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
731,586✔
2991

2992
# Vectorized forms
2993
function _sub2ind(inds::Indices{1}, I1::AbstractVector{T}, I::AbstractVector{T}...) where T<:Integer
×
2994
    throw(ArgumentError("Linear indexing is not defined for one-dimensional arrays"))
×
2995
end
2996
_sub2ind(inds::Tuple{OneTo}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
2997
    _sub2ind_vecs(inds, I1, I...)
2998
_sub2ind(inds::Union{DimsInteger,Indices}, I1::AbstractVector{T}, I::AbstractVector{T}...) where {T<:Integer} =
×
2999
    _sub2ind_vecs(inds, I1, I...)
3000
function _sub2ind_vecs(inds, I::AbstractVector...)
×
3001
    I1 = I[1]
×
3002
    Iinds = axes1(I1)
×
3003
    for j = 2:length(I)
×
3004
        axes1(I[j]) == Iinds || throw(DimensionMismatch("indices of I[1] ($(Iinds)) does not match indices of I[$j] ($(axes1(I[j])))"))
×
3005
    end
×
3006
    Iout = similar(I1)
×
3007
    _sub2ind!(Iout, inds, Iinds, I)
×
3008
    Iout
×
3009
end
3010

3011
function _sub2ind!(Iout, inds, Iinds, I)
×
3012
    @noinline
×
3013
    for i in Iinds
×
3014
        # Iout[i] = _sub2ind(inds, map(Ij -> Ij[i], I)...)
3015
        Iout[i] = sub2ind_vec(inds, i, I)
×
3016
    end
×
3017
    Iout
×
3018
end
3019

3020
sub2ind_vec(inds, i, I) = (@inline; _sub2ind(inds, _sub2ind_vec(i, I...)...))
×
3021
_sub2ind_vec(i, I1, I...) = (@inline; (I1[i], _sub2ind_vec(i, I...)...))
×
3022
_sub2ind_vec(i) = ()
×
3023

3024
function _ind2sub(inds::Union{DimsInteger{N},Indices{N}}, ind::AbstractVector{<:Integer}) where N
×
3025
    M = length(ind)
×
3026
    t = ntuple(n->similar(ind),Val(N))
×
3027
    for (i,idx) in pairs(IndexLinear(), ind)
×
3028
        sub = _ind2sub(inds, idx)
×
3029
        for j = 1:N
×
3030
            t[j][i] = sub[j]
×
3031
        end
×
3032
    end
×
3033
    t
×
3034
end
3035

3036
## iteration utilities ##
3037

3038
"""
3039
    foreach(f, c...) -> Nothing
3040

3041
Call function `f` on each element of iterable `c`.
3042
For multiple iterable arguments, `f` is called elementwise, and iteration stops when
3043
any iterator is finished.
3044

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

3048
# Examples
3049
```jldoctest
3050
julia> tri = 1:3:7; res = Int[];
3051

3052
julia> foreach(x -> push!(res, x^2), tri)
3053

3054
julia> res
3055
3-element Vector{$(Int)}:
3056
  1
3057
 16
3058
 49
3059

3060
julia> foreach((x, y) -> println(x, " with ", y), tri, 'a':'z')
3061
1 with a
3062
4 with b
3063
7 with c
3064
```
3065
"""
3066
foreach(f) = (f(); nothing)
2✔
3067
foreach(f, itr) = (for x in itr; f(x); end; nothing)
206,904,386✔
3068
foreach(f, itrs...) = (for z in zip(itrs...); f(z...); end; nothing)
11✔
3069

3070
## map over arrays ##
3071

3072
## transform any set of dimensions
3073
## dims specifies which dimensions will be transformed. for example
3074
## dims==1:2 will call f on all slices A[:,:,...]
3075
"""
3076
    mapslices(f, A; dims)
3077

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

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

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

3087
# Examples
3088
```jldoctest
3089
julia> A = reshape(1:30,(2,5,3))
3090
2×5×3 reshape(::UnitRange{$Int}, 2, 5, 3) with eltype $Int:
3091
[:, :, 1] =
3092
 1  3  5  7   9
3093
 2  4  6  8  10
3094

3095
[:, :, 2] =
3096
 11  13  15  17  19
3097
 12  14  16  18  20
3098

3099
[:, :, 3] =
3100
 21  23  25  27  29
3101
 22  24  26  28  30
3102

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

3105
julia> B = mapslices(f, A, dims=(1,2))
3106
1×4×3 Array{$Int, 3}:
3107
[:, :, 1] =
3108
 1  1  1  1
3109

3110
[:, :, 2] =
3111
 11  11  11  11
3112

3113
[:, :, 3] =
3114
 21  21  21  21
3115

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

3118
julia> B == stack(f2, eachslice(A, dims=3))
3119
true
3120

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

3123
julia> mapslices(g, A, dims=[1,3])
3124
1×5×1 Array{Rational{$Int}, 3}:
3125
[:, :, 1] =
3126
 1//21  3//23  1//5  7//27  9//29
3127

3128
julia> map(g, eachslice(A, dims=2))
3129
5-element Vector{Rational{$Int}}:
3130
 1//21
3131
 3//23
3132
 1//5
3133
 7//27
3134
 9//29
3135

3136
julia> mapslices(sum, A; dims=(1,3)) == sum(A; dims=(1,3))
3137
true
3138
```
3139

3140
Notice that in `eachslice(A; dims=2)`, the specified dimension is the
3141
one *without* a colon in the slice. This is `view(A,:,i,:)`, whereas
3142
`mapslices(f, A; dims=(1,3))` uses `A[:,i,:]`. The function `f` may mutate
3143
values in the slice without affecting `A`.
3144
"""
3145
function mapslices(f, A::AbstractArray; dims)
892✔
3146
    isempty(dims) && return map(f, A)
446✔
3147

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

3158
    # Apply the function to the first slice in order to determine the next steps
3159
    idx1 = ntuple(d -> d in dims ? (:) : firstindex(A,d), ndims(A))
3,156✔
3160
    Aslice = A[idx1...]
829✔
3161
    r1 = f(Aslice)
532✔
3162

3163
    res1 = if r1 isa AbstractArray && ndims(r1) > 0
449✔
3164
        n = sum(dim_mask)
29✔
3165
        if ndims(r1) > n && any(ntuple(d -> size(r1,d+n)>1, ndims(r1)-n))
33✔
3166
            s = size(r1)[1:n]
1✔
3167
            throw(DimensionMismatch("mapslices cannot assign slice f(x) of size $(size(r1)) into output of size $s"))
1✔
3168
        end
3169
        r1
28✔
3170
    else
3171
        # If the result of f on a single slice is a scalar then we add singleton
3172
        # dimensions. When adding the dimensions, we have to respect the
3173
        # index type of the input array (e.g. in the case of OffsetArrays)
3174
        _res1 = similar(Aslice, typeof(r1), reduced_indices(Aslice, 1:ndims(Aslice)))
432✔
3175
        _res1[begin] = r1
414✔
3176
        _res1
813✔
3177
    end
3178

3179
    # Determine result size and allocate. We always pad ndims(res1) out to length(dims):
3180
    din = Ref(0)
442✔
3181
    Rsize = ntuple(ndims(A)) do d
442✔
3182
        if d in dims
3,237✔
3183
            axes(res1, din[] += 1)
875✔
3184
        else
3185
            axes(A,d)
805✔
3186
        end
3187
    end
3188
    R = similar(res1, Rsize)
459✔
3189

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

3195
    # That skips the first element, which we already have:
3196
    ridx = ntuple(d -> d in dims ? Slice(axes(R,d)) : firstindex(A,d), ndims(A))
2,508✔
3197
    concatenate_setindex!(R, res1, ridx...)
455✔
3198

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

3206
    _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
468✔
3207
    return R
442✔
3208
end
3209

3210
@noinline function _inner_mapslices!(R, indices, f, A, dim_mask, Aslice, safe_for_reuse)
442✔
3211
    must_extend = any(dim_mask .& size(R) .> 1)
2,010✔
3212
    if safe_for_reuse
442✔
3213
        # when f returns an array, R[ridx...] = f(Aslice) line copies elements,
3214
        # so we can reuse Aslice
3215
        for I in indices
418✔
3216
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
11,173✔
3217
            _unsafe_getindex!(Aslice, A, idx...)
11,173✔
3218
            r = f(Aslice)
15,359✔
3219
            if r isa AbstractArray || must_extend
11,173✔
3220
                ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
65✔
3221
                R[ridx...] = r
104✔
3222
            else
3223
                ridx = ifelse.(dim_mask, first.(axes(R)), Tuple(I))
11,108✔
3224
                R[ridx...] = r
11,108✔
3225
            end
3226
        end
11,173✔
3227
    else
3228
        # we can't guarantee safety (#18524), so allocate new storage for each slice
3229
        for I in indices
74✔
3230
            idx = ifelse.(dim_mask, Slice.(axes(A)), Tuple(I))
1,857✔
3231
            ridx = ifelse.(dim_mask, Slice.(axes(R)), Tuple(I))
1,857✔
3232
            concatenate_setindex!(R, f(A[idx...]), ridx...)
1,870✔
3233
        end
1,857✔
3234
    end
3235
end
3236

3237
concatenate_setindex!(R, v, I...) = (R[I...] .= (v,); R)
3,702✔
3238
concatenate_setindex!(R, X::AbstractArray, I...) = (R[I...] = X)
448✔
3239

3240
## 0 arguments
3241

3242
map(f) = f()
1✔
3243

3244
## 1 argument
3245

3246
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3,610✔
3247
    for (i,j) in zip(eachindex(dest),eachindex(A))
234,575,261✔
3248
        val = f(@inbounds A[j])
235,846,611✔
3249
        @inbounds dest[i] = val
140,710,657✔
3250
    end
174,384,452✔
3251
    return dest
127,740,563✔
3252
end
3253

3254
# map on collections
3255
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
141,410✔
3256

3257
mapany(f, A::AbstractArray) = map!(f, Vector{Any}(undef, length(A)), A)
2,914✔
3258
mapany(f, itr) = Any[f(x) for x in itr]
×
3259

3260
"""
3261
    map(f, c...) -> collection
3262

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

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

3268
# Examples
3269
```jldoctest
3270
julia> map(x -> x * 2, [1, 2, 3])
3271
3-element Vector{Int64}:
3272
 2
3273
 4
3274
 6
3275

3276
julia> map(+, [1, 2, 3], [10, 20, 30, 400, 5000])
3277
3-element Vector{Int64}:
3278
 11
3279
 22
3280
 33
3281
```
3282
"""
3283
map(f, A) = collect(Generator(f,A)) # default to returning an Array for `map` on general iterators
402✔
3284

3285
map(f, ::AbstractDict) = error("map is not defined on dictionaries")
1✔
3286
map(f, ::AbstractSet) = error("map is not defined on sets")
1✔
3287

3288
## 2 argument
3289
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
238✔
3290
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
463✔
3291
        @inbounds a, b = A[j], B[k]
370,419✔
3292
        val = f(a, b)
328,292✔
3293
        @inbounds dest[i] = val
328,292✔
3294
    end
656,359✔
3295
    return dest
238✔
3296
end
3297

3298
## N argument
3299

3300
@inline ith_all(i, ::Tuple{}) = ()
430✔
3301
function ith_all(i, as)
1,290✔
3302
    @_propagate_inbounds_meta
1,290✔
3303
    return (as[1][i], ith_all(i, tail(as))...)
1,290✔
3304
end
3305

3306
function map_n!(f::F, dest::AbstractArray, As) where F
10✔
3307
    idxs1 = LinearIndices(As[1])
10✔
3308
    @boundscheck LinearIndices(dest) == idxs1 && all(x -> LinearIndices(x) == idxs1, As)
80✔
3309
    for i = idxs1
20✔
3310
        @inbounds I = ith_all(i, As)
430✔
3311
        val = f(I...)
430✔
3312
        @inbounds dest[i] = val
430✔
3313
    end
850✔
3314
    return dest
10✔
3315
end
3316

3317
"""
3318
    map!(function, destination, collection...)
3319

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

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

3325
# Examples
3326
```jldoctest
3327
julia> a = zeros(3);
3328

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

3331
julia> a
3332
3-element Vector{Float64}:
3333
 2.0
3334
 4.0
3335
 6.0
3336

3337
julia> map!(+, zeros(Int, 5), 100:999, 1:3)
3338
5-element Vector{$(Int)}:
3339
 101
3340
 103
3341
 105
3342
   0
3343
   0
3344
```
3345
"""
3346
function map!(f::F, dest::AbstractArray, As::AbstractArray...) where {F}
11✔
3347
    isempty(As) && throw(ArgumentError(
11✔
3348
        """map! requires at least one "source" argument"""))
3349
    map_n!(f, dest, As)
10✔
3350
end
3351

3352
"""
3353
    map(f, A::AbstractArray...) -> N-array
3354

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

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

3360
# Examples
3361
```
3362
julia> map(//, [1 2; 3 4], [4 3; 2 1])
3363
2×2 Matrix{Rational{$Int}}:
3364
 1//4  2//3
3365
 3//2  4//1
3366

3367
julia> map(+, [1 2; 3 4], zeros(2,1))
3368
ERROR: DimensionMismatch
3369

3370
julia> map(+, [1 2; 3 4], [1,10,100,1000], zeros(3,1))  # iterates until 3rd is exhausted
3371
3-element Vector{Float64}:
3372
   2.0
3373
  13.0
3374
 102.0
3375
```
3376
"""
3377
map(f, iters...) = collect(Generator(f, iters...))
956✔
3378

3379
# multi-item push!, pushfirst! (built on top of type-specific 1-item version)
3380
# (note: must not cause a dispatch loop when 1-item case is not defined)
3381
push!(A, a, b) = push!(push!(A, a), b)
1,014✔
3382
push!(A, a, b, c...) = push!(push!(A, a, b), c...)
2✔
3383
pushfirst!(A, a, b) = pushfirst!(pushfirst!(A, b), a)
×
3384
pushfirst!(A, a, b, c...) = pushfirst!(pushfirst!(A, c...), a, b)
2✔
3385

3386
## hashing AbstractArray ##
3387

3388
const hash_abstractarray_seed = UInt === UInt64 ? 0x7e2d6fb6448beb77 : 0xd4514ce5
3389
function hash(A::AbstractArray, h::UInt)
12,827✔
3390
    h += hash_abstractarray_seed
12,827✔
3391
    # Axes are themselves AbstractArrays, so hashing them directly would stack overflow
3392
    # Instead hash the tuple of firsts and lasts along each dimension
3393
    h = hash(map(first, axes(A)), h)
13,007✔
3394
    h = hash(map(last, axes(A)), h)
13,007✔
3395

3396
    # For short arrays, it's not worth doing anything complicated
3397
    if length(A) < 8192
13,007✔
3398
        for x in A
16,199✔
3399
            h = hash(x, h)
552,481✔
3400
        end
682,819✔
3401
        return h
12,823✔
3402
    end
3403

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

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

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

3425
    # Start at the last index
3426
    keyidx = last(ks)
4✔
3427
    linidx = key_to_linear[keyidx]
4✔
3428
    fibskip = prevfibskip = oneunit(linidx)
4✔
3429
    first_linear = first(LinearIndices(linear_to_key))
4✔
3430
    n = 0
4✔
3431
    while true
28,192✔
3432
        n += 1
28,192✔
3433
        # Hash the element
3434
        elt = A[keyidx]
28,192✔
3435
        h = hash(keyidx=>elt, h)
28,192✔
3436

3437
        # Skip backwards a Fibonacci number of indices -- this is a linear index operation
3438
        linidx = key_to_linear[keyidx]
28,192✔
3439
        linidx < fibskip + first_linear && break
28,192✔
3440
        linidx -= fibskip
28,188✔
3441
        keyidx = linear_to_key[linidx]
28,188✔
3442

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

3453
        # Find a key index with a value distinct from `elt` -- might be `keyidx` itself
3454
        keyidx = findprev(!isequal(elt), A, keyidx)
56,376✔
3455
        keyidx === nothing && break
28,188✔
3456
    end
28,188✔
3457

3458
    return h
4✔
3459
end
3460

3461
# The semantics of `collect` are weird. Better to write our own
3462
function rest(a::AbstractArray{T}, state...) where {T}
11✔
3463
    v = Vector{T}(undef, 0)
11✔
3464
    # assume only very few items are taken from the front
3465
    sizehint!(v, length(a))
11✔
3466
    return foldl(push!, Iterators.rest(a, state...), init=v)
11✔
3467
end
3468

3469

3470
## keepat! ##
3471

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

3474
function _keepat!(a::AbstractVector, inds)
11✔
3475
    local prev
11✔
3476
    i = firstindex(a)
11✔
3477
    for k in inds
19✔
3478
        if @isdefined(prev)
34✔
3479
            prev < k || throw(ArgumentError("indices must be unique and sorted"))
27✔
3480
        end
3481
        ak = a[k] # must happen even when i==k for bounds checking
32✔
3482
        if i != k
29✔
3483
            @inbounds a[i] = ak # k > i, so a[i] is inbounds
13✔
3484
        end
3485
        prev = k
29✔
3486
        i = nextind(a, i)
29✔
3487
    end
51✔
3488
    deleteat!(a, i:lastindex(a))
11✔
3489
    return a
6✔
3490
end
3491

3492
function _keepat!(a::AbstractVector, m::AbstractVector{Bool})
5✔
3493
    length(m) == length(a) || throw(BoundsError(a, m))
7✔
3494
    j = firstindex(a)
3✔
3495
    for i in eachindex(a, m)
5✔
3496
        @inbounds begin
20✔
3497
            if m[i]
20✔
3498
                i == j || (a[j] = a[i])
19✔
3499
                j = nextind(a, j)
11✔
3500
            end
3501
        end
3502
    end
38✔
3503
    deleteat!(a, j:lastindex(a))
3✔
3504
end
3505

3506
## 1-d circshift ##
3507
function circshift!(a::AbstractVector, shift::Integer)
1,137✔
3508
    n = length(a)
1,137✔
3509
    n == 0 && return
1,137✔
3510
    shift = mod(shift, n)
2,274✔
3511
    shift == 0 && return
1,137✔
3512
    l = lastindex(a)
725✔
3513
    reverse!(a, firstindex(a), l-shift)
725✔
3514
    reverse!(a, l-shift+1, lastindex(a))
725✔
3515
    reverse!(a)
725✔
3516
    return a
725✔
3517
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