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

JuliaLang / julia / #37447

pending completion
#37447

push

local

web-flow
`@inbounds` in `copyto!` for structured broadcasting (#48437)

* `@inbounds` in diagonal broadcasting

* inbounds copyto for bi/tridiag and triangular

* Move inbounds to broadcast getindex

---------

Co-authored-by: Daniel Karrasch <daniel.karrasch@posteo.de>

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

71468 of 82456 relevant lines covered (86.67%)

32670681.69 hits per line

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

92.26
/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
5,803,943✔
17
convert(::Type{AbstractArray{T}}, a::AbstractArray) where {T} = AbstractArray{T}(a)::AbstractArray{T}
20,668✔
18
convert(::Type{AbstractArray{T,N}}, a::AbstractArray{<:Any,N}) where {T,N} = AbstractArray{T,N}(a)::AbstractArray{T,N}
27,412✔
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,460,341✔
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}
860,720✔
76
    @inline
859,223✔
77
    d::Integer <= N ? axes(A)[d] : OneTo(1)
862,409✔
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)
160,137,484✔
97
    @inline
138,684,649✔
98
    map(oneto, size(A))
5,370,580,258✔
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)...)
603,123✔
111
has_offset_axes(A::AbstractVector) = Int(firstindex(A))::Int != 1 # improve performance of a common case (ranges)
195,641✔
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...)
451,232✔
115
has_offset_axes(::Colon) = false
67✔
116
has_offset_axes(::Array) = false
606,285✔
117

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

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

125
!!! compat "Julia 1.2"
126
     This function requires at least Julia 1.2.
127
"""
128
require_one_based_indexing(A...) = !has_offset_axes(A...) || throw(ArgumentError("offset arrays are not supported but got an array with index other than 1"))
1,414,142✔
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])
5,440,228,898✔
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,067✔
163
keys(a::AbstractVector) = LinearIndices(a)
35,345,325✔
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,716,133✔
186

187
keytype(A::Type{<:AbstractArray}) = CartesianIndex{ndims(A)}
2✔
188
keytype(A::Type{<:AbstractVector}) = Int
22,716,133✔
189

190
valtype(a::AbstractArray) = valtype(typeof(a))
15✔
191

192
"""
193
    valtype(T::Type{<:AbstractArray})
194
    valtype(A::AbstractArray)
195

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

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

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

210
prevind(::AbstractArray, i::Integer) = Int(i)-1
137,375✔
211
nextind(::AbstractArray, i::Integer) = Int(i)+1
169,225,453✔
212

213

214
"""
215
    eltype(type)
216

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

223
See also: [`keytype`](@ref), [`typeof`](@ref).
224

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

230
julia> eltype(fill(0x1, (2,2)))
231
UInt8
232
```
233
"""
234
eltype(::Type) = Any
14,093✔
235
eltype(::Type{Bottom}) = throw(ArgumentError("Union{} does not have elements"))
1✔
236
eltype(x) = eltype(typeof(x))
4,618,031✔
237
eltype(::Type{<:AbstractArray{E}}) where {E} = @isdefined(E) ? E : Any
2,606,875✔
238

239
"""
240
    elsize(type)
241

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

246
# Examples
247
```jldoctest
248
julia> Base.elsize(rand(Float32, 10))
249
4
250
```
251
"""
252
elsize(A::AbstractArray) = elsize(typeof(A))
1,640,762✔
253

254
"""
255
    ndims(A::AbstractArray) -> Integer
256

257
Return the number of dimensions of `A`.
258

259
See also: [`size`](@ref), [`axes`](@ref).
260

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

265
julia> ndims(A)
266
3
267
```
268
"""
269
ndims(::AbstractArray{T,N}) where {T,N} = N
797,665✔
270
ndims(::Type{<:AbstractArray{<:Any,N}}) where {N} = N
57✔
271

272
"""
273
    length(collection) -> Integer
274

275
Return the number of elements in the collection.
276

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

279
See also: [`size`](@ref), [`ndims`](@ref), [`eachindex`](@ref).
280

281
# Examples
282
```jldoctest
283
julia> length(1:5)
284
5
285

286
julia> length([1, 2, 3, 4])
287
4
288

289
julia> length([1 2; 3 4])
290
4
291
```
292
"""
293
length
294

295
"""
296
    length(A::AbstractArray)
297

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

300
# Examples
301
```jldoctest
302
julia> length([1, 2, 3, 4])
303
4
304

305
julia> length([1 2; 3 4])
306
4
307
```
308
"""
309
length(t::AbstractArray) = (@inline; prod(size(t)))
15,470,343✔
310

311
# `eachindex` is mostly an optimization of `keys`
312
eachindex(itrs...) = keys(itrs...)
251✔
313

314
# eachindex iterates over all indices. IndexCartesian definitions are later.
315
eachindex(A::AbstractVector) = (@inline(); axes1(A))
990,375,285✔
316

317

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

325
"""
326
    eachindex(A...)
327
    eachindex(::IndexStyle, A::AbstractArray...)
328

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

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

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

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

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

353
# Examples
354
```jldoctest
355
julia> A = [10 20; 30 40];
356

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

365
julia> for i in eachindex(view(A, 1:2, 1:1)) # Cartesian indexing
366
           println(i)
367
       end
368
CartesianIndex(1, 1)
369
CartesianIndex(2, 1)
370
```
371
"""
372
eachindex(A::AbstractArray) = (@inline(); eachindex(IndexStyle(A), A))
158,687✔
373

374
function eachindex(A::AbstractArray, B::AbstractArray)
37✔
375
    @inline
37✔
376
    eachindex(IndexStyle(A,B), A, B)
37✔
377
end
378
function eachindex(A::AbstractArray, B::AbstractArray...)
×
379
    @inline
×
380
    eachindex(IndexStyle(A,B...), A, B...)
×
381
end
382
eachindex(::IndexLinear, A::AbstractArray) = (@inline; oneto(length(A)))
8,513,078✔
383
eachindex(::IndexLinear, A::AbstractVector) = (@inline; axes1(A))
4,264,596,731✔
384
function eachindex(::IndexLinear, A::AbstractArray, B::AbstractArray...)
34✔
385
    @inline
34✔
386
    indsA = eachindex(IndexLinear(), A)
34✔
387
    _all_match_first(X->eachindex(IndexLinear(), X), indsA, B...) ||
69✔
388
        throw_eachindex_mismatch_indices(IndexLinear(), eachindex(A), eachindex.(B)...)
389
    indsA
33✔
390
end
391
function _all_match_first(f::F, inds, A, B...) where F<:Function
39✔
392
    @inline
39✔
393
    (inds == f(A)) & _all_match_first(f, inds, B...)
43✔
394
end
395
_all_match_first(f::F, inds) where F<:Function = true
39✔
396

397
# keys with an IndexStyle
398
keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...)
×
399

400
"""
401
    lastindex(collection) -> Integer
402
    lastindex(collection, d) -> Integer
403

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

406
The syntaxes `A[end]` and `A[end, end]` lower to `A[lastindex(A)]` and
407
`A[lastindex(A, 1), lastindex(A, 2)]`, respectively.
408

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

411
# Examples
412
```jldoctest
413
julia> lastindex([1,2,4])
414
3
415

416
julia> lastindex(rand(3,4,5), 2)
417
4
418
```
419
"""
420
lastindex(a::AbstractArray) = (@inline; last(eachindex(IndexLinear(), a)))
1,979,495,154✔
421
lastindex(a, d) = (@inline; last(axes(a, d)))
3,452✔
422

423
"""
424
    firstindex(collection) -> Integer
425
    firstindex(collection, d) -> Integer
426

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

429
The syntaxes `A[begin]` and `A[1, begin]` lower to `A[firstindex(A)]` and
430
`A[1, firstindex(A, 2)]`, respectively.
431

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

434
# Examples
435
```jldoctest
436
julia> firstindex([1,2,4])
437
1
438

439
julia> firstindex(rand(3,4,5), 2)
440
1
441
```
442
"""
443
firstindex(a::AbstractArray) = (@inline; first(eachindex(IndexLinear(), a)))
1,465,995✔
444
firstindex(a, d) = (@inline; first(axes(a, d)))
2,677✔
445

446
first(a::AbstractArray) = a[first(eachindex(a))]
1,118,393✔
447

448
"""
449
    first(coll)
450

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

454
See also: [`only`](@ref), [`firstindex`](@ref), [`last`](@ref).
455

456
# Examples
457
```jldoctest
458
julia> first(2:2:10)
459
2
460

461
julia> first([1; 2; 3; 4])
462
1
463
```
464
"""
465
function first(itr)
3,021,620✔
466
    x = iterate(itr)
6,039,974✔
467
    x === nothing && throw(ArgumentError("collection must be non-empty"))
3,021,620✔
468
    x[1]
3,021,618✔
469
end
470

471
"""
472
    first(itr, n::Integer)
473

474
Get the first `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
475
long enough.
476

477
See also: [`startswith`](@ref), [`Iterators.take`](@ref).
478

479
!!! compat "Julia 1.6"
480
    This method requires at least Julia 1.6.
481

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

489
julia> first(1:6, 10)
490
1:6
491

492
julia> first(Bool[], 1)
493
Bool[]
494
```
495
"""
496
first(itr, n::Integer) = collect(Iterators.take(itr, n))
34✔
497
# Faster method for vectors
498
function first(v::AbstractVector, n::Integer)
1,490✔
499
    n < 0 && throw(ArgumentError("Number of elements must be nonnegative"))
1,490✔
500
    v[range(begin, length=min(n, checked_length(v)))]
1,488✔
501
end
502

503
"""
504
    last(coll)
505

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

510
See also [`first`](@ref), [`endswith`](@ref).
511

512
# Examples
513
```jldoctest
514
julia> last(1:2:10)
515
9
516

517
julia> last([1; 2; 3; 4])
518
4
519
```
520
"""
521
last(a) = a[end]
21,126,719✔
522

523
"""
524
    last(itr, n::Integer)
525

526
Get the last `n` elements of the iterable collection `itr`, or fewer elements if `itr` is not
527
long enough.
528

529
!!! compat "Julia 1.6"
530
    This method requires at least Julia 1.6.
531

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

539
julia> last(1:6, 10)
540
1:6
541

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

553
"""
554
    strides(A)
555

556
Return a tuple of the memory strides in each dimension.
557

558
See also: [`stride`](@ref).
559

560
# Examples
561
```jldoctest
562
julia> A = fill(1, (3,4,5));
563

564
julia> strides(A)
565
(1, 3, 12)
566
```
567
"""
568
function strides end
569

570
"""
571
    stride(A, k::Integer)
572

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

575
See also: [`strides`](@ref).
576

577
# Examples
578
```jldoctest
579
julia> A = fill(1, (3,4,5));
580

581
julia> stride(A,2)
582
3
583

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

600
@inline size_to_strides(s, d, sz...) = (s, size_to_strides(s * d, sz...)...)
314,536✔
601
size_to_strides(s, d) = (s,)
107✔
602
size_to_strides(s) = ()
×
603

604

605
function isassigned(a::AbstractArray, i::Integer...)
189,237✔
606
    try
189,237✔
607
        a[i...]
309,476✔
608
        true
189,232✔
609
    catch e
610
        if isa(e, BoundsError) || isa(e, UndefRefError)
63✔
611
            return false
33✔
612
        else
613
            rethrow()
1✔
614
        end
615
    end
616
end
617

618
function isstored(A::AbstractArray{<:Any,N}, I::Vararg{Integer,N}) where {N}
4✔
619
    @boundscheck checkbounds(A, I...)
7✔
620
    return true
1✔
621
end
622

623
# used to compute "end" for last index
624
function trailingsize(A, n)
×
625
    s = 1
×
626
    for i=n:ndims(A)
×
627
        s *= size(A,i)
×
628
    end
×
629
    return s
×
630
end
631
function trailingsize(inds::Indices, n)
×
632
    s = 1
×
633
    for i=n:length(inds)
×
634
        s *= length(inds[i])
×
635
    end
×
636
    return s
×
637
end
638
# This version is type-stable even if inds is heterogeneous
639
function trailingsize(inds::Indices)
×
640
    @inline
×
641
    prod(map(length, inds))
×
642
end
643

644
## Bounds checking ##
645

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

660
"""
661
    checkbounds(Bool, A, I...)
662

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

668
See also [`checkindex`](@ref).
669

670
# Examples
671
```jldoctest
672
julia> A = rand(3, 3);
673

674
julia> checkbounds(Bool, A, 2)
675
true
676

677
julia> checkbounds(Bool, A, 3, 4)
678
false
679

680
julia> checkbounds(Bool, A, 1:3)
681
true
682

683
julia> checkbounds(Bool, A, 1:3, 2:4)
684
false
685
```
686
"""
687
function checkbounds(::Type{Bool}, A::AbstractArray, I...)
95,689,292✔
688
    @inline
95,689,292✔
689
    checkbounds_indices(Bool, axes(A), I)
96,086,401✔
690
end
691

692
# Linear indexing is explicitly allowed when there is only one (non-cartesian) index
693
function checkbounds(::Type{Bool}, A::AbstractArray, i)
45,434,994✔
694
    @inline
39,229,624✔
695
    checkindex(Bool, eachindex(IndexLinear(), A), i)
2,307,125,378✔
696
end
697
# As a special extension, allow using logical arrays that match the source array exactly
698
function checkbounds(::Type{Bool}, A::AbstractArray{<:Any,N}, I::AbstractArray{Bool,N}) where N
88✔
699
    @inline
88✔
700
    axes(A) == axes(I)
143✔
701
end
702

703
"""
704
    checkbounds(A, I...)
705

706
Throw an error if the specified indices `I` are not in bounds for the given array `A`.
707
"""
708
function checkbounds(A::AbstractArray, I...)
541,244,913✔
709
    @inline
132,149,450✔
710
    checkbounds(Bool, A, I...) || throw_boundserror(A, I)
541,245,446✔
711
    nothing
541,244,506✔
712
end
713

714
"""
715
    checkbounds_indices(Bool, IA, I)
716

717
Return `true` if the "requested" indices in the tuple `I` fall within
718
the bounds of the "permitted" indices specified by the tuple
719
`IA`. This function recursively consumes elements of these tuples,
720
usually in a 1-for-1 fashion,
721

722
    checkbounds_indices(Bool, (IA1, IA...), (I1, I...)) = checkindex(Bool, IA1, I1) &
723
                                                          checkbounds_indices(Bool, IA, I)
724

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

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

732
See also [`checkbounds`](@ref).
733
"""
734
function checkbounds_indices(::Type{Bool}, IA::Tuple, I::Tuple)
208,082,765✔
735
    @inline
11,708,479✔
736
    checkindex(Bool, IA[1], I[1])::Bool & checkbounds_indices(Bool, tail(IA), tail(I))
372,189,249✔
737
end
738
function checkbounds_indices(::Type{Bool}, ::Tuple{}, I::Tuple)
20,183✔
739
    @inline
3,563✔
740
    checkindex(Bool, OneTo(1), I[1])::Bool & checkbounds_indices(Bool, (), tail(I))
32,638✔
741
end
742
checkbounds_indices(::Type{Bool}, IA::Tuple, ::Tuple{}) = (@inline; all(x->length(x)==1, IA))
577,845✔
743
checkbounds_indices(::Type{Bool}, ::Tuple{}, ::Tuple{}) = true
×
744

745
throw_boundserror(A, I) = (@noinline; throw(BoundsError(A, I)))
566✔
746

747
# check along a single dimension
748
"""
749
    checkindex(Bool, inds::AbstractUnitRange, index)
750

751
Return `true` if the given `index` is within the bounds of
752
`inds`. Custom types that would like to behave as indices for all
753
arrays can extend this method in order to provide a specialized bounds
754
checking implementation.
755

756
See also [`checkbounds`](@ref).
757

758
# Examples
759
```jldoctest
760
julia> checkindex(Bool, 1:20, 8)
761
true
762

763
julia> checkindex(Bool, 1:20, 21)
764
false
765
```
766
"""
767
checkindex(::Type{Bool}, inds::AbstractUnitRange, i) =
×
768
    throw(ArgumentError("unable to check bounds for indices of type $(typeof(i))"))
769
checkindex(::Type{Bool}, inds::AbstractUnitRange, i::Real) = (first(inds) <= i) & (i <= last(inds))
2,990,307,378✔
770
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Colon) = true
446✔
771
checkindex(::Type{Bool}, inds::AbstractUnitRange, ::Slice) = true
75✔
772
function checkindex(::Type{Bool}, inds::AbstractUnitRange, r::AbstractRange)
8,306,897✔
773
    @_propagate_inbounds_meta
936,763✔
774
    isempty(r) | (checkindex(Bool, inds, first(r)) & checkindex(Bool, inds, last(r)))
304,860,239✔
775
end
776
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractVector{Bool}) = indx == axes1(I)
2✔
777
checkindex(::Type{Bool}, indx::AbstractUnitRange, I::AbstractArray{Bool}) = false
1✔
778
function checkindex(::Type{Bool}, inds::AbstractUnitRange, I::AbstractArray)
3,113✔
779
    @inline
632✔
780
    b = true
632✔
781
    for i in I
6,088✔
782
        b &= checkindex(Bool, inds, i)
6,392,912✔
783
    end
6,421,354✔
784
    b
5,490✔
785
end
786

787
# See also specializations in multidimensional
788

789
## Constructors ##
790

791
# default arguments to similar()
792
"""
793
    similar(array, [element_type=eltype(array)], [dims=size(array)])
794

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

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

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

807
```julia-repl
808
julia> similar(1:10, 1, 4)
809
1×4 Matrix{Int64}:
810
 4419743872  4374413872  4419743888  0
811
```
812

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

816
```julia-repl
817
julia> similar(trues(10,10), 2)
818
2-element BitVector:
819
 0
820
 0
821
```
822

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

826
```julia-repl
827
julia> similar(falses(10), Float64, 2, 4)
828
2×4 Matrix{Float64}:
829
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
830
 2.18425e-314  2.18425e-314  2.18425e-314  2.18425e-314
831
```
832

833
See also: [`undef`](@ref), [`isassigned`](@ref).
834
"""
835
similar(a::AbstractArray{T}) where {T}                             = similar(a, T)
3,346✔
836
similar(a::AbstractArray, ::Type{T}) where {T}                     = similar(a, T, to_shape(axes(a)))
3,366✔
837
similar(a::AbstractArray{T}, dims::Tuple) where {T}                = similar(a, T, to_shape(dims))
53,503,257✔
838
similar(a::AbstractArray{T}, dims::DimOrInd...) where {T}          = similar(a, T, to_shape(dims))
821✔
839
similar(a::AbstractArray, ::Type{T}, dims::DimOrInd...) where {T}  = similar(a, T, to_shape(dims))
5,568,741✔
840
# Similar supports specifying dims as either Integers or AbstractUnitRanges or any mixed combination
841
# thereof. Ideally, we'd just convert Integers to OneTos and then call a canonical method with the axes,
842
# but we don't want to require all AbstractArray subtypes to dispatch on Base.OneTo. So instead we
843
# define this method to convert supported axes to Ints, with the expectation that an offset array
844
# package will define a method with dims::Tuple{Union{Integer, UnitRange}, Vararg{Union{Integer, UnitRange}}}
845
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T} = similar(a, T, to_shape(dims))
151,695✔
846
similar(a::AbstractArray, ::Type{T}, dims::Tuple{Integer, Vararg{Integer}}) where {T} = similar(a, T, to_shape(dims))
5✔
847
# similar creates an Array by default
848
similar(a::AbstractArray, ::Type{T}, dims::Dims{N}) where {T,N}    = Array{T,N}(undef, dims)
5,543,656✔
849

850
to_shape(::Tuple{}) = ()
18✔
851
to_shape(dims::Dims) = dims
5,587✔
852
to_shape(dims::DimsOrInds) = map(to_shape, dims)::DimsOrInds
5,170,386✔
853
# each dimension
854
to_shape(i::Int) = i
4✔
855
to_shape(i::Integer) = Int(i)
38✔
856
to_shape(r::OneTo) = Int(last(r))
41,176✔
857
to_shape(r::AbstractUnitRange) = r
196✔
858

859
"""
860
    similar(storagetype, axes)
861

862
Create an uninitialized mutable array analogous to that specified by
863
`storagetype`, but with `axes` specified by the last
864
argument.
865

866
**Examples**:
867

868
    similar(Array{Int}, axes(A))
869

870
creates an array that "acts like" an `Array{Int}` (and might indeed be
871
backed by one), but which is indexed identically to `A`. If `A` has
872
conventional indexing, this will be identical to
873
`Array{Int}(undef, size(A))`, but if `A` has unconventional indexing then the
874
indices of the result will match `A`.
875

876
    similar(BitArray, (axes(A, 2),))
877

878
would create a 1-dimensional logical array whose indices match those
879
of the columns of `A`.
880
"""
881
similar(::Type{T}, dims::DimOrInd...) where {T<:AbstractArray} = similar(T, dims)
49✔
882
similar(::Type{T}, shape::Tuple{Union{Integer, OneTo}, Vararg{Union{Integer, OneTo}}}) where {T<:AbstractArray} = similar(T, to_shape(shape))
397,997,098✔
883
similar(::Type{T}, dims::Dims) where {T<:AbstractArray} = T(undef, dims)
397,997,134✔
884

885
"""
886
    empty(v::AbstractVector, [eltype])
887

888
Create an empty vector similar to `v`, optionally changing the `eltype`.
889

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

892
# Examples
893

894
```jldoctest
895
julia> empty([1.0, 2.0, 3.0])
896
Float64[]
897

898
julia> empty([1.0, 2.0, 3.0], String)
899
String[]
900
```
901
"""
902
empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
328✔
903

904
# like empty, but should return a mutable collection, a Vector by default
905
emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}()
194✔
906
emptymutable(itr, ::Type{U}) where {U} = Vector{U}()
49✔
907

908
"""
909
    copy!(dst, src) -> dst
910

911
In-place [`copy`](@ref) of `src` into `dst`, discarding any pre-existing
912
elements in `dst`.
913
If `dst` and `src` are of the same type, `dst == src` should hold after
914
the call. If `dst` and `src` are multidimensional arrays, they must have
915
equal [`axes`](@ref).
916

917
See also [`copyto!`](@ref).
918

919
!!! compat "Julia 1.1"
920
    This method requires at least Julia 1.1. In Julia 1.0 this method
921
    is available from the `Future` standard library as `Future.copy!`.
922
"""
923
function copy!(dst::AbstractVector, src::AbstractVector)
35,026,630✔
924
    firstindex(dst) == firstindex(src) || throw(ArgumentError(
50✔
925
        "vectors must have the same offset for copy! (consider using `copyto!`)"))
926
    if length(dst) != length(src)
35,026,630✔
927
        resize!(dst, length(src))
35,026,551✔
928
    end
929
    copyto!(dst, src)
35,026,630✔
930
end
931

932
function copy!(dst::AbstractArray, src::AbstractArray)
15✔
933
    axes(dst) == axes(src) || throw(ArgumentError(
16✔
934
        "arrays must have the same axes for copy! (consider using `copyto!`)"))
935
    copyto!(dst, src)
14✔
936
end
937

938
## from general iterable to any array
939

940
# This is `Experimental.@max_methods 1 function copyto! end`, which is not
941
# defined at this point in bootstrap.
942
typeof(function copyto! end).name.max_methods = UInt8(1)
943

944
function copyto!(dest::AbstractArray, src)
3,887,795✔
945
    destiter = eachindex(dest)
3,887,849✔
946
    y = iterate(destiter)
5,169,738✔
947
    for x in src
6,188,176✔
948
        y === nothing &&
4,576,837✔
949
            throw(ArgumentError("destination has fewer elements than required"))
950
        dest[y[1]] = x
4,576,956✔
951
        y = iterate(destiter, y[2])
7,871,514✔
952
    end
7,382,407✔
953
    return dest
3,887,847✔
954
end
955

956
function copyto!(dest::AbstractArray, dstart::Integer, src)
276✔
957
    i = Int(dstart)
276✔
958
    if haslength(src) && length(dest) > 0
276✔
959
        @boundscheck checkbounds(dest, i:(i + length(src) - 1))
271✔
960
        for x in src
281✔
961
            @inbounds dest[i] = x
2,337✔
962
            i += 1
2,335✔
963
        end
2,803✔
964
    else
965
        for x in src
6✔
966
            dest[i] = x
6✔
967
            i += 1
3✔
968
        end
3✔
969
    end
970
    return dest
272✔
971
end
972

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

1002
# this method must be separate from the above since src might not have a length
1003
function copyto!(dest::AbstractArray, dstart::Integer, src, sstart::Integer, n::Integer)
100,314✔
1004
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",n,
100,314✔
1005
        ", elements, but n should be nonnegative")))
1006
    n == 0 && return dest
100,313✔
1007
    dmax = dstart + n - 1
100,312✔
1008
    inds = LinearIndices(dest)
100,312✔
1009
    if (dstart ∉ inds || dmax ∉ inds) | (sstart < 1)
200,622✔
1010
        sstart < 1 && throw(ArgumentError(LazyString("source start offset (",
4✔
1011
            sstart,") is < 1")))
1012
        throw(BoundsError(dest, dstart:dmax))
3✔
1013
    end
1014
    y = iterate(src)
100,308✔
1015
    for j = 1:(sstart-1)
200,606✔
1016
        if y === nothing
50,148,670,373✔
1017
            throw(ArgumentError(LazyString(
1✔
1018
                "source has fewer elements than required, ",
1019
                "expected at least ",sstart,", got ",j-1)))
1020
        end
1021
        y = iterate(src, y[2])
50,148,670,372✔
1022
    end
100,297,240,447✔
1023
    i = Int(dstart)
100,307✔
1024
    while i <= dmax && y !== nothing
9,100,311✔
1025
        val, st = y
9,000,004✔
1026
        @inbounds dest[i] = val
9,000,004✔
1027
        y = iterate(src, st)
9,000,013✔
1028
        i += 1
9,000,004✔
1029
    end
9,000,004✔
1030
    i <= dmax && throw(BoundsError(dest, i))
100,307✔
1031
    return dest
100,306✔
1032
end
1033

1034
## copy between abstract arrays - generally more efficient
1035
## since a single index variable can be used.
1036

1037
"""
1038
    copyto!(dest::AbstractArray, src) -> dest
1039

1040
Copy all elements from collection `src` to array `dest`, whose length must be greater than
1041
or equal to the length `n` of `src`. The first `n` elements of `dest` are overwritten,
1042
the other elements are left untouched.
1043

1044
See also [`copy!`](@ref Base.copy!), [`copy`](@ref).
1045

1046
# Examples
1047
```jldoctest
1048
julia> x = [1., 0., 3., 0., 5.];
1049

1050
julia> y = zeros(7);
1051

1052
julia> copyto!(y, x);
1053

1054
julia> y
1055
7-element Vector{Float64}:
1056
 1.0
1057
 0.0
1058
 3.0
1059
 0.0
1060
 5.0
1061
 0.0
1062
 0.0
1063
```
1064
"""
1065
function copyto!(dest::AbstractArray, src::AbstractArray)
2,761,019✔
1066
    isempty(src) && return dest
2,774,200✔
1067
    if dest isa BitArray
148,105✔
1068
        # avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1069
        return _copyto_bitarray!(dest, src)
1✔
1070
    end
1071
    src′ = unalias(dest, src)
2,809,385✔
1072
    copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
2,773,717✔
1073
end
1074

1075
function copyto!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
×
1076
    isempty(src) && return dest
×
1077
    src′ = unalias(dest, src)
×
1078
    copyto_unaliased!(deststyle, dest, srcstyle, src′)
×
1079
end
1080

1081
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
2,771,636✔
1082
    isempty(src) && return dest
2,773,717✔
1083
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
2,773,720✔
1084
    idf, isf = first(destinds), first(srcinds)
148,104✔
1085
    Δi = idf - isf
148,104✔
1086
    (checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
2,773,718✔
1087
        throw(BoundsError(dest, srcinds))
1088
    if deststyle isa IndexLinear
148,103✔
1089
        if srcstyle isa IndexLinear
143,607✔
1090
            # Single-index implementation
1091
            @inbounds for i in srcinds
5,270,208✔
1092
                dest[i + Δi] = src[i]
35,731,615✔
1093
            end
68,819,453✔
1094
        else
1095
            # Dual-index implementation
1096
            i = idf - 1
133,704✔
1097
            @inbounds for a in src
267,254✔
1098
                dest[i+=1] = a
3,260,208✔
1099
            end
6,378,931✔
1100
        end
1101
    else
1102
        iterdest, itersrc = eachindex(dest), eachindex(src)
4,496✔
1103
        if iterdest == itersrc
4,496✔
1104
            # Shared-iterator implementation
1105
            for I in iterdest
4,278✔
1106
                @inbounds dest[I] = src[I]
6,386,210✔
1107
            end
12,202,707✔
1108
        else
1109
            # Dual-iterator implementation
1110
            ret = iterate(iterdest)
4,714✔
1111
            @inbounds for a in src
4,402✔
1112
                idx, state = ret::NTuple{2,Any}
2,009,469✔
1113
                dest[idx] = a
2,009,469✔
1114
                ret = iterate(iterdest, state)
2,011,827✔
1115
            end
4,008,113✔
1116
        end
1117
    end
1118
    return dest
2,773,716✔
1119
end
1120

1121
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray)
20,804✔
1122
    copyto!(dest, dstart, src, first(LinearIndices(src)), length(src))
20,812✔
1123
end
1124

1125
function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray, sstart::Integer)
22✔
1126
    srcinds = LinearIndices(src)
22✔
1127
    checkbounds(Bool, srcinds, sstart) || throw(BoundsError(src, sstart))
31✔
1128
    copyto!(dest, dstart, src, sstart, last(srcinds)-sstart+1)
13✔
1129
end
1130

1131
function copyto!(dest::AbstractArray, dstart::Integer,
52,660✔
1132
               src::AbstractArray, sstart::Integer,
1133
               n::Integer)
1134
    n == 0 && return dest
52,660✔
1135
    n < 0 && throw(ArgumentError(LazyString("tried to copy n=",
52,658✔
1136
        n," elements, but n should be nonnegative")))
1137
    destinds, srcinds = LinearIndices(dest), LinearIndices(src)
52,657✔
1138
    (checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
52,669✔
1139
    (checkbounds(Bool, srcinds, sstart)  && checkbounds(Bool, srcinds, sstart+n-1))  || throw(BoundsError(src,  sstart:sstart+n-1))
52,648✔
1140
    src′ = unalias(dest, src)
54,783✔
1141
    @inbounds for i = 0:n-1
105,284✔
1142
        dest[dstart+i] = src′[sstart+i]
2,467,575✔
1143
    end
4,882,508✔
1144
    return dest
52,642✔
1145
end
1146

1147
function copy(a::AbstractArray)
147,026✔
1148
    @_propagate_inbounds_meta
648✔
1149
    copymutable(a)
147,222✔
1150
end
1151

1152
function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::AbstractRange{Int},
2,791✔
1153
               A::AbstractVecOrMat{S}, ir_src::AbstractRange{Int}, jr_src::AbstractRange{Int}) where {R,S}
1154
    if length(ir_dest) != length(ir_src)
2,791✔
1155
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
1✔
1156
            length(ir_src)," and ",length(ir_dest),")")))
1157
    end
1158
    if length(jr_dest) != length(jr_src)
2,790✔
1159
        throw(ArgumentError(LazyString("source and destination must have same size (got ",
×
1160
            length(jr_src)," and ",length(jr_dest),")")))
1161
    end
1162
    @boundscheck checkbounds(B, ir_dest, jr_dest)
2,790✔
1163
    @boundscheck checkbounds(A, ir_src, jr_src)
2,790✔
1164
    A′ = unalias(B, A)
5,578✔
1165
    jdest = first(jr_dest)
2,790✔
1166
    for jsrc in jr_src
5,580✔
1167
        idest = first(ir_dest)
19,724✔
1168
        for isrc in ir_src
39,448✔
1169
            @inbounds B[idest,jdest] = A′[isrc,jsrc]
198,060✔
1170
            idest += step(ir_dest)
197,900✔
1171
        end
376,076✔
1172
        jdest += step(jr_dest)
19,724✔
1173
    end
36,658✔
1174
    return B
2,790✔
1175
end
1176

1177
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
72,225✔
1178

1179
function copyto_axcheck!(dest, src)
45,723✔
1180
    _checkaxs(axes(dest), axes(src))
51,442✔
1181
    copyto!(dest, src)
62,709✔
1182
end
1183

1184
"""
1185
    copymutable(a)
1186

1187
Make a mutable copy of an array or iterable `a`.  For `a::Array`,
1188
this is equivalent to `copy(a)`, but for other array types it may
1189
differ depending on the type of `similar(a)`.  For generic iterables
1190
this is equivalent to `collect(a)`.
1191

1192
# Examples
1193
```jldoctest
1194
julia> tup = (1, 2, 3)
1195
(1, 2, 3)
1196

1197
julia> Base.copymutable(tup)
1198
3-element Vector{Int64}:
1199
 1
1200
 2
1201
 3
1202
```
1203
"""
1204
function copymutable(a::AbstractArray)
2,771✔
1205
    @_propagate_inbounds_meta
1,483✔
1206
    copyto!(similar(a), a)
153,617✔
1207
end
1208
copymutable(itr) = collect(itr)
1✔
1209

1210
zero(x::AbstractArray{T}) where {T} = fill!(similar(x, typeof(zero(T))), zero(T))
16,311✔
1211

1212
## iteration support for arrays by iterating over `eachindex` in the array ##
1213
# Allows fast iteration by default for both IndexLinear and IndexCartesian arrays
1214

1215
# While the definitions for IndexLinear are all simple enough to inline on their
1216
# own, IndexCartesian's CartesianIndices is more complicated and requires explicit
1217
# inlining.
1218
function iterate(A::AbstractArray, state=(eachindex(A),))
77,506,682✔
1219
    y = iterate(state...)
103,199,533✔
1220
    y === nothing && return nothing
80,088,275✔
1221
    A[y[1]], (state[1], tail(y)...)
79,662,057✔
1222
end
1223

1224
isempty(a::AbstractArray) = (length(a) == 0)
2,414,014,314✔
1225

1226

1227
## range conversions ##
1228

1229
map(::Type{T}, r::StepRange) where {T<:Real} = T(r.start):T(r.step):T(last(r))
2✔
1230
map(::Type{T}, r::UnitRange) where {T<:Real} = T(r.start):T(last(r))
13✔
1231
map(::Type{T}, r::StepRangeLen) where {T<:AbstractFloat} = convert(StepRangeLen{T}, r)
6✔
1232
function map(::Type{T}, r::LinRange) where T<:AbstractFloat
1✔
1233
    LinRange(T(r.start), T(r.stop), length(r))
1✔
1234
end
1235

1236
## unsafe/pointer conversions ##
1237

1238
# note: the following type definitions don't mean any AbstractArray is convertible to
1239
# a data Ref. they just map the array element type to the pointer type for
1240
# convenience in cases that work.
1241
pointer(x::AbstractArray{T}) where {T} = unsafe_convert(Ptr{T}, x)
17,225,889✔
1242
function pointer(x::AbstractArray{T}, i::Integer) where T
8,625,455✔
1243
    @inline
5,132,246✔
1244
    unsafe_convert(Ptr{T}, x) + Int(_memory_offset(x, i))::Int
293,198,485✔
1245
end
1246

1247
# The distance from pointer(x) to the element at x[I...] in bytes
1248
_memory_offset(x::DenseArray, I::Vararg{Any,N}) where {N} = (_to_linear_index(x, I...) - first(LinearIndices(x)))*elsize(x)
252,374,587✔
1249
function _memory_offset(x::AbstractArray, I::Vararg{Any,N}) where {N}
70,193✔
1250
    J = _to_subscript_indices(x, I...)
70,193✔
1251
    return sum(map((i, s, o)->s*(i-o), J, strides(x), Tuple(first(CartesianIndices(x)))))*elsize(x)
271,283✔
1252
end
1253

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

1266
Return a subset of array `A` as specified by `inds`, where each `ind` may be,
1267
for example, an `Int`, an [`AbstractRange`](@ref), or a [`Vector`](@ref).
1268
See the manual section on [array indexing](@ref man-array-indexing) for details.
1269

1270
# Examples
1271
```jldoctest
1272
julia> A = [1 2; 3 4]
1273
2×2 Matrix{Int64}:
1274
 1  2
1275
 3  4
1276

1277
julia> getindex(A, 1)
1278
1
1279

1280
julia> getindex(A, [2, 1])
1281
2-element Vector{Int64}:
1282
 3
1283
 1
1284

1285
julia> getindex(A, 2:4)
1286
3-element Vector{Int64}:
1287
 3
1288
 2
1289
 4
1290
```
1291
"""
1292
function getindex(A::AbstractArray, I...)
95,713,021✔
1293
    @_propagate_inbounds_meta
95,023,901✔
1294
    error_if_canonical_getindex(IndexStyle(A), A, I...)
95,023,901✔
1295
    _getindex(IndexStyle(A), A, to_indices(A, I)...)
219,364,361✔
1296
end
1297
# To avoid invalidations from multidimensional.jl: getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...)
1298
@propagate_inbounds getindex(A::Array, i1::Integer, I::Integer...) = A[to_indices(A, (i1, I...))...]
114,168,400✔
1299

1300
function unsafe_getindex(A::AbstractArray, I...)
262✔
1301
    @inline
262✔
1302
    @inbounds r = getindex(A, I...)
387✔
1303
    r
260✔
1304
end
1305

1306
struct CanonicalIndexError <: Exception
1307
    func::String
1308
    type::Any
1309
    CanonicalIndexError(func::String, @nospecialize(type)) = new(func, type)
14✔
1310
end
1311

1312
error_if_canonical_getindex(::IndexLinear, A::AbstractArray, ::Int) =
2✔
1313
    throw(CanonicalIndexError("getindex", typeof(A)))
1314
error_if_canonical_getindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
3✔
1315
    throw(CanonicalIndexError("getindex", typeof(A)))
1316
error_if_canonical_getindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
95,022,246✔
1317

1318
## Internal definitions
1319
_getindex(::IndexStyle, A::AbstractArray, I...) =
×
1320
    error("getindex for $(typeof(A)) with types $(typeof(I)) is not supported")
1321

1322
## IndexLinear Scalar indexing: canonical method is one Int
1323
_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)
1,544,591✔
1324
_getindex(::IndexLinear, A::AbstractArray, i::Int) = (@_propagate_inbounds_meta; getindex(A, i))
×
1325
function _getindex(::IndexLinear, A::AbstractArray, I::Vararg{Int,M}) where M
982,241✔
1326
    @inline
895,826✔
1327
    @boundscheck checkbounds(A, I...) # generally _to_linear_index requires bounds checking
36,816,750✔
1328
    @inbounds r = getindex(A, _to_linear_index(A, I...))
36,816,714✔
1329
    r
36,816,688✔
1330
end
1331
_to_linear_index(A::AbstractArray, i::Integer) = i
181,296✔
1332
_to_linear_index(A::AbstractVector, i::Integer, I::Integer...) = i
1,690,036✔
1333
_to_linear_index(A::AbstractArray) = first(LinearIndices(A))
289,002✔
1334
_to_linear_index(A::AbstractArray, I::Integer...) = (@inline; _sub2ind(A, I...))
1,099,342✔
1335

1336
## IndexCartesian Scalar indexing: Canonical method is full dimensionality of Ints
1337
function _getindex(::IndexCartesian, A::AbstractArray, I::Vararg{Int,M}) where M
152,755✔
1338
    @inline
152,755✔
1339
    @boundscheck checkbounds(A, I...) # generally _to_subscript_indices requires bounds checking
152,768✔
1340
    @inbounds r = getindex(A, _to_subscript_indices(A, I...)...)
156,356✔
1341
    r
152,741✔
1342
end
1343
function _getindex(::IndexCartesian, A::AbstractArray{T,N}, I::Vararg{Int, N}) where {T,N}
92,916,414✔
1344
    @_propagate_inbounds_meta
92,916,414✔
1345
    getindex(A, I...)
180,459,913✔
1346
end
1347
_to_subscript_indices(A::AbstractArray, i::Integer) = (@inline; _unsafe_ind2sub(A, i))
202,428✔
1348
_to_subscript_indices(A::AbstractArray{T,N}) where {T,N} = (@inline; fill_to_length((), 1, Val(N)))
2✔
1349
_to_subscript_indices(A::AbstractArray{T,0}) where {T} = ()
×
1350
_to_subscript_indices(A::AbstractArray{T,0}, i::Integer) where {T} = ()
5✔
1351
_to_subscript_indices(A::AbstractArray{T,0}, I::Integer...) where {T} = ()
×
1352
function _to_subscript_indices(A::AbstractArray{T,N}, I::Integer...) where {T,N}
1,792✔
1353
    @inline
1,792✔
1354
    J, Jrem = IteratorsMD.split(I, Val(N))
1,792✔
1355
    _to_subscript_indices(A, J, Jrem)
1,792✔
1356
end
1357
_to_subscript_indices(A::AbstractArray, J::Tuple, Jrem::Tuple{}) =
2✔
1358
    __to_subscript_indices(A, axes(A), J, Jrem)
1359
function __to_subscript_indices(A::AbstractArray,
2✔
1360
        ::Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}}, J::Tuple, Jrem::Tuple{})
1361
    @inline
2✔
1362
    (J..., map(first, tail(_remaining_size(J, axes(A))))...)
2✔
1363
end
1364
_to_subscript_indices(A, J::Tuple, Jrem::Tuple) = J # already bounds-checked, safe to drop
1,790✔
1365
_to_subscript_indices(A::AbstractArray{T,N}, I::Vararg{Int,N}) where {T,N} = I
24,502✔
1366
_remaining_size(::Tuple{Any}, t::Tuple) = t
2✔
1367
_remaining_size(h::Tuple, t::Tuple) = (@inline; _remaining_size(tail(h), tail(t)))
2✔
1368
_unsafe_ind2sub(::Tuple{}, i) = () # _ind2sub may throw(BoundsError()) in this case
×
1369
_unsafe_ind2sub(sz, i) = (@inline; _ind2sub(sz, i))
202,428✔
1370

1371
## Setindex! is defined similarly. We first dispatch to an internal _setindex!
1372
# function that allows dispatch on array storage
1373

1374
"""
1375
    setindex!(A, X, inds...)
1376
    A[inds...] = X
1377

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

1381
# Examples
1382
```jldoctest
1383
julia> A = zeros(2,2);
1384

1385
julia> setindex!(A, [10, 20], [1, 2]);
1386

1387
julia> A[[3, 4]] = [30, 40];
1388

1389
julia> A
1390
2×2 Matrix{Float64}:
1391
 10.0  30.0
1392
 20.0  40.0
1393
```
1394
"""
1395
function setindex!(A::AbstractArray, v, I...)
2,678,030✔
1396
    @_propagate_inbounds_meta
2,564,474✔
1397
    error_if_canonical_setindex(IndexStyle(A), A, I...)
2,564,474✔
1398
    _setindex!(IndexStyle(A), A, v, to_indices(A, I)...)
3,694,770✔
1399
end
1400
function unsafe_setindex!(A::AbstractArray, v, I...)
732✔
1401
    @inline
732✔
1402
    @inbounds r = setindex!(A, v, I...)
732✔
1403
    r
730✔
1404
end
1405

1406
error_if_canonical_setindex(::IndexLinear, A::AbstractArray, ::Int) =
7✔
1407
    throw(CanonicalIndexError("setindex!", typeof(A)))
1408
error_if_canonical_setindex(::IndexCartesian, A::AbstractArray{T,N}, ::Vararg{Int,N}) where {T,N} =
2✔
1409
    throw(CanonicalIndexError("setindex!", typeof(A)))
1410
error_if_canonical_setindex(::IndexStyle, ::AbstractArray, ::Any...) = nothing
2,563,949✔
1411

1412
## Internal definitions
1413
_setindex!(::IndexStyle, A::AbstractArray, v, I...) =
×
1414
    error("setindex! for $(typeof(A)) with types $(typeof(I)) is not supported")
1415

1416
## IndexLinear Scalar indexing
1417
_setindex!(::IndexLinear, A::AbstractArray, v, i::Int) = (@_propagate_inbounds_meta; setindex!(A, v, i))
222,765✔
1418
function _setindex!(::IndexLinear, A::AbstractArray, v, I::Vararg{Int,M}) where M
155,773✔
1419
    @inline
107,271✔
1420
    @boundscheck checkbounds(A, I...)
159,246✔
1421
    @inbounds r = setindex!(A, v, _to_linear_index(A, I...))
159,209✔
1422
    r
159,208✔
1423
end
1424

1425
# IndexCartesian Scalar indexing
1426
function _setindex!(::IndexCartesian, A::AbstractArray{T,N}, v, I::Vararg{Int, N}) where {T,N}
2,396,241✔
1427
    @_propagate_inbounds_meta
2,396,241✔
1428
    setindex!(A, v, I...)
2,396,242✔
1429
end
1430
function _setindex!(::IndexCartesian, A::AbstractArray, v, I::Vararg{Int,M}) where M
3,049✔
1431
    @inline
3,049✔
1432
    @boundscheck checkbounds(A, I...)
3,054✔
1433
    @inbounds r = setindex!(A, v, _to_subscript_indices(A, I...)...)
3,044✔
1434
    r
3,044✔
1435
end
1436

1437
"""
1438
    parent(A)
1439

1440
Return the underlying "parent array”. This parent array of objects of types `SubArray`, `ReshapedArray`
1441
or `LinearAlgebra.Transpose` is what was passed as an argument to `view`, `reshape`, `transpose`, etc.
1442
during object creation. If the input is not a wrapped object, return the input itself. If the input is
1443
wrapped multiple times, only the outermost wrapper will be removed.
1444

1445
# Examples
1446
```jldoctest
1447
julia> A = [1 2; 3 4]
1448
2×2 Matrix{Int64}:
1449
 1  2
1450
 3  4
1451

1452
julia> V = view(A, 1:2, :)
1453
2×2 view(::Matrix{Int64}, 1:2, :) with eltype Int64:
1454
 1  2
1455
 3  4
1456

1457
julia> parent(V)
1458
2×2 Matrix{Int64}:
1459
 1  2
1460
 3  4
1461
```
1462
"""
1463
parent(a::AbstractArray) = a
1,913✔
1464

1465
## rudimentary aliasing detection ##
1466
"""
1467
    Base.unalias(dest, A)
1468

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

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

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

1479
See also [`Base.mightalias`](@ref).
1480
"""
1481
unalias(dest, A::AbstractArray) = mightalias(dest, A) ? unaliascopy(A) : A
8,093,646✔
1482
unalias(dest, A::AbstractRange) = A
2,785,180✔
1483
unalias(dest, A) = A
2,597,548✔
1484

1485
"""
1486
    Base.unaliascopy(A)
1487

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

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

1508
"""
1509
    Base.mightalias(A::AbstractArray, B::AbstractArray)
1510

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

1513
By default, this simply checks if either of the arrays reference the same memory
1514
regions, as identified by their [`Base.dataids`](@ref).
1515
"""
1516
mightalias(A::AbstractArray, B::AbstractArray) = !isbits(A) && !isbits(B) && !_isdisjoint(dataids(A), dataids(B))
5,432,147✔
1517
mightalias(x, y) = false
×
1518

1519
_isdisjoint(as::Tuple{}, bs::Tuple{}) = true
×
1520
_isdisjoint(as::Tuple{}, bs::Tuple{UInt}) = true
×
1521
_isdisjoint(as::Tuple{}, bs::Tuple) = true
×
1522
_isdisjoint(as::Tuple{UInt}, bs::Tuple{}) = true
×
1523
_isdisjoint(as::Tuple{UInt}, bs::Tuple{UInt}) = as[1] != bs[1]
5,319,822✔
1524
_isdisjoint(as::Tuple{UInt}, bs::Tuple) = !(as[1] in bs)
82,752✔
1525
_isdisjoint(as::Tuple, bs::Tuple{}) = true
×
1526
_isdisjoint(as::Tuple, bs::Tuple{UInt}) = !(bs[1] in as)
2,096✔
1527
_isdisjoint(as::Tuple, bs::Tuple) = !(as[1] in bs) && _isdisjoint(tail(as), bs)
83,886✔
1528

1529
"""
1530
    Base.dataids(A::AbstractArray)
1531

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

1534
Custom arrays that would like to opt-in to aliasing detection of their component
1535
parts can specialize this method to return the concatenation of the `dataids` of
1536
their component parts.  A typical definition for an array that wraps a parent is
1537
`Base.dataids(C::CustomArray) = dataids(C.parent)`.
1538
"""
1539
dataids(A::AbstractArray) = (UInt(objectid(A)),)
70,208✔
1540
dataids(A::Array) = (UInt(pointer(A)),)
10,689,702✔
1541
dataids(::AbstractRange) = ()
6,265✔
1542
dataids(x) = ()
3,748✔
1543

1544
## get (getindex with a default value) ##
1545

1546
RangeVecIntList{A<:AbstractVector{Int}} = Union{Tuple{Vararg{Union{AbstractRange, AbstractVector{Int}}}},
1547
    AbstractVector{UnitRange{Int}}, AbstractVector{AbstractRange{Int}}, AbstractVector{A}}
1548

1549
get(A::AbstractArray, i::Integer, default) = checkbounds(Bool, A, i) ? A[i] : default
11✔
1550
get(A::AbstractArray, I::Tuple{}, default) = checkbounds(Bool, A) ? A[] : default
8✔
1551
get(A::AbstractArray, I::Dims, default) = checkbounds(Bool, A, I...) ? A[I...] : default
15✔
1552
get(f::Callable, A::AbstractArray, i::Integer) = checkbounds(Bool, A, i) ? A[i] : f()
4✔
1553
get(f::Callable, A::AbstractArray, I::Tuple{}) = checkbounds(Bool, A) ? A[] : f()
8✔
1554
get(f::Callable, A::AbstractArray, I::Dims) = checkbounds(Bool, A, I...) ? A[I...] : f()
8✔
1555

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

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

1576
function get!(X::AbstractArray{T}, A::AbstractArray, I::RangeVecIntList, default::T) where T
2✔
1577
    fill!(X, default)
72✔
1578
    dst, src = indcopy(size(A), I)
2✔
1579
    X[dst...] = A[src...]
2✔
1580
    X
2✔
1581
end
1582

1583
get(A::AbstractArray, I::RangeVecIntList, default) =
2✔
1584
    get!(similar(A, typeof(default), index_shape(I...)), A, I, default)
1585

1586
## structured matrix methods ##
1587
replace_in_print_matrix(A::AbstractMatrix,i::Integer,j::Integer,s::AbstractString) = s
24,338✔
1588
replace_in_print_matrix(A::AbstractVector,i::Integer,j::Integer,s::AbstractString) = s
5,166✔
1589

1590
## Concatenation ##
1591
eltypeof(x) = typeof(x)
21,488✔
1592
eltypeof(x::AbstractArray) = eltype(x)
13,273✔
1593

1594
promote_eltypeof() = Bottom
×
1595
promote_eltypeof(v1, vs...) = promote_type(eltypeof(v1), promote_eltypeof(vs...))
34,761✔
1596

1597
promote_eltype() = Bottom
118✔
1598
promote_eltype(v1, vs...) = promote_type(eltype(v1), promote_eltype(vs...))
7,845✔
1599

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

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

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

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

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

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

1625
_typed_vcat_similar(V, ::Type{T}, n) where T = similar(V[1], T, n)
793,206✔
1626
_typed_vcat(::Type{T}, V::AbstractVecOrTuple{AbstractVector}) where T =
819,464✔
1627
    _typed_vcat!(_typed_vcat_similar(V, T, sum(map(length, V))), V)
1628

1629
function _typed_vcat!(a::AbstractVector{T}, V::AbstractVecOrTuple{AbstractVector}) where T
793,206✔
1630
    pos = 1
793,206✔
1631
    for k=1:Int(length(V))::Int
793,211✔
1632
        Vk = V[k]
794,973✔
1633
        p1 = pos + Int(length(Vk))::Int - 1
795,570✔
1634
        a[pos:p1] = Vk
5,721,152✔
1635
        pos = p1+1
794,973✔
1636
    end
796,740✔
1637
    a
793,206✔
1638
end
1639

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

1642
hcat(A::AbstractVecOrMat...) = typed_hcat(promote_eltype(A...), A...)
1✔
1643
hcat(A::AbstractVecOrMat{T}...) where {T} = typed_hcat(T, A...)
12✔
1644

1645
function _typed_hcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
521✔
1646
    nargs = length(A)
521✔
1647
    nrows = size(A[1], 1)
521✔
1648
    ncols = 0
521✔
1649
    dense = true
521✔
1650
    for j = 1:nargs
527✔
1651
        Aj = A[j]
1,065✔
1652
        if size(Aj, 1) != nrows
1,408✔
1653
            throw(ArgumentError("number of rows of each array must match (got $(map(x->size(x,1), A)))"))
3✔
1654
        end
1655
        dense &= isa(Aj,Array)
1,064✔
1656
        nd = ndims(Aj)
1,408✔
1657
        ncols += (nd==2 ? size(Aj,2) : 1)
1,353✔
1658
    end
1,608✔
1659
    B = similar(A[1], T, nrows, ncols)
520✔
1660
    pos = 1
520✔
1661
    if dense
520✔
1662
        for k=1:nargs
283✔
1663
            Ak = A[k]
586✔
1664
            n = length(Ak)
709✔
1665
            copyto!(B, pos, Ak, 1, n)
705✔
1666
            pos += n
586✔
1667
        end
891✔
1668
    else
1669
        for k=1:nargs
243✔
1670
            Ak = A[k]
477✔
1671
            p1 = pos+(isa(Ak,AbstractMatrix) ? size(Ak, 2) : 1)-1
654✔
1672
            B[:, pos:p1] = Ak
477✔
1673
            pos = p1+1
477✔
1674
        end
477✔
1675
    end
1676
    return B
520✔
1677
end
1678

1679
vcat(A::AbstractVecOrMat...) = typed_vcat(promote_eltype(A...), A...)
×
1680
vcat(A::AbstractVecOrMat{T}...) where {T} = typed_vcat(T, A...)
8✔
1681

1682
function _typed_vcat(::Type{T}, A::AbstractVecOrTuple{AbstractVecOrMat}) where T
760✔
1683
    nargs = length(A)
760✔
1684
    nrows = sum(a->size(a, 1), A)::Int
2,380✔
1685
    ncols = size(A[1], 2)
760✔
1686
    for j = 2:nargs
761✔
1687
        if size(A[j], 2) != ncols
815✔
1688
            throw(ArgumentError("number of columns of each array must match (got $(map(x->size(x,2), A)))"))
3✔
1689
        end
1690
    end
875✔
1691
    B = similar(A[1], T, nrows, ncols)
759✔
1692
    pos = 1
759✔
1693
    for k=1:nargs
760✔
1694
        Ak = A[k]
1,568✔
1695
        p1 = pos+size(Ak,1)::Int-1
1,653✔
1696
        B[pos:p1, :] = Ak
1,568✔
1697
        pos = p1+1
1,568✔
1698
    end
2,377✔
1699
    return B
759✔
1700
end
1701

1702
typed_vcat(::Type{T}, A::AbstractVecOrMat...) where {T} = _typed_vcat(T, A)
815,046✔
1703

1704
reduce(::typeof(vcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1705
    _typed_vcat(mapreduce(eltype, promote_type, A), A)
1706

1707
reduce(::typeof(hcat), A::AbstractVector{<:AbstractVecOrMat}) =
6✔
1708
    _typed_hcat(mapreduce(eltype, promote_type, A), A)
1709

1710
## cat: general case
1711

1712
# helper functions
1713
cat_size(A) = (1,)
22,142✔
1714
cat_size(A::AbstractArray) = size(A)
16,883✔
1715
cat_size(A, d) = 1
22,555✔
1716
cat_size(A::AbstractArray, d) = size(A, d)
24,639✔
1717

1718
cat_length(::Any) = 1
100✔
1719
cat_length(a::AbstractArray) = length(a)
472✔
1720

1721
cat_ndims(a) = 0
183✔
1722
cat_ndims(a::AbstractArray) = ndims(a)
684✔
1723

1724
cat_indices(A, d) = OneTo(1)
22,143✔
1725
cat_indices(A::AbstractArray, d) = axes(A, d)
18,042✔
1726

1727
cat_similar(A, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
7,282✔
1728
cat_similar(A, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
4✔
1729
cat_similar(A::Array, ::Type{T}, shape::Tuple) where T = Array{T}(undef, shape)
935✔
1730
cat_similar(A::Array, ::Type{T}, shape::Vector) where T = Array{T}(undef, shape...)
45✔
1731
cat_similar(A::AbstractArray, T::Type, shape::Tuple) = similar(A, T, shape)
1,071✔
1732
cat_similar(A::AbstractArray, T::Type, shape::Vector) = similar(A, T, shape...)
2✔
1733

1734
# These are for backwards compatibility (even though internal)
1735
cat_shape(dims, shape::Tuple{Vararg{Int}}) = shape
×
1736
function cat_shape(dims, shapes::Tuple)
4✔
1737
    out_shape = ()
4✔
1738
    for s in shapes
4✔
1739
        out_shape = _cshp(1, dims, out_shape, s)
18✔
1740
    end
15✔
1741
    return out_shape
4✔
1742
end
1743
# The new way to compute the shape (more inferable than combining cat_size & cat_shape, due to Varargs + issue#36454)
1744
cat_size_shape(dims) = ntuple(zero, Val(length(dims)))
×
1745
@inline cat_size_shape(dims, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, (), cat_size(X)), tail...)
9,246✔
1746
_cat_size_shape(dims, shape) = shape
1,721✔
1747
@inline _cat_size_shape(dims, shape, X, tail...) = _cat_size_shape(dims, _cshp(1, dims, shape, cat_size(X)), tail...)
29,922✔
1748

1749
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, ::Tuple{}) = ()
×
1750
_cshp(ndim::Int, ::Tuple{}, ::Tuple{}, nshape) = nshape
18✔
1751
_cshp(ndim::Int, dims, ::Tuple{}, ::Tuple{}) = ntuple(Returns(1), Val(length(dims)))
508✔
1752
@inline _cshp(ndim::Int, dims, shape, ::Tuple{}) =
511✔
1753
    (shape[1] + dims[1], _cshp(ndim + 1, tail(dims), tail(shape), ())...)
1754
@inline _cshp(ndim::Int, dims, ::Tuple{}, nshape) =
10,338✔
1755
    (nshape[1], _cshp(ndim + 1, tail(dims), (), tail(nshape))...)
1756
@inline function _cshp(ndim::Int, ::Tuple{}, shape, ::Tuple{})
25✔
1757
    _cs(ndim, shape[1], 1)
27✔
1758
    (1, _cshp(ndim + 1, (), tail(shape), ())...)
23✔
1759
end
1760
@inline function _cshp(ndim::Int, ::Tuple{}, shape, nshape)
248✔
1761
    next = _cs(ndim, shape[1], nshape[1])
248✔
1762
    (next, _cshp(ndim + 1, (), tail(shape), tail(nshape))...)
248✔
1763
end
1764
@inline function _cshp(ndim::Int, dims, shape, nshape)
30,896✔
1765
    a = shape[1]
30,896✔
1766
    b = nshape[1]
30,896✔
1767
    next = dims[1] ? a + b : _cs(ndim, a, b)
31,849✔
1768
    (next, _cshp(ndim + 1, tail(dims), tail(shape), tail(nshape))...)
30,926✔
1769
end
1770

1771
_cs(d, a, b) = (a == b ? a : throw(DimensionMismatch(
1,504✔
1772
    "mismatch in dimension $d (expected $a got $b)")))
1773

1774
dims2cat(::Val{dims}) where dims = dims2cat(dims)
922✔
1775
function dims2cat(dims)
1,540✔
1776
    if any(≤(0), dims)
2,734✔
1777
        throw(ArgumentError("All cat dimensions must be positive integers, but got $dims"))
2✔
1778
    end
1779
    ntuple(in(dims), maximum(dims))
1,579✔
1780
end
1781

1782
_cat(dims, X...) = _cat_t(dims, promote_eltypeof(X...), X...)
7,290✔
1783

1784
@inline function _cat_t(dims, ::Type{T}, X...) where {T}
9,246✔
1785
    catdims = dims2cat(dims)
9,283✔
1786
    shape = cat_size_shape(catdims, X...)
9,246✔
1787
    A = cat_similar(X[1], T, shape)
9,240✔
1788
    if count(!iszero, catdims)::Int > 1
9,240✔
1789
        fill!(A, zero(T))
591✔
1790
    end
1791
    return __cat(A, shape, catdims, X...)
9,747✔
1792
end
1793
# this version of `cat_t` is not very kind for inference and so its usage should be avoided,
1794
# nevertheless it is here just for compat after https://github.com/JuliaLang/julia/pull/45028
1795
@inline cat_t(::Type{T}, X...; dims) where {T} = _cat_t(dims, T, X...)
×
1796

1797
# Why isn't this called `__cat!`?
1798
__cat(A, shape, catdims, X...) = __cat_offset!(A, shape, catdims, ntuple(zero, length(shape)), X...)
9,751✔
1799

1800
function __cat_offset!(A, shape, catdims, offsets, x, X...)
39,014✔
1801
    # splitting the "work" on x from X... may reduce latency (fewer costly specializations)
1802
    newoffsets = __cat_offset1!(A, shape, catdims, offsets, x)
39,522✔
1803
    return __cat_offset!(A, shape, catdims, newoffsets, X...)
39,013✔
1804
end
1805
__cat_offset!(A, shape, catdims, offsets) = A
9,242✔
1806

1807
function __cat_offset1!(A, shape, catdims, offsets, x)
39,014✔
1808
    inds = ntuple(length(offsets)) do i
39,137✔
1809
        (i <= length(catdims) && catdims[i]) ? offsets[i] .+ cat_indices(x, i) : 1:shape[i]
43,150✔
1810
    end
1811
    if x isa AbstractArray
39,014✔
1812
        A[inds...] = x
109,123✔
1813
    else
1814
        fill!(view(A, inds...), x)
22,810✔
1815
    end
1816
    newoffsets = ntuple(length(offsets)) do i
39,013✔
1817
        (i <= length(catdims) && catdims[i]) ? offsets[i] + cat_size(x, i) : offsets[i]
45,119✔
1818
    end
1819
    return newoffsets
39,013✔
1820
end
1821

1822
"""
1823
    vcat(A...)
1824

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

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

1831
See also [`hcat`](@ref), [`Iterators.flatten`](@ref), [`stack`](@ref).
1832

1833
# Examples
1834
```jldoctest
1835
julia> v = vcat([1,2], [3,4])
1836
4-element Vector{Int64}:
1837
 1
1838
 2
1839
 3
1840
 4
1841

1842
julia> v == vcat(1, 2, [3,4])  # accepts numbers
1843
true
1844

1845
julia> v == [1; 2; [3,4]]  # syntax for the same operation
1846
true
1847

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

1851
julia> vcat(range(1, 2, length=3))  # collects lazy ranges
1852
3-element Vector{Float64}:
1853
 1.0
1854
 1.5
1855
 2.0
1856

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

1860
julia> vcat(two...)
1861
3×3 Matrix{Float64}:
1862
 10.0  20.0  30.0
1863
  4.0   5.0   6.0
1864
  7.0   8.0   9.0
1865

1866
julia> vs = [[1, 2], [3, 4], [5, 6]];
1867

1868
julia> reduce(vcat, vs)  # more efficient than vcat(vs...)
1869
6-element Vector{Int64}:
1870
 1
1871
 2
1872
 3
1873
 4
1874
 5
1875
 6
1876

1877
julia> ans == collect(Iterators.flatten(vs))
1878
true
1879
```
1880
"""
1881
vcat(X...) = cat(X...; dims=Val(1))
380✔
1882
"""
1883
    hcat(A...)
1884

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

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

1892
See also [`vcat`](@ref), [`hvcat`](@ref).
1893

1894
# Examples
1895
```jldoctest
1896
julia> hcat([1,2], [3,4], [5,6])
1897
2×3 Matrix{Int64}:
1898
 1  3  5
1899
 2  4  6
1900

1901
julia> hcat(1, 2, [30 40], [5, 6, 7]')  # accepts numbers
1902
1×7 Matrix{Int64}:
1903
 1  2  30  40  5  6  7
1904

1905
julia> ans == [1 2 [30 40] [5, 6, 7]']  # syntax for the same operation
1906
true
1907

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

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

1914
julia> reduce(hcat, ms)  # more efficient than hcat(ms...)
1915
2×6 Matrix{Float64}:
1916
 0.0  0.0  1.0  2.0  50.0  60.0
1917
 0.0  0.0  3.0  4.0  70.0  80.0
1918

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

1922
julia> hcat(Int[], Int[], Int[])  # empty vectors, each of size (0,)
1923
0×3 Matrix{Int64}
1924

1925
julia> hcat([1.1, 9.9], Matrix(undef, 2, 0))  # hcat with empty 2×0 Matrix
1926
2×1 Matrix{Any}:
1927
 1.1
1928
 9.9
1929
```
1930
"""
1931
hcat(X...) = cat(X...; dims=Val(2))
9✔
1932

1933
typed_vcat(::Type{T}, X...) where T = _cat_t(Val(1), T, X...)
253✔
1934
typed_hcat(::Type{T}, X...) where T = _cat_t(Val(2), T, X...)
256✔
1935

1936
"""
1937
    cat(A...; dims)
1938

1939
Concatenate the input arrays along the dimensions specified in `dims`.
1940

1941
Along a dimension `d in dims`, the size of the output array is `sum(size(a,d) for
1942
a in A)`.
1943
Along other dimensions, all input arrays should have the same size,
1944
which will also be the size of the output array along those dimensions.
1945

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

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

1955
The keyword also accepts `Val(dims)`.
1956

1957
!!! compat "Julia 1.8"
1958
    For multiple dimensions `dims = Val(::Tuple)` was added in Julia 1.8.
1959

1960
# Examples
1961
```jldoctest
1962
julia> cat([1 2; 3 4], [pi, pi], fill(10, 2,3,1); dims=2)  # same as hcat
1963
2×6×1 Array{Float64, 3}:
1964
[:, :, 1] =
1965
 1.0  2.0  3.14159  10.0  10.0  10.0
1966
 3.0  4.0  3.14159  10.0  10.0  10.0
1967

1968
julia> cat(true, trues(2,2), trues(4)', dims=(1,2))  # block-diagonal
1969
4×7 Matrix{Bool}:
1970
 1  0  0  0  0  0  0
1971
 0  1  1  0  0  0  0
1972
 0  1  1  0  0  0  0
1973
 0  0  0  1  1  1  1
1974

1975
julia> cat(1, [2], [3;;]; dims=Val(2))
1976
1×3 Matrix{Int64}:
1977
 1  2  3
1978
```
1979
"""
1980
@inline cat(A...; dims) = _cat(dims, A...)
17,464✔
1981
# `@constprop :aggressive` allows `catdims` to be propagated as constant improving return type inference
1982
@constprop :aggressive _cat(catdims, A::AbstractArray{T}...) where {T} = _cat_t(catdims, T, A...)
22✔
1983

1984
# The specializations for 1 and 2 inputs are important
1985
# especially when running with --inline=no, see #11158
1986
vcat(A::AbstractArray) = cat(A; dims=Val(1))
1✔
1987
vcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(1))
3✔
1988
vcat(A::AbstractArray...) = cat(A...; dims=Val(1))
×
1989
hcat(A::AbstractArray) = cat(A; dims=Val(2))
1✔
1990
hcat(A::AbstractArray, B::AbstractArray) = cat(A, B; dims=Val(2))
1✔
1991
hcat(A::AbstractArray...) = cat(A...; dims=Val(2))
1✔
1992

1993
typed_vcat(T::Type, A::AbstractArray) = _cat_t(Val(1), T, A)
1✔
1994
typed_vcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(1), T, A, B)
3✔
1995
typed_vcat(T::Type, A::AbstractArray...) = _cat_t(Val(1), T, A...)
1✔
1996
typed_hcat(T::Type, A::AbstractArray) = _cat_t(Val(2), T, A)
3✔
1997
typed_hcat(T::Type, A::AbstractArray, B::AbstractArray) = _cat_t(Val(2), T, A, B)
2✔
1998
typed_hcat(T::Type, A::AbstractArray...) = _cat_t(Val(2), T, A...)
2✔
1999

2000
# 2d horizontal and vertical concatenation
2001

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

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

2015
"""
2016
    hvcat(blocks_per_row::Union{Tuple{Vararg{Int}}, Int}, values...)
2017

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

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

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

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

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

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

2056
function typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}, as::AbstractVecOrMat...) where T
655✔
2057
    nbr = length(rows)  # number of block rows
655✔
2058

2059
    nc = 0
655✔
2060
    for i=1:rows[1]
1,310✔
2061
        nc += size(as[i],2)
1,278✔
2062
    end
1,901✔
2063

2064
    nr = 0
655✔
2065
    a = 1
655✔
2066
    for i = 1:nbr
655✔
2067
        nr += size(as[a],1)
1,157✔
2068
        a += rows[i]
1,157✔
2069
    end
1,659✔
2070

2071
    out = similar(as[1], T, nr, nc)
655✔
2072

2073
    a = 1
655✔
2074
    r = 1
655✔
2075
    for i = 1:nbr
655✔
2076
        c = 1
1,157✔
2077
        szi = size(as[a],1)
1,157✔
2078
        for j = 1:rows[i]
2,314✔
2079
            Aj = as[a+j-1]
2,161✔
2080
            szj = size(Aj,2)
2,161✔
2081
            if size(Aj,1) != szi
2,161✔
2082
                throw(ArgumentError("mismatched height in block row $(i) (expected $szi, got $(size(Aj,1)))"))
1✔
2083
            end
2084
            if c-1+szj > nc
3,011✔
2085
                throw(ArgumentError("block row $(i) has mismatched number of columns (expected $nc, got $(c-1+szj))"))
1✔
2086
            end
2087
            out[r:r-1+szi, c:c-1+szj] = Aj
3,375✔
2088
            c += szj
2,159✔
2089
        end
3,163✔
2090
        if c != nc+1
1,155✔
2091
            throw(ArgumentError("block row $(i) has mismatched number of columns (expected $nc, got $(c-1))"))
1✔
2092
        end
2093
        r += szi
1,154✔
2094
        a += rows[i]
1,154✔
2095
    end
1,656✔
2096
    out
652✔
2097
end
2098

2099
hvcat(rows::Tuple{Vararg{Int}}) = []
1✔
2100
typed_hvcat(::Type{T}, rows::Tuple{Vararg{Int}}) where {T} = Vector{T}()
×
2101

2102
function hvcat(rows::Tuple{Vararg{Int}}, xs::T...) where T<:Number
1,262✔
2103
    nr = length(rows)
511✔
2104
    nc = rows[1]
1,262✔
2105

2106
    a = Matrix{T}(undef, nr, nc)
1,262✔
2107
    if length(a) != length(xs)
1,262✔
2108
        throw(ArgumentError("argument count does not match specified shape (expected $(length(a)), got $(length(xs)))"))
2✔
2109
    end
2110
    k = 1
510✔
2111
    @inbounds for i=1:nr
1,260✔
2112
        if nc != rows[i]
3,418✔
2113
            throw(ArgumentError("row $(i) has mismatched number of columns (expected $nc, got $(rows[i]))"))
1✔
2114
        end
2115
        for j=1:nc
6,834✔
2116
            a[i,j] = xs[k]
9,095✔
2117
            k += 1
9,095✔
2118
        end
14,773✔
2119
    end
5,575✔
2120
    a
1,259✔
2121
end
2122

2123
function hvcat_fill!(a::Array, xs::Tuple)
433✔
2124
    nr, nc = size(a,1), size(a,2)
433✔
2125
    len = length(xs)
433✔
2126
    if nr*nc != len
433✔
2127
        throw(ArgumentError("argument count $(len) does not match specified shape $((nr,nc))"))
1✔
2128
    end
2129
    k = 1
432✔
2130
    for i=1:nr
864✔
2131
        @inbounds for j=1:nc
2,388✔
2132
            a[i,j] = xs[k]
9,107✔
2133
            k += 1
8,436✔
2134
        end
15,678✔
2135
    end
1,956✔
2136
    a
432✔
2137
end
2138

2139
hvcat(rows::Tuple{Vararg{Int}}, xs::Number...) = typed_hvcat(promote_typeof(xs...), rows, xs...)
171✔
2140
hvcat(rows::Tuple{Vararg{Int}}, xs...) = typed_hvcat(promote_eltypeof(xs...), rows, xs...)
105✔
2141

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

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

2164
## N-dimensional concatenation ##
2165

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2261

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

2265
# 1-dimensional hvncat methods
2266

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

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

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

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

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

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

2308
    nd = N
17✔
2309

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

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

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

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

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

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

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

2367

2368
# balanced dimensions hvncat methods
2369

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

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

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

2399
function hvncat_fill!(A::Array, row_first::Bool, xs::Tuple)
62✔
2400
    # putting these in separate functions leads to unnecessary allocations
2401
    if row_first
62✔
2402
        nr, nc = size(A, 1), size(A, 2)
16✔
2403
        nrc = nr * nc
16✔
2404
        na = prod(size(A)[3:end])
16✔
2405
        k = 1
16✔
2406
        for d ∈ 1:na
32✔
2407
            dd = nrc * (d - 1)
29✔
2408
            for i ∈ 1:nr
58✔
2409
                Ai = dd + i
38✔
2410
                for j ∈ 1:nc
76✔
2411
                    A[Ai] = xs[k]
87✔
2412
                    k += 1
87✔
2413
                    Ai += nr
87✔
2414
                end
136✔
2415
            end
47✔
2416
        end
29✔
2417
    else
2418
        for k ∈ eachindex(xs)
46✔
2419
            A[k] = xs[k]
93✔
2420
        end
93✔
2421
    end
2422
end
2423

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

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

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

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

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

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

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

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

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

2513

2514
# unbalanced dimensions hvncat methods
2515

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2704
Higher-dimensional examples:
2705

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2876

2877
## Reductions and accumulates ##
2878

2879
function isequal(A::AbstractArray, B::AbstractArray)
247,431✔
2880
    if A === B return true end
247,690✔
2881
    if axes(A) != axes(B)
490,847✔
2882
        return false
3,479✔
2883
    end
2884
    for (a, b) in zip(A, B)
486,782✔
2885
        if !isequal(a, b)
91,311,899✔
2886
            return false
566✔
2887
        end
2888
    end
182,175,561✔
2889
    return true
243,127✔
2890
end
2891

2892
function cmp(A::AbstractVector, B::AbstractVector)
313✔
2893
    for (a, b) in zip(A, B)
626✔
2894
        if !isequal(a, b)
868✔
2895
            return isless(a, b) ? -1 : 1
309✔
2896
        end
2897
    end
1,125✔
2898
    return cmp(length(A), length(B))
15✔
2899
end
2900

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

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

2908
function (==)(A::AbstractArray, B::AbstractArray)
6,558,200✔
2909
    if axes(A) != axes(B)
13,116,325✔
2910
        return false
2,986✔
2911
    end
2912
    anymissing = false
6,551,513✔
2913
    for (a, b) in zip(A, B)
12,226,717✔
2914
        eq = (a == b)
336,034,815✔
2915
        if ismissing(eq)
301,376,674✔
2916
            anymissing = true
24✔
2917
        elseif !eq
335,146,490✔
2918
            return false
2,346✔
2919
        end
2920
    end
664,620,624✔
2921
    return anymissing ? missing : true
6,554,363✔
2922
end
2923

2924
# _sub2ind and _ind2sub
2925
# fallbacks
2926
function _sub2ind(A::AbstractArray, I...)
733,392✔
2927
    @inline
733,392✔
2928
    _sub2ind(axes(A), I...)
1,099,342✔
2929
end
2930

2931
function _ind2sub(A::AbstractArray, ind)
202,429✔
2932
    @inline
202,429✔
2933
    _ind2sub(axes(A), ind)
202,429✔
2934
end
2935

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

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

2952
_sub2ind_recurse(::Any, L, ind) = ind
2,393,360✔
2953
function _sub2ind_recurse(::Tuple{}, L, ind, i::Integer, I::Integer...)
1,806✔
2954
    @inline
867✔
2955
    _sub2ind_recurse((), L, ind+(i-1)*L, I...)
12,139✔
2956
end
2957
function _sub2ind_recurse(inds, L, ind, i::Integer, I::Integer...)
3,639,177✔
2958
    @inline
3,121,735✔
2959
    r1 = inds[1]
3,684,435✔
2960
    _sub2ind_recurse(tail(inds), nextL(L, r1), ind+offsetin(i, r1)*L, I...)
1,933,492,530✔
2961
end
2962

2963
nextL(L, l::Integer) = L*l
2,498,461✔
2964
nextL(L, r::AbstractUnitRange) = L*length(r)
1,689,073✔
2965
nextL(L, r::Slice) = L*length(r.indices)
×
2966
offsetin(i, l::Integer) = i-1
1,930,532,102✔
2967
offsetin(i, r::AbstractUnitRange) = i-first(r)
2,821,534✔
2968

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

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

2988
_lookup(ind, d::Integer) = ind+1
2,067✔
2989
_lookup(ind, r::AbstractUnitRange) = ind+first(r)
202,441✔
2990
_div(ind, d::Integer) = div(ind, d), 1, d
2,067✔
2991
_div(ind, r::AbstractUnitRange) = (d = length(r); (div(ind, d), first(r), d))
728,396✔
2992

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

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

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

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

3037
## iteration utilities ##
3038

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

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

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

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

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

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

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

3071
## map over arrays ##
3072

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3241
## 0 arguments
3242

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

3245
## 1 argument
3246

3247
function map!(f::F, dest::AbstractArray, A::AbstractArray) where F
3,593✔
3248
    for (i,j) in zip(eachindex(dest),eachindex(A))
207,909,419✔
3249
        val = f(@inbounds A[j])
208,243,823✔
3250
        @inbounds dest[i] = val
124,268,498✔
3251
    end
154,083,323✔
3252
    return dest
113,657,942✔
3253
end
3254

3255
# map on collections
3256
map(f, A::AbstractArray) = collect_similar(A, Generator(f,A))
135,850✔
3257

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

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

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

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

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

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

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

3289
## 2 argument
3290
function map!(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) where F
274✔
3291
    for (i, j, k) in zip(eachindex(dest), eachindex(A), eachindex(B))
535✔
3292
        @inbounds a, b = A[j], B[k]
370,727✔
3293
        val = f(a, b)
328,622✔
3294
        @inbounds dest[i] = val
328,622✔
3295
    end
656,983✔
3296
    return dest
274✔
3297
end
3298

3299
## N argument
3300

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3387
## hashing AbstractArray ##
3388

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

3397
    # For short arrays, it's not worth doing anything complicated
3398
    if length(A) < 8192
14,615✔
3399
        for x in A
18,887✔
3400
            h = hash(x, h)
544,688✔
3401
        end
678,356✔
3402
        return h
14,374✔
3403
    end
3404

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

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

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

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

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

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

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

3459
    return h
4✔
3460
end
3461

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

3470

3471
## keepat! ##
3472

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

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

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

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